Only first when expression works in apache camel choice? - regex

I have this route which check if body begins with "01" or "02" and calls different beans based on that. the problem is that only first one works. for example if I send a message beginning with "01"
it works fine but if my message begins with "02" the otherwise part gets executed and i get the error message with an empty body.
<route id="genericService">
<from uri="servlet:///genericService"/>
<choice>
<when>
<simple>${body} regex "^01.*$"</simple>
<bean ref="cardFacade" method="getBalance" />
</when>
<when>
<simple>${body} regex "^02.*$"</simple>
<bean ref="depositFacade" method="getBalance" />
</when>
<otherwise>
<transform>
<simple>error: ${body}</simple>
</transform>
</otherwise>
</choice>
<marshal>
<json />
</marshal>
<transform>
<simple>${body}</simple>
</transform>
</route>

The problem is the servlet component provides the body as a stream that is only readable once. So you need to either enable stream caching, or convert the message body to a non stream type such as String or byte[].
You can find more details here
http://camel.apache.org/why-is-my-message-body-empty.html
And also see the 1st box on this page
http://camel.apache.org/servlet

I had the same problem in Java DSL (not the compilation issue). What I have to do is add .endchoice() for each and every choice some thing as below:
from(endPointTopic)
.errorHandler(deadLetterChannel)
.log("Message from Topic is ${body} & header string is ${header.Action}" )
.choice()
.when(header("Action").isEqualTo("POST"))
.setHeader(Exchange.HTTP_METHOD, constant("POST"))
.setHeader("Content-Type", constant("application/json"))
.convertBodyTo(String.class)
.to("log:like-to-see-all?level=INFO&showAll=true&multiline=true")
.to(privateApi)
.log("POST request for " + topicName)
.endChoice()
.when(header("Action").isEqualTo("PUT"))
.setHeader(Exchange.HTTP_METHOD, constant("PUT"))
.setHeader("Content-Type", constant("application/json"))
.convertBodyTo(String.class)
.to("log:like-to-see-all?level=INFO&showAll=true&multiline=true")
.to(privateApi)
.log("PUT request for " + topicName)
.endChoice()
.when(header("Action").isEqualTo("DELETE"))
.setHeader(Exchange.HTTP_METHOD, constant("DELETE"))
.setHeader("Content-Type", constant("application/json"))
.convertBodyTo(String.class)
.to("log:like-to-see-all?level=INFO&showAll=true&multiline=true")
.to(privateApi)
.log("DELET request for " + topicName)
.endChoice()
.otherwise()
.setHeader(Exchange.HTTP_METHOD, constant("GET"))
.setHeader("Content-Type", constant("application/json"))
.convertBodyTo(String.class)
.to("log:like-to-see-all?level=INFO&showAll=true&multiline=true")
.to(privateApi)
.log("Un-known HTTP action so posting to GET queue")
.endChoice();

Related

Camunda-Pass parameter between HTTP-CONNECTOR

I want to pass output of one REST API to another REST-API in camunda . My first API is returning JSON which has value of email .
I am getting output from first REST-API using HTTP-CONNECTOR script variable
<camunda:outputParameter name="email">
<camunda:script scriptFormat="JavaScript">var value = S(NUMBER, 'application/json');
print("DATA ::: "+ value);
var response = S(connector.getVariable("response"), 'application/json');
print("Response ::: "+ response );
print("Email :::"+ response.prop("email"));
response.prop("email");</camunda:script>
</camunda:outputParameter>
now I want to pass email in payload of another rest-API call for which I am using HTTP-CONNECTOR
<camunda:connector>
<camunda:inputOutput>
<camunda:inputParameter name="url">http://localhost:8080/step2</camunda:inputParameter>
<camunda:inputParameter name="method">POST</camunda:inputParameter>
<camunda:inputParameter name="header">
<camunda:map>
<camunda:entry key="accept">application/json</camunda:entry>
<camunda:entry key="content-type">application/json</camunda:entry>
</camunda:map>
</camunda:inputParameter>
<camunda:inputParameter name="payload">
<camunda:script scriptFormat="JavaScript">var email=execution.getVariable("email");</camunda:script>
</camunda:inputParameter>
</camunda:inputOutput>
<camunda:connectorId>http-connector</camunda:connectorId>
</camunda:connector>
but it's giving error as
w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.HttpMediaTypeNotSupportedException: Content type '' not supported]
How to pass output variable to next REST-API ?
<camunda:inputParameter name="header"> instead of this <camunda:inputParameter name="headers"> should be used , more-ever it's not possible to pass script as input to text variable.
so I used
<camunda:outputParameter name="email">
${response}
</camunda:outputParameter>
to pass complete response to next service

