FELIX-2240 Implement support to specify a selection filter for the HTTP Service to which the Web Console should bind. If the filter is empty or not set (the default), the Web Console binds to any HTTP Service provided by the framework.

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@957829 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/ConfigurationListener2.java b/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/ConfigurationListener2.java
index 05c9209..0bfa367 100644
--- a/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/ConfigurationListener2.java
+++ b/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/ConfigurationListener2.java
@@ -80,6 +80,16 @@
             final ArrayList adList = new ArrayList();
             adList.add( new AttributeDefinitionImpl( OsgiManager.PROP_MANAGER_ROOT, "Root URI",
                 "The root path to the OSGi Management Console.", OsgiManager.DEFAULT_MANAGER_ROOT ) );
+            adList.add( new AttributeDefinitionImpl( OsgiManager.PROP_HTTP_SERVICE_SELECTOR, "Http Service Selector",
+                "The Http Service Selector is an OSGi filter used to select the Http Service to "
+                    + "which the Web Console binds. The value of this property (if not empty) is "
+                    + "combined the object class selection term to get the actual service selection "
+                    + "filter like (&(objectClass=org.osgi.service.http.HttpService)(selector)). This "
+                    + "property must not have leading an trailing parentheses. For example, to bind "
+                    + "to the service with service ID 15 set the selector to 'service.id=15' (without "
+                    + "the quotes). By default (if this property is not set or set to an empty "
+                    + "string) the Web Console binds with an Http Service available.",
+                OsgiManager.DEFAULT_HTTP_SERVICE_SELECTOR ) );
             adList.add( new AttributeDefinitionImpl( OsgiManager.PROP_DEFAULT_RENDER, "Default Page",
                 "The name of the default configuration page when invoking the OSGi Management console.",
                 OsgiManager.DEFAULT_PAGE ) );
@@ -94,9 +104,12 @@
             adList.add( new AttributeDefinitionImpl( OsgiManager.PROP_PASSWORD, "Password",
                 "The password for the user allowed to access the OSGi Management Console.",
                 OsgiManager.DEFAULT_PASSWORD ) );
