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?
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 building Mule project who receive JSON by HTTPComponent and convet to object.
My problem is can't acess field in object converted.
My flux's XML is:
<flow name="RestJsonHelloWorldFlow1" doc:name="RestJsonHelloWorldFlow1"><http:inbound-endpointexchange-pattern="request-response"
host="localhost" port="8081"
path="credit/new" doc:name="HTTP"
mimeType="application/json"/> <response>
<logger message=" #[message.payload.transactionCode]" level="INFO" doc:name="Logger"/>
</response>
<json:json-to-object-transformer doc:name="JSON to Object" returnClass="com.creditmobile.domain.Request" name="request"/></flow>
My pojo is:
#JsonAutoDetect
public class Request {
private Integer transactionCode;
public Request() {
super();
}
public Integer getTransactionCode() {
return transactionCode;
}
My JSON is:
{
"transactionCode": 1
}
I got following exception:
org.mule.api.transformer.TransformerMessagingException: The object transformed is of type: "SimpleDataType{type=java.lang.String, mimeType='*/*'}", but the expected return type is "SimpleDataType{type=org.mule.api.transport.OutputHandler, mimeType='application/json'}". The current MuleMessage is null! Please report this to dev#mule.codehaus.org
at org.mule.transformer.AbstractMessageTransformer.checkReturnClass(AbstractMessageTransformer.java:183)
at org.mule.transformer.AbstractMessageTransformer.transform(AbstractMessageTransformer.java:162)
at org.mule.transformer.AbstractMessageTransformer.transform(AbstractMessageTransformer.java:73)
+ 3 more (set debug level logging or '-Dmule.verbose.exceptions=true' for everything)
I saw anothers topics with same problem, but they don't have resolution and yours suggesttion doesn't work for me.
I access field with:[message.payload.transactionCode]
Thanks.
I think your problem is in the http response phase, not in accessing the field. Mule gets confused when you try to return your Java object as an http response. Depending on your requirements, try setting the return payload to something more understandable in the response phase. For example
<set-payload value="#[payload.transactionCode.toString()]"/>
or
<json:object-to-json-transformer/>
What do you actually want to return to the user once the application exits RestJsonHelloWorldFlow1 flow?
I think as Anton Kupias said your problem is the tag. I managed to solve the exception by removing the tag, and convert the payload into an object exactly after the HTTP inbound endpoint.
Config XML
<flow name="RestJsonHelloWorldFlow1" doc:name="RestJsonHelloWorldFlow1">
<http:inbound-endpoint exchange-pattern="request-response" host="localhost" port="8081" path="credit/new"
doc:name="HTTP" mimeType="application/json" />
<json:json-to-object-transformer
doc:name="JSON to Object" returnClass="com.creditmobile.domain.Request" />
<component class="com.creditmobile.domain.TransactionResponse" doc:name="Java"/>
<object-to-string-transformer doc:name="Object to String"/>
</flow>
basically you have
1) An HTTP inbound endpoint which is set to request-response
2) immediately convert the JSON to Object
3) Then I have created a java component to perform the required processing; by creating a class which implements org.mule.api.lifecycle.Callable. Got the transaction code from the payload and set the overridden method to return an object of type string
public class TransactionResponse implements Callable {
#Override
public Object onCall(MuleEventContext eventContext) throws Exception {
// Type casts payload to object Request
Request requestObject = (Request) eventContext.getMessage().getPayload();
int code = Integer.valueOf(requestObject.getTransactionCode());
String reply = "";
switch (code) {
case 1:
reply = "New";
break;
case 2:
reply = "Delete";
break;
}
return reply;
}
}
4) Then i terminated the flow by adding the Object to String component, Or place the Object to JSON component if you wish to return a JSON object to the user.
I have a main flow which begins with a http endpoint then a soap component which implements the interface and after a java component 1 that implements this interface. Now, I want to add a flow ref and after it a java component 2 that implements the same interface. I get the problem of "could not find entry point"
I am now following this tutorial blogs.mulesoft.org/mule-school-invoking-component-methods-using-entry-point-resolvers/
Given below is my flow.
<flow name="CreateAccountFlow1" doc:name="CreateAccountFlow1">
<http:inbound-endpoint exchange-pattern="request-response" host="localhost" port="8081"
doc:name="HTTP" path="bank"/>
<cxf:jaxws-service doc:name="SOAP" serviceClass="com.essai2.AccountService"/>
<component class="com.essai2.AccountRequest" doc:name="Java"/>
<logger level="INFO" doc:name="Logger"/>
<flow-ref name="Projet2Flow1" doc:name="Flow Reference"/>
<component class="com.essai2.AccountResponse" doc:name="Java"/>
<logger level="INFO" doc:name="Logger"/>
</flow>
Can anyone help me?
In mule there are many ways to invoke a Java component.
1. Entry point resolver
2. Implemnt mule Life Cycle API i.e callable
3. Invoke component.
when ever Mule finds Java component as message processors in a flow, tries to execute above three methods .
In the java component if you have created any methods with param same as mule message payload , Entry Point resolver is used.
eg : class XYZ{
method1(String s1){
}
method2(List<String> S2){
}
}
If Mule Message Payload has type String then method1 is invoked, if message payload has List of String , method2 is invoked during run time.
2. If you can invoke the Java component in the flow irrespective of type of the payload, should implement Callable interface which overrides onCall() method.
for eg : class XYS implements Callable{
#override
onCall(MuleEventConext muleEventConext){
}
using MuleEvent Conext you can extract the payload and process it.
3. Using Invoke component, you can create the object of the Class and invoke explicitly the method with appropriate Parameters passed.
I am trying to determine whether to use --
Jersey (JAX-RS) with HTTP based inbound endpoint.
Use HTTP based inbound end-point, and then examine HTTP header data ( like http.method, http.query.params, http.query.string, etc.) to determine the REST methods. i.e. non-Jersey-based custom approach to implement REST.
Advantages of approach #1
Standard: JAX-RS standards-based approach for implementing rest service in Java.
Documenting Is Easy: Generating the documentation is pretty easy because there are many tools out there which use JAX-RS annotations to generate the documentation.
Disadvantages of approach #1
If we have to use Jersey within Mule then the Jersey methods act as pass-through for the payload data. Example-
#POST
#Produces(MediaType.APPLICATION_JSON)
public String create(String jsonPayload) {
logger.debug("Received and added data :" jasonPayload);
return jsonPayload;
}
In our use case we have to pass this data over to the next flow where it either inserted into database or forwarded to some other Web service. We do not want to inject mule specific code in this class to call other Mule flows from within the create method. We are left with no choice but to pass the payload out of this method and handle it in the mule flow.
After Jersey processes create method it creates a Response object that encapsulates the payload. If we want to do something to the payload then we have to first extract the payload from Response object. This is an un-necessary hassle.
Any suggestions, opinions, thoughts ?
Based on feedback from David. Here is how I implemented it --
REST class is TestAPI --
#Path("/test")
public class TestAPI {
private DBOperations dbo;
#POST
#Produces(MediaType.APPLICATION_JSON)
public String create(String jsonPayload) {
System.out.println("Received and added global attribute :"
+ jsonPayload);
dbo.create(jsonPayload);
return jsonPayload;
}
Here is the interface --
public interface DBOperations {
public String create(String json);
public String read(String json);
public String update(String json);
public String delete(String json);
}
Here is the mule flow, which shows how each method of DBOperations is mapped to a different flow in the mule config.
<flow name="jersey-rest-flow" doc:name="jersey-rest-flow">
<http:inbound-endpoint exchange-pattern="request-response"
host="localhost" port="8100" doc:name="HTTP" />
<logger message="Message Received - #[payload]" level="INFO"
doc:name="Logger" />
<jersey:resources doc:name="REST">
<component class="com.test.rest.TestAPI">
<binding interface="com.test.DBOperations"
method="create">
<vm:outbound-endpoint exchange-pattern="request-response"
path="create-data-vm" />
</binding>
<binding interface="com.test.DBOperations"
method="read">
<vm:outbound-endpoint exchange-pattern="request-response"
path="read-data-vm" />
</binding>
<binding interface="com.test.DBOperations"
method="update">
<vm:outbound-endpoint exchange-pattern="request-response"
path="update-data-vm" />
</binding>
<binding interface="com.test.DBOperations"
method="delete">
<vm:outbound-endpoint exchange-pattern="request-response"
path="delete-data-vm" />
</binding>
</component>
</jersey:resources>
</flow>
There is also a third option, if you don't want to tie yourself to Java code - it's REST Router Module: http://mulesoft.github.io/mule-module-rest-router/mule/rest-router-config.htmland I think, that it would be a better fit for you.
What's more, couple days ago I have written an article about REST services on Mule, describing all these three approaches. Examples included. It may be helpful to you:
http://poznachowski.blogspot.com/2013/10/exposing-restful-interface-with-mule-pt1.html
http://poznachowski.blogspot.com/2013/10/exposing-restful-interface-with-mule-pt2.html
We do not want to inject mule specific code in this class to call other Mule flows from within the create method. We are left with no choice but to pass the payload out of this method and handle it in the mule flow.
I disagree to this statement: component bindings inject Mule-free custom interface into your own classes. This is the approach I recommend for your use: http://www.mulesoft.org/documentation/display/current/Component+Bindings
I'm using Mule Studio (Mule 3.2.1CE) to configure a proxy service which simply calls a remote web service. Everything works fine with calling and getting the proper response (using soapUI). I want to log SOAP message received within the ESB. I'm getting a DepthXMLStreamReader message as expected by the CXF component but I'm facing an odd behavior when I use XMLStreamReader object's next() method. Here is the code I use:
public Object onCall(MuleEventContext context) throws Exception {
MuleMessage message = context.getMessage();
DepthXMLStreamReader streamReader = new DepthXMLStreamReader((XMLStreamReader) message.getPayload());
while(streamReader.hasNext()){
streamReader.next();
if(streamReader.getEventType() == XMLStreamReader.START_ELEMENT)
{
System.out.println(streamReader.getLocalName());
}
}
return context.getMessageAsString();
The above code works and prints XML elements but I get the following error afterwards:
org.apache.cxf.interceptor.Fault: Failed to route event via endpoint: DefaultOutboundEndpoint{endpointUri=..., connector=HttpConnector
...
Caused by: org.mule.transport.http.HttpResponseException: Internal Server Error, code: 500
I tried using StaxUtils.nextEvent and StaxUtils.toNextElement, but no difference in result. I wonder why parsing XML by next() method affects mule context. If I use System.out.println(context.getMessageAsString()); before the return statement it prints "[Messaage could not be converted to string]" but it works before while statement in the above code.
Here is my mule config:
<flow name="wsFlow1" doc:name="wsFlow1">
<http:inbound-endpoint exchange-pattern="request-response" host="localhost" port="8090" contentType="text/xml" doc:name="HTTP"/>
<cxf:proxy-service bindingId="..." namespace="http://..." service="..." payload="body" wsdlLocation="..." enableMuleSoapHeaders="false" doc:name="SOAP"/>
<component class="mule.ws.SoapLogging" doc:name="Java"/>
<http:outbound-endpoint exchange-pattern="request-response" address="http://..." contentType="text/xml" doc:name="HTTP"/>
</flow>
Thanks
I don't think this is related to MuleEventContext.
The in-flight payload is a XMLStreamReader. You consume this XMLStreamReader in your component then try to return a String representation of it, which is not possible anymore because you've consumed it.
Try the following in your component:
Serialize the XMLStreamReader to a String
Log this String or part thereof
Return this String from the component.