Return-Path: X-Original-To: apmail-felix-commits-archive@www.apache.org Delivered-To: apmail-felix-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 9E0CE763C for ; Mon, 5 Dec 2011 20:29:41 +0000 (UTC) Received: (qmail 62870 invoked by uid 500); 5 Dec 2011 20:29:41 -0000 Delivered-To: apmail-felix-commits-archive@felix.apache.org Received: (qmail 62843 invoked by uid 500); 5 Dec 2011 20:29:41 -0000 Mailing-List: contact commits-help@felix.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@felix.apache.org Delivered-To: mailing list commits@felix.apache.org Received: (qmail 62826 invoked by uid 99); 5 Dec 2011 20:29:41 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 05 Dec 2011 20:29:41 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 05 Dec 2011 20:29:33 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id A79BB238899C for ; Mon, 5 Dec 2011 20:29:10 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1210612 [1/2] - in /felix/trunk/http/whiteboard/src: main/java/org/apache/felix/http/whiteboard/ main/java/org/apache/felix/http/whiteboard/internal/ main/java/org/apache/felix/http/whiteboard/internal/manager/ main/java/org/apache/felix/h... Date: Mon, 05 Dec 2011 20:29:09 -0000 To: commits@felix.apache.org From: fmeschbe@apache.org X-Mailer: svnmailer-1.0.8-patched Message-Id: <20111205202910.A79BB238899C@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: fmeschbe Date: Mon Dec 5 20:29:08 2011 New Revision: 1210612 URL: http://svn.apache.org/viewvc?rev=1210612&view=rev Log: FELIX-3226 Improve HttpContext whiteboard support - export constants - allow for sharing HttpContext services across bundles (must be declared) - delay Servlet/Filter registration as long as HttpContext service referred to is missing - add unit tests FELIX-2882 service instance as key - replace the service instances by the service reference as the key of the mappings Added: felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/HttpWhiteboardConstants.java felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/internal/manager/ExtenderManager.java - copied, changed from r1203903, felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/internal/manager/ExtenderManagerImpl.java felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/package-info.java felix/trunk/http/whiteboard/src/test/ felix/trunk/http/whiteboard/src/test/java/ felix/trunk/http/whiteboard/src/test/java/org/ felix/trunk/http/whiteboard/src/test/java/org/apache/ felix/trunk/http/whiteboard/src/test/java/org/apache/felix/ felix/trunk/http/whiteboard/src/test/java/org/apache/felix/http/ felix/trunk/http/whiteboard/src/test/java/org/apache/felix/http/whiteboard/ felix/trunk/http/whiteboard/src/test/java/org/apache/felix/http/whiteboard/internal/ felix/trunk/http/whiteboard/src/test/java/org/apache/felix/http/whiteboard/internal/manager/ felix/trunk/http/whiteboard/src/test/java/org/apache/felix/http/whiteboard/internal/manager/ExtenderManagerTest.java felix/trunk/http/whiteboard/src/test/java/org/apache/felix/http/whiteboard/internal/manager/FilterMappingTest.java felix/trunk/http/whiteboard/src/test/java/org/apache/felix/http/whiteboard/internal/manager/HttpContextManagerTest.java felix/trunk/http/whiteboard/src/test/java/org/apache/felix/http/whiteboard/internal/manager/ServletMappingTest.java Removed: felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/internal/manager/ExtenderManagerImpl.java Modified: felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/internal/WhiteboardActivator.java felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/internal/manager/AbstractMapping.java felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/internal/manager/FilterMapping.java felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/internal/manager/HttpContextManager.java felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/internal/manager/HttpWhiteboardWebConsolePlugin.java felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/internal/manager/ServletMapping.java felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/internal/tracker/AbstractTracker.java felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/internal/tracker/FilterTracker.java felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/internal/tracker/HttpContextTracker.java felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/internal/tracker/HttpServiceTracker.java felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/internal/tracker/ServletTracker.java Added: felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/HttpWhiteboardConstants.java URL: http://svn.apache.org/viewvc/felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/HttpWhiteboardConstants.java?rev=1210612&view=auto ============================================================================== --- felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/HttpWhiteboardConstants.java (added) +++ felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/HttpWhiteboardConstants.java Mon Dec 5 20:29:08 2011 @@ -0,0 +1,128 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.felix.http.whiteboard; + +/** + * The HttpWhiteboardConstants defines constants for values + * used by the Http Whiteboard registration support. + * + * @since Http Whiteboard Bundle 2.3.0 + */ +public class HttpWhiteboardConstants +{ + + /** + * The service registration property indicating the name of a + * HttpContext service. + *

+ * If the property is set to a non-empty string for an + * HttpContext service it indicates the name by which it may be + * referred to by Servlet and Filter services. + * This is also a required registration property for + * HttpService services to be accepted by the Http Whiteboard + * registration. + *

