FELIX-2005 Prevent console failure in the absence of the Metatype Service API.

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@903278 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/webconsole/src/main/java/org/apache/felix/webconsole/internal/compendium/ComponentConfigurationPrinter.java b/webconsole/src/main/java/org/apache/felix/webconsole/internal/compendium/ComponentConfigurationPrinter.java
index 4d0091d..e555f69 100644
--- a/webconsole/src/main/java/org/apache/felix/webconsole/internal/compendium/ComponentConfigurationPrinter.java
+++ b/webconsole/src/main/java/org/apache/felix/webconsole/internal/compendium/ComponentConfigurationPrinter.java
@@ -103,7 +103,7 @@
 
         pw.println( "  Bundle" + component.getBundle().getSymbolicName() + " (" + component.getBundle().getBundleId()
             + ")" );
-        pw.println( "  State=" + ComponentsServlet.toStateString( component.getState() ) );
+        pw.println( "  State=" + toStateString( component.getState() ) );
         pw.println( "  DefaultState=" + ( component.isDefaultEnabled() ? "enabled" : "disabled" ) );
         pw.println( "  Activation=" + ( component.isImmediate() ? "immediate" : "delayed" ) );
 
@@ -216,7 +216,33 @@
                 pw.println( "    " + key + "=" + value );
             }
         }
-
     }
 
+
+    static String toStateString( int state )
+    {
+        switch ( state )
+        {
+            case Component.STATE_DISABLED:
+                return "disabled";
+            case Component.STATE_ENABLED:
+                return "enabled";
+            case Component.STATE_UNSATISFIED:
+                return "unsatisfied";
+            case Component.STATE_ACTIVATING:
+                return "activating";
+            case Component.STATE_ACTIVE:
+                return "active";
+            case Component.STATE_REGISTERED:
+                return "registered";
+            case Component.STATE_FACTORY:
+                return "factory";
+            case Component.STATE_DEACTIVATING:
+                return "deactivating";
+            case Component.STATE_DESTROYED:
+                return "destroyed";
+            default:
+                return String.valueOf( state );
+        }
+    }
 }
diff --git a/webconsole/src/main/java/org/apache/felix/webconsole/internal/compendium/ComponentsServlet.java b/webconsole/src/main/java/org/apache/felix/webconsole/internal/compendium/ComponentsServlet.java
index d6fba8a..20636a2 100644
--- a/webconsole/src/main/java/org/apache/felix/webconsole/internal/compendium/ComponentsServlet.java
+++ b/webconsole/src/main/java/org/apache/felix/webconsole/internal/compendium/ComponentsServlet.java
@@ -242,7 +242,7 @@
         jw.key( "name" );
         jw.value( name );
         jw.key( "state" );
-        jw.value( toStateString( state ) );
+        jw.value( ComponentConfigurationPrinter.toStateString( state ) );
 
         final String pid = ( String ) component.getProperties().get( Constants.SERVICE_PID );
         if ( pid != null )
@@ -435,33 +435,6 @@
     }
 
 
