Implementing REST API calls in mule - Jersey versus Plain-Old-Mule-HTTP - mule

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

Related

How to consume Webservice in Mule using wsdl-cxf component

Hi I was exploring wsdl-cxf for consuming a web service ... I have the following Mule flow :-
<stdio:connector name="stdioConnector" promptMessage="Enter Value :" doc:name="STDIO"/>
<flow name="ServiceFlow" doc:name="ServiceFlow">
<http:inbound-endpoint exchange-pattern="request-response" host="localhost" port="8082" path="mainData" doc:name="HTTP"/>
<cxf:jaxws-service serviceClass="com.test.services.schema.maindata.v1.MainData" doc:name="SOAP"/>
<component class="com.test.services.schema.maindata.v1.Impl.MainDataImpl" doc:name="JavaMain_ServiceImpl"/>
</flow>
<flow name="inputService" doc:name="inputService" >
<stdio:inbound-endpoint system="IN" doc:name="STDIO"/>
<logger message="Payyyload : #[message.payload]" level="INFO" doc:name="Logger"/>
<outbound-endpoint address="wsdl-cxf:http://localhost:8082/mainData?WSDL&method=retrieveDataOperation" doc:name="Generic"/>
<stdio:outbound-endpoint system="OUT" doc:name="STDIO"/>
<mulexml:object-to-xml-transformer doc:name="Object to XML"/>
</flow>
Now the first flow ServiceFlow is the web service exposed which is working perfectly when the following input is given from SOAPUI :-
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:v1="http://services.test.com/schema/MainData/V1">
<soapenv:Header/>
<soapenv:Body>
<v1:retrieveDataRequest>
<v1:Id>33</v1:Id>
</v1:retrieveDataRequest>
</soapenv:Body>
</soapenv:Envelope>
It fetch the data from DB and display the result ...
The second flow inputService try to consume the service using wsdl-cxf ... Here I used stdio:inbound for taking the input .. Now when I pass the Data 33 as input .. it does not able to fetch the value from DB ... Now my web service implement class has the following method :-
public DataResponse retrieveDataOperation(
RetrieveRequest retrieveDataRequest)
{
//All the Logic here
}
where RetrieveRequest retrieveDataRequest is the Object type as input .. So how can I pass the value using wsdl-cxf here which may be taking a String request ... what I mean is how to use wsdl-cxf to consume a webservice and pass a value which is taking Object as parameter ... Please help ..
From the documentation:
The one limitation of the CXF WSDL provider is that it does not allow you to use non-Java primitives (objects that are not a String, int, double, and so on).
Your web service receives a retrieveDataRequest object, not a simple type, so the provider can't be used in your use case.

Accessing the MuleMessage in soap based web service

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?

relate a flow ref to java component mule

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.

Mule 3.2 flow and cxf:jaxws-service

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

XMLStreamReader parser affects MuleEventContext

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.