+ * If the property is set for a Servlet or Filter + * services it indicates the name of a registered HttpContext + * which is to be used for the registration with the Http Service. If the + * property is not set for a Servlet or Filter + * services or its value is the empty string, a default HttpContext is used + * which does no security handling and has no MIME type support and which + * returns resources from the servlet's or the filter's bundle. + *

+ * The value of this service registration property is a single string. + */ + public static final String CONTEXT_ID = "contextId"; + + /** + * The service registration property indicating whether a + * HttpContext service registered with the {@link #CONTEXT_ID} + * service registration + * property is shared across bundles or not. By default + * HttpContext services are only available to + * Servlet and Filter services registered by the + * same bundle. + *

+ * If this property is set to true for HttpContext + * service, it may be referred to by Servlet or + * Filter services from different bundles. + *

+ * Recommendation: Shared HttpContext services should + * either not implement the getResource at all or be registered + * as service factories to ensure no access to foreign bundle resources is + * not allowed through this backdoor. + *

+ * The value of this service registration is a single boolean or string. + * Only if the boolean value is true (either by + * Boolean.booleanValue() or by + * Boolean.valueOf(String)) will the HttpContext + * be shared. + */ + public static final String CONTEXT_SHARED = "context.shared"; + + /** + * The service registration property indicating the registration alias + * for a Servlet service. This value is used as the + * alias parameter for the HttpService.registerServlet call. + *

+ * A Servlet service registered with this service property may + * also provide a {@link #CONTEXT_ID} property which referrs to a + * HttpContext service. If such a service is not registered + * (yet), the servlet will not be registered with the Http Service. Once the + * HttpContext service becomes available, the servlet is + * registered. + *

+ * The value of this service registration property is a single string + * starting with a slash. + */ + public static final String ALIAS = "alias"; + + /** + * The service registration property indicating the URL patter + * for a Filter service. This value is used as the + * pattern parameter for the ExtHttpService.registerFilter + * call. + *

+ * A Filter service registered with this service property may + * also provide a {@link #CONTEXT_ID} property which referrs to a + * HttpContext service. If such a service is not registered + * (yet), the filter will not be registered with the Http Service. Once the + * HttpContext service becomes available, the filter is + * registered. + *

+ * The value of this service registration property is a single string being + * a regular expression. + *

+ * Note: Filter services are only supported if the Http + * Service implements the + * org.apache.felix.http.api.ExtHttpService interface. + */ + public static final String PATTERN = "pattern"; + + /** + * Prefix for service registration properties being used as init parameters + * for the Servlet and Filter initialization. + */ + public static final String INIT_PREFIX = "init."; + + // no instances + private HttpWhiteboardConstants() + { + } +} Modified: felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/internal/WhiteboardActivator.java URL: http://svn.apache.org/viewvc/felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/internal/WhiteboardActivator.java?rev=1210612&r1=1210611&r2=1210612&view=diff ============================================================================== --- felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/internal/WhiteboardActivator.java (original) +++ felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/internal/WhiteboardActivator.java Mon Dec 5 20:29:08 2011 @@ -23,7 +23,6 @@ import org.apache.felix.http.whiteboard. import org.apache.felix.http.whiteboard.internal.tracker.HttpContextTracker; import org.apache.felix.http.whiteboard.internal.tracker.ServletTracker; import org.apache.felix.http.whiteboard.internal.tracker.HttpServiceTracker; -import org.apache.felix.http.whiteboard.internal.manager.ExtenderManagerImpl; import org.apache.felix.http.whiteboard.internal.manager.ExtenderManager; import org.apache.felix.http.whiteboard.internal.manager.HttpWhiteboardWebConsolePlugin; import org.apache.felix.http.base.internal.AbstractActivator; @@ -46,13 +45,13 @@ public final class WhiteboardActivator protected void doStart() throws Exception { - this.manager = new ExtenderManagerImpl(); + this.manager = new ExtenderManager(); addTracker(new HttpContextTracker(getBundleContext(), this.manager)); addTracker(new FilterTracker(getBundleContext(), this.manager)); addTracker(new ServletTracker(getBundleContext(), this.manager)); addTracker(new HttpServiceTracker(getBundleContext(), this.manager)); - HttpWhiteboardWebConsolePlugin plugin = new HttpWhiteboardWebConsolePlugin((ExtenderManagerImpl) this.manager); + HttpWhiteboardWebConsolePlugin plugin = new HttpWhiteboardWebConsolePlugin(this.manager); Hashtable props = new Hashtable(); props.put("felix.webconsole.label", plugin.getLabel()); props.put("felix.webconsole.title", plugin.getTitle()); Modified: felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/internal/manager/AbstractMapping.java URL: http://svn.apache.org/viewvc/felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/internal/manager/AbstractMapping.java?rev=1210612&r1=1210611&r2=1210612&view=diff ============================================================================== --- felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/internal/manager/AbstractMapping.java (original) +++ felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/internal/manager/AbstractMapping.java Mon Dec 5 20:29:08 2011 @@ -16,19 +16,35 @@ */ package org.apache.felix.http.whiteboard.internal.manager; +import java.util.Hashtable; + +import org.osgi.framework.Bundle; import org.osgi.service.http.HttpContext; import org.osgi.service.http.HttpService; -import java.util.Hashtable; -public abstract class AbstractMapping +abstract class AbstractMapping { - private final HttpContext context; + private final Bundle bundle; + private HttpContext context; private final Hashtable initParams; + private boolean registered; - public AbstractMapping(HttpContext context) + protected AbstractMapping(final Bundle bundle) { - this.context = context; + this.bundle = bundle; + this.context = null; this.initParams = new Hashtable(); + this.registered = false; + } + + public Bundle getBundle() + { + return bundle; + } + + public void setContext(HttpContext context) + { + this.context = context; } public final HttpContext getContext() @@ -41,6 +57,16 @@ public abstract class AbstractMapping return this.initParams; } + boolean isRegistered() + { + return registered; + } + + void setRegistered(boolean registered) + { + this.registered = registered; + } + public abstract void register(HttpService httpService); public abstract void unregister(HttpService httpService); Copied: felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/internal/manager/ExtenderManager.java (from r1203903, felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/internal/manager/ExtenderManagerImpl.java) URL: http://svn.apache.org/viewvc/felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/internal/manager/ExtenderManager.java?p2=felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/internal/manager/ExtenderManager.java&p1=felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/internal/manager/ExtenderManagerImpl.java&r1=1203903&r2=1210612&rev=1210612&view=diff ============================================================================== --- felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/internal/manager/ExtenderManagerImpl.java (original) +++ felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/internal/manager/ExtenderManager.java Mon Dec 5 20:29:08 2011 @@ -19,42 +19,58 @@ package org.apache.felix.http.whiteboard import java.util.Collection; import java.util.HashMap; import java.util.Map; +import java.util.Set; import javax.servlet.Filter; import javax.servlet.Servlet; import org.apache.felix.http.api.ExtHttpService; import org.apache.felix.http.base.internal.logger.SystemLogger; +import org.apache.felix.http.whiteboard.HttpWhiteboardConstants; +import org.apache.felix.http.whiteboard.internal.manager.HttpContextManager.HttpContextHolder; import org.osgi.framework.Bundle; import org.osgi.framework.Constants; import org.osgi.framework.ServiceReference; import org.osgi.service.http.HttpContext; import org.osgi.service.http.HttpService; -public final class ExtenderManagerImpl - implements ExtenderManager +public final class ExtenderManager { - private final static String CONTEXT_ID_KEY = "contextId"; - private final static String PATTERN_KEY = "pattern"; - private final static String ALIAS_KEY = "alias"; - private final static String INIT_KEY_PREFIX = "init."; - private HttpService httpService; - private final HashMap mapping; + private final HashMap mapping; private final HttpContextManager contextManager; - public ExtenderManagerImpl() + public ExtenderManager() { - this.mapping = new HashMap(); + this.mapping = new HashMap(); this.contextManager = new HttpContextManager(); } + static boolean isEmpty(final String value) + { + return value == null || value.length() == 0; + } + private String getStringProperty(ServiceReference ref, String key) { Object value = ref.getProperty(key); return (value instanceof String) ? (String)value : null; } + private boolean getBooleanProperty(ServiceReference ref, String key) + { + Object value = ref.getProperty(key); + if (value instanceof String) + { + return Boolean.valueOf((String) value); + } + else if (value instanceof Boolean) + { + return ((Boolean) value).booleanValue(); + } + return false; + } + private int getIntProperty(ServiceReference ref, String key, int defValue) { Object value = ref.getProperty(key); @@ -72,8 +88,8 @@ public final class ExtenderManagerImpl private void addInitParams(ServiceReference ref, AbstractMapping mapping) { for (String key : ref.getPropertyKeys()) { - if (key.startsWith(INIT_KEY_PREFIX)) { - String paramKey = key.substring(INIT_KEY_PREFIX.length()); + if (key.startsWith(HttpWhiteboardConstants.INIT_PREFIX)) { + String paramKey = key.substring(HttpWhiteboardConstants.INIT_PREFIX.length()); String paramValue = getStringProperty(ref, key); if (paramValue != null) { @@ -85,64 +101,86 @@ public final class ExtenderManagerImpl public void add(HttpContext service, ServiceReference ref) { - Bundle bundle = ref.getBundle(); - String contextId = getStringProperty(ref, CONTEXT_ID_KEY); - if (contextId != null) { - this.contextManager.addHttpContext(bundle, contextId, service); + String contextId = getStringProperty(ref, HttpWhiteboardConstants.CONTEXT_ID); + if (!isEmpty(contextId)) + { + boolean shared = getBooleanProperty(ref, HttpWhiteboardConstants.CONTEXT_SHARED); + Bundle bundle = shared ? null : ref.getBundle(); + Collection mappings = this.contextManager.addHttpContext(bundle, contextId, service); + for (AbstractMapping mapping : mappings) + { + registerMapping(mapping); + } + } + else + { + SystemLogger.debug("Ignoring HttpContext Service " + ref + ", " + HttpWhiteboardConstants.CONTEXT_ID + + " is missing or empty"); } } public void remove(HttpContext service) { - this.contextManager.removeHttpContext(service); + Collection mappings = this.contextManager.removeHttpContext(service); + if (mappings != null) + { + for (AbstractMapping mapping : mappings) + { + unregisterMapping(mapping); + } + } } - private HttpContext getHttpContext(ServiceReference ref) + private void getHttpContext(AbstractMapping mapping, ServiceReference ref) { Bundle bundle = ref.getBundle(); - String contextId = getStringProperty(ref, CONTEXT_ID_KEY); + String contextId = getStringProperty(ref, HttpWhiteboardConstants.CONTEXT_ID); + this.contextManager.getHttpContext(bundle, contextId, mapping); + } - if (contextId != null) { - return this.contextManager.getHttpContext(bundle, contextId); - } else { - return new DefaultHttpContext(bundle); - } + private void ungetHttpContext(AbstractMapping mapping, ServiceReference ref) + { + Bundle bundle = ref.getBundle(); + String contextId = getStringProperty(ref, HttpWhiteboardConstants.CONTEXT_ID); + this.contextManager.ungetHttpContext(bundle, contextId, mapping); } public void add(Filter service, ServiceReference ref) { int ranking = getIntProperty(ref, Constants.SERVICE_RANKING, 0); - String pattern = getStringProperty(ref, PATTERN_KEY); + String pattern = getStringProperty(ref, HttpWhiteboardConstants.PATTERN); - if (pattern == null) { + if (isEmpty(pattern)) { + SystemLogger.debug("Ignoring Filter Service " + ref + ", " + HttpWhiteboardConstants.PATTERN + + " is missing or empty"); return; } - FilterMapping mapping = new FilterMapping(getHttpContext(ref), service, pattern, ranking); + FilterMapping mapping = new FilterMapping(ref.getBundle(), service, pattern, ranking); + getHttpContext(mapping, ref); addInitParams(ref, mapping); - addMapping(service, mapping); - } - - public void remove(Filter service) - { - removeMapping(service); + addMapping(ref, mapping); } public void add(Servlet service, ServiceReference ref) { - String alias = getStringProperty(ref, ALIAS_KEY); - if (alias == null) { + String alias = getStringProperty(ref, HttpWhiteboardConstants.ALIAS); + if (isEmpty(alias)) + { + SystemLogger.debug("Ignoring Servlet Service " + ref + ", " + HttpWhiteboardConstants.ALIAS + + " is missing or empty"); return; } - ServletMapping mapping = new ServletMapping(getHttpContext(ref), service, alias); + ServletMapping mapping = new ServletMapping(ref.getBundle(), service, alias); + getHttpContext(mapping, ref); addInitParams(ref, mapping); - addMapping(service, mapping); + addMapping(ref, mapping); } - public void remove(Servlet service) + public void remove(ServiceReference ref) { - removeMapping(service); + removeMapping(ref); } public synchronized void setHttpService(HttpService service) @@ -199,26 +237,64 @@ public final class ExtenderManagerImpl } } - private synchronized void addMapping(Object key, AbstractMapping mapping) + private synchronized void addMapping(ServiceReference ref, AbstractMapping mapping) + { + this.mapping.put(ref, mapping); + this.registerMapping(mapping); + } + + private synchronized void removeMapping(ServiceReference ref) { - this.mapping.put(key, mapping); - if (this.httpService != null) { - mapping.register(this.httpService); + AbstractMapping mapping = this.mapping.remove(ref); + if (mapping != null) + { + ungetHttpContext(mapping, ref); + unregisterMapping(mapping); + } + } + + private void registerMapping(AbstractMapping mapping) + { + HttpService httpService = this.httpService; + if (httpService != null) + { + mapping.register(httpService); } } - private synchronized void removeMapping(Object key) + private void unregisterMapping(AbstractMapping mapping) { - AbstractMapping mapping = this.mapping.remove(key); - if ((mapping != null) && (this.httpService != null)) { - mapping.unregister(this.httpService); + HttpService httpService = this.httpService; + if (httpService != null) + { + mapping.unregister(httpService); } } - Map getHttpContexts() { + /** + * Returns + * {@link org.apache.felix.http.whiteboard.internal.manager.HttpContextManager.HttpContextHolder} + * instances of HttpContext services. + * + * @return + */ + Map getHttpContexts() + { return this.contextManager.getHttpContexts(); } + /** + * Returns {@link AbstractMapping} instances for which there is no + * registered HttpContext as desired by the context ID. + */ + Map> getOrphanMappings() + { + return this.contextManager.getOrphanMappings(); + } + + /** + * Returns mappings indexed by there owning OSGi service. + */ Map getMappings() { synchronized (this) Modified: felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/internal/manager/FilterMapping.java URL: http://svn.apache.org/viewvc/felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/internal/manager/FilterMapping.java?rev=1210612&r1=1210611&r2=1210612&view=diff ============================================================================== --- felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/internal/manager/FilterMapping.java (original) +++ felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/internal/manager/FilterMapping.java Mon Dec 5 20:29:08 2011 @@ -16,12 +16,12 @@ */ package org.apache.felix.http.whiteboard.internal.manager; -import org.osgi.service.http.HttpService; -import org.osgi.service.http.HttpContext; +import javax.servlet.Filter; + import org.apache.felix.http.api.ExtHttpService; import org.apache.felix.http.base.internal.logger.SystemLogger; - -import javax.servlet.Filter; +import org.osgi.framework.Bundle; +import org.osgi.service.http.HttpService; public final class FilterMapping extends AbstractMapping @@ -30,9 +30,9 @@ public final class FilterMapping private final int ranking; private final String pattern; - public FilterMapping(HttpContext context, Filter filter, String pattern, int ranking) + public FilterMapping(Bundle bundle, Filter filter, String pattern, int ranking) { - super(context); + super(bundle); this.filter = filter; this.pattern = pattern; this.ranking = ranking; @@ -62,17 +62,26 @@ public final class FilterMapping private void register(ExtHttpService httpService) { - try { - httpService.registerFilter(this.filter, this.pattern, getInitParams(), ranking, getContext()); - } catch (Exception e) { - SystemLogger.error("Failed to register filter", e); + if (!this.isRegistered() && getContext() != null) + { + try + { + httpService.registerFilter(this.filter, this.pattern, getInitParams(), ranking, getContext()); + setRegistered(true); + } + catch (Exception e) + { + SystemLogger.error("Failed to register filter", e); + } } } public void unregister(HttpService httpService) { - if (httpService instanceof ExtHttpService) { - unregister((ExtHttpService)httpService); + if (httpService instanceof ExtHttpService && this.isRegistered()) + { + unregister((ExtHttpService) httpService); + setRegistered(false); } } Modified: felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/internal/manager/HttpContextManager.java URL: http://svn.apache.org/viewvc/felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/internal/manager/HttpContextManager.java?rev=1210612&r1=1210611&r2=1210612&view=diff ============================================================================== --- felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/internal/manager/HttpContextManager.java (original) +++ felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/internal/manager/HttpContextManager.java Mon Dec 5 20:29:08 2011 @@ -1,12 +1,12 @@ /* * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with + * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at + * the License. You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -19,59 +19,248 @@ package org.apache.felix.http.whiteboard import org.osgi.framework.Bundle; import org.osgi.service.http.HttpContext; import org.apache.felix.http.base.internal.logger.SystemLogger; + +import java.util.Collection; import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; import java.util.Map; +import java.util.Set; public final class HttpContextManager { - private final HashMap idMap; + /** + * HttpContextHolders indexed by context ID fully configured + * with an HttpContext and optional servlets and filters. + *

