I need to hot-deploy and -undeploy resources in a Jersey ServletContainer.
There seems to be no way to 'unregister' resources on a ResourceConfig, so the route I'm following is to replace all resources with a new set.
Although the documentation says registerResources on ResourceConfig replaces all resources, browsing through the source code seems to contradict this.
The solution I found was to reload the ServletContainer with an entirely new ResourceConfig.
Set<Class<?>> classes = ... ResourceConfig config = new ResourceConfig(classes); container.reload(config);
This works fine until I deploy a resource that results in a ModelValidationException. After that I cannot get the ServletContainer back in a proper state.
If I take a look at the source code:
public void reload(final ResourceConfig configuration) { try { containerListener.onShutdown(this); webComponent = new WebComponent(webComponent.webConfig, configuration); containerListener = webComponent.appHandler; containerListener.onReload(this); containerListener.onStartup(this); } catch (final ServletException ex) { LOGGER.log(Level.SEVERE, "Reload failed", ex); } }
The ModelValidationException is thrown from the WebComponent constructor. After that any call to reload results in an exception from the onShutdown method, caused by checkState in the preDestroy method of the ServiceLocatorImpl.
I can avoid the exception by ignoring validation errors
ResourceConfig config = new ResourceConfig(classes); config.property(ServerProperties.RESOURCE_VALIDATION_IGNORE_ERRORS, Boolean.TRUE); container.reload(config);
There is no way now however to find out if there were any errors but to explore the logging, which is just as bad, really.
Per heenenee's comment I tried subclassing ServletContainer, but something like this gives problems because the ResourceConfig cannot be put in two WebComponents.
I tried creating the WebComponent before shutting down, to get an early exit, but this fails the actual reload if there is no error in the resources (because the resourceconfig cannot be modified after the webcomponent has been created)
@Override public void reload(ResourceConfig configuration) { try { new WebComponent(new WebServletConfig(this), configuration); } catch (ServletException e) { LOGGER.log(Level.SEVERE, "Reload failed", e); List<ResourceModelIssue> resources = Collections.emptyList(); throw new ModelValidationException(e.getMessage(), resources); } super.reload(configuration); }
Is there another way to hot-undeploy resources? Is there a way to reset the ServletContainer after a failed reload?
I don't think this can be achieved without the use of a servlet container that supports hot deployments. In my experience, a good way of doing this is using a container that supports OSGi. You can take a look at Eclipse Virgo or Apache Karaf.
For example, in an OSGi environment, you can create modules (called bundles) that can be dropped to a scanned folder to enable features at runtime, or removed from a folder, to disable some features. This is similar to how plugins work in Eclipse IDE, where a new plugin install/uninstall doesn't necessarily require a restart.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With