-            adList.add( new AttributeDefinitionImpl( OsgiManager.PROP_LOCALE, "Locale",
-                "If set, this locale forces the localization to use this locale instead of the one, requested by the web browser",
-                "" ) );
+            adList
+                .add( new AttributeDefinitionImpl(
+                    OsgiManager.PROP_LOCALE,
+                    "Locale",
+                    "If set, this locale forces the localization to use this locale instead of the one, requested by the web browser",
+                    "" ) );
             adList.add( new AttributeDefinitionImpl( OsgiManager.PROP_LOG_LEVEL, "Log Level", "Logging Level",
                 AttributeDefinition.INTEGER, new String[]
                     { String.valueOf( OsgiManager.DEFAULT_LOG_LEVEL ) }, 0, new String[]
diff --git a/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/OsgiManager.java b/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/OsgiManager.java
index 1e15b7e..9bcbbbb 100644
--- a/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/OsgiManager.java
+++ b/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/OsgiManager.java
@@ -18,7 +18,6 @@
 
 
 import java.io.IOException;
-import java.security.GeneralSecurityException;
 import java.text.MessageFormat;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -52,6 +51,9 @@
 import org.apache.felix.webconsole.internal.i18n.ResourceBundleManager;
 import org.apache.felix.webconsole.internal.misc.ConfigurationRender;
 import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
 import org.osgi.framework.ServiceReference;
 import org.osgi.framework.ServiceRegistration;
 import org.osgi.service.http.HttpContext;
@@ -119,6 +121,8 @@
 
     static final String PROP_LOCALE = "locale";
 
+    static final String PROP_HTTP_SERVICE_SELECTOR = "http.service.filter";
+
     public static final int DEFAULT_LOG_LEVEL = LogService.LOG_WARNING;
 
     static final String DEFAULT_PAGE = BundlesServlet.NAME;
@@ -129,6 +133,8 @@
 
     static final String DEFAULT_PASSWORD = "admin";
 
+    static final String DEFAULT_HTTP_SERVICE_SELECTOR = "";
+
     /**
      * The default value for the {@link #PROP_MANAGER_ROOT} configuration
      * property (value is "/system/console").
@@ -157,7 +163,7 @@
 
     private BundleContext bundleContext;
 
-    private ServiceTracker httpServiceTracker;
+    private HttpServiceTracker httpServiceTracker;
 
     private HttpService httpService;
 
@@ -221,11 +227,6 @@
             }
         }
 
-        // get at the HttpService first, this should initialize
-        // the OSGi Manager and start the initial setup
-        httpServiceTracker = new HttpServiceTracker( this );
-        httpServiceTracker.open();
-
         // setup the included plugins
         ClassLoader classLoader = getClass().getClassLoader();
         for ( int i = 0; i < PLUGIN_CLASSES.length; i++ )
@@ -568,13 +569,60 @@
     private static class HttpServiceTracker extends ServiceTracker
     {
 
+        private static final String HTTP_SERVICE = "org.osgi.service.http.HttpService";
+
         private final OsgiManager osgiManager;
 
+        private final String httpServiceSelector;
 
-        HttpServiceTracker( OsgiManager osgiManager )
+
+        static HttpServiceTracker create( OsgiManager osgiManager, String httpServiceSelector )
         {
-            super( osgiManager.getBundleContext(), HttpService.class.getName(), null );
+            // got a service selector filter
+            if ( httpServiceSelector != null && httpServiceSelector.length() > 0 )
+            {
+                try
+                {
+                    final String filterString = "(&(" + Constants.OBJECTCLASS + "=" + HTTP_SERVICE + ")("
+                        + httpServiceSelector + "))";
+                    Filter filter = osgiManager.getBundleContext().createFilter( filterString );
+                    return new HttpServiceTracker( osgiManager, httpServiceSelector, filter );
+                }
+                catch ( InvalidSyntaxException ise )
+                {
+                    // TODO: log or throw or ignore ....
+                }
+            }
+
+            // no filter or illegal filter string
+            return new HttpServiceTracker( osgiManager );
+        }
+
+
+        private HttpServiceTracker( final OsgiManager osgiManager )
+        {
+            super( osgiManager.getBundleContext(), HTTP_SERVICE, null );
             this.osgiManager = osgiManager;
+            this.httpServiceSelector = null;
+        }
+
+
+        private HttpServiceTracker( final OsgiManager osgiManager, final String httpServiceSelector,
+            final Filter httpServiceFilter )
+        {
+            super( osgiManager.getBundleContext(), httpServiceFilter, null );
+            this.osgiManager = osgiManager;
+            this.httpServiceSelector = httpServiceSelector;
+        }
+
+
+        boolean isSameSelector( final String newHttpServiceSelector )
+        {
+            if ( newHttpServiceSelector != null )
+            {
+                return newHttpServiceSelector.equals( httpServiceSelector );
+            }
+            return httpServiceSelector == null;
         }
 
 
@@ -747,6 +795,16 @@
             newWebManagerRoot = "/" + newWebManagerRoot;
         }
 
+        // get the HTTP Service selector (and dispose tracker for later
+        // recreation)
+        final String newHttpServiceSelector = getProperty( config, PROP_HTTP_SERVICE_SELECTOR,
+            DEFAULT_HTTP_SERVICE_SELECTOR );
+        if ( httpServiceTracker != null && !httpServiceTracker.isSameSelector( newHttpServiceSelector ) )
+        {
+            httpServiceTracker.close();
+            httpServiceTracker = null;
+        }
+
         // get enabled plugins
         Object pluginValue = config.get( PROP_ENABLED_PLUGINS );
         if ( pluginValue == null )
@@ -786,6 +844,13 @@
             // just set the configured location (FELIX-2034)
             this.webManagerRoot = newWebManagerRoot;
         }
+
+        // create or recreate the HTTP service tracker with the new selector
+        if ( httpServiceTracker == null )
+        {
+            httpServiceTracker = HttpServiceTracker.create( this, newHttpServiceSelector );
+            httpServiceTracker.open();
+        }
     }