SOAP WS with trivial characteristics:
- WSDL address:
http://<ip>:<port>/service/name?wsdl
- target method name:
getData(...)
Part of Spring-integration config ('spring-context.xml') for calling WS:
...
<int:chain input-channel="data" output-channel="stdout">
<!-- transform message to request -->
<int:transformer
ref="soapRequestTransformer"
method="createReq">
</int:transformer>
<!-- define the WS method to be called (getData) -->
<int:header-enricher>
<int:header
name="SoapAction"
value="http://<ip>:<port>/service/name/getData"/>
</int:header-enricher>
<!-- call WS -->
<int-ws:outbound-gateway uri="http://<ip>:<port>/service/name"/>
</int:chain>
...
After transformer (successful) i have request object:
request.getHeaders(): {sequenceNumber=1, correlationId=2bfb560c-
96ba-9c35-96dc-ba16104604b9, id=32f43a24-dee2-461c-a9b9-92c8ee37aaec,
sequenceSize=12, timestamp=1532509142590}
request.getPayload(): org.types.GetDataRequest#77409e4b
How to properly setup the spring-integration to correctly call the WS?
Problem is that WS is not called.
How does this problem look? We can't say anything without at least some stack trace.
Is the name of the WS method used correctly?
The SoapAction value is vendor-specific. You have to consult the WS provided to determine what and how should be presented in that header.
How are the parameters passed?
Not sure about nay parameter. Yes, you can send some query params as well, but doesn't look like that is your questions. Please, be more specific.
By the way, if you send some POJO (e.g. your org.types.GetDataRequest), you need to use a marshaling gateway instead of simple one:
<int-ws:outbound-gateway marshaller="someMarshaller" uri="http://<ip>:<port>/service/name"/>
Not sure, of course, if you have a good XSD-genarated model, based on the provided info in that WSDL...
Related
I have an HTTP Inbound Gateway in my Integration Application, which I will call during some save operation. It's like this. If I have one product, I will call the API once, and if I have more than once, then I will call multiple times. The problem is, for single invoke, SI works just fine. But for multiple calls, request and response get messed up. I thought Spring Integration Channels are just like MQ's, but it is not?
Let me explain this. Let's say I have 2 products. First, I invoke SI for Product A and then for B. Response of A got mapped to request B! It happens all the time. I don't want to use some dirty hacks like wait for the first response to come and invoke again. This means the system has to wait for a long time. I guess we can do it in Spring Integration using task executor, but with all the basic samples out there, I can't find the right one. So please help me find out how can I fix this issue!
My Configuration is :
<int:channel id="n2iMotorCNInvokeRequest" />
<int:channel id="n2iMotorCNInvokeResponse" />
<int:channel id="n2iInvoketransformerOut" />
<int:channel id="n2iInvokeobjTransformerOut" />
<int:channel id="n2iInvokegatewayOut" />
<int-http:inbound-gateway id="i2nInvokeFromPOS"
supported-methods="GET"
request-channel="i2nInvokeRequest"
reply-channel="i2nInvokeResponse"
path="/postProduct/{Id}"
mapped-response-headers="Return-Status, Return-Status-Msg, HTTP_RESPONSE_HEADERS"
reply-timeout="50000">
<int-http:header name="Id" expression="#pathVariables.Id"/>
</int-http:inbound-gateway>
<int:service-activator id="InvokeActivator"
input-channel="i2nInvokeRequest"
output-channel="i2nInvokeResponse"
ref="apiService"
method="getProductId"
requires-reply="true"
send-timeout="60000"/>
<int:transformer input-channel="i2nInvokeResponse"
ref="apiTransformer"
method="retrieveProductJson"
output-channel="n2iInvokeRequest"/>
<int-http:outbound-gateway request-channel="n2iInvokeRequest" reply-channel="n2iInvoketransformerOut"
url="http://10.xx.xx.xx/api/index.php" http-method="POST"
expected-response-type="java.lang.String">
</int-http:outbound-gateway>
<int:service-activator
input-channel="n2iInvoketransformerOut"
output-channel="n2iInvokeobjTransformerOut"
ref="apiService"
method="productResponse"
requires-reply="true"
send-timeout="60000"/>
The i2nInvokeFromPOS gateway is what we call from Web Application which is where all the products will be created. This Integration API will fetch that data, and post it to the backend system so that it will get updated to the other POS locations too!
Steps :
I will send the productId to i2nInvokeFromPOS.
apiTransformer -> retrieveProductJson() method will fetch the product details from DB based on the ID
Send the Request JSON to Backend system using http:outbound-gateway
Get the response from Backend and update the product status as uploaded in DB. Happens in apiService -> productResponse()
Once the response for A is received, all I'm getting is HTTP 500 Error for the Request B! But the Backend API is just fine.
The framework is completely thread-safe - if you are seeing cross-talk between different requests/responses then one (or more) of your components that the framework is invoking is not thread-safe.
You can't keep state in fields in, for example, code invoked from a service activator.
I am working currently on an API that is exposed by Mule ESB 3.5.0 (non-EE). This API accepts a XML file with accounts to be imported via HTTP and puts this task definition into a RabbitMQ queue. Another Mule flow is responsible for taking items from the queue one-at-a-time (thanks to processingStrategy="synchronous") and feeding them to the platform core. The queue is required as the core is able to process one-file-at-a-time.
The setup above is up & running smoothly. What I would like to achieve now, is to enable our customers to troubleshoot the integration by exposing an HTTPS endpoint, where import statuses will be available (identified by some GUID and SHA1 of the request).
I created a simple POJO component that handles the logic of adding the status updates, the method signature being:
void addStatus(final String guid, final String status)
I managed to invoke the method above by defining the bean as
<bean id="importStatusComponent" class="com.example.ImportStatusComponent" />
and invoking the java-component in the Mule flow with:
<invoke object-ref="importStatusComponent" method="addStatus"
methodArguments="#[flowVars.guid], Import started"
methodArgumentTypes="java.lang.String, java.lang.String" />
As we would like to expose this to customers and allow them to implement some programmatic checking of the status, I decided to change the status type to an enum-based dictionary ImportStatusEnum.
Unfortunately, I am unable to fed enum into MEL that goes into <invoke methodArgument=""> tag attribute.
Examples of what I have tried:
1) Arguments as two separate MEL expressions.
<configuration>
<expression-language>
<import class="com.example.ImportStatusEnum" />
</expression-language>
</configuration>
<invoke object-ref="importStatusComponent" method="addStatus"
methodArguments="#[flowVars.guid], #[ImportStatusEnum.STARTED]"
methodArgumentTypes="java.lang.String, com.example.ImportStatusEnum" />
2) Arguments as a single MEL expression.
<configuration>
<expression-language>
<import class="com.example.ImportStatusEnum" />
</expression-language>
</configuration>
<invoke object-ref="importStatusComponent" method="addStatus"
methodArguments="#[flowVars.guid, ImportStatusEnum.STARTED]"
methodArgumentTypes="java.lang.String, com.example.ImportStatusEnum" />
3) Fully qualified class names instead of imports (not shown here).
How to pass an enum value as method argument to invoke component in Mule? Any help will be highly appreciated :)
This one will work
<invoke object-ref="importStatusComponent" method="addStatus" methodArguments="#[flowVars.guid], #[com.example.ImportStatusEnum.STARTED]" methodArgumentTypes="java.lang.String, com.example.ImportStatusEnum" />
I'm trying to create en REST endpoint with Apache Camel. I already have a REST service that return me JSON content and I want this endpoint to get it. My problem is that I don't know what's happening when my Camel route is built.. For the moment, it doesn't do anything. Here is my code :
restConfiguration().component("servlet")
.bindingMode(RestBindingMode.json)
.dataFormatProperty("prettyPrint", "true").host("localhost")
.port(9080);
rest("/ContextServices/rest/contextServices/document")
.consumes("application/json").produces("application/json")
.get("/testContext/557064c8f7f71f29cea0e657").outTypeList(String.class)
.to("bean:processor?method=affiche")
.to(dest.getRouteTo());
I'm running my REST service on a local Tomcat on port 9080, my full URL is
/ContextServices/rest/contextServices/document/{collection}/{id}.
I've tried to read the documentation but there is two syntax and both don't work:
from("rest:get:hello:/french/{me}").transform().simple("Bonjour ${header.me}");
or
rest("/say")
.get("/hello").to("direct:hello")
.get("/bye").consumes("application/json").to("direct:bye")
.post("/bye").to("mock:update");
The first is Java DSL, the second is REST DSL, what's the difference ?
Thanks a lot !
First of all, REST component itself is not a REST implementation.
It just declares language to describe REST endpoints.
You should use actual implementation of REST, something like Restlet (see the full list here)
I can be wrong, but AFAIR, REST endpoint is only for the case when you want to listen for REST requests from another application.
What you need is to make request to REST endpoint and process it.
The question is: when do you want to trigger request?
Is it some event, or may be you want to check external REST service periodically?
For the latter case I use the following pattern:
<route>
<from uri="timer:polling-rest?period=60000"/>
<setHeader headerName="CamelHttpMethod">
<constant>GET</constant>
</setHeader>
<recipientList>
<simple>http://${properties:service.url}/api/outbound-messages/all</simple>
</recipientList>
<unmarshal ref="message-format"/>
<!-- do something with the message, transform it, log,
send to another services, etc -->
<setHeader headerName="CamelHttpMethod">
<constant>DELETE</constant>
</setHeader>
<recipientList>
<simple>http://${properties:service.url}/api/outbound-messages/by-id/${header.id}</simple>
</recipientList>
</route>
Sorry for the example with http component instead of REST.
I simply copy-pasted it from my working project, which uses pure http.
I suppose, rewriting this via something like Restlet or CXF component.
I'm currently trying out Apache camel (as routing engine). I understand that Camel supports multiple DSLs and that it could be configured using Java (Java DSL) or Spring (Spring DSL).
Question:
I have the following Spring DSL configuration. The idea is that if the incoming request has header-param called "name", it would hit when clause or else to would route the request to google:
<camel:route>
<camel:from uri="servlet:///test" />
<camel:choice>
<camel:when>
<camel:header>name</camel:header>
<camel:transform>
<camel:simple>Hello ${header.name} how are you?</camel:simple>
</camel:transform>
</camel:when>
<camel:otherwise>
<camel:to uri="http://www.google.com?bridgeEndpoint=true" />
</camel:otherwise>
</camel:choice>
</camel:route>
I expected the above config to work only for Header Param. However, I noticed that this configuration is working even for Query params as shown in the following request:
http://localhost:8080/<war-context>/test?name=test
Is there a way to make sure that it is made to work only for header params ?
It's well documented here that query params are copied to exchange headers in the servlet component.
Can you use a Spring-WS WebserviceTemplate for calling a webservice and avoid that it generates a SOAP-envelope? That is, the message already contains an SOAP-Envelope and I don't want that the WebserviceTemplate wraps another one around it. :-)
The reason I want this is that I'd like to call a webservice that uses ws-security and do not want to put the ws-security stuff into the WebserviceTemplate, but just want to feed it a message with pre-generated ws-security information in the SOAP-envelope. I tried calling the method sendSourceAndReceiveToResult with a Source already contains a Soap-Envelope with the WS-Security stuff and the webservice template wraps around another Soap-Envelope and thus destroys the message.
You're using ws-security in a strange way... I guess that you're trying to avoid ws-security dependancy by using pre-generated messages - for simple client might make sense, although it's definitely not by-the-book.
You can configure WebServiceTemplate to use plain XML without SOAP by setting messageFactory on WebServiceTemplate to this bean:
<bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate">
<property name="messageFactory" ref="poxMessageFactory" />
</bean>
<bean id="poxMessageFactory" class="org.springframework.ws.pox.dom.DomPoxMessageFactory" />
Interceptors can come in handy for the sort of thing you are trying to do. Take a look at the Interceptor hierarchy here: http://static.springframework.org/spring-ws/docs/1.0-m1/api/org/springframework/ws/EndpointInterceptor.html
You can register an EndpointInterceptor with spring-ws and manipulate the response to your liking.