Mule 3: Creating a RESTful web service endpoint - mule

I'm trying to create an endpoint (I think that's the right word?) in Mule 3 that responds to GET requests. This Mule application runs within a JavaEE web app within a web container.
In my web.xml, I have a MuleRESTReceiverServlet servlet defined so that it handles all requests whose URLs begin with "/rest/":
<web-app>
<listener>
<listener-class>org.mule.config.builders.MuleXmlBuilderContextListener</listener-class>
</listener>
<servlet>
<servlet-name>muleRESTServlet</servlet-name>
<servlet-class>org.mule.transport.servlet.MuleRESTReceiverServlet</servlet-class>
<load-on-startup />
</servlet>
<servlet-mapping>
<servlet-name>muleRESTServlet</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
</web-app>
My <flow> looks like this:
<flow name="myFlow">
<servlet:inbound-endpoint path="category/service" />
<component>
<singleton-object class="com.company.MyComponent" />
</component>
<outbound-endpoint ... />
</flow>
When I sent a GET request to "http://localhost:8080/webappName/rest/category/service", I expect it to invoke the com.company.MyComponent class. But instead, I get the error:
org.mule.api.endpoint.MalformedEndpointException: The endpoint "service" is malformed and cannot be parsed. If this is the name of a global endpoint, check the name is correct, that the endpoint exists, and that you are using the correct configuration (eg the "ref" attribute). Note that names on inbound and outbound endpoints cannot be used to send or receive messages; use a named global endpoint instead.
I tried defining the inbound endpoint as a global endpoint like the error message seems to suggest, but I just get back the same error.
<servlet:endpoint name="myEndpoint" path="category/service" />
...
<flow name="myFlow">
<inbound-endpoint ref="myEndpoint" />
<component>
<singleton-object class="com.company.MyComponent" />
</component>
<outbound-endpoint ... />
</flow>
I've also tried setting the "path" attribute to "rest/category/service" and "/rest/category/service", but still got the same error message.
What am I doing wrong? Thanks.

The org.mule.transport.servlet.MuleRESTReceiverServlet works with a very specific path convention that allows you to directly query an existing Mule endpoint by name or path. Read the JavaDoc here.
In your case, to use servlet:inbound-endpoint, you need to use the org.mule.transport.servlet.MuleReceiverServlet.

Related

Https soap service in mule

I have a requirement where soap based service needs to be consumed and in order to achieve that I had used WSConsumer component in Mule.
Where we give the service URL in the properties file and refer to it.
<ws:consumer-config name="Web_Service_Consumer" wsdlLocation="serviceApi.wsdl"
service="serviceAPI" port="serviceApiSoap12Port" serviceAddress="${serviceurl}"
doc:name="Web Service Consumer"/>
Now after the development we came to know that QA web service is a HTTPS web service and while hitting the service following exception is received
SSLHandshakeException: General SSLEngine problem
I'm able to hit the service with Http:request connector as following
<http:request-config name="HTTP_Request_Configuration" host="${host}" port="${port}"
doc:name="HTTP Request Configuration" protocol="HTTPS">
<tls:context>
<tls:trust-store insecure="true" />
</tls:context>
</http:request-config>
But the issue with above config is it won't work for HTTP configuration.
I should be able to connect to both HTTP & HTTPS as I have different environments.
Is there a way where I can achieve this with ws:consumer??
I assume the HTTP connector configuration shown is the one queried by your WS Consumer connector. A simple solution would be to configure the protocol of your HTTP config via property file but Mule doesn't play well with it because you may end-up with a TLS Context configured with HTTP and your connector won't work. There is a little trick you can do however: create 2 HTTP configurations - one for HTTP and one for HTTPS:
<http:listener-config name="HTTPS_Config"
protocol="HTTPS"
host="${host}"
port="${port}"
doc:name="HTTPS Config" >
<tls:context>
<tls:key-store type="${keystore.type}"
path="${keystore.path}"
keyPassword="${keystore.keyPassword}"
password="${keystore.password}"/>
</tls:context>
</http:listener-config>
<http:listener-config name="HTTP_Config"
host="${host}"
port="${port}"
doc:name="HTTP Config" >
</http:listener-config>
In a property file, define which configuration (i.e. which protocol) should be used:
host=localhost
port=443
protocol=HTTPS # or HTTP
And finally in your flow, use your property to reference the proper HTTP(S) config:
<flow name="http-testFlow">
<http:listener config-ref="${protocol}_Config" path="/test" doc:name="HTTP"/>
...
</flow>
The trick is to name your configuration ${protocol}_Config such as HTTP_Config and HTTPS_Config so the proper one is used at runtime via config-ref="${protocol}_Config". Mule will then dynamically use the proper configuration when your app is launched. This is entirely transparent for the user as only the protocol (HTTP vs. HTTPS) needs to be configured, and it can be used in any environment.
You can use this differently, the idea is to have Mule pick your HTTP or HTTPS dynamically at runtime.
EDIT: to configure your WS Consumer with HTTPS you'll need to reference a proper HTTP Requester Configuration such as:
<ws:consumer-config name="Web_Service_Consumer"
...
connectorConfig="HTTP_Request_Configuration"/>
<http:request-config name="HTTP_Request_Configuration"
...
<tls:context>
...
</tls:context>
...
/>
See Web Service Consumer documentation for details.
Note: though this solution works I would recommend using HTTPS all the time, for security reasons and to have less differences between your dev/QA/Prod/... environments - among other things.
I faced similar issues, we finally chose to have only an HTTPS config and define via property which keystore to use at runtime. In dev we would use a self-signed certificate and a proper keystore in environments requiring proper security.
Hope this helps.