Wanted to remove property name while printing the log in WSO2

Here I have one doubt
I am creating log mediator in WSO2 and setting one property msg and it gives me output as follows
[2017-08-04 18:13:10,041] [] INFO - LogMediator Msg = Msg Coming************************
Here I just want the output like Msg Coming************************ I dont want to print property name...
How I will able to do it..
Example
<property name="*******************" value="hello" />
or
<property name="*******************" expression="translate('some string to log', 'abcdefg.....z', '****************************')" />
In first case you will get unknown property, in second unkond property with unknown value. Why you need such logging

Mock a message from a 3rd party system in Mule using MUnit

I'm writing a test suite (using Munit) for a Mule application that is processing new data coming from an instance of Magento. One of my flows is polling Magento for new customers and the message it receives is of type: com.magento.api.CustomerCustomerEntity
I'm wondering how I'd mock this so that in my test case, when the Magento message processor is called I can return a payload of the same type and make the appropriate assertations?
Currently my Munit test looks as follows:
<mock:config name="mock_MagentoToSalesforce" doc:name="Mock configuration"/>
<spring:beans>
<spring:import resource="classpath:MagentoToSalesforce.xml"/>
<spring:bean id="myBean" name="myBean" class="com.magento.api.CustomerCustomerEntity">
<spring:property name="email" value="test#test.com"/>
</spring:bean>
</spring:beans>
<munit:test name="MagentoToSalesforce-test-getCustomersFlowTest" description="Test">
<mock:when config-ref="mock_MagentoToSalesforce" messageProcessor=".*:.*" doc:name="Mock">
<mock:with-attributes>
<mock:with-attribute whereValue-ref="#[string:Get New Customers]" name="doc:name"/>
</mock:with-attributes>
<mock:then-return payload-ref="#[app.registry.myBean]"/>
</mock:when>
<flow-ref name="getCustomers" doc:name="Flow-ref to getCustomers"/>
</munit:test>
And the flow I'm trying to test is:
<flow name="getCustomers" processingStrategy="synchronous">
<poll doc:name="Poll">
<fixed-frequency-scheduler frequency="30" timeUnit="SECONDS"/>
<watermark variable="watermark" default-expression="#[new org.mule.el.datetime.DateTime().plusYears(-30)]" update-expression="#[new org.mule.el.datetime.DateTime().plusYears(-0)]" selector-expression="#[new org.mule.el.datetime.DateTime(payload.created_at, 'yyyy-MM-dd HH:mm:ss')]"/>
<magento:list-customers config-ref="Magento" filter="dsql:SELECT confirmation,created_at,created_in,customer_id,dob,email,firstname,group_id,increment_id,lastname,middlename,password_hash,prefix,store_id,suffix,taxvat,updated_at,website_id FROM CustomerCustomerEntity WHERE updated_at > '#[flowVars.watermark]'" doc:name="Get New Customers"/>
</poll>
<foreach doc:name="For Each">
<data-mapper:transform config-ref="MagentoCustomer_To_SalesforceContact" doc:name="Map Customer to SFDC Contact">
<data-mapper:input-arguments>
<data-mapper:input-argument key="ContactSource">Magento</data-mapper:input-argument>
</data-mapper:input-arguments>
</data-mapper:transform>
<flow-ref name="upsertSalesforceContactFlow" doc:name="upsertSalesforceContactFlow"/>
</foreach>
</flow>
Update following Ryan's answer:
Changed the expression to return a payload of #[ent = new com.magento.api.CustomerCustomerEntity(); ent.setEmail('test#test.com'); return [ent];] - note, changed the method to setEmail to match the documentation here. The error I get with this is:
ERROR 2015-06-22 09:58:34,719 [main] org.mule.exception.DefaultMessagingExceptionStrategy:
********************************************************************************
Message : Object "org.mule.transport.NullPayload" not of correct type. It must be of type "{interface java.lang.Iterable,interface java.util.Iterator,interface org.mule.routing.MessageSequence,interface java.util.Collection}" (java.lang.IllegalArgumentException). Message payload is of type: NullPayload
Code : MULE_ERROR--2
--------------------------------------------------------------------------------
Exception stack is:
1. Object "org.mule.transport.NullPayload" not of correct type. It must be of type "{interface java.lang.Iterable,interface java.util.Iterator,interface org.mule.routing.MessageSequence,interface java.util.Collection}" (java.lang.IllegalArgumentException)
org.mule.util.collection.EventToMessageSequenceSplittingStrategy:64 (null)
2. Object "org.mule.transport.NullPayload" not of correct type. It must be of type "{interface java.lang.Iterable,interface java.util.Iterator,interface org.mule.routing.MessageSequence,interface java.util.Collection}" (java.lang.IllegalArgumentException). Message payload is of type: NullPayload (org.mule.api.MessagingException)
org.mule.execution.ExceptionToMessagingExceptionExecutionInterceptor:32 (http://www.mulesoft.org/docs/site/current3/apidocs/org/mule/api/MessagingException.html)
--------------------------------------------------------------------------------
Root Exception stack trace:
java.lang.IllegalArgumentException: Object "org.mule.transport.NullPayload" not of correct type. It must be of type "{interface java.lang.Iterable,interface java.util.Iterator,interface org.mule.routing.MessageSequence,interface java.util.Collection}"
at org.mule.util.collection.EventToMessageSequenceSplittingStrategy.split(EventToMessageSequenceSplittingStrategy.java:64)
at org.mule.util.collection.EventToMessageSequenceSplittingStrategy.split(EventToMessageSequenceSplittingStrategy.java:25)
at org.mule.routing.CollectionSplitter.splitMessageIntoSequence(CollectionSplitter.java:29)
+ 3 more (set debug level logging or '-Dmule.verbose.exceptions=true' for everything)
********************************************************************************
One way is to build up the object yourself using the constructor or properties/setters.
From the docs:
http://mulesoft.github.io/magento-connector/2.1.2/java/com/magento/api/CustomerCustomerEntity.html
<mock:then-return payload-ref="#[ent = new com.magento.api.CustomerCustomerEntity(); ent.email('test#test.com'); return ent;]"/>
You can also create these objects aS reusable spring beans and reference them from MEL.
<bean class="com.magento.api.CustomerCustomerEntity" id="myEntityWithEmail">
<property name="email" value="test#test.com" />
</bean>
<mock:then-return payload-ref="#[app.registry.myEntityWithEmail]"/>
After your update I can see that you sre using a foreach which expects a collection or iterable. YOu can return a collection of you custom object simply in MEL using: [] for example:
#[ent = new com.magento.api.CustomerCustomerEntity(); ent.email('test#test.com'); return [ent];]
More on MEL here: https://developer.mulesoft.com/docs/display/current/Mule+Expression+Language+MEL
Or again you can use Spring to return a list:
<util:list id="entities">
<ref bean="myEntityWithEmail" />
</util:list>

Create sub-tags in Matlab Soap request

I am developing a SOAP client in Matlab for connection a Web Service. What I am doing is the following script:
createClassFromWsdl('http://192.168.107.239/WSDL/v4.0/iLON100.wsdl')
obj = iLON100
methods(obj)
With the next result:
Methods for class iLON100:
Clear Get List Set display
Delete InvokeCmd Read Write iLON100
Then, I am editing for example the method List in order to request the list of Items for the service. The dot m file is:
% Build up the argument lists.
values = { '','//Item[#xsi:type="Dp_Cfg"]'};
names = { 'iLonItem','xSelect'};
types = {};
% Create the message, make the call, and convert the response into a variable.
soapMessage = createSoapMessage('http://wsdl.echelon.com/web_services_ns/ilon100/v4.0/message/',
'List', values, names, types, 'document');
I have also a SOAP tester from the vendor of the device. Then, if I compare both XML requests, they differ as you can see in the next example (firstly the original request and secondly the Matlab one):
<SOAP-ENV:Body>
<List xmlns="http://wsdl.echelon.com/web_services_ns/ilon100/v4.0/message/">
<iLonItem>
<xSelect>
//Item[#xsi:type="Dp_Cfg"]
</xSelect>
</iLonItem>
</List>
</SOAP-ENV:Body>
<soap:Body soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<List xmlns="http://wsdl.echelon.com/web_services_ns/ilon100/v4.0/message/">
<iLonItem/>
<xSelect>Item</xSelect>
</List>
</soap:Body>
As you can observe, the tags are not included as sub-tags. I would like to know how to do it and generate the same structure of XML for sending the SOAP request correctly.
Thank you so much,
At the end, I have solved it by creating a structure as follows:
myStruct = struct('iLonItem',struct('xSelect','//Item[#xsi:type="Dp_Cfg"]'))
This structure is inserted into "values" and the method's name "iLONItem".

Elmah Filter for Nancy MVC Framework

I'm using Nancy MVC and Nancy.Elmah. Currently, there's a bug in Nancy that raises an exception for requests with accept headers of "*". Here's the Elmah log:
System.ArgumentException
inputString not in correct Type/SubType format Parameter name: *
System.ArgumentException: inputString not in correct Type/SubType format
Parameter name: *
at Nancy.Responses.Negotiation.MediaRange.FromString(String contentType)
at Nancy.Routing.DefaultRouteInvoker.<>c__DisplayClass5a.<>c__DisplayClass5c.<GetCompatibleHeaders>b__4f(MediaRange mr)
at System.Linq.Enumerable.WhereSelectListIterator`2.MoveNext()
at System.Linq.Enumerable.<SelectManyIterator>d__14`2.MoveNext()
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
at Nancy.Routing.DefaultRouteInvoker.GetCompatibleHeaders(IEnumerable`1 coercedAcceptHeaders, NancyContext context, Negotiator negotiator)
at Nancy.Routing.DefaultRouteInvoker.ProcessAsNegotiator(Object routeResult, NancyContext context)
at Nancy.Routing.DefaultRouteInvoker.InvokeRouteWithStrategy(Object result, NancyContext context)
at System.Dynamic.UpdateDelegates.UpdateAndExecute3[T0,T1,T2,TRet](CallSite site, T0 arg0, T1 arg1, T2 arg2)
at CallSite.Target(Closure , CallSite , DefaultRouteInvoker , Object , NancyContext )
at Nancy.Routing.DefaultRouteInvoker.Invoke(Route route, DynamicDictionary parameters, NancyContext context)
at Nancy.Routing.DefaultRequestDispatcher.Dispatch(NancyContext context)
at Nancy.NancyEngine.InvokeRequestLifeCycle(NancyContext context, IPipelines pipelines)
I tried filtering it with the following web.config
<errorFilter>
<test>
<or>
<regex binding="Exception" pattern="inputString not in correct Type/SubType format Parameter name: \*" />
</or>
</test>
</errorFilter>
But the errors are not filtered out.
Also tried binding="BaseException.Message" without luck.
I would like a way to filter these messages from being logged. Could some "correct" my filter configuration above to do so? Thanks!
Well, after a few more hours of trail and error I discovered the issue is that the, "Parameter name: *" portion is not part of the actual exception message. I'm guessing that the message in the log is a concatenation of the exception message and parameter values. Changed the filter as shown and it's works.
<errorFilter>
<test>
<regex binding="Exception.Message" pattern="inputString not in correct Type/SubType format" />
</test>
</errorFilter>