+ * The context ID either includes the bundle ID as the first part of the + * name, such as 123-sample.context in the case of non-shared + * contexts. IDs of shared contexts are prefixed with the fixed string + * shared to not mix them with per-bundle contexts. + */ + private final HashMap idMap; + + /** + * Reverse mapping of HttpContext services to the context ID with + * which they are registered. + */ private final HashMap contextMap; + /** + * Map of servlets and filters registered referring to unregistered + * contexts as of yet. + */ + private final HashMap> orphanMappings; + public HttpContextManager() { - this.idMap = new HashMap(); + this.idMap = new HashMap(); this.contextMap = new HashMap(); + this.orphanMappings = new HashMap>(); } - private String createId(Bundle bundle, String contextId) + private static String createId(Bundle bundle, String contextId) { - return bundle.getBundleId() + "-" + contextId; + if (bundle != null) + { + return bundle.getBundleId() + "-" + ((contextId == null) ? "" : contextId); + } + + return createId(contextId); } - public synchronized HttpContext getHttpContext(Bundle bundle, String contextId) + private static String createId(String contextId) { + return "shared-" + ((contextId == null) ? "" : contextId); + } + + private static String getContextId(String id) + { + final int dash = id.indexOf('-'); + return (dash < 0) ? id : id.substring(dash + 1); + } + + public synchronized HttpContext getHttpContext(Bundle bundle, String contextId, AbstractMapping mapping) + { + // per-bundle context String id = createId(bundle, contextId); - HttpContext context = this.idMap.get(id); + HttpContextHolder holder = this.idMap.get(id); - if (context == null) { - context = new DefaultHttpContext(bundle); - this.idMap.put(id, context); - this.contextMap.put(context, id); - SystemLogger.debug("Added context with id [" + contextId + "]"); - } else { - SystemLogger.debug("Reusing context with id [" + contextId + "]"); + // shared context + if (holder == null) + { + id = createId(contextId); + holder = this.idMap.get(id); } - return context; + // no context yet, put the mapping on hold + if (holder == null) + { + + // care for default context if no context ID + if (ExtenderManager.isEmpty(contextId)) + { + addHttpContext(bundle, "", new DefaultHttpContext(bundle)); + return getHttpContext(bundle, "", mapping); + } + + // otherwise context is not here yet + Set orphaned = this.orphanMappings.get(contextId); + if (orphaned == null) + { + orphaned = new HashSet(); + this.orphanMappings.put(contextId, orphaned); + } + SystemLogger.debug("Holding off mapping with unregistered context with id [" + contextId + "]"); + orphaned.add(mapping); + return null; + } + + // otherwise use the context + SystemLogger.debug("Reusing context with id [" + contextId + "]"); + holder.addMapping(mapping); + return holder.getContext(); } - public synchronized void removeHttpContext(HttpContext context) + public synchronized void ungetHttpContext(Bundle bundle, String contextId, AbstractMapping mapping) { - String id = this.contextMap.remove(context); - if (id != null) { - this.idMap.remove(id); + // per-bundle context + String id = createId(bundle, contextId); + HttpContextHolder context = this.idMap.get(id); + + // shared context + if (context == null) + { + id = createId(contextId); + context = this.idMap.get(id); + } + + // remove the mapping if there is a mapped context + if (context != null) + { + context.removeMapping(mapping); + } + else + { + Set orphans = this.orphanMappings.get(contextId); + if (orphans != null) + { + orphans.remove(mapping); + if (orphans.isEmpty()) + { + this.orphanMappings.remove(contextId); + } + } + + // it is not expected but make sure there is no reference + mapping.setContext(null); } } - public synchronized void addHttpContext(Bundle bundle, String contextId, HttpContext context) + public synchronized Collection addHttpContext(Bundle bundle, String contextId, HttpContext context) { String id = createId(bundle, contextId); - this.idMap.put(id, context); + HttpContextHolder holder = new HttpContextHolder(context); + + Set orphans = this.orphanMappings.remove(contextId); + if (orphans != null) + { + for (Iterator mi = orphans.iterator(); mi.hasNext();) + { + AbstractMapping mapping = mi.next(); + if (bundle == null || bundle.equals(mapping.getBundle())) + { + holder.addMapping(mapping); + mi.remove(); + } + } + + // put any remaining orphans back + if (!orphans.isEmpty()) + { + this.orphanMappings.put(contextId, orphans); + } + } + + this.idMap.put(id, holder); this.contextMap.put(context, id); + + return holder.getMappings(); + } + + public synchronized Collection removeHttpContext(HttpContext context) + { + String id = this.contextMap.remove(context); + if (id != null) + { + HttpContextHolder holder = this.idMap.remove(id); + if (holder != null) + { + Set mappings = holder.getMappings(); + if (mappings != null && !mappings.isEmpty()) + { + // keep the orphans around + final String contextId = getContextId(id); + Set orphans = this.orphanMappings.get(contextId); + if (orphans == null) + { + orphans = new HashSet(); + this.orphanMappings.put(getContextId(id), orphans); + } + + for (AbstractMapping mapping : mappings) + { + mapping.setContext(null); + orphans.add(mapping); + } + } + return mappings; + } + } + return null; + } + + synchronized Map getHttpContexts() + { + return new HashMap(this.idMap); + } + + synchronized Map> getOrphanMappings() + { + return new HashMap>(this.orphanMappings); } - public synchronized Map getHttpContexts() + static class HttpContextHolder { - return new HashMap(this.idMap); + private final HttpContext context; + private final Set mappings; + + HttpContextHolder(final HttpContext context) + { + this.context = context; + this.mappings = new HashSet(); + } + + public HttpContext getContext() + { + return context; + } + + void addMapping(AbstractMapping mapping) + { + this.mappings.add(mapping); + mapping.setContext(this.getContext()); + } + + void removeMapping(AbstractMapping mapping) + { + mapping.setContext(null); + this.mappings.remove(mapping); + } + + public Set getMappings() + { + return mappings; + } } } Modified: felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/internal/manager/HttpWhiteboardWebConsolePlugin.java URL: http://svn.apache.org/viewvc/felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/internal/manager/HttpWhiteboardWebConsolePlugin.java?rev=1210612&r1=1210611&r2=1210612&view=diff ============================================================================== --- felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/internal/manager/HttpWhiteboardWebConsolePlugin.java (original) +++ felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/internal/manager/HttpWhiteboardWebConsolePlugin.java Mon Dec 5 20:29:08 2011 @@ -27,13 +27,13 @@ import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.osgi.service.http.HttpContext; +import org.apache.felix.http.whiteboard.internal.manager.HttpContextManager.HttpContextHolder; @SuppressWarnings("serial") public class HttpWhiteboardWebConsolePlugin extends HttpServlet { - private final ExtenderManagerImpl extMgr; + private final ExtenderManager extMgr; public String getLabel() { @@ -45,7 +45,7 @@ public class HttpWhiteboardWebConsolePlu return "Http Whiteboard"; } - public HttpWhiteboardWebConsolePlugin(final ExtenderManagerImpl extMgr) + public HttpWhiteboardWebConsolePlugin(final ExtenderManager extMgr) { this.extMgr = extMgr; } @@ -92,12 +92,12 @@ public class HttpWhiteboardWebConsolePlu pw.println("HttpContext"); pw.println(""); - final Map contexts = extMgr.getHttpContexts(); - for (Map.Entry handler : contexts.entrySet()) + final Map contexts = extMgr.getHttpContexts(); + for (Map.Entry handler : contexts.entrySet()) { pw.println(""); pw.println("" + handler.getKey() + ""); - pw.println("" + handler.getValue() + ""); + pw.println("" + handler.getValue().getContext() + ""); pw.println(""); } } @@ -167,10 +167,10 @@ public class HttpWhiteboardWebConsolePlu private void printHttpContextServicesTxt(PrintWriter pw) { pw.println("Registered HttpContext Services"); - final Map contexts = extMgr.getHttpContexts(); - for (Map.Entry handler : contexts.entrySet()) + final Map contexts = extMgr.getHttpContexts(); + for (Map.Entry handler : contexts.entrySet()) { - pw.println(" " + handler.getKey() + " ==> " + handler.getValue() + ""); + pw.println(" " + handler.getKey() + " ==> " + handler.getValue().getContext() + ""); } pw.println(); } @@ -183,8 +183,8 @@ public class HttpWhiteboardWebConsolePlu if (handler.getValue() instanceof ServletMapping) { ServletMapping sm = (ServletMapping) handler.getValue(); - pw.println(" " + sm.getAlias() + " ==> " + sm.getServlet() + " (" + sm.getInitParams() + ", " - + sm.getContext() + ")"); + pw.printf(" %s ==> %s (%s, %s, %s)%n", sm.getAlias(), sm.getServlet(), + sm.isRegistered() ? "registered" : "unregistered", sm.getInitParams(), sm.getContext()); } } pw.println(); @@ -198,8 +198,9 @@ public class HttpWhiteboardWebConsolePlu if (handler.getValue() instanceof FilterMapping) { FilterMapping fm = (FilterMapping) handler.getValue(); - pw.println(" " + fm.getPattern() + " ==> " + fm.getFilter() + " (" + fm.getRanking() + ", " - + fm.getInitParams() + ", " + fm.getContext() + ")"); + pw.printf(" %s ==> %s (%s, %s, %s, %s)%n", fm.getPattern(), fm.getFilter(), + fm.isRegistered() ? "registered" : "unregistered", fm.getRanking(), fm.getInitParams(), + fm.getContext()); } } pw.println(); Modified: felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/internal/manager/ServletMapping.java URL: http://svn.apache.org/viewvc/felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/internal/manager/ServletMapping.java?rev=1210612&r1=1210611&r2=1210612&view=diff ============================================================================== --- felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/internal/manager/ServletMapping.java (original) +++ felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/internal/manager/ServletMapping.java Mon Dec 5 20:29:08 2011 @@ -16,21 +16,21 @@ */ package org.apache.felix.http.whiteboard.internal.manager; -import org.osgi.service.http.HttpService; -import org.osgi.service.http.HttpContext; -import org.apache.felix.http.base.internal.logger.SystemLogger; - import javax.servlet.Servlet; +import org.apache.felix.http.base.internal.logger.SystemLogger; +import org.osgi.framework.Bundle; +import org.osgi.service.http.HttpService; + public final class ServletMapping extends AbstractMapping { private final Servlet servlet; private final String alias; - public ServletMapping(HttpContext context, Servlet servlet, String alias) + public ServletMapping(Bundle bundle, Servlet servlet, String alias) { - super(context); + super(bundle); this.servlet = servlet; this.alias = alias; } @@ -47,15 +47,26 @@ public final class ServletMapping public void register(HttpService httpService) { - try { - httpService.registerServlet(this.alias, this.servlet, getInitParams(), getContext()); - } catch (Exception e) { - SystemLogger.error("Failed to register servlet", e); + if (!this.isRegistered() && getContext() != null) + { + try + { + httpService.registerServlet(this.alias, this.servlet, getInitParams(), getContext()); + this.setRegistered(true); + } + catch (Exception e) + { + SystemLogger.error("Failed to register servlet", e); + } } } public void unregister(HttpService httpService) { - httpService.unregister(this.alias); + if (this.isRegistered()) + { + httpService.unregister(this.alias); + this.setRegistered(false); + } } } Modified: felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/internal/tracker/AbstractTracker.java URL: http://svn.apache.org/viewvc/felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/internal/tracker/AbstractTracker.java?rev=1210612&r1=1210611&r2=1210612&view=diff ============================================================================== --- felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/internal/tracker/AbstractTracker.java (original) +++ felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/internal/tracker/AbstractTracker.java Mon Dec 5 20:29:08 2011 @@ -23,7 +23,7 @@ import org.osgi.framework.ServiceReferen public abstract class AbstractTracker extends ServiceTracker { - public AbstractTracker(BundleContext context, Class clz) + public AbstractTracker(BundleContext context, Class clz) { super(context, clz.getName(), null); } @@ -49,12 +49,12 @@ public abstract class AbstractTracker public final void removedService(ServiceReference ref, Object service) { super.removedService(ref, service); - removed((T)service); + removed((T) service, ref); } protected abstract void modified(T service, ServiceReference ref); protected abstract void added(T service, ServiceReference ref); - protected abstract void removed(T service); + protected abstract void removed(T service, ServiceReference ref); } Modified: felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/internal/tracker/FilterTracker.java URL: http://svn.apache.org/viewvc/felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/internal/tracker/FilterTracker.java?rev=1210612&r1=1210611&r2=1210612&view=diff ============================================================================== --- felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/internal/tracker/FilterTracker.java (original) +++ felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/internal/tracker/FilterTracker.java Mon Dec 5 20:29:08 2011 @@ -39,12 +39,12 @@ public final class FilterTracker protected void modified(Filter service, ServiceReference ref) { - removed(service); + removed(service, ref); added(service, ref); } - protected void removed(Filter service) + protected void removed(Filter service, ServiceReference ref) { - this.manager.remove(service); + this.manager.remove(ref); } } Modified: felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/internal/tracker/HttpContextTracker.java URL: http://svn.apache.org/viewvc/felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/internal/tracker/HttpContextTracker.java?rev=1210612&r1=1210611&r2=1210612&view=diff ============================================================================== --- felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/internal/tracker/HttpContextTracker.java (original) +++ felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/internal/tracker/HttpContextTracker.java Mon Dec 5 20:29:08 2011 @@ -25,7 +25,7 @@ public final class HttpContextTracker extends AbstractTracker { private final ExtenderManager manager; - + public HttpContextTracker(BundleContext context, ExtenderManager manager) { super(context, HttpContext.class); @@ -39,11 +39,11 @@ public final class HttpContextTracker protected void modified(HttpContext service, ServiceReference ref) { - removed(service); + removed(service, ref); added(service, ref); } - - protected void removed(HttpContext service) + + protected void removed(HttpContext service, ServiceReference ref) { this.manager.remove(service); } Modified: felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/internal/tracker/HttpServiceTracker.java URL: http://svn.apache.org/viewvc/felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/internal/tracker/HttpServiceTracker.java?rev=1210612&r1=1210611&r2=1210612&view=diff ============================================================================== --- felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/internal/tracker/HttpServiceTracker.java (original) +++ felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/internal/tracker/HttpServiceTracker.java Mon Dec 5 20:29:08 2011 @@ -42,7 +42,7 @@ public final class HttpServiceTracker // Do nothing } - protected void removed(HttpService service) + protected void removed(HttpService service, ServiceReference ref) { this.manager.unsetHttpService(); } Modified: felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/internal/tracker/ServletTracker.java URL: http://svn.apache.org/viewvc/felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/internal/tracker/ServletTracker.java?rev=1210612&r1=1210611&r2=1210612&view=diff ============================================================================== --- felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/internal/tracker/ServletTracker.java (original) +++ felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/internal/tracker/ServletTracker.java Mon Dec 5 20:29:08 2011 @@ -39,12 +39,12 @@ public final class ServletTracker protected void modified(Servlet service, ServiceReference ref) { - removed(service); + removed(service, ref); added(service, ref); } - - protected void removed(Servlet service) + + protected void removed(Servlet service, ServiceReference ref) { - this.manager.remove(service); + this.manager.remove(ref); } } Added: felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/package-info.java URL: http://svn.apache.org/viewvc/felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/package-info.java?rev=1210612&view=auto ============================================================================== --- felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/package-info.java (added) +++ felix/trunk/http/whiteboard/src/main/java/org/apache/felix/http/whiteboard/package-info.java Mon Dec 5 20:29:08 2011 @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * @see: @TODO ref to whiteboard page on felix.apache.org + */ +@Version("1.0") +@Export(optional = "provide:=true") +package org.apache.felix.http.whiteboard; + +import aQute.bnd.annotation.Export; +import aQute.bnd.annotation.Version; +