FELIX-2099 Cleanup loggging: All logging now goes through the GenericServlet.log methods where the AbstractWebConsolePlugin provides log methods taking a log level used to filter log messages on a log level configurable for all web console plugins. Removing the now unused Logger and BaseManagementPlugin classes. Simplifying the BasedUpdateInstallHelper and its extension classes using a SimpleWebConsolePlugin as its basis for logging and service access. Add configuration option (loglevel) to configure the loglevel message filter.

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@922540 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/webconsole/src/main/java/org/apache/felix/webconsole/AbstractWebConsolePlugin.java b/webconsole/src/main/java/org/apache/felix/webconsole/AbstractWebConsolePlugin.java
index 2d4a601..eb40bdc 100644
--- a/webconsole/src/main/java/org/apache/felix/webconsole/AbstractWebConsolePlugin.java
+++ b/webconsole/src/main/java/org/apache/felix/webconsole/AbstractWebConsolePlugin.java
@@ -95,6 +95,9 @@
 
     private static BrandingPlugin brandingPlugin = DefaultBrandingPlugin.getInstance();
 
+    private static int logLevel;
+
+
     //---------- HttpServlet Overwrites ----------------------------------------
 
     /**
@@ -155,7 +158,6 @@
         }
     }
 
-
     /**
      * Detects whether this request is intended to have the headers and
      * footers of this plugin be rendered or not. This method always returns
@@ -369,6 +371,50 @@
 
 
     /**
+     * Calls the <code>GenericServlet.log(String)</code> method if the
+     * configured log level is less than or equal to the given <code>level</code>.
+     * <p>
+     * Note, that the <code>level</code> paramter is only used to decide whether
+     * the <code>GenericServlet.log(String)</code> method is called or not. The
+     * actual implementation of the <code>GenericServlet.log</code> method is
+     * outside of the control of this method.
+     *
+     * @param level The log level at which to log the message
+     * @param message The message to log
+     */
+    public void log( int level, String message )
+    {
+        if ( logLevel >= level )
+        {
+            log( message );
+        }
+    }
+
+
+    /**
+     * Calls the <code>GenericServlet.log(String, Throwable)</code> method if
+     * the configured log level is less than or equal to the given
+     * <code>level</code>.
+     * <p>
+     * Note, that the <code>level</code> paramter is only used to decide whether
+     * the <code>GenericServlet.log(String, Throwable)</code> method is called
+     * or not. The actual implementation of the <code>GenericServlet.log</code>
+     * method is outside of the control of this method.
+     *
+     * @param level The log level at which to log the message
+     * @param message The message to log
+     * @param t The <code>Throwable</code> to log with the message
+     */
+    public void log( int level, String message, Throwable t )
+    {
+        if ( logLevel >= level )
+        {
+            log( message, t );
+        }
+    }
+
+
+    /**
      * If the request addresses a resource which may be served by the
      * <code>getResource</code> method of the
      * {@link #getResourceProvider() resource provider}, this method serves it
@@ -546,13 +592,13 @@
                     }
                     else
                     {
-                        map.put( labelMapEntry.getValue(), "<div class='ui-state-active'><span>" + labelMapEntry.getValue() 
+                        map.put( labelMapEntry.getValue(), "<div class='ui-state-active'><span>" + labelMapEntry.getValue()
                             + "</span></div>");
                     }
                 }
                 else
                 {
-                    map.put( labelMapEntry.getValue(), "<div class='ui-state-default'><a href='" + appRoot + "/" + labelMapEntry.getKey() + "'>" 
+                    map.put( labelMapEntry.getValue(), "<div class='ui-state-default'><a href='" + appRoot + "/" + labelMapEntry.getKey() + "'>"
                         + labelMapEntry.getValue() + "</a></div>");
                 }
             }
@@ -622,6 +668,9 @@
     }
 
     /**
+     * Returns the {@link BrandingPlugin} currently used for web console
+     * branding.
+     *
      * @return the brandingPlugin
      */
     public static BrandingPlugin getBrandingPlugin() {
@@ -629,6 +678,12 @@
     }
 
     /**
+     * Sets the {@link BrandingPlugin} to use globally by all extensions of
+     * this class for branding.
+     * <p>
+     * Note: This method is intended to be used internally by the Web Console
+     * to update the branding plugin to use.
+     *
      * @param brandingPlugin the brandingPlugin to set
      */
     public static final void setBrandingPlugin(BrandingPlugin brandingPlugin) {
@@ -640,6 +695,21 @@
     }
 
 
