Nested iterator in wso2 esb skipping all the sequence after completion of second iterator - iterator

I have a situation in my current assignment , I have some xlx files in a ftp server, I am reading it one by one in my first iterator in a proxy service. Inside this iterator I am splitting this xlx file into some csv files and again running a iterator(Inside the first iterator) to read it and do some validation & transformation on the top of it using smooks and XSLT transformer mediator. Now the issue is once the second iterator completes proxy service is skipping all the other sequence that are there in the first iterator and the outside the first iterator and just getting stopped after the second iterator.
Please help me out , is it wso2 esb expected behavior or i am doing some this wrong in my configuration? i googled a lot related to this but not found any solution .

I've implemented the same for a different use case. I wasn't runnning into any issues, so it looks for me like there must be something missing in your configuration.
// first iterator
<iterate xmlns:sfdc="http://wso2.org/salesforce/adaptor"
continueParent="true"
expression="//sfdc:iterator">
<target>
//second interator
<sequence>
<iterate xmlns:ns="http://org.apache.synapse/xsd"
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:sf="urn:sobject.partner.soap.sforce.com"
continueParent="true"
expression="//*[local-name() = 'queryMoreResponse']/*[local-name() = 'result']/*[local-name() = 'records']">
//do something
</iterate>
Hope that helps.

Related

Invalid content error on compression:extract

I am attempting to use the zip-extract method in a foreach loop to unzip several files. When I attempt to deploy the project the following error is returned:
Invalid content was found starting with element 'compression:extract'. One of >'{"http://www.mulesoft.org/schema/mule/core":annotations, >"http://www.mulesoft.org/schema/mule/core":abstract-message-processor, >"http://www.mulesoft.org/schema/mule/core":abstract-mixed-content-message-processor}' is expected.
The actual code is:
<compression:extract doc:name="Extract" doc:id="9119d722-95eb-4aee-a734-50e2a2825449" >
<set-payload value="#[payload]" />
<compression:extractor >
<compression:zip-extractor />
</compression:extractor>
</compression:extract>
I have not been able to find anything online that would point towards a solution.
It look like accidentally a <set-payload> was put inside the <compression:extract> element. Also it doesn't make sense at all because it puts the payload as the payload, which it is already is. Just remove that line.
Maybe the intention was to use <compression-compressed>?
Example:
<compression:extract>
<compression:compressed>#[payload]</compression:compressed>
<compression:extractor>
<compression:zip-extractor/>
</compression:extractor>
</compression:extract>
payload is already the default, so it is not needed.

How to use assertions in soapUI to match with external property

I have a test case containing the test steps below :
(JDBC) LoadTestDataStep
(Transfer) GetPropertyStep
(SOAP) SoapRequestStep
In the LoadTestDataStep i load some data from a JDBC database that i will need later in the 'SoapRequestStep'
The GetPropertyStep allow me to retrieve data from LoadTestDataStep result and put them SoapRequestStep request.
Now in the SoapRequestStep i want to assert that an evaluation of some xpath matches some data i retrieve in the LoadTestDataStep
I hope i made myself understandable.
this the JDBC result :
<Results>
<ResultSet fetchSize="10">
<Row rowNumber="1">
<DRV_DVR_ID>46259976</DRV_DVR_ID>
<CUST_DPT>00025888</CUST_DPT>
</Row>
</ResultSet>
</Results>
And this is the SOAP Result (simplified) :
<chargeCard chargeSequence="1353" businessAccountId="1520444" ownershipType="N" meanOfPaymentCode="EPPV" cashOrChargeFlag="CH" custdept="982-1602"/>
I want to assert that the CUST_DPT from JDBC = the custdept attribute from the soap response.
The problem is that in the SoapStep i cant assert against something external to this soap step
"The problem is that in the SoapStep i cant assert against something external to this soap step" Yes, you can assert against something from another step.
In your step's '(SOAP) SoapRequestStep' script assertion, you can pull in the response of the JDBC step by doing something along the lines of....
def jdbsResponseAsXml = context.expand( '${(JDBC) LoadTestDataStep#ResponseAsXml#//Results[1]}' )
def slurper = new groovy.json.JsonSlurper()
def jdbcJson = slurper.parseText(jdbsResponseAsXml );
With the above steps, you'll have the jdbc result in JSON form in the '(SOAP) SoapRequestStep' script assertion.
You'll then need to find the node of interest and compare.
Additionally, and this is my own preference, I tend not use to script assertions in this way. Instead, after the two steps of interest, I would create a new Groovy script test step and in there I would pull the data from the steps of interest and assert in there.

Nlog variable and log file issue with multiple log files

