Node-SOAP Header Issue - node.js

i have a requirement to include authentication stuff on the <soap:Header> under a certain attribute name "RequestHeader" like <soap:Header><RequestHeader></RequestHeader></soap:Header><soap:Body>
but unfortunately, node-soap places this inside <soap:Body> instead.
so what i see is <soap:Header></soap:Header><soap:Body><RequestHeader>
question is, how do i move it to soap:Header? the wsdl might be at fault here but fixing it is not an option for now.
looking at the wsdl angle,
these are snippets from the wsdl, it's quite clear that the wsdl states that RequestHeaderElement should be in header, i wonder why it's being thrown to the body?
<wsdl:input name="SendSms">
<soap:header message="tns:SendSms" part="Headers" use="literal" />
<soap:body parts="Parameters" use="literal" />
</wsdl:input>
<wsdl:message name="SendSms">
<wsdl:part element="ns1:RequestHeaderElement" name="Headers" />
<wsdl:part element="tns:SendSmsRequestElement" name="Parameters" />
</wsdl:message>

Have you tried adding a XML string literal to the header?
const auth = '<RequestHeader></RequestHeader>'
soap.createClient(url, soapOptions, function (err, client) {
client.addSoapHeader(auth);
client.myFunction(args, function (err, result) {
console.log(client.lastRequest) //see the xml generated
});
});

Related

Unable to construct a SOAP request with NodeJS

The WSDL in question is under the following URL: https://bmdweb.bmd.at/bmdntcswsdev/bmdntcsws.dll/wsdl/IBMDSOAPNTCS
I was provided with a sample log-output of how the XML should be constructed.
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:tns="http://www.bmd.at/" xmlns:types="http://www.bmd.at/encodedTypes" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<q1:Login xmlns:q1="http://www.bmd.at/wws">
<ALoginRequest href="#id1" />
</q1:Login>
<q2:TBMDLoginRequest id="id1" xsi:type="q2:TBMDLoginRequest" xmlns:q2="http://www.bmd.at/soap">
<Auth href="#id2" />
</q2:TBMDLoginRequest>
<q3:TBMDPlainText id="id2" xsi:type="q3:TBMDPlainText" xmlns:q3="http://www.bmd.at/soap">
<Username xsi:type="xsd:string">xxxxUSER</Username>
<Password xsi:type="xsd:string">xxxxPASSWORD</Password>
<DBAlias xsi:type="xsd:string">xxxxDBALIAS</DBAlias>
</q3:TBMDPlainText>
</soap:Body>
</soap:Envelope>
Problem
I simply cannot figure out how to construct this XML using https://www.npmjs.com/package/soap. The part, where ALoginRequest is within the Login element, while everything else is outside of it, confuses me.
Efforts
When I try this: const login = await client.LoginAsync({ALoginRequest: {Auth: {TBMDPlainText: auth}}}), I get the following output.
<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tns="http://www.bmd.at/" xmlns:ns1="http://www.bmd.at/soap" xmlns:ns2="http://www.bmd.at/wws"><soap:Body><tns:Login><ALoginRequest><Auth><TBMDPlainText><Username>xxxx</Username><Password>xxxx</Password><DBAlias>xxxx</DBAlias></TBMDPlainText></Auth></ALoginRequest></tns:Login></soap:Body></soap:Envelope>
Can anyone provide me any hints?

Node-soap consuming delphi soap webservice

