Context :
SAP Solution Manager (will call it SolMan) exposes a SOAP webservice where a 3rd party can call to interoperate with it. The 3rd party application can also implement the same webservice interface so that SolMan can interoperate in the other direction.
I need to interoperate with SolMan in both directions. My webservice is a WCF Service based on the interface and the types generated from the WSDL of the SolMan webservice with VS2010 "Add Service reference".
Problem #1
In the WSDL, all of the declared operations has soapAction="". When the service contract interface has been generated from VS2010, all OperationContractAttribute are Action="", ReplyAction="*". Since more than one OperationContract has the same Action (empty string), the Webservice doesn't work, the exception is :
[InvalidOperationException: The operations AcceptIncidentProcessing
and AddInfo have the same action (). Every operation must have a
unique action value.]
Is this normal? There is another way to fix it other than removing all Action="" declarations from the generated ServiceContract interface?
Problem #2
I've removed all empty string Actions from the generated ServiceContract interface.
I can now inspect the WSDL generated by my webservice and call it with my .net wcf client.
SolMan is unable to call my webservice, after enabling MessageLogging in my web.config, I found that my service has faulted with :
<s:Fault>
<faultcode xmlns:a="http://schemas.microsoft.com/ws/2005/05/addressing/none" xmlns="">a:ActionNotSupported</faultcode>
<faultstring xml:lang="en-CA" xmlns="">The message with Action '' cannot be processed at the receiver, due to a ContractFilter mismatch at the EndpointDispatcher. This may be because of either a contract mismatch (mismatched Actions between sender and receiver) or a binding/security mismatch between the sender and the receiver. Check that sender and receiver have the same contract and the same binding (including security requirements, e.g. Message, Transport, None).</faultstring>
</s:Fault>
Indeed inspecting the SOAP request message shows that soapaction is present in the HTTP Headers, but empty, and that Action is also presents in the SOAP headers and it is also empty .
So I found a Post about the Microsoft's 1DispatchByBodyBehavior1 sample, gave it a try and replayed the http request with Fiddler wihout success. The only way I manage to make it work, is by removing the <Action> and <To> from the SOAP headers in Fiddler. SolMan will indeed continue to pass these headers.
Is it valid that SolMan sets no Action when calling a SOAP webservice?
What am I doing wrong?
Related
I want to set a dynamically generated HTTP header on each SOAP JAX-WS request.
If I wanted to set the same HTTP header on each JAX-WS request I could use the technique here, i.e.
public class MyApplicationClass {
// Inject an instance of the service's port-type.
#WebServiceRef(EchoService.class)
private EchoPortType port;
// This method will invoke the web service operation and send transport headers on the request.
public void invokeService() {
// Set up the Map that will contain the request headers.
Map<String, Object> requestHeaders = new HashMap<String, Object>();
requestHeaders.put(“MyHeader1”, “This is a string value”);
requestHeaders.put(“MyHeader2”, new Integer(33));
requestHeaders.put(“MyHeader3”, new Boolean(true));
// Set the Map as a property on the RequestContext.
BindingProvider bp = (BindingProvider) port;
bp.getRequestContext().put(com.ibm.websphere.webservices.Constants.REQUEST_TRANSPORT_PROPERTIES, requestHeaders);
// Invoke the web services operation.
String result = port.echoString(“Hello, world!”);
}
}
However, here I want to use a different HTTP header for each request. Essentially I want to include a X-RequestId header or similar with a random value, so the receiving server can distinguish between requests duplicated on a timeout either by the Java client or (worse) an inline HTTP proxy.
Moreover, it JAX-WS retries the same call, I don't want it to regenerate the header (obviously).
Note that my application is already covered in the equivalent of port.echoString (lots of calls to the web service). I can't manually change the header in front of each such call because:
they share the same binding provider, and this would not be thread-safe (i.e. user A could change the header, user B could change the header, then user A could call, then user B could call, and the same header be passed)
this would require modification all over the code.
What I want to do is add something to the class that serialises each request, to add the header at serialisation time.
Questions that are related but are not duplicates:
java web service client, adding http headers - does not use JAX-WS binding, i.e. each call has to be made manually
How to add header to SOAP request? - SOAP headers not HTTP headers
As for the unique value aspect, you can use the JDK's UUID class to create a GUID:
requestHeaders.put("X-RequestId", java.util.UUID.randomUUID().toString());
As for the clarified thread safety concern, based on the JAX-WS specification (JSR-224) section 9.3 I'd suggest using a JAX-WS client handler to do this as the handler spec identifies a thread safe mechanism: MessageContext:
9.3.3 Handler Implementation Considerations
Handler instances may be pooled by a JAX-WS runtime system. All
instances of a specific handler are considered equivalent by a JAX-WS
runtime system and any instance may be chosen to handle a particular
message. Different handler instances may be used to handle each
message of an MEP. Different threads may be used for each handler in a
handler chain, for each message in an MEP or any combination of the
two. Handlers should not rely on thread local state to share
information. Handlers should instead use the message context, see section 9.4.
You can write one central handler class and attach it to the BindingProvider's handler chain to avoid changing all the places you invoke the service operation across the application. You can add a handler to the handler chain programmatically or via the #HandlerChain annotation companion to #WebServiceRef
This post describes using the handler framework's MessageContext to set outbound http headers like you want. However in your case you want to set the X-RequestId with the UUID value discussed above.
I need to create the dynamic client to call web services, which can call web services with Service Mode as Service.Mode.PAYLOAD as well as Service.Mode.MESSAGE. I have created the Dispatcher as:
Dispatch<Source> sourceDispatch =service.createDispatch(portName, Source.class, Service.Mode.PAYLOAD);
But this can invoke the services with Service Mode PAYLOAD only. Please suggest me the way how can I previously determine the Service Mode from WSDL link (service Mode parser code) before creating Dispatch instance?
The mode does not depend on the WSDL.
If you want to pass to sourceDispatch.invoke(T msg) an entire SOAP message use mode.MESSAGE. If you only want to pass the PAYLOAD (the body) use mode.PAYLOAD, and invoke will wrap it in a message for you.
The mode also determines wether invoke returns you a message or the payload.
Could you please explain what exactly the method getHeaders from SOAPHandler interface is supposed to do?
http://docs.oracle.com/javaee/5/api/javax/xml/ws/handler/soap/SOAPHandler.html#getHeaders%28%29
I'm not sure if it creates additional headers or if it should just tell the runtime which headers the message should have.
I've been sweeping the internet looking for detailed information but I couldn't find any. I think is is so basic and obvious that no documentation is needed LOL :-)
Thanks
The description you're looking for can be found in the JAX-WS 2.2 spec in the section titled, "10.2.1 SOAP mustUnderstand Processing". Inbound messages require an additional processing step that occurs before the start of normal handler processing. Basically, the set of QName instances returned from getHeaders allows the handler to contribute to the full set of SOAP headers that a node understands (the other contributors to the full set are documented in the spec). If an inbound SOAP header contains the mustUnderstand attribute with a value of 1 or true, then an exception will be generated if that header can't be marked as understood.
EDIT: Apparently I was wrong and after reading further I must agree, therefore please ignore this.
A SOAP message is a HTTP request. HTTP requests can have number of different headers as a part of the message (e.g. in SOAP 1.1 there was a header called SOAPAction, which could contain the name of the service and operation). The getHeaders function returns the list of all the headers QNames that came with the request, so in case of previous example, you would get a list that would contain element of value "SOAPAction".
I need to post jobs in monster.com by using their web service.
I have genarated the client files using wsimport.
I am calling updateJob method which accepts <Job> type object.
The client files have dedicated classes for SOAP headers, in which I am
setting the required username and password.
But I have no idea how do bind this Header object in my request, as the method
I am calling only accepts <job> type objects.
The dedicated objects which constitute soap headers are being populated as follows
MonsterHeader monsterHeader=new MonsterHeader();
MessageDataType MessageDataType=new MessageDataType();
MessageDataType.setMessageId("Company Jobs created on 06/09/2004 02:41:44 PM");
MessageDataType.setTimestamp("2004-06-09T14:41:44Z");
monsterHeader.setMessageData(MessageDataType);
Security security=new Security();
UsernameTokenType UsernameTokenType=new UsernameTokenType();
UsernameTokenType.setUsername("testxftp");
PasswordType PasswordType=new PasswordType();
PasswordType.setValue("ftp12345");
UsernameTokenType.setPassword(PasswordType);
The method which is being called is businessGatewayInterface.updateJob(job);
Also , please advise on some easy way to view my outgoing SOAP request.
I have a use case that required all calls to NewWebService are routed to OldWebService, if the SOAP request does not validate against NewWebService's XSD and WSDL. NewWebService is located on ServerA and OldWebService is on ServerB.
Abstractly, I know I need some mechanism that will allow me to take a SOAP request that hits NewWebService, send it to OldWebService, then return the SOAP result back to the client. My limited experience with spring-ws is making it difficult to decide how to accomplish that.
My first thought was to build a SOAP client into the NewWebService that calls the OldWebService whenever the payload cannot be validated. Is this the best solution, or is there a better way to allow the NewWebService to act as a pass-through for certain requests?
My solution was to write a custom SoapRequestFilter that implements a javax.servlet.Filter and a new class that extends HttpServletRequestWrapper. Since HttpServletRequestWrapper implements the HttpServletRequest interface, extending the wrapper allows you to copy the HttpRequest and act on the stream without consuming the object and causing issues downstream.
Once I had the filter and wrapper, I was able to parse the endpoint and payload from the HttpRequest. If the request needed to be redirected, I created a new HttpUrlConnection to the old SOAP WebService and set the InputStream from that response to the OutputStream of the HttpResponse.
I think Apache Camel can help you in an efficient way.
You can take a look at its proxy example, it's simple and easy to fulfill your requirement.
http://camel.apache.org/cxf-proxy-example.html