Configure Spring.Web.Services.WebServiceProxyFactory for SOAP MTOM - soap

I create proxy object for WCF servise with Spring.NEt frwm - Spring.Web.Services.WebServiceProxyFactory.
WCF service use SOAP MTOM. Configuration is here:
<basicHttpBinding>
<binding name="MTOM_BINDING"
maxReceivedMessageSize="10000000000"
receiveTimeout="00:10:00"
sendTimeout="00:10:00"
maxBufferSize="10000000000"
maxBufferPoolSize="524288"
bypassProxyOnLocal="true"
messageEncoding="Mtom">
<readerQuotas
maxArrayLength="10000000000"
maxBytesPerRead="10000000000"
maxDepth="10000000000"
maxNameTableCharCount="10000000000"
maxStringContentLength="10000000000"/>
</binding>
</basicHttpBinding>
<service name="TestService"
behaviorConfiguration="DefaultBehavior">
<endpoint address=""
binding="basicHttpBinding"
bindingConfiguration="MTOM_BINDING"
contract="TestService.ITestService"
bindingNamespace="http://test.com/TEST"
behaviorConfiguration="SimpleWSDLBehavior"/>
<endpoint
contract="IMetadataExchange"
binding="mexHttpBinding"
address="mex"/>
</service>
Confuguration for Spring.Web.Services.WebServiceProxyFactory proxy object:
<object id="testProxy"
type="Spring.Web.Services.WebServiceProxyFactory, Spring.Services">
<property name="ServiceUri" value="http://localhost/TestService.svc?wsdl"/>
<property name="ServiceInterface" value="TestService.ITestService, TestService"/>
<property name="ProductTemplate">
<object>
<property name="Timeout" value="2147483646" />
</object>
</property>
</object>
I could’t find how can I specify for Spring.Web.Services.WebServiceProxyFactory that WCF service use not SOAP but SOAP MTOM.
Because this configuration of Spring.Web.Services.WebServiceProxyFactory except SOAP mesage which has data serialized to text not binnary.

WebServiceProxyFactory is for .asmx Web service.
For WCF support, see:
http://www.springframework.net/doc-latest/reference/html/wcf.html

Related

Configure different handlers for APIs based on HTTP method in WSO2 synapse file

I have a WSO2 synapse file to handle my API requests at gateway level. I have configured my GET and POST/PUT for an endpoint as below. I have a custom handler which deals with allowing a specific host to call these APIs. I have a requirement to allow GET from any host and POST/PUT only from a specific host. However, I cannot configure it in my synapse file because handlers which we define in the file are getting applied to all HTTP methods. Is there way to configure handlers based on HTTP method for the same endpoint/context. How I can have my custom handler (com.abc.wso2.handler.HostRestrictionHandler) applicable to only POST?PUT calls? Below is my configuration.
<api xmlns="http://ws.apache.org/ns/synapse" context="/user/notification/v3" version="v2" version-type="context">
<resource methods="GET" uri-template="/*">
<inSequence>
<class name="org.wso2.carbon.apimgt.gateway.mediators.TokenPasser"/>
<filter regex="PRODUCTION" source="$ctx:AM_KEY_TYPE">
<then>
<class name="com.abc.mediators.DispatchMediator">
<property name="url" value="http://api.{HOST_NAME}.com/user/notification/v3"/>
</class>
<send>
<endpoint name="Notification_API">
<address>
<timeout>
<duration>30000</duration>
<responseAction>fault</responseAction>
</timeout>
<suspendOnFailure>
<errorCodes>-1</errorCodes>
<initialDuration>0</initialDuration>
<progressionFactor>1.0</progressionFactor>
<maximumDuration>0</maximumDuration>
</suspendOnFailure>
<markForSuspension>
<errorCodes>-1</errorCodes>
</markForSuspension>
</address>
</endpoint>
</send>
</then>
<else>
<sequence key="_sandbox_key_error_"/>
</else>
</filter>
</inSequence>
<outSequence>
<send/>
</outSequence>
</resource>
<resource methods="POST PUT" uri-template="/*">
<inSequence>
<property name="X-Forwarded-Host" scope="transport" expression="$trp:Host"/>
<class name="org.wso2.carbon.apimgt.gateway.mediators.TokenPasser"/>
<filter regex="PRODUCTION" source="$ctx:AM_KEY_TYPE">
<then>
<class name="com.abc.mediators.DispatchMediator">
<property name="url" value="http://api.{HOST_NAME}.com/user/notification/v3"/>
</class>
<send>
<endpoint name="Notification_API_2">
<address>
<timeout>
<duration>30000</duration>
<responseAction>fault</responseAction>
</timeout>
<suspendOnFailure>
<errorCodes>-1</errorCodes>
<initialDuration>0</initialDuration>
<progressionFactor>1.0</progressionFactor>
<maximumDuration>0</maximumDuration>
</suspendOnFailure>
<markForSuspension>
<errorCodes>-1</errorCodes>
</markForSuspension>
</address>
</endpoint>
</send>
</then>
<else>
<sequence key="_sandbox_key_error_"/>
</else>
</filter>
</inSequence>
<outSequence>
<send/>
</outSequence>
</resource>
<handlers>
<handler class="com.abc.wso2.handler.HostRestrictionHandler">
<property name="allowedHosts" value="my.customhost.com" />
</handler>
</handlers>
</api>
You can use this(context.getProperty("api.ut.HTTP_METHOD")) to get the method resource and this(context.getProperty("api.ut.hostName")) to get the host. So you can implement a logic in your handler to check the host and the resource and then allow the request.