+    /**
+     * Sets the log level to be applied for calls to the {@link #log(int, String)}
+     * and {@link #log(int, String, Throwable)} methods.
+     * <p>
+     * Note: This method is intended to be used internally by the Web Console
+     * to update the log level according to the Web Console configuration.
+     *
+     * @param logLevel
+     */
+    public static final void setLogLevel( int logLevel )
+    {
+        AbstractWebConsolePlugin.logLevel = logLevel;
+    }
+
+
     private final String getHeader()
     {
         // MessageFormat pattern place holder
diff --git a/webconsole/src/main/java/org/apache/felix/webconsole/SimpleWebConsolePlugin.java b/webconsole/src/main/java/org/apache/felix/webconsole/SimpleWebConsolePlugin.java
index f41ba98..8bb3a60 100644
--- a/webconsole/src/main/java/org/apache/felix/webconsole/SimpleWebConsolePlugin.java
+++ b/webconsole/src/main/java/org/apache/felix/webconsole/SimpleWebConsolePlugin.java
@@ -188,7 +188,7 @@
      * @param serviceName the service name to obtain
      * @return the service or <code>null</code> if missing.
      */
-    protected final Object getService( String serviceName )
+    public final Object getService( String serviceName )
     {
         ServiceTracker serviceTracker = ( ServiceTracker ) services.get( serviceName );
         if ( serviceTracker == null )
diff --git a/webconsole/src/main/java/org/apache/felix/webconsole/internal/BaseManagementPlugin.java b/webconsole/src/main/java/org/apache/felix/webconsole/internal/BaseManagementPlugin.java
deleted file mode 100644
index d38b03c..0000000
--- a/webconsole/src/main/java/org/apache/felix/webconsole/internal/BaseManagementPlugin.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * 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;
-
-
-import org.osgi.framework.BundleContext;
-import org.osgi.service.packageadmin.PackageAdmin;
-import org.osgi.service.startlevel.StartLevel;
-import org.osgi.util.tracker.ServiceTracker;
-
-
-public class BaseManagementPlugin implements OsgiManagerPlugin
-{
-
-    private BundleContext bundleContext;
-    private Logger log;
-
-    private ServiceTracker startLevelService;
-
-    private ServiceTracker packageAdmin;
-
-
-    protected BaseManagementPlugin()
-    {
-    }
-
-
-    public void activate( BundleContext bundleContext )
-    {
-        this.bundleContext = bundleContext;
-        this.log = new Logger( bundleContext );
-    }
-
-
-    public void deactivate()
-    {
-        if ( log != null )
-        {
-            log.dispose();
-        }
-
-        if ( startLevelService != null )
-        {
-            startLevelService.close();
-            startLevelService = null;
-        }
-
-        if ( packageAdmin != null )
-        {
-            packageAdmin.close();
-            packageAdmin = null;
-        }
-    }
-
-
-    protected BundleContext getBundleContext()
-    {
-        return bundleContext;
-    }
-
-
-    protected Logger getLog()
-    {
-        return log;
-    }
-
-
-    protected StartLevel getStartLevel()
-    {
-        if ( startLevelService == null )
-        {
-            startLevelService = new ServiceTracker( getBundleContext(), StartLevel.class.getName(), null );
-            startLevelService.open();
-        }
-        return ( StartLevel ) startLevelService.getService();
-    }
-
-
-    protected PackageAdmin getPackageAdmin()
-    {
-        if ( packageAdmin == null )
-        {
-            packageAdmin = new ServiceTracker( getBundleContext(), PackageAdmin.class.getName(), null );
-            packageAdmin.open();
-        }
-        return ( PackageAdmin ) packageAdmin.getService();
-    }
-
-}
diff --git a/webconsole/src/main/java/org/apache/felix/webconsole/internal/Logger.java b/webconsole/src/main/java/org/apache/felix/webconsole/internal/Logger.java
deleted file mode 100644
index 8d2f0c5..0000000
--- a/webconsole/src/main/java/org/apache/felix/webconsole/internal/Logger.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * 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;
-
-
-import org.osgi.framework.BundleContext;
-import org.osgi.service.log.LogService;
-import org.osgi.util.tracker.ServiceTracker;
-
-
-public class Logger
-{
-
-    private static final String LOGSERVICE_NAME = "org.osgi.service.log.LogService";
-    
-    private ServiceTracker logTracker;
-
-
-    public Logger( BundleContext bundleContext )
-    {
-        logTracker = new ServiceTracker( bundleContext, LOGSERVICE_NAME, null );
-        logTracker.open();
-    }
-
-
-    public void dispose()
-    {
-        if ( logTracker != null )
-        {
-            logTracker.close();
-        }
-    }
-
-
-    public void log( int logLevel, String message )
-    {
-        log( logLevel, message, null );
-    }
-
-
-    public void log( int logLevel, String message, Throwable t )
-    {
-        Object log = logTracker.getService();
-        if ( log != null )
-        {
-            ( ( LogService ) log ).log( logLevel, message, t );
-        }
-        else
-        {
-            String level;
-            switch ( logLevel )
-            {
-                case LogService.LOG_DEBUG:
-                    level = "*DEBUG*";
-                    break;
-                case LogService.LOG_INFO:
-                    level = "*INFO *";
-                    break;
-                case LogService.LOG_WARNING:
-                    level = "*WARN *";
-                    break;
-                case LogService.LOG_ERROR:
-                    level = "*ERROR*";
-                    break;
-                default:
-                    level = "*" + logLevel + "*";
-                    break;
-            }
-
-            if ( message == null && t != null )
-            {
-                message = t.getMessage();
-            }
-
-            System.out.println( level + " " + message );
-            if ( t != null )
-            {
-                t.printStackTrace( System.out );
-            }
-        }
-    }
-}
diff --git a/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/BaseUpdateInstallHelper.java b/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/BaseUpdateInstallHelper.java
index 1790843..654faf4 100644
--- a/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/BaseUpdateInstallHelper.java
+++ b/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/BaseUpdateInstallHelper.java
@@ -21,11 +21,10 @@
 
 import java.io.File;
 import java.io.FileInputStream;
-import java.io.IOException;
 import java.io.InputStream;
 
 import org.apache.commons.io.IOUtils;
-import org.apache.felix.webconsole.internal.Logger;
+import org.apache.felix.webconsole.SimpleWebConsolePlugin;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleException;
 import org.osgi.service.log.LogService;
@@ -35,6 +34,8 @@
 abstract class BaseUpdateInstallHelper implements Runnable
 {
 
+    private final SimpleWebConsolePlugin plugin;
+
     private final File bundleFile;
 
     private final boolean refreshPackages;
@@ -42,8 +43,9 @@
     private Thread updateThread;
 
 
-    BaseUpdateInstallHelper( String name, File bundleFile, boolean refreshPackages )
+    BaseUpdateInstallHelper( SimpleWebConsolePlugin plugin, String name, File bundleFile, boolean refreshPackages )
     {
+        this.plugin = plugin;
         this.bundleFile = bundleFile;
         this.refreshPackages = refreshPackages;
         this.updateThread = new Thread( this, name );
@@ -60,10 +62,16 @@
     protected abstract Bundle doRun( InputStream bundleStream ) throws BundleException;
 
 
-    protected abstract Logger getLog();
+    protected final Object getService( String serviceName )
+    {
+        return plugin.getService( serviceName );
+    }
 
 
-    protected abstract Object getService( String serviceName );
+    protected final SimpleWebConsolePlugin getLog()
+    {
+        return plugin;
+    }
 
 
     /**
diff --git a/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/BundlesServlet.java b/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/BundlesServlet.java
index 03b405f..438012a 100644
--- a/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/BundlesServlet.java
+++ b/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/BundlesServlet.java
@@ -54,7 +54,6 @@
 import org.apache.felix.webconsole.SimpleWebConsolePlugin;
 import org.apache.felix.webconsole.WebConsoleConstants;
 import org.apache.felix.webconsole.WebConsoleUtil;
-import org.apache.felix.webconsole.internal.Logger;
 import org.apache.felix.webconsole.internal.OsgiManagerPlugin;
 import org.apache.felix.webconsole.internal.Util;
 import org.json.JSONArray;
@@ -1307,20 +1306,7 @@
 
     private void update( final Bundle bundle )
     {
-        UpdateHelper t = new UpdateHelper( bundle, false )
-        {
-            protected Logger getLog()
-            {
-                return BundlesServlet.this.getLog();
-            }
-
-
-            protected Object getService( String serviceName )
-            {
-                return BundlesServlet.this.getService( serviceName );
-            }
-        };
-
+        UpdateHelper t = new UpdateHelper( this, bundle, false );
         t.start();
     }
 
@@ -1386,18 +1372,6 @@
         return ( StartLevel ) getService( StartLevel.class.getName() );
     }
 
-    // TODO: may remove later, when BaseWebConsolePlugin is made to extend SimpleWebConsolePlugin
-    private Logger log;
-    Logger getLog()
-    {
-        if ( log == null )
-        {
-            log = new Logger( getBundleContext() );
-        }
-
-        return log;
-    }
-
 
     //---------- Bundle Installation handler (former InstallAction)
 
@@ -1436,8 +1410,8 @@
             }
             catch ( NumberFormatException nfe )
             {
-                getLog().log( LogService.LOG_INFO,
-                    "Cannot parse start level parameter " + startLevelItem + " to a number, not setting start level" );
+                log( LogService.LOG_INFO, "Cannot parse start level parameter " + startLevelItem
+                    + " to a number, not setting start level" );
             }
         }
 
@@ -1454,8 +1428,7 @@
             }
             catch ( Exception e )
             {
-                getLog().log( LogService.LOG_ERROR, "Problem accessing uploaded bundle file: " + bundleItem.getName(),
-                    e );
+                log( LogService.LOG_ERROR, "Problem accessing uploaded bundle file: " + bundleItem.getName(), e );
 
                 // remove the tmporary file
                 if ( tmpFile != null )
@@ -1581,7 +1554,7 @@
         }
         catch ( IOException ioe )
         {
-            getLog().log( LogService.LOG_WARNING, "Cannot extract symbolic name of bundle file " + bundleFile, ioe );
+            log( LogService.LOG_WARNING, "Cannot extract symbolic name of bundle file " + bundleFile, ioe );
         }
         finally
         {
@@ -1607,55 +1580,15 @@
         final boolean doStart, final boolean refreshPackages )
     {
 
-        InstallHelper t = new InstallHelper( getBundleContext(), bundleFile, location, startlevel, doStart,
-            refreshPackages )
-        {
-            protected Logger getLog()
-            {
-                return BundlesServlet.this.getLog();
-            }
-
-
-            protected Object getService( String serviceName )
-            {
-                if ( serviceName.equals( PackageAdmin.class.getName() ) )
-                {
-                    return BundlesServlet.this.getPackageAdmin();
-                }
-                else if ( serviceName.equals( StartLevel.class.getName() ) )
-                {
-                    return BundlesServlet.this.getStartLevel();
-                }
-
-                return null;
-            }
-        };
-
+        InstallHelper t = new InstallHelper( this, getBundleContext(), bundleFile, location, startlevel, doStart,
+            refreshPackages );
         t.start();
     }
 
 
     private void updateBackground( final Bundle bundle, final File bundleFile, final boolean refreshPackages )
     {
-        UpdateHelper t = new UpdateHelper( bundle, bundleFile, refreshPackages )
-        {
-            protected Logger getLog()
-            {
-                return BundlesServlet.this.getLog();
-            }
-
-
-            protected Object getService( String serviceName )
-            {
-                if ( serviceName.equals( PackageAdmin.class.getName() ) )
-                {
-                    return BundlesServlet.this.getPackageAdmin();
-                }
-
-                return null;
-            }
-        };
-
+        UpdateHelper t = new UpdateHelper( this, bundle, bundleFile, refreshPackages );
         t.start();
     }
 }
diff --git a/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/InstallHelper.java b/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/InstallHelper.java
index 2003b47..9b64f93 100644
--- a/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/InstallHelper.java
+++ b/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/InstallHelper.java
@@ -22,23 +22,25 @@
 import java.io.File;
 import java.io.InputStream;
 
+import org.apache.felix.webconsole.SimpleWebConsolePlugin;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.BundleException;
 import org.osgi.service.startlevel.StartLevel;
 
 
-abstract class InstallHelper extends BaseUpdateInstallHelper
+class InstallHelper extends BaseUpdateInstallHelper
 {
     private final BundleContext bundleContext;
     private final String location;
     private final int startlevel;
     private final boolean doStart;
 
-    InstallHelper( final BundleContext bundleContext, final File bundleFile, final String location, final int startlevel,
-        final boolean doStart, final boolean refreshPackages )
+
+    InstallHelper( final SimpleWebConsolePlugin plugin, final BundleContext bundleContext, final File bundleFile,
+        final String location, final int startlevel, final boolean doStart, final boolean refreshPackages )
     {
-        super( "Background Install " + bundleFile, bundleFile, refreshPackages );
+        super( plugin, "Background Install " + bundleFile, bundleFile, refreshPackages );
 
         this.bundleContext = bundleContext;
         this.location = location;
diff --git a/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/UpdateHelper.java b/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/UpdateHelper.java
index 93ec6b6..1b47bd7 100644
--- a/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/UpdateHelper.java
+++ b/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/UpdateHelper.java
@@ -20,14 +20,12 @@
 
 
 import java.io.File;
-import java.io.IOException;
 import java.io.InputStream;
-import java.net.URL;
 
-import org.apache.commons.io.IOUtils;
 import org.apache.felix.bundlerepository.RepositoryAdmin;
 import org.apache.felix.bundlerepository.Resolver;
 import org.apache.felix.bundlerepository.Resource;
+import org.apache.felix.webconsole.SimpleWebConsolePlugin;
 import org.apache.felix.webconsole.internal.obr.DeployerThread;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleException;
@@ -36,22 +34,23 @@
 import org.osgi.service.log.LogService;
 
 
-abstract class UpdateHelper extends BaseUpdateInstallHelper
+class UpdateHelper extends BaseUpdateInstallHelper
 {
 
     private final Bundle bundle;
 
 
-    UpdateHelper( final Bundle bundle, boolean refreshPackages )
+    UpdateHelper( final SimpleWebConsolePlugin plugin, final Bundle bundle, boolean refreshPackages )
     {
-        this( bundle, null, refreshPackages );
+        this( plugin, bundle, null, refreshPackages );
     }
 
 
-    UpdateHelper( final Bundle bundle, final File bundleFile, boolean refreshPackages )
+    UpdateHelper( final SimpleWebConsolePlugin plugin, final Bundle bundle, final File bundleFile,
+        boolean refreshPackages )
     {
-        super( "Background Update " + bundle.getSymbolicName() + " (" + bundle.getBundleId() + ")", bundleFile,
-            refreshPackages );
+        super( plugin, "Background Update " + bundle.getSymbolicName() + " (" + bundle.getBundleId() + ")",
+            bundleFile, refreshPackages );
         this.bundle = bundle;
     }
 
diff --git a/webconsole/src/main/java/org/apache/felix/webconsole/internal/obr/BundleRepositoryRender.java b/webconsole/src/main/java/org/apache/felix/webconsole/internal/obr/BundleRepositoryRender.java
index 500db13..324c90b 100644
--- a/webconsole/src/main/java/org/apache/felix/webconsole/internal/obr/BundleRepositoryRender.java
+++ b/webconsole/src/main/java/org/apache/felix/webconsole/internal/obr/BundleRepositoryRender.java
@@ -19,11 +19,7 @@
 package org.apache.felix.webconsole.internal.obr;
 
 import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Enumeration;
-import java.util.List;
-
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
@@ -34,7 +30,6 @@
 import org.apache.felix.webconsole.DefaultVariableResolver;
 import org.apache.felix.webconsole.SimpleWebConsolePlugin;
 import org.apache.felix.webconsole.WebConsoleUtil;
-import org.apache.felix.webconsole.internal.Logger;
 import org.apache.felix.webconsole.internal.OsgiManagerPlugin;
 import org.json.JSONException;
 import org.json.JSONObject;
@@ -324,12 +319,12 @@
                 }
             }
 
-            DeployerThread dt = new DeployerThread(resolver, new Logger(getBundleContext()), start, optional);
+            DeployerThread dt = new DeployerThread( resolver, this, start, optional );
             dt.start();
         }
         catch (InvalidSyntaxException e)
         {
-            throw new IllegalStateException(e); 
+            throw new IllegalStateException(e);
         }
     }
 
diff --git a/webconsole/src/main/java/org/apache/felix/webconsole/internal/obr/DeployerThread.java b/webconsole/src/main/java/org/apache/felix/webconsole/internal/obr/DeployerThread.java
index 0e193eb..d814bb8 100644
--- a/webconsole/src/main/java/org/apache/felix/webconsole/internal/obr/DeployerThread.java
+++ b/webconsole/src/main/java/org/apache/felix/webconsole/internal/obr/DeployerThread.java
@@ -22,7 +22,7 @@
 import org.apache.felix.bundlerepository.Reason;
 import org.apache.felix.bundlerepository.Resolver;
 import org.apache.felix.bundlerepository.Resource;
-import org.apache.felix.webconsole.internal.Logger;
+import org.apache.felix.webconsole.AbstractWebConsolePlugin;
 import org.osgi.service.log.LogService;
 
 
@@ -31,20 +31,22 @@
 
     private final Resolver obrResolver;
 
-    private final Logger logger;
+    private final AbstractWebConsolePlugin logger;
 
     private final boolean startBundles;
 
     private final boolean optionalDependencies;
 
 
-    public DeployerThread( Resolver obrResolver, Logger logger, boolean startBundles, boolean optionalDependencies )
+    public DeployerThread( Resolver obrResolver, AbstractWebConsolePlugin logger, boolean startBundles,
+        boolean optionalDependencies )
     {
         this( obrResolver, logger, startBundles, optionalDependencies, "OBR Bundle Deployer" );
     }
 
 
-    public DeployerThread( Resolver obrResolver, Logger logger, boolean startBundles, boolean optionalDependencies, String name )
+    public DeployerThread( Resolver obrResolver, AbstractWebConsolePlugin logger, boolean startBundles,
+        boolean optionalDependencies, String name )
     {
         super( name );
         this.obrResolver = obrResolver;
@@ -83,7 +85,7 @@
     }
 
 
-    public static void logResource( Logger logger, String message, Resource[] res )
+    public static void logResource( AbstractWebConsolePlugin logger, String message, Resource[] res )
     {
         if ( res != null && res.length > 0 )
         {
@@ -97,7 +99,7 @@
     }
 
 
-    public static void logRequirements( Logger logger, String message, Reason[] reasons )
+    public static void logRequirements( AbstractWebConsolePlugin logger, String message, Reason[] reasons )
     {
         logger.log( LogService.LOG_ERROR, message );
         for ( int i = 0; reasons != null && i < reasons.length; i++ )
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 65f9441..14cbfec 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
@@ -90,6 +90,11 @@
             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_LOG_LEVEL, "Log Level", "Logging Level",
+                AttributeDefinition.INTEGER, new String[]
+                    { String.valueOf( OsgiManager.DEFAULT_LOG_LEVEL ) }, 0, new String[]
+                    { "Debug", "Information", "Warn", "Error" }, new String[]
+                    { "4", "3", "2", "1" } ) );
 
             final TreeMap namesByClassName = new TreeMap();
             final ClassLoader loader = getClass().getClassLoader();
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 83d5ac9..7b1c621 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
@@ -40,7 +40,6 @@
 import org.apache.felix.webconsole.AbstractWebConsolePlugin;
 import org.apache.felix.webconsole.BrandingPlugin;
 import org.apache.felix.webconsole.WebConsoleConstants;
-import org.apache.felix.webconsole.internal.Logger;
 import org.apache.felix.webconsole.internal.OsgiManagerPlugin;
 import org.apache.felix.webconsole.internal.WebConsolePluginAdapter;
 import org.apache.felix.webconsole.internal.core.BundlesServlet;
@@ -104,6 +103,10 @@
 
     static final String PROP_ENABLED_PLUGINS = "plugins";
 
+    static final String PROP_LOG_LEVEL = "loglevel";
+
+    public static final int DEFAULT_LOG_LEVEL = LogService.LOG_WARNING;
+
     static final String DEFAULT_PAGE = BundlesServlet.NAME;
 
     static final String DEFAULT_REALM = "OSGi Management Console";
@@ -138,8 +141,6 @@
 
     private BundleContext bundleContext;
 
-    private Logger log;
-
     private ServiceTracker httpServiceTracker;
 
     private HttpService httpService;
@@ -176,11 +177,11 @@
 
     private ResourceBundleManager resourceBundleManager;
 
+    private int logLevel = DEFAULT_LOG_LEVEL;
+
     public OsgiManager( BundleContext bundleContext )
     {
-
         this.bundleContext = bundleContext;
-        this.log = new Logger( bundleContext );
 
         updateConfiguration( null );
 
@@ -225,11 +226,6 @@
             configurationListener = null;
         }
 
-        if ( log != null )
-        {
-            log.dispose();
-        }
-
         this.defaultPlugin = null;
         this.bundleContext = null;
     }
@@ -256,7 +252,7 @@
                 // check whether enabled by configuration
                 if ( isPluginDisabled( pluginClassName, plugin ) )
                 {
-                    log.log( LogService.LOG_INFO, "Ignoring plugin " + pluginClassName + ": Disabled by configuration" );
+                    log( LogService.LOG_INFO, "Ignoring plugin " + pluginClassName + ": Disabled by configuration" );
                     continue;
                 }
 
@@ -286,11 +282,11 @@
                     // message is just a class name, try to be more descriptive
                     message = "Class " + message + " missing";
                 }
-                log.log( LogService.LOG_INFO, pluginClassName + " not enabled. Reason: " + message );
+                log( LogService.LOG_INFO, pluginClassName + " not enabled. Reason: " + message );
             }
             catch ( Throwable t )
             {
-                log.log( LogService.LOG_INFO, "Failed to instantiate plugin " + pluginClassName + ". Reason: " + t );
+                log( LogService.LOG_INFO, "Failed to instantiate plugin " + pluginClassName + ". Reason: " + t );
             }
         }
 
@@ -404,6 +400,7 @@
         this.labelMap.clear();
     }
 
+
     //---------- internal
 
     BundleContext getBundleContext()
@@ -422,6 +419,50 @@
     }
 
 
+    /**
+     * Calls the <code>GenericServlet.log(String)</code> method if the
+     * configured log level is less than or equal to the given <code>level</code>.
+     * <p>
+     * Note, that the <code>level</code> paramter is only used to decide whether
+     * the <code>GenericServlet.log(String)</code> method is called or not. The
+     * actual implementation of the <code>GenericServlet.log</code> method is
+     * outside of the control of this method.
+     *
+     * @param level The log level at which to log the message
+     * @param message The message to log
+     */
+    private void log( int level, String message )
+    {
+        if ( logLevel >= level )
+        {
+            log( message );
+        }
+    }
+
+
+    /**
+     * Calls the <code>GenericServlet.log(String, Throwable)</code> method if
+     * the configured log level is less than or equal to the given
+     * <code>level</code>.
+     * <p>
+     * Note, that the <code>level</code> paramter is only used to decide whether
+     * the <code>GenericServlet.log(String, Throwable)</code> method is called
+     * or not. The actual implementation of the <code>GenericServlet.log</code>
+     * method is outside of the control of this method.
+     *
+     * @param level The log level at which to log the message
+     * @param message The message to log
+     * @param t The <code>Throwable</code> to log with the message
+     */
+    private void log( int level, String message, Throwable t )
+    {
+        if ( logLevel >= level )
+        {
+            log( message, t );
+        }
+    }
+
+
     private HttpServletResponse wrapResponse( final HttpServletRequest request, final HttpServletResponse response,
         final AbstractWebConsolePlugin plugin )
     {
@@ -584,7 +625,7 @@
         // do not bind service, when we are already bound
         if ( this.httpService != null )
         {
-            log.log( LogService.LOG_DEBUG,
+            log( LogService.LOG_DEBUG,
                 "bindHttpService: Already bound to an HTTP Service, ignoring further services" );
             return;
         }
@@ -614,7 +655,7 @@
         }
         catch ( Exception e )
         {
-            log.log( LogService.LOG_ERROR, "bindHttpService: Problem setting up", e );
+            log( LogService.LOG_ERROR, "bindHttpService: Problem setting up", e );
         }
 
         this.httpService = httpService;
@@ -625,7 +666,7 @@
     {
         if ( this.httpService != httpService )
         {
-            log.log( LogService.LOG_DEBUG,
+            log( LogService.LOG_DEBUG,
                 "unbindHttpService: Ignoring unbind of an HttpService to which we are not registered" );
             return;
         }
@@ -641,7 +682,7 @@
             }
             catch ( Throwable t )
             {
-                log.log( LogService.LOG_WARNING, "unbindHttpService: Failed unregistering Resources", t );
+                log( LogService.LOG_WARNING, "unbindHttpService: Failed unregistering Resources", t );
             }
             httpResourcesRegistered = false;
         }
@@ -654,7 +695,7 @@
             }
             catch ( Throwable t )
             {
-                log.log( LogService.LOG_WARNING, "unbindHttpService: Failed unregistering Servlet", t );
+                log( LogService.LOG_WARNING, "unbindHttpService: Failed unregistering Servlet", t );
             }
             httpServletRegistered = false;
         }
@@ -682,7 +723,7 @@
         }
         catch ( ServletException se )
         {
-            log.log( LogService.LOG_WARNING, "Initialization of plugin '" + title + "' (" + label
+            log( LogService.LOG_WARNING, "Initialization of plugin '" + title + "' (" + label
                 + ") failed; not using this plugin", se );
         }
     }
@@ -727,6 +768,9 @@
 
         configuration = config;
 
+        logLevel = getProperty( config, PROP_LOG_LEVEL, DEFAULT_LOG_LEVEL );
+        AbstractWebConsolePlugin.setLogLevel( logLevel );
+
         defaultRenderName = getProperty( config, PROP_DEFAULT_RENDER, DEFAULT_PAGE );
         if ( defaultRenderName != null && plugins.get( defaultRenderName ) != null )
         {
@@ -810,6 +854,42 @@
 
 
     /**
+     * Returns the named property from the configuration. If the property does
+     * not exist, the default value <code>def</code> is returned.
+     *
+     * @param config The properties from which to returned the named one
+     * @param name The name of the property to return
+     * @param def The default value if the named property does not exist
+     * @return The value of the named property as a string or <code>def</code>
+     *         if the property does not exist
+     */
+    private int getProperty( Dictionary config, String name, int def )
+    {
+        Object value = config.get( name );
+        if ( value instanceof Number )
+        {
+            return ( ( Number ) value ).intValue();
+        }
+
+        // try to convert the value to a number
+        if ( value != null )
+        {
+            try
+            {
+                return Integer.parseInt( value.toString() );
+            }
+            catch ( NumberFormatException nfe )
+            {
+                // don't care
+            }
+        }
+
+        // not a number, not convertible, not set, use default
+        return def;
+    }
+
+
+    /**
      * Returns <code>true</code> if the plugin is an
      * {@link AbstractWebConsolePlugin} and a list of enabled plugins is
      * configured but the plugin is not contained in that list.