diff --git a/.gitignore b/.gitignore index f10592c7..68a4cf84 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ bin .DS_Store target .idea -*.iml \ No newline at end of file +*.iml +**/pom.xml.versionsBackup diff --git a/README.md b/README.md index 8e571e71..0f2ce44b 100644 --- a/README.md +++ b/README.md @@ -104,6 +104,9 @@ With Jersey 2.0 the library was splitted into several modules with a whole bunch ## Changelog Checkout the [github releases](https://github.com/hstaudacher/osgi-jax-rs-connector/releases). +- Upgrade to Jersey 2.25.1 +- Bugfix [Fixed following scenarios not returning HTTP Error 503 while Jersey s…](https://github.com/hstaudacher/osgi-jax-rs-connector/pull/147), publischer version changed to 5.3.2 + ## License The code is published under the terms of the [Eclipse Public License, version 1.0](http://www.eclipse.org/legal/epl-v10.html). diff --git a/build/com.eclipsesource.jaxrs.build/pom.xml b/build/com.eclipsesource.jaxrs.build/pom.xml index a0ed60ef..71ffba92 100644 --- a/build/com.eclipsesource.jaxrs.build/pom.xml +++ b/build/com.eclipsesource.jaxrs.build/pom.xml @@ -10,26 +10,26 @@ com.eclipsesource osgi-jaxrs-connector - 1.0.0-SNAPSHOT + 1.1.0-SNAPSHOT pom OSGi - JAX-RS Connector - 1.7 - 1.7 + 1.8 + 1.8 UTF-8 - 0.24.0 - 0.24.0 + 1.2.0 + 1.2.0 org.eclipse.tycho - 2.18 - 2.5.5 - 4.11 - 1.9.5 + 2.22.0 + 3.0.5 + 4.12 + 1.10.19 ${basedir}/../../build/com.eclipsesource.jaxrs.build/lib/jacocoagent.jar -Xms512m -Xmx512m -javaagent:${jacocoagent}=destfile=${basedir}/../../build/com.eclipsesource.jaxrs.build/target/jacoco.exec,append=true - ${java.home}/../bin/javadoc + ${java.home}/../bin/javadoc @@ -63,7 +63,7 @@ ../com.eclipsesource.jaxrs.repository - + connector-dependencies p2 @@ -142,7 +142,7 @@ - + org.eclipse.tycho tycho-p2-plugin @@ -157,20 +157,20 @@ - - - org.apache.maven.plugins - maven-javadoc-plugin - 2.10 - - - attach-javadocs - - jar - - - - + + + + + + + + + + + + + + diff --git a/build/com.eclipsesource.jaxrs.connector.feature/pom.xml b/build/com.eclipsesource.jaxrs.connector.feature/pom.xml index eec35f15..7c77e4ba 100644 --- a/build/com.eclipsesource.jaxrs.connector.feature/pom.xml +++ b/build/com.eclipsesource.jaxrs.connector.feature/pom.xml @@ -6,7 +6,7 @@ com.eclipsesource osgi-jaxrs-connector - 1.0.0-SNAPSHOT + 1.1.0-SNAPSHOT ../com.eclipsesource.jaxrs.build diff --git a/build/com.eclipsesource.jaxrs.jersey.all/pom.xml b/build/com.eclipsesource.jaxrs.jersey.all/pom.xml index 93eaea07..c7de211a 100644 --- a/build/com.eclipsesource.jaxrs.jersey.all/pom.xml +++ b/build/com.eclipsesource.jaxrs.jersey.all/pom.xml @@ -3,12 +3,12 @@ 4.0.0 com.eclipsesource.jaxrs jersey-all - 2.22.2 + 2.25.1 1.7 1.7 - 2.22.2 + 2.25.1 2.0 @@ -18,7 +18,7 @@ org.apache.maven.plugins maven-jar-plugin - 2.4 + 3.1.0 false @@ -35,7 +35,7 @@ org.apache.felix maven-bundle-plugin - 2.3.7 + 3.5.1 true @@ -80,7 +80,7 @@ org.apache.maven.plugins maven-shade-plugin - 2.4.1 + 3.1.1 shaded-DO-NOT-USE true diff --git a/build/com.eclipsesource.jaxrs.jersey.min/pom.xml b/build/com.eclipsesource.jaxrs.jersey.min/pom.xml index 23e0956e..ccd20e26 100644 --- a/build/com.eclipsesource.jaxrs.jersey.min/pom.xml +++ b/build/com.eclipsesource.jaxrs.jersey.min/pom.xml @@ -3,12 +3,12 @@ 4.0.0 com.eclipsesource.jaxrs jersey-min - 2.22.2 + 2.25.1 1.7 1.7 - 2.22.2 + 2.25.1 2.0 @@ -18,7 +18,7 @@ org.apache.maven.plugins maven-jar-plugin - 2.4 + 3.1.0 false @@ -35,7 +35,7 @@ org.apache.felix maven-bundle-plugin - 2.3.7 + 3.5.1 true @@ -80,7 +80,7 @@ org.apache.maven.plugins maven-shade-plugin - 2.4.1 + 3.1.1 shaded-DO-NOT-USE true diff --git a/build/com.eclipsesource.jaxrs.jersey.runtime.feature/pom.xml b/build/com.eclipsesource.jaxrs.jersey.runtime.feature/pom.xml index fb50b5f1..e5a6de1f 100644 --- a/build/com.eclipsesource.jaxrs.jersey.runtime.feature/pom.xml +++ b/build/com.eclipsesource.jaxrs.jersey.runtime.feature/pom.xml @@ -5,7 +5,7 @@ com.eclipsesource osgi-jaxrs-connector - 1.0.0-SNAPSHOT + 1.1.0-SNAPSHOT ../com.eclipsesource.jaxrs.build diff --git a/build/com.eclipsesource.jaxrs.provider.gson.feature/pom.xml b/build/com.eclipsesource.jaxrs.provider.gson.feature/pom.xml index e5c51855..958efb89 100644 --- a/build/com.eclipsesource.jaxrs.provider.gson.feature/pom.xml +++ b/build/com.eclipsesource.jaxrs.provider.gson.feature/pom.xml @@ -5,7 +5,7 @@ com.eclipsesource osgi-jaxrs-connector - 1.0.0-SNAPSHOT + 1.1.0-SNAPSHOT ../com.eclipsesource.jaxrs.build diff --git a/build/com.eclipsesource.jaxrs.provider.moxy.feature/pom.xml b/build/com.eclipsesource.jaxrs.provider.moxy.feature/pom.xml index 59c612ea..94ee809a 100644 --- a/build/com.eclipsesource.jaxrs.provider.moxy.feature/pom.xml +++ b/build/com.eclipsesource.jaxrs.provider.moxy.feature/pom.xml @@ -5,7 +5,7 @@ com.eclipsesource osgi-jaxrs-connector - 1.0.0-SNAPSHOT + 1.1.0-SNAPSHOT ../com.eclipsesource.jaxrs.build diff --git a/build/com.eclipsesource.jaxrs.provider.multipart.feature/pom.xml b/build/com.eclipsesource.jaxrs.provider.multipart.feature/pom.xml index fa9745fa..023bcdac 100644 --- a/build/com.eclipsesource.jaxrs.provider.multipart.feature/pom.xml +++ b/build/com.eclipsesource.jaxrs.provider.multipart.feature/pom.xml @@ -5,7 +5,7 @@ com.eclipsesource osgi-jaxrs-connector - 1.0.0-SNAPSHOT + 1.1.0-SNAPSHOT ../com.eclipsesource.jaxrs.build diff --git a/build/com.eclipsesource.jaxrs.provider.security.feature/pom.xml b/build/com.eclipsesource.jaxrs.provider.security.feature/pom.xml index 411c8ff5..e993715a 100644 --- a/build/com.eclipsesource.jaxrs.provider.security.feature/pom.xml +++ b/build/com.eclipsesource.jaxrs.provider.security.feature/pom.xml @@ -5,7 +5,7 @@ com.eclipsesource osgi-jaxrs-connector - 1.0.0-SNAPSHOT + 1.1.0-SNAPSHOT ../com.eclipsesource.jaxrs.build diff --git a/build/com.eclipsesource.jaxrs.provider.sse.feature/pom.xml b/build/com.eclipsesource.jaxrs.provider.sse.feature/pom.xml index d3181023..e26abe74 100644 --- a/build/com.eclipsesource.jaxrs.provider.sse.feature/pom.xml +++ b/build/com.eclipsesource.jaxrs.provider.sse.feature/pom.xml @@ -5,7 +5,7 @@ com.eclipsesource osgi-jaxrs-connector - 1.0.0-SNAPSHOT + 1.1.0-SNAPSHOT ../com.eclipsesource.jaxrs.build diff --git a/build/com.eclipsesource.jaxrs.provider.swagger.feature/pom.xml b/build/com.eclipsesource.jaxrs.provider.swagger.feature/pom.xml index 33dc9829..fd38c2db 100644 --- a/build/com.eclipsesource.jaxrs.provider.swagger.feature/pom.xml +++ b/build/com.eclipsesource.jaxrs.provider.swagger.feature/pom.xml @@ -5,7 +5,7 @@ com.eclipsesource osgi-jaxrs-connector - 1.0.0-SNAPSHOT + 1.1.0-SNAPSHOT ../com.eclipsesource.jaxrs.build diff --git a/build/com.eclipsesource.jaxrs.repository/pom.xml b/build/com.eclipsesource.jaxrs.repository/pom.xml index c393f668..b6ef0a74 100644 --- a/build/com.eclipsesource.jaxrs.repository/pom.xml +++ b/build/com.eclipsesource.jaxrs.repository/pom.xml @@ -5,7 +5,7 @@ com.eclipsesource osgi-jaxrs-connector - 1.0.0-SNAPSHOT + 1.1.0-SNAPSHOT ../com.eclipsesource.jaxrs.build diff --git a/bundles/com.eclipsesource.jaxrs.consumer/pom.xml b/bundles/com.eclipsesource.jaxrs.consumer/pom.xml index 48491d56..1bd2446a 100644 --- a/bundles/com.eclipsesource.jaxrs.consumer/pom.xml +++ b/bundles/com.eclipsesource.jaxrs.consumer/pom.xml @@ -6,7 +6,7 @@ com.eclipsesource osgi-jaxrs-connector - 1.0.0-SNAPSHOT + 1.1.0-SNAPSHOT ../../build/com.eclipsesource.jaxrs.build diff --git a/bundles/com.eclipsesource.jaxrs.provider.gson/pom.xml b/bundles/com.eclipsesource.jaxrs.provider.gson/pom.xml index 76ceb3aa..b01259e8 100644 --- a/bundles/com.eclipsesource.jaxrs.provider.gson/pom.xml +++ b/bundles/com.eclipsesource.jaxrs.provider.gson/pom.xml @@ -6,7 +6,7 @@ com.eclipsesource osgi-jaxrs-connector - 1.0.0-SNAPSHOT + 1.1.0-SNAPSHOT ../../build/com.eclipsesource.jaxrs.build diff --git a/bundles/com.eclipsesource.jaxrs.provider.moxy/pom.xml b/bundles/com.eclipsesource.jaxrs.provider.moxy/pom.xml index 8b5093d4..942672c4 100644 --- a/bundles/com.eclipsesource.jaxrs.provider.moxy/pom.xml +++ b/bundles/com.eclipsesource.jaxrs.provider.moxy/pom.xml @@ -6,7 +6,7 @@ com.eclipsesource osgi-jaxrs-connector - 1.0.0-SNAPSHOT + 1.1.0-SNAPSHOT ../../build/com.eclipsesource.jaxrs.build diff --git a/bundles/com.eclipsesource.jaxrs.provider.multipart/pom.xml b/bundles/com.eclipsesource.jaxrs.provider.multipart/pom.xml index a602a968..6e927589 100644 --- a/bundles/com.eclipsesource.jaxrs.provider.multipart/pom.xml +++ b/bundles/com.eclipsesource.jaxrs.provider.multipart/pom.xml @@ -6,7 +6,7 @@ com.eclipsesource osgi-jaxrs-connector - 1.0.0-SNAPSHOT + 1.1.0-SNAPSHOT ../../build/com.eclipsesource.jaxrs.build diff --git a/bundles/com.eclipsesource.jaxrs.provider.security/pom.xml b/bundles/com.eclipsesource.jaxrs.provider.security/pom.xml index fc34ef3f..bab316cc 100644 --- a/bundles/com.eclipsesource.jaxrs.provider.security/pom.xml +++ b/bundles/com.eclipsesource.jaxrs.provider.security/pom.xml @@ -6,7 +6,7 @@ com.eclipsesource osgi-jaxrs-connector - 1.0.0-SNAPSHOT + 1.1.0-SNAPSHOT ../../build/com.eclipsesource.jaxrs.build diff --git a/bundles/com.eclipsesource.jaxrs.provider.sse/pom.xml b/bundles/com.eclipsesource.jaxrs.provider.sse/pom.xml index 2e18f19f..b57fb956 100644 --- a/bundles/com.eclipsesource.jaxrs.provider.sse/pom.xml +++ b/bundles/com.eclipsesource.jaxrs.provider.sse/pom.xml @@ -6,7 +6,7 @@ com.eclipsesource osgi-jaxrs-connector - 1.0.0-SNAPSHOT + 1.1.0-SNAPSHOT ../../build/com.eclipsesource.jaxrs.build diff --git a/bundles/com.eclipsesource.jaxrs.provider.swagger/pom.xml b/bundles/com.eclipsesource.jaxrs.provider.swagger/pom.xml index 92bce029..bf56225e 100644 --- a/bundles/com.eclipsesource.jaxrs.provider.swagger/pom.xml +++ b/bundles/com.eclipsesource.jaxrs.provider.swagger/pom.xml @@ -6,7 +6,7 @@ com.eclipsesource osgi-jaxrs-connector - 1.0.0-SNAPSHOT + 1.1.0-SNAPSHOT ../../build/com.eclipsesource.jaxrs.build diff --git a/bundles/com.eclipsesource.jaxrs.provider.swagger/src/com/eclipsesource/jaxrs/provider/swagger/internal/SwaggerConfiguration.java b/bundles/com.eclipsesource.jaxrs.provider.swagger/src/com/eclipsesource/jaxrs/provider/swagger/internal/SwaggerConfiguration.java index 2f0e55ad..b46c2b5d 100644 --- a/bundles/com.eclipsesource.jaxrs.provider.swagger/src/com/eclipsesource/jaxrs/provider/swagger/internal/SwaggerConfiguration.java +++ b/bundles/com.eclipsesource.jaxrs.provider.swagger/src/com/eclipsesource/jaxrs/provider/swagger/internal/SwaggerConfiguration.java @@ -53,8 +53,9 @@ public class SwaggerConfiguration implements ManagedService { private Dictionary configuration; + @SuppressWarnings( "unchecked" ) @Override - public void updated( Dictionary configuration ) throws ConfigurationException { + public void updated( @SuppressWarnings( "rawtypes" ) Dictionary configuration ) throws ConfigurationException { this.configuration = configuration; } diff --git a/bundles/com.eclipsesource.jaxrs.publisher/META-INF/MANIFEST.MF b/bundles/com.eclipsesource.jaxrs.publisher/META-INF/MANIFEST.MF index f1d175a5..8aaeabc4 100644 --- a/bundles/com.eclipsesource.jaxrs.publisher/META-INF/MANIFEST.MF +++ b/bundles/com.eclipsesource.jaxrs.publisher/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Bundle-SymbolicName: com.eclipsesource.jaxrs.publisher -Bundle-Version: 5.3.1.qualifier +Bundle-Version: 5.3.2 Bundle-Vendor: %Bundle-Name Bundle-RequiredExecutionEnvironment: JavaSE-1.7 Bundle-Localization: plugin @@ -19,4 +19,4 @@ Import-Package: javax.servlet;version="[2.3.0,4.0.0)", org.osgi.service.cm;version="[1.2.0,2.0.0)", org.osgi.service.http;version="[1.2.0,2.0.0)", org.osgi.util.tracker;version="[1.4.0,2.0.0)" -Export-Package: com.eclipsesource.jaxrs.publisher;version="5.3.1" +Export-Package: com.eclipsesource.jaxrs.publisher;version="5.3.2" diff --git a/bundles/com.eclipsesource.jaxrs.publisher/pom.xml b/bundles/com.eclipsesource.jaxrs.publisher/pom.xml index ccf9b0c5..679ce1ea 100644 --- a/bundles/com.eclipsesource.jaxrs.publisher/pom.xml +++ b/bundles/com.eclipsesource.jaxrs.publisher/pom.xml @@ -6,13 +6,13 @@ com.eclipsesource osgi-jaxrs-connector - 1.0.0-SNAPSHOT + 1.1.0-SNAPSHOT ../../build/com.eclipsesource.jaxrs.build com.eclipsesource com.eclipsesource.jaxrs.publisher - 5.3.1-SNAPSHOT + 5.3.2 eclipse-plugin diff --git a/bundles/com.eclipsesource.jaxrs.publisher/src/com/eclipsesource/jaxrs/publisher/internal/JerseyContext.java b/bundles/com.eclipsesource.jaxrs.publisher/src/com/eclipsesource/jaxrs/publisher/internal/JerseyContext.java index f7c37bf7..f18bed29 100644 --- a/bundles/com.eclipsesource.jaxrs.publisher/src/com/eclipsesource/jaxrs/publisher/internal/JerseyContext.java +++ b/bundles/com.eclipsesource.jaxrs.publisher/src/com/eclipsesource/jaxrs/publisher/internal/JerseyContext.java @@ -56,6 +56,24 @@ public JerseyContext( HttpService httpService, this.servletConfiguration = servletConfiguration; this.resourcePublisher = new ResourcePublisher( servletContainerBridge, configuration.getPublishDelay() ); } + + // for testing purposes + JerseyContext( HttpService httpService, + Configuration configuration, + ServletConfiguration servletConfiguration, + ServiceContainer applicationConfigurations, + RootApplication rootApplication, + ServletContainerBridge servletContainerBridge) + { + this.httpService = httpService; + this.rootPath = configuration.getRoothPath(); + this.application = rootApplication; + this.applicationConfigurations = applicationConfigurations; + applyApplicationConfigurations( applicationConfigurations ); + this.servletContainerBridge = servletContainerBridge; + this.servletConfiguration = servletConfiguration; + this.resourcePublisher = new ResourcePublisher( servletContainerBridge, configuration.getPublishDelay() ); + } void applyApplicationConfigurations( ServiceContainer applicationConfigurations ) { getRootApplication().addProperties( new DefaultApplicationConfiguration().getProperties() ); @@ -181,7 +199,15 @@ private void resetContextClassloader( ClassLoader loader ) { } public void removeResource( Object resource ) { - getRootApplication().removeResource( resource ); + boolean isDirty = getRootApplication().removeResource( resource ); + // When removing resources that cause the application to be dirty, it makes sense to turn off + // request servicing until Jersey is reloaded as Jersey will hold on to the old OSGi instances + // of registered resources and we may see some exceptions if a request comes in that should be + // processed by a service that is in the process of deactivating (for example some unset methods + // were called). This way we'll send out a nice 503 until Jersey reloads which is much cleaner. + if( isDirty ) { + servletContainerBridge.setJerseyReady( false ); + } unregisterServletWhenNoResourcePresents(); resourcePublisher.schedulePublishing(); } @@ -221,4 +247,8 @@ void safeUnregister( String rootPath ) { RootApplication getRootApplication() { return application; } + + ServletContainerBridge getServletContainerBridge() { + return servletContainerBridge; + } } diff --git a/bundles/com.eclipsesource.jaxrs.publisher/src/com/eclipsesource/jaxrs/publisher/internal/RootApplication.java b/bundles/com.eclipsesource.jaxrs.publisher/src/com/eclipsesource/jaxrs/publisher/internal/RootApplication.java index 14573ea3..d395a9d8 100644 --- a/bundles/com.eclipsesource.jaxrs.publisher/src/com/eclipsesource/jaxrs/publisher/internal/RootApplication.java +++ b/bundles/com.eclipsesource.jaxrs.publisher/src/com/eclipsesource/jaxrs/publisher/internal/RootApplication.java @@ -36,15 +36,14 @@ public RootApplication() { void addResource( Object resource ) { synchronized( lock ) { - resources.add( resource ); - dirty = true; + dirty = resources.add( resource ); } } - void removeResource( Object resource ) { + boolean removeResource( Object resource ) { synchronized( lock ) { - resources.remove( resource ); - dirty = true; + dirty = resources.remove( resource ); + return dirty; } } diff --git a/bundles/com.eclipsesource.jaxrs.publisher/src/com/eclipsesource/jaxrs/publisher/internal/ServletContainerBridge.java b/bundles/com.eclipsesource.jaxrs.publisher/src/com/eclipsesource/jaxrs/publisher/internal/ServletContainerBridge.java index d3832189..5ca01466 100644 --- a/bundles/com.eclipsesource.jaxrs.publisher/src/com/eclipsesource/jaxrs/publisher/internal/ServletContainerBridge.java +++ b/bundles/com.eclipsesource.jaxrs.publisher/src/com/eclipsesource/jaxrs/publisher/internal/ServletContainerBridge.java @@ -45,17 +45,19 @@ public void run() { try { Thread.currentThread().setContextClassLoader( Request.class.getClassLoader() ); synchronized( this ) { - if( !isJerseyReady() ) { - // if jersey has not been initialized - use the init method + isJerseyReady = false; + // No WebComponent present, initialize Jersey so it's created + if( getServletContainer().getWebComponent() == null ) { getServletContainer().init( servletConfig ); - } else { - // otherwise reload - isJerseyReady = false; + } + // We already have a WebComponent we need to reload it + else { getServletContainer().reload( ResourceConfig.forApplication( application ) ); } isJerseyReady = true; } - } catch( ServletException e ) { + } catch( Throwable e ) { + e.printStackTrace(); throw new RuntimeException( e ); } finally { Thread.currentThread().setContextClassLoader( original ); @@ -83,8 +85,8 @@ public void service( ServletRequest req, ServletResponse res ) throws ServletExc public void destroy() { synchronized( this ) { if( isJerseyReady() ) { - getServletContainer().destroy(); this.isJerseyReady = false; + getServletContainer().destroy(); // create a new ServletContainer when the old one is destroyed. this.servletContainer = new ServletContainer( ResourceConfig.forApplication( application ) ); } @@ -95,6 +97,10 @@ public void destroy() { ServletContainer getServletContainer() { return servletContainer; } + + void setJerseyReady(boolean isJerseyReady) { + this.isJerseyReady = isJerseyReady; + } // for testing purposes boolean isJerseyReady() { diff --git a/tests/com.eclipsesource.jaxrs.consumer.test/pom.xml b/tests/com.eclipsesource.jaxrs.consumer.test/pom.xml index 5e85a8c9..499b7988 100644 --- a/tests/com.eclipsesource.jaxrs.consumer.test/pom.xml +++ b/tests/com.eclipsesource.jaxrs.consumer.test/pom.xml @@ -6,7 +6,7 @@ com.eclipsesource osgi-jaxrs-connector - 1.0.0-SNAPSHOT + 1.1.0-SNAPSHOT ../../build/com.eclipsesource.jaxrs.build diff --git a/tests/com.eclipsesource.jaxrs.provider.gson.test/pom.xml b/tests/com.eclipsesource.jaxrs.provider.gson.test/pom.xml index ccf7907b..a77747ea 100644 --- a/tests/com.eclipsesource.jaxrs.provider.gson.test/pom.xml +++ b/tests/com.eclipsesource.jaxrs.provider.gson.test/pom.xml @@ -5,7 +5,7 @@ com.eclipsesource osgi-jaxrs-connector - 1.0.0-SNAPSHOT + 1.1.0-SNAPSHOT ../../build/com.eclipsesource.jaxrs.build diff --git a/tests/com.eclipsesource.jaxrs.provider.multipart.test/pom.xml b/tests/com.eclipsesource.jaxrs.provider.multipart.test/pom.xml index e78c9c06..816d93fc 100644 --- a/tests/com.eclipsesource.jaxrs.provider.multipart.test/pom.xml +++ b/tests/com.eclipsesource.jaxrs.provider.multipart.test/pom.xml @@ -5,7 +5,7 @@ com.eclipsesource osgi-jaxrs-connector - 1.0.0-SNAPSHOT + 1.1.0-SNAPSHOT ../../build/com.eclipsesource.jaxrs.build diff --git a/tests/com.eclipsesource.jaxrs.provider.security.test/pom.xml b/tests/com.eclipsesource.jaxrs.provider.security.test/pom.xml index 7682b3e2..3a4bf4f4 100644 --- a/tests/com.eclipsesource.jaxrs.provider.security.test/pom.xml +++ b/tests/com.eclipsesource.jaxrs.provider.security.test/pom.xml @@ -5,7 +5,7 @@ com.eclipsesource osgi-jaxrs-connector - 1.0.0-SNAPSHOT + 1.1.0-SNAPSHOT ../../build/com.eclipsesource.jaxrs.build diff --git a/tests/com.eclipsesource.jaxrs.provider.sse.test/pom.xml b/tests/com.eclipsesource.jaxrs.provider.sse.test/pom.xml index a34633ed..4fbdb1cb 100644 --- a/tests/com.eclipsesource.jaxrs.provider.sse.test/pom.xml +++ b/tests/com.eclipsesource.jaxrs.provider.sse.test/pom.xml @@ -5,7 +5,7 @@ com.eclipsesource osgi-jaxrs-connector - 1.0.0-SNAPSHOT + 1.1.0-SNAPSHOT ../../build/com.eclipsesource.jaxrs.build diff --git a/tests/com.eclipsesource.jaxrs.provider.swagger.test/pom.xml b/tests/com.eclipsesource.jaxrs.provider.swagger.test/pom.xml index 2e2c5012..c1457993 100644 --- a/tests/com.eclipsesource.jaxrs.provider.swagger.test/pom.xml +++ b/tests/com.eclipsesource.jaxrs.provider.swagger.test/pom.xml @@ -5,7 +5,7 @@ com.eclipsesource osgi-jaxrs-connector - 1.0.0-SNAPSHOT + 1.1.0-SNAPSHOT ../../build/com.eclipsesource.jaxrs.build diff --git a/tests/com.eclipsesource.jaxrs.publisher.test/pom.xml b/tests/com.eclipsesource.jaxrs.publisher.test/pom.xml index 63460880..859da994 100644 --- a/tests/com.eclipsesource.jaxrs.publisher.test/pom.xml +++ b/tests/com.eclipsesource.jaxrs.publisher.test/pom.xml @@ -5,7 +5,7 @@ com.eclipsesource osgi-jaxrs-connector - 1.0.0-SNAPSHOT + 1.1.0-SNAPSHOT ../../build/com.eclipsesource.jaxrs.build diff --git a/tests/com.eclipsesource.jaxrs.publisher.test/src/com/eclipsesource/jaxrs/publisher/internal/JerseyContext_Test.java b/tests/com.eclipsesource.jaxrs.publisher.test/src/com/eclipsesource/jaxrs/publisher/internal/JerseyContext_Test.java index 184d899c..cc24dc7f 100644 --- a/tests/com.eclipsesource.jaxrs.publisher.test/src/com/eclipsesource/jaxrs/publisher/internal/JerseyContext_Test.java +++ b/tests/com.eclipsesource.jaxrs.publisher.test/src/com/eclipsesource/jaxrs/publisher/internal/JerseyContext_Test.java @@ -12,18 +12,22 @@ package com.eclipsesource.jaxrs.publisher.internal; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.timeout; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import java.io.IOException; import java.util.Dictionary; import java.util.HashMap; import java.util.HashSet; @@ -33,6 +37,9 @@ import javax.servlet.Servlet; import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletResponse; import org.glassfish.jersey.server.ServerProperties; import org.glassfish.jersey.servlet.ServletContainer; @@ -40,7 +47,9 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; +import org.mockito.invocation.InvocationOnMock; import org.mockito.runners.MockitoJUnitRunner; +import org.mockito.stubbing.Answer; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceReference; import org.osgi.service.http.HttpContext; @@ -61,6 +70,8 @@ public class JerseyContext_Test { private HttpService httpService; @Mock private RootApplication rootApplication; + @Mock + private ServletContainerBridge servletContainerBridge; @Before public void setUp() { @@ -69,9 +80,10 @@ public void setUp() { JerseyContext original = new JerseyContext( httpService, configuration, servletConfigurationService, - new ServiceContainer( mock( BundleContext.class ) ) ); + new ServiceContainer( mock( BundleContext.class ) ), + rootApplication, + servletContainerBridge); jerseyContext = spy( original ); - doReturn( rootApplication ).when( jerseyContext ).getRootApplication(); } @Test @@ -205,13 +217,15 @@ public void testAddResourceWithServletConfigurationServicePresent() throws Excep JerseyContext withConfiguration = spy( new JerseyContext( httpService, configuration, servletConfigurationService, - new ServiceContainer( mock( BundleContext.class ) ) ) ); + new ServiceContainer( mock( BundleContext.class ) ), + rootApplication, + servletContainerBridge ) ); Object resource = new Object(); - withConfiguration.addResource( resource ); - - verify( servletConfigurationService, times( 1 ) ).getHttpContext( any( HttpService.class ), anyString() ); - verify( servletConfigurationService, times( 1 ) ).getInitParams( any( HttpService.class ), anyString() ); + verify( servletConfigurationService, times( 1 ) ).getHttpContext( any( HttpService.class ), + anyString() ); + verify( servletConfigurationService, times( 1 ) ).getInitParams( any( HttpService.class ), + anyString() ); } @Test @@ -301,6 +315,124 @@ public void testUpdateServletConfigurationAfterServletRegistered() { verify( jerseyContext ).safeUnregister( "/test" ); verify( jerseyContext, times( 2 ) ).registerServletWhenNotAlreadyRegistered(); } + + @Test + public void testRemoveResourceServletBridgeStatus() + throws ServletException, NamespaceException, IOException, InterruptedException + { + Object monitor = new Object(); + JerseyContext jerseyContext = getJerseyContextWithSpyServletContainerBridgeRunMonitor( 1500L, monitor ); + ServletContainerBridge servletContainerBridge = jerseyContext.getServletContainerBridge(); + + // Add two resources, but not the third + Object resource1 = new Object(); + Object resource2 = new Object(); + Object resource3 = new Object(); + + jerseyContext.addResource( resource1 ); + jerseyContext.addResource( resource2 ); + + // Check if Jersey was loaded + waitForMonitor( monitor, 1500L ); + verify( servletContainerBridge, timeout( Integer.MAX_VALUE ).times( 1 ) ).run(); + + // Should not reload when removing a resource that is not present + jerseyContext.removeResource( resource3 ); + verify( servletContainerBridge, times( 1 ) ).run(); + + // Fire up a request - it should be serviced as jersey did not need to reload + verifyServiceWasExecuted(servletContainerBridge, 1); + + // Jersy is marked as not ready and should reload + jerseyContext.removeResource( resource2 ); + + + // Fire up a request again - should get a 503 as jersey will need to reload + verifyServiceWasNotExecuted(servletContainerBridge, 1); + waitForMonitor( monitor, 1500L ); + + // Wait for the run method to be executed + verify( servletContainerBridge, timeout( Integer.MAX_VALUE ).times( 2) ).run(); + + // Fire up a request - it should be serviced after reload + verifyServiceWasExecuted(servletContainerBridge, 2); + } + + /** + * Calls the service method of the given {@link ServletContainerBridge} and verifies that the + * underlying {@link ServletContainer#service(ServletRequest, ServletResponse)} has been executed + * the given numberOfTimes. + * + * @param servletContainerBridge + * @param numberOfTimes + * @throws ServletException + * @throws IOException + */ + private void verifyServiceWasExecuted( ServletContainerBridge servletContainerBridge, + int numberOfTimes ) throws ServletException, IOException + { + servletContainerBridge.service( mock( ServletRequest.class ), mock( ServletResponse.class ) ); + verify( servletContainerBridge.getServletContainer(), times( numberOfTimes ) ) + .service( any( ServletRequest.class ), any( ServletResponse.class ) ); + } + + /** + * Calls the service method of the given {@link ServletContainerBridge} and verifies that the + * {@link HttpServletResponse#sendError(int)} is executed with + * HttpServletResponse.SC_SERVICE_UNAVAILABLE. + * + * @param servletContainerBridge + * @param numberOfTimes + * @throws ServletException + * @throws IOException + */ + private void verifyServiceWasNotExecuted( ServletContainerBridge servletContainerBridge, + int numberOfTimes ) + throws ServletException, IOException + { + HttpServletResponse response = mock( HttpServletResponse.class ); + servletContainerBridge.service( mock( ServletRequest.class ), response ); + verify( response, times( numberOfTimes ) ) + .sendError( eq( HttpServletResponse.SC_SERVICE_UNAVAILABLE ), any( String.class ) ); + } + + private JerseyContext getJerseyContextWithSpyServletContainerBridgeRunMonitor(Long publishDelay, final Object monitor) { + Configuration configuration = createConfiguration( "/test", false, publishDelay ); + ServletConfiguration servletConfigurationService = mock( ServletConfiguration.class ); + + RootApplication rootApplication = spy( new RootApplication() ); + ServletContainerBridge servletContainerBridge = spy( new ServletContainerBridge( rootApplication ) ); + + ServletContainer spyContainer = mock( ServletContainer.class ); + when( servletContainerBridge.getServletContainer() ).thenReturn( spyContainer ); + + // Mock destroy so that it will block until the given monitor is notified! + doAnswer( new Answer() { + + @Override + public Object answer( InvocationOnMock invocation ) throws Throwable { + invocation.callRealMethod(); + synchronized( monitor ) { + monitor.notifyAll(); + } + return null; + } + } ).when( servletContainerBridge ).run(); + + + return spy( new JerseyContext( httpService, + configuration, + servletConfigurationService, + new ServiceContainer( mock( BundleContext.class ) ), + rootApplication, + servletContainerBridge ) ); + } + + private void waitForMonitor(Object monitor, Long timeout) throws InterruptedException { + synchronized(monitor) { + monitor.wait(timeout); + } + } private Configuration createConfiguration( String path, boolean wadlDisable, long publishDelay ) { Configuration configuration = mock( Configuration.class ); diff --git a/tests/com.eclipsesource.jaxrs.publisher.test/src/com/eclipsesource/jaxrs/publisher/internal/ServletContainerBridge_Test.java b/tests/com.eclipsesource.jaxrs.publisher.test/src/com/eclipsesource/jaxrs/publisher/internal/ServletContainerBridge_Test.java index aec6aa45..e7c08a40 100644 --- a/tests/com.eclipsesource.jaxrs.publisher.test/src/com/eclipsesource/jaxrs/publisher/internal/ServletContainerBridge_Test.java +++ b/tests/com.eclipsesource.jaxrs.publisher.test/src/com/eclipsesource/jaxrs/publisher/internal/ServletContainerBridge_Test.java @@ -14,12 +14,14 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -35,6 +37,7 @@ import org.glassfish.jersey.server.ResourceConfig; import org.glassfish.jersey.servlet.ServletContainer; +import org.glassfish.jersey.servlet.WebComponent; import org.junit.Before; import org.junit.Test; import org.mockito.Mockito; @@ -149,7 +152,7 @@ public void testRunReloadAfterInit() throws ServletException { ServletContainer container = mock( ServletContainer.class ); when( actualBridge.getServletContainer() ).thenReturn( container ); when( application.isDirty() ).thenReturn( true ); - when( actualBridge.isJerseyReady() ).thenReturn( true ); + when( container.getWebComponent() ).thenReturn( mock(WebComponent.class)); actualBridge.run(); @@ -181,4 +184,99 @@ public void testServiceWhenReady() throws ServletException, IOException { verify(container).service(request, response); } + + @Test + public void testServiceWhenNotReadyAndDestroyIsRunningSlow() + throws ServletException, IOException, InterruptedException + { + Object monitor = new Object(); + ServletContainerBridge actualBridge = getDestroyMockedServletBridge( monitor ); + + // Initialize Jersey + actualBridge.run(); + assertTrue( actualBridge.isJerseyReady() ); + + // Async destroy + runDestroyAsync( actualBridge ); + + // Make sure destroy thread has started! + waitForMonitor( monitor, 1000L ); + + // Try to fire up a request - should get a 503 while destroying! + verifyServiceWasNotExecuted(actualBridge); + + // finish up destroying + notifyAllMonitor( monitor ); + + // Fire up a request again should get a 503 after destroying! + verifyServiceWasNotExecuted(actualBridge); + } + + /** + * @param monitor + * @return A {@link ServletContainerBridge} with a mocked {@link ServletContainer#destroy()} + * method in such away that it blocks until the given monitor is notified + */ + private ServletContainerBridge getDestroyMockedServletBridge( final Object monitor ) { + final ServletContainerBridge actualBridge = spy( bridge ); + ServletContainer spyContainer = mock( ServletContainer.class ); + when( application.isDirty() ).thenReturn( true ); + when( actualBridge.getServletContainer() ).thenReturn( spyContainer ); + // Mock destroy so that it will block until the given monitor is notified! + doAnswer( new Answer() { + + @Override + public Object answer( InvocationOnMock invocation ) throws Throwable { + synchronized( monitor ) { + monitor.notifyAll(); + monitor.wait(); + } + return null; + } + } ).when( spyContainer ).destroy(); + return actualBridge; + } + + private void runDestroyAsync( final ServletContainerBridge bridge ) { + // Start destroying the bridge asynchronously + new Thread( new Runnable() { + + @Override + public void run() { + bridge.destroy(); + } + } ).start(); + } + + private void waitForMonitor( Object monitor, Long timeout ) throws InterruptedException { + synchronized( monitor ) { + monitor.wait( timeout ); + } + } + + private void notifyAllMonitor( Object monitor ) { + synchronized( monitor ) { + monitor.notifyAll(); + } + } + + /** + * Calls the service method of the given {@link ServletContainerBridge} and verifies that the + * {@link HttpServletResponse#sendError(int)} is executed with + * HttpServletResponse.SC_SERVICE_UNAVAILABLE. + * + * @param servletContainerBridge + * @param numberOfTimes + * @throws ServletException + * @throws IOException + */ + private void verifyServiceWasNotExecuted( ServletContainerBridge servletContainerBridge) + throws ServletException, IOException + { + HttpServletResponse response = mock( HttpServletResponse.class ); + servletContainerBridge.service( mock( ServletRequest.class ), response ); + verify( response, times( 1 ) ) + .sendError( eq( HttpServletResponse.SC_SERVICE_UNAVAILABLE ), any( String.class ) ); + } + }