Setting SO_TIMEOUT for Webservice consumer in mule

We are using webservice consumer to hit a service hosted by 3rd party.
While hitting the service, SocketTimeOutException happens after 16 minutes.
Our webservice consumer config is as given below.
<ws:consumer-config name="config_name"
wsdlLocation="${wsdlLocation}"
service="Service_name" port="service_portType"
serviceAddress="${serviceAddress}"
doc:name="Web Service Consumer" />
<ws:consumer config-ref="config_name" operation="test_operation"
doc:name="do_it" />
We have a default response timeout set at top of the configuration file.
<configuration defaultResponseTimeout="1000000" doc:name="Configuration" />
Now, when we asked the 3rd party about the time out, they asked us to set the SO_TIMEOUT of server to 0.
I know we can set it for https:connector with property 'serverSoTimeout="0"'.
My question is how do we set it for Webservice consumer?
This can be set by adding a parameter to your webservice endpoint like this:
http://hostname:port/restoftheendpoint?responseTimeout=120000
Or
This can be set up on the http listener global configuration attached to your wsconsumer config as below:
<ws:consumer-config name="test" wsdlLocation="test.wsdl" service="test" port="testSoap" serviceAddress="${test.endpoint}" doc:name="Web Service Consumer" connectorConfig="HTTP_Request_Config" />
<http:request-config name="HTTP_Request_Config" host="test" port="2000" responseTimeout="30000" doc:name="HTTP Request Configuration">
</http:request-config>

WSO2 - Forward response from REST (called from WSO2) to JMS queue

I've faced an issue, with trying to forward message, returned from my custom REST end-point, into JMS queue.
I wanted to implement something like:
SMTH CUSTOM IS PUSHING MESSAGE TO WSO2 JMS QUEUE called testQueue
WSO2 is retrieving this message, and once there is an message, it's pushing this message next to custom REST service:
Becasue I've defined receive to testResponse inside send section, I'm able to log reponse from REST API inside testResponse.
Now I'm stuck, as I'm trying to somehow push response from REST API next, to let say second JMS queue, called testQueue2.
I've already tried with call tags inside my custom sequence (called testReponse), but it's just not executing at all (I've also tried for test, just to execute second REST API inside, to be just sure, if it's not something with executing of JMS itself...):
Any ideas, how I can move response from called REST API on to JMS queue?
Thanks.
<proxy name="testQueue" startOnLoad="true" transports="jms">
<target>
<inSequence>
<send receive="testResponse">
<endpoint>
<http format="rest" method="POST" uri-template="http://localhost/customRestAPI?message=test" />
</endpoint>
</send>
</inSequence>
<outSequence />
</target>
</proxy>
<sequence name="testResponse">
<log level="full" />
</sequence>
Try adding an "Out Flow" mediation extension as explained here.

Mule - session variables lost after sftp:outbound-endpoint

Running the following config, I set a session variable before an sftp outbound endpoint and after it its not available anymore. I thought session variables were meant to be available across transport barriers? Am I doing something wrong?
<set-session-variable variableName="total" value="#[payload.size()]" />
<foreach>
<!-- Omitted for brevity -->
</foreach>
<sftp:outbound-endpoint encoding="UTF-8"
connector-ref="sftp-out" exchange-pattern="request-response" outputPattern="#[flowVars.filename]"
host="${sftp.host}" port="${sftp.port}" path="${sftp.output.path}" user="${sftp.username}"
responseTimeout="60000" identityFile="${app.home}/${sftp.keyPath}" passphrase="${sftp.passphrase}" />
<logger level="INFO" message="#[sessionVars.total]" />
Being available through transport barrier means that are still available when sending the message through a VM outbound endpoint, inside the same server (same app or different apps).
This is useful for sharing behaviour between flows, use transactions, make asynchronous processing or distribute load in a cluster.
Regards.

