Skip to content
This repository has been archived by the owner on Nov 18, 2022. It is now read-only.

Commit

Permalink
Merge branch 'issue60'
Browse files Browse the repository at this point in the history
  • Loading branch information
hstaudacher committed Dec 2, 2014
2 parents 24fd1e0 + 514d70e commit 3a32aef
Show file tree
Hide file tree
Showing 9 changed files with 236 additions and 57 deletions.
Expand Up @@ -7,12 +7,13 @@
import org.osgi.service.cm.ManagedService;


@SuppressWarnings( "rawtypes" )
public class Configuration implements ManagedService {

static final String CONFIG_SERVICE_PID = "com.eclipsesource.jaxrs.connector";
static final String ROOT_PROPERTY = "root";
static final String WADL_DISABLE_PROPERTY = "disableWadl";

static final String PUBLISH_INTERVAL = "publishInterval";

private final JAXRSConnector connector;

Expand All @@ -21,14 +22,13 @@ public Configuration( JAXRSConnector jaxRsConnector ) {
}

@Override
@SuppressWarnings( "rawtypes" )
public void updated( Dictionary properties ) throws ConfigurationException {
if( properties != null ) {
Object root = properties.get( ROOT_PROPERTY );
ensureRootIsPresent( root );
String rootPath = ( String )root;
ensureRootIsValid( rootPath );
connector.updateConfiguration( rootPath, isWadlDisabled( properties ) );
connector.updateConfiguration( rootPath, isWadlDisabled( properties ), getPublishInterval( properties ) );
}
}

Expand All @@ -44,12 +44,19 @@ private void ensureRootIsPresent( Object root ) throws ConfigurationException {
}
}

@SuppressWarnings( "rawtypes" )
private boolean isWadlDisabled( Dictionary properties ){
Object wadl = properties.get( WADL_DISABLE_PROPERTY );
if( wadl == null ){
return false;
}
return ( ( Boolean)wadl ).booleanValue();
}

