I'm trying to send a form with a file and two inputs to an Mule inbound-endpoint. I've got a custom-processor, and a flow defined like that:
<custom-processor class="informa.app.classifier.transformers.MyfileUploadProcessor" name="fileuploadprocessor"></custom-processor>
<flow name="httpTest">
<http:inbound-endpoint
address="http://tango.privada.informa:11002/services/fileupload"></http:inbound-endpoint>
<processor ref="fileuploadprocessor"/>
</flow>
In the class MyfileUploadProcessor:
public class MyfileUploadProcessor implements MessageProcessor {
#Override
public MuleEvent process(MuleEvent event) throws MuleException {
// TODO Auto-generated method stub
String response = "success";
MuleMessage mulemessage = event.getMessage();
String countryCode = mulemessage.getInboundProperty("username");
String sourceCode = mulemessage.getInboundProperty("password");
InputStream input = (InputStream) mulemessage.getPayload();
...
And to test, a simple html:
<form action="http://tango.privada.informa:11002/services/fileupload" method="post"
enctype="multipart/form-data">
<p>Country Code :<input type="text" name="username" /></p>
<p>Source Code :<input type="text" name="password" /></p>
<p>File :<input type="file" name="payload" /></p>
<p><input type="submit" name="submit" value="submit" />
<input type="reset" name="reset" value="reset"></p>
</form>
</body>
</html>
The issue is I can't create a file from the payload of the mulemessage and I don't know how to get the value of the inputs in the form...what I'm doing wrong? any clues?
Thanks in advance
You need to configure the HTTP connector to use the org.mule.transport.http.HttpMultipartMuleMessageFactory in order to handle multipart/form-data HTTP POSTs.
For this, add the following to your configuration:
<http:connector name="httpConnector">
<service-overrides messageFactory="org.mule.transport.http.HttpMultipartMuleMessageFactory"/>
</http:connector>
With this in place, the payload form field will become the streaming payload of the Mule message and all the other fields values will be in inbound attachments (any part header will be in inbound headers).
Great answer from David (a life saver for me !! cudos david)
for what it is worth some extra items I didn't realize at first the httpConnector has to be used as http transport reference a full flow would be
<http:connector name="httpConnector" doc:name="HTTP\HTTPS">
<service-overrides
messageFactory="org.mule.transport.http.HttpMultipartMuleMessageFactory" />
</http:connector>
<flow name="AttachmentTestFlow1" doc:name="AttachmentTestFlow1">
<http:inbound-endpoint connector-ref="httpConnector" doc:name="HTTP" exchange-pattern="request-response" host="localhost" port="8081"/>
<component class="ProcessAttachment" doc:name="Java" />
</flow>
I was able to upload using jmeter adding two attachments, the first
has a paramter name = "payload" and mime-type="multipart/form-data"
the second has a user specificed name, e.g "attachment"
This can then be processed by a normal mule flow, or a component
public String process(#Payload String payload, #InboundAttachments("*") Map<String, DataHandler> headers ) throws IOException{
InputStream in = headers.get("attachment").getDataSource().getInputStream();
Related
Trying to use the Mule XML streaming feature as have to process very large xml files. Followed the documentation, the document does not have concrete examples.
When I inspected the payload I get the XMLUtils class and not the XMLStreamReader class as stated in the documentation.
The flow is as follows have a file connector which passes payload to a custom transformer, the transformer passes the data to a spring bean which is going to have event based processing.
In the spring bean. At run time the spring bean gets the XMLUtils class and not the XMLStreamReader class.
Mule - Config:
<spring:beans>
<spring:bean id="OracleCDMMapper" class="oraclecdmstream.OracleCDMMapper">
</spring:bean>
<spring:bean id = "OraclePaySlip" class="com.nect.transform.OracleCDMPaySlip" ></spring:bean>
</spring:beans>
<flow name="mulefileconnectorexampleFlow1" >
<file:inbound-endpoint path="C:/c-OracleCloud/src/main/resources" pollingFrequency="600000" moveToDirectory="C:/c-OracleCloud/src/main/resources/back" doc:name="File Input" >
<!-- <file:filename-regex-filter pattern="(^*.xml$)" caseSensitive="false"/>
--> <file:filename-wildcard-filter pattern="*.xml"></file:filename-wildcard-filter>
</file:inbound-endpoint>
<logger message="Transferring file : #[message.inboundProperties['originalFilename']]" level="INFO" doc:name="Logger"/>
<logger message ="Logger 1 " level="INFO" doc:name ="Logger1" />
<!-- Call the XMLSTREAMER -->
**<custom-transformer name="XmlToXSR" class="org.mule.module.xml.transformer.XmlToXMLStreamReader" doc:name="XMLTOORACLE">**
</custom-transformer>
<component doc:name="Java">
<spring-object bean="OracleCDMMapper"/>
</component>
-->
<logger message ="I am Complete " level="INFO" doc:name ="LoggerMurali" />
</flow>
</mule>
Here is the Javacode:
Spring Bean
public class OracleCDMMapper implements Callable {
private final Logger logger = LoggerFactory.getLogger(OracleCDMMapper.class);
#Override
public Object onCall(MuleEventContext eventContext) throws Exception {
// TODO Auto-generated method stub
MuleMessage muleMessage = eventContext.getMessage();
logger.info("In the Spring Component");
logger.info(muleMessage.getPayload().getClass().toString());
**javax.xml.stream.XMLStreamReader xsr = (XMLStreamReader) muleMessage.getPayload(javax.xml.stream.XMLStreamReader.class);**
Any help will be much appreciated
I've verified and you are right, in the code the supposed returning class should be a DelegateXMLStreamReader class that implements XMLStreamReader, but the returned class is an anonymous inner class of XMLUtils that at runtime cannot be casted to any Stream like class. It seems to be a defect.
If you really need the control of the xml stream, you could use a custom java component:
<component class="com.foo.CustomJavaComponent" doc:name="Java"/>
.
public class CustomJavaComponent implements Callable{
#Override
public Object onCall(MuleEventContext eventContext) throws Exception {
MuleMessage muleMessage = eventContext.getMessage();
FileInputStream fis = (FileInputStream)muleMessage.getPayload();
//Do something with this stream
return "Hello world";
}
}
And get the input stream to do whatever you want.
I am facing problem with mule testing. I just tries out simple functional testing example.
following is my flow
<flow name="muletestFlow1" doc:name="muletestFlow1">
<http:inbound-endpoint exchange-pattern="request-response" host="localhost" port="8081" path="test" doc:name="HTTP"/>
<response>
<object-to-string-transformer />
</response>
<component class="com.org.Square" doc:name="Square"/>
<component class="com.org.Neg doc:name="Neg"/>
</flow>
and following is my testing class
#Test
public void testSquareAddInverse() throws Exception {
MuleClient client = muleContext.getClient();
MuleMessage reply = client.send ("http://localhost:8081/test", "3", null, 5000);
assertNotNull(reply);
assertNotNull(reply.getPayload());
assertTrue(reply.getPayload() instanceof String);
String result = (String)reply.getPayload();
assertEquals("-9", result);
If i run above class as junit test then got following error.
java.lang.AssertionError
at org.junit.Assert.fail(Assert.java:92)
at org.junit.Assert.assertTrue(Assert.java:43)
at org.junit.Assert.assertTrue(Assert.java:54)
at com.test.TestEx.testSquareAddInverse(TestEx.java:25)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:622)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31)
at org.junit.rules.TestWatcher$1.evaluate(TestWatcher.java:46)
at org.junit.internal.runners.statements.FailOnTimeout$1.run(FailOnTimeout.java:28)
What is the solution please help me.
If i comment this line
assertTrue(reply.getPayload() instanceof String);
then got following error.
java.lang.ClassCastException: org.mule.transport.http.ReleasingInputStream cannot be cast to java.lang.String
What is the wrong in this code? How can i solve this problem. please help me
Thanks in advance
Since you call the flow through http protocol, which implicitly transforms the payload type. So the reply in the unit test will not contain a String but a InputStream. This is expected so you should test for a InputStream instead of a String. To get the value as a String you can use the method MuleMessage#getPayload(java.lang.Class) that will transform the payload to a String using the registered transformers.
#Test
public void testGetNegaiveNine() throws Exception {
MuleClient client = muleContext.getClient();
MuleMessage reply = client.send ("http://localhost:8081/test", "3", null, 5000);
assertNotNull(reply);
assertNotNull(reply.getPayload());
assertTrue(reply.getPayload() instanceof InputStream);
String result = reply.getPayload(String.class);
assertEquals("-9", result);
}
The exception you get in the flow
after that.
"DefaultJavaComponent{muletestFlow1.component.3418143}. Message payload is of type: ContentLengthInputStream"
is because the components can not handle the payload that the message inside your flow has. Since you are sending a HTTP POST into the flow the payload of the incoming message is a ContenLengthInputStream and you components expects a String.
So you will have to transform the payload into a String by adding a object-to-string transformer before the components. The complete flow would then be something like this.
<flow name="muletestFlow1" doc:name="muletestFlow1">
<http:inbound-endpoint exchange-pattern="request-response" host="localhost" port="8081" path="test" doc:name="HTTP"/>
<response>
<!-- Ensure that the response is a String -->
<object-to-string-transformer />
</response>
<!-- Ensure that the incoming request is a String -->
<object-to-string-transformer />
<component class="com.org.Square" doc:name="Square"/>
<component class="com.org.Neg doc:name="Neg"/>
</flow>
In a soap based web service i want to access the Mule message properties. Is there a way of doing this i know one way of using RequestContext.getEvent().getMessage() but this i guess is deprecated. An other way of accessing the MuleMessage properties in the web service. Can someone please provide any pointers on this.
Code Snippet
<flow name="MyWebService" doc:name="MyWebService">
<http:inbound-endpoint exchange-pattern="request-response" address="${WEB_SERVICE_PROTOCOL}://${WEB_SERVICE_HOST}:${WEB_SERVICE_PORT}/MyWebService?wsdl" tracking:enable-default-events="true">
<cxf:jaxws-service serviceClass="com.XXX.XXX.service.MyWebService" doc:name="SOAP"/>
</http:inbound-endpoint>
<component doc:name="My Web Service">
<spring-object bean="WebServiceImpl"/>
</component>
</flow>
Depending on what is your purpose for obtaining the message properties, one option is to use a cxf interceptor to access the message. See the following example.
adding the interceptor:
<cxf:jaxws-service serviceClass="org.example.HelloWorld">
<cxf:inInterceptors>
<spring:bean class="org.example.MyInterceptor"/>
</cxf:inInterceptors>
</cxf:jaxws-service>
interceptor class:
package org.example;
import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.binding.soap.interceptor.AbstractSoapInterceptor;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.phase.Phase;
import org.mule.api.MuleEvent;
import org.mule.api.MuleMessage;
public class MyInterceptor extends AbstractSoapInterceptor {
public MyInterceptor() {
super(Phase.USER_PROTOCOL);
}
#Override
public void handleMessage(SoapMessage message) throws Fault {
MuleEvent muleEvent = (MuleEvent)message.getContextualProperty("mule.event");
MuleMessage muleMessage = muleEvent.getMessage();
System.out.println(muleMessage.toString());
}
}
You can achieve this by not implementing the service interface at all and deal with the SOAP requests as Mule messages (where properties are accessible) instead of dealing with deserialized objects in service classes.
Here is an example fragment, assuming you've generated the necessary classes and interfaces from the WSDL with wsdl2java:
<flow name="WebServiceFlow">
<http:inbound-endpoint exchange-pattern="request-response"
address="http://localhost:8080/services/some" />
<cxf:jaxws-service
serviceClass="com.amce.SomePortType" />
<choice>
<when
expression="#[cxf_operation.localPart == 'SomeOperation']">
<flow-ref name="HandleSomeOperation" />
</when>
If you have access to MuleMessage then you get the required properties by using the method
Set<String> getPropertyNames(PropertyScope scope);
available in MuleMessage class. To get the MuleMessage you would need access to MuleClient; have you got access to MuleClient? if yes, then use:
muleClient = muleContext.getClient();
MuleMessage result = muleClient.send(webaddress, "", props);
Is this what you are trying to acheive?
I am trying a simple Mule 3.3.0 configuration which will download every email and pass it on to my custom processor class. Once the email is retrieved it should be deleted from the gmail inbox. But that doesn't seem to be working. Below is my mule-config.xml
<spring:beans>
<spring:import resource="classpath:spring/applicationContextServices-core.xml"/>
<spring:import resource="classpath:spring/applicationContextServices-configuration.xml"/>
<spring:bean id="emailSender" name="emailSender" class="com.test.EmailSender"/>
<spring:bean id="retrieveEmailProcessor" name="retrieveEmailProcessor" class="com.test.RetrieveEmailProcessor"/>
</spring:beans>
<jms:activemq-connector name="Active_MQ" specification="1.1" username="[username]" password="[password]" brokerURL="tcp://localhost:61616" validateConnections="true" doc:name="Active MQ">
<reconnect/>
</jms:activemq-connector>
<pop3s:connector name="pop3Connector" checkFrequency="45600" deleteReadMessages="true"/>
<flow name="1_SendMessageToOwner" doc:name="1_SendMessageToOwner" doc:description="This is to confirm that your email was received successfully">
<jms:inbound-endpoint topic="PoolMessage" connector-ref="Active_MQ" doc:name="JMS"/>
<component doc:name="Build Email Message">
<spring-object bean="emailSender"/>
</component>
<smtps:outbound-endpoint host="smtp.gmail.com" port="465" user="[username]%40gmail.com" password="[password]" from="[username]#gmail.com" responseTimeout="50000" doc:name="SMTP"/>
</flow>
<flow name="2_ReceiveConfirmation" doc:name="2_ReceiveConfirmation" doc:description="Retrieving Email">
<pop3s:inbound-endpoint connector-ref="pop3Connector" host="pop.gmail.com" port="995" user="[username]%40gmail.com" password="[password]" responseTimeout="10000" doc:name="Pop3"/>
<component doc:name="Process Transaction - Confirmation Message" doc:description="Recieve confirmation from member.">
<spring-object bean="retrieveEmailProcessor"/>
</component>
</flow>
</mule>
and the RetrieveEmailProcessor class
package com.test;
import java.util.Map;
import org.mule.api.MuleEventContext;
import org.mule.api.lifecycle.Callable;
public class RetrieveEmailProcessor implements Callable {
public Object onCall(MuleEventContext eventContext)
throws Exception
{
System.out.println("########## Entering RetrieveEmailProcessor.OnCall ##########");
Map dataMapMessage = (Map)eventContext.getMessage().getPayload();
String subject = (String)dataMapMessage.get("subject");
String toAddressList = (String)dataMapMessage.get("toAddressList");
String fromAddress = (String)dataMapMessage.get("fromAddress");
eventContext.getMessage().setOutboundProperty(
"toAddresses",
toAddressList);
eventContext.getMessage().setOutboundProperty(
"subject",
subject);
eventContext.getMessage().setOutboundProperty(
"replyToAddresses",
fromAddress);
System.out.println("########## Exiting RetrieveEmailProcessor.OnCall ##########");
return dataMapMessage.get("mailBody");
}
}
Is there anything obvious that I am missing?
Thanks in advance
Your Mule configuration is fine.
You need to check your Gmail's configuration:
Settings -> Forwarding and POP/IMAP -> In POP Download: --> 2. When messages are accessed with POP
There you need to select "delete Gmail's copy" if you want your messages deleted or archived once they're read by the POP connector.
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