Mule 3 async-reply

I have a flow where I receive request via webservice. I forward that request to a JMS queue using component binding. However, I would like to get async-reply from that queue and use it as response to the webservice. Do I need to use reply-to and async-reply-router in the flow? Or is there any other way to do that in Mule 3? Any pointers?
<flow name="mviService">
<http:inbound-endpoint address="http://localhost:62005/mvi"
exchange-pattern="request-response">
<cxf:jaxws-service serviceClass="com.xyz.services.mvi.MVIServicePortType" />
</http:inbound-endpoint>
<component class="com.pennmutual.services.mvi.MVIServiceImpl">
<binding interface="com.pennmutual.mvi.helper.XMLReqProcessorInterface"
method="process121Order">
<jms:outbound-endpoint queue="mviq.121.order" />
</binding>
</component>
<async-reply>
</async-reply>
</flow>
============ EDITED - SEE BELOW FOR RE-FRAMED QUESTION =================
I think I haven't done a good job in describing the scenario. Let me try again. Here's the scenario --
A client calls our service described in this flow "mviService". mviService gets XML request via HTTP/SOAP based inbound endpoint. Let's call this request as XML121Request.4
A component defined in MVI "com.xyz.services.mvi.MVIServiceImpl" makes some changes in XML121Request.
Forwards this XML121 to a JMS queue "mviq.121.order". It uses component binding for this.
The outbound endpoint to this JMS queue is a third party web service where this request is forwarded. The third party acknowledges the receipt of XML121 and the synchronous web service call returns.
The response from that third party service comes at a later point of time, which is generally couple of seconds. The response comes asynchronously. Third party invokes another webservice endpoint on MVI and sends the XML121Response.
MVI puts this response in a JMS queue named "mviq.async.service.reply".
The "mviService" flow needs to wait for this response and send this response (after some modification) to caller(in step 1).
I'm able to get the response from third party and this response is enqued in a queue named "mviq.async.service.reply". I would like to use/consume this message and return it as a response to first call to MVI.
I'm trying to use "request-reply".
<request-reply timeout="60000">
<vm:outbound-endpoint path="request" />
<jms:inbound-endpoint queue="mviq.async.service.reply"
exchange-pattern="one-way" />
</request-reply>
THe problem is that even though I don't want to have outbound-endpoint in this case, I still have to put one as this is required by request-reply tag. The flow waits for 60 seconds at that point of time but even if I put something in the queue "mviq.async.service.reply" the correlation ID doesn't match so the service timesout and returns an error.
flow is mentioned below.
<flow name="mviService">
<http:inbound-endpoint address="http://localhost:62005/mvi"
exchange-pattern="request-response">
<cxf:jaxws-service serviceClass="com.xyz.services.mvi.MVIServicePortType" />
</http:inbound-endpoint>
<component class="com.pennmutual.services.mvi.MVIServiceImpl">
<binding interface="com.xyz.mvi.helper.XMLReqProcessorInterface"
method="process121Order">
<jms:outbound-endpoint queue="mviq.121.order" />
</binding>
</component>
<!-- <logger message="XML Correlation ID 1 is #[mule:message.headers(all)]" /> -->
<request-reply timeout="60000">
<vm:outbound-endpoint path="request" /> <!-- we don't care about this -->
<jms:inbound-endpoint queue="mviq.async.service.reply"
exchange-pattern="one-way" />
</request-reply>
<!-- <component class="com.xyz.mvi.CreateMVIServiceResponse"/> -->
</flow>
===== FLow with REPLY TO =============
<flow name="mviService">
<http:inbound-endpoint address="http://localhost:62005/mvi"
exchange-pattern="request-response">
<cxf:jaxws-service serviceClass="com.xyz.services.mvi.MVIServicePortType" />
</http:inbound-endpoint>
<component class="com.xyz.services.mvi.MVIServiceImpl">
<binding interface="com.xyz.mvi.helper.XMLReqProcessorInterface"
method="process121Order">
<jms:outbound-endpoint queue="mviq.121.order" exchange-pattern="request-response">
<message-properties-transformer scope="outbound">
<add-message-property key="MULE_REPLYTO" value="mviq.async.service.reply" />
</message-properties-transformer>
</jms:outbound-endpoint>
</binding>
</component>
</flow>
I'd like to suggest you do not create a service component class and instead use cxf:proxy-service, which will give you direct access to the SOAP envelope and the opportunity to assemble the response the way you want at XML level.
This will free you from the constraint a service component class imposes on you, hence waive the need to use bindings and open the door to using request-response.
See this SO answer and check the (skinny) proxy service user guide for more information.