This is an automated email from the ASF dual-hosted git repository. rombert pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-startupfilter.git
commit b11cf5d5b89aa9b704566cc09dea191c2a701b1e Author: Carsten Ziegeler <[email protected]> AuthorDate: Wed Aug 31 08:23:44 2016 +0000 Update to parent pom 28 and move to http whiteboard git-svn-id: https://svn.apache.org/repos/asf/sling/trunk@1758544 13f79535-47bb-0310-9956-ffa450edef68 --- pom.xml | 147 ++++++++++----------- .../apache/sling/startupfilter/StartupFilter.java | 17 ++- .../sling/startupfilter/StartupFilterDisabler.java | 3 + .../sling/startupfilter/StartupInfoProvider.java | 5 +- .../startupfilter/impl/StartupFilterImpl.java | 89 +++++++------ ...tartupFilterDisabler.java => package-info.java} | 8 +- .../OSGI-INF/metatype/metatype.properties | 2 +- .../startupfilter/impl/StartupFilterImplTest.java | 94 ++++++------- 8 files changed, 191 insertions(+), 174 deletions(-) diff --git a/pom.xml b/pom.xml index eecd0cf..edfd37d 100644 --- a/pom.xml +++ b/pom.xml @@ -17,85 +17,80 @@ <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> - <modelVersion>4.0.0</modelVersion> - <parent> - <groupId>org.apache.sling</groupId> - <artifactId>sling</artifactId> - <version>16</version> - <relativePath/> - </parent> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.apache.sling</groupId> + <artifactId>sling</artifactId> + <version>28</version> + <relativePath/> + </parent> - <artifactId>org.apache.sling.startupfilter</artifactId> - <version>0.0.1-SNAPSHOT</version> - <packaging>bundle</packaging> + <artifactId>org.apache.sling.startupfilter</artifactId> + <version>0.0.1-SNAPSHOT</version> + <packaging>bundle</packaging> - <name>Apache Sling Startup Filter</name> - <description> - Servlet Filter that blocks access to Sling - while starting up. - </description> + <name>Apache Sling Startup Filter</name> + <description> + Servlet Filter that blocks access to Sling while starting up. + </description> - <scm> - <connection>scm:svn:http://svn.apache.org/repos/asf/sling/trunk/contrib/extensions/startup-filter</connection> - <developerConnection>scm:svn:http://svn.apache.org/repos/asf/sling/trunk/contrib/extensions/startup-filter</developerConnection> - <url>http://svn.apache.org/repos/asf/sling/trunk/contrib/extensions/startup-filter</url> - </scm> + <scm> + <connection>scm:svn:http://svn.apache.org/repos/asf/sling/trunk/contrib/extensions/startup-filter</connection> + <developerConnection>scm:svn:http://svn.apache.org/repos/asf/sling/trunk/contrib/extensions/startup-filter</developerConnection> + <url>http://svn.apache.org/repos/asf/sling/trunk/contrib/extensions/startup-filter</url> + </scm> - <build> - <plugins> - <plugin> - <groupId>org.apache.felix</groupId> - <artifactId>maven-scr-plugin</artifactId> - </plugin> - <plugin> - <groupId>org.apache.felix</groupId> - <artifactId>maven-bundle-plugin</artifactId> - <extensions>true</extensions> - <configuration> - <instructions> - <Export-Package>org.apache.sling.startupfilter</Export-Package> - <Private-Package>org.apache.sling.startupfilter.impl.*</Private-Package> - </instructions> - </configuration> - </plugin> - </plugins> - </build> + <build> + <plugins> + <plugin> + <groupId>org.apache.felix</groupId> + <artifactId>maven-scr-plugin</artifactId> + </plugin> + <plugin> + <groupId>org.apache.felix</groupId> + <artifactId>maven-bundle-plugin</artifactId> + <extensions>true</extensions> + <configuration> + <instructions> + <Require-Capability> + osgi.implementation;filter:="(&(osgi.implementation=osgi.http)(version=1.0))" + </Require-Capability> + </instructions> + </configuration> + </plugin> + </plugins> + </build> - <dependencies> - <dependency> - <groupId>org.osgi</groupId> - <artifactId>org.osgi.core</artifactId> - </dependency> - <dependency> - <groupId>org.osgi</groupId> - <artifactId>org.osgi.compendium</artifactId> - </dependency> - <dependency> - <groupId>org.apache.felix</groupId> - <artifactId>org.apache.felix.scr.annotations</artifactId> - </dependency> - <dependency> - <groupId>javax.servlet</groupId> - <artifactId>servlet-api</artifactId> - </dependency> - <dependency> - <groupId>org.slf4j</groupId> - <artifactId>slf4j-api</artifactId> - </dependency> - <dependency> - <groupId>org.slf4j</groupId> - <artifactId>slf4j-simple</artifactId> - <scope>test</scope> - </dependency> - <dependency> - <groupId>junit</groupId> - <artifactId>junit</artifactId> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.jmock</groupId> - <artifactId>jmock-junit4</artifactId> - <scope>test</scope> - </dependency> - </dependencies> + <dependencies> + <dependency> + <groupId>org.osgi</groupId> + <artifactId>osgi.core</artifactId> + </dependency> + <dependency> + <groupId>org.osgi</groupId> + <artifactId>org.osgi.service.http.whiteboard</artifactId> + <version>1.0.0</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>javax.servlet</groupId> + <artifactId>javax.servlet-api</artifactId> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-simple</artifactId> + </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + </dependency> + <dependency> + <groupId>org.jmock</groupId> + <artifactId>jmock-junit4</artifactId> + </dependency> + </dependencies> </project> \ No newline at end of file diff --git a/src/main/java/org/apache/sling/startupfilter/StartupFilter.java b/src/main/java/org/apache/sling/startupfilter/StartupFilter.java index d84faec..93c5e3d 100644 --- a/src/main/java/org/apache/sling/startupfilter/StartupFilter.java +++ b/src/main/java/org/apache/sling/startupfilter/StartupFilter.java @@ -18,28 +18,31 @@ */ package org.apache.sling.startupfilter; -/** Servlet Filter that blocks access to the Sling main +import org.osgi.annotation.versioning.ProviderType; + +/** Servlet Filter that blocks access to the Sling main * servlet during startup, by returning an HTTP 503 * or other suitable status code. - * + * * A typical use case is to start this filter before * the Sling main servlet (by setting a lower start level * on its bundle than on the Sling engine bundle), and * deactivating once startup is finished. */ +@ProviderType public interface StartupFilter { - + /** Enable the status filter, which outputs a default status message * and a concatenation of all status messages returned * by {@link StartupInfoProvider} services. - * - * The filter is initially enabled. + * + * The filter is initially enabled. */ void enable(); - + /** Disable the status filter */ void disable(); - + /** True if currently enabled */ boolean isEnabled(); } \ No newline at end of file diff --git a/src/main/java/org/apache/sling/startupfilter/StartupFilterDisabler.java b/src/main/java/org/apache/sling/startupfilter/StartupFilterDisabler.java index 6cfd0f7..f44c90a 100644 --- a/src/main/java/org/apache/sling/startupfilter/StartupFilterDisabler.java +++ b/src/main/java/org/apache/sling/startupfilter/StartupFilterDisabler.java @@ -18,6 +18,9 @@ */ package org.apache.sling.startupfilter; +import org.osgi.annotation.versioning.ConsumerType; + +@ConsumerType public interface StartupFilterDisabler { /** Indicate why the StartupFilter should be disabled */ String getReason(); diff --git a/src/main/java/org/apache/sling/startupfilter/StartupInfoProvider.java b/src/main/java/org/apache/sling/startupfilter/StartupInfoProvider.java index e4baf85..c1279e1 100644 --- a/src/main/java/org/apache/sling/startupfilter/StartupInfoProvider.java +++ b/src/main/java/org/apache/sling/startupfilter/StartupInfoProvider.java @@ -18,9 +18,12 @@ */ package org.apache.sling.startupfilter; +import org.osgi.annotation.versioning.ConsumerType; + +@ConsumerType public interface StartupInfoProvider { /** Return startup progress information, which the startup - * filter adds to its HTTP 503 response. + * filter adds to its HTTP 503 response. */ String getProgressInfo(); } diff --git a/src/main/java/org/apache/sling/startupfilter/impl/StartupFilterImpl.java b/src/main/java/org/apache/sling/startupfilter/impl/StartupFilterImpl.java index 1bfba9b..6f850ff 100644 --- a/src/main/java/org/apache/sling/startupfilter/impl/StartupFilterImpl.java +++ b/src/main/java/org/apache/sling/startupfilter/impl/StartupFilterImpl.java @@ -22,6 +22,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Hashtable; import java.util.List; +import java.util.Map; import javax.servlet.Filter; import javax.servlet.FilterChain; @@ -47,7 +48,7 @@ import org.osgi.framework.BundleContext; import org.osgi.framework.Constants; import org.osgi.framework.ServiceReference; import org.osgi.framework.ServiceRegistration; -import org.osgi.service.component.ComponentContext; +import org.osgi.service.http.whiteboard.HttpWhiteboardConstants; import org.osgi.util.tracker.ServiceTracker; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -60,42 +61,43 @@ import org.slf4j.LoggerFactory; public class StartupFilterImpl implements StartupFilter, Filter { private final Logger log = LoggerFactory.getLogger(getClass()); - private ServiceRegistration filterServiceRegistration; + private ServiceRegistration<Filter> filterServiceRegistration; private BundleContext bundleContext; - private ServiceTracker providersTracker; + private ServiceTracker<StartupInfoProvider, StartupInfoProvider> providersTracker; private int providersTrackerCount = -1; - + private final List<StartupInfoProvider> providers = new ArrayList<StartupInfoProvider>(); - + @Property(boolValue=true) public static final String ACTIVE_BY_DEFAULT_PROP = "active.by.default"; private boolean defaultFilterActive; - + public static final String DEFAULT_MESSAGE = "Startup in progress"; - + @Property(value=DEFAULT_MESSAGE) public static final String DEFAULT_MESSAGE_PROP = "default.message"; private String defaultMessage; @Reference(cardinality=ReferenceCardinality.OPTIONAL_UNARY, policy=ReferencePolicy.DYNAMIC) - private StartupFilterDisabler startupFilterDisabler; + private volatile StartupFilterDisabler startupFilterDisabler; private static final String FRAMEWORK_PROP_MANAGER_ROOT = "felix.webconsole.manager.root"; static final String DEFAULT_MANAGER_ROOT = "/system/console"; private String managerRoot; - + /** @inheritDoc */ + @Override public void doFilter(ServletRequest request, ServletResponse sr, FilterChain chain) throws IOException, ServletException { - + // Disable if a StartupFilterDisabler is present if(startupFilterDisabler!= null) { - log.info("StartupFilterDisabler service present, disabling StartupFilter ({})", + log.info("StartupFilterDisabler service present, disabling StartupFilter ({})", startupFilterDisabler.getReason()); disable(); chain.doFilter(request, sr); return; } - + // Bypass for the managerRoot path if(request instanceof HttpServletRequest) { final String pathInfo = ((HttpServletRequest)request).getPathInfo(); @@ -105,9 +107,9 @@ public class StartupFilterImpl implements StartupFilter, Filter { return; } } - + updateProviders(); - + final StringBuilder sb = new StringBuilder(); sb.append(defaultMessage); for(StartupInfoProvider p : providers) { @@ -124,30 +126,32 @@ public class StartupFilterImpl implements StartupFilter, Filter { response.getWriter().write(sb.toString()); response.getWriter().flush(); } - + @Override public String toString() { - return getClass().getSimpleName() + ": " + (isEnabled() ? "enabled" : "disabled"); + return getClass().getSimpleName() + ": " + (isEnabled() ? "enabled" : "disabled"); } /** @inheritDoc */ + @Override public void destroy() { } /** @inheritDoc */ + @Override public void init(FilterConfig cfg) throws ServletException { } - + /** If needed, update our list of providers */ private void updateProviders() { if(providersTracker.getTrackingCount() != providersTrackerCount) { synchronized(this) { if(providersTracker.getTrackingCount() != providersTrackerCount) { providers.clear(); - final ServiceReference [] refs = providersTracker.getServiceReferences(); + final ServiceReference<StartupInfoProvider> [] refs = providersTracker.getServiceReferences(); if(refs != null) { - for(ServiceReference ref : refs) { - providers.add((StartupInfoProvider)bundleContext.getService(ref)); + for(ServiceReference<StartupInfoProvider> ref : refs) { + providers.add(bundleContext.getService(ref)); } } } @@ -158,16 +162,16 @@ public class StartupFilterImpl implements StartupFilter, Filter { } @Activate - protected void activate(ComponentContext ctx) throws InterruptedException { - bundleContext = ctx.getBundleContext(); - - providersTracker = new ServiceTracker(bundleContext, StartupInfoProvider.class.getName(), null); + protected void activate(final BundleContext ctx, final Map<String, Object> properties) throws InterruptedException { + bundleContext = ctx; + + providersTracker = new ServiceTracker(bundleContext, StartupInfoProvider.class, null); providersTracker.open(); - - Object prop = ctx.getProperties().get(DEFAULT_MESSAGE_PROP); + + Object prop = properties.get(DEFAULT_MESSAGE_PROP); defaultMessage = prop == null ? DEFAULT_MESSAGE : prop.toString(); - - prop = ctx.getProperties().get(ACTIVE_BY_DEFAULT_PROP); + + prop = properties.get(ACTIVE_BY_DEFAULT_PROP); defaultFilterActive = (prop instanceof Boolean ? (Boolean)prop : false); prop = bundleContext.getProperty(FRAMEWORK_PROP_MANAGER_ROOT); @@ -178,36 +182,41 @@ public class StartupFilterImpl implements StartupFilter, Filter { } log.info("Activated, enabled={}, managerRoot={}", isEnabled(), managerRoot); } - + @Deactivate - protected void deactivate(ComponentContext ctx) throws InterruptedException { + protected void deactivate() throws InterruptedException { disable(); providersTracker.close(); providersTracker = null; bundleContext = null; } - - + + + @Override public synchronized void enable() { - if(filterServiceRegistration == null) { + if (filterServiceRegistration == null) { final String pattern = "/"; final Hashtable<String, Object> params = new Hashtable<String, Object>(); params.put(Constants.SERVICE_RANKING, 0x9000); // run before RequestLoggerFilter (0x8000) - params.put("filter.scope", "REQUEST"); - params.put("pattern", pattern); - filterServiceRegistration = bundleContext.registerService(Filter.class.getName(), this, params); - log.info("Registered {} as a Filter service with pattern {}", this, pattern); + params.put("sling.filter.scope", "REQUEST"); + params.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_SELECT, + "(" + HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_NAME + "=*)"); + params.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_FILTER_PATTERN, pattern); + filterServiceRegistration = bundleContext.registerService(Filter.class, this, params); + log.info("Registered {} as a servlet filter service with pattern {}", this, pattern); } } - + + @Override public synchronized void disable() { - if(filterServiceRegistration != null) { + if (filterServiceRegistration != null) { filterServiceRegistration.unregister(); filterServiceRegistration = null; log.info("Filter service disabled"); } } - + + @Override public synchronized boolean isEnabled() { return filterServiceRegistration != null; } diff --git a/src/main/java/org/apache/sling/startupfilter/StartupFilterDisabler.java b/src/main/java/org/apache/sling/startupfilter/package-info.java similarity index 86% copy from src/main/java/org/apache/sling/startupfilter/StartupFilterDisabler.java copy to src/main/java/org/apache/sling/startupfilter/package-info.java index 6cfd0f7..2177642 100644 --- a/src/main/java/org/apache/sling/startupfilter/StartupFilterDisabler.java +++ b/src/main/java/org/apache/sling/startupfilter/package-info.java @@ -16,9 +16,9 @@ * specific language governing permissions and limitations * under the License. */ + +@Version("1.0.0") package org.apache.sling.startupfilter; -public interface StartupFilterDisabler { - /** Indicate why the StartupFilter should be disabled */ - String getReason(); -} +import org.osgi.annotation.versioning.Version; + diff --git a/src/main/resources/OSGI-INF/metatype/metatype.properties b/src/main/resources/OSGI-INF/metatype/metatype.properties index 2e04d0f..5f9bcb2 100644 --- a/src/main/resources/OSGI-INF/metatype/metatype.properties +++ b/src/main/resources/OSGI-INF/metatype/metatype.properties @@ -23,7 +23,7 @@ # descriptions as used in the metatype.xml descriptor generated by the # the Sling SCR plugin -org.apache.sling.startupfilter.impl.StartupFilterImpl.name=Sling Startup Filter +org.apache.sling.startupfilter.impl.StartupFilterImpl.name=Apache Sling Startup Filter org.apache.sling.startupfilter.impl.StartupFilterImpl.description=Rejects Sling requests \ with a 503 error code during startup. diff --git a/src/test/java/org/apache/sling/startupfilter/impl/StartupFilterImplTest.java b/src/test/java/org/apache/sling/startupfilter/impl/StartupFilterImplTest.java index fb80d66..46a2c5c 100644 --- a/src/test/java/org/apache/sling/startupfilter/impl/StartupFilterImplTest.java +++ b/src/test/java/org/apache/sling/startupfilter/impl/StartupFilterImplTest.java @@ -23,7 +23,8 @@ import static org.junit.Assert.assertEquals; import java.io.PrintWriter; import java.io.StringWriter; import java.util.Dictionary; -import java.util.Hashtable; +import java.util.HashMap; +import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; import javax.servlet.Filter; @@ -47,63 +48,71 @@ import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceListener; import org.osgi.framework.ServiceReference; import org.osgi.framework.ServiceRegistration; -import org.osgi.service.component.ComponentContext; /** Test the StartupFilterImpl */ public class StartupFilterImplTest { static private class TestProvider implements StartupInfoProvider, ServiceReference { private final String info; - + TestProvider(String s) { info = s; } - + + @Override public String getProgressInfo() { return info; } + @Override public Object getProperty(String key) { return null; } + @Override public String[] getPropertyKeys() { return null; } + @Override public Bundle getBundle() { return null; } + @Override public Bundle[] getUsingBundles() { return null; } + @Override public boolean isAssignableTo(Bundle bundle, String className) { return false; } + @Override public int compareTo(Object reference) { return 0; } } static private class TestFilterImpl extends StartupFilterImpl { - void setup(ComponentContext ctx) throws Exception { - activate(ctx); + void setup(BundleContext ctx, Map<String, Object> props) throws Exception { + activate(ctx, props); } }; - + static private class ChangeInteger implements Action { private final boolean increment; private final AtomicInteger value; - + ChangeInteger(AtomicInteger value, boolean increment) { this.increment = increment; this.value = value; } + @Override public void describeTo(Description d) { d.appendText(increment ? "increment" : "decrement"); d.appendText(" an integer"); } + @Override public Object invoke(Invocation invocation) throws Throwable { if(increment) { value.incrementAndGet(); @@ -116,7 +125,7 @@ public class StartupFilterImplTest { private TestFilterImpl filter; private Mockery mockery; - private HttpServletRequest request; + private HttpServletRequest request; private HttpServletResponse response; private FilterChain chain; private int lastReturnedStatus; @@ -130,23 +139,24 @@ public class StartupFilterImplTest { public void setup() { activeFilterCount = new AtomicInteger(); mockery = new Mockery(); - request = mockery.mock(HttpServletRequest.class); + request = mockery.mock(HttpServletRequest.class); response = mockery.mock(HttpServletResponse.class); chain = mockery.mock(FilterChain.class); serviceRegistration = mockery.mock(ServiceRegistration.class); filter = new TestFilterImpl(); requestPath = "/NO_PATH_YET"; } - + private void setProvider(final TestProvider provider) throws Exception { - final BundleContext bundleContext = mockery.mock(BundleContext.class); - final ComponentContext componentContext = mockery.mock(ComponentContext.class); - + final BundleContext bundleContext = mockery.mock(BundleContext.class); + final Action storeStatus = new Action() { + @Override public void describeTo(Description d) { d.appendText("Store HTTP response values"); } + @Override public Object invoke(Invocation invocation) throws Throwable { lastReturnedStatus = (Integer)invocation.getParameter(0); return null; @@ -154,76 +164,70 @@ public class StartupFilterImplTest { }; messageWriter = new StringWriter(); - final PrintWriter responseWriter = new PrintWriter(messageWriter); - - final Dictionary<String, Object> props = new Hashtable<String, Object>(); + final PrintWriter responseWriter = new PrintWriter(messageWriter); + + final Map<String, Object> props = new HashMap<String, Object>(); props.put(StartupFilterImpl.ACTIVE_BY_DEFAULT_PROP, Boolean.TRUE); - + final ServiceReference [] providerRefs = provider == null ? null : new ServiceReference[] { provider }; mockery.checking(new Expectations() {{ - allowing(componentContext).getBundleContext(); - will(returnValue(bundleContext)); - - allowing(componentContext).getProperties(); - will(returnValue(props)); - allowing(bundleContext).createFilter(with(any(String.class))); allowing(bundleContext).addServiceListener(with(any(ServiceListener.class))); allowing(bundleContext).addServiceListener(with(any(ServiceListener.class)), with(any(String.class))); - + allowing(bundleContext).getServiceReferences(StartupInfoProvider.class.getName(), null); will(returnValue(providerRefs)); allowing(bundleContext).getService(with(any(ServiceReference.class))); will(returnValue(provider)); - + allowing(bundleContext).getProperty(with("felix.webconsole.manager.root")); will(returnValue(CONSOLE_ROOT)); - allowing(bundleContext).registerService(with(Filter.class.getName()), with(any(Object.class)), with(any(Dictionary.class))); + allowing(bundleContext).registerService(with(equal(Filter.class)), with(any(Filter.class)), with(any(Dictionary.class))); will(new DoAllAction( new ChangeInteger(activeFilterCount, true), returnValue(serviceRegistration) )); - + allowing(response).setStatus((with(any(Integer.class)))); will(storeStatus); - + allowing(response).setContentType("text/plain"); - + allowing(response).getWriter(); will(returnValue(responseWriter)); allowing(response).setCharacterEncoding(with(any(String.class))); - + allowing(serviceRegistration).unregister(); will(new ChangeInteger(activeFilterCount, false)); - + allowing(request).getPathInfo(); will(returnValue(getRequestPath())); - + allowing(chain).doFilter(with(any(ServletRequest.class)), with(any(ServletResponse.class))); }}); - - filter.setup(componentContext); + + filter.setup(bundleContext, props); } - + private String getRequestPath() { return requestPath; } - + private void assertRequest(final int expectedStatus, final String expectedMessage) throws Exception { lastReturnedStatus = -1; - + filter.doFilter(request, response, chain); - + final String responseText = messageWriter.toString(); - + // status 0 means we expect the request to go through - assertEquals("Expecting status to match", + assertEquals("Expecting status to match", expectedStatus, lastReturnedStatus); - assertEquals("Expecting message to match", + assertEquals("Expecting message to match", expectedMessage, responseText); } - + @Test public void testInitialState() throws Exception { setProvider(null); @@ -256,10 +260,10 @@ public class StartupFilterImplTest { @Test public void testProviders() throws Exception { final TestProvider p = new TestProvider("TEST"); - + setProvider(p); assertEquals("Initially expecting one filter service", 1, activeFilterCount.get()); - + final String expectedMessage = StartupFilterImpl.DEFAULT_MESSAGE + "\nTEST"; assertRequest(503, expectedMessage); -- To stop receiving notification emails like this one, please contact "[email protected]" <[email protected]>.
