We have the following mule flow:
<flow name="mule-flow-1">
<component>
<spring-object bean="springBean_1"/>
<binding interface="com.acme.EmailService" method="send">
<vm:outbound-endpoint path="send-email" exchange-pattern="one-way"/>
</binding>
</component>
</flow>
but right now we want to introduce new flow, with new Spring bean which uses the same EmailService.send method, so, we can do it as:
<flow name="mule-flow-2">
<component>
<spring-object bean="springBean_2"/>
<binding interface="com.acme.EmailService" method="send">
<vm:outbound-endpoint path="send-email" exchange-pattern="one-way"/>
</binding>
</component>
</flow>
As you can see, we bound EmailService.send method twice in two different flows and it is pure code duplication.
Is it possible to bind EmailService.send method somewhere in common place and just use ref in mule-flow-1 and mule-flow-2?
maybe you can use subflow? Define your component there and then use flow-ref in any flow you want to reuse it.
<sub-flow name="mule-flow-send">
<component>
<spring-object bean="springBean_1"/>
<binding interface="com.acme.EmailService" method="send">
<vm:outbound-endpoint path="send-email" exchange-pattern="one-way"/>
</binding>
</component>
</sub-flow>
and then reusing:
<flow name="mule-flow-1">
<flow-ref name="mule-flow-send" doc:name="mule-flow-send"/>
</flow>
<flow name="mule-flow-2">
<flow-ref name="mule-flow-send" doc:name="mule-flow-send"/>
</flow>
Related
I have a list which I want to process in paraller, so after calling collection-splitter, I post each record to an outbound-endpoint, but the receiving inbound-endpoint is not been triggered.
Configuration below;
<flow name="ProcessPolledOrders" doc:name="ProcessPolledOrders">
<set-session-variable variableName="fileName" value="#[message.payload.orderBatch.orderSourceName]" />
<set-session-variable variableName="batchId" value="#[message.payload.orderBatch.id]" />
<logger message="************* Item: #[sessionVars.fileName] processing resumed. ***********" level="INFO"/>
<component>
<spring-object bean="PolledOrderSplitter"/>
</component>
<set-session-variable variableName="size" value="#[message.payload.size()"/>
<collection-splitter/>
<set-property propertyName="MULE_CORRELATION_GROUP_SIZE" value="#[sessionVars.size]" />
<set-property propertyName="MULE_CORRELATION_ID" value="#[sessionVars.fileName]" />
<choice>
<when>
<payload-type-filter expectedType="model.Order"/>
<vm:outbound-endpoint exchange-pattern="one-way" path="step2" doc:name="VM"/>
</when>
<otherwise>
<echo-component/>
</otherwise>
</choice>
</flow>
<flow name="PollerOrderProcessingFlow" doc:name="PollerOrderProcessingFlow">
<vm:inbound-endpoint exchange-pattern="one-way" path="step2" doc:name="VM"/>
<logger message="***************** Validating order with id #[message.payload.id] ********************"
level="INFO"/>
<component>
<spring-object bean="PolledOrderValidationComponent"/>
</component>
<collection-aggregator timeout="600000" failOnTimeout="false"
doc:name="Validated Orders Aggregator"/>
<component>
<spring-object bean="BatchOrderUpdateComponent"/>
</component>
<default-exception-strategy>
<flow-ref name="ValidationProcessingExceptionFlow" />
</default-exception-strategy>
</flow>
Are you getting any exception? try to debug and see where the message dropping? I tried similar flow and working fine for me.
I am getting an error message when trying to add a Spring component to a Mule Flow. This should be a common user-case, but I wasn't able to find the right documentation or examples. Thanks in advance.
The follow was the original configuration and works fine:
<flow name="ApplicationEndpoint">
<inbound-endpoint address="server:port/JSONAPI/"/>
<jersey:resources>
<component>
<spring-object bean="myJerseyService"/>
</component>
</jersey:resources>
<catch-exception-strategy doc:name="Catch Exception Strategy">
<flow-ref name="ErrorHandling" doc:name="Flow Reference"/>
</catch-exception-strategy>
</flow>
I simply want to add a new component to do some post-processing. When I try this, it doesn't work:
<flow name="ApplicationEndpoint">
<inbound-endpoint address="server:port/JSONAPI/"/>
<jersey:resources>
<component>
<spring-object bean="myJerseyService"/>
</component>
</jersey:resources>
<component>
<spring-object bean="postProcessor"/>
<component>
<catch-exception-strategy doc:name="Catch Exception Strategy">
<flow-ref name="ErrorHandling" doc:name="Flow Reference"/>
</catch-exception-strategy>
</flow>
Where "postProcessor" maps elsewhere in the config as a spring bean.
The error message I get is:
org.xml.sax.SAXParseException: cvc-complex-type.2.4.a: Invalid content was found starting with element 'component'. One of '{"http://www.mulesoft.org/schema/mule/core":abstract-lifecycle-adapter-factory, "http://www.mulesoft.org/schema/mule/core":binding}' is expected.
The above error clearly shows that the tag <component> is not closed..
for example, it should be in following format :-
<component>
<spring-object bean="postProcessor"/>
</component>
where you need to end the tag like the following :- </component>
One more thing ... I tried to run your code, but due to server:port/JSONAPI/ configured in your inbound-endpoint address it gives a error saying the xml is malformed
So I modified your code as following and it ran successfully :-
<flow name="ApplicationEndpoint">
<inbound-endpoint address="http://localhost:8189/JSONAPI"/>
<jersey:resources>
<component>
<spring-object bean="myJerseyService"/>
</component>
</jersey:resources>
<component>
<spring-object bean="postProcessor"/>
</component>
<catch-exception-strategy doc:name="Catch Exception Strategy">
<flow-ref name="ErrorHandling" doc:name="Flow Reference"/>
</catch-exception-strategy>
</flow>
So, you can now use it and modify as per your requirement
I need to send HTTP Request to publish some data in a WS
E.g:
http://localhost:8081/hello/publishAMANSequence/filter/sequenceGenerationTime=1696-09-01T00:00:00Z&AMANId=B1&landingSequenceEntry=11234567890EST
I take this fault from server:
Parameter should be ordered in the following sequence: [sequenceGenerationTime, AMANId, landingSequenceEntry]
I'm doing something wrong in the order?
mule flow:
<jms:activemq-connector name="Active_MQ1" brokerURL="tcp://localhost:61616" validateConnections="true" doc:name="Active MQ"/>
<flow name="jmsFlow1" doc:name="jmsFlow1">
<http:inbound-endpoint exchange-pattern="request-response" host="localhost" port="8081" path="hello" doc:name="HTTP"/>
<cxf:jaxws-service doc:name="SOAP" serviceClass="aero.itec.amansequenceservice.AMANSequenceInfo"/>
<component doc:name="Java" class="implementations.AMANSequenceImpl"/>
<mulexml:object-to-xml-transformer doc:name="Object to XML"/>
<jms:outbound-endpoint queue="StudioIN" connector-ref="Active_MQ1" doc:name="JMS"/>
<logger message="#[message.payload]" level="INFO" doc:name="Logger"/>
</flow>
The url which you have provided is wrong. There should be a questionmark(?) after "filter". Then only it will consider it as parameters
http://localhost:8081/hello/publishAMANSequence/filter?sequenceGenerationTime=1696-09-01T00:00:00Z&AMANId=B1&landingSequenceEntry=11234567890EST
Moreover if you are trying to access a webservice you can't do that with a HTTP GET. You need to send it as a SOAP request. You can use APIs like CXF, AXIS etc.
Following this tutorial ~
I create a flow for publish the WS , that have an inbound-endpoint where I do the request
publish.flow:
<jms:activemq-connector name="Active_MQ1" brokerURL="tcp://localhost:61616" validateConnections="true" doc:name="Active MQ"/>
<flow name="jmsFlow1" doc:name="jmsFlow1">
<http:inbound-endpoint exchange-pattern="request-response" host="localhost" port="8081" path="hello" doc:name="HTTP"/>
<cxf:jaxws-service doc:name="SOAP" serviceClass="aero.itec.amansequenceservice.AMANSequenceInfo" >
<cxf:jaxb-databinding/>
<cxf:inInterceptors>
<spring:bean class="org.apache.cxf.interceptor.LoggingInInterceptor" />
</cxf:inInterceptors>
<cxf:outInterceptors>
<spring:bean class="org.apache.cxf.interceptor.LoggingOutInterceptor" />
</cxf:outInterceptors>
</cxf:jaxws-service>
<component doc:name="Java" class="implementations.AMANSequenceImpl"/>
<object-to-string-transformer doc:name="Object to String"/>
<jms:outbound-endpoint queue="StudioIN" connector-ref="Active_MQ1" doc:name="JMS"/>
<logger message="#[message.payload]" level="INFO" doc:name="Logger"/>
</flow>
Then I create a client.class where I set the variable values:
client.java
public class AMANwsClient extends AbstractTransformer{
#Override
protected Object doTransform(Object src, String enc)
throws TransformerException {
AMANSequence sequence = new AMANSequence();
XMLGregorianCalendar fec;
sequence.setSequenceGenerationTime(fec);
sequence.setAMANId("AA");
System.out.println(sequence);
return sequence;
}
This class is used like a transformer, we don't need to pass parameters in the url, only need to connect to the endpoint URL
Finally, create a client.flow
<custom-transformer class="implementations.AMANwsClient" name="AMANwsClient" />
<flow name="csvPublisher">
<transformer ref="AMANwsClient" />
<object-to-string-transformer doc:name="Object to String"/>
<outbound-endpoint address="http://localhost:63081/hello" exchange-pattern="request-response">
<cxf:jaxws-client clientClass="aero.itec.amansequenceservice.AMANSequenceInfo_Service" port="AMANSequenceInfoService" operation="publishAMANSequence">
<cxf:inInterceptors>
<spring:bean class="org.apache.cxf.interceptor.LoggingInInterceptor" />
</cxf:inInterceptors>
<cxf:outInterceptors>
<spring:bean class="org.apache.cxf.interceptor.LoggingOutInterceptor" />
</cxf:outInterceptors>
</cxf:jaxws-client>
</outbound-endpoint>
</flow>
Now I can save the payload into a JMS Queue and reproduce the payload from Browser, console and JMS.
If you have some suggestion to improve program performance, I'm open to listen to it.
Put http://localhost:8081/hello?wsdl in SOAPUI ... It will create the request and response there ... then you can pass the values in the request and invoke the webservice ...
Please check the following for your reference :-
http://developers-blog.org/blog/default/Webservice-testing-with-soapUI and http://quicksoftwaretesting.com/soapui-web-service-testing-tool/
My use case requires to enrich my input with smne data and send it to an outbound endpoint.
The data for enriching is obtained by making calls to two web-services and then extract the data from the reply.
This extracted data is enriched into my input XML and sent to an outbound endpoint.
The two web-service calls that I need to make needs to be parallel, as they don't have dependency on another. This way I could save my processing time.
Please suggest how I could achieve this parallel processing in a flow in Mule.
Note: I have tried using ALL flow control, but it seems that is calling the web-services (sub-flows) sequentially.
Given below is my abstract flow.
<flow name="mainFlow">
<inbound-endpoint> .....
<some validation>
<setting some flow variables>
<!-- Now make calls to the sub-flows which has some processing of the input and make some web-service calls -->
<all>
<flow-ref name="myFlow1" />
<flow-ref name="myFlow2" />
<flow-ref name="myFlow3" />
</all>
<enrich the input with the data obtained from the output of the above three flows>
<outbound-endpoint>
</flow>
<flow name="myFlow1">
<some transformer to transform the payload provided >
< the tran sformed payload is passed as input to the web-service call>
<http:outbound-endpoint ...>
<transform the reply from the web-service call>
</flow>
<flow name="myFlow2">
<some transformer to transform the payload provided >
< the tran sformed payload is passed as input to the web-service call>
<http:outbound-endpoint ...>
<transform the reply from the web-service call>
</flow>
<flow name="myFlow3">
<some transformer to transform the payload provided to it>
< the tran sformed payload is passed as input to the web-service call>
<http:outbound-endpoint ...>
<transform the reply from the web-service call>
</flow>
Here is a simple configuration that shows one way to make a fork/join with two HTTP outbound endpoints. To add a third endpoint, set MULE_CORRELATION_GROUP_SIZE to 3 and the MULE_CORRELATION_SEQUENCE of the third async flow-ref to 3.
<flow name="fork">
<vm:inbound-endpoint path="fork.in" />
<set-property propertyName="MULE_CORRELATION_GROUP_SIZE"
value="2" />
<all enableCorrelation="IF_NOT_SET">
<async>
<set-property propertyName="MULE_CORRELATION_SEQUENCE"
value="1" />
<flow-ref name="parallel1" />
</async>
<async>
<set-property propertyName="MULE_CORRELATION_SEQUENCE"
value="2" />
<flow-ref name="parallel2" />
</async>
</all>
</flow>
<sub-flow name="parallel1">
<logger level="INFO" message="parallel1: processing started" />
<http:outbound-endpoint address="..."
exchange-pattern="request-response" />
<logger level="INFO" message="parallel1: processing finished" />
<flow-ref name="join" />
</sub-flow>
<sub-flow name="parallel2">
<logger level="INFO" message="parallel2: processing started" />
<http:outbound-endpoint address="..."
exchange-pattern="request-response" />
<logger level="INFO" message="parallel2: processing finished" />
<flow-ref name="join" />
</sub-flow>
<sub-flow name="join">
<collection-aggregator timeout="6000"
failOnTimeout="true" />
<combine-collections-transformer />
<logger level="INFO"
message="Continuing processing of: #[message.payloadAs(java.lang.String)]" />
</sub-flow>
EDIT: In the above config, the aggregator times out after 6 seconds. This is potentially too short for your actual use case: increase as you see fit. Also it is set to fail on time-out, which is maybe not the behaviour you desire in case not all the outbound HTTP endpoint interactions succeeded: it's up to you to decide based on your use case.
I have the following code to configure a Jersey service at "http://localhost:8080/alpha":
*** my mule config ***
<flow name="flow1">
<inbound-endpoint address="http://localhost:8080/" exchange-pattern="request-response" />
<jersey:resources>
<component>
<singleton-object class="com.address.Flow1Resource"/>
</component>
</jersey:resources>
</flow>
*** Flow1Resource.java ***
#Path("/alpha")
public class Flow1Resource {...}
I want to add a new inbound-endpoint that handles all the addresses under "http://localhost:8080" except "http://localhost:8080/alpha" (e.g. "http://localhost:8080/beta"). These new addresses need a single jersey resource. For example:
*** my mule config ***
<flow name="flow1">
<inbound-endpoint address="http://localhost:8080/" exchange-pattern="request-response" />
<jersey:resources>
<component>
<singleton-object class="com.address.Flow1Resource"/>
</component>
</jersey:resources>
</flow>
<flow name="flow2">
<inbound-endpoint address="http://localhost:8080/*" exchange-pattern="request-response" />
<jersey:resources>
<component>
<singleton-object class="com.address.Flow2Resource"/>
</component>
</jersey:resources>
</flow>
*** Flow1Resource.java ***
#Path("/alpha")
public class Flow1Resource {...}
*** Flow2Resource.java ***
#Path("/")
public class Flow2Resource {
#Path("beta")
public void beta() {...}
#Path("gamma")
public void gamma() {...}
...
}
How do I set up the mule inbound-endpoint to capture all the addresses (i.e. beta & gamma), except for a specific url (i.e. alpha).
I know that I can hardcode the paths in the mule config, but this would result in duplication because each address (i.e. beta & gamma) would need its own flow and resource code, which are similar.
Please note that I used "http://localhost:8080/*" in the code above as an conceptual example. It does not work.
--- Update ---
I forgot to mention that the beta and gamma uri's also have security associated with them using:
<http:inbound-endpoint ...>
<spring-security:http-security-filter realm="mule-realm"/>
</http:inbound-endpoint>
I tried adding a 'choice' element to the endpoint, but it complained that spring-security was invalid inside the choice decision structure.
A solution would also need to accommodate this feature.
An easy way to achieve your goal is to combine your flows into one and use the choice router. In this configuration your flow will look like the following:
<flow name="stackoverflowFlow1" doc:name="stackoverflowFlow1">
<http:inbound-endpoint exchange-pattern="request-response"
host="localhost" port="8081" doc:name="HTTP" />
<logger level="ERROR" />
<choice doc:name="Choice">
<when expression="#[message.inboundProperties['http.request'] == '/']">
<processor-chain>
<logger message="/ invoked " level="ERROR" />
<jersey:resources doc:name="REST">
<component class="Resource" />
</jersey:resources>
</processor-chain>
</when>
<otherwise>
<processor-chain>
<logger message="otherwise invoked " level="ERROR" />
<jersey:resources doc:name="REST">
<component class="ApplicationsResource" />
</jersey:resources>
</processor-chain>
</otherwise>
</choice>
</flow>
As you can imagine you can take decision on the path or on top of any other http header.
You can find this router documentation here and a list of the most common http properties you can use to make your choices here