I have following xml response out of a transformer:-
<?xml version="1.0" encoding="UTF-8"?>
<detailList>
<details>
<Id>ID123</Id>
<personInfo>
<address>
<address>All the address</address>
<city>CITY</city>
<state>STATE</state>
<postalCode>123123</postalCode>
<country>UNITED STATES</country>
</address>
</personInfo>
<nameF>NAME1</nameF>
<nameL>NAME2</nameL>
</details>
</detailList>
I want to obtain the details node (including all of its child nodes).
I have used following xpath expressions to get this but all of them are printing blank spaces :-
<logger level="INFO" message="#[xpath://detailList]" />
<logger level="INFO" message="#[xpath:/detailList]" />
<logger level="INFO" message="#[xpath:/detailList/*]" />
<logger level="INFO" message="#[xpath://detailList/details]" />
<logger level="INFO" message="#[xpath:/detailList/details]" />
The response that gets printed is (blank space after LoggerMessageProcessor) :-
INFO TimeStamp org.mule.api.processor.LoggerMessageProcessor:
Everything looks fine but I am puzzled why it is not able to locate the node(s)/element(s) through these xpath evaluators.
Assume you are using 3.5+ (else use Xpath3()). You can use splitter, soon after that dont keep logger it would provide you empty result like below org.dom4j.tree.DefaultElement#22a76cce [Element: <details attributes: []/>]. So use any transformer which is required `dom to xml', followed by logger will provide the details value. If you dont use splitter, use expression component or whatever you are currently using.
<splitter expression="#[xpath('/detailList/details')]" doc:name="Splitter"/>
<mulexml:dom-to-xml-transformer doc:name="DOM to XML"/>
<logger message="****Logger:#[payload]" level="INFO" doc:name="Logger"/>
The XPATH you are trying is old and depriciated
You can extract all the values easily using the new Mule XPATH3 :- https://developer.mulesoft.com/docs/display/current/XPath
for example :-
<splitter expression="#[xpath3('//detailList/details', message.payload, 'NODESET')]" doc:name="Splitter"/>
<logger level="INFO" message=" #[xpath3('Id', payload, 'STRING')]" doc:name="Logger"/>
<logger level="INFO" message=" #[xpath3('personInfo/address/address', payload, 'STRING')]" doc:name="Logger"/>
and so on ..
Related
I am working on a custom policy in mule 3. When I am using message-filter inside mule:choice, on onUnaccpted, execution of next statement DOES NOT stop.
if I do not use mule:choice, execution of next statement stop on onUnaccepted in message-filter.
I need to use message-filter in mule:choice, can you please let me know how to stop next statement execution on message-filer onUnaccepted.
I have provided example below:
Case 1:
<before>
<mule:logger level="INFO" message="Logger 0"/>
<mule:message-filter onUnaccepted="policyViolation">
<mule:expression-filter expression="true==false" />
</mule:message-filter>
<mule:logger level="INFO" message="Logger 1"/>
</before>
<mule:processor-chain name="policyViolation">
<mule:logger message="The custom policy filtered the message #[message.getId()] based on a MEL query" level="DEBUG" />
<mule:set-property propertyName="http.status" value="403"/>
<mule:set-property propertyName="Content-Type" value="application/json"/>
<mule:set-payload value='{ "error" : "Custom Policy: {{ denied-message }}"}'/>
</mule:processor-chain>
Output: 403 - {"error": "Custom Policy: Access denied"}
and DOES NOT log message Logger 1.
execution breaks when onUnaccepted
Case 2:
<before>
<mule:logger level="INFO" message="Logger 0"/>
<mule:choice>
<mule:when expression="true==false" >
<mule:logger level="INFO" message="Logger 1"/>
</mule:when>
<mule:otherwise>
<mule:message-filter onUnaccepted="policyViolation">
<mule:expression-filter expression="true==false" />
</mule:message-filter>
</mule:otherwise>
</mule:choice>
<mule:logger level="INFO" message="Logger 2"/>
</before>
<mule:processor-chain name="policyViolation">
<mule:logger message="The custom policy filtered the message #[message.getId()] based on a MEL query" level="DEBUG" />
<mule:set-property propertyName="http.status" value="403"/>
<mule:set-property propertyName="Content-Type" value="application/json"/>
<mule:set-payload value='{ "error" : "Custom Policy: {{ denied-message }}"}'/>
</mule:processor-chain>
Output: 403 - {"error": "Custom Policy: Access denied"}
and LOGS message Logger 2. after message filter onUnaccepted, execution does not break and continues
DO NOT want to print Logger 2.
onUnaccepted doesn't seem to play well with MUnit. I have seen in the past that using filters with onUnaccepted produce unexpected results with MUnit. I recommend to avoid using it at all. I prefer to use Validators, which throw exceptions.
Since WSO2 5.0 supports WebSockets, I have written a simple app following by tutorials:
WebSocket Transport
Sending a Message from a WebSocket Client to an HTTP Endpoint
Here's my source view output from WSO2:
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://ws.apache.org/ns/synapse">
<registry provider="org.wso2.carbon.mediation.registry.WSO2Registry">
<parameter name="cachableDuration">15000</parameter>
</registry>
<taskManager provider="org.wso2.carbon.mediation.ntask.NTaskTaskManager"/>
<sequence name="fault">
<!-- Log the message at the full log level with the ERROR_MESSAGE and the ERROR_CODE-->
<log level="full">
<property name="MESSAGE" value="Executing default 'fault' sequence"/>
<property expression="get-property('ERROR_CODE')" name="ERROR_CODE"/>
<property expression="get-property('ERROR_MESSAGE')" name="ERROR_MESSAGE"/>
</log>
<!-- Drops the messages by default if there is a fault -->
<drop/>
</sequence>
<sequence name="main">
<in>
<!-- Log all messages passing through -->
<log level="full"/>
<!-- ensure that the default configuration only sends if it is one of samples -->
<!-- Otherwise Synapse would be an open proxy by default (BAD!) -->
<filter regex="http://localhost:9000.*" source="get-property('To')">
<!-- Send the messages where they have been sent (i.e. implicit "To" EPR) -->
<send/>
</filter>
</in>
<out>
<send/>
</out>
<description>The main sequence for the message mediation</description>
</sequence>
<sequence name="outDispatchSeq">
<log level="full"/>
<respond/>
</sequence>
<sequence name="dispatchSeq">
<switch
source="get-property('websocket.source.handshake.present')" xmlns:ns="http://org.apache.synapse/xsd">
<case regex="true">
<drop/>
</case>
<default>
<call/>
<respond/>
</default>
</switch>
</sequence>
<!-- You can add any flat sequences, endpoints, etc.. to this synapse.xml file if you do
*not* want to keep the artifacts in several files -->
<inboundEndpoint name="test" onError="fault" protocol="ws"
sequence="dispatchSeq" suspend="false">
<parameters>
<parameter name="inbound.ws.port">9091</parameter>
<parameter name="ws.client.side.broadcast.level">0</parameter>
<parameter name="ws.outflow.dispatch.sequence">outDispatchSeq</parameter>
<parameter name="ws.outflow.dispatch.fault.sequence">fault</parameter>
</parameters>
</inboundEndpoint>
</definitions>
I was able to successfully test it with Nett client:
C:\work\servers\netty>java -Durl=ws://localhost:9091/websocket -DsubProtocol="synapse(contentType='application/xml')" -cp netty-example-4.1.4.Final.jar;lib/*;. io.netty.example.http.websocketx.client.WebSocketClient
WebSocket Client connected!
However if I try to test it from JavaScript code I am getting error like:
Do you know what is wrong in my code?
This issue occurs because SockJS internally trying to load the URL using XMLHttpRequest, but Chrome does not allow accessing cross origin content unless the protocol is one of the aforementioned protocols (In this case it is ws://). I have tried a similar scenario with Firefox and it works fine since it doesn't have this Chrome specific limitation.
In this scenario since WSO2 ESB exposes a WebSocket interface to invoke the HTTP Endpoint, you can use native HTML5 WebSocket implementation as follows.
var url = 'ws://localhost:9091/websocket';
var ws = new WebSocket(url);
ws.onopen = function() {
// todo
}
ws.onmessage = function(e) {
// todo
}
I wanted to write logs in two different files using log4net, one in the global log file while the other for particular user file, for this I set the param in appender like this
<param name="File" value="D:\Projects\Web\Web\Services\Log\%property{LogFileName}" />
And defined a function like this
public void AddInfo(string message)
{
log4net.GlobalContext.Properties["LogFileName"] = this.UserId + ".txt";
log4net.Config.XmlConfigurator.Configure();
Logger.Info(message);
log4net.GlobalContext.Properties["LogFileName"] = "ServiceLog.txt";
log4net.Config.XmlConfigurator.Configure();
Logger.Info(message);
}
This all is working find, every log is written in two different files successfully.
My concern is, is the approach correct if we think about performance?
For each and every log it will configure log4net two times, will it affect performance negatively?
Create two file appenders - one for user log (with pattern for file name), and another for global log:
<appender name="UserFileAppender" type="log4net.Appender.RollingFileAppender">
<file type="log4net.Util.PatternString" value="%property{userId}.txt" />
...
</appender>
<appender name="GlobalFileAppender" type="log4net.Appender.RollingFileAppender">
<file value="log.txt" />
...
</appender>
<root>
<level value="DEBUG" />
<appender-ref ref="UserFileAppender" />
<appender-ref ref="GlobalFileAppender" />
</root>
Then configure log4net only once per user:
GlobalContext.Properties["userId"] = "Bob";
XmlConfigurator.Configure();
And use loggers in your application.
How can I check if my session variable is null or empty in this CHOICE
Its not working for me.
<processor-chain doc:name="Processor Chain">
<choice>
<when evaluator="groovy" expression="#[header:session:countryCode] != ">
<logger message="Valid Country Id" level="INFO" doc:name="Logger"/>
</when>
<otherwise>
<logger message="Invalid Country Id" level="INFO" doc:name="Logger"/>
</otherwise>
</choice>
</processor-chain>
I also tried != '' and != null
If you're using Mule 3.3.x, better use MEL than Groovy:
<when expression="#[org.mule.util.StringUtils.isNotEmpty(sessionVars.countryCode)]">
You are using an invalid groovy expression. It should be:
...
<when expression="message.getProperty('countryCode',org.mule.api.transport.PropertyScope.SESSION)!=null
|| message.getProperty('countryCode',org.mule.api.transport.PropertyScope.SESSION)!=''"
evaluator="groovy">
...
You can also access properties with Header evaluator but I'm not sure if you can evaluate to find out if it is null or empty
here is my nlog.config file. I have turned on the throwsException.
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" throwExceptions="true">
<targets>
<target type="Database" name="databaseLog"
dbProvider="sqlserver" connectionstring="server=.\SQLExpress;database=Movie;integrated security=true">
<commandText>
INSERT INTO [Log] ([Description] , [Level] ) VALUES (#Description, #Level )
</commandText>
<parameter name="#Description" layout="${message}"/>
<parameter name="#Level" layout="${level}"/>
</target>
</targets>
<rules>
<logger name="*" minLevel="Trace" appendTo="databaseLog"/>
</rules>
</nlog>
This will work and will insert records into the database. However I would like to use connectionstringName and not retype the connectionstring.
When I change the connectionstring to connectionstringname like this....
connectionstring="server=.\SQLExpress;database=Movie;integrated security=true"
to
connectionStringName="ApplicationConnectionString"
I get an error
Expecting non-empty string for 'providerInvariantName' parameter
Add System.Data.SqlClient to attribute ProviderName in your connection string in web.config/app.config:
<add name="ApplicationConnectionString"
providerName="System.Data.SqlClient"
connectionString="server=.\SQLExpress;database=Movie;integrated security=true;"/>