WSDL Requests with Metro/JAX-WS/WSIT During Runtime - java

During runtime, JAX-WS fetches the WSDL of a SOAP endpoint even though it already ran wsimport in the IDE. This behavior is illustrated here: http://jax-ws.java.net/faq/index.html#wsdl_at_runtime
Is there a limit to amount of metadata that a client can retrieve during runtime? If so, is there a way to increase this limit?
Please note that I am not referring to running wsimport inside the IDE; that works fine. I'm specifically talking about fetching the WSDL metadata during runtime.

After many long hours spent on this problem, we came up with a solution. I was working in a Glassfish environment with Metro in Netbeans. If we copied the WEB-INF to the source packages folder everything worked. The java runtime could now bind to the relative path in the jaxws-catalog.xml file. Without copying that folder, it wouldn't work.

Metro/JAX-WS-ri needs the WSDL at runtime, period.
See http://jax-ws.java.net/faq/index.html#wsdl_at_runtime for an explanation.
To prevent WSDL fetch at runtime you should package it as a resource and provide it when instanciating the proxy factory :
new XYZ_Service( XYZ_Service.class.getResource( "/path/to/your/XYZ.wsdl" ), new QName( "NameSpace", "ServiceName" ) );

Based on the fact that you refer to the Metro FAQ, you obviously have read about the reasons as to why a copy of the WSDL is still needed at runtime. To reiterate the FAQ, the reason is to be able to support WS-* extensions that have no corresponding Java annotations.
There is currently no possibility in Metro to disable support for extensions and as a consequence no way to bypass the need for a WSDL at runtime.

Related

ClassCastException while sending soap request

I am working on a project which already had metro based web-service client implemented. Now, I needed to add another client for different service. I implemented new client, but now it throws exception when there are headers ( Headers are required). If I remove all metro jars, this new client works fine , but obviously my metro client fails. I need guidance on possible options,workarounds or resolutions.
Caused by: javax.xml.ws.WebServiceException: java.lang.ClassCastException: com.sun.xml.ws.message.saaj.SAAJHeader cannot be cast to com.sun.xml.ws.security.opt.impl.outgoing.SecurityHeader
at com.sun.xml.wss.jaxws.impl.SecurityClientTube.processRequest(SecurityClientTube.java:250)
at com.sun.xml.ws.api.pipe.Fiber.__doRun(Fiber.java:961)
at com.sun.xml.ws.api.pipe.Fiber._doRun(Fiber.java:910)
at com.sun.xml.ws.api.pipe.Fiber.doRun(Fiber.java:873)
at com.sun.xml.ws.api.pipe.Fiber.runSync(Fiber.java:775)
at com.sun.xml.ws.client.Stub.process(Stub.java:429)
at com.sun.xml.ws.client.sei.SEIStub.doProcess(SEIStub.java:168)
at com.sun.xml.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:119)
at com.sun.xml.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:102)
at com.sun.xml.ws.client.sei.SEIStub.invoke(SEIStub.java:151)
at com.sun.proxy.$Proxy70.methodName(Unknown Source)
... 15 more
Caused by: java.lang.ClassCastException: com.sun.xml.ws.message.saaj.SAAJHeader cannot be cast to com.sun.xml.ws.security.opt.impl.outgoing.SecurityHeader
at com.sun.xml.ws.security.opt.impl.JAXBFilterProcessingContext.setJAXWSMessage(JAXBFilterProcessingContext.java:166)
at com.sun.xml.wss.jaxws.impl.SecurityTubeBase.secureOutboundMessage(SecurityTubeBase.java:381)
at com.sun.xml.wss.jaxws.impl.SecurityClientTube.processClientRequestPacket(SecurityClientTube.java:323)
at com.sun.xml.wss.jaxws.impl.SecurityClientTube.processRequest(SecurityClientTube.java:247)
I found few questions with similar problem like here, but they all end up suggesting to remove headers which is not an option for me.
P.S : For the existing webservice client that uses metro jars, we use a connector like client( its a jar that actually includes all metro related classes within itself) provided by the server parties to connect to their server (which I think is very weird). If I move anything from the connector , it voids the support agreement. So I prefer not to remove metro jars, but find alternate way to accommodate with it.
It seems fairly clear that what's happening is there are clashing versions of the metro library in the third party jar, vs the new metro libraries you are trying to use.
My first thought is, do you have any control over the ordering of the classpath? Could you put your own metro jars to either end of the classpath to see if that makes a difference?
Then perhaps it might be best to try and implement your own interface in terms of the metro libraries included in the third party library? I'm not sure if this kind of version information is available to you, but most modern IDE should be able to decompile the classes in the third party jar for you. If I were in your situation it would be the first thing I would try since it has the "least moving parts" and uses dependencies that are already available to you.
The other option is to run one or other client in a separate VM, and access through a basic RMI interface. Not ideal I know.
You might also try investigating the Maven shade plugin which supports repackaging of libraries so that they don't clash with other versions, though I'm not sure how well that works with precompiled binaries - in particular the kind of complexity that is involved in JAX-WS packages ...