I created a Log File class that uses NLog with the hopes of writing to multiple log files at the same time. This seems to work fine until I add variables to the mix.
Problem
Changing the variable seems to change that variable setting for all instances of the log file instead of the particular instance I am working with.
My Code
Here is how I have the programming structured:
LogClass - Basically a wrapper to give me some additional functionality. The 'SetVariable' is what I am using to set the particular variable (called dqwAlertName)
With this log class, I am passing in the specific logger that I want to use like this:
Public iLogger as new Logger(NLog.LogManager.GetLogger("dataQualityWatcher"),True)
That statement instantiates the logging class with the "dataQualityWatcher" logger and sets Debug=True (which I simply use to allow a more verbose logging that can be turned on and off).
With that said... The statement above is ALSO within another class object:
dataQualityWatcher Class - This is a 'watcher' that is called many times over and runs continuously. If you familiar with FileSystemWatcher, it works similarly to that. It basically watches data for a specific value and raises an event.
Inside THIS class is where I instantiate the logger as mentioned above with the following code:
Public iLogger as new Logger(NLog.LogManager.GetLogger("dataQualityWatcher"), True)
iLogger.SetVariable("dqwAlertName", _AlertName)
The first line instantiates, the second line will set the variable. The Logging Class SetVariable method is pretty basic:
Public Sub SetVariable(variableName as string, value as String)
'Set variable context for the logger
NLog.LogManager.Configuration.Variables(variableName) = value
End Sub
I am using that variable within the NLog.config file in the following manner:
<variable name="LogLayout" value="[${date:format=MM/dd/yyyy h\:mm\:ss.fff tt}] [${gdc:item=location}] | ${level} | ${message}" />
<variable name="InfoLayout" value="[${date:format=MM/dd/yyyy h\:mm\:ss.fff tt}] ${gdc:item=SoftwareName} Version ${gdc:item=SoftwareVersion} - ${message}" />
<variable name="DebugInfoLayout" value="[${date:format=MM/dd/yyyy h\:mm\:ss.fff tt}] ${message}" />
<variable name="logDir" value="C:/Log/PWTester/" />
<variable name="dqwAlertName" value="" />
<targets>
<target name="dataQualityWatcher" xsi:type="File" fileName="${logDir}/LogFiles/${var:dqwAlertName}-DataQualityWatcher.log" layout="${LogLayout}" />
</targets>
<rules>
<logger name="dataQualityWatcher" minlevel="Trace" writeTo="dataQualityWatcher" />
</rules>
THE PROBLEM:
I run multiple 'watchers' (as I call them) with the following code to create that object and assign properties:
dataWatch.Add(New dataQualityWatcher(True) With {.Tags = lstTags, .AlertTimerInterval = Convert.ToInt64(intTimerMilliseconds), .AlertGroupID = Convert.ToInt64(CARow(0)), .EmailGroupID = Convert.ToInt64(CARow(1)), .CustomSubject = CARow(3), .CustomMessage = CARow(4), .AlertName = DataAlertGroupName, .Debug = blnVerboseLogging, .HistorianServer = SH})
Multiple Version Example
I run the code above where: .AlertName = {"Test1", "Test2", "Test3"}. Other parameters would also change and a new object is instantiated each time. In this example there are 3 dataQualityWatcher objects instantiated, which also instantiates 3 Logger objects.
Each time a new dataQualityWatcher object is instanciated, it instanciates a Logger, which would then write to the file. The AlertName variable is passed on through the SetVariable method above.
I would expect 3 log files to be written:
Test1-DataQualityWatcher.log
Test2-DataQualityWatcher.log
Test3-DataQualityWatcher.log
This DOES happen. However, the last dataQualityWatch object that is created will run the SetVariable method = "Test3" (in this example). Now that variable is set and all 3 Loggers will begin logging to that file (i.e., Test3-DataQualityWatcher.log).
I can only assume that there is a better way to do this with variables such that they are for the life of that particular log instance, but I can't seem to figure it out!
Thanks in advance and sorry for the VERY, VERY long post.
As far as I understand your are trying to log to multiple files, with one target.
This won't work well with the use of variables as they are static (Shared in VB.net) - so this isn't threadsafe.
Other options to do this are:
Create multiple file targets in your nlog.config and setup the right <rules>, or
Pass extra properties for every message, and use event-properties: fileName="${logDir}/LogFiles/${event-properties:dqwAlertName}-DataQualityWatcher.log", VB.NET call:
Dim theEvent As New LogEventInfo(LogLevel.Debug, "", "Pass my custom value")
theEvent.Properties("MyValue") = "My custom string".
You could write a sub class for Logger to make it less verbose. Or
Create the targets & rules programmatically (in VB.NET). See tutorial (in C#)
If performance is very important, choose for 1 or 3.

Recursively invoke a Mule flow

Trying to figure out the proper way to recursively invoke a Mule flow.
We have a flow that builds an array of work to do as it runs, then recursively calls itself using a "Flow Reference" inside a "For Each" block. Problem is, we haven't figured out the correct way to pass parameters to this recursive flow, so we're not getting the results we expect.
We tried passing parameters using flow properties (setInvocationParameter() in Groovy), but it seems that these are shared across multiple instances of the flow.
For an example, we have the ForEach array iterating through an array containing [2. 3. 4], but depending on timing, some of these values are lost (we typically see 2, then 4 twice - skipping 3).
We've tried different Mule processing strategies without any luck. Mule's default queued-asynchronous has the issues described above. Synchronous doesn't seem to work at all (makes sense since our recursive model probably requires two instances to run at minimum).
Here's the relevant part of the configuration XML (the entire flow is quite large). At the end of the flow is this:
<foreach collection="#[sessionVars['actionArray']]"
counterVariableName="actionIndex"
rootMessageVariableName="actionVar" doc:name="For Each">
<scripting:component doc:name="Run Each Action">
<scripting:script engine="Groovy">
<![CDATA[def aa = message.getSessionProperty('actionArray')
def this_item = aa.get(message.getInvocationProperty('actionIndex'))
// Pass the desired action for the recursive call
message.setInvocationProperty('FlowAction', this_item)
log.info "Running $this_item" // <- Shows the correct item
return]]>
</scripting:script>
</scripting:component>
<flow-ref name="DoAction" doc:name="Do Action"/>
</foreach>
At the front of the flow, there's a logger that displays the "FlowAction" flow variable. When we test with my [2, 3, 4] array, this logger statement is driven three times (as expected), but usually with values 2, 4 and 4.
We're getting the same results on Mule 3.7 and an older 3.4 system we have (both are the Community Edition).
Thanks for any suggestions from the Mule mavens out there...
I'm not sure this is 100% correct, but here's what we did...
After spending a lot of time trying to get the "For Each" and "Flow reference" approach to work reliably, we gave up and switched to a different technique. Our alternative was to delete the For Each block and drive the flow recursively from a short Groovy script:
. . .
// Invoke the flow recursively for every item in the array
Flow flow = muleContext.getRegistry().lookupFlowConstruct("flow name")
actions.each // actions is an array of integers built earlier
{ item->
MuleMessage msg = message.createInboundMessage()
DefaultMuleSession sess = new DefaultMuleSession(flow, muleContext)
DefaultMuleEvent event = new DefaultMuleEvent(msg, MessageExchangePattern.ONE_WAY, sess)
// Copy the current inbound properties to the new message
message.getInboundPropertyNames().each
{
event.getMessage().setProperty(it, message.getInboundProperty(it), PropertyScope.INBOUND)
}
// Copy the current session variables to the new message too
message.getSessionPropertyNames().each
{
event.setSessionVariable(it, message.getSessionProperty(it))
}
// Now set the item we want processed as a flow variable
event.setFlowVariable("Action", item.toString())
// Finally, trigger the flow (which runs asynchronously)
flow.process(event).getMessage()
}
This is working properly in our environment now.

Mule ESB 3 not getting port value from property file

In my configuration file, I have this...
<spring:beans>
<context:property-placeholder
location="classpath:sbg-esb.properties" />
</spring:beans>
My properties file looks like this...
# Primary endpoint
esb.endpoint=localhost
esb.port=8081
The endpoint in the config file looks like this...
<http:inbound-endpoint exchange-pattern="request-response" host="${esb.endpoint}" port="${esb.port}" doc:name="Incoming localhost"/>
When starting the Mule Server I get the following error...
Invalid bean definition with name 'sbg-mobile-direction-flow' defined in null: Could not resolve placeholder 'esb.port' in string value "${esb.port}
I don't get any error if all I do is use the esb.endpoint value in the properties file. Once I put in the esb.port value the server breaks as described. Is there a problem with integer values? Am I screwing up the properties file somehow? I thought perhaps using "port" was messing it up but I changed the name to esb.esb.port-like-thing and that got the same error. Any help would be appreciated.
MORE INFO
I took the port out of the properties file. I added the following.
esb.wsdlLocation=http\://dev.example.com/services/Mobile/LinkDevice/soap_server.php?wsdl
The Server breaks with the same error. That would seem to mean that whatever is wrong doesn't have anything to do with port value itself. No properties after the first one are being read correctly.