This is an automated email from the ASF dual-hosted git repository.

cziegeler pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/felix-dev.git


The following commit(s) were added to refs/heads/master by this push:
     new 552b3d00ed FELIX-6621 : Regressions caused by FELIX-6607
552b3d00ed is described below

commit 552b3d00ed00165e630f2b76309496ee4dd283ea
Author: Carsten Ziegeler <[email protected]>
AuthorDate: Sun Jul 30 17:57:32 2023 +0200

    FELIX-6621 : Regressions caused by FELIX-6607
---
 .../webconsole/internal/servlet/OsgiManager.java   |   8 +-
 .../felix/webconsole/internal/servlet/Plugin.java  | 200 ++++++
 .../webconsole/internal/servlet/PluginHolder.java  | 697 ++++++---------------
 3 files changed, 394 insertions(+), 511 deletions(-)

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 ff6eea118a..f0497cc9fb 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
@@ -333,12 +333,6 @@ public class OsgiManager extends GenericServlet
         // the resource bundle manager
         resourceBundleManager = new ResourceBundleManager(getBundleContext());
 
-        // start the configuration render, providing the resource bundle 
manager
-        //ConfigurationRender cr = new 
ConfigurationRender(resourceBundleManager);
-        //cr.activate(bundleContext);
-        //osgiManagerPlugins.add(cr);
-        //holder.addOsgiManagerPlugin(cr);
-
         // start tracking external plugins after setting up our own plugins
         holder.open();
 
@@ -1200,7 +1194,7 @@ public class OsgiManager extends GenericServlet
             {
                 if (active)
                 {
-                    holder.removeInternalPlugin(label);
+                    holder.removeInternalPlugin(pluginClassName, label);
                 }
             }
             else
diff --git 
a/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/Plugin.java
 
b/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/Plugin.java
new file mode 100644
index 0000000000..106271977d
--- /dev/null
+++ 
b/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/Plugin.java
@@ -0,0 +1,200 @@
+/*
+ * 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.webconsole.internal.servlet;
+
+import java.util.Collections;
+import java.util.Enumeration;
+
+import javax.servlet.Servlet;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+
+import org.apache.felix.webconsole.AbstractWebConsolePlugin;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+
+public abstract class Plugin implements ServletConfig, Comparable<Plugin> {
+
+    private final PluginHolder holder;
+    private final String label;
+
+    private final ServiceReference<Servlet> serviceReference; // used for 
comparing conflicting services
+
+    private volatile String title;
+
+    private volatile AbstractWebConsolePlugin consolePlugin;
+
+    public Plugin( final PluginHolder holder, final ServiceReference<Servlet> 
serviceReference, final String label ) {
+        this.holder = holder;
+        this.serviceReference = serviceReference;
+        this.label = label;
+    }
+
+    public ServiceReference<Servlet> getServiceReference() {
+        return this.serviceReference;
+    }
+
+    public abstract String getId();
+
+    public Bundle getBundle() {
+        if ( this.serviceReference != null ) {
+            return this.serviceReference.getBundle();
+        }
+        return this.holder.getBundleContext().getBundle();
+    }
+
+    /**
+     * Cleans up this plugin when it is not used any longer. This means
+     * destroying the plugin servlet and, if it was registered as an OSGi
+     * service, ungetting the service.
+     */
+    public void dispose() {
+        if (this.consolePlugin != null) {
+           try {
+                this.consolePlugin.destroy();
+            } catch ( final Throwable t) {
+                // ignore
+            }
+            this.doUngetConsolePlugin(this.consolePlugin);
+            this.consolePlugin = null;
+        }
+    }
+
+    private static Integer getRanking(final ServiceReference<Servlet> 
serviceReference) {
+        // ranking must be of type Integer
+        final Object ranking = serviceReference != null ? 
serviceReference.getProperty(Constants.SERVICE_RANKING) : null;
+        if (ranking instanceof Integer) {
+            return (Integer) ranking;
+        }
+        // otherwise return default value
+        return 0;
+    }
+
+    @Override
+    public int compareTo(final Plugin other) {
+        // serviceReference = null means internal (i.e. service.ranking=0 and 
service.id=0)
+        final Long id = serviceReference != null ? (Long) 
serviceReference.getProperty(Constants.SERVICE_ID) : 0;
+        final Long otherId = other.serviceReference != null ? (Long) 
other.serviceReference.getProperty(Constants.SERVICE_ID) : 0;
+        if (id.compareTo(otherId) == 0) {
+            return 0; // same service or both internal
+        }
+
+        final Integer rank = getRanking(this.serviceReference);
+        final Integer otherRank = getRanking(other.serviceReference);
+
+        // Sort by rank in ascending order.
+        if (rank.compareTo(otherRank) < 0) {
+            return -1; // lower rank
+        } else if (rank.compareTo(otherRank) > 0) {
+            return 1; // higher rank
+        }
+
+        // If ranks are equal, then sort by service id in descending order.
+        return -1 * id.compareTo(otherId);
+    }
+
+    protected PluginHolder getHolder() {
+        return holder;
+    }
+
+    public String getLabel() {
+        return label;
+    }
+
+    protected void setTitle( String title ) {
+        this.title = title;
+    }
+
+    public String getTitle() {
+        if ( this.title == null ) {
+            final String v = this.doGetTitle();
+            this.title = ( v == null ) ? this.label : v;
+        }
+        return this.title;
+    }
+
+    protected String doGetTitle() {
+        // get the service now
+        final AbstractWebConsolePlugin plugin = this.getConsolePlugin();
+
+        // reset the title:
+        // - null if the servlet cannot be loaded
+        // - to the servlet's actual title if the servlet is loaded
+        return ( plugin != null ) ? plugin.getTitle() : null;
+    }
+
+    // methods added to support categories
+
+    final String getCategory() {
+        return doGetCategory();
+    }
+
+    protected String doGetCategory() {
+        // get the service now
+        final AbstractWebConsolePlugin plugin = getConsolePlugin();
+        return ( plugin != null ) ? plugin.getCategory() : null;
+    }
+
+    public final AbstractWebConsolePlugin getConsolePlugin() {
+        if ( this.consolePlugin == null ) {
+            final AbstractWebConsolePlugin plugin = this.doGetConsolePlugin();
+            if ( plugin != null ) {
+                try {
+                    plugin.init(this);
+                } catch (final ServletException e) {
+                    // ignore this
+                }
+                this.consolePlugin = plugin;
+            }
+        }
+        return this.consolePlugin;
+    }
+
+    protected boolean isEnabled() {
+        return true;
+    }
+
+    protected abstract AbstractWebConsolePlugin doGetConsolePlugin();
+
+    protected abstract void doUngetConsolePlugin( AbstractWebConsolePlugin 
consolePlugin );
+
+    //---------- ServletConfig interface
+
+    @Override
+    public String getInitParameter( final String name ) {
+        return null;
+    }
+
+    @Override
+    public Enumeration<?> getInitParameterNames() {
+        return Collections.emptyEnumeration();
+    }
+
+    @Override
+    public ServletContext getServletContext() {
+        return getHolder().getServletContext();
+    }
+
+    @Override
+    public String getServletName() {
+        return getTitle();
+    }
+}
diff --git 
a/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/PluginHolder.java
 
b/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/PluginHolder.java
index 8b22be5e80..7fb3833dec 100644
--- 
a/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/PluginHolder.java
+++ 
b/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/PluginHolder.java
@@ -18,62 +18,68 @@
  */
 package org.apache.felix.webconsole.internal.servlet;
 
-
+import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Enumeration;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 import java.util.NoSuchElementException;
 import java.util.ResourceBundle;
 
 import javax.servlet.Servlet;
-import javax.servlet.ServletConfig;
 import javax.servlet.ServletContext;
-import javax.servlet.ServletException;
 
 import org.apache.felix.webconsole.AbstractWebConsolePlugin;
 import org.apache.felix.webconsole.WebConsoleConstants;
 import org.apache.felix.webconsole.internal.OsgiManagerPlugin;
 import org.apache.felix.webconsole.internal.WebConsolePluginAdapter;
 import org.apache.felix.webconsole.internal.i18n.ResourceBundleManager;
-import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.Constants;
+import org.osgi.framework.Filter;
 import org.osgi.framework.InvalidSyntaxException;
-import org.osgi.framework.ServiceEvent;
-import org.osgi.framework.ServiceListener;
 import org.osgi.framework.ServiceReference;
 import org.osgi.service.log.LogService;
+import org.osgi.util.tracker.ServiceTracker;
+import org.osgi.util.tracker.ServiceTrackerCustomizer;
 
 
 /**
  * The <code>PluginHolder</code> class implements the maintenance and lazy
  * access to web console plugin services.
  */
-class PluginHolder implements ServiceListener
-{
+class PluginHolder implements ServiceTrackerCustomizer<Servlet, Plugin> {
 
     private final OsgiManager osgiManager;
 
     // The Web Console's bundle context to access the plugin services
     private final BundleContext bundleContext;
 
-    // registered plugins
-    private final Map<String, Plugin> plugins;
+    // Registered plugins
+    private final Map<String, List<Plugin>> plugins = new HashMap<>();
 
     // The servlet context used to initialize plugin services
-    private ServletContext servletContext;
+    private volatile ServletContext servletContext;
 
     // the label of the default plugin
-    private String defaultPluginLabel;
-
+    private volatile String defaultPluginLabel;
 
+    private final ServiceTracker<Servlet, Plugin> servletTracker;
 
-    PluginHolder( final OsgiManager osgiManager, final BundleContext context )
-    {
+    PluginHolder( final OsgiManager osgiManager, final BundleContext context ) 
{
         this.osgiManager = osgiManager;
         this.bundleContext = context;
-        this.plugins = new HashMap<>();
+        Filter filter = null;
+        try {
+            filter = context.createFilter("(&(" + Constants.OBJECTCLASS + "=" 
+ WebConsoleConstants.SERVICE_NAME + 
+                ")(" + WebConsoleConstants.PLUGIN_LABEL + "=*))");
+        } catch (final InvalidSyntaxException e) {
+            // not expected, thus fail hard
+            throw new InternalError( "Failed creating filter: " + 
e.getMessage() );
+        }
+        this.servletTracker = new ServiceTracker<>(context, filter, this);
     }
 
 
@@ -84,90 +90,69 @@ class PluginHolder implements ServiceListener
      * and getting references to all plugins already registered in the
      * framework.
      */
-    void open()
-    {
-        try
-        {
-            bundleContext.addServiceListener( this, "(" + 
Constants.OBJECTCLASS + "="
-                + WebConsoleConstants.SERVICE_NAME + ")" );
-        }
-        catch ( InvalidSyntaxException ise )
-        {
-            // not expected, thus fail hard
-            throw new InternalError( "Failed registering for Servlet service 
events: " + ise.getMessage() );
-        }
-
-        try
-        {
-            ServiceReference<?>[] refs = bundleContext.getServiceReferences( 
WebConsoleConstants.SERVICE_NAME, null );
-            if ( refs != null )
-            {
-                for ( int i = 0; i < refs.length; i++ )
-                {
-                    serviceAdded( refs[i] );
-                }
-            }
-        }
-        catch ( InvalidSyntaxException ise )
-        {
-            // not expected, thus fail hard
-            throw new InternalError( "Failed getting existing Servlet 
services: " + ise.getMessage() );
-        }
+    void open() {
+        this.servletTracker.open();
     }
 
-
     /**
      * Stop using the plugin manager by removing as a service listener and
      * releasing all held plugins, which includes ungetting and destroying any
      * held plugin services.
      */
-    void close()
-    {
-        bundleContext.removeServiceListener( this );
-
-        Plugin[] plugin = getPlugins();
-        for ( int i = 0; i < plugin.length; i++ )
-        {
-            plugin[i].dispose();
-        }
+    void close() {
+        this.servletTracker.close();
 
-        plugins.clear();
-        defaultPluginLabel = null;
+        this.plugins.clear();
+        this.servletContext = null;
+        this.defaultPluginLabel = null;
     }
 
-
     /**
      * Returns label of the default plugin
      * @return label of the default plugin
      */
-    String getDefaultPluginLabel()
-    {
+    String getDefaultPluginLabel() {
         return defaultPluginLabel;
     }
 
-
     /**
      * Sets the label of the default plugin
      * @param defaultPluginLabel
      */
-    void setDefaultPluginLabel( String defaultPluginLabel )
-    {
+    void setDefaultPluginLabel( final String defaultPluginLabel ) {
         this.defaultPluginLabel = defaultPluginLabel;
     }
 
-    void addInternalPlugin( final String pluginClassName, final String label)
-    {
+    /**
+     * Add the internal Web Console plugin registered under the given label
+     * @param pluginClassName The class name of the Web Console internal 
plugin to add
+     * @param label The label of the Web Console internal plugin to add
+     */
+    void addInternalPlugin( final String pluginClassName, final String label) {
         final Plugin plugin = new InternalPlugin(this, osgiManager, 
pluginClassName, label);
-        addPlugin( label, plugin );
+        this.addPlugin( plugin );
     }
 
     /**
      * Remove the internal Web Console plugin registered under the given label
+     * @param pluginClassName The class name of the Web Console internal 
plugin to remove
      * @param label The label of the Web Console internal plugin to remove
      */
-    void removeInternalPlugin( final String label )
-    {
-        removePlugin( label );
+    void removeInternalPlugin( final String pluginClassName, final String 
label ) {
+        synchronized ( plugins ) {
+            final List<Plugin> list = plugins.get( label );
+            if ( list != null ) {
+                for(final Plugin plugin : list) {
+                    if ( plugin instanceof InternalPlugin ) {
+                        final InternalPlugin internalPlugin = 
(InternalPlugin)plugin;
+                        if ( internalPlugin.getId().equals(pluginClassName) ) {
+                            this.removePlugin( plugin );
+                            break;
+                        }
+                    }
+                }
+            }
+        }
     }
 
     /**
@@ -180,28 +165,26 @@ class PluginHolder implements ServiceListener
      * @return The plugin or <code>null</code> if no plugin is registered with
      *      the given label.
      */
-    AbstractWebConsolePlugin getPlugin( final String label )
-    {
+    AbstractWebConsolePlugin getPlugin( final String label ) {
         AbstractWebConsolePlugin consolePlugin = null;
-        if ( label != null && label.length() > 0 )
-        {
+
+        if ( label != null && label.length() > 0 ) {
             final Plugin plugin;
-            synchronized ( plugins )
-            {
-                plugin = plugins.get( label );
+            synchronized ( plugins ) {
+                final List<Plugin> list = plugins.get( label );
+                plugin = list != null && !list.isEmpty() ? list.get(0) : null;
             }
 
-            if ( plugin != null )
-            {
+            if ( plugin != null ) {
                 consolePlugin = plugin.getConsolePlugin();
             }
-        }
-        else
-        {
-            Plugin[] plugins = getPlugins();
-            for ( int i = 0; i < plugins.length && consolePlugin == null; i++ )
-            {
-                consolePlugin = plugins[i].getConsolePlugin();
+        } else{
+            final List<Plugin> plugins = getPlugins();
+            for(final Plugin p : plugins) {
+                consolePlugin = p.getConsolePlugin();
+                if ( consolePlugin != null ) {
+                    break;
+                }
             }
         }
 
@@ -231,13 +214,9 @@ class PluginHolder implements ServiceListener
     {
         final Map map = new HashMap();
         final Map flatMap = new HashMap();
-        Plugin[] plugins = getPlugins();
-        for ( int i = 0; i < plugins.length; i++ )
-        {
-            final Plugin plugin = plugins[i];
-
-            if ( !plugin.isEnabled() )
-            {
+        final List<Plugin> plugins = getPlugins();
+        for(final Plugin plugin : plugins) {
+            if ( !plugin.isEnabled() ) {
                 continue;
             }
 
@@ -311,46 +290,16 @@ class PluginHolder implements ServiceListener
      * Returns the bundle context of the Web Console itself.
      * @return the bundle context of the Web Console itself.
      */
-    BundleContext getBundleContext()
-    {
+    BundleContext getBundleContext() {
         return bundleContext;
     }
 
-
     /**
      * Sets the servlet context to be used to initialize plugin services
      * @param servletContext
      */
-    void setServletContext( ServletContext servletContext )
-    {
-        final Plugin[] plugin = getPlugins();
-        if ( servletContext != null )
-        {
-            this.servletContext = servletContext;
-            for ( int i = 0; i < plugin.length; i++ )
-            {
-                try
-                {
-                    plugin[i].init();
-                }
-                catch ( ServletException se )
-                {
-                    // TODO: log !!
-                }
-            }
-        }
-        else
-        {
-            for ( int i = 0; i < plugin.length; i++ )
-            {
-                try {
-                    plugin[i].destroy();
-                } catch (Throwable t) {
-                    // TODO: log !!
-                }
-            }
-            this.servletContext = null;
-        }
+    void setServletContext( final ServletContext context ) {
+        this.servletContext = context;
     }
 
 
@@ -358,339 +307,104 @@ class PluginHolder implements ServiceListener
      * Returns the servlet context to be used to initialize plugin services
      * @return the servlet context to be used to initialize plugin services
      */
-    ServletContext getServletContext()
-    {
+    ServletContext getServletContext() {
         return servletContext;
     }
 
-
-    //---------- ServletListener
-
-    /**
-     * Called when plugin services are registered or unregistered (or modified,
-     * which is currently ignored)
-     *
-     * @see 
org.osgi.framework.ServiceListener#serviceChanged(org.osgi.framework.ServiceEvent)
-     */
-    public void serviceChanged( ServiceEvent event )
-    {
-        switch ( event.getType() )
-        {
-            case ServiceEvent.REGISTERED:
-                // add service
-                serviceAdded( event.getServiceReference() );
-                break;
-
-            case ServiceEvent.UNREGISTERING:
-                // remove service
-                serviceRemoved( event.getServiceReference() );
-                break;
-
-            default:
-                // update service
-                break;
-        }
-    }
-
-
-    private void serviceAdded( final ServiceReference<?> serviceReference )
-    {
-        final String label = getProperty( serviceReference, 
WebConsoleConstants.PLUGIN_LABEL );
-        if ( label != null )
-        {
-            addPlugin( label, new ServletPlugin( this, serviceReference, label 
) );
-        }
-    }
-
-
-    private void serviceRemoved( final ServiceReference<?> serviceReference )
-    {
-        final String label = getProperty( serviceReference, 
WebConsoleConstants.PLUGIN_LABEL );
-        if ( label != null )
-        {
-            removePlugin( label );
-        }
-    }
-
-
-    private void addPlugin( final String label, final Plugin plugin )
-    {
-        synchronized ( plugins )
-        {
-            plugins.compute( label, (key, oldPlugin) -> {
-                if (oldPlugin != null) {
-                    if (plugin.compareTo(oldPlugin) > 0) {
-                        osgiManager.log(LogService.LOG_WARNING, "Overwriting 
existing plugin " + oldPlugin.doGetConsolePlugin().getClass().getName() 
-                                + " having label " + key + " with new plugin " 
+ plugin.doGetConsolePlugin().getClass().getName()
-                                + " due to higher ranking " );
-                    } else {
-                        osgiManager.log(LogService.LOG_WARNING, "Ignoring new 
plugin " + plugin.doGetConsolePlugin().getClass().getName()
-                                + " having existing label " + key + " due to 
lower ranking than old plugin " +  
oldPlugin.doGetConsolePlugin().getClass().getName() );
-                        return oldPlugin;
-                    }
+    private List<Plugin> getPlugins() {
+        final List<Plugin> plugins = new ArrayList<>();
+        synchronized ( plugins ) {
+            for(final List<Plugin> c : this.plugins.values()) {
+                if ( !c.isEmpty() ) {
+                    plugins.add(c.get(0));
                 }
-                return plugin;
-            });
-            plugins.put( label, plugin );
+            }
         }
+        return plugins;
     }
 
+    //---------- ServiceTrackerCustomizer
 
-    private void removePlugin( final String label )
-    {
-        final Plugin oldPlugin;
-        synchronized ( plugins )
-        {
-            oldPlugin = plugins.remove( label );
-        }
-
-        if ( oldPlugin != null )
-        {
-            oldPlugin.dispose();
+    @Override
+    public Plugin addingService(final ServiceReference<Servlet> reference) {
+        Plugin plugin = null;
+        final String label = getProperty( reference, 
WebConsoleConstants.PLUGIN_LABEL );
+        if ( label != null ) {
+            plugin = new ServletPlugin( this, reference, label );
+            addPlugin( plugin );
         }
+        return plugin;
     }
 
 
-    private Plugin[] getPlugins()
-    {
-        synchronized ( plugins )
-        {
-            return plugins.values().toArray( new Plugin[plugins.size()] );
-        }
+    @Override
+    public void modifiedService(final ServiceReference<Servlet> reference, 
final Plugin plugin) {
+        removedService( reference, plugin );
+        addingService(reference);
     }
 
 
-    static String getProperty( final ServiceReference<?> service, final String 
propertyName )
-    {
-        final Object property = service.getProperty( propertyName );
-        if ( property instanceof String )
-        {
-            return ( String ) property;
-        }
-
-        return null;
+    @Override
+    public void removedService(final ServiceReference<Servlet> reference, 
final Plugin plugin) {
+        removePlugin( plugin );
     }
 
-    private abstract static class Plugin implements ServletConfig, 
Comparable<Plugin>
-    {
-        private final PluginHolder holder;
-        protected final ServiceReference<?> serviceReference; // used for 
comparing conflicting services
-        private final String label;
-        private String title;
-
-        protected Plugin( final PluginHolder holder, final ServiceReference<?> 
serviceReference, final String label )
-        {
-            this.holder = holder;
-            this.serviceReference = serviceReference;
-            this.label = label;
-        }
-
-
-        void init() throws ServletException {
-        }
-
-        void destroy()
-        {
-        }
-
-        /**
-         * Cleans up this plugin when it is not used any longer. This means
-         * destroying the plugin servlet and, if it was registered as an OSGi
-         * service, ungetting the service.
-         */
-        final void dispose()
-        {
-        }
-
-        @Override
-        public int compareTo(Plugin other)
-        {
-            // serviceReference = null means internal (i.e. service.ranking=0 
and service.id=0)
-            // mostly a copy from 
org.apache.felix.framework.ServiceRegistrationImpl.ServiceReferenceImpl
-
-            Long id = serviceReference != null ? (Long) 
serviceReference.getProperty(Constants.SERVICE_ID) : 0;
-            Long otherId = other.serviceReference != null ? (Long) 
other.serviceReference.getProperty(Constants.SERVICE_ID) : 0;
-
-            if (id.equals(otherId))
-            {
-                return 0; // same service
+    private void addPlugin( final Plugin plugin ) {
+        synchronized ( plugins ) {
+            final List<Plugin> list = 
plugins.computeIfAbsent(plugin.getLabel(), k -> new ArrayList<>());
+            final Plugin oldPlugin = list.isEmpty() ? null : list.get(0);
+            list.add(plugin);
+            Collections.sort(list);
+            Collections.reverse(list);
+            final Plugin first = list.get(0);
+            if (first == plugin && oldPlugin != null) {
+                osgiManager.log(LogService.LOG_WARNING, "Overwriting existing 
plugin " + oldPlugin.getId() 
+                        + " having label " + plugin.getLabel() + " with new 
plugin " + plugin.getId()
+                        + " due to higher ranking " );
+                oldPlugin.dispose();
             }
-
-            Object rankObj = serviceReference != null ? 
serviceReference.getProperty(Constants.SERVICE_RANKING) : null;
-            Object otherObj = other.serviceReference != null ? 
other.serviceReference.getProperty(Constants.SERVICE_RANKING) : null;
-
-            // If no rank, then spec says it defaults to zero.
-            rankObj = (rankObj == null) ? new Integer(0) : rankObj;
-            otherObj = (otherObj == null) ? new Integer(0) : otherObj;
-
-            // If rank is not Integer, then spec says it defaults to zero.
-            Integer rank = (rankObj instanceof Integer)
-                ? (Integer) rankObj : new Integer(0);
-            Integer otherRank = (otherObj instanceof Integer)
-                ? (Integer) otherObj : new Integer(0);
-
-            // Sort by rank in ascending order.
-            if (rank.compareTo(otherRank) < 0)
-            {
-                return -1; // lower rank
-            }
-            else if (rank.compareTo(otherRank) > 0)
-            {
-                return 1; // higher rank
-            }
-
-            // If ranks are equal, then sort by service id in descending order.
-            return (id.compareTo(otherId) < 0) ? 1 : -1;
-        }
-
-
-        protected PluginHolder getHolder()
-        {
-            return holder;
-        }
-
-
-        Bundle getBundle()
-        {
-            return getHolder().getBundleContext().getBundle();
-        }
-
-
-        final String getLabel()
-        {
-            return label;
-        }
-
-
-        protected void setTitle( String title )
-        {
-            this.title = title;
-        }
-
-
-        final String getTitle()
-        {
-            if ( title == null )
-            {
-                final String title = doGetTitle();
-                this.title = ( title == null ) ? getLabel() : title;
+            if (first == oldPlugin) {
+                osgiManager.log(LogService.LOG_WARNING, "Ignoring new plugin " 
+ plugin.getId()
+                        + " having existing label " + plugin.getLabel() + " 
due to lower ranking than old plugin " + oldPlugin.getId() );
             }
-            return title;
-        }
-
-        protected String doGetTitle()
-        {
-            // get the service now
-            final AbstractWebConsolePlugin consolePlugin = getConsolePlugin();
-
-            // reset the title:
-            // - null if the servlet cannot be loaded
-            // - to the servlet's actual title if the servlet is loaded
-            return ( consolePlugin != null ) ? consolePlugin.getTitle() : null;
-        }
-
-        // methods added to support categories
-
-        final String getCategory() {
-               return doGetCategory();
-        }
-
-        protected String doGetCategory() {
-               // get the service now
-            final AbstractWebConsolePlugin consolePlugin = getConsolePlugin();
-            return ( consolePlugin != null ) ? consolePlugin.getCategory() : 
null;
         }
+    }
 
-        final AbstractWebConsolePlugin getConsolePlugin()
-        {
-            final AbstractWebConsolePlugin consolePlugin = 
doGetConsolePlugin();
-            if ( consolePlugin != null )
-            {
-                try
-                {
-                    init();
-                }
-                catch ( ServletException se )
-                {
-                    // TODO: log
+    private void removePlugin( final Plugin plugin ) {
+        synchronized ( plugins ) {
+            final List<Plugin> list = plugins.get( plugin.getLabel() );
+            if ( list != null ) {
+                list.remove( plugin );
+                if ( list.isEmpty() ) {
+                    plugins.remove( plugin.getLabel() );
                 }
-            } else {
-                // TODO: log !!
             }
-            return consolePlugin;
-        }
-
-        protected boolean isEnabled() {
-            return true;
-        }
-
-        protected abstract AbstractWebConsolePlugin doGetConsolePlugin();
-
-
-        protected void doUngetConsolePlugin( AbstractWebConsolePlugin 
consolePlugin )
-        {
-        }
-
-
-        //---------- ServletConfig interface
-
-        public String getInitParameter( String name )
-        {
-            return null;
-        }
-
-
-        public Enumeration<?> getInitParameterNames()
-        {
-            return new Enumeration<Object>()
-            {
-                public boolean hasMoreElements()
-                {
-                    return false;
-                }
-
-
-                public Object nextElement()
-                {
-                    throw new NoSuchElementException();
-                }
-            };
-        }
-
-
-        public ServletContext getServletContext()
-        {
-            return getHolder().getServletContext();
+            plugin.dispose();
         }
+    }
 
-
-        public String getServletName()
-        {
-            return getTitle();
+    static String getProperty( final ServiceReference<?> service, final String 
propertyName ) {
+        final Object property = service.getProperty( propertyName );
+        if ( property instanceof String ) {
+            return ( String ) property;
         }
-
-
+        return null;
     }
 
-    private static class ServletPlugin extends Plugin
-    {
+    private static class ServletPlugin extends Plugin {
 
-        ServletPlugin( final PluginHolder holder, final ServiceReference<?> 
serviceReference, final String label )
-        {
+        ServletPlugin( final PluginHolder holder, final 
ServiceReference<Servlet> serviceReference, final String label ) {
             super(holder, serviceReference, label);
         }
 
-        Bundle getBundle()
-        {
-            return serviceReference.getBundle();
+        public String getId() {
+            return this.getServiceReference().toString();
         }
 
-
         protected String doGetTitle() {
             // check service Reference
-            final String title = getProperty( serviceReference, 
WebConsoleConstants.PLUGIN_TITLE );
-            if ( title != null )
-            {
+            final String title = getProperty( this.getServiceReference(), 
WebConsoleConstants.PLUGIN_TITLE );
+            if ( title != null ) {
                 return title;
             }
 
@@ -705,28 +419,22 @@ class PluginHolder implements ServiceListener
         // added to support categories
         protected String doGetCategory() {
             // check service Reference
-            final String category = getProperty( serviceReference, 
WebConsoleConstants.PLUGIN_CATEGORY );
-            if ( category != null )
-            {
+            final String category = getProperty( this.getServiceReference(), 
WebConsoleConstants.PLUGIN_CATEGORY );
+            if ( category != null ) {
                 return category;
             }
 
             return super.doGetCategory();
         }
 
-        protected AbstractWebConsolePlugin doGetConsolePlugin()
-        {
-            Object service = getHolder().getBundleContext().getService( 
serviceReference );
-            if ( service instanceof Servlet )
-            {
+        protected AbstractWebConsolePlugin doGetConsolePlugin() {
+            final Servlet service = getHolder().getBundleContext().getService( 
this.getServiceReference() );
+            if ( service != null ) {
                 final AbstractWebConsolePlugin servlet;
-                if ( service instanceof AbstractWebConsolePlugin )
-                {
+                if ( service instanceof AbstractWebConsolePlugin ) {
                     servlet = ( AbstractWebConsolePlugin ) service;
-                }
-                else
-                {
-                    servlet = new WebConsolePluginAdapter( getLabel(), ( 
Servlet ) service, serviceReference );
+                } else {
+                    servlet = new WebConsolePluginAdapter( getLabel(), 
service, this.getServiceReference() );
                 }
 
                 return servlet;
@@ -734,119 +442,100 @@ class PluginHolder implements ServiceListener
             return null;
         }
 
-        protected void doUngetConsolePlugin( AbstractWebConsolePlugin 
consolePlugin )
-        {
-            getHolder().getBundleContext().ungetService( serviceReference );
+        protected void doUngetConsolePlugin( AbstractWebConsolePlugin 
consolePlugin ) {
+            try {
+                getHolder().getBundleContext().ungetService( 
this.getServiceReference() );
+            } catch ( final IllegalStateException ise ) {
+                // ignore - bundle context is no longer valid
+            }
         }
 
         //---------- ServletConfig overwrite (based on ServletReference)
 
-        public String getInitParameter( String name )
-        {
-            Object property = serviceReference.getProperty( name );
-            if ( property != null && !property.getClass().isArray() )
-            {
+        @Override
+        public String getInitParameter( final String name ) {
+            Object property = this.getServiceReference().getProperty( name );
+            if ( property != null && !property.getClass().isArray() ) {
                 return property.toString();
             }
 
             return super.getInitParameter( name );
         }
 
-
-        public Enumeration<?> getInitParameterNames()
-        {
-            final String[] keys = serviceReference.getPropertyKeys();
-            return new Enumeration<Object>()
-            {
+        @Override
+        public Enumeration<?> getInitParameterNames() {
+            final String[] keys = this.getServiceReference().getPropertyKeys();
+            return new Enumeration<Object>() {
                 int idx = 0;
 
-
-                public boolean hasMoreElements()
-                {
+                public boolean hasMoreElements() {
                     return idx < keys.length;
                 }
 
-
-                public Object nextElement()
-                {
-                    if ( hasMoreElements() )
-                    {
+                public Object nextElement() {
+                    if ( hasMoreElements() ) {
                         return keys[idx++];
                     }
                     throw new NoSuchElementException();
                 }
-
             };
         }
-
     }
 
-    static class InternalPlugin extends Plugin
-    {
-        final String pluginClassName;
-        final OsgiManager osgiManager;
-        AbstractWebConsolePlugin plugin;
-        boolean doLog = true;
+    static class InternalPlugin extends Plugin {
 
-        protected InternalPlugin(PluginHolder holder, OsgiManager osgiManager, 
String pluginClassName, String label)
-        {
+        private final String pluginClassName;
+        private final OsgiManager osgiManager;
+        private volatile boolean doLog = true;
+
+        protected InternalPlugin(PluginHolder holder, OsgiManager osgiManager, 
String pluginClassName, String label) {
             super(holder, null, label);
             this.osgiManager = osgiManager;
             this.pluginClassName = pluginClassName;
         }
 
+        public String getId() {
+            return this.pluginClassName;
+        }
+
         protected final boolean isEnabled() {
             // check if the plugin is enabled
             return !osgiManager.isPluginDisabled(pluginClassName);
         }
 
-        protected AbstractWebConsolePlugin doGetConsolePlugin()
-        {
-            if (null == plugin) {
-                if (!isEnabled())
-                {
-                    if (doLog)
-                    {
-                        osgiManager.log( LogService.LOG_INFO, "Ignoring plugin 
" + pluginClassName + ": Disabled by configuration" );
-                        doLog = false;
-                    }
-                    return null;
+        protected AbstractWebConsolePlugin doGetConsolePlugin() {
+            if (!isEnabled()) {
+                if (doLog) {
+                    osgiManager.log( LogService.LOG_INFO, "Ignoring plugin " + 
pluginClassName + ": Disabled by configuration" );
+                    doLog = false;
                 }
+                return null;
+            }
 
-                try
-                {
-                    Class<?> pluginClass = 
getClass().getClassLoader().loadClass(pluginClassName);
-                    plugin = (AbstractWebConsolePlugin) 
pluginClass.newInstance();
+            AbstractWebConsolePlugin plugin = null;
+            try {
+                Class<?> pluginClass = 
getClass().getClassLoader().loadClass(pluginClassName);
+                plugin = (AbstractWebConsolePlugin) 
pluginClass.getDeclaredConstructor().newInstance();
 
-                    if (plugin instanceof OsgiManagerPlugin)
-                    {
-                        ((OsgiManagerPlugin) 
plugin).activate(getBundle().getBundleContext());
-                    }
-                    doLog = true; // reset logging if it succeeded
+                if (plugin instanceof OsgiManagerPlugin) {
+                    ((OsgiManagerPlugin) 
plugin).activate(osgiManager.getBundleContext());
                 }
-                catch (Throwable t)
-                {
-                    plugin = null; // in case only activate has faled!
-                    if (doLog)
-                    {
-                        osgiManager.log( LogService.LOG_WARNING, "Failed to 
instantiate plugin " + pluginClassName, t );
-                        doLog = false;
-                    }
+                doLog = true; // reset logging if it succeeded
+            } catch (final Throwable t) {
+                plugin = null; // in case only activate has faled!
+                if (doLog) {
+                    osgiManager.log( LogService.LOG_WARNING, "Failed to 
instantiate plugin " + pluginClassName, t );
+                    doLog = false;
                 }
             }
 
             return plugin;
         }
 
-        protected void doUngetConsolePlugin(AbstractWebConsolePlugin 
consolePlugin)
-        {
-            if (consolePlugin == plugin) plugin = null;
-            if (consolePlugin instanceof OsgiManagerPlugin)
-            {
-                ((OsgiManagerPlugin) consolePlugin).deactivate();
+        protected void doUngetConsolePlugin(final AbstractWebConsolePlugin 
plugin) {
+            if (plugin instanceof OsgiManagerPlugin) {
+                ((OsgiManagerPlugin) plugin).deactivate();
             }
-            super.doUngetConsolePlugin(consolePlugin);
         }
-
     }
 }


Reply via email to