How to resolve jersey.internal.RuntimeDelegateImpl with Jersey on OSGi - java

Im am using Jersey in an OSGi environment. I wrapped all Jetty and Jersey jars in one bundle containing also my own server / servlet / resource abstraction. This is running quite well. I am importing the javax.ws.rs-api via OSGi package import because related packages are also used by JAX-RS resource implementations in other bundles.
However, from time to time my implementation does not work with an "java.lang.ClassNotFoundException: org.glassfish.jersey.internal.RuntimeDelegateImpl cannot be found by javax.ws.rs-api_2.1.0".
It seems this could be a race condition. Maybe Jersey sometimes uses a class from my internal bundles and sometimes a class from imported javax. I cannot really figure out what the problem is.
The problem is similar to [1], but in my case it is not about any import or dependency. I wrapped the Jetty and Jersey Jars in an OSGi bundle.
[1] org.glassfish.jersey.internal.RuntimeDelegateImpl NOT FOUND

This problem occurs because the JAX-RS API uses many static methods to get hold of implementation types from the JAX-RS provider. In this case the error isn't coming from Jersey, but actually from the JAX-RS API itself when it tries to find an implementation of the various JAX-RS interfaces.
You effectively have four options:
Avoid exposing the JAX-RS API from your server by putting all the resources in there as well (I don't recommend this option!)
Embed the JAX-RS API in your existing Jetty/Jersey uber bundle and export it from there. Be careful to include the correct API package versions and contract capabilities! (This option is fiddly)
Use an OSGi-aware API bundle (such as one from Apache Aries, Apache Geronimo or Apache Service Mix). Many Java EE API bundles (JAX-RS included) package themselves as OSGi bundles, but ignore the fact that they actually need to work in OSGi, which means that you can't rely on reflectively loading types/resources from a flat classpath. (This option is probably quickest and lets you keep working as you are)
Move to using the new OSGi JAX-RS whiteboard from OSGi Release 7. The reference implementation for this is in Apache Aries and available on GitHub (This is the best long term option from an OSGi perspective, and means that you can avoid maintaining your own server)
I hope this all makes sense, explains why you're seeing the error, and hopefully gives you some options for working through the problem.

Related

Swagger does not recognize #Api annotation if used in ear module but swagger deployed in war

We are using Wildlfy 10 and Swagger 1.5.12 (Swagger 2.0 Spec)
In our application we are deploying the contract and implementation of our webservice in our ear to ensure being able to exchange the implementation on this level.
The war exposing our webservice is packaged in the same ear and has access to all its modules.
The swagger definition is placed in the war file. While the webservice endpoints are working as intended the swagger.json only contains the general information but does not contain the Api documentation.
After debugging a while i came to the following result:
The classes are discovered by the Scanner using reflections.getTypesAnnotatedWith(Api.class)
trying to generate the config afterwards they are using cls.getAnnotation(annotationClass) and alternatively cls.getAnnotations() and annotation = metaAnnotation.annotationType().getAnnotation(annotationClass); both return null
After debugging further i narrowed it down to the fact, that the Annotation attached to the class is loaded by the ear-classloader while swagger is using the war-classloader (as it is placed in the war).
This is conform to the Wildlfy Documentation as war-modules use a different classloader.
Other questions were answered with
I think you'll end up with other issues with the multiple classloader issue
source
and
To be honest it should be also said that when you load the same class in more than a ClassLoader it's quite easy getting other side effects, like static state duplication and so on.
That's why I think the developers using swagger in exotic scenarios - like build systems integration - should be warned about the fact that the library uses reflection for code analysis, hence the classloader matters.
source
Deploying the contract and ejb module in our war solved it, but unfortunately is no valid solution in our architecture.
Questions:
Is there a (non hacky) way to load the swagger-annotations-jar in the ear module with the same classloader in bot the war and ear modules?
Is it possible to solve this by tweaking the swagger configuration? (adjusting the implementation to not use reflection is only the last resort)
Can this be seen as a bug of swagger?

WildFly RestEasy Version confusion

I want to build a REST API using RestEasy. The generated file should be deployed in a WildFly application server.
I face the issue described in the following SO-question:
AsynchronousDispatcher error
The marked solution tells me, to set the dependency to "provided". Which as far as I understand means, that the library is not included in my war file but taken directly from the app-server...
Isn't that just wrong?
My idea would be to build a self-containing war file which contains all the needed libraries in the version I need.
When provided from the app-server I do get the currently available version from there. I have not really a clue about the version... when someone has the idea to update the RestEasy library on the server, it might break my app.
I'm not sure whether I missed something or did something completely wrong?
One of the big advantages to Java EE is developing towards the API and not having to worry about the implementation. Java EE containers provide the API's and implementations for the API's. If you include implementation dependencies one of two things is likely to happen.
You're dependencies will be ignored making it pointless to include them in your deployment.
You'll get conflicts between the dependencies you included vs what the server is expecting. This could be things like:
ClassCastException because it's finding two of the same class on the class path.
MethodNotFoundException because there is a version mismatch
Various other issues with conflcts
Developing towards the API instead of the implementation also allows you to easily switch between Java EE compliant containers with no to minimal changes to your deployment. The API's are generally backwards compatible as well making version upgrades not as big of an issue.
If you want to use a fat WAR (including implementations) instead of a skinny WAR (not including the implementations) then a servlet container is probably a better solution. WildFly does have a servlet only download. I'd encourage you though to trust container to do the right thing with the implementation dependencies :). Usually the only time there is an issue with upgrading is if you're upgrading Java EE versions. Even then it's usually pretty safe.

How can I expose Eclipse plugins as web services?

I've been doing my research about exposing Eclipse plugins as web services, but I'm getting confused.
My requirement is basically to build an Equinox back end for a set of web services.
I'll be using EMF and related projects heavily, so with this goal in mind I've been reading about Equinox/OSGI and options to build what I need.
However, there are some mysterious points and in general an abundance of projects around. Given the findings below, I'd like hear your suggestions. Maybe there is an option I'm missing, or maybe you've done this before. Here are the nominees (drumroll)
Hosting Equinox in a web container. Using bridge.war, the plugins can expose a servlet. The problem is, to use nice REST frameworks such as RestEasy (my favourite), the REST framework needs to be a osgi bundle that'd live in the Equionox runtime. I've spend 3 days, and due to classloader issues, this is not working. I am now convinced that I won't be able to have RestEasy in Equinox. I can have RestEasy in web container, and use XML serialization/deserialization to make code in web container talk to code in Equionox, but this feels like such a waste of resources. Still, this may work.
The other option seems to be ECF, which is an implementation of distributed OSGI, which seems to support SOAP/Rest. However, I could not find a clear tutorial that just exposes Equinox hosted functionality as a web service. So this still forces me no not to use RestEasy, but at least it seems to give me a proper framework to talk to Equinox. I'd probably still have to keep this in a web contaner for scalability.
Then there is Eclipse Virgo, which seems to support hosting web applications alongside OSGI runtime, and apparently web container hosted code can talk to OSGI runtime code. Still, I am not sure if I can pass around classes since a Jaxb annotated type A created under web container is likely to use a differnet classloader than the OSGI runtime plugin. Also, this setup locks me into Virgo, and I would rather go with JBoss etc for production use.
So given these options, and possibly more I do not know about at the moment, how would you expose EMF and other Eclipse framework based projects as web services?
Edit:
based on the great response I'd like to add more. Partially details of the question, partially comments which did not fit into comment section.
My research after the question let me to the exact same point with the accepted answer: Apache CXF is now an implementation of Distributed OSGI, which is good. I have given up on RestEasy. My current concern is, I already have a XSD that has created my classes. RestEasy made it very easy to expose these, and I'd have to do the same here. My plugins would have to use these JAXB based classes. In the worst case, I may attempt to use Eclipse Link project which offers JAXB support, in order to create XML content, and pass it through either basic servlet use or as string values based on CXF. So solutions discussed here don't feel perfect, but I guess this is the best one can do at the moment.
I work on a product that has done this. We have Equinox inside the web container. We expose SOAP and REST web services using Apache CXF. It took some black magic to get everything wired up correctly. I found the CXF documentation to be not so great, especailly for OSGI.
As I am sure you know, hosting Equinox in the web container is not a recommended practice, although it is a hard one to avoid if you want to use OSGI. We too experienced a number of classloading issues. In fact we never really enjoyed the advertised benefits from OSGI (modularity, etc). It's too late for us to turn back now. OSGI should not be entered into lightly.
So here is a quick overview of how we have enabled SOAP/REST using CXF. Hopefully this will at least point you in the right direction.
1) Install CXF OSGI bundles, both core and DOSGI - We are using the following:
cxf-bundle-minimal-2.2.12.jar
cxf-dosgi-ri-discovery-local-1.1.jar
cxf-dosgi-ri-dsw-cxf-1.1.jar
Links:
http://cxf.apache.org/download.html
2) Install JAX-RS (REST) and JAX-WS (SOAP) APIs
-The API definition are in org.apache.servicemix.specs.jsr311-api-1.0-1.3.0.jar and org.apache.servicemix.specs.jaxws-api-2.1-1.1.1.jar (these are the versions we have)
-These may or may not be bundled with CXF. IN our case, only the JAX-WS jar was included. We had to hunt down the JAX-RS bundle.
-In addition to installing the bundles in the webapp (WEB-INF/eclipse/plugins), we also had to add them to the ECLIPSE/plugins directory for compilation.
3) Tell Equinox to load CXF plugins. There are probably other ways to do this. We accomplished this with entries in WEB-INF/eclipse/configuration/config.ini.
-If this file exists, add your new jars to the osgi.bundles property:
osgi.bundles=... org.apache.servicemix.specs.jaxb-api-2.1-1.1.1.jar#start, org.apache.servicemix.specs.jaxws-api-2.1-1.1.1.jar#start, org.apache.servicemix.specs.jsr311-api-1.0-1.3.0.jar#start, \
cxf-dosgi-ri-discovery-local-1.1.jar#5:start, \
cxf-bundle-minimal-2.2.12.jar#5:start, \
cxf-dosgi-ri-dsw-cxf-1.1.jar#5:start
4) That's it. You should now be able to start writing SOAP and REST services. This is a Java-first approach (as opposed to XML-schema first). What this means is that you:
-Define a Java interface
-Configure CXF to publish you interface as either REST or SOAP endpoint.
Here's a very simple example for REST. It comes with the standard disclaimer that it is specific to our environment. YMMV.
a) We use declarative services, so first we define the DS file in our bundle's manifest
Service-Component: META-INF/ds/helloworld.xml
b) Here is the DS file: META-INF/ds/helloworld.xml. The DS file defines the services in your OSGI bundle and their dependencies. Those entries have been omitted for brevity.
<?xml version="1.0"?>
<components xmlns="http://www.osgi.org/xmlns/scr/v1.0.0">
<component name="hello_world_service" xmlns="http://www.osgi.org/xmlns/scr/v1.0.0">
<!-- Defines this as a REST service --->
<property name="service.exported.configs" value="org.apache.cxf.rs"/>
<!-- This is the URI of your REST resource.
It is realtive to the Equinox bridge servlet in your webapp -->
<property name="org.apache.cxf.rs.httpservice.context" value="/helloworld" />
<!-- This is the java interace that will be exposed . You
will use JAX-RS annotations to map these java methods to HTTP verbs. -->
<property name="service.exported.interfaces" value="com.foo.IHelloWorldService"/>
...
</components>
c) Here is the interface class:
package com.foo;
#Path("/greeting")
public Interface IHelloWorldService {
#GET
#Produces("application/xml")
public Greeting getGreeting();
}
public class HelloWorldService implements IHelloWorldService {
#override
public Greeting getGreeting() {
Greeting g = new Greeting();
g.message = "Hello World";
return g;
}
}
d) So, once this is all in place, you should be able to GET the following URL:
/<web-app-name>/bridge/helloworld/greeting
and receive the following response:
<Greeting>
<message>Hello World</message>
</Greeting>
Good luck. Hope this helps.
Unfortunately I think that RESTeasy is the problem here. As per your comment in another question, RESTeasy uses the Java ServiceLoader API to lookup classes dynamically, which unfortunately makes assumptions about classloading that are untrue in any non-flat (i.e. modular) classloading architecture.
I would encourage you to ask on the RESTeasy forums about alternatives to the ServiceLoader approach to looking up these classes. It may be possible to explicitly register those classes, for example.
However failing a solution that allows you to continue using RESTeasy, there are alternative REST APIs that do work very well in OSGi. Restlet for example has explicit OSGi support. I have successfully used Jersey as well.

