How to modify the XML of a WebMethod request generated by JAXWS - java

I have a weird problem: I have a central Web Service client that calls web methods on thousands of embedded Web Service servers. We recently discovered that the Web Service servers have a bug that make server crash if the XML request is exactly 0x4000 long. This does not happen very often, but with thousands of devices it happens every day, making the whole solution erratic.
The middle term solution is to fix the bug on the servers, but with thousands of firmware to flash this solution is not easy to deploy in few days.
The short term solution is to modify the XML request if it is exactly 0x4000 long and to pad it with a space character or something like that.
So, the XML is generated by JAX-WS (all classes were generated from Web Server manufacturer's WSDL), and I just call an interface annotated with #WebService with methods annotated with #WebMethod, #WebResult, ....
FYI: this the JAX-WS version.
/**
* This class was generated by the JAX-WS RI.
* JAX-WS RI 2.1.3-hudson-390-
* Generated source version: 2.1
*
*/
My question is how can I tinker the XML generated by this call to check its length and modify it if needed?

You could use client-side SOAP Message Handlers to solve your problem.
Check the following link: https://docs.oracle.com/cd/E21764_01/web.1111/e13734/handlers.htm

Related

Java SOAP client stub generation with service endpoint determined at runtime

Previously, I've written SOAP clients in Python and used the SUDS library. Without getting into the details, the "stub" generation is really quite dynamic as it's done at runtime and, with Python being so typeless, I'm able to reference the expected methods generated by the WSDL without a pre-compiled stub. I'm fine with generating a stub with something like wsimport, because it's great to have the composition of SOAP messages being handled via a nice Java object structure. So, I'm not looking for a dynamic generation mechanism akin to SUDS in python.
My problem is that all the simple JAX-WS examples I see are for what I'll call a "statically located web service". What I'm trying to do is connect to a web service with a known WSDL from which I could generate stubs at compile time but whose location is only known at runtime. For example, say I want to access Microsoft SharePoint Web Services. Wherever my application is deployed, there will a different SharePoint server (or servers) running which will need to be specified at runtime. All the simple examples I've seen have the service location URL hard-coded into the stubs through wsimport. Is there a way to generate stubs but supply the service location at runtime?
I'm really surprised not to find any examples of this because I figure what I'm trying to do should be very common as Web Services go. Perhaps the answer is that I can't be lazy and get a nice objectified version of the WSDL methods if the server location is only known at runtime. I've seen SAAJ examples but there, of course, I have to generate the SOAP messages by hand myself. That would be such a shame when the WSDL is known at compile time. Can't I have my cake and eat it too?
If I understand your question right, you want to connect to multiple web services that expose the same WSDL but are located at different addresses and your client contains only the address of the service used to generate it?
In that case have a look at this post: Changing WSDL url (endpoint) in JAX-WS client.

How do you intercept WSDL requests in CXF?

Backstory:
I have a WSDL that was created by the customer (non-negotiable) that mixes several web standards into a single service. This one soap service has four soap ports that refer to bindings in referenced (wsdl:import) WSDL files that import XSDs resulting in a dependency tree that is significantly complex.
Since this is done by imports, the top level WSDL isn't that big. WSDL2Java and wsimport choke on it, but I have a library of the schemas compiled into JAXB objects to work with. So I created a CXF service that has all of the required operations and I was able to test it with SoapUI (it imported the top level WSDL fine since it didn't have to make java classes).
Since all the soap ports point to the same address, and that service handles all the operations from the various ports, the client doesn't know that the server thinks all the operations belong to the same port.
Problem:
This breaks down when it comes to CXF generating the WSDL. It puts all the operations on one port with the same namespace. In the customer provided WSDL, the service, ports and bindings are not all in the same namespace. I have tried to supply the service with the WSDL using the #WebService(wsdlLocation="") annotation, but it tries to parse it and match it to the code (as it would in a sane world).
Question:
I would like to intercept/override the http://example.com/service?wsdl operation and return the customer provided wsdl. Is there a way to do this in CXF?
I ended up splitting the ports out into separate services, but I still needed a custom WSDL that had info for all the ports. The way to do this with CXF is to create an interceptor.
I followed the example of the CXF interceptor that regularly handles WSDL generation: http://grepcode.com/file/repo1.maven.org/maven2/org.apache.cxf/cxf-rt-frontend-simple/2.4.0/org/apache/cxf/frontend/WSDLGetInterceptor.java. I read in my custom WSDL and replace the placeholder hostname with the hostname that comes from the request URL.
You need to then add the custom interceptor when you make your service (I use spring for my configuration). More info on that at http://cxf.apache.org/docs/interceptors.html.