private long getPublishInterval( Dictionary properties ) {
Object interval = properties.get( PUBLISH_INTERVAL );
if( interval == null ){
return 3000;
}
return Long.parseLong( ( String )interval );
}
}
Expand Up @@ -37,24 +37,27 @@ public class JAXRSConnector {
private final List<ServiceHolder> resourceCache;
private String rootPath;
private boolean isWadlDisabled;
private long publishInterval;

JAXRSConnector( BundleContext bundleContext ) {
this.bundleContext = bundleContext;
this.httpServices = new ServiceContainer( bundleContext );
this.resources = new ServiceContainer( bundleContext );
this.contextMap = new HashMap<HttpService, JerseyContext>();
this.resourceCache = new ArrayList<ServiceHolder>();
this.publishInterval = 2500;
}

void updateConfiguration( String rootPath, boolean isWadlDisabled ) {
void updateConfiguration( String rootPath, boolean isWadlDisabled, long publishInterval ) {
synchronized( lock ) {
doUpdateConfiguration( rootPath, isWadlDisabled );
doUpdateConfiguration( rootPath, isWadlDisabled, publishInterval );
}
}

private void doUpdateConfiguration( String rootPath, boolean isWadlDisabled ) {
private void doUpdateConfiguration( String rootPath, boolean isWadlDisabled, long publishInterval ) {
this.rootPath = rootPath;
this.isWadlDisabled = isWadlDisabled;
this.publishInterval = publishInterval;
ServiceHolder[] services = httpServices.getServices();
for( ServiceHolder serviceHolder : services ) {
doRemoveHttpService( ( HttpService )serviceHolder.getService() );
Expand All @@ -71,7 +74,7 @@ HttpService addHttpService( ServiceReference reference ) {
HttpService doAddHttpService( ServiceReference reference ) {
ServiceHolder serviceHolder = httpServices.add( reference );
HttpService service = ( HttpService )serviceHolder.getService();
contextMap.put( service, createJerseyContext( service, rootPath, isWadlDisabled ) );
contextMap.put( service, createJerseyContext( service, rootPath, isWadlDisabled, publishInterval ) );
clearCache();
return service;
}
Expand Down Expand Up @@ -181,8 +184,8 @@ private void removeResourcesFromContext( Object resource, HttpService httpServic
}

// For testing purpose
JerseyContext createJerseyContext( HttpService service, String rootPath, boolean disableWadl ) {
return new JerseyContext( service, rootPath, disableWadl );
JerseyContext createJerseyContext( HttpService service, String rootPath, boolean disableWadl, long publishInterval ) {
return new JerseyContext( service, rootPath, disableWadl, publishInterval );
}

}
Expand Up @@ -12,35 +12,55 @@
******************************************************************************/
package com.eclipsesource.jaxrs.publisher.internal;

import java.lang.Thread.UncaughtExceptionHandler;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;

import javax.servlet.ServletException;
import javax.ws.rs.core.Application;
import javax.ws.rs.core.Request;

import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.ServerProperties;
import org.glassfish.jersey.servlet.ServletContainer;
import org.osgi.service.http.HttpService;
import org.osgi.service.http.NamespaceException;


public class JerseyContext {

private final RootApplication application;
private ServletContainer servletContainer;
private final HttpService httpService;
private final String rootPath;
private boolean isApplicationRegistered;
private final ServletContainerBridge servletContainerBridge;

public JerseyContext( HttpService httpService, String rootPath, boolean isWadlDisabled ) {
public JerseyContext( HttpService httpService, String rootPath, boolean isWadlDisabled, long publishInterval ) {
this.httpService = httpService;
this.rootPath = rootPath == null ? "/services" : rootPath;
this.application = new RootApplication();
disableAutoDiscovery();
disableWadl( isWadlDisabled );
this.servletContainer = new ServletContainer( ResourceConfig.forApplication( application ) );
this.servletContainerBridge = new ServletContainerBridge( application );
scheduleContainerBridge( publishInterval );
}

private void scheduleContainerBridge( long publishInterval ) {
Executors.newSingleThreadScheduledExecutor( new ThreadFactory() {

@Override
public Thread newThread( Runnable runnable ) {
Thread thread = new Thread( runnable, "ServletContainerBridge" );
thread.setUncaughtExceptionHandler( new UncaughtExceptionHandler() {

@Override
public void uncaughtException( Thread t, Throwable e ) {
throw new IllegalStateException( e );
}
} );
return thread;
}
} ).scheduleAtFixedRate( servletContainerBridge, 1000, publishInterval, TimeUnit.MILLISECONDS );
}

private void disableAutoDiscovery() {
Expand All @@ -64,15 +84,6 @@ private void disableWadl( boolean disableWadl ) {
public void addResource( Object resource ) {
getRootApplication().addResource( resource );
registerServletWhenNotAlreadyRegistered();
if( isApplicationRegistered ) {
ClassLoader original = getContextClassloader();
try {
Thread.currentThread().setContextClassLoader( Request.class.getClassLoader() );
getServletContainer().reload( ResourceConfig.forApplication( application ) );
} finally {
resetContextClassloader( original );
}
}
}

void registerServletWhenNotAlreadyRegistered() {
Expand Down Expand Up @@ -109,7 +120,7 @@ private void registerServlet() throws ServletException, NamespaceException {
try {
Thread.currentThread().setContextClassLoader( Application.class.getClassLoader() );
httpService.registerServlet( rootPath,
getServletContainer(),
servletContainerBridge.getServletContainer(),
null,
null );
} finally {
Expand All @@ -123,22 +134,19 @@ private void resetContextClassloader( ClassLoader loader ) {

public void removeResource( Object resource ) {
getRootApplication().removeResource( resource );
if( isApplicationRegistered ) {
getServletContainer().reload( ResourceConfig.forApplication( application ) );
}
unregisterServletWhenNoresourcePresents();
}

private void unregisterServletWhenNoresourcePresents() {
if( !getRootApplication().hasResources() ) {
httpService.unregister( rootPath );
servletContainer = new ServletContainer( ResourceConfig.forApplication( application ) );
servletContainerBridge.reset();
isApplicationRegistered = false;
}
}

public List<Object> eliminate() {
getServletContainer().destroy();
servletContainerBridge.destroy();
try {
httpService.unregister( rootPath );
} catch( IllegalArgumentException iae ) {
Expand All @@ -147,11 +155,6 @@ public List<Object> eliminate() {
return new ArrayList<Object>( getRootApplication().getSingletons() );
}

// For testing purpose
ServletContainer getServletContainer() {
return servletContainer;
}

// For testing purpose
RootApplication getRootApplication() {
return application;
Expand Down
Expand Up @@ -25,18 +25,26 @@ public class RootApplication extends Application {

private final Map<String, Object> properties;
private final List<Object> resources;
private final Object lock = new Object();
private boolean dirty;

public RootApplication() {
resources = new LinkedList<Object>();
properties = new HashMap<String, Object>();
}

void addResource( Object resource ) {
resources.add( resource );
synchronized( lock ) {
resources.add( resource );
dirty = true;
}
}

void removeResource( Object resource ) {
resources.remove( resource );
synchronized( lock ) {
resources.remove( resource );
dirty = false;
}
}

boolean hasResources() {
Expand All @@ -58,5 +66,17 @@ public Map<String, Object> getProperties() {
public void addProperty( String key, Object value ) {
properties.put( key, value );
}

public boolean isDirty() {
synchronized( lock ) {
return dirty;
}
}

public void setDirty( boolean isDirty ) {
synchronized( lock ) {
dirty = isDirty;
}
}

}
@@ -0,0 +1,44 @@
package com.eclipsesource.jaxrs.publisher.internal;

import javax.ws.rs.core.Request;

import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.servlet.ServletContainer;


public class ServletContainerBridge implements Runnable {

private final RootApplication application;
private ServletContainer servletContainer;

public ServletContainerBridge( RootApplication application ) {
this.servletContainer = new ServletContainer( ResourceConfig.forApplication( application ) );
this.application = application;
}

@Override
public void run() {
if( application.isDirty() ) {
ClassLoader original = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader( Request.class.getClassLoader() );
getServletContainer().reload( ResourceConfig.forApplication( application ) );
} finally {
Thread.currentThread().setContextClassLoader( original );
application.setDirty( false );
}
}
}

public ServletContainer getServletContainer() {
return servletContainer;
}

public void destroy() {
servletContainer.destroy();
}

public void reset() {
this.servletContainer = new ServletContainer( ResourceConfig.forApplication( application ) );
}
}
@@ -1,10 +1,11 @@
package com.eclipsesource.jaxrs.publisher.internal;

import static org.mockito.Matchers.anyLong;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.eq;

import java.util.Dictionary;
import java.util.Hashtable;
Expand All @@ -29,28 +30,35 @@ public void setUp() {
public void testUpdateWithNull() throws Exception {
config.updated( null );

verify( connector, never() ).updateConfiguration( anyString(), eq(false));
verify( connector, never() ).updateConfiguration( anyString(), eq(false), anyLong() );
}

@Test
public void testUpdateWithPath() throws Exception {
config.updated( createProperties( "/test" ) );

verify( connector ).updateConfiguration( "/test" , false);
verify( connector ).updateConfiguration( "/test" , false, 4 );
}

@Test
public void testUpdateWithPath2() throws Exception {
config.updated( createProperties( "/test2" ) );

verify( connector ).updateConfiguration( "/test2" , false );
verify( connector ).updateConfiguration( "/test2" , false, 4 );
}

@Test
public void testUpdateWithDisabledWadl() throws Exception {
config.updated( createProperties( "/test", true ) );

verify( connector ).updateConfiguration( "/test" , true );
verify( connector ).updateConfiguration( "/test" , true, 4 );
}

@Test
public void testUpdateWithPublishInterval() throws Exception {
config.updated( createProperties( "/test", true ) );

verify( connector ).updateConfiguration( "/test" , true, 4 );
}

@Test( expected = ConfigurationException.class )
Expand All @@ -71,6 +79,7 @@ public void testUpdateWithEmptyProperties() throws Exception {
Hashtable<String, Object> properties = new Hashtable<String, Object>();
properties.put( Configuration.ROOT_PROPERTY, path );
properties.put( Configuration.WADL_DISABLE_PROPERTY, disableWadl );
properties.put( Configuration.PUBLISH_INTERVAL, "4" );
return properties;
}

Expand Down

0 comments on commit 3a32aef

Please sign in to comment.