java tomcat6: javax.ws missing

I'm trying to run TinyFbClient (tiny facebook client) and it needs to import
javax.ws.rs.core.UriBuilder and javax.ws.rs.core.MediaType
i don't have javax.ws package.
what jar file am i missing?
programming using netbeans 6.8
on tomcat 6.0.20
thanks!
You need a concrete JAX-WS implementation. Tomcat isn't, it's just a Servlet API implementation. You'll need another appserver which implements JAX-WS as well (e.g. Glassfish), or to add a concrete JAX-WS implementation to your webapp. Glassfish uses Metro, which is built on top of Sun reference JAX-WS implementation. You can download it separately and use on Tomcat as well. If you Google using keywords "tomcat metro", you'll find several hints at blogs, for example this one.
Update you need javax.ws.rs package, not javax.ws package only ;) So here's a slight modified answer:
You need a concrete JAX-RS implementation. Tomcat isn't, it's just a Servlet API implementation. You'll need another appserver which implements JAX-RS as well (e.g. Glassfish), or to add a concrete JAX-RS implementation to your webapp. Glassfish uses Jersey, which is built on top of Sun reference JAX-RS implementation. You can download it separately and use on Tomcat as well. If you Google using keywords "tomcat jersey", you'll find several hints at blogs, for example this one.
It seems you need JAX-RS on your classpath. Jersey is the JAX-RS reference imeplementation.
Googling, as advised by BalusC, gives this tutorial, which seems like a good one.

