Hi David, thanks for reporting it including solutions. Is this code, that I could include in the Restlet extension, or does every developer has to include it in his own code? If the first is the case, please enter an issue for it with the relevant parts of your email (http://restlet.tigris.org/servlets/ProjectIssues, don't forget to login).
I'm very busy now, so it may take a while until I've included your proposals best regards Stephan David Fogel schrieb: > Hello all- > > Has anybody actually tried to use the restlet Jax-RS extension in an OSGi > environment? > > My guess is that no-one has, because it doesn't work :-) > > By "doesn't work", I mean that trying to run a JaxRspplication in an OSGI > container will result in extremely odd and unclear runtime exceptions, > involving, among other things, ClassNotFoundException's for classes not > provided > by the ext jar at all (com.sun.ws.rs.ext.RuntimeDelegateImpl). > > The problem is this: > > The Jax-RS API, (shipped as "lib/javax.ws.rs_1.0/javax.ws.rs.jar" in the > restlet > distribution) does some pretty funky stuff. In addition to the painful but by > now somewhat expected use of the ServiceLoader pattern (where the API jar > inspects the classpath for resources named > "META-INF/services/javax.ws.rs.ext.RuntimeDelegate" and looks inside those > files > for an implementation class name), the jax-rs API jar executes this code > _lazily_, from within a static method on it's RuntimeDelegate class. This > means > that the API jar will look for a provided implementation only when some bit of > code first tries to access any of the jax-rs API classes which happen to make > use, internally, of this static method. > > The ServiceLoader code will fail to find any implementation in an OSGI > environment, and will then try, as a last resort, to find it's fallback > implementation: "com.sun.ws.rs.ext.RuntimeDelegateImpl", which also doesn't > exist, and for which it then reports a ClassNotFound exception, which is very > misleading. > > The good news is that there are several solutions and work-arounds. > > As a SHORT-TERM fix, any client code which wants to create a JaxRsApplication > can do one of two things that will allow the Jax-RS API to find the restlet > jax-rs extension implementation: > > 1) set the thread's context classloader (remember to restore it after): > > Classloader originalCL = Thread.currentThread().getContextClassLoader(); > ClassLoader jaxrsExtCL = JaxRsApplication.class.getClassLoader(); > Thread.currentThread().setContextClassLoader(jaxrsExtCL); > > JaxRsApplication jaxrsApp = new JaxRsApplication(); > jaxrsApp.add(new MyApplication()); // <- failure here without the above > > Thread.currentThread().setContextClassLoader(originalCL); > > OR > > 2) set the RuntimeDelegate instance manually: > > import javax.ws.rs.ext.RuntimeDelegate; > import org.restlet.ext.jaxrs.internal.spi.RuntimeDelegateImpl; > .... > > // this is the critical line > RuntimeDelegate.setInstance(new RuntimeDelegateImpl()); > > JaxRsApplication jaxrsApp = new JaxRsApplication(); > jaxrsApp.add(new MyApplication()); > > > However, I think it would be preferable if client code didn't have to know > anything about the internal workings of the JAX-RS SPI layer. So, I think > there > are two possible LONG-TERM solutions: > > 1) the Restlet jax-rs extension could call RuntimeDelegate.setInstance() > itself, > from within a static initializer block of code in, e.g. JaxRsRestlet.java. > This > is what I have running locally, and it works fine. > > OR > > 2) The Restlet jax-rs extension could ship with the JAX-RS API classes rolled > up > into it's bundle archive, either as a wholly-contained jar within the bundle > or > as "exploded" contents added to the extension jar. Then the JAX-RS API code > would exist within the same bundle classloader, and therefor the normal > service > discovery process would work fine. > > I think that solution #2 is preferable. > > In particular, the whole thing is a little ridiculous- unlike, for instance, > Restlet's use of the service loader pattern, the JAX-RS API, as it's designed > now, can only ever support EXACTLY ONE provider implementation, regardless > whether it's used in a standard or OSGi environment. Therefore, it certainly > adds no value whatsoever to distribut it as a freestanding jar, since it MUST > be > used in conjunction with exactly one provider. Additionally, it doesn't seem > like it should use the ServiceLoader pattern at all- why not just have a > static > dependency on a RuntimeDelegateImpl implementation class, and skip all the > complicated and fragile discovery stuff? The jax-rs API design in > particularly > loathsome in an OSGi environment, where, if not for the discovery processs, it > would be perfectly reasonable to have more than one jax-rs provider! > > Anyhow, sorry for the rant (I've just spent the better part of a day > struggling > with this stuff- ugh). > > -Dave Fogel > > p.s. should this be posted in the restlet.code list? > > ------------------------------------------------------ > http://restlet.tigris.org/ds/viewMessage.do?dsForumId=4447&dsMessageId=1350550 > ------------------------------------------------------ http://restlet.tigris.org/ds/viewMessage.do?dsForumId=4447&dsMessageId=1354173

