Reputation: 1279
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?
Upvotes: 23
Views: 2316
Reputation: 5045
Jersey is not technically a servlet container, it is a REST/JaxB framework running on a servlet container.
Most embeddable servlet containers, Tomcat, Jetty, Grizzly allows you to redeploy application and servlets at runtime. But redeployment is typically not a feature you use when you embed the container in code.
Hot redeployment is most useful in production, allowing you to continuously deploy new versions. On Tomcat you can have new and old version of an application deployed on the same server, and tomcat ensures that new sessions are started on the newest version on the application, but older versions will continue to use the application version they were started with. When an application is no loger used it is automatically undeployed.
Upvotes: 0
Reputation: 1224
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.
Upvotes: 1