For a BizTalk WCF-SQL adapter in Solicit-Response Send port. How to let adapter handle the response data like XmlPolling? - sql

For a SP using For Xml returns a xml as response, If this sp was consumed by a WCF receive location, we can specify the Polling as XmlPolling to let adapter keep the responsed xml "as-is". But for a wcf-sql Solicit-Response Send port, It seems no same way to do it. Currently, the best result I can get is let adapter treat the xml response as a CDATA. Like below:
<usp_MySPResponse xmlns="http://schemas.microsoft.com/Sql/2008/05/TypedProcedures/dbo">
<StoredProcedureResultSet0>
<StoredProcedureResultSet0 xmlns="http://schemas.microsoft.com/Sql/2008/05/ProceduresResultSets/dbo/usp_MySP">
<UnNamedColumn0><![CDATA[ <!-- The XML content of sp returned goes here -->
....

Assuming the Stored Procedure uses the FOR XML clause, there are two binding properties you must set for the result to be recognized as Xml:
XmlStoredProcedureRootNodeName
XmlStoredProcedureRootNodeNamespace
It's these two properties that tell the Adapter it's a FOR XML Stored Procedure. These are essentially the same as the legacy SQL Adapter.
Details here: http://msdn.microsoft.com/en-us/library/dd787898.aspx
There is no way around this so your BizTalk Schema must match these values.

Reading the link https://learn.microsoft.com/en-us/biztalk/adapters-and-accelerators/adapter-sql/execute-stored-procedures-having-a-for-xml-clause-in-sql-server-using-biztalk carefully, it says that the request schema must be generated selecting from "Procedures", undeniably not "TypedProcedures". The request message will therefore be in the namespace http://schemas.microsoft.com/Sql/2008/05/Procedures/dbo which is not explicitly mentioned in
https://learn.microsoft.com/en-us/biztalk/adapters-and-accelerators/adapter-sql/message-schemas-for-procedures-and-functions but the action for a "for xml"-typed procedure is specified there. To summarize: A request message is thus:
<YOURSPNAME xmlns="http://schemas.microsoft.com/Sql/2008/05/Procedures/dbo" />
and the port configuration action header is
<BtsActionMapping xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Operation Name="YOURSPNAME" Action="XmlProcedure/dbo/YOURSPNAME" />
</BtsActionMapping>
Note the discrepancy between the request message's namespace and the operation action, only the action has "Xml" in it. And don't forget to specify the (FOR XML) binding parameters, as answered by Johns-305.

Related

how to pass an attribute over ActiveMQ in Mule 4

We are migrating from Mule 3 to Mule 4 and in one of our functionalities we need to publish messages to a topic and downstream another mule component is consuming from the queue which is bridged to the topic.
Nothing special here .
To ensure we are able to trace the flow via logs we were sending a 'TrackingId' attribute while publishing messages to the topic ( Mule 3 )
message.setOutboundProperty("XYZ_TrackingID", flowVars['idFromUI']);
return payload;
However when I try the same in Mule 4 we get the following exception :
ERROR 2020-12-20 10:09:12,214 [[MuleRuntime].cpuIntensive.14: [mycomponent].my_Flow.CPU_INTENSIVE
#66024695] org.mule.runtime.core.internal.exception.OnErrorPropagateHandler:
Message : groovy.lang.MissingMethodException: No signature of method:
org.mule.runtime.api.el.BindingContextUtils$MessageWrapper.setOutboundProperty() is applicable for
argument types: (java.lang.String, org.mule.weave.v2.el.ByteArrayBasedCursorStream) values:
[XYZ_TrackingID, "1234567"].\nError type : (set debug level logging or '-
Dmule.verbose.exceptions=true' for
everything)\n********************************************************************************
Checked internet and it seems in Mule4 setting outbound properties is removed as per here
So how do I achieve the same in Mule 4 ?
Don't even try to do that for several reasons. For one message structure is different, so output properties doesn't exist anymore and that method doesn't even exists. On the other hand, in Mule 4 components like the Groovy component can only return a value and cannot change the event. They can not decide to what that value is going to be assigned. You can set the target in the configuration (payload or a variable) and not change the attributes. Note that variables in Mule 4 are referenced by var., not by flowVars. like in Mule 3 (ie vars.idFromUI).
There is a simpler way to set message properties in the Mule 4 JMS connector. Use the properties element and pass it an object with the properties.
For example it could be something like this:
<jms:publish config-ref="JMS_config" destination="${bridgeDestination}" destinationType="TOPIC">
<jms:message>
<jms:body>#["bridged_" ++ payload]</jms:body>
<jms:properties>#[{
XYZ_TrackingID: vars.idFromUI
}]</jms:properties>
</jms:message>
</jms:publish>
It is in the documentation: https://docs.mulesoft.com/jms-connector/1.0/jms-publish#setting-user-properties. I adapted my example from there.
I am not sure if Correlation Id serves the purpose of a tracking ID for your scenario. But you can pass a CID as below. It's there in the mule documentation.
https://docs.mulesoft.com/jms-connector/1.7/jms-publish
<jms:publish config-ref="JMS_config" sendCorrelationId="ALWAYS" destination="#[attributes.headers.replyTo.destination]">
<jms:message correlationId="#[attributes.headers.correlationId]"/>
</jms:publish>
If your priority is to customise the Tracking ID you want to publish, then try passing below format. The key names may differ as per your use case.
<jms:publish config-ref="JMS_config" destination="${bridgeDestination}" destinationType="TOPIC">
<jms:message>
<jms:body>#["bridged_" ++ payload]</jms:body>
<jms:properties>#[{
AUTH_TYPE: 'jwt',
AUTH_TOKEN: attributes.queryParams.token
}]</jms:properties>
</jms:message>
</jms:publish>
In the above the expression attributes.queryParams.token is basically trying to access a token query parameters which is passed to JMS as a property AUTH_TOKEN key-name , consumed by the API through a HTTP Listener or Requestor earlier.
However, attributes.headers.correlationId is a header. Both queryParams and headers are part of attributes in Mule 4.

