I've got some test code with Jersey (2.7) and Jetty (9.2.5.v2014112) that I'm trying to port to CXF (3.0.x) and Jetty (same version). There's one part that I can't figure out, the equivalent of the rc.register(resource)
line below:
ServletContextHandler sch = new ServletContextHandler();
sch.setContextPath("/xxx");
resource = new TheResource();
ResourceConfig rc = new ResourceConfig();
rc.register(resource);
ServletContainer sc = new ServletContainer(rc);
ServletHolder holder = new ServletHolder(sc);
sch.addServlet(holder, "/*");
Server server = new Server(port);
server.setHandler(sch);
server.start();
server.join();
For the CXF/Jetty case I know I need to do something like:
CXFNonSpringJaxrsServlet context = new CXFNonSpringJaxrsServlet();
// EQUIVALENT OF:
// ResourceConfig rc = new ResourceConfig();
// rc.register(myresource)
// SOMETHING.setResourceConfig(rc)
ServletHolder holder = new ServletHolder(context);
ServletContextHandler handler = new ServletContextHandler("/restroot");
handler.addServlet(holder, "/*");
// Using ContextHandlerCollection cos my jetty needs to serve more
// than just this REST service
ContextHandlerCollection collection = new ContextHandlerCollection();
collection.addHandler(handler);
Server server = new Server(8080);
server.setHandler(collection);
server.start();
server.join();
Does anybody know how/if this is possible?
Just to clarify what I'm trying to do here: I'm trying to publish a JAX-RS service on an embedded Jetty instance, and I need full control over the lifecycle of the JAX-RS bean.
Maarten
Look at the source for CXFNonSpringJaxrsServlet, it is configured via init params from web.xml. However you're free to override that functionality of course
I've managed to get something working by:
- extending
CXFNonSpringJaxrsServlet
- Overriding
getResourceProviders()
- Providing my own implementation of
ResourceProvider
It all looks a bit complex, and I feel that there should be a standard API for this in CXF, but anyways, here's my solution:
public class TheApp {
private static final Logger LOG = LoggerFactory.getLogger(TheApp.class);
TheResource resource;
public static class BeanResourceProvider implements ResourceProvider {
private final Object theBean;
public BeanResourceProvider(Object theBean) {
this.theBean = theBean;
}
@Override
public Object getInstance(Message m) {
return theBean;
}
@Override
public void releaseInstance(Message m, Object o) {
}
@Override
public Class<?> getResourceClass() {
return theBean.getClass();
}
@Override
public boolean isSingleton() {
return true;
}
};
public TheApp(int port) throws Exception {
resource = new TheResource();
CXFNonSpringJaxrsServlet context = new CXFNonSpringJaxrsServlet() {
public void configureSingleton(Object o) {
LOG.info("configureSingleton() called");
}
public Map<Class<?>, ResourceProvider>
getResourceProviders(ServletConfig servletConfig,
Map<Class<?>, Map<String, List<String>>> resourceClasses) throws ServletException {
LOG.info("getResourceProviders called");
Map<Class<?>, ResourceProvider> map = new HashMap<Class<?>, ResourceProvider>();
for (Map.Entry<Class<?>, Map<String, List<String>>> entry : resourceClasses.entrySet()) {
Class<?> c = entry.getKey();
LOG.info("getting provider for {}", c.getName());
map.put(c, new BeanResourceProvider(resource));
}
return map;
}
};
ServletHolder holder = new ServletHolder(context);
holder.setInitParameter("jaxrs.serviceClasses", "com.test.cxfjetty.TheResource");
ServletContextHandler handler = new ServletContextHandler();
handler.addServlet(holder, "/*");
handler.setContextPath("/theroot");
Server server = new Server(port);
server.setHandler(handler);
server.start();
server.join();
}
public static void main(String[] args) throws Exception {
TheApp app = new TheApp(8122);
}
}
Fun exercise this was...
From CXF version 3.0.4 onwards, there are additional constructors on the CXFNonSpringJaxrsServlet
that make this a lot easier:
public SNAPSHOTApp(int port) throws Exception {
resource = new TheResource();
Set<Object> resourceSingletons = new HashSet<>();
resourceSingletons.add(resource);
CXFNonSpringJaxrsServlet context = new CXFNonSpringJaxrsServlet(resourceSingletons);
ServletHolder servlet = new ServletHolder(context);
ServletContextHandler handler = new ServletContextHandler();
handler.addServlet(servlet, "/*");
handler.setContextPath("/snapshot");
Server server = new Server(port);
server.setHandler(handler);
server.start();
server.join();
}
Big thanks to @Sergey Beryozkin for adding this based on my question on the CXF user mailing list.