ServiceConfigurationError caused by LinkageError in WebSphere - java

I have an application that is deployed on WebSphere 9.0.5.2 where I want to use CXF for webservice calls and I'm getting this This ServiceConfigurationError
WrapperedException { java.util.ServiceConfigurationError: javax.xml.ws.spi.Provider: Provider org.apache.cxf.jaxws.spi.ProviderImpl could not be instantiated
Further down the stacktrace, I see that this is caused by a LinkageError
Caused by: java.lang.LinkageError: loading constraint violation when overriding method
"javax/xml/ws/spi/ServiceDelegate.createDispatch(Ljavax/xml/namespace/QName;Ljavax/xml/bind/JAXBContext;Ljavax/xml/ws/Service$Mode;)Ljavax/xml/ws/Dispatch;" during creation of class
"org/apache/cxf/jaxws/ServiceImpl": loader
"com/ibm/ws/classloader/CompoundClassLoader#832133d2" of class
"org/apache/cxf/jaxws/ServiceImpl" and loader
"com/ibm/oti/vm/BootstrapClassLoader#2eec706a" of class
"javax/xml/ws/spi/ServiceDelegate" have different types for the method signature
I understand that this could be caused by multiple libraries that have different definitions for QName or JAXBContext, but I think I've ruled those out.
I also understand that WebSphere has it's own JAX-WS with it's own method signature for ServiceDelegate.createDispatch and I've tried setting DisableIBMJAXWSEngine to true in WebSphere as instructed here
Using a third-party JAX-WS web services engine
I still haven't been able to get rid of the error and am pretty much at a loss as to what to try next. Any suggestions is appreciated!!!

The issue here is a cross-linkage between the application and server's copies of the JAXB API, JAX-WS API, and JAX-WS implementation. The application (configured with parent-last class loading delegation, so it searches locally before delegating to parents) contains a JAX-WS implementation and JAXB API/impl, but it does not contain the JAX-WS API. Since JAX-WS references JAXB, we get the following linkage pattern:
1) Some application class references the JAX-WS API. Because it's not packaged in the application, it's loaded from the server libraries.
2) When the API class is linked, it uses its local class loader to find the JAXB API. That, in turn, links it to the server's version as well.
3) JAX-WS uses the thread context class loader to load its implementation. It finds it in the parent-last application.
4) When the implementation class is linked, it uses its local class loader to find the JAXB API, which finds it locally in the application.
5) The implementation now is linked to two versions of the same class:
JAXWSImpl -> JAXWSAPI -> JAXB (server)
JAXWSImpl -> JAXB (app)
The JVM can't tolerate that, and a LinkageError is thrown.
The solution can be approached one of two ways:
1) Add the JAX-WS API to the application - this prevents the initial delegation in #1 above
2) Remove the JAXB API (and implementation, if provided) from the application - this causes the linkage in #4 to delegate down to the server for JAXB, so it's always loaded from the same place.
Either way, the trick is to ensure that all the necessary classes are available to the application through the same class loader.

Related

WebSphere & javax.xml.ws.spi.Provider: Provider org.apache.axis2.jaxws.spi.Provider not a subtype