WSO2 EI Dataservice as Rest API with sequence calls

I'm new to wso2 and currently I'm trying to expose a mongodb data service as REST API. I followed this tutorial and exposed my data service as Rest resource like this:
<data>
<config>...</config>
<query id="count" useConfig="MongoDB">
<expression>myCollection.count()</expression>
<result outputType="json">{
"Documents": {
"Document": [
{
"Data": "$document"
}
]
}
}</result>
</query>
<operation name="count_op">
<call-query href="count"/>
</operation>
<resource method="GET" path="users/count">
<call-query href="count"/>
</resource>
</data>
Works fine, however when I tried to access the resource from my angular2 project, I stumbled upon the CORS problem. I read up some posts about that and figured I need to modify my Rest API with something like this:
<resource methods="OPTIONS" url-mapping="/*">
<inSequence>
<property action="set" name="HTTP_SC" scope="axis2"
type="STRING" value="200"/>
<property action="set" name="messageType" scope="axis2"
type="STRING" value="application/json"/>
<sequence key="rest_add_access_control_headers"/>
<respond/>
</inSequence>
<outSequence/>
<faultSequence>
<sequence key="rest_add_access_control_headers"/>
<respond/>
</faultSequence>
</resource>
I tried to integrate this code with my data service definition (the one above) but I can't get it working and it makes me wonder if data service exposed as REST resource are the same thing as Rest APIs? It seems I cannot invoke any elements or other mediators in the data service definition. Do I need to create an actual Rest API for this? If so, how can I use my mongo dataservice as a resource for my Rest API?
EDIT: The CORS error I'm getting from my angular2 project when trying to access the service is "No 'Access-Control-Allow-Origin' header is present on the requested resource." which is another topic. But it led me to edit my data service so I edited my data service resource element and added a new one:
<resource method="GET" path="users/count">
<inSequence>
<property action="set" name="HTTP_SC" scope="axis2" type="STRING" value="200"/>
<property action="set" name="messageType" scope="axis2" type="STRING" value="application/json"/>
<sequence key="rest_add_access_control_headers"/>
<respond/>
</inSequence>
<outSequence/>
<faultSequence>
<sequence key="rest_add_access_control_headers"/>
<respond/>
</faultSequence>
<call-query href="count"/>
</resource>
<resource method="OPTIONS" path="users/count">
<inSequence>
<property action="set" name="HTTP_SC" scope="axis2"
type="STRING" value="200"/>
<property action="set" name="messageType" scope="axis2"
type="STRING" value="application/json"/>
<sequence key="rest_add_access_control_headers"/>
<respond/>
</inSequence>
<outSequence/>
<faultSequence>
<sequence key="rest_add_access_control_headers"/>
<respond/>
</faultSequence>
</resource>
rest_add_access_control_headers sequence looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<sequence name="rest_add_access_control_headers" xmlns="http://ws.apache.org/ns/synapse">
<property name="Access-Control-Allow-Origin" scope="transport"
type="STRING" value="*"/>
<property name="Access-Control-Allow-Methods" scope="transport"
type="STRING" value="GET,POST,PUT,DELETE,OPTIONS"/>
<property name="Access-Control-Allow-Headers" scope="transport"
type="STRING" value="origin, content-type, accept, Authorization"/>
</sequence>
The first seems to be fine but the second one makes my dataservice faulty, giving this error in managemenet console:
DS Code: UNKNOWN_ERROR Source Data Service:- Name: mongodb_dataservice Location: \MongoDB.dbs Description: N/A Default Namespace: http://ws.wso2.org/dataservice Nested Exception:- java.lang.NullPointerException at org.wso2.carbon.dataservices.core.DataServiceFactory.createDataService(DataServiceFactory.java:207) at org.wso2.carbon.dataservices.core.DBDeployer.createDBService(DBDeployer.java:797) at org.wso2.carbon.dataservices.core.DBDeployer.processService(DBDeployer.java:1152) at org.wso2.carbon.dataservices.core.DBDeployer.deploy(DBDeployer.java:201) at org.apache.axis2.deployment.repository.util.DeploymentFileData.deploy(DeploymentFileData.java:136) at org.apache.axis2.deployment.DeploymentEngine.doDeploy(DeploymentEngine.java:807) at org.apache.axis2.deployment.repository.util.WSInfoList.update(WSInfoList.java:144) at org.apache.axis2.deployment.RepositoryListener.update(RepositoryListener.java:377) at org.apache.axis2.deployment.RepositoryListener.checkServices(RepositoryListener.java:254) at org.apache.axis2.deployment.RepositoryListener.startListener(RepositoryListener.java:371) at org.apache.axis2.deployment.scheduler.SchedulerTask.checkRepository(SchedulerTask.java:59) at org.apache.axis2.deployment.scheduler.SchedulerTask.run(SchedulerTask.java:67) at org.wso2.carbon.core.deployment.CarbonDeploymentSchedulerTask.runAxisDeployment(CarbonDeploymentSchedulerTask.java:93) at org.wso2.carbon.core.deployment.CarbonDeploymentSchedulerTask.run(CarbonDeploymentSchedulerTask.java:138) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:748) Caused by: java.lang.NullPointerException at org.wso2.carbon.dataservices.core.engine.DataService.init(DataService.java:352) at org.wso2.carbon.dataservices.core.DataServiceFactory.createDataService(DataServiceFactory.java:190) ... 20 more
Again, I'm not sure if I'm even supposed to put such code in data service definition since the code was meant to be for Rest API definition, the one where you use sequences, mediators etc...
How can I consume my dataservice with an ESB API? Would you please provide an example on how to do that ? I did some research but couldn't find anything.
May I know why you are unable to invoke the data service? Are you getting any error while invocation? if you could provide the logs it will be helpful.
Moreover DSS is used to fetch data from DB ,The best practice is to provide an ESB API which will consume this service rather than exposing DSS service to outside world directly