Using Guice with OSGi

I have a project that I am trying to convert to OSGi. However, this project has been built with Guice as its dependency injection manager. It's a large project with Guice interwoven all throughout. Guice has been giving me many fits with the conversion process. Specifically, it has been given me a NoClassDefFoundError for com.google.inject.internal.cglib.reflect.FastClass. I have made sure that nothing is package-private and I also downloaded and used the guice-2.0-customloader.jar. Still, to no avail.
Is there any advice from anyone that has gone down this path? It is worth mentioning that I use peaberry to get dynamic services from the OSGi environment (for a plugin-type architecture) that I then use in the program later on.
Thanks a lot,
Steve
Hard to say exactly what the problem is, classloader issues can be very situation specific in OSGi and hard to debug.
If guice really is a core to your application it may make sense to make it a Fragment bundle of the System Bundle. The System Bundle is the root node in the classloader tree for ALL bundles. If classes exist in this bundle, they'll be accessible everywhere. This is a technique I've used successfully to wrap Swing LAF (Substance, Alloy, Jide) as OSGi bundles. They've gotta be at the root level since all of my bundles use Swing (especially the Swing classloader)
You'll want to check the OSGi specs for creating a Fragment bundle and making that fragment bundle a framework extension fragment. I've only been able to do this using Eclipse's Equinox runtime. At the time I wrote most of the supporting classes, Apache Felix did not yet support framework extension fragments. It may have changed now. I have no idea about frameworks (knopplefish, spring-dm)
Just use Peaberry. It has all the support you need for using Guice in OSGi. No need to reinvent everything from scratch!
I'm assuming your comments on package-private are related to this page on Guice and bridging class loaders?
There's a bug report/patch that may be related to your issue: http://code.google.com/p/google-guice/issues/detail?id=343
Have you tried adding Guice and cglib to the standard classpath and doing boot delegation for them? That would prove/disprove your issue is the same one as mentioned on the above bug report.
You could try my latest patch for Issue 343 - just attached a freshly patched build which is the latest Guice trunk plus this one patch, so people can try it and give feedback.
The latest patch avoids a lot of these CGLIB exceptions without forcing you to make classes public, and also provides a better error message in the few remaining places where this is still necessary (basically when you explicitly use method interception).

Categories