Accessing SOAP web service with incorrect wsdl - java

Background:
I need to consume an existing web service (SOAP over http) that has a couple of issues:
1) The wsdl on the server doesn't even resemble the web service as described in their documentation, which includes a completely different wsdl file
2) The wsdl file provided with their documentation seems to come close to describing the web service on the server, but when I generated java client code using cxf and used it to access the web service, cxf throws exceptions like the following
javax.xml.bind.UnmarshalException: unexpected element (uri:"http://us-labs.companyxyz.com/", local:"searchResponse"). Expected elements are <{http://companyxyz.com/xyz-xml/2.0/}searchResponse>
... 33 more
I'm no SOAP expert, but assuming this means the namespaces in their response don't match those defined in the wsdl.
Since my application is written in java, I was able to connect and get a response using commons http client and a handcrafted SOAP request, so worst case I can fall back to that and parse the response to get what I need.
My questions:
Did I interpret the exception correctly?
If no: any suggestions on how I can debug this?
If yes: can anyone suggest better alternatives to handcrafting http requests and parsing xml by hand? (Getting correct wsdl is, unfortunately, not an option)
Thanks in advance.

Most likely. The response is using the namespace "http://us-labs.companyxyz.com/", but in the WSDL, the same element is declared with namespace "http://companyxyz.com/xyz-xml/2.0/".
I'm not familiar with CXF, but other SOAP frameworks usually offer some kind of logging capabilities. It would probably help you if the SOAP requests and responses are logged somewhere for more specific analysis.
Why is it not an option to get a correct WSDL? If you really are able to "handcraft" correct SOAP requests and expect to be able to "handparse" the responses, you should be able to write the WSDL yourself as well. Of course, the WSDL should be provided to you by the service operator, but if you mean that noone is able to provide you with a correct WSDL, I would consider writing it myself instead of creating and parsing the SOAP messages manually.

I think you interpreted the exception correctly - the namespace is different than expected.
It is also not really unexpected. it is a fact of life that vendor supplied wsdls are not always correct. We actually write our own WSDLs and XSDs for vendor applications for just that reason.
You can use your own WSDL even run-time. There are some SO questions on that, here and here.
You could also have a look here. I haven't tried it, but it could work.
We actually extend the generated service and create a port supplying a WSDL located on the classpath using the JaxWS Service constructor. That works fine for us.
We debug CXF by dumping the incoming and outgoing messages. There seem to be quite a lot of methods to do just that. We use either a proxy between de web service and our client, or recently a cxf.xml file somewhere. Using a -D flag we temprarily configure this.
-Dcxf.config.file=/home/me/cxf-debug.xml
and cxf-debug.xml contains something like:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:cxf="http://cxf.apache.org/core"
xsi:schemaLocation="
http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
<cxf:bus>
<cxf:features>
<cxf:logging/>
</cxf:features>
</cxf:bus>
</beans>
http://cxf.apache.org/docs/debugging-and-logging.html

Both responses suggested the same basic approach, which turned out to be the correct one.
I fixed the provided wsdl to make it match the web service, and I was able to use cxf, which saved me a lot of hand coding.
The main problem with their wsdl was in fact a namespace issue. The essence of the problem was as follows: their wsdl defined two namespaces, both of which have a "searchResponse" element.
{http://us-labs.companyxyz.com/}searchResponse
was defined in the wsdl to contain 0 or more
{http://companyxyz.com/xyz-xml/2.0/}searchResponse
But in their response the nested searchResponse wasn't qualified by {http://companyxyz.com/xyz-xml/2.0/} so cxf interpreted it as a {http://us-labs.companyxyz.com/}searchResponse
I fixed it by introducing a new type.
Thanks to both responders.

Related

Apache CXF wsdl response issue

I am trying to do a POC where I am not able to change where the soap client gets their WSDL definition. This soap client has a ".wsdl" hardcoded in their code when they instantiate the service I am POCing. To start I have a pretty simple service, basically, a hello world which can be found here: https://github.com/apache/cxf/tree/master/distribution/src/main/release/samples/jaxws_spring_boot/src/main/java/sample/ws
The issue I am having is that I can't figure out how to configure jaxws or apache CXF to switch the WSDL URL response from http://localhost:8080/Service/Hello?wsdl to http://localhost:8080/Service/Hello.wsdl
I removed the metrics part from the example above and my WebServiceConfig looks like this:
#Bean
public Endpoint endpoint() {
EndpointImpl endpoint = new EndpointImpl(bus, new HelloPortImpl());
endpoint.publish("/Hello");
return endpoint;
}
Is there any way to get apache CXF to respond with the WSDL document from localhost/<myservice>.wsdl instead of localhost/<myservice>?wsdl
I feel like I am missing something really obvious.
The easiest thing is probably to issue a redirect or if the client doesn't honor that configure a rewrite rule.
You can also switch from a code first approach to a contract (WSDL) first approach and save the WSDL document somewhere else.
?wsdl is hard-coded in several places inside CXF and therefore not just a configuration to change.

How to create a web service proxy? Can we generate #Endpoints?

I'm working on a web-service-proxy with auditing (later on with caching = creating own responses) and I need to generate #Endpoints (such that will just forward i.e. call a remote web service or dummy atleast). Marshaling/unmarshaling seems neccessary for the proxy will add "something" to the request...
We are to use spring-ws and JAXB. Got all XSDs and static WSDLs of the proxied web service.
Any hints around? Anyone doing something similar? How are you doing it?
Is there a simple way how to achieve this using spring or spring-integration?
Thanks in advance..
This should be possible using both Spring WS and Spring Integration:
With Spring WS, you can create a proxy class for your remote WS, wrapping around a org.springframework.ws.client.core.WebServiceTemplate to talk to the WS - which has API's to take care of marshalling the request to xml and unmarshalling the response.
With Spring Integration, you can use an outbound Webservices gateway , but you will need to front it with a messaging gateway, which will act as your proxy, along these lines:
<int:gateway id="wsproxy" service-interface="..ProxyInterface" default-request-channel="requestChannel" default-reply-channel="replyChannel"/>
<int-ws:outbound-gateway id="wsGateway" request-channel="requestChannel" uri="http://serviceURL" marshaller="someMarshaller" unmarshaller="someUnmarshaller"/>
However, I would recommend the first approach of using the WebserviceTemplate, as you do not have a very complex integration need here.
Today I can tell how we proceeded without spring-integration. We found two different ways how to generate #Endpoint class.
1) Using XSLT and Freemarker we generated the endpoint class source in pre-compile phase. XSLT transformation walked thru all WSDL files to create one summary file which was then used to generate the source.
2) Using Javassist we copied the template class, then generated methods regarding content of JAXB2Marshaller instance and finally instantiated object using FactoryBean, all at server start-up.
Problem here we met was set of XSD files written in form that caused the root objects were generated without #XmlRootAnnotation. Javassist version we had internally works with Java 1.4 (no generics) so we used global customization file for XJC and forced #XmlRootAnnotation on root objects.
Both solutions have their pros and cons but both are simpler then using ESB.

JAX-RS: Resolve URI of Linked Resources on the Server

is there a standard way (JAX-RS) to resolve REST URIs to resources on the server side? As I understand the common practices, it's best to provide a full URI as an identifier for resources. If I want to allow somebody to POST/PUT a document like this to create/change a product:
<product>
[...]
<categories>
<category>http://.../rest/categories/12</category>
<category>http://.../rest/categories/35</category>
</categories>
</product>
As you can see, the references to the categories are their resource URIs. On the server side I now have to resolve these URIs to the corresponding resources. The simplest approach would be to create a client for the service on the server itself and do a standard GET request on these URIs. But I feel like this shouldn't be necessary.
Is there a standard way to do this? Is there a CXF way to do this? Is it better to always provide an additional id as well?
Thanks.
Dominik
I think you are looking for -
http://jersey.java.net/nonav/apidocs/latest/jersey/com/sun/jersey/api/core/ResourceContext.html
It is not from CXF or JAX-RS but from Jersey. I used it to parse documents just as in your example.
Inject it using #Context into your resource to use it.

Consuming Java Web Service from .NET

I have a web service written in Java now I want to consume that web service in the .NET world. I use the WSDL to add a proxy class to my .NET application but when I invoke the Java web service method the response is always null. Anyone familiar with this issue?
UPDATE 1:
Another thing I noted is that I opened one of the svcinfo files and found the following code:
<endpoint normalizedDigest="<?xml version="1.0" encoding="utf-16"?><Data address="http://fff.mywebserive/somewebservie" binding="basicHttpBinding" bindingConfiguration="DOC_TOI_Binding" contract="ServiceReference1.DOC_TOI_PortType" name="DOC_TOI_Port" />" digest="<?xml version="1.0" encoding="utf-16"?><Data
This does not look right to me!
UPDATE 2: Solution (Kind of)
The problem was that the response had a different namespace than used by the client proxy class. This way the object was never deserialized correctly. Once, I changed the namespace to match the response namespace it worked fine. But now if I update the web service reference I will again get the same issue as the namespace will be updated. What is a good way to solve this problem? The only solution I can think of is to ask the creator of the webservice to use the correct namespace.
Using .Net, we can add the java web service in our application using Service Referrence or Web Service Referrence.
Service Reference - This is a dedicated way of calling Microsoft WCF Web Services 3.5 and higher.
Web Service Reference - Way of referencing Non Microsoft Web Service and lower version of Microsoft webservice such as 2.0
We can also use Service reference in non Microsoft web service, we just need to modify some configuration in app.config such as Security Configurations()
Now, when Invoking the web service request method it always ends up with the NULL object response.
(This is caused by the discrepancy between the proxy namespace expected response and the actual xml namespace webservice response )
Sample:
Proxy Code
[return: System.Xml.Serialization.XmlElementAttribute("GetResponse ", Namespace = "http://AJ_TUASON.COM ")]
Public GetResponse Get()
{}
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://AJ_TUASON.COM")]
public partial class GetResponse
{}
Actual XML Namespace Response
webservice:GetResponse xmlns:"http://AJTUASON.COM"
To resolve this issue, install fiddler2. This will helps you track and confirm that the web services are working fine.
Then, copy the actual namespace in the XML response from web service.
Paste the actual xml namespace response in proxy class of .NET:
Sample:
[return: System.Xml.Serialization.XmlElementAttribute("GetResponse ", Namespace = "http://AJTUASON.COM ")]
Public GetResponse Get()
{}
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://AJTUASON.COM")]
public partial class GetResponse
{}
This will resolve the Null issue.
Note: Do not always rely on the tool that generates proxy class. Tools can surely translate but doing analysis is another thing - AJ
It suggests to me that either your WSDL or your client is incorrect. The client should not be able to tell from the WSDL what language it's implemented in. Check your namespaces.
SOAP UI is a very nice tool for testing SOAP services. I'd recommend it for sorting out this issue.
Looks to me like something tried to escape that snippet. You don't want > you want >
You need to make sure that the service and the client are using the same namespace. Communication is paramount here.

CXF Client Side Duplication of targetnamespace

I am hosting a webservice and a webapp on the same server, generated from wsdl2java. I can contact the service just fine through SoapUI and it returns a single namespace declaration when posted to the live server, but when I am working locally and use SoapUI it generates two instances of xlmns="" instead of a single one in my xml. I have copied below an example xml file:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body>
<SendResponse xmlns="http://myendpoint.org/service" xmlns:ns2="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<Receipt>
<MyReceipt xmlns:ns3="http://myendpoint.org/service" xmlns="" xmlns="" xmlns:ns6="http://myapp.myserver.net/myservicegroup/myservice/V01" receiptVersion="V01">
<ReceiptHeader>
<ReceiptTimestamp>2010-04-13T08:27:03.036-04:00</ReceiptTimestamp>
</ReceiptHeader>
<TransmissionReceipt>
<TransmissionID>testuser</TransmissionID>
<TransmissionTimestamp>2010-04-13T08:27:03.036-04:00</TransmissionTimestamp>
</TransmissionReceipt>
</MyReceipt></Receipt></SendResponse></soap:Body></soap:Envelope>
So when it unmarshalls, it fails badly when I use my webapp as a webservice client. Why is CXF adding a second namespace? I watched the debug all the way through until the return and it looked 100% perfect on the webservice side, no duplicate name space at all. It does not happen until the return of the xml to the client side.
In XML, attributes are unique to each element, so if this occurs then it is probably a bug and you should report it as such. I've worked with CXF before and it's a great library, but it's unfortunately not perfect. I had to mess around with various versions, upgrading to an unstable one to get around the bugs I encountered.
W3C XML Spec
An attribute name MUST NOT appear more than once in the same start-tag or empty-element tag.

Categories

Resources