I'm new to Mule ESB.
I have the following config file for Mule which was taken from the Spell Checker tutorial:
<file:connector name="FILE" streaming="false" doc:name="File" autoDelete="true" validateConnections="false"/>
<flow name="SpellCheckerFlow1" doc:name="SpellCheckerFlow1">
<file:inbound-endpoint connector-ref="FILE" path=".\xmlIn" pollingFrequency="3000" responseTimeout="10000" doc:name="Incoming File" moveToDirectory=".\xmlProcessed"/>
<http:outbound-endpoint exchange-pattern="request-response" host="www.google.com/tbproxy/spell?lang=en" port="80" doc:name="Invoke API"/>
<echo-component doc:name="Echo"/>
<file:outbound-endpoint path=".\xmlOut" outputPattern="#[function:datestamp:dd-MM-yy]_#[function:systime].xml" responseTimeout="10000" doc:name="File"/>
</flow>
I'm trying to extend the FunctionalTestCase class and test this flow. Below is the extracted code I'm using to do that:
MuleClient client = new MuleClient(muleContext);
client.dispatch("file://./xmlIn", "<valid_xml />", null);
MuleMessage message = client.request("file://./xmlOut", 1000000000);
When I execute this code it creates a data file in the /xmlIn folder. The rest of the flow does not get executed. The flow should poll on this folder to pick up the file.
Thanks in advance!
The time-out parameter is ineffective when requesting from a file endpoint: Mule is not going to wait for the file to appear.
This means that your test doesn't block and always fails. The easiest/less refined way to solve the issue is to loop on a { Thread.wait(); client.request(); } until you get a non-null message, ie until the file in xmlOut has been read.
No need to add a retry counter: Mule's FunctionalTestCase will automatically fail the test after getTestTimeoutSecs() has elapsed (60 seconds by default).
Side notes:
To make your config work in my environment, I had to replace the .\ with ./ in the file paths of the XML config.
The outbound HTTP endpoint is mis-configured: the path is mixed in the host, use instead:
<http:outbound-endpoint exchange-pattern="request-response"
host="www.google.com" path="tbproxy/spell?lang=en" port="80"
doc:name="Invoke API" />
It's slightly more efficient to get the Mule client this way:
MuleClient muleClient = muleContext.getClient();
Related
I'm trying to call a REST service that is protected by basic authentication and I can't get this work. Basically, I need to setup the authorization header as
"Authorization: Basic [base64 encoded user name and password]".
My flow looks like this:
<flow name="testjsonFlow1" doc:name="testjsonFlow1">
<http:inbound-endpoint exchange-pattern="request-response" host="localhost" port="8081" path="testjson" doc:name="HTTP"/>
<set-property propertyName="Authorization" doc:name="Set Authentication Header" value="#["Basic " + Base64.encodeBase64String("username:password")]"/>
<http:outbound-endpoint exchange-pattern="request-response" host="<url>" port="80" path="Services/V1/testservices" method="POST" contentType="text/plain" doc:name="HTTP"/>
<echo-component doc:name="Echo"/>
</flow>
Invoking this flow results in the following error:
[Error: unresolvable property or identifier: Base64]
[Near : {... "Basic " + Base64.encodeBase64String("com ....}]
I see that the MuleStudio ships with commons-codec-1.3-osgi.jar while the Base64 API is not included and only comes with later version.
So my questions are:
Is this the right way to call a REST service that is protected with basic auth?
How can I resolve this issue?
How can I make the Mulestudio reference the commons-codec-1.9 jar instead of the commons-codec-1.3-osgi.jar?
Environment details: Windows 7 64 bit, Mule CE 3.4.
Any help is appreciated.
Update 1:
I made some updates to the script and it works now. Here is the updated script:
<flow name="testjsonFlow1" doc:name="testjsonFlow1">
<http:inbound-endpoint exchange-pattern="request-response" host="localhost" port="8081" path="testjson" doc:name="HTTP" />
<set-variable variableName="uName" doc:name="Variable" value="domain\user"/>
<set-variable variableName="pwd" doc:name="Variable" value="P#ssword"/>
<scripting:component doc:name="Groovy">
<scripting:script engine="Groovy">
<scripting:text><![CDATA[
def cred = message.getInvocationProperty("uName") + ":" + message.getInvocationProperty("pwd")
def credBytes = cred.bytes
def encodedCred = credBytes.encodeBase64().toString()
message.setProperty("credential",encodedCred)
return null;]]></scripting:text>
</scripting:script>
</scripting:component>
<set-property propertyName="Authorization" doc:name="Set Authentication Header" value="Basic #[header:OUTBOUND:credential]"/>
<logger level="INFO" doc:name="Logger"/>
<logger message="#[message.outboundProperties['Authorization']]" level="INFO" doc:name="Logger"/>
<http:outbound-endpoint exchange-pattern="request-response" host="myserver.com" port="80" path="Services/V1/service1/" method="POST" contentType="text/plain" doc:name="HTTP" />
</flow>
Answering your question to david in the comments above but hate pasting code into the comment editor.
You can add the user and pw to the endpoint and it'll base64 encode it like above.
<http:outbound-endpoint exchange-pattern="request-response"
host="foo.bar.com" port="80"
path="getFoo" method="GET"
user="username" password="password">
</http:outbound-endpoint>
<configuration>
<expression-language>
<import class="org.apache.commons.codec.binary.Base64" />
</expression-language>
</configuration>
or use the fully qualified class name in your expression.
But...
No, configure the username and password on the endpoint. See: http://www.mulesoft.org/documentation/display/current/Mule+Endpoint+URIs
Ditto.
Don't. Stick to the version provided by Mule. If you insist on using a most recent version, you'll need to package it with your application and use classloader override to ensure your application will use the packaged Commons Codec. See: http://www.mulesoft.org/documentation/display/current/Classloader+Control+in+Mule#ClassloaderControlinMule-Fine-GrainedClassloadingControl
Embedding user name and password on the http:outbound-endpoint didn't work as the password had a special character ('#') which was throwing a different exception. I made it work with a different approach and updated it in the question.
I was trying to develop a Functional Test case for my mule configuration. Here is the code:
protected String getConfigResources() {
// TODO Auto-generated method stub
return "src/test/resources/employee-get-functionalTestCase-config.xml";
}
#Test
public void testMessage() throws Exception {
MuleClient client = muleContext.getClient();
client.dispatch("vm://in", "70009", null);
MuleMessage result = client.request("vm://out", 60000);
Assert.assertNotNull("Response payload was null", result);
Assert.assertNull(result.getExceptionPayload());
Assert.assertFalse(result.getPayload() instanceof NullPayload);
& here is the context of my XMl file:
<spring:beans>
<context:property-placeholder location="classpath:mule-app.properties"/>
</spring:beans>
<flow name="testFlow">
<vm:inbound-endpoint path="in"/>
<logger message="in functional-test-config.xml (v4)" level="INFO" doc:name="Logger"/>
<set-payload value="70010" doc:name="Use fixed employeeId 70010"/>
<vm:outbound-endpoint exchange-pattern="request-response" path="employee-profile-get" doc:name="VM"/>
<logger message="after employee-profile-get; payload: #[payload]" level="INFO" doc:name="Logger"/>
<vm:outbound-endpoint path="out"/>
</flow>
However when I execute this code, I get the following error:
org.mule.api.transport.NoReceiverForEndpointException: There is no receiver registered on connector "connector.VM.mule.default" for endpointUri vm://employee-profile-get
Where do I register the vm endpoint?
You must have an inbound endpoint for every exchange-pattern="request-response" vm endpoint .
When the application is run in your mule studio you may not get any error(at compile time ) but when the message is passed through the flow you will get an error of the above mentioned sort .
This is because VM is an in-memory queue ,where once you put a message, there should be a receiver to pick the message thus when not there this error pops and it is only for the exchange-pattern="request-response" because the flow from where you put the message(outbound endpoint with request-response) will wait for a response from the vm endpoint "employee-profile-get" .
To depict the same error replace the with a localhost http endpoint and try invoking the http endpoint .
To avoid this create another flow with inbound endpoint as vm with path="employee-profile-get" and return a string using set payload component .Then your test case would work.
Regards,
Naveen Raj
In a flow something like below:
<flow name="fileFlow">
<file:inbound-endpoint path="/inbound/ftp/sbc" pollingFrequency="30000" fileAge="30000" moveToDirectory="/inbound/ftp/sbc/archive">
<file:filename-wildcard-filter pattern="*.xml" caseSensitive="false"/>
</file:inbound-endpoint>
<logger message="Entering #[flow.name] flow" level="INFO"/>
<component class="com.abc.RequestFile"/>
<logger message="Payload after transformation is: #[payload] flow" level="INFO"/>
<vm:outbound-endpoint path="merge" />
<logger message="Exiting #[flow.name] flow" level="INFO"/>
</flow>
I get InputStream from file:inbound-endpoint which is passed to RequestFile component. This component is required to return a list of files of which one of this is the original one read and passed. I am seeking a solution other than manual copying InputStream to File in java component.
As explained in this answer https://stackoverflow.com/a/12397775/387927 you can get the java.io.File object instead of its content with this setting:
<file:connector name="fileConnector" streaming="false" autoDelete="false">
<service-overrides messageFactory="org.mule.transport.file.FileMuleMessageFactory" />
</file:connector>
Note that it is up to you to move / delete the file either before you start or once you've done processing it, otherwise Mule will poll it again and again.
I'm using mule 3.2.0 and
I'm invoking muleclient.send method in java-class which sends soap-request to a mule flow(not present here), which sends it to the http endpoint which receives request, logs it to my db with proxy pattern and propagates it to "ServiceFlow" which has Dispatcher transformer - java class, which uses invocation of MuleClient.send(String url, Object payload, Map messageProperties) method to dispatch one object of the payload array to an endpoint.
Then it gets processed by cxf:jax-ws-client, logged to a db once again and transferred to another instance of Dispatcher (where incoming payload is again of type Object[]). There I have http endpoint which does the service invocation. This part works okay.
But trouble appears at the receiving of the response. I've put Test1(2,3,4) transformers to print the invocation chain in my flows (They just do the System.out.println()), and saw that they're invoked in a weird sequence: I have it like 1,3 then TestTransformer (which is also the sysouter) then I get the error "NullPayload" in the caller of the main flow "Service flow" and then I receive the Test 4 and Test 2 outs. The responseTransformer-refs in patterns "1Proxy" are ignored, so as in "ServiceProxy". I've been looking for the solution for like a week now, and can't find it. In debugging, I can see that transformer called "TestTransformer" in has expected payload (Object[]) but when I receive it in my class caller, it appears as "NullPayload". I can see now that one of my endpoints has the path element instead of ref, not sure if this cause any impact on flow, but will check it. Also tried to use the "response" block to ensure my flow runs as expected. Any suggestions appreciated. Thanks
Here is what my config looks like:
<http:endpoint name="httpService" address="${service.soap}" exchange-pattern="request-response" responseTimeout="${timeout}" />
<vm:endpoint name="vmService" path="vmService" exchange-pattern="request-response"/>
<pattern:web-service-proxy
name="ServiceProxy"
inboundEndpoint-ref="httpService"
transformer-refs="to-string logging"
responseTransformer-refs="to-string logging"
outboundEndpoint-ref="vmService" />
<flow name="ServiceFlow" >
<inbound-endpoint ref="vmService"/>
<cxf:jaxws-service serviceClass="pkg.ServiceImpl" wsdlLocation="${service.wsdl}" enableMuleSoapHeaders="false" validationEnabled="true"/>
<custom-transformer class="pkg.Dispatcher">
<spring:property name="vmFlowPath" value="vm.logService"/>
</custom-transformer>
<custom-transformer name="TestTransformer" class="pkg.TestTransformer"/>
</flow>
<vm:endpoint name="vm1In" path="vm1In" exchange-pattern="request-response"/>
<vm:endpoint name="vm1Out" path="vm1Out" exchange-pattern="request-response"/>
<custom-transformer name="arrayGenerator" class="pkg.ArrayGenerator"/>
<custom-transformer name="objectExtractor" class="pkg.ObjectExtractor"/>
<custom-transformer name="faultChecker" class="pkg.FaultChecker"/>
<custom-transformer name="objectLogging" class="pkg.ObjectLogger">
<pattern:web-service-proxy
name="1Proxy"
inboundEndpoint-ref="vm1In"
transformer-refs="arrayGenerator objectLogging"
responseTransformer-refs="objectLogging objectExtractor faultChecker"
outboundEndpoint-ref="vm1Out" />
<flow name="logService">
<vm:inbound-endpoint path="vm.logService exchange-pattern="request-response"/>
<custom-transformer class="Test1"/>
<vm:outbound-endpoint ref="vm1In">
<cxf:jaxws-client
serviceClass="pkg.ServiceImpl"
operation="import"
enableMuleSoapHeaders="false"/>
<object-to-string-transformer/>
</vm:outbound-endpoint>
<object-to-xml-transformer>
<xm:xml-to-object-transformer returnClass="pkg.WSResponseClass"/>
<custom-transformer class="Test2"/>
</flow>
<flow name="DispatcherToServiceFlow">
<custom-transformer class="Test3"/>
<vm:inbound-endpoint path="vm1.Out"/>
<custom-transformer class="pkg.Dispatcher">
<spring:property name="vmFlowPath" value="vm.import"/>
</custom-transformer>
</flow>
<flow name="import">
<vm:inbound-endpoint path="vm.import" exchange-pattern="request-response"/>
<http:outbound-endpoint address="${importService}" responseTimeout="${timeout}" exchange-pattern="request-response" />
<object-to-string-transformer/>
<custom-transformer class="Test4"/>
</flow>
well, my problem really was the "path" element instead of referring to an existing vm endpoint with "ref" element like
<inbound-endpoint ref="vm1Out"/>
I am relatively new to mule and trying to define a mule flow which takes request XML via soap-based Web service. The XML is based on a complex schema and I have generated classes using WSDL2Java
After receiving the request cxf:jaxws-service executes the method submitOrder(SubmitOrderRequest parameters). After this method's execution I would like to transform the request XML to a little bit different format. Then this XML needs to be forwarded to another web service. The problem is that the mule message that comes out of ServiceImpl contains SubmitOrderResponse whereas I still want to work on SubmitOrderRequest.
<flow name="testService">
<http:inbound-endpoint address="http://localhost:62005/test"
exchange-pattern="request-response">
<cxf:jaxws-service serviceClass="com.test.ServicePortType" />
</http:inbound-endpoint>
<component class="com.test.ServiceImpl" />
<!-- transformer ref="MVIRequestTransformer" / -->
<!-- xm:object-to-xml-transformer / -->
<!-- logger message="XML payload is #[payload]" level="INFO" / -->
<!-- SEND TRASNFORMED MESSAGE TO ANOTHER SERVICE -->
</flow>
#WebService(endpointInterface = "com.pennmutual.services.mvi.MVIServicePort")
public class ServiceImpl implements ServicePortType {
...
#Override
public SubmitOrderResponse submitOrder(SubmitOrderRequest parameters) {
...
}
...
}
What are my options are. I can think of the following –
1. Put the request object somewhere in the context and retreive it later on for processing.
2. Change the return type of submitOrder to Object and return SubmitOrderRequest instead of SubmitOrderResponse.
Please suggest the best possible way to handle this situation. I am using mule 3.2.
I think there are two elegant way to do that (excluding the one that involves changing the webservice interface)
Store the request into a session variable and restore it afterwards.
Here is how your flow would look like:
<flow name="testService">
<http:inbound-endpoint address="http://localhost:62005/test" exchange-pattern="request-response">
<cxf:jaxws-service serviceClass="com.test.ServicePortType" />
</http:inbound-endpoint>
<message-properties-transformer scope="session">
<add-message-property value="payload" key="originalPayload" />
</message-properties-transformer>
<component class="com.test.ServiceImpl" />
</flow>
Use the enricher around the component to store the returned value into a variable so that it won't become the payload of your flow. Following an example of how to achieve this
<flow name="Echo" doc:name="Echo">
<http:inbound-endpoint exchange-pattern="request-response" host="localhost" port="6090" path="echo" encoding="UTF-8" />
<cxf:jaxws-service serviceClass="org.mule.example.echo.Echo" />
<enricher target="#[variable:echo]">
<component class="org.mule.example.echo.Echo" />
</enricher>
<logger level="ERROR" message="#[variable:echo]"/>
</flow>
You can find more informations on the enricher here