How can I get WebMock to match a body containing specific XML data using hash_including?

I have a Ruby (2.6.5) on Rails (5.2.3) application which is already successfully using Savon (2.12) to interact with FlightAware's FlightXML 2 API via SOAP/WSDL. However, I'm running into an issue while attempting to write Minitest tests for this functionality, using WebMock (3.7.6) to stub out the API requests.
My application (via Savon) makes a request including an XML body like the following example:
<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:FlightXML2="http://flightxml.flightaware.com/soap/FlightXML2" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
<env:Body>
<FlightXML2:AirportInfoRequest>
<FlightXML2:airportCode>KDFW</FlightXML2:airportCode>
</FlightXML2:AirportInfoRequest>
</env:Body>
</env:Envelope>
I would like to use a with statement so that the stub only responds to a request having a specific airport code in the element. For example, if I'm looking for "KDFW", then a request containing <FlightXML2:airportCode>KDFW</FlightXML2:airportCode> should match, but a request containing <FlightXML2:airportCode>CYYZ</FlightXML2:airportCode> should not.
Right now, I have it working by including the XML tag in a regular expression:
icao_code = "KDFW"
response_body = "[the response I want]"
WebMock.stub_request(:post, "http://flightxml.flightaware.com/soap/FlightXML2/op").
with(body: /<FlightXML2:airportCode>#{icao_code}<\/FlightXML2:airportCode>/).
to_return(status: 200, body: response_body)
This feels like a kludge, especially when the documentation for WebMock mentions that I can use hash_including to match XML tags. No matter what I try, though, I get the typical WebMock unregistered request error, indicating that I don't match the request. Here are the with statements that I've tried so far:
with(body: hash_including({airport_code: icao_code})
with(body: hash_including({"airportCode": icao_code})
with(body: hash_including({"FlightXML2:airportCode": icao_code})
How can I match a specific XML element without having to resort to putting the XML tag in a regular expression?
Match the request against a block:
stub_request(:post, "http://flightxml.flightaware.com/soap/FlightXML2/op")
.with do |request|
# do something
end.to_return(status: 200, body: response_body)
The block code could look something like:
request_xml = Nokogiri::XML(request.body)
request_xml.xpath("//FlightXML2:airportCode").any? do |node|
node.content == icao_code
end
This approach has an additional advantage in that you can insert a debugger into the above code block and figure out why your test case isn't working. You can see Webmock docs here.

Parsing XML Response In GateWayScript

Hi i am new to API connect ... i have a use case where i have to merge responses coming from two endpoints in XML format based on certain conditions.
My flow in the assemble section is like this
1) INVOKE
(i make my
first service call
and capture the response
in a custom 'Response
object varibale' -XMLResponse1
2) INVOKE
(i make my
second service call
and here i am not using any
custom 'Response object varibale'
Instead i am using apim.getvaribale('message.body') to get the response
3)GATEWAYSCRIPT
Here i want to write my script for parsing the xml and merging the two responses
and send back the merged response to the consumer
I observed that the xml response is not getting captured in a custom Response object variable when i try to capture it like below
var test1= apim.getvariable('XMLResponse1');
test1.item(0).childNodes
it throws me an exception like this
test1.item is not a function
now for the second response like below where i am not capturing the response in a custom Response object variable it works well
var test2= apim.getvariable('message.body');
My question:
1)How do i capture the xml responses in a custom Response object variable?
2)How can i parse the response into a javascript object? are there any libraries supported in api connect?
Below is the samples found from IBM community. Hope this may help you.
**** Sample XML ****
<Routing>
<partner name="Partner A" key="1">
<from_ID>PartnerA-KEY1-INT</from_ID>
<to_ID>PartnerA-KEY1-EXT</to_ID>
<destination>PartnerA-KEY1-DESTINATION</destination>
</partner>
<partner name="Partner B" key="2">
<from_ID>PartnerB-KEY2-INT</from_ID>
<to_ID>PartnerB-KEY2-EXT</to_ID>
<destination>PartnerB-KEY2-DESTINATION</destination>
</partner>
<partner name="Partner C" key="3">
<from_ID>PartnerC-KEY3-INT</from_ID>
<to_ID>PartnerC-KEY3-EXT</to_ID>
<destination>PartnerC-KEY3-DESTINATION</destination>
</partner>
</Routing>
**** Corresponing Gateway Script *****
var response = apim.getvariable('XMLResponse1.body');
var objType = response.item(0);
var string = objType.getElementsByTagName("partner").item(0).getElementsByTagName("from_ID").item(0).textContent;
output ---> string = PartnerA-KEY1-INT
Why do you want to merge them in a GatewayScript node??
You could merge them in a mapping node, in wich you have 2 variables as input (refered to the output objects of your invokes) and one XML object as output...
If you have to apply some conditions or comparisons, you could do them in the code part of the mapping nodes

How to add custom XML element to Message using PacketInterceptor in Openfire plugin using XMPP

I want to add custom XML to an incoming message packet. To do that as part of plugin implementation I have written a PacketInterceptor, which intercepts the message and adds an extension. Till this point everything is fine but when this message is received by the receiver, the information stored in custom xml is striped off. Only the xml element with namespaces is shown.
Incoming messages are regular text messages as shown below-
<message to='18#mcasax01/SomeResource' from='myroom#conference.mcasax01/testbot2' id='63S0G-27' type='groupchat'>
<body>Hi</body>
</message>
When I add custom XML to this message body, it looks as below after adding the XML in PacketInterceptor logs-
<message to='18#mcasax01/SomeResource' from='myroom#conference.mcasax01/testbot2' id='63S0G-27' type='groupchat'>
<body>Hi</body>
<data value="imgURL1"/>
</message>
But when this message is received by the receiver the value attribute in data is striped off and below message is received by the participant -
<message to='17#mcasax01/SomeResource' from='myroom#conference.mcasax01/testbot2' id='63S0G-27' type='groupchat'>
<body>Hi</body>
<data xmlns='jabber:client'></data>
</message>
Please note that both the text and attributes are getting stripped off from data XML node.
Below is java code snippet for your reference
public void interceptPacket(Packet packet, Session session, boolean incoming, boolean processed) throws PacketRejectedException {
// Some code
Message messagePacket = (Message) packet;
Document document = DocumentHelper.createDocument();
Element root = document.addElement("data");
Element root1 = root.addAttribute("value", "imgURL1");
PacketExtension pe = new PacketExtension(root1);
messagePacket.addExtension(pe);
}
When implementing the interceptPacket method you need to pay careful attention to the different parameters. The same XMPP packet will be intercepted multiple times. Make sure you are only intercepting incoming packets that are not processed. You do this by writing a conditional on the boolean values passed to the method.
As for ensuring the XML is created properly, you should use the addChildElement method not the addExtension method on the Message object.
I've successfully used the addChildElement method before to add a timestamp to the XMPP message before it is sent to the receiver. The API for addChildElement is straightforward and avoids you having to create an entirely new document.

after receiving soap response modify xml and send to anther service using http adapter

while using http adapter I need to call first service that return XML,
after receiving the response I want to change values and send back to anther service,
how can I do it ?
do http adapter has json to xml function ?
WL adapter will automatically convert XML to JSON for you, however it doesn't have any manual JSON<->XML conversion APIs.
In your case possible solution might be to retrieve XML as plaintext by supplying returnedContentType:"plain" in invocation options. Alter whatever you need using regex/string replace. Use resulting string in 2nd procedure invocation as post body.
Alternatively, you can use 3rd party library to parse/convert/do whatever you need with XML, e.g. http://www.json.org/java/ (more info about how to use it in your adapter - http://public.dhe.ibm.com/software/mobile-solutions/worklight/docs/v506/04_08_Using_Java_in_adapters.pdf)
After checking number of solutions, I state the the http result will be a plain text,
then made a call to java function sending the xml as String, and used
javax.xml to hold and alter the XML.
XPath to retrieve the correct node using org.w3c.dom.*
Hope this will help you too.