package org.springframework.roo.rest.publisher;
import javax.json.stream.JsonGenerator;
import javax.servlet.ServletException;
import org.glassfish.jersey.jsonp.JsonProcessingFeature;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.servlet.ServletContainer;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.service.http.HttpService;
import org.osgi.service.http.NamespaceException;
/**
* {@link JAXRSApplication} that tracks and registers JAX-RS resources.
*
* @author Enrique Ruiz at DISID Corporation S.L.
* @since 2.0
*/
public class JAXRSApplication {
private BundleContext bc;
private HttpService httpService;
private ResourceConfig resourceConfig;
private ResourceTracker resourceTracker = null;
private ServletContainer servletContainer;
private String contextPath;
/**
* Create REST Application and the default Jersey {@link ResourceConfig
* https://jersey.java.net/apidocs/2.6/jersey/org/glassfish/jersey/server/
* ResourceConfig.html}.
*
* @param bundleContext
*/
public JAXRSApplication(BundleContext bundleContext, String cpath) {
this.bc = bundleContext;
this.contextPath = cpath;
this.resourceConfig =
new ResourceConfig().register(JsonProcessingFeature.class).property(
JsonGenerator.PRETTY_PRINTING, true);
}
/**
* Set the HTTP service in which register the servlet container that will
* host the JAX-RS resources.
* <p/>
* After get an HTTP service, start the resource tracker to track
* for REST services.
*
* @param service
* @return
* @throws ServletException
* @throws NamespaceException
*/
public HttpService addHttpService(HttpService service) throws ServletException,
NamespaceException {
// 1st registered HttpService will win
if (this.httpService == null) {
this.servletContainer = new ServletContainer(this.resourceConfig);
this.httpService = service;
this.httpService.registerServlet(this.contextPath, servletContainer, null, null);
// After get an HTTP service, start the resource tracker to track
// for REST resources
this.resourceTracker = new ResourceTracker(this.bc, this);
this.resourceTracker.open();
return service;
} else {
return this.httpService;
}
}
/**
* Register the given JAX-RS service in the {@link JAXRS#servletContainer}.
*
* @param ref JAX-RS service
* @return registered service
*/
public Object addResource(ServiceReference<Object> ref) {
Object resource = this.bc.getService(ref);
// How to add Resources at runtime in Jersey
// http://stackoverflow.com/questions/27959594/can-we-add-resource-path-at-runtime-in-jersey#answer-28891762
ResourceConfig freshConfig = new ResourceConfig(this.resourceConfig);
freshConfig.registerInstances(resource);
this.resourceConfig = freshConfig;
this.servletContainer.reload(freshConfig);
return resource;
}
/**
* Stop the HTTP service
* .
* @param service
*/
public void removeHttpService(HttpService service) {
// stop if given service is the holded HttpService only
if (this.httpService == service) {
stop();
}
}
/**
* Stopping the bundle, so clean the resources and trackers.
*/
public void stop() {
if (this.resourceTracker != null) {
this.resourceTracker.close();
}
if (this.servletContainer != null) {
this.servletContainer.destroy();
}
if (this.httpService != null) {
this.httpService.unregister(this.contextPath);
}
this.servletContainer = null;
this.httpService = null;
}
}