I've upgraded from Mule 3.5.x to 3.6.x and since the old http transport is deprecated in 3.6.x I wanted to migrate to the new HTTP connector.
Here is the original code for calling my webservice:
<http:outbound-endpoint ref="OrderEndpoint" doc:name="GetApprovedOrder">
<cxf:jaxws-client serviceClass="com.acme.orders.IOrderServiceBean"
port="OrderServiceBean_v2_0Port"
operation="getApprovedOrderOp" />
</http:outbound-endpoint>
The point I have got to with the new connector is as follows:
<cxf:jaxws-client serviceClass="com.acme.orders.v2_0.IOrderServiceBean" port="OrderServiceBean_v2_0Port" operation="getApprovedOrderOp" />
<http:request config-ref="http.request.config" path="acme-services/OrderServiceBean_v2_0" method="POST" />
The issue that I have is that with the old version of the code, after calling the web service, the payload would be the response [java] object. With the new version of the code the payload is a org.glassfish.grizzly.utils.BufferInputStream containing the soap xml.
I could use a combination of xpath and a jaxb-xml-object-transformer to convert the contents of the stream to the response object, this just seems like a backwards step though.
I have looked into using the jaxws-client without the request and also at the ws-consumer, but my following requirements seems to rule these options out (unless I'm just misunderstanding how to use them).
I need to use the contract first method for calling the web services, see above where I have specified serviceClass rather than wsdl.
The web services use basic auth, therefore I need to specify a username and password.
I need to be able to specify the host and port (or at least the address) of the web service.
The solution is: wrap your element into a processor-chain
As follows:
<processor-chain>
<cxf:jaxws-client serviceClass="com.acme.orders.v2_0.IOrderServiceBean" port="OrderServiceBean_v2_0Port" operation="getApprovedOrderOp" />
<http:request config-ref="http.request.config" path="acme-services/OrderServiceBean_v2_0" method="POST" />
</processor-chain>
This is because cxf is intercepting, so after the processor chain you would have the same object as you had in your previous solution.
Related
We are using spring ws as a filter to perform WS-Security based on Token, timestamp and signature on the incoming soap request.
We wants to prevent the XXE attack using the same filter and wondering if its possible.
We're using 'org.springframework.ws.soap.axiom.AxiomSoapMessageFactory' as a messageFactory and it has two setters 'setSupportingExternalEntities' & 'setReplacingEntityReferences' which are by default false.
<!DOCTYPE foo [<!ENTITY xxe SYSTEM "file:///c:/windows/win.ini"> ]>
Now if a entity is decalared using doctype in soap request and it is referred using &xxe; then spring framework throws back an error
org.apache.axiom.soap.SOAPProcessingException: A SOAP message cannot contain entity references because it must not have a DTD
2018-05-18T13:14:33,272 DEBUG [org.springframework.ws.soap.server.SoapMessageDispatcher] Endpoint invocation resulted in exception - responding with Fault
org.apache.axiom.soap.SOAPProcessingException: A SOAP message cannot contain entity references because it must not have a DTD
at org.apache.axiom.soap.impl.builder.StAXSOAPModelBuilder.createEntityReference(StAXSOAPModelBuilder.java:359) ~[axiom-api-1.2.15.jar:1.2.15]
at org.apache.axiom.om.impl.builder.StAXOMBuilder.next(StAXOMBuilder.java:279) ~[axiom-api-1.2.15.jar:1.2.15]
But then this error does not come if we replace &name; with & ;xxe; or & xxe; Spring ws framework let it go through.
I don't want it to go through to any further processing so may be if possible we can somehow don't allow doctype declaration itself in the soap request.
thanks for any help and pointer(s) to resolve this
Adding how I got it resolved. Did not find a way to handle it in the spring-ws filter and Spring was not mis-behaving as it was not trying ti resolve the passed entity.
Later in the flow in our project, we're using standard java DOM parser lib and by adding
factory.setFeature(DISALLOW_DOCTYPE_DECL_FEATURE, true);
we were able to stop the DTD declaration which resolved the XXE issue.
We have a requirement to service the GUI with a SI service. The GUI communicates with the backend over JMS queues, and will wait for a response on a tmp queue that is specified in the jms replyTo header property.
So there can be 10 gui's making queries to the backend, and receiving messages on their individual tmp queues.
So I wrote a SI service using inbound gateway that looks like this
<int:channel id="inChannel" />
<int:channel id="outChannel" />
<int-jms:inbound-gateway id="jmsSampleService" request-destination-name="TEST_QUEUE_2" request-channel="inChannel"
connection-factory="qpidJmsConnectionFactory" extract-request-payload="true" error-channel="errorChannel" />
<int:service-activator input-channel="inChannel" ref="sampleService2" method="processMessage" />
public class SampleService2 {
public Response processMessage(Object obj) throws Exception {
LOG.info("Message received on sample service. ");
Thread.sleep(5000);
Response response = new ResponseImpl();
response.setPayload("Test response");
return response;
}
This works fine, i can see the service return a message back on the jmsReplyTo queue. However, this is a single threaded synchronous operation which means unless GUI1 was serviced, GUI2 's call will be blocked. I want to do this asynchronously since this is simply a method call on a class.
We were doing something similar in mule
<flow name="sampleServiceFlow">
<jms:inbound-endpoint queue="TEST_QUEUE" connector-ref="queryQpidConnector" />
<byte-array-to-object-transformer />
<component>
<spring-object bean="sampleService" />
</component>
<object-to-byte-array-transformer />
<expression-filter evaluator="groovy"
expression="message.getOutboundProperty('replyToQueueName') != null" />
<jms:outbound-endpoint queue="#[header:OUTBOUND:replyToQueueName]" connector-ref="queryQpidConnector" />
</flow>
Since the mule service does not have any txns, it is able to simply consume a message in auto-ack, and have the SampleService's method call service the call.
Is there a way of implementing something like this in SI? perhaps by using the message-driven-channel-adapter? Is there a way to propagate jms header properties between channels?
Simply use concurrency on the inbound gateway. concurrent-consumers is the min max-concurrent-consumers (if specified) is the max; the adapter's container with adjust the concurrency depending on demand.
I am not sure what you mean by
Is there a way to propagate jms header properties between channels?
The jms headers are mapped to integration headers and vice-versa.
I would like to call Apache Solr using Spring Integration. Solr provides RESTful like features for searching e.g. I want to call: http://localhost:8983/solr/#/ccy/query?q=id:*&wt=json this will return a json string.
So the plan is to provide a ReferenceData Controller which calls a service which in turn will call Solr via spring integration. But I need the response to be Synchronous.
I have looked at the sample Spring Integration code provided and came across rest-http example . But it want over my head. So how can I do this and any code sample would be useful.
Thanks
GM
The rest sample is concentrated on the server side; on the client side, you'd need something like...
<int:gateway id="toRest" default-request-channel="foo" service-interface="ToRest" />
<int:channel id="foo" />
<int-http:outbound-gateway id="out" request-channel="foo"
http-method="GET"
url="http://localhost:8983/solr/ccy/query?q=id:{currency}&wt=json">
<int-http:uri-variable name="currency" expression="headers['currency']"/>
</int-http:outbound-gateway>
With ToRest being a Java interface with a method something like String toRest(String in); inject the ToRest instance into your controller and just send an empty String "".
However, I think that # in the middle of the URL is going to give you trouble.
EDIT:
Added uri-variable - the expression can be any SpEL expression, e.g. payload.currency (calls getCurrency() on the message payload); headers['currency']; or #someBean.determineCurrency(payload); etc, etc.
Your gateway can populate the header...
String result(#Payload String payload, #Header("currency") String currency);
Of course, since you are only doing a GET, you could simply set the currency in the payload and just use expression="payload".
Regarding the hash tag, please have a look at: http://en.wikipedia.org/wiki/Fragment_identifier
The fragment identifier functions differently than the rest of the URI: namely, its processing is exclusively client-side with no participation from the web server
I am getting a NullPointerException while invoking a REST webservice hosted on Tomcat. The route looks something like:
<route>
<from uri="rabbitmq:exchange:queue"/>
<to uri="http://localhost:8080/rest-webservice/service/execute?message=${body}" /></route>
I have written a custom type convertor which converts the object I read from the rabbitMQ into a String XML. I need to send this as a parameter to the web service.
I used the <log message="message: ${body}" /> after reading from the rabbitMQ and the type convertor successfully converts the object into String.
Caused by: org.apache.camel.TypeConversionException: Error during type conversion from type: java.lang.String to the required type: org.apache.commons.httpclient.methods.RequestEntity with value
You can't use dynamic expressions like ${body} in the to operation in an endpoint URI. Use recipientList instead if you need to compute a URI dynamically: http://camel.apache.org/how-do-i-use-dynamic-uri-in-to.html
I am running blazeds on the server side. I would like to filter http requests using an http header. My goal is to send extra parameters to the server without changing the signatures of my blazeds services.
On the client side, I am using Flex RemoteObject methods.
With Flex WebService components, it is possible to set an http header using the property httpHeaders. I have not found anything similar on the RemoteObject class...
I couldnt modify http request from flex, instead I can add custom headers to the mx.messaging.messages.IMessage that RemoteObject sends to the server and there, extending flex.messaging.services.remoting.adapters.JavaAdapter (used for accessing Spring beans), it's posible to read the header parameters and put them into the HTTPRequest.
In the flex part, I had to extend mx.rpc.AsyncRequest:
declares a new property "header" and overwrites invoke method that checks if there is a not null value for set the msg.headers.
and mx.rpc.remoting.mxml.RemoteObject:
the constructor creates a new instance of our custom AsyncRequest and overwrite old AsyncRequest and it defines a setHeaders method that set the argument to the custom AsyncRequest.
com.asfusion.mate.actions.builders.RemoteObjectInvoker (extra :P):
this one reads the param declared in the Mate's map RemoteObjectInvoker and puts in the RemoteObject header.
I hope it will be understandable (with my apache english xDDD)
Bye. Agur!
This worked for me using BlazeDS and Spring-Flex 1.5.2
Flex:
use namespace mx_internal;
var service:RemoteObject = new RemoteObject(destination);
var operation:Operation = service[functionName];
operation.asyncRequest.defaultHeaders = {company:'company'};
var token:AsyncToken = operation.send();
Java Spring-Flex:
public class FlexJavaCustomAdapter extends JavaAdapter{
#Override
public Object invoke(Message message) {
String locale = (String) message.getHeader("com.foo.locale");
return super.invoke(message);
}
}
dispatcher-servlet.xml
<bean id="customAdapter" class="org.springframework.flex.core.ManageableComponentFactoryBean">
<constructor-arg value="com.codefish.model.flex.FlexJavaCustomAdapter"/>
</bean>
<flex:message-broker id="_messageBroker" services-config-path="classpath*:/com/codefish/resources/spring/services-config.xml" >
<flex:remoting-service default-adapter-id="customAdapter"
default-channels="my-amf, my-secure-amf" />
</flex:message-broker>
</bean>
RemoteObject uses AMF as the data channel, and is managed in a completely different way than HttpService or WebService (which use Http).
What you can do, is call setCredentials(username,password) and then capture this on the server side using the FlexLoginCommand (either the standard one for your container, or derive your own).
Lookup setCredentials and how you should handle this on both sides (client and server).
I have similar problem, and I afraid there is no simple way to set HTTP header when using AMF. But I've designed following solution.
Flex uses HTTP to transfer AMF, but invokes it through browser interfaces, this allows you to set cookie. Just in document containing application invoke following JavaScript
document.cookie="clientVersion=1.0;expires=2100-01-01;path=/";
Browser should transfer it to server, and you can filter (problem will be if the user will have cookies turned off).
Much more you can invoke JavaScript functions from Flex (more is here: http://livedocs.adobe.com/flex/3/html/help.html?content=passingarguments_4.html).
You might be trying to re-invent the wheel. Is there a reason you can't use the standard HTTP(s) authentication?
A reason I was thinking too to use http headers was for the server to be able to 'recognize' the flex client in the a context of service versionning.
On the server I can always build an indirection/proxy that would allow the different clients to only use 1 end point and route to the right adapter depending on the client version.
The question is on the client side. How would the server identify the flex client token or 'version'. One way is certainly via authentication. But, assuming there is not authentication involved?
We recently run into the same issue and this is how we added our custom headers without creating a subclass:
var operation:AbstractOperation = _remoteSession.getOperation('myRemoteOperation');
var async:AsyncRequest = operation.mx_internal::asyncRequest;
async.defaultHeaders = {my_header:'my_value'};
The AsyncRequest object is actually accessible via the operation object via the mx_internal namespace.
You can debug the $GLOBALS in PHP to see that.
I think this is in the
$GLOBALS['HTTP_RAW_POST_DATA'];
or you can simple do
file_get_contents('php://input');