users@jersey.java.net

Re: [Jersey] restart a resource

From: Paul Sandoz <Paul.Sandoz_at_Sun.COM>
Date: Fri, 17 Oct 2008 13:05:23 +0200

On Oct 17, 2008, at 12:34 PM, Guilhem wrote:

> I was about to scream for victory after reloaded five times my
> service and then... no more reload.
>

Sorry about that :-( I just did some more tests and can reproduce the
problem.

It is due to multiple instances of ContainerNotifierImpl being created
because of the issue of configure being called every time there is a
reload. But! notification is initiated only at servlet init time. Gosh
this reloading area is complex!

Try having the following as a field of your servlet:

   ContainerNotifierImpl cn = new ContainerNotifierImpl();

or making sure that the following:

        ContainerNotifierImpl cn = new ContainerNotifierImpl();
        rc.getSingletons().add(new
ContextInjectableProvider<ContainerNotifierImpl>(
                ContainerNotifierImpl.class, cn));
         
rc.getProperties().put(ResourceConfig.PROPERTY_CONTAINER_NOTIFIER, cn);

is only called once by checking a boolean field:
        if (!configured) {
            ContainerNotifierImpl cn = new ContainerNotifierImpl();
            rc.getSingletons().add(new
ContextInjectableProvider<ContainerNotifierImpl>(
                    ContainerNotifierImpl.class, cn));
             
rc.getProperties().put(ResourceConfig.PROPERTY_CONTAINER_NOTIFIER, cn);
            configured = true;
        }

In my workspace i have fixed the multiple calls to configure and have
a unit test in place that reproduces your functionality and passes.

Paul.


> randomly (sometimes after the first reload, sometimes i reload 20
> times my resources without having the problem).
>
> I don't get an exception its just that the list of
> containerListener is empty :
>
>
>
> public class ContainerNotifierImpl implements ContainerNotifier {
> private List<ContainerListener> cls;
>
> public ContainerNotifierImpl() {
> cls = new ArrayList<ContainerListener>();
> }
> public void addListener(ContainerListener arg0) {
> cls.add(arg0);
> }
> public void reload() {
> System.out.println("reloading");
> for ( ContainerListener cl : cls) {
> cl.onReload();
> System.out.println("realoaded");
> }
> }
>
> }
>
>
> with the system.out i see that at a moment there is only
> "reloading" and no "reloaded".
>
>
>
>
> Guilhem a écrit :
>> I can't use the following line:
>>
>> rc.getSingletons().add(new
>> ContextInjectableProvider
>> <ContainerNotifierImpl>(ContainerNotifierImpl.class, cnImpl));
>>
>> ContextInjectableProvider has private access in
>> com.sun.jersey.spi.container.servlet.ServletContainer
>>
>
> I didn't see the following mail with static class sorry.
>>
>>
>> Paul Sandoz a écrit :
>>>
>>> On Oct 17, 2008, at 10:14 AM, Guilhem wrote:
>>>
>>>> hi paul,
>>>>
>>>> first I'm not using spring but yes all my resources are singletons.
>>>>
>>>
>>> Ah! I reproduced the same issue in a different context. I just
>>> reproduced what you observe using singleton instances explicitly
>>> added. The problem is the singleton instance is retaining the old
>>> reference on the field. When reloading the old instance of
>>> ConfigurationService needs to be removed from the singleton and a
>>> new one added.
>>>
>>> But i just noticed another issue, the reload application is doing:
>>>
>>> WebApplication _application = create();
>>> configure(config, resourceConfig, _application);
>>> initiate(resourceConfig, _application);
>>> application = _application;
>>>
>>> which is wrong, i think reload should just do:
>>>
>>> WebApplication _application = create();
>>> initiate(resourceConfig, _application);
>>> application = _application;
>>>
>>> which is why you require the boolean variable (but still see the
>>> issue with the old reference). Also i think configure should no
>>> longer have WebApplication passed in as a parameter to the method.
>>>
>>> Perhaps i was being too smart proposing the use of a singleton
>>> resource and instead it may be more appropriate to inject a
>>> ContainerNotifier implementation as follows in the Servlet
>>> configure method:
>>>
>>> rc.getSingletons().add(new
>>> ContextInjectableProvider<ContainerNotifierImpl>(
>>> ContainerNotifierImpl.class, cnImpl));
>>>
>>> and in your ConfigurationService do:
>>>
>>> @Path("reload")
>>> public class ConfigurationService {
>>> @Context ContainerNotifierImpl cn;
>>>
>>> @Context UriInfo u;
>>>
>>> @POST public void reload() {
>>> cn.reload();
>>> }
>>> }
>>>
>>> Then you will not get any old reference issues.
>>>
>>>
>>>> i'm using the :
>>>> @Context
>>>> protected UriInfo context;
>>>>
>>>> MultivaluedMap parameters = context.getQueryParameters();
>>>>
>>>> to get a GET parameters like: request=restart or whatever in
>>>> all my singletons.
>>>>
>>>>
>>>> the weird thing is that all the other resources restarted does
>>>> not throw the illegalStateException by getting parameters, only
>>>> the reloadResource launch this.
>>>>
>>>
>>> OK.
>>>
>>>
>>>> for 2), It seems that the resources are well destroyed and re-
>>>> instanciated (They all pass in constructor).
>>>>
>>>> when you say fields for injection you means that : @Context
>>>> Protected UriInfo context ?
>>>>
>>>
>>> Yes.
>>>
>>> Paul.
>>>
>>>> Guilhem
>>>>
>>>>
>>>>
>>>> Paul Sandoz a écrit :
>>>>> Hi Guilhem,
>>>>>
>>>>> This was a bit of a head scratcher. I am guessing you are using
>>>>> a Singleton resource with Spring?
>>>>>
>>>>> The problem is the reference held by the field on the singleton
>>>>> resource is longer valid after the reloading. This is because
>>>>> reloading will cause the web application to create new
>>>>> references for injection, which invalidates any previously help
>>>>> references. This is a general problem for singletons whose
>>>>> instances are controlled outside of Jersey and for which
>>>>> injection is performed. When Jersey performs injection it will
>>>>> not overwrite anything with a non-null value.
>>>>>
>>>>> Three possible ways to directly resolve this:
>>>>>
>>>>> 1) Don't use fields for injection;
>>>>>
>>>>> 2) The reload functionality you have implemented needs to
>>>>> destroy the singletons so that they are re-
>>>>> instantiated; or
>>>>>
>>>>> 3) Jersey is modified inject on non-null values.
>>>>>
>>>>> I am not comfortable supporting 3) or doing something more
>>>>> complicated around sharing state or detecting reloads and
>>>>> working around the issues. In this case i think 2) is required.
>>>>>
>>>>> Of course the better approach is to support richer notification
>>>>> events on changes to resource classes: removal, addition and
>>>>> class modification. Changes to provider classes may be more
>>>>> problematic...
>>>>>
>>>>> Paul.
>>>>>
>>>>> On Oct 16, 2008, at 6:20 PM, Guilhem wrote:
>>>>>
>>>>>> Hi,
>>>>>>
>>>>>> i put in place the mecanism described previously, everything
>>>>>> working well until i realized that i can restart my WS only one
>>>>>> time before getting a IllegalStateException:
>>>>>>
>>>>>> i just change some pieces of code to get this working :
>>>>>>
>>>>>> - my resource ReloadResource (ConfigurationService)
>>>>>> implementing ContainerNotifier is not in the same class that
>>>>>> the servletContainer.
>>>>>>
>>>>>> - i had to put a boolean flag to add the reload resource only
>>>>>> one time (i got an exception else) :
>>>>>>
>>>>>>
>>>>>> public class CstlServletContainer extends ServletContainer {
>>>>>>
>>>>>> public static boolean reload = false;
>>>>>> @Override
>>>>>> protected void configure(final ServletConfig sc, ResourceConfig
>>>>>> rc, WebApplication wa) {
>>>>>> super.configure(sc, rc, wa);
>>>>>> ConfigurationService configService = new
>>>>>> ConfigurationService();
>>>>>> if (!reload) {
>>>>>> rc.getSingletons().add(configService);
>>>>>> }
>>>>>> reload = true;
>>>>>>
>>>>>> rc
>>>>>> .getProperties
>>>>>> ().put(ResourceConfig.PROPERTY_CONTAINER_NOTIFIER,
>>>>>> configService);
>>>>>> }
>>>>>> }
>>>>>>
>>>>>>
>>>>>> so the first time the restart works well when i do this (you
>>>>>> can see that i don't want to restart my reloadResource in order
>>>>>> to send a xml result when the operation is ended):
>>>>>>
>>>>>> ...................
>>>>>>
>>>>>> for ( ContainerListener cl : cls) {
>>>>>> if (!cl.equals(this))
>>>>>> cl.onReload();
>>>>>> }
>>>>>>
>>>>>> .....................
>>>>>>
>>>>>>
>>>>>> and the second time i call this method i get an
>>>>>> illegalstateException when i trying to get a parameter in this
>>>>>> line :
>>>>>>
>>>>>> .....................
>>>>>>
>>>>>> @Context
>>>>>> protected UriInfo context;
>>>>>>
>>>>>> ......................
>>>>>>
>>>>>>
>>>>>> line 352: final MultivaluedMap parameters =
>>>>>> context.getQueryParameters();
>>>>>>
>>>>>>
>>>>>> ................
>>>>>>
>>>>>> exception:
>>>>>>
>>>>>> java.lang.IllegalStateException
>>>>>>
>>>>>> com
>>>>>> .sun
>>>>>> .jersey
>>>>>> .impl
>>>>>> .ThreadLocalHttpContext.getUriInfo(ThreadLocalHttpContext.java:
>>>>>> 67)
>>>>>> com.sun.jersey.impl.application.WebApplicationImpl
>>>>>> $2.invoke(WebApplicationImpl.java:184)
>>>>>> $Proxy7.getQueryParameters(Unknown Source)
>>>>>>
>>>>>> org.constellation.ws.rs.WebService.getParameter(WebService.java:
>>>>>> 352)
>>>>>>
>>>>>>
>>>>>>
>>>>>> Is someone know you know why i'm getting this exception?
>>>>>>
>>>>>> Guilhem Legal
>>>>>>
>>>>>> Paul Sandoz a écrit :
>>>>>>>
>>>>>>> On Oct 3, 2008, at 2:23 PM, Guilhem wrote:
>>>>>>>
>>>>>>>> hi,
>>>>>>>>
>>>>>>>> i follow the tutorial i 've found at http://blogs.sun.com/sandoz/entry/javarebel_and_jersey_take_2
>>>>>>>> this works well, but I don't see how to use this with tomcat
>>>>>>>> instead of a lightWebContainer.
>>>>>>>>
>>>>>>>
>>>>>>> You can extend the ServletContainer to register a container
>>>>>>> notifier. You need to add an instance of ContainerNotifier to
>>>>>>> to the resource config properties
>>>>>>> (ResourceConfig.PROPERTY_CONTAINER_NOTIFIER).
>>>>>>>
>>>>>>> Override the configure methods to do something like this:
>>>>>>>
>>>>>>> protected void configure(final ServletConfig sc,
>>>>>>> ResourceConfig rc, WebApplication wa) {
>>>>>>> super.configure(sc, rc, wa);
>>>>>>>
>>>>>>> ContainerNotifier cn = ....
>>>>>>>
>>>>>>> rc
>>>>>>> .getProperties
>>>>>>> ().put(esourceConfig.PROPERTY_CONTAINER_NOTIFIER, cn);
>>>>>>> }
>>>>>>>
>>>>>>>
>>>>>>>> more, the resource are reloaded only when the classes are
>>>>>>>> changed.
>>>>>>>>
>>>>>>>> For my application I want to make a JSF interface with a
>>>>>>>> button "reload" which restart all the resources (i had prefer
>>>>>>>> only selected resource but it seems to be unpossible).
>>>>>>>>
>>>>>>>
>>>>>>> Yes, currently it is not possible reload a single resource. Do
>>>>>>> you want to log an issue?
>>>>>>>
>>>>>>> It sounds like you want to have a another resource that
>>>>>>> triggers a reload.
>>>>>>>
>>>>>>> You could have a singleton resource instance you add to the
>>>>>>> singletons of ResourceConfig at configuration time that has
>>>>>>> the instance of the ContainerNotifier, then when a POST method
>>>>>>> is sent to that resource it can perform a reload.
>>>>>>>
>>>>>>> protected void configure(final ServletConfig sc,
>>>>>>> ResourceConfig rc, WebApplication wa) {
>>>>>>> super.configure(sc, rc, wa);
>>>>>>>
>>>>>>> ReloadResource rr = new ReloadResource(cn);
>>>>>>> rc.getSingletons().add(rr);
>>>>>>>
>>>>>>> rc
>>>>>>> .getProperties
>>>>>>> ().put(esourceConfig.PROPERTY_CONTAINER_NOTIFIER, rr);
>>>>>>> }
>>>>>>>
>>>>>>> ....
>>>>>>>
>>>>>>> @Path("reload")
>>>>>>> public class ReloadResource implements ContainerNotifier {
>>>>>>> List<ContainerListener> cls;
>>>>>>> ...
>>>>>>>
>>>>>>> @POST void reload() {
>>>>>>> for (ContainerListener cl : cls) cl.onReload();
>>>>>>> }
>>>>>>> }
>>>>>>>
>>>>>>>
>>>>>>> Alternatively you could create an injectable provider to
>>>>>>> inject the registered container notifier.
>>>>>>>
>>>>>>>
>>>>>>>> is there any tutorial which help me to do this?
>>>>>>>>
>>>>>>>
>>>>>>> Unfortunately not :-(
>>>>>>>
>>>>>>> Paul.
>>>>>>>
>>>>>>>
>>>>>>>> Guilhem Legal
>>>>>>>>
>>>>>>>>
>>>>>>>> Paul Sandoz a écrit :
>>>>>>>>>
>>>>>>>>> On Sep 24, 2008, at 4:42 PM, Guilhem wrote:
>>>>>>>>>
>>>>>>>>>> hi,
>>>>>>>>>>
>>>>>>>>>> I would know if its possible to dynamically restart a
>>>>>>>>>> resource without having to undeploy/deploy or restart the
>>>>>>>>>> container?
>>>>>>>>>>
>>>>>>>>>
>>>>>>>>> It is currently only possible to reload all resources. What
>>>>>>>>> happens is a new web application is created, configured and
>>>>>>>>> initiated.
>>>>>>>>>
>>>>>>>>> See the JavaDoc of the class:
>>>>>>>>>
>>>>>>>>> com.sun.jersey.spi.container.ContainerNotifier
>>>>>>>>>
>>>>>>>>> to register a notifier that may reload the container.
>>>>>>>>>
>>>>>>>>> I have used this in conjunction with JavaRebel. When
>>>>>>>>> JavaRebel detects changes to class files i have a hook in
>>>>>>>>> that to dynamically reload things using a ContainerNotifier
>>>>>>>>> without having to undeploy/deploy the web application.
>>>>>>>>>
>>>>>>>>> Does that work for you?
>>>>>>>>>
>>>>>>>>> Paul.
>>>>>>>>>
>>>>>>>>> ---------------------------------------------------------------------
>>>>>>>>> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
>>>>>>>>> For additional commands, e-mail: users-
>>>>>>>>> help_at_jersey.dev.java.net
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> ---------------------------------------------------------------------
>>>>>>>> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
>>>>>>>> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> ---------------------------------------------------------------------
>>>>>>> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
>>>>>>> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>
>>>>>>
>>>>>> ---------------------------------------------------------------------
>>>>>> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
>>>>>> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>>>>>>
>>>>>
>>>>>
>>>>> ---------------------------------------------------------------------
>>>>> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
>>>>> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>>>>>
>>>>>
>>>>>
>>>>
>>>>
>>>> ---------------------------------------------------------------------
>>>> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
>>>> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>>>>
>>>
>>>
>>> ---------------------------------------------------------------------
>>> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
>>> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>>>
>>>
>>>
>>
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
>> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>>
>>
>>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>