users@jersey.java.net

Re: [Jersey] restart a resource

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

Should be fixed now. See this unit test for an example:

https://jersey.dev.java.net/source/browse/*checkout*/jersey/trunk/jersey/jersey-tests/src/test/java/com/sun/jersey/impl/container/grizzly/web/ReloadResourceTest.java

Paul.

On Oct 17, 2008, at 1:05 PM, Paul Sandoz wrote:

>
> 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
>>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>