Restore task class in WSO2 ESB

When i use a task in WSO2 ESB it always returns the same error with every web service:
"Unable to handle request. The action '(mySoapAction)' was not recognized"
where (mySoapAction) is every SOAP action used, for EVERY action, for EVERY proxy service i use for task implementation.
What could i do in order to fix this error? I thought a task class error in org.apache.synapse.startup.tasks.MessageInjector.
Obvoiusly the task implementation is correct, because the same tasks some day ago were perfectly working. Suggestions?
Here come a sample with the weather webservice (http://wsf.cdyne.com/WeatherWS/Weather.asmx?WSDL)
Proxy service :
<?xml version="1.0" encoding="UTF-8"?>
<proxy xmlns="http://ws.apache.org/ns/synapse"
name="TestSOF"
transports="https http"
startOnLoad="true"
trace="disable">
<target>
<endpoint>
<wsdl service="Weather"
port="WeatherSoap12"
uri="http://wsf.cdyne.com/WeatherWS/Weather.asmx?WSDL"/>
</endpoint>
<outSequence>
<log level="full"/>
<property name="OUT_ONLY" value="true"/>
<property name="transport.vfs.ReplyFileName" value="weather.xml" scope="transport"/>
<send>
<endpoint>
<address uri="vfs:file:///E:/temp"/>
</endpoint>
</send>
</outSequence>
</target>
<publishWSDL uri="http://wsf.cdyne.com/WeatherWS/Weather.asmx?WSDL"/>
</proxy>
Task :
<?xml version="1.0" encoding="UTF-8"?>
<task xmlns="http://ws.apache.org/ns/synapse"
name="TestSOFTask"
class="org.apache.synapse.startup.tasks.MessageInjector"
group="synapse.simple.quartz">
<trigger count="1" interval="1"/>
<property xmlns:task="http://www.wso2.org/products/wso2commons/tasks"
name="proxyName"
value="TestSOF"/>
<property xmlns:task="http://www.wso2.org/products/wso2commons/tasks"
name="soapAction"
value="http://ws.cdyne.com/WeatherWS/GetCityWeatherByZIP"/>
<property xmlns:task="http://www.wso2.org/products/wso2commons/tasks" name="message">
<weat:GetCityWeatherByZIP xmlns:weat="http://ws.cdyne.com/WeatherWS/">
<weat:ZIP>11010</weat:ZIP>
</weat:GetCityWeatherByZIP>
</property>
<property xmlns:task="http://www.wso2.org/products/wso2commons/tasks"
name="format"
value="soap12"/>
<property xmlns:task="http://www.wso2.org/products/wso2commons/tasks"
name="injectTo"
value="proxy"/>
</task>
Schedule the task and you will find the service response in a file name weather.xml
If you want to change from soap12 to soap11 :
Change the value of property "format" in the task def to : soap11
Change the endpoint def in the proxy service using port "WeatherSoap" rather than "WeatherSoap12"
Hope it will help you to find what is going wrong with your conf...

WSO2 ESB How to send an email from a JMS message to a custom email address?

I'm wondering if someone can help me with the following setup.
I want to send a message from my application via JMS to WSO2 ESB so the ESB can send it as en email. I'm using ActiveMQ as queue. Until now, when I send a message via the ActiveMQ interface to the queue, wso2 esb gets it. Then, wso2 esb send the message as email to a specific email address.
So I could configure ActiveMQ and WSO2 esb to send the JMS message to a specific email address (eg. specificaddress#test.com).
And here is my question. How can I modify the receiver address for the email? In the ESB sequence configuration, I currently use a specific address. But the address is dependant on the user that uses my application. So I have to change the "To" property, dependant on the user that has to receive the email.
So how can I pass the values for the properties "To", but also for "Subject", through a JMS message to WSO2 esb sequence?
That's the configuration of the sequence I have:
<sequence xmlns="http://ws.apache.org/ns/synapse" name="sendMail">
<property name="messageType" value="text/html" scope="axis2" type="STRING"></property>
<property name="ContentType" value="text/html" scope="axis2"></property>
<property name="Subject" value="This is the subject." scope="transport"></property>
<property name="To" value="specificaddress#test.com" scope="transport"></property>
<property name="OUT_ONLY" value="true" scope="default" type="STRING"></property>
<log level="full"></log>
<send>
<endpoint>
<address uri="mailto:"></address>
</endpoint>
</send>
</sequence>
And this is my proxy:
<?xml version="1.0" encoding="UTF-8"?>
<proxy xmlns="http://ws.apache.org/ns/synapse"
name="sendToMailIn"
transports="jms"
statistics="disable"
trace="disable"
startOnLoad="true">
<target inSequence="sendMail"/>
<description/>
</proxy>
I hope someone has a clue.
UPDATE
I think I have the solution!!! Wow :-) Maybe, at first, I was stupid, but here it is ...
What you can do is sending a SOAP envelop through a JMS message to WSO2 ESB. And then, with an XPath expression, you can get the passed values. A little bit has to changed at the proxy and the sequence.
This is the new sequence:
<sequence xmlns="http://ws.apache.org/ns/synapse" name="sendMail">
<property name="messageType" value="text/html" scope="axis2" type="STRING"></property>
<property name="ContentType" value="text/html" scope="axis2"></property>
<property xmlns:ns="http://org.apache.synapse/xsd" name="Subject" expression="$body/subject" scope="transport"></property>
<property xmlns:ns="http://org.apache.synapse/xsd" name="To" expression="$body/to" scope="transport"></property>
<property name="OUT_ONLY" value="true" scope="default" type="STRING"></property>
<log level="full"></log>
<send>
<endpoint>
<address uri="mailto:"></address>
</endpoint>
</send>
</sequence>
And this is the new proxy:
<?xml version="1.0" encoding="UTF-8"?>
<proxy xmlns="http://ws.apache.org/ns/synapse"
name="sendToMailIn"
transports="jms"
statistics="disable"
trace="disable"
startOnLoad="true">
<target inSequence="sendMail"/>
<parameter name="transport.jms.ContentType">
<rules>
<jmsProperty>contentType</jmsProperty>
<default>text/xml</default>
</rules>
</parameter>
<description/>
</proxy>
And this was my SOAP Envelop that WSO2 ESB receives from my ActiMQ queue as JMS message:
<?xml version="1.0" encoding="utf-8"?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org /soap/envelope/">
<soapenv:Body>
<subject>Email subject comes here.</subject>
<to>address#test.com</to>
</soapenv:Body>
</soapenv:Envelope>
you have couple of options here.
you can use http headers and send the "to", "subject" values to ESB.
Send it as a payload value and extract using XPath expression
I solved it with using JSON in a JMS message. Here is my setup that works for me.
This is my JSON message:
{"to":"mail#test.com","subject":"TestSubject","mailbody":"Some body text ..."}
This is my proxy:
<?xml version="1.0" encoding="UTF-8"?>
<proxy xmlns="http://ws.apache.org/ns/synapse"
name="sendToMailIn"
transports="jms"
statistics="disable"
trace="disable"
startOnLoad="true">
<target inSequence="sendMail"/>
<parameter name="transport.jms.ContentType">
<rules>
<jmsProperty>contentType</jmsProperty>
<default>application/json</default>
</rules>
</parameter>
<parameter name="transport.mail.ContentType">application/xml</parameter>
<description/>
</proxy>
And this is my sequence:
<sequence xmlns="http://ws.apache.org/ns/synapse" name="sendMail">
<property name="messageType" value="text/plain" scope="axis2" type="STRING"></property>
<property name="ContentType" value="text/plain" scope="axis2"></property>
<property xmlns:ns="http://org.apache.synapse/xsd" name="Subject" expression="json-eval($.subject)" scope="transport"></property>
<property xmlns:ns="http://org.apache.synapse/xsd" name="To" expression="json-eval($.to)" scope="transport"></property>
<property name="OUT_ONLY" value="true" scope="default" type="STRING"></property>
<script language="js">
<![CDATA[var mailbody = mc.getPayloadJSON().mailbody.toString(); mc.setPayloadXML(
<ns:text xmlns:ns="http://ws.apache.org/commons/ns/payload">{mailbody}</ns:text>);]]>
</script>
<log level="full"></log>
<send>
<endpoint>
<address uri="mailto:"></address>
</endpoint>
</send>
</sequence>

JBoss ESB XML MEP Behviour

I am using JBoss AS 5.1.0 and Jboss ESB 4.10
I am trying to Invoke a Service which has a single action. I have Set MEP = oneWay for the Service.
When I Invoke the Service Using the Below Method I do not get a reply but an Exception.
new ServiceInvoker("Chapter3Sample", "Chapter3Service").deliverSync(esbMessage, 10000);
WHen I change mep=RequestResponse : I am able to get the Reply
As per my understanding ESB Message has a ReplyTo field (Since I am invkoing a Sync Request) the Message should be returned back by the last Action which is not happening in my case. Please find below the ESB XML:
<?xml version="1.0"?>
<jbossesb parameterReloadSecs="5"
xmlns="http://anonsvn.labs.jboss.com/labs/jbossesb/trunk/product/etc/schemas/xml/jbossesb-1.0.1.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://anonsvn.labs.jboss.com/labs/jbossesb/trunk/product/etc/schemas/xml/jbossesb-1.0.1.xsd http://anonsvn.jboss.org/repos/labs/labs/jbossesb/trunk/product/etc/schemas/xml/jbossesb-1.0.1.xsd">
<providers>
<jms-provider connection-factory="ConnectionFactory" name="JBossMQ">
<jms-bus busid="chapter3GwChannel">
<jms-message-filter dest-name="queue/chapter3_Request_gw" dest-type="QUEUE"/>
</jms-bus>
<jms-bus busid="chapter3EsbChannel">
<jms-message-filter dest-name="queue/chapter3_Request_esb" dest-type="QUEUE"/>
</jms-bus>
</jms-provider>
</providers>
<services>
<service category="Chapter3Sample"
description="A template for Chapter3" name="Chapter3Service">
<listeners>
<jms-listener busidref="chapter3GwChannel" is-gateway="true" name="Chapter3GwListener"/>
<jms-listener busidref="chapter3EsbChannel" name="Chapter3Listener"/>
</listeners>
<actions mep="OneWay">
<action class="org.jboss.soa.esb.samples.chapter3.MyAction"
name="BodyPrinter">
<property name="process" value="displayMessage"/>
<property name="symbol" value="*"/>
<property name="count" value="50"/>
<property name="propertyName">
<hierarchicalProperty attr="value">
<inner name="myName" random="randomValue"/>
</hierarchicalProperty>
</property>
<property name="exceptionMethod" value="processException"/>
<property name="okMethod" value="processSuccess"/>
</action>
</actions>
</service>
</services>
</jbossesb>
When your are invoking call as synchronus.
new ServiceInvoker("Chapter3Sample", "Chapter3Service").deliverSync(esbMessage, 10000).
set mep=RequestResponse.
when your are invoking call asynchronus.
new ServiceInvoker("Chapter3Sample", "Chapter3Service").deliverASync(esbMessage, 10000).
set mep=oneWay .