Getting a Axis 1.1 client talk to an Axis2 service

Is it possible to have an Axis 1.1 client talk to an Axis2 web service endpoint? From my understanding, web services work by passing XML SOAP messages back and forth using the schema specified by the service's WSDL, but I'm unsure as to whether or not these versions of Axis utilize different versions of the web service specification that would stop them from talking. Any thoughts?
Alright, using Axis 1.1 to communicate with an Axis2 web service works just fine. I generated the stubs using Axis 1.1, created a Client class, and tested. Axis 1.1's API doesn't offer some of the same functionality that my previous Axis 1.4 allows, specifically in the ParameterDesc class, where you can specify if web service method parameters are nillable or their minOccurs, but my calls seemed to work just fine.
All in all, it can be done with (what appear to be) basic WSDL definitions, however, I'm unsure as to whether or not Axis2 utilizes new functionality that Axis 1.1 cannot accommodate due to Axis 1.1's aged API...
Oh, and one last note, I needed to use SOAP 1.1 stubs for my request. I'm not 100% sure why since my responses were coming back as SOAP 1.2, but there you have it.
In general your understanding is correct,i.e. that if a client adheres to the WSDL description it should be able to contact the web service.
But Axis1 and Axis2 use by default different encodings which are not compatible.
Axis1 uses RPC (which is obsolete) and Axis2 uses doc/lit.
So the oposite of what you ask i.e. an Axis2 client communicating with an Axis1 server will not work.
For the reverse (and what you ask in the post) I am not really sure.
Did you try to generate the stubs using the WSDL?
Did you get any errors? If you got no errors in stub creation, I believe you could give it a try.

JAX-WS client: JAXB required?

I need to "dive into JAX-WS programming".
So, I played around with Netbeans, after 20 or so erroneous attempts,
finally managed to let a web service client execute a web service.
I noticed, that a lot of code is generated, especially JAXB classes
for the web service response.
My current task is, to write a web service and web client completely
by hand.
Is JAXB required at all? Is is part of the standard anyway? What would happen without it?
EDIT:
Seems that the answer is given here
You can see Developing Web Services with Java 2 Platform, Enterprise Edition (J2EE) 1.4 Platform
I took a wsdl and used eclipse to generate the service, serviceLocator, ws interface, ws binding stub, ws proxy, and then the client code. I added a main method and was able to hit the webservice successfully.
I used this tutorial as a guide with the url below and no, there are no jaxb objects as I'm not pulling any objects back in the simple example I used. I was just hitting some methods that pulled back a boolean value.
http://px.pats.no/px/Eclipse_tutorial.html

Problem consuming Exchange Web Service 2010 with jax-ws metro

I am trying to consume the Exchange 2010 Web Service interface using JAX-WS. I'm using JAX-WS 2.2 RI (Metro 2.0). 2.1 exhibited the same problem.
I am running into trouble with Exchange, which returns "HTTP/1.1 415 Cannot process the message because the content type 'text/xml;charset=utf-8' was not the expected type 'text/xml; charset=utf-8'." as a reponse (2.1 quoted the charset value, otherwise same response).
Apparently I need to dictate the exact Content-type header for Exchange to be happy.
Is there a way for me to do this without forcing me to manually rebuild the dependency? I currently rely on published maven artifacts, and would like to continue doing this if at all possible.
The consuming process is a regular J2SE app, with no containers in sight. I have control of the application and can add pretty much anything required to the applications scope, but can not add out-of-process items like proxy servers. The client classes were generated from local WSDL, but the charset specification is derived from constants declared in the jaxws RI implementation, not the generated code. The resulting HTTP transport is thus handled by the standard http/https client from Sun JRE5 or JRE6.
From this thread (giving a cached link, because currently java.net forums are down), it appears that the fault is ultimately that your Exchange Web Service 2010 demands a space after the semicolon - something NOT part of the w3c spec.
A solution might be to put something (depending on your setup) in front of the metro to change the header.
You could try some of the following approaches:
Use reflection to change the Metro constant.
Use AOP (I can't tell you how exactly)
See where is this constant defined in Metro, create a package javax.xml.ws.etc (or com.sun.etc.. in your sources, and copy-paste the source for that class, changing the constant.

Categories

Resources