I'm using nodejs and node-soap as client to consume a webservice published on iis and developed in delphi. The webservice is published with document/literal style.
On Node I'm invoking and logging the response of the operations like this:
client[functionName](args, function (err, result) {
if (err) {
console.log(err);
} else {
console.log(result);
}
});
Here is a portion of the xml result from delphi:
...
<GetValuesResponse xmlns="urn:WS_TEST">
<res xmlns="urn:UTest">
<matrixData>
<TDoubleDynArray>
<double>4.32427893698308</double>
<double>4.40404718921869</double>
<double>4.50060875771443</double>
<double>4.56778202275494</double>
<double>4.61816197153533</double>
<double>4.73991351442126</double>
<double>4.78609513413661</double>
<double>4.8238800957219</double>
<double>4.8238800957219</double>
<double>4.81128510852681</double>
...
And this is the json obtained from node-soap (response):
...
"matrixData": {
"TDoubleDynArray": [
{
"double": [
"4.32427893698308",
"4.40404718921869",
"4.50060875771443",
"4.56778202275494",
"4.61816197153533",
"4.73991351442126",
"4.78609513413661",
"4.8238800957219",
"4.8238800957219",
"4.81128510852681",
...
I dont understand why node-soap includes the types of the data in the structure of the resulting json. Also, I don`t understand why arrays are parsed to json like an object with an array inside, instead of just an array.
Is there any way to ask node-soap just to include the data and the arrays just like simple arrays?
Here is the wsdl portion with the defines involved:
<element name="matrixData" type="ns6:TMatOfDouble"/>
<complexType name="TMatOfDouble">
<complexContent>
<restriction base="soapenc:Array">
<sequence/>
<attribute ref="soapenc:arrayType" n1:arrayType="ns1:TDoubleDynArray[]"/>
</restriction>
</complexContent>
</complexType>
<complexType name="TDoubleDynArray">
<complexContent>
<restriction base="soapenc:Array">
<sequence/>
<attribute ref="soapenc:arrayType" n1:arrayType="xs:double[]"/>
</restriction>
</complexContent>
</complexType>
Thanks in advance for any help
It result to be a bug in the node-soap library so we are trying to fix it.

Using Smooks or Groovy with Java Camel to split/transform XML

Camel version 2.14 Smooks version 1.5.1
I got a message which i want to split and transform, but i need the id from the parent. So I thought about using Smooks, splitting the message, transforming and send each output to a queue. Which will be using freemarker template for the transform.
<!-- Message -->
<data>
<id>123</id> <!-- This is needed in both portal messages -->
<portals>
<portal id="1" />
<portal id="2" />
</portals
</data>
<!-- Msg 1 -->
<portal dataId="123">
<id>1</id>
<portal>
<!-- Msg 2 -->
<portal dataId="123">
<id>2</id>
<portal>
There are plenty of examples. But for example the camel examples does not work, due to "java.lang.ClassNotFoundException: org.apache.camel.component.ResourceBasedComponent" which is a known issue.
An alternative would be using groovy for transformation?
So, how could this easiest be solved?
I don't know about smooks, but you can combine the XSLT transformer with a XPATH splitter to do this.
First, transform the data into the blocks that should make up each message. Do it using XSLT, groovy or whatever you feel comfortable with. Here is a simple stylesheet, to be put into src/main/resources (or any classpath location).
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
<portals>
<xsl:variable name="dataId" select="/data/id"/>
<xsl:for-each select="/data/portals/portal">
<portal dataId="$dataId">
<xsl:attribute name="dataId">
<xsl:value-of select="/data/id"/>
</xsl:attribute>
<id><xsl:value-of select="#id"/></id>
</portal>
</xsl:for-each>
</portals>
</xsl:template>
The Camel route: First the transform, then splitter. The "to" can be whatever, like a seda/direct for further processing or the target protocol.
<camelContext xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="file:data"/>
<to uri="xslt:transform.xslt"/>
<split>
<xpath>portals/portal</xpath>
<to uri="log:foo.bar?level=INFO"/>
</split>
</route>
In groovy it can be done this way:
import groovy.util.XmlSlurper
import groovy.xml.MarkupBuilder
def xml = """
<data>
<id>123</id>
<portals>
<portal id="1" />
<portal id="2" />
</portals>
</data>
"""
def slurped = new XmlSlurper().parseText(xml)
def msgId = slurped.id
def portalIds = slurped.portals.portal.#id*.text()
def portalXmls = portalIds.collect { portalId ->
writer = new StringWriter()
portalXml = new MarkupBuilder(writer)
portalXml.doubleQuotes = true
portalXml.portal(dataId: msgId) {
id(portalId)
}
writer
}.each { println it.toString() }
null

Spring Integration - how to keep the orginal payload and use it later?

I would like to keep the original payload of the original requests and ise it in a xslt-transformer or in other operation. I lose it because I use an xslt-transformer and I need just some of the elements in the transformation. So my scenario is:
1.inbound-gateway (incoming WS req) -> 2.xslt-transformer (mapping for calling an external WS) -> 3.outbound-gateway (calling the external WS) -> 4.xslt-transformer (creating response from the resp. of the external WS and the original req)
At the 4th step I don't have the original req but I'd need it as I have to put values from it to the response. How could I implement it?
Thanks,
V.
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:int="http://www.springframework.org/schema/integration" xmlns:int-ws="http://www.springframework.org/schema/integration/ws" xmlns:int-xml="http://www.springframework.org/schema/integration/xml" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/integration/ws http://www.springframework.org/schema/integration/ws/spring-integration-ws.xsd http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/integration/xml http://www.springframework.org/schema/integration/xml/spring-integration-xml.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
<bean id="authenticator" class="uk.co.virginmedia.test.Authenticator"/>
<bean id="webserviceDestinationProvider" class="uk.co.virginmedia.test.WebserviceDestinationProvider"/>
<bean id="resultToDocumentTransformer" class="org.springframework.integration.xml.transformer.ResultToDocumentTransformer"/>
<util:map id="orderNamespaceMap">
<entry key="res" value="http://schema/ReserveAppointment/2/0" />
</util:map>
<int-ws:inbound-gateway id="ws-gateway-for-rbta" request-channel="incoming-req-channel" reply-channel=""/>
<int:channel id="incoming-req-channel"/>
<int:service-activator id="authentication" input-channel="incoming-req-channel" ref="authenticator" method="authenticate" output-channel="authenticated-channel" />
<int:channel id="authenticated-channel"/>
<int-xml:xpath-router id="servicetype-router" input-channel="authenticated-channel" evaluate-as-string="true">
<int-xml:xpath-expression expression="//res:ReserveAppointmentRequest/res:serviceType/text()" ns-prefix="res" ns-uri="http://schema/ReserveAppointment/2/0"/>
<int-xml:mapping value="Broadband" channel="broadband-channel"/>
<int-xml:mapping value="FTTC+WholesaleLineRental" channel="fttc-wlr-channel"/>
</int-xml:xpath-router>
<int:channel id="broadband-channel"/>
<int-xml:xslt-transformer id="req_for_bt_xslt_transformer" input-channel="broadband-channel" output-channel="domresult_for_bt_channel" xsl-resource="classpath:/xsl/ToBTReq.xsl" result-type="StringResult"/>
<int:channel id="domresult_for_bt_channel"/>
<int:transformer input-channel="domresult_for_bt_channel" output-channel="document_for_bt_channel" expression="payload.toString()"/>
<int:channel id="document_for_bt_channel"/>
<int-ws:outbound-gateway request-channel="document_for_bt_channel" reply-channel="resp_from_bt_channel" destination-provider="webserviceDestinationProvider" id="call_bt-outbound_gateway" />
<int:channel id="resp_from_bt_channel"/>
<int-xml:xslt-transformer id="resp_for_rbta_xslt_transformer" input-channel="resp_from_bt_channel" output-channel="resp_for_rbta_channel" xsl-resource="classpath:/xsl/ToBTReq.xsl" result-type="StringResult"/>
Since your original message is just text you could copy it to a header field. This should work as long as you don't do anything special in between when you store and afterwards retrieve it.
So what I would try is:
<int:header-enricher input-channel="authenticated-channel" output-channel="pre-routing-channel">
<int:header name="original-payload" expression="payload.toString()" />
</int:header-enricher>
<!-- changed input channel of router -->
<int-xml:xpath-router id="servicetype-router" input-channel="pre-routing-channel" evaluate-as-string="true">
If this is not working for you (maybe because you have to do something more special in between or the payload is too big), you still have the option to use a ClaimCheck. Which is actually exactly what you are asking for. For this you'll need a MessageStore and then just store the message payload before modifying it. So instead of the header-enricher you will call
<int:claim-check-in input-channel="authenticated-channel" output-channel="pre-routing-channel" message-store="payloadstore" />
<!-- MessageStore definition storing payload using in memory map -->
<bean id="simpleMessageStore"
class="org.springframework.integration.store.SimpleMessageStore"/>

Threading issues with Hibernate

I'm experiencing a strange behaviour with Hibernate. I've been banging my head against the wall for a while now, and will award any answer which leads to a solution with a +100 bounty.
I have a JAX-RS (Jersey) REST server, with a filter that associates one Hibernate-session per request.
In one request a client POSTs some data which is stored in the database using one session (and one transaction). In a subsequent call, the client tries to GET this entity, but Hibernate can't find it.
Some observations:
I can only reproduce this if I run multiple simultaneous clients. I've never managed to reproduce it by running one client at a time.)
I can see the entity ID in the database, and if I restart the server, the entity is found by Hibernate as it should.
The error does not occur if I use a thread pool of size 1 (regardless of how many clients I run simultaneously).
Here's the code, with some logging:
chargeables.setId(new SecureRandom().nextLong());
System.out.printf("%s, session: %s [%s]%n",
Thread.currentThread(),
System.identityHashCode(session),
"session.beginTransaction()");
session.beginTransaction();
System.out.printf("%s, session: %s [%s]%n",
Thread.currentThread(),
System.identityHashCode(session),
"session.save(id = "+chargeables.getId()+")");
session.save(chargeables);
System.out.printf("%s, session: %s [%s]%n",
Thread.currentThread(),
System.identityHashCode(session),
"session.getTransaction().commit()");
session.getTransaction().commit();
The code for getting the entity:
System.out.printf("%s, session: %s [%s]%n",
Thread.currentThread(),
System.identityHashCode(session),
"session.get("+id+")");
Chargeables entity = (Chargeables) session.get(Chargeables.class, id);
if (entity == null)
System.out.printf("%s, session: %s [%s]%n",
Thread.currentThread(),
System.identityHashCode(session),
"ENTITY NOT FOUND!");
Now here is an excerpt of the resulting log (with some additional open/close session output):
Thread[Grizzly(5),5,main], session: 2041842357 [factory.openSession()]
Thread[Grizzly(5),5,main], session: 2041842357 [session.beginTransaction()]
Thread[Grizzly(5),5,main], session: 2041842357 [session.save(id = 7939229356942262438)]
Thread[Grizzly(5),5,main], session: 2041842357 [session.getTransaction().commit()]
Thread[Grizzly(5),5,main], session: 2041842357 [session.close()]
[...]
Thread[Grizzly(7),5,main], session: 1717445911 [factory.openSession()]
Thread[Grizzly(7),5,main], session: 1717445911 [session.get(7939229356942262438)]
Thread[Grizzly(7),5,main], session: 1717445911 [ENTITY NOT FOUND!]
Thread[Grizzly(7),5,main], session: 1717445911 [session.close()]
Why on earth do I reach ENTITY NOT FOUND!?
Hibernate version: 4.1.9.Final
MySQL verison: 14.14 Distrib 5.5.29
Mapping file for Chargeables:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping
default-cascade="all"
package="se.package.common.chargeables"
default-lazy="false">
<class name="Chargeables">
<id name="id" type="long">
<generator class="assigned"/>
</id>
<property name="startTimeStamp" />
<property name="endTimeStamp" />
<list name="chargeables">
<key column="chargeableId" />
<list-index column="pos" />
<many-to-many class="Chargeable"/>
</list>
</class>
<class name="Chargeable">
<id column="id" type="long">
<generator class="native"/>
</id>
<discriminator />
<property name="timestamp" />
</class>
<subclass name="DataTransfer" extends="Chargeable">
<property name="bytesSent" />
<property name="bytesReceived" />
</subclass>
<subclass name="TelephonyChargeable" extends="Chargeable">
<many-to-one name="num" />
</subclass>
<subclass name="Call" extends="TelephonyChargeable">
<property name="duration" />
</subclass>
<subclass name="OutgoingCall" extends="Call" />
<subclass name="IncomingCall" extends="Call" />
<subclass name="Message" extends="TelephonyChargeable" />
<subclass name="Sms" extends="Message" />
<subclass name="IncomingSms" extends="Sms" />
<subclass name="OutgoingSms" extends="Sms" />
<subclass name="Mms" extends="Message" />
<subclass name="IncomingMms" extends="Mms" />
<subclass name="OutgoingMms" extends="Mms" />
</hibernate-mapping>
IMHO it's an isolation problem. Your second session start before the transaction of the 1st one is commited. As default hibernate isolation level is read_commited, the 2nd session can't so retrieve the entity. How are you passing id between the 2 threads ?
If you can see the commit in the database, it cannot be an isolation issue at the MySQL level: console operations are also client operations, you don't get special powers when running them, so they conform to the isolation policy you selected.
Looking out for solution, I discovered that Hibernate provide some facilities to cache DB results: there are actually 2 levels of cache implemented there. Perhaps your hibernate installation comes bundled with a cache mechanism?
The first level works on a per session basis, which is consistent with the behaviour you observe when running the code on one thread, and seemingly happens to be activated by default. I am not Hibernate proficient, I can't say that for sure, but my opinion is that your setup has this first level of cache set in read-only mode, while you would like it to be in read-write mode.

Resources