RE: Re: Restlet Jax-RS extension and OSGi

2009-04-02 Thread Jerome Louvel
Dave,

Were you able to fix or workaround this issue? If not, you should enter a
defect report (a patch would be nice).
 
Best regards,
Jerome Louvel
--
Restlet ~ Founder and Lead developer ~ http://www.restlet.org
Noelios Technologies ~ Co-founder ~ http://www.noelios.com
 

-Message d'origine-
De : David Fogel [mailto:carrotsa...@gmail.com] 
Envoyé : vendredi 20 mars 2009 04:55
À : discuss@restlet.tigris.org
Objet : Re: Re: Restlet Jax-RS extension and OSGi

Hi Stephan-

I've been experimenting with the restlet.ext.jaxrs support, trying to get a
small test project working, and I've run into what seems like a pretty big
problem.  While I am fairly new to JAX-RS, it is my understanding that the
suggested way of giving your Resource classes access to other things in
their environment (such as a persistence service, a ServletContext, an osgi
BundleContext, etc) is by creating classes that extend
javax.ws.rs.ext.ContextResolver, annotating them with @Provider, and
registering instances of them with the jax-rs implementation.  The container
should then be able to inject these custom objects into Resource classes
that annotate a parameter or field type with @Context.

For example, if I have a service class called StorageService, I would create
a ContextResolver like this:

@Provider
public class StorageServiceResolver extends ContextResolver
{

  private StorageService service;

  public StorageServiceResolver(StorageService service) {
this.service = service;
  }

  public StorageService getContext(Class type) {
return service;
  }
}

I would then be able to access the StorageService object within my Resource
classes like this:

@Path("path/to/root/resource")
public class MyResource {

  // should be able to do annotate a field:
  @Context
  private StorageService service;

  // OR should be able to annotate a constructor param:
  public MyResource(@Context StorageService service) {
this.service = service;
  }

  @GET
  @Produces("text/plain")
  public String getStoredThing(@QueryParam("id") String id) {

// and then access the service here:
return service.getValueForID(id);
  }
}

But when I create such classes, and register them with your JaxRsRestlet,
the JaxRsRestlet refuses to accept the Resource classes, claiming that they
are missing any valid constructor or that a field can not be injected with
that type.

The problem may be that the methods in WrapperUtil.java don't make use of
the current set of "providers", but instead expect only the minimal set of
predefined context types.

Is there some other way I'm missing to give my Resource classes access to my
application environment?

thanks,
  -Dave Fogel

--
http://restlet.tigris.org/ds/viewMessage.do?dsForumId=4447&dsMessageId=13610
04

--
http://restlet.tigris.org/ds/viewMessage.do?dsForumId=4447&dsMessageId=1522529


RE: Restlet Jax-RS extension and OSGi

2009-03-26 Thread Jerome Louvel
Hi David,

As mentioned in the "code" list, I've added your first long term workaround.
I agree that the second one would be even better, so I've entered a RFE:

"Improve setting of JAX-RS API implementation"
http://restlet.tigris.org/issues/show_bug.cgi?id=767

Regarding the JAX-RS implementation, we definitely want to maintain it,
complete it and upgrade to JAX-RS 1.1 when it is released. It's a strategic
piece for the project, so no question about that.

Stephan has lacked time in the past months due to a new job and moving into
a new place. On my side, I've started to get more involved in the code of
the extension but I've got so many other things to do that I would warmly
welcome any help until Stephan can jump on this again. 

So, YES, your contributions would be welcome! :)
 
Best regards,
Jerome Louvel
--
Restlet ~ Founder and Lead developer ~ http://www.restlet.org
Noelios Technologies ~ Co-founder ~ http://www.noelios.com
 

-Message d'origine-
De : David Fogel [mailto:carrotsa...@gmail.com] 
Envoyé : lundi 23 mars 2009 17:01
À : discuss@restlet.tigris.org
Objet : Re: Restlet Jax-RS extension and OSGi

Hi Stephan-

Thanks for taking a look at this.

