/*******************************************************************************
* Copyright (c) 2014,2015 EclipseSource and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Holger Staudacher - initial API and implementation
* Ivan Iliev - Performance Optimizations
******************************************************************************/
package com.eclipsesource.jaxrs.publisher.internal;
import java.io.IOException;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.core.Request;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.servlet.ServletContainer;
public class ServletContainerBridge extends HttpServlet implements Runnable {
private final RootApplication application;
private ServletContainer servletContainer;
private ServletConfig servletConfig;
private volatile boolean isJerseyReady;
public ServletContainerBridge( RootApplication application ) {
this.servletContainer = new ServletContainer( ResourceConfig.forApplication( application ) );
this.application = application;
this.isJerseyReady = false;
}
@Override
public void run() {
if( application.isDirty() ) {
ClassLoader original = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader( Request.class.getClassLoader() );
synchronized( this ) {
if( !isJerseyReady() ) {
// if jersey has not been initialized - use the init method
getServletContainer().init( servletConfig );
} else {
// otherwise reload
isJerseyReady = false;
getServletContainer().reload( ResourceConfig.forApplication( application ) );
}
isJerseyReady = true;
}
} catch( ServletException e ) {
throw new RuntimeException( e );
} finally {
Thread.currentThread().setContextClassLoader( original );
}
}
}
@Override
public void init( ServletConfig config ) throws ServletException {
application.setDirty( true );
this.servletConfig = config;
}
@Override
public void service( ServletRequest req, ServletResponse res ) throws ServletException, IOException {
// if jersey has not yet been initialized return service unavailable
if( isJerseyReady() ) {
getServletContainer().service( req, res );
} else {
( ( HttpServletResponse )res ).sendError( HttpServletResponse.SC_SERVICE_UNAVAILABLE, "Jersey is not ready yet!" );
}
}
@Override
public void destroy() {
synchronized( this ) {
if( isJerseyReady() ) {
getServletContainer().destroy();
this.isJerseyReady = false;
// create a new ServletContainer when the old one is destroyed.
this.servletContainer = new ServletContainer( ResourceConfig.forApplication( application ) );
}
}
}
// for testing purposes
ServletContainer getServletContainer() {
return servletContainer;
}
// for testing purposes
boolean isJerseyReady() {
return isJerseyReady;
}
}