I have an app deployed on IBM WebSphere 8.5.5.0.
When the app tries to call a remote web service, I get
java.util.ServiceConfigurationError: javax.xml.ws.spi.Provider: Provider org.apache.axis2.jaxws.spi.Provider not a subtype.
It seems that WAS is picking (probably bundled) Axis2 impl. of the JAX-WS Provider class instead of the CXF one that I want to use.
The app WAR does not come with Axis2 impl. of javax.xml.ws.spi.Provider
The app WAR contains a CXF jar with the Provider impl., org.apache.cxf.jaxws.spi.ProviderImpl
I tried
Classloaders set to "Classes loaded with local class loader first (parent last)"
http://www.ibm.com/support/knowledgecenter/SSEQTP_8.5.5/com.ibm.websphere.base.doc/ae/twbs_thirdparty.html
Set the com.ibm.websphere.webservices.DisableIBMJAXWSEngine property to true (http://www.ibm.com/support/knowledgecenter/SSAW57_8.5.5/com.ibm.websphere.nd.doc/ae/twbs_thirdparty.html)
adding "-Djavax.xml.ws.spi.Provider=org.apache.cxf.jaxws.spi.ProviderImpl" in JVM arguments for the server
Neither of them helped, I still have the same exception.
Interestingly when I print System.getProperty(“javax.xml.ws.spi.Provider”) from a test JSP within the app, it outputs org.apache.cxf.jaxws.spi.ProviderImpl.
Thanks for any help
Applying a WebSphere Fix Pack 9 solved the issue completely.

Correct way to lookup local EJB in websphere - Getting ClassCastException

I have an EJB which is exposed by both local and remote interfaces
package com.sam.enqueue;
import javax.ejb.Local;
import javax.ejb.Remote;
import javax.ejb.Singleton;
#Singleton
#Local(SamEnqueueLocal.class)
#Remote(SamEnqueueRemote.class)
public class SamEnqueue implements SamEnqueueRemote, SamEnqueueLocal {
}
// remote interface
package com.sam.enqueue;
import javax.ejb.Remote;
#Remote
public interface SamEnqueueRemote {
}
// local interface
package com.sam.enqueue;
#Local
public interface SamEnqueueLocal {
}
My app container is websphere 8.0 and I am not overriding the default JNDI names which the server assigns.
During server startup I get the following default bindings in logs:
CNTR0167I: The server is binding the com.sam.enqueue.SamEnqueueRemote interface of the SamEnqueue enterprise bean in the SAM_ENQUEUE.jar module of the SAM_ENQUEUE application. The binding location is: ejb/SAM_ENQUEUE/SAM_ENQUEUE.jar/SamEnqueue#com.sam.enqueue.SamEnqueueRemote
CNTR0167I: The server is binding the com.sam.enqueue.SamEnqueueRemote interface of the SamEnqueue enterprise bean in the SAM_ENQUEUE.jar module of the SAM_ENQUEUE application. The binding location is: com.sam.enqueue.SamEnqueueRemote
CNTR0167I: The server is binding the com.sam.enqueue.SamEnqueueRemote interface of the SamEnqueue enterprise bean in the SAM_ENQUEUE.jar module of the SAM_ENQUEUE application. The binding location is: java:global/SAM_ENQUEUE/SamEnqueue!com.sam.enqueue.SamEnqueueRemote
CNTR0167I: The server is binding the com.sam.enqueue.SamEnqueueLocal interface of the SamEnqueue enterprise bean in the SAM_ENQUEUE.jar module of the SAM_ENQUEUE application. The binding location is: ejblocal:SAM_ENQUEUE/SAM_ENQUEUE.jar/SamEnqueue#com.sam.enqueue.SamEnqueueLocal
CNTR0167I: The server is binding the com.sam.enqueue.SamEnqueueLocal interface of the SamEnqueue enterprise bean in the SAM_ENQUEUE.jar module of the SAM_ENQUEUE application. The binding location is: ejblocal:com.sam.enqueue.SamEnqueueLocal
CNTR0167I: The server is binding the com.sam.enqueue.SamEnqueueLocal interface of the SamEnqueue enterprise bean in the SAM_ENQUEUE.jar module of the SAM_ENQUEUE application. The binding location is: java:global/SAM_ENQUEUE/SamEnqueue!com.sam.enqueue.SamEnqueueLocal
The lookup class is just a simple java class in a different EAR in the same server with the following code:
Context ctx = new InitialContext();
Object local = ctx.lookup("java:global/SAM_ENQUEUE/SamEnqueue!com.sam.enqueue.SamEnqueueLocal");
SamEnqueueLocal samEnqueue = (SamEnqueueLocal) local;
The lookup is working with any of the three JNDI names for the local but it's not getting cast to SamEnqueueLocal. The exception trace is:
SystemErr R java.lang.ClassCastException: com.sam.enqueue.EJSLocal0SGSamEnqueue_cf56ba6f incompatible with com.sam.enqueue.SamEnqueueLocal
... rest ommited
I've made a shared library and put the stub of destination EAR in it. The library is the classpath of the source lookup EAR with the Classes loaded with local class loader first (parent last) policy. The library is not isolated. If I remove the stub, I get a java.lang.ClassNotFoundException: com.sam.enqueue.SamEnqueueLocal as expected.
Update:
While using Dependency Injection:
#EJB(lookup="ejblocal:com.sam.enqueue.SamEnqueueLocal")
private SamEnqueueLocal samEnqueueLocal;
The error I get is:
javax.ejb.EJBException: Injection failure; nested exception is: java.lang.IllegalArgumentException: Can not set com.sam.enqueue.SamEnqueueLocal field com.some.SomeBean.samEnqueueLocal to com.sam.enqueue.EJSLocal0SGSamEnqueue_cf56ba6f
Caused by: java.lang.IllegalArgumentException: Can not set com.sam.enqueue.SamEnqueueLocal field com.some.SomeBean.samEnqueueLocal to com.sam.enqueue.EJSLocal0SGSamEnqueue_cf56ba6f
So it's basically the same.
You are getting java.lang.ClassCastException because you are retrieving a reference to an EJB that exists in a different class loader than the deployment unit (ejb-jar, war, etc) that is trying to inject it.
Using local EJB references between applications is vendor dependent if possible at all. You may be able to deploy your SamEnqueue bean in a separate EJB module and try to reference it via a manifest Class-Path: entry from each application. Be sure that there are no copies of SamEnqueueLocal in either EAR file.
Alternatively, just use the SamEnqueueRemote interface.
Refer to chapter 8 of the Java EE specification for more information.
See the "Local client views" section of the EJB modules topic in the knowledge center:
The EJB specification only requires local client views to be supported
for EJBs packaged within the same application. This includes local
homes, local business interfaces, and the no-interface view.
WebSphere® Application Server permits access to local client views to
EJBs packaged within a separate application with some restrictions
The local interface and all parameter, return, and exception types used by the local interface must be visible to the class loader of both the calling application and the target EJB application. You can ensure this by either using a shared library associated with a server class loader or by using an isolated shared library associated with both applications. Read the Creating shared libraries topic for more information.
...
From the link provided by in bkail's answer, These are the steps that I followed to make it work.
Take out the Local and Remote interfaces i.e. SamEnqueueRemote and SamEnqueueLocal from my source EJB jar and package then into a separate jar file. Although just taking out the Local interface will also work.
Make a shared library and put this jar into it. The shared library must be isolated so that same version of class is loaded by caller and callee.
In the caller EAR, get a reference to the local interface with either a lookup or injection.
Deploy both the caller and callee to the server and make sure to add the shared library in the classpath of both the EARs.
One of the approaches mentioned in this link is similar.
One way to prevent this is to use a remote interface. As Paul mentioned, there is optimization that happens when the caller and callee are in the same JVM, so it's not as expensive as if they're in separate JVMs. The ORB has classloader machinery that ensures the classes for the caller and callee are loaded using classloaders compatible with each side of the call.
Option 2, including the ejb jar within the new ear, won't solve the problem. Even though the classes will be available in both classloaders, the object passed by-reference from callee back to caller will still be instanciated using the other application's classloader and will not be type-assignable. Same with Option 3.
The 2nd way to make it work is to place the classes used by caller and callee in a "WAS shared library" and configure both applications to use that shared library. The subject of shared libraries and how to configure them is described in the WAS InfoCenter documentation...search on "shared library."
The 3rd way to make it work, which is the least desirable of the three, is to change the WAS server classloader policy to "one classloader per server." The default, as I mentioned at the top, is "one classloader per application (EAR file)." Changing to one classloader per server ensures that everything gets loaded by the same classloader and is thus type-compatible, but deprives your applications of the isolation/security benefits that come from having each app in its own classloader.

Can I look up an EJB via JNDI and invoke methods using reflection?

I'm using EJB 3.1. I need to get a references to one of the EJBs in a servlet and I'd rather not put an EJB interface jar on the class path to get the code to compile.
Is it possible to look an EJB via JNDI and find the method I want to invoke using reflection without ever strongly typing the object to an interface?
Yes, if you're looking up a local EJB interface, then you can look up and invoke a local EJB within the same application using reflection.
This should work if you're using a direct lookup or an EJB ref lookup because the Java EE spec requires the application server to make EJB module classes available to WARs within the same application. The EJB spec doesn't require support for local interfaces across applications, so if that's what you're doing, you'll have to check with your application server vendor.
This will not work in general for remote EJB interfaces because a client proxy needs to be created. If you're using RMI-IIOP (EJB 2.x remote or EJB 3 extending java.rmi.Remote), you might be able to cast the EJB lookup result to javax.rmi.CORBA.Stub and use the _servant_preinvoke or _invoke methods the same as a generated stub method would do.
(Ultimately, this is a lot of caveats just to avoid a compile-time dependency. It's probably not worth the fragility, so I would recommend finding a way to solve that and compile normally.)

calling wsdl based webservice from within alfresco

i followed this article: http://www.mkyong.com/webservices/jax-ws/jax-ws-hello-world-example/
so i have:
HelloWorld http://pastebin.com/BJ3QA7pR
HelloWorldImpl http://pastebin.com/RM5SBZ5C
HelloWorldPublisher http://pastebin.com/H525WevK
which serves as the endpoint.
on the other side i have the client which i generated with wsimport:
HelloWorld http://pastebin.com/g07H1exf
HelloWorldImplService http://pastebin.com/f0YWMiYt
this runs fine in eclispe without alfresco being involved. however, i want to call the webservice from alfresco (from java backed web script for example)
i tried to copy the client side stuff to my amp file and calling it from a webscript but it fails!
Caused by: java.lang.IncompatibleClassChangeError: Class com.ibm.wsdl.DefinitionImpl does not implement the requested interface javax.wsdl.extensions.AttributeExtensible
Webscript http://pastebin.com/7JksRdtU
1 - is there a more elegant way to configure the access to the wsdl by defining a spring bean (spring-ws) or such
2 - why is it not working? full trace: http://pastebin.com/ak1qzygA
using alfresco community 5.0.a
thanks
You will see IncompatibleClassChangeError usually when the dependancy/library jar has changed. Hence the method/code dependant on the library has to be recompiled against the changes.
Guessing the problem here has much to do with some dependancy jar being mispicked or an older version of jar present or one jar prioritized over the other. A look into the jars containing 'com.ibm.wsdl.DefinitionImpl' class in your classpath should be of some help.

Web Service Auto Generated Files

When I create a new Web service using RSA 7.5 IDE and Web Sphere 7.0 server from a Web Application, then I can see a few auto-generated files created by this process, namely:
1) For the service, a SEI file is created
2) For the models, ser, deser and helper files are created.
But I cant understand what are the use of all these SEI, ser, deser and helper files.
Any valid explanation on this will be much appreciated.
BOUNTY EDIT:
Bounty-Edit:
Since I did not get any response I would like to ask this question again - offering a bounty to encourage an in-depth answer. I would love to know how and when are these files used internally?
Regards,
Service Endpoint Interface (SEI):
SEI is the Java interface corresponding to the Web service port type
being implemented. It is defined by the JAX-RPC, which specifies the
language mapping from WSDL 1.1 to Java. Ref
Or
A service endpoint interface (SEI) is a Java interface that
declares the methods that a client can invoke on the service. Ref
These ser,dser,helper are helpers to convert an XML document into a java object and vice versa (WebServices). Ref
Files generated in the server project: (WebSphere Application Server 6.1 Ref)
According to the settings made during the run of the wizard, the following files in the WeatherJavaBeanWeb project have been created:
Service endpoint interface (SEI): itso.bean.WeatherJavaBean_SEI.java is the interface defining the methods exposed in the Web service.
WSDL file: /WebContent/WEB-INF/wsdl/WeatherJavaBean.wsdl describes the Web service.
Deployment descriptor: webservices.xml, ibm-webservices-ext.xml and ibm-webservices-bnd.xml. These files describe the Web service according to the Web services for J2EE style (JSR 109). The JAX-RPC mapping is described in the WeatherJavaBean_mapping.xml file.
Data mapping files: The helper beans in the itso.objects package perform the data conversion from XML to Java objects and back.
A servlet is defined in the Web deployment descriptor to invoke the JavaBean.
Hope this information help you.
Those files are related to the WebSphere mapping between Java, WSDL, and XML. They are automatically generated, and should not need to be edited. You should pretend they are not there (except if they are not there you may have trouble deploying...).
SEI - Service Endpoint Interface
ser - Serialize
deser - Deserialize
helper - ?
Here are some psuedo-helpful links, that may provide some more insight into your question:
IBM Technotes
WebSphere v6.1 Handbook (check Chapter 15 -> Creating a Web Service --> Generated Files)
All these files are basically generated for webservice.
A web service ia basically a port between 2 running applications independant of the framework or language.
Leta say if you are using java from one side of web service then for complete compilation the java end would need some class files that have those methids which you wish to call on the service.
For this a stub is generated. This stub is basically an interface(SEI).
Also websphere needs additional files for implementing the webservices functionality, thus tge helper files.
This is basically the summary of it.

Categories

Resources