Yes, I did see that it would be possible to get the Providers object
injected into my resource classes.  However I don't think that is the
recommended way to accomplish this with Jax-Rs.  (from what I remember, I
think the Providers object is often meant to be injected into other Provider
classes that need to make use of pre-existing Providers, but I'm not sure.)

Is there any plan or timeframe for continuing development of the Restlet
JAX-RS implementation?  Would it make sense for me to put some time
contributing some patches to this implementation?

Thanks again,

  - Dave Fogel

On Mon, Mar 23, 2009 at 4:37 AM, Stephan Koops  wrote:
> Hi David,
>
> I've had no time to look into my own code or work with it, so I 
> forget, that the injection was changed.
> Use a field (or parameter) of type javax.ws.rs.ext.Providers, annotate 
> it with @Context and use method getContextResolver(...) .
>
> I hope, that's the right solution. As said, I've long time no time to 
> keep me busy with Restlet and JAX-RS. Sorry for the wrong information
first.
>
> best regards
>   Stephan

--
http://restlet.tigris.org/ds/viewMessage.do?dsForumId=4447&dsMessageId=13905
77

--
http://restlet.tigris.org/ds/viewMessage.do?dsForumId=4447&dsMessageId=1429067


RE: Re: Restlet Jax-RS extension and OSGi

2009-03-25 Thread Jerome Louvel
Dave,

Thanks. I've added your workaround to SVN trunk.

Let's consider using a better solution in the long term, such as your
fragment idea or a special Activator.
 
Best regards,
Jerome Louvel
--
Restlet ~ Founder and Lead developer ~ http://www.restlet.org
Noelios Technologies ~ Co-founder ~ http://www.noelios.com
 

-Message d'origine-
De : David Fogel [mailto:carrotsa...@gmail.com] 
Envoyé : jeudi 19 mars 2009 19:25
À : discuss@restlet.tigris.org
Objet : RE: Re: Restlet Jax-RS extension and OSGi

Hi Stephan-

Well, in my previous message I actually described two quick fixes (that can
be used by developers), as well as two solutions that involve changes to the
extension.

The easiest one for you to do quickly would be to add the following static
code block to JaxRsRestlet:

public class JaxRsRestlet extends Restlet {

static {
javax.ws.rs.ext.RuntimeDelegate.setInstance(
new org.restlet.ext.jaxrs.internal.spi.RuntimeDelegateImpl());
}

...
}

But, as I said in my message, I believe the best solution would be to have
the JAX-RS API classes included in the org.restlet.ext.jaxrs.jar build
artifact.

-Dave Fogel

> 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

--
http://restlet.tigris.org/ds/viewMessage.do?dsForumId=4447&dsMessageId=13568
63

--
http://restlet.tigris.org/ds/viewMessage.do?dsForumId=4447&dsMessageId=1416985


Re: Restlet Jax-RS extension and OSGi

2009-03-23 Thread Stephan Koops
Hi David,
> Yes, I did see that it would be possible to get the Providers object
> injected into my resource classes.  However I don't think that is the
> recommended way to accomplish this with Jax-Rs.  (from what I
> remember, I think the Providers object is often meant to be injected
> into other Provider classes that need to make use of pre-existing
> Providers, but I'm not sure.)
>   
If I remeber right (!), first the way was to annotate the 
javax.ws.rs.ext.ContextResolver with @Context, but than we changed it to 
the current way to use javax.ws.rs.ext.Provider. The reasons are not in 
my mind now; you have to look in the mailing list archive 
(https://jsr311.dev.java.net/servlets/ProjectMailingListList, look into 
mailing lists dev and users).
This change is the reason for the explicit hint in the code.
> Is there any plan or timeframe for continuing development of the
> Restlet JAX-RS implementation?  Would it make sense for me to put some
> time contributing some patches to this implementation?
Yes, nice ! But unfortunatley I have not much time, because I'm very 
busy at work this months. I hope, I will have time in the next weeks.

best regards
Stephan

--
http://restlet.tigris.org/ds/viewMessage.do?dsForumId=4447&dsMessageId=1391575


Re: Restlet Jax-RS extension and OSGi

2009-03-23 Thread David Fogel
Hi Stephan-

Thanks for taking a look at this.

Yes, I did see that it would be possible to get the Providers object
injected into my resource classes.  However I don't think that is the
recommended way to accomplish this with Jax-Rs.  (from what I
remember, I think the Providers object is often meant to be injected
into other Provider classes that need to make use of pre-existing
Providers, but I'm not sure.)

Is there any plan or timeframe for continuing development of the
Restlet JAX-RS implementation?  Would it make sense for me to put some
time contributing some patches to this implementation?

Thanks again,

  - Dave Fogel

On Mon, Mar 23, 2009 at 4:37 AM, Stephan Koops  wrote:
> Hi David,
>
> I've had no time to look into my own code or work with it, so I forget,
> that the injection was changed.
> Use a field (or parameter) of type javax.ws.rs.ext.Providers, annotate
> it with @Context and use method getContextResolver(...) .
>
> I hope, that's the right solution. As said, I've long time no time to
> keep me busy with Restlet and JAX-RS. Sorry for the wrong information first.
>
> best regards
>   Stephan

--
http://restlet.tigris.org/ds/viewMessage.do?dsForumId=4447&dsMessageId=1390577


Re: Restlet Jax-RS extension and OSGi

2009-03-23 Thread Stephan Koops
Hi David,

I've had no time to look into my own code or work with it, so I forget, 
that the injection was changed.
Use a field (or parameter) of type javax.ws.rs.ext.Providers, annotate 
it with @Context and use method getContextResolver(...) .

I hope, that's the right solution. As said, I've long time no time to 
keep me busy with Restlet and JAX-RS. Sorry for the wrong information first.

best regards
   Stephan

David Fogel schrieb:
> Stephan-
>
> Maybe I should write shorter messages, so as to encourage people to
> actually read them.  :-)
>
> As I said in my previous message, I tried to use field injection as
> well as constructor param injection.  Both attempts failed.
>
> This is the log message I get when I try the annotated field approach
> that you recommend:
>
> Mar 20, 2009 12:48:14 PM
> org.restlet.ext.jaxrs.internal.wrappers.ResourceClasses addRootClass
> WARNING: The root resource class com.example.TestResource has an
> illegal annotated and typed field: class com.example.StorageService
> must not be annotated with @Context
>
> Here is the method in your class
> org.restlet.ext.jaxrs.internal.wrappers.params.ContextInjenctor
>
> static Object getInjectObject(Class declaringClass,
> ThreadLocalizedContext tlContext, Providers providers,
> ExtensionBackwardMapping extensionBackwardMapping)
> throws IllegalTypeException, ImplementationException {
> if (declaringClass.equals(Providers.class)) {
> return providers;
> }
> if (declaringClass.equals(ContextResolver.class)) {
> // NICE also throw, where the error occurs.
> throw new IllegalTypeException(
> "The ContextResolver is not allowed for @Context
> annotated fields yet. Use
> javax.ws.rs.ext.Providers#getContextResolver(...)");
> }
> if (declaringClass.equals(ExtensionBackwardMapping.class)) {
> return extensionBackwardMapping;
> }
> if (declaringClass.equals(PathSegment.class)) {
> final String msg = "The use of PathSegment annotated with
> @Context is not standard.";
> logger.config(msg);
> return new GetLastPathSegment(tlContext);
> }
> if (declaringClass.equals(SecurityContext.class)
> || declaringClass.equals(HttpHeaders.class)
> || declaringClass.equals(Request.class)) {
> return tlContext;
> }
> if (declaringClass.equals(UriInfo.class)) {
> throw new ImplementationException(
> "You must not call the method
> ContextInjector.getInjectObject(...) with class UriInfo");
> }
> // NICE also allow injection of ClientInfo and Conditions. Proxies are
> // required, because the injected objects must be thread local.
> throw new IllegalTypeException(declaringClass
> + " must not be annotated with @Context");
> }
>
> It doesn't appear that this code currently supports having custom
> ContextResolver providers (although they appear to be available in the
> "providers" parameter).
>
> I'd very much appreciate it if you could take a closer look at this-
> seems like an important part of any JAX-RS implementation!
>
>   -Dave Fogel
>
> On Fri, Mar 20, 2009 at 4:04 AM, Stephan Koops  wrote:
>   
>> Hi David,
>>
>> use
>>
>>  @Context
>>  private StorageServiceResolver serviceResolver;
>>
>> best regards
>>   Stephan
>> 
>
> --
> http://restlet.tigris.org/ds/viewMessage.do?dsForumId=4447&dsMessageId=1365883
>

--
http://restlet.tigris.org/ds/viewMessage.do?dsForumId=4447&dsMessageId=1388032


Re: Restlet Jax-RS extension and OSGi

2009-03-20 Thread David Fogel
Stephan-

Maybe I should write shorter messages, so as to encourage people to
actually read them.  :-)

As I said in my previous message, I tried to use field injection as
well as constructor param injection.  Both attempts failed.

This is the log message I get when I try the annotated field approach
that you recommend:

Mar 20, 2009 12:48:14 PM
org.restlet.ext.jaxrs.internal.wrappers.ResourceClasses addRootClass
WARNING: The root resource class com.example.TestResource has an
illegal annotated and typed field: class com.example.StorageService
must not be annotated with @Context

Here is the method in your class
org.restlet.ext.jaxrs.internal.wrappers.params.ContextInjenctor

static Object getInjectObject(Class declaringClass,
ThreadLocalizedContext tlContext, Providers providers,
ExtensionBackwardMapping extensionBackwardMapping)
throws IllegalTypeException, ImplementationException {
if (declaringClass.equals(Providers.class)) {
return providers;
}
if (declaringClass.equals(ContextResolver.class)) {
// NICE also throw, where the error occurs.
throw new IllegalTypeException(
"The ContextResolver is not allowed for @Context
annotated fields yet. Use
javax.ws.rs.ext.Providers#getContextResolver(...)");
}
if (declaringClass.equals(ExtensionBackwardMapping.class)) {
return extensionBackwardMapping;
}
if (declaringClass.equals(PathSegment.class)) {
final String msg = "The use of PathSegment annotated with
@Context is not standard.";
logger.config(msg);
return new GetLastPathSegment(tlContext);
}
if (declaringClass.equals(SecurityContext.class)
|| declaringClass.equals(HttpHeaders.class)
|| declaringClass.equals(Request.class)) {
return tlContext;
}
if (declaringClass.equals(UriInfo.class)) {
throw new ImplementationException(
"You must not call the method
ContextInjector.getInjectObject(...) with class UriInfo");
}
// NICE also allow injection of ClientInfo and Conditions. Proxies are
// required, because the injected objects must be thread local.
throw new IllegalTypeException(declaringClass
+ " must not be annotated with @Context");
}

It doesn't appear that this code currently supports having custom
ContextResolver providers (although they appear to be available in the
"providers" parameter).

I'd very much appreciate it if you could take a closer look at this-
seems like an important part of any JAX-RS implementation!

  -Dave Fogel

On Fri, Mar 20, 2009 at 4:04 AM, Stephan Koops  wrote:
> Hi David,
>
> use
>
> �...@context
>  private StorageServiceResolver serviceResolver;
>
> best regards
>   Stephan

--
http://restlet.tigris.org/ds/viewMessage.do?dsForumId=4447&dsMessageId=1365883


Re: Restlet Jax-RS extension and OSGi

2009-03-20 Thread Stephan Koops
Hi David,

use

  @Context
  private StorageServiceResolver serviceResolver;

best regards
   Stephan

David Fogel schrieb:
> Hi Stephan-
>
> I've been experimenting with the restlet.ext.jaxrs support, trying to
> get a small test project working, and I've run into what seems like a
> pretty big problem.  While I am fairly new to JAX-RS, it is my
> understanding that the suggested way of giving your Resource classes
> access to other things in their environment (such as a persistence
> service, a ServletContext, an osgi BundleContext, etc) is by creating
> classes that extend javax.ws.rs.ext.ContextResolver, annotating them
> with @Provider, and registering instances of them with the jax-rs
> implementation.  The container should then be able to inject these
> custom objects into Resource classes that annotate a parameter or
> field type with @Context.
>
> For example, if I have a service class called StorageService, I would
> create a ContextResolver like this:
>
> @Provider
> public class StorageServiceResolver extends ContextResolver {
>
>   private StorageService service;
>
>   public StorageServiceResolver(StorageService service) {
> this.service = service;
>   }
>
>   public StorageService getContext(Class type) {
> return service;
>   }
> }
>
> I would then be able to access the StorageService object within my
> Resource classes like this:
>
> @Path("path/to/root/resource")
> public class MyResource {
>
>   // should be able to do annotate a field:
>   @Context
>   private StorageService service;
>
>   // OR should be able to annotate a constructor param:
>   public MyResource(@Context StorageService service) {
> this.service = service;
>   }
>
>   @GET
>   @Produces("text/plain")
>   public String getStoredThing(@QueryParam("id") String id) {
>
> // and then access the service here:
> return service.getValueForID(id);
>   }
> }
>
> But when I create such classes, and register them with your
> JaxRsRestlet, the JaxRsRestlet refuses to accept the Resource classes,
> claiming that they are missing any valid constructor or that a field
> can not be injected with that type.
>
> The problem may be that the methods in WrapperUtil.java don't make use
> of the current set of "providers", but instead expect only the minimal
> set of predefined context types.
>
> Is there some other way I'm missing to give my Resource classes access
> to my application environment?
>
> thanks,
>   -Dave Fogel

--
http://restlet.tigris.org/ds/viewMessage.do?dsForumId=4447&dsMessageId=1362709


Re: Re: Restlet Jax-RS extension and OSGi

2009-03-19 Thread David Fogel
Hi Stephan-

I've been experimenting with the restlet.ext.jaxrs support, trying to
get a small test project working, and I've run into what seems like a
pretty big problem.  While I am fairly new to JAX-RS, it is my
understanding that the suggested way of giving your Resource classes
access to other things in their environment (such as a persistence
service, a ServletContext, an osgi BundleContext, etc) is by creating
classes that extend javax.ws.rs.ext.ContextResolver, annotating them
with @Provider, and registering instances of them with the jax-rs
implementation.  The container should then be able to inject these
custom objects into Resource classes that annotate a parameter or
field type with @Context.

For example, if I have a service class called StorageService, I would
create a ContextResolver like this:

@Provider
public class StorageServiceResolver extends ContextResolver {

  private StorageService service;

  public StorageServiceResolver(StorageService service) {
this.service = service;
  }

  public StorageService getContext(Class type) {
return service;
  }
}

I would then be able to access the StorageService object within my
Resource classes like this:

@Path("path/to/root/resource")
public class MyResource {

  // should be able to do annotate a field:
  @Context
  private StorageService service;

  // OR should be able to annotate a constructor param:
  public MyResource(@Context StorageService service) {
this.service = service;
  }

  @GET
  @Produces("text/plain")
  public String getStoredThing(@QueryParam("id") String id) {

// and then access the service here:
return service.getValueForID(id);
  }
}

But when I create such classes, and register them with your
JaxRsRestlet, the JaxRsRestlet refuses to accept the Resource classes,
claiming that they are missing any valid constructor or that a field
can not be injected with that type.

The problem may be that the methods in WrapperUtil.java don't make use
of the current set of "providers", but instead expect only the minimal
set of predefined context types.

Is there some other way I'm missing to give my Resource classes access
to my application environment?

thanks,
  -Dave Fogel

--
http://restlet.tigris.org/ds/viewMessage.do?dsForumId=4447&dsMessageId=1361004


RE: Re: Restlet Jax-RS extension and OSGi

2009-03-19 Thread David Fogel
Hi Stephan-

Well, in my previous message I actually described two quick fixes (that can be 
used by developers), 
as well as two solutions that involve changes to the extension.

The easiest one for you to do quickly would be to add the following static code 
block to JaxRsRestlet:

public class JaxRsRestlet extends Restlet {

static {
javax.ws.rs.ext.RuntimeDelegate.setInstance(
new org.restlet.ext.jaxrs.internal.spi.RuntimeDelegateImpl());
}

...
}

But, as I said in my message, I believe the best solution would be to have the 
JAX-RS API classes 
included in the org.restlet.ext.jaxrs.jar build artifact.

-Dave Fogel

> 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

--
http://restlet.tigris.org/ds/viewMessage.do?dsForumId=4447&dsMessageId=1356863


Re: Restlet Jax-RS extension and OSGi

2009-03-19 Thread Stephan Koops
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 par

Restlet Jax-RS extension and OSGi

2009-03-19 Thread David Fogel
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