JMSCS0002 from Spring JMS and IBM Websphere MQ

I've seen a question or two on Stack overflow regarding this error but I'm still unable to solve it, so I thought I would pose my own question.
Here's my issue:
I'm using Spring and Spring's JMSTemplate to do some messaging and queue work. I'm trying to read from a queue. I'm not 100% positive if my logic is correct in my code, but anytime I try to run my app I am greeted with this exception (I've included only the last section):
Caused by: com.ibm.msg.client.commonservices.CSIException: JMSCS0002
at com.ibm.msg.client.commonservices.workqueue.PIWorkQueueManager.enqueueItem(PIWorkQueueManager.java:67)
at com.ibm.msg.client.commonservices.workqueue.WorkQueueManager.enqueue(WorkQueueManager.java:225)
at com.ibm.msg.client.commonservices.workqueue.WorkQueueManager.enqueue(WorkQueueManager.java:194)
at com.ibm.msg.client.wmq.common.internal.WMQThreadPool.enqueue(WMQThreadPool.java:91)
Now I'm fairly certain this has nothing to do with my code because no matter how much I change my logic, if I try calling any of the methods made available by JMSTemplate, I receive this exception. After doing some research (based on the other stack overflow answers) I assume it has something to do with the way my classpath is setup. Here is a link to those questions:
One and Two
In addition to this, here's some info I found on IBM's site:
To compile and run WebSphere MQ classes for JMS applications, use the
CLASSPATH setting for your platform as shown in Table 1.
CLASSPATH=MQ_INSTALLATION_PATH\java\lib\com.ibm.mqjms.jar;
MQ_INSTALLATION_PATH\tools\jms;
I have tried this however and It still seems to be failing me. Here's what I have added in my .bat file for my application that I run:
c:\java\jre6\bin\javaw -cp "C:\ussco\wmsflgint\mqs\mqjms-7.5.0.0.jar; C:\ussco\wmsflgint\mqs\mq-7.5.0.0.jar; C:\ussco\wmsflgint\mqs\headers-1.4.2.jar; C:\ussco\wmsflgint\mqs\jmqi-7.5.0.0.jar;" -Xmx256M .... (there's more on the end but I don't feel it's relevant)
Am I not adding this correctly?
Thanks
I've just ran into the same issue with queue listeners. The solution was to place a file compinfo.properties under the directory src/main/resources/META-INF of the Spring project. The file should set values for two properties:
CompList: comp1
comp1_CompClass: com.ibm.msg.client.commonservices.j2se.J2SEComponent
Or you can change the property (comp1_CompClass) value right in the jar com.ibm.msg.client.commonservices.j2se.jar. It has the same effect though I doubt it's legal due to copyright.
Hope it would be helpful and save a couple of hours for someone.
The problem here is that you have been copying and renaming IBM MQ jar files and, as a result, do not have the full set on the Java class path at runtime. This can lead to all kinds problems and unexpected exceptions, such as the one you are experiencing.
Please note that copying MQ jar files, renaming them and/or bundling them into applications is not permitted by IBM Support and invalidates the MQ terms and conditions. (The rules are subtlety different for bundling into apps for the V8 and V9 redistributable client and allclient; but your not using that here).
If you perform a proper install of the MQ client onto your system (which you should do) and then use the instructions that you have already found in the Knowledge Center to reference the com.ibm.mq.jar file for classes for Java applications or the com.ibm.mqjms.jar for classes for JMS applications on the Java class path, your problem will be resolved.

Consuming WCF Service with Digest authentication from Java

I want to create a client in Java that connects to a web service which requires Digest authentication. Since I am not familiar with java and java stack, I've made a research and came across jax-ws, axis2, xcf, and metro. I have learned JAX-WS is an API and there is a reference implementation in the JDK but it lacks the digest authorization support.
My first attempt was to use axis2 since there is a built-in support for it in the Eclipse IDE. The following code seems to follow digest authentication workflow but somehow it still fails the authorization in the end.
Service1Stub stub = new Service1Stub();
HttpTransportProperties.Authenticator authenticator = new Authenticator();
List<String> authSchemes = new ArrayList<String>();
authSchemes.add(Authenticator.DIGEST);
authenticator.setAuthSchemes(authSchemes);
authenticator.setUsername("doman user");
authenticator.setPassword("domain password");
authenticator.setPreemptiveAuthentication(true);
Options options = stub._getServiceClient().getOptions();
options.setProperty(org.apache.axis2.transport.http.HTTPConstants.AUTHENTICATE, authenticator);
options.setProperty(org.apache.axis2.transport.http.HTTPConstants.CHUNKED, org.apache.axis2.Constants.VALUE_FALSE);
GetData getData = new GetData();
getData.setValue(25);
GetDataResponse data = stub.getData(getData);
System.out.println(data.getGetDataResult());
My second attempt was to use metro framework but I get some errors related to JAXB versions.
java.lang.LinkageError: JAXB 2.1 API is being loaded from the bootstrap classloader, but this RI needs 2.2 API.
I have to use JDK 1.6.0_03 so I guess this is happening because of a JDK version mismatch, but I also don't want to use the suggested "endorsed directory mechanism" because it might cause lots of troubles during deployment.
I am totally lost and I am looking for the simplest, quickest and up-to-date way of consuming a web service that requires Digest authentication in Java? Preferably with as little as dependencies possible.
Java classloading is a mess, sorry. The root cause is that there are no strong names like there are in the .NET world, and therefore the runtime linker takes whatever match comes first on the classpath, regardless of whether that's the library version that the code was compiled against. The OSGi system solves this problem, but it never gained mainstream adoption.
The error message you cited:
java.lang.LinkageError: JAXB 2.1 API is being loaded from the bootstrap classloader, but this RI needs 2.2 API.
is uncharacteristically useful and specific, most of the time what happens instead is that you're left staring at a NoSuchMethodError or something of the sort. Over time, you learn to recognise these as library version mismatches. In this case, the library author(s) have written code to recognize a common error case and print a better error message (bless 'em).
Rant over, here's some info that I hope will set you on the right track:
Java classloaders are hierarchical and resolution is bottom-up
but there's a blessed class loader at the root of the hierarchy that's responsible for loading the core runtime library
vendor shenanigans have led to a lot of stuff getting included in the core runtime library that really shouldn't have been in there, as it's a shortcut to becoming dominant in an otherwise Darwinistic selection process. JAXB is one of these things, as you've just found out. JAXB2 is actually pretty decent, but it evolves independent of the core runtime and, well, here we are.
the JDK and JRE installation has a folder called lib\endorsed where you can add JAR files that need to be loaded by the root loader, bypassing even what's in rt.jar.
In summary, if you manually add the 2.2 version of the JAXB library to %JAVA_HOME%\lib\endorsed, then it should override the included 2.1 version and your web service client will deploy. This will have to happen on every system that will run the web service client, until the JDK is updated to a 7.x version that does included JAXB 2.2. If the same JVM is running other JAXB based applications, these may or may not break as a result.
Yes, this is painful. A tangent that you could investigate is to deliberately use an older version of Metro that's built for JAXB 2.1. So long as you're bound to deploying on 1.6.0_03, this may well be the better option, despite losing some of the recent improvements in Metro.
Updated: here's a blog post on this topic. It contains some links to further information.
Metro framework was way too complicated to configure and documents that I have found were incomplete. So I've done it with using Apache Axis2.
Steps to follow:
Download and extract Apache Axis2 binaries.
Reference to all jar files
Go to /bin folder and use wsdl2java to generate client code.
wsdl2java -S src -uri "wsdl_file_location"
Copy everything under the src folder to your java application and connect to the service as follows:
//Fictious is the name of the web service
FictiousStub stub = new FictiousStub("servicelocation/fictiousService.php");
HttpTransportProperties.Authenticator authenticator = new Authenticator();
List<String> authSchemes = new ArrayList<String>();
authSchemes.add(Authenticator.DIGEST);
authenticator.setAuthSchemes(authSchemes);
authenticator.setUsername("admin");
authenticator.setPassword("12345");
authenticator.setPreemptiveAuthentication(true);
Options options = stub._getServiceClient().getOptions();
options.setProperty(org.apache.axis2.transport.http.HTTPConstants.AUTHENTICATE, authenticator);
options.setProperty(org.apache.axis2.transport.http.HTTPConstants.CHUNKED, org.apache.axis2.Constants.VALUE_FALSE);

What methods exist to expose documentation on SOAP interfaces?

I am attempting to expose documentation (like Javadocs) for a SOAP Service. Best case, it would either be exposed directly from the WSDL or through an autonomously generated report. I am using CXF as my SOAP implementation.
I have tried using the WSDL Viewer found here, but I havn't found a good tutorial on how to annotate my methods to get the structure and level of detail seen in his example.
The best solution that I’ve found thus far is to use an engine known as Enunciate (http://enunciate.codehaus.org/). Once added to the project it reads the JavaDocs and composes a set of HTML files. I don't fully understand all of the features or problems (it generates and links to its own WSDL, which isn't ideal, and does "scratch work" within an extra folder in the project which then reads as an error unless deleted), but it does successfully read and expose the JavaDocs in a clear and useable manner.

Generating client stubs from WSDL

I am starting on a new project with commercial vendor. I need to write an integration module in our application to consume commercial vendor's web service. So, WSDL is not controlled by us.
I think the general approach is to do a "Contract First" development and generate stubs from the WSDL file. I would like to know what technologies are available to do this? I would really like the simplest approach that works. We use Maven 3.0.3 and Spring 3.0.5 extensively. Can I use Spring WebServiceTemplate?
Please let me know if the question isn't clear or additional details are needed.
Thanks,
Tapasvi
You can generate the java stubs with the maven plugin for JAX-WS. Then you can use the stubs in spring to expose them as a webservice. Luckily, it's quite simple :).
Just a suggestion, don't re-generate the stubs every time you build the project, as (obviously) you won't be able to add any code to the stubs, which is sometimes very useful. I made this mistake long time ago and it was quite painful, because I had to put code in places where it didn't belong. In the last few years I used a maven profile to generate the stubs on demand and then I merged them "manually" to add the extra code. Of course, this is only viable if the WSDL doesn't change very often.
I have used axis and the easiest way to do is to run the utility wsdl2java and pass the location of the webservice along with the ?wdsl option.
I know lots of IDE's these days will allow to generate you stubs from within. MyeclipseIDE has an option to ingest an WSDL so does intelliJ. I think the safer approach is to use wsdl. Also if you are using jax-ws you can try
wsimport -keep -verbose location to wsdl
JAX-WS is included in the standard Java 6 distribution making it very simple to use.
Generate stubs with wsimport in the JDK (remember to enable as many warnings as possible, as you want to know anything that may cause problems).

Categories