-    static String toStateString( int state )
-    {
-        switch ( state )
-        {
-            case Component.STATE_DISABLED:
-                return "disabled";
-            case Component.STATE_ENABLED:
-                return "enabled";
-            case Component.STATE_UNSATISFIED:
-                return "unsatisfied";
-            case Component.STATE_ACTIVATING:
-                return "activating";
-            case Component.STATE_ACTIVE:
-                return "active";
-            case Component.STATE_REGISTERED:
-                return "registered";
-            case Component.STATE_FACTORY:
-                return "factory";
-            case Component.STATE_DEACTIVATING:
-                return "deactivating";
-            case Component.STATE_DESTROYED:
-                return "destroyed";
-            default:
-                return String.valueOf( state );
-        }
-    }
-
     /**
      * Check if the component with the specified pid is
      * configurable
diff --git a/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/ConfigurationListener.java b/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/ConfigurationListener.java
index 14620cf..87592b2 100644
--- a/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/ConfigurationListener.java
+++ b/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/ConfigurationListener.java
@@ -19,49 +19,43 @@
 package org.apache.felix.webconsole.internal.servlet;
 
 
-import java.io.InputStream;
-import java.util.ArrayList;
 import java.util.Dictionary;
 import java.util.Hashtable;
-import java.util.TreeMap;
-
-import org.apache.felix.webconsole.AbstractWebConsolePlugin;
 import org.osgi.framework.Constants;
 import org.osgi.framework.ServiceRegistration;
 import org.osgi.service.cm.ManagedService;
-import org.osgi.service.metatype.AttributeDefinition;
-import org.osgi.service.metatype.MetaTypeProvider;
-import org.osgi.service.metatype.ObjectClassDefinition;
 
 
-class ConfigurationListener implements ManagedService, MetaTypeProvider
+class ConfigurationListener implements ManagedService
 {
 
-    private final String pid;
-
     private final OsgiManager osgiManager;
 
-    private ObjectClassDefinition ocd;
-
 
     static ServiceRegistration create( OsgiManager osgiManager )
     {
         ConfigurationListener cl = new ConfigurationListener( osgiManager );
+        return registerService( cl, new String[]
+            { ManagedService.class.getName() } );
+    }
+
+
+    static ServiceRegistration registerService( ConfigurationListener listener, final String[] serviceNames )
+    {
+        final OsgiManager osgiManager = listener.osgiManager;
 
         Dictionary props = new Hashtable();
         props.put( Constants.SERVICE_VENDOR, "The Apache Software Foundation" );
         props.put( Constants.SERVICE_DESCRIPTION, "OSGi Management Console Configuration Receiver" );
-        props.put( Constants.SERVICE_PID, cl.pid );
+        props.put( Constants.SERVICE_PID, osgiManager.getConfigurationPid() );
 
-        return osgiManager.getBundleContext().registerService( new String[]
-            { ManagedService.class.getName(), MetaTypeProvider.class.getName() }, cl, props );
+        return osgiManager.getBundleContext().registerService( serviceNames, listener, props );
     }
 
 
-    private ConfigurationListener( OsgiManager osgiManager )
+    protected ConfigurationListener( OsgiManager osgiManager )
     {
         this.osgiManager = osgiManager;
-        this.pid = osgiManager.getClass().getName();
     }
 
 
@@ -72,197 +66,4 @@
         osgiManager.updateConfiguration( config );
     }
 
-
-    //---------- MetaTypeProvider
-
-    public String[] getLocales()
-    {
-        // there is no locale support here
-        return null;
-    }
-
-
-    public ObjectClassDefinition getObjectClassDefinition( String id, String locale )
-    {
-        if ( !pid.equals( id ) )
-        {
-            return null;
-        }
-
-        if ( ocd == null )
-        {
-
-            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_DEFAULT_RENDER, "Default Page",
-                "The name of the default configuration page when invoking the OSGi Management console.",
-                OsgiManager.DEFAULT_PAGE ) );
-            adList.add( new AttributeDefinitionImpl( OsgiManager.PROP_REALM, "Realm",
-                "The name of the HTTP Authentication Realm.", OsgiManager.DEFAULT_REALM ) );
-            adList
-                .add( new AttributeDefinitionImpl(
-                    OsgiManager.PROP_USER_NAME,
-                    "User Name",
-                    "The name of the user allowed to access the OSGi Management Console. To disable authentication clear this value.",
-                    OsgiManager.DEFAULT_USER_NAME ) );
-            adList.add( new AttributeDefinitionImpl( OsgiManager.PROP_PASSWORD, "Password",
-                "The password for the user allowed to access the OSGi Management Console.",
-                OsgiManager.DEFAULT_PASSWORD ) );
-
-            final TreeMap namesByClassName = new TreeMap();
-            final ClassLoader loader = getClass().getClassLoader();
-            final String[] defaultPluginsClasses = OsgiManager.PLUGIN_CLASSES;
-            for ( int i = 0; i < defaultPluginsClasses.length; i++ )
-            {
-                try
-                {
-                    final Object plugin = loader.loadClass( defaultPluginsClasses[i] ).newInstance();
-                    if ( plugin instanceof AbstractWebConsolePlugin )
-                    {
-                        final String name = ( ( AbstractWebConsolePlugin ) plugin ).getTitle();
-                        namesByClassName.put( defaultPluginsClasses[i], name );
-                    }
-                }
-                catch ( Throwable t )
-                {
-                    // ignore
-                }
-            }
-            final String[] classes = ( String[] ) namesByClassName.keySet().toArray(
-                new String[namesByClassName.size()] );
-            final String[] names = ( String[] ) namesByClassName.values().toArray( new String[namesByClassName.size()] );
-
-            adList.add( new AttributeDefinitionImpl( OsgiManager.PROP_ENABLED_PLUGINS, "Plugins",
-                "Select active plugins", AttributeDefinition.STRING, classes, Integer.MIN_VALUE, names, classes ) );
-
-            ocd = new ObjectClassDefinition()
-            {
-
-                private final AttributeDefinition[] attrs = ( AttributeDefinition[] ) adList
-                    .toArray( new AttributeDefinition[adList.size()] );
-
-
-                public String getName()
-                {
-                    return "Apache Felix OSGi Management Console";
-                }
-
-
-                public InputStream getIcon( int arg0 )
-                {
-                    return null;
-                }
-
-
-                public String getID()
-                {
-                    return pid;
-                }
-
-
-                public String getDescription()
-                {
-                    return "Configuration of the Apache Felix OSGi Management Console.";
-                }
-
-
-                public AttributeDefinition[] getAttributeDefinitions( int filter )
-                {
-                    return ( filter == OPTIONAL ) ? null : attrs;
-                }
-            };
-        }
-
-        return ocd;
-    }
-
-    private static class AttributeDefinitionImpl implements AttributeDefinition
-    {
-
-        private final String id;
-        private final String name;
-        private final String description;
-        private final int type;
-        private final String[] defaultValues;
-        private final int cardinality;
-        private final String[] optionLabels;
-        private final String[] optionValues;
-
-
-        AttributeDefinitionImpl( final String id, final String name, final String description, final String defaultValue )
-        {
-            this( id, name, description, STRING, new String[]
-                { defaultValue }, 0, null, null );
-        }
-
-
-        AttributeDefinitionImpl( final String id, final String name, final String description, final int type,
-            final String[] defaultValues, final int cardinality, final String[] optionLabels,
-            final String[] optionValues )
-        {
-            this.id = id;
-            this.name = name;
-            this.description = description;
-            this.type = type;
-            this.defaultValues = defaultValues;
-            this.cardinality = cardinality;
-            this.optionLabels = optionLabels;
-            this.optionValues = optionValues;
-        }
-
-
-        public int getCardinality()
-        {
-            return cardinality;
-        }
-
-
-        public String[] getDefaultValue()
-        {
-            return defaultValues;
-        }
-
-
-        public String getDescription()
-        {
-            return description;
-        }
-
-
-        public String getID()
-        {
-            return id;
-        }
-
-
-        public String getName()
-        {
-            return name;
-        }
-
-
-        public String[] getOptionLabels()
-        {
-            return optionLabels;
-        }
-
-
-        public String[] getOptionValues()
-        {
-            return optionValues;
-        }
-
-
-        public int getType()
-        {
-            return type;
-        }
-
-
-        public String validate( String arg0 )
-        {
-            return null;
-        }
-    }
 }
\ No newline at end of file
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
new file mode 100644
index 0000000..78b0506
--- /dev/null
+++ b/webconsole/src/main/java/org/apache/felix/webconsole/internal/servlet/ConfigurationListener2.java
@@ -0,0 +1,249 @@
+/*
+ * 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.io.InputStream;
+import java.util.ArrayList;
+import java.util.TreeMap;
+
+import org.apache.felix.webconsole.AbstractWebConsolePlugin;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.cm.ManagedService;
+import org.osgi.service.metatype.AttributeDefinition;
+import org.osgi.service.metatype.MetaTypeProvider;
+import org.osgi.service.metatype.ObjectClassDefinition;
+
+
+class ConfigurationListener2 extends ConfigurationListener implements MetaTypeProvider
+{
+
+    private final String pid;
+
+    private ObjectClassDefinition ocd;
+
+
+    static ServiceRegistration create( OsgiManager osgiManager )
+    {
+        ConfigurationListener2 cl = new ConfigurationListener2( osgiManager );
+        return registerService( cl, new String[]
+            { ManagedService.class.getName(), MetaTypeProvider.class.getName() } );
+    }
+
+
+    private ConfigurationListener2( OsgiManager osgiManager )
+    {
+        super( osgiManager );
+        this.pid = osgiManager.getConfigurationPid();
+    }
+
+
+    //---------- MetaTypeProvider
+
+    public String[] getLocales()
+    {
+        // there is no locale support here
+        return null;
+    }
+
+
+    public ObjectClassDefinition getObjectClassDefinition( String id, String locale )
+    {
+        if ( !pid.equals( id ) )
+        {
+            return null;
+        }
+
+        if ( ocd == null )
+        {
+
+            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_DEFAULT_RENDER, "Default Page",
+                "The name of the default configuration page when invoking the OSGi Management console.",
+                OsgiManager.DEFAULT_PAGE ) );
+            adList.add( new AttributeDefinitionImpl( OsgiManager.PROP_REALM, "Realm",
+                "The name of the HTTP Authentication Realm.", OsgiManager.DEFAULT_REALM ) );
+            adList
+                .add( new AttributeDefinitionImpl(
+                    OsgiManager.PROP_USER_NAME,
+                    "User Name",
+                    "The name of the user allowed to access the OSGi Management Console. To disable authentication clear this value.",
+                    OsgiManager.DEFAULT_USER_NAME ) );
+            adList.add( new AttributeDefinitionImpl( OsgiManager.PROP_PASSWORD, "Password",
+                "The password for the user allowed to access the OSGi Management Console.",
+                OsgiManager.DEFAULT_PASSWORD ) );
+
+            final TreeMap namesByClassName = new TreeMap();
+            final ClassLoader loader = getClass().getClassLoader();
+            final String[] defaultPluginsClasses = OsgiManager.PLUGIN_CLASSES;
+            for ( int i = 0; i < defaultPluginsClasses.length; i++ )
+            {
+                try
+                {
+                    final Object plugin = loader.loadClass( defaultPluginsClasses[i] ).newInstance();
+                    if ( plugin instanceof AbstractWebConsolePlugin )
+                    {
+                        final String name = ( ( AbstractWebConsolePlugin ) plugin ).getTitle();
+                        namesByClassName.put( defaultPluginsClasses[i], name );
+                    }
+                }
+                catch ( Throwable t )
+                {
+                    // ignore
+                }
+            }
+            final String[] classes = ( String[] ) namesByClassName.keySet().toArray(
+                new String[namesByClassName.size()] );
+            final String[] names = ( String[] ) namesByClassName.values().toArray( new String[namesByClassName.size()] );
+
+            adList.add( new AttributeDefinitionImpl( OsgiManager.PROP_ENABLED_PLUGINS, "Plugins",
+                "Select active plugins", AttributeDefinition.STRING, classes, Integer.MIN_VALUE, names, classes ) );
+
+            ocd = new ObjectClassDefinition()
+            {
+
+                private final AttributeDefinition[] attrs = ( AttributeDefinition[] ) adList
+                    .toArray( new AttributeDefinition[adList.size()] );
+
+
+                public String getName()
+                {
+                    return "Apache Felix OSGi Management Console";
+                }
+
+
+                public InputStream getIcon( int arg0 )
+                {
+                    return null;
+                }
+
+
+                public String getID()
+                {
+                    return pid;
+                }
+
+
+                public String getDescription()
+                {
+                    return "Configuration of the Apache Felix OSGi Management Console.";
+                }
+
+
+                public AttributeDefinition[] getAttributeDefinitions( int filter )
+                {
+                    return ( filter == OPTIONAL ) ? null : attrs;
+                }
+            };
+        }
+
+        return ocd;
+    }
+
+    private static class AttributeDefinitionImpl implements AttributeDefinition
+    {
+
+        private final String id;
+        private final String name;
+        private final String description;
+        private final int type;
+        private final String[] defaultValues;
+        private final int cardinality;
+        private final String[] optionLabels;
+        private final String[] optionValues;
+
+
+        AttributeDefinitionImpl( final String id, final String name, final String description, final String defaultValue )
+        {
+            this( id, name, description, STRING, new String[]
+                { defaultValue }, 0, null, null );
+        }
+
+
+        AttributeDefinitionImpl( final String id, final String name, final String description, final int type,
+            final String[] defaultValues, final int cardinality, final String[] optionLabels,
+            final String[] optionValues )
+        {
+            this.id = id;
+            this.name = name;
+            this.description = description;
+            this.type = type;
+            this.defaultValues = defaultValues;
+            this.cardinality = cardinality;
+            this.optionLabels = optionLabels;
+            this.optionValues = optionValues;
+        }
+
+
+        public int getCardinality()
+        {
+            return cardinality;
+        }
+
+
+        public String[] getDefaultValue()
+        {
+            return defaultValues;
+        }
+
+
+        public String getDescription()
+        {
+            return description;
+        }
+
+
+        public String getID()
+        {
+            return id;
+        }
+
+
+        public String getName()
+        {
+            return name;
+        }
+
+
+        public String[] getOptionLabels()
+        {
+            return optionLabels;
+        }
+
+
+        public String[] getOptionValues()
+        {
+            return optionValues;
+        }
+
+
+        public int getType()
+        {
+            return type;
+        }
+
+
+        public String validate( String arg0 )
+        {
+            return null;
+        }
+    }
+}
\ No newline at end of file
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 8f245bf..0f2d6b8 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
@@ -199,11 +199,20 @@
 
         try
         {
-            this.configurationListener = ConfigurationListener.create( this );
+            this.configurationListener = ConfigurationListener2.create( this );
         }
-        catch ( Throwable t )
+        catch ( Throwable t2 )
         {
-            // might be caused by CM not available
+            // might be caused by Metatype API not available
+            // try without MetaTypeProvider
+            try
+            {
+                this.configurationListener = ConfigurationListener.create( this );
+            }
+            catch ( Throwable t )
+            {
+                // might be caused by CM API not available
+            }
         }
 
         // get at the HttpService first, this should initialize
@@ -474,6 +483,16 @@
     }
 
 
+    /**
+     * Returns the Service PID used to retrieve configuration and to describe
+     * the configuration properties.
+     */
+    String getConfigurationPid()
+    {
+        return getClass().getName();
+    }
+
+
     private HttpServletResponse wrapResponse( final HttpServletRequest request, final HttpServletResponse response,
         final AbstractWebConsolePlugin plugin )
     {