FELIX-2236 Improvement and fixes:
* Ensure bundle can be started without Config Admin, Metatype and Web Console on IBM J9 VM
* Support basic configuration with framework properties
* Prevent NullPointerException if no configuration is available or config is deleted
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@927746 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/webconsole-plugins/memoryusage/src/main/java/org/apache/felix/webconsole/plugins/memoryusage/internal/Activator.java b/webconsole-plugins/memoryusage/src/main/java/org/apache/felix/webconsole/plugins/memoryusage/internal/Activator.java
index 18d0fc1..4b18d68 100644
--- a/webconsole-plugins/memoryusage/src/main/java/org/apache/felix/webconsole/plugins/memoryusage/internal/Activator.java
+++ b/webconsole-plugins/memoryusage/src/main/java/org/apache/felix/webconsole/plugins/memoryusage/internal/Activator.java
@@ -1,18 +1,18 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
+ * or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
+ * 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
+ * with the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
+ * KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
@@ -49,14 +49,12 @@
// install Web Console plugin
try
{
- MemoryUsagePanel tdp = new MemoryUsagePanel(support);
- tdp.activate(bundleContext);
-
Dictionary<String, Object> properties = new Hashtable<String, Object>();
- properties.put("felix.webconsole.label", tdp.getLabel());
+ properties.put("felix.webconsole.label", MemoryUsageConstants.LABEL);
register(bundleContext, new String[]
- { "javax.servlet.Servlet", "org.apache.felix.webconsole.ConfigurationPrinter" }, tdp, properties);
+ { "javax.servlet.Servlet", "org.apache.felix.webconsole.ConfigurationPrinter" }, new MemoryUsagePanel(
+ bundleContext, support), properties);
}
catch (Throwable t)
{
@@ -66,15 +64,15 @@
// register for configuration
try
{
- MemoryUsageConfigurator tdp = new MemoryUsageConfigurator(support);
Dictionary<String, Object> properties = new Hashtable<String, Object>();
- properties.put(Constants.SERVICE_PID, MemoryUsageConfigurator.NAME);
+ properties.put(Constants.SERVICE_PID, MemoryUsageConstants.PID);
register(bundleContext, new String[]
- { "org.osgi.service.cm.ManagedService" }, tdp, properties);
+ { "org.osgi.service.cm.ManagedService" }, new MemoryUsageConfigurator(support), properties);
}
catch (Throwable t)
{
- // Configuration Admin and Metatype Service API might not be available, don't care
+ // Configuration Admin and Metatype Service API might not be
+ // available, don't care
}
}
@@ -87,7 +85,7 @@
}
}
- private void register(BundleContext context, String[] serviceNames, Object service,
+ static void register(BundleContext context, String[] serviceNames, Object service,
Dictionary<String, Object> properties)
{
diff --git a/webconsole-plugins/memoryusage/src/main/java/org/apache/felix/webconsole/plugins/memoryusage/internal/MemoryUsageCommand.java b/webconsole-plugins/memoryusage/src/main/java/org/apache/felix/webconsole/plugins/memoryusage/internal/MemoryUsageCommand.java
index 9a8a45d..9499a33 100644
--- a/webconsole-plugins/memoryusage/src/main/java/org/apache/felix/webconsole/plugins/memoryusage/internal/MemoryUsageCommand.java
+++ b/webconsole-plugins/memoryusage/src/main/java/org/apache/felix/webconsole/plugins/memoryusage/internal/MemoryUsageCommand.java
@@ -25,7 +25,7 @@
import org.apache.felix.shell.Command;
-public class MemoryUsageCommand implements Command
+class MemoryUsageCommand implements Command
{
private static final String HELP_CMD = "help";
@@ -42,7 +42,7 @@
private final MemoryUsageSupport support;
- public MemoryUsageCommand(final MemoryUsageSupport support)
+ MemoryUsageCommand(final MemoryUsageSupport support)
{
this.support = support;
}
diff --git a/webconsole-plugins/memoryusage/src/main/java/org/apache/felix/webconsole/plugins/memoryusage/internal/MemoryUsageConfigurator.java b/webconsole-plugins/memoryusage/src/main/java/org/apache/felix/webconsole/plugins/memoryusage/internal/MemoryUsageConfigurator.java
index 8aad994..7fbe40a 100644
--- a/webconsole-plugins/memoryusage/src/main/java/org/apache/felix/webconsole/plugins/memoryusage/internal/MemoryUsageConfigurator.java
+++ b/webconsole-plugins/memoryusage/src/main/java/org/apache/felix/webconsole/plugins/memoryusage/internal/MemoryUsageConfigurator.java
@@ -1,18 +1,18 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
+ * or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
+ * 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
+ * with the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
+ * KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
@@ -21,21 +21,17 @@
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Dictionary;
+import java.util.Hashtable;
+
import org.osgi.service.cm.ConfigurationException;
import org.osgi.service.cm.ManagedService;
import org.osgi.service.metatype.AttributeDefinition;
import org.osgi.service.metatype.MetaTypeProvider;
import org.osgi.service.metatype.ObjectClassDefinition;
-public class MemoryUsageConfigurator implements ManagedService, MetaTypeProvider
+class MemoryUsageConfigurator implements ManagedService, MetaTypeProvider
{
- static final String NAME = "org.apache.felix.webconsole.plugins.memoryusage.internal.MemoryUsageConfigurator";
-
- private static final String PROP_DUMP_THRESHOLD = "dump.threshold";
-
- private static final String PROP_DUMP_LOCATION = "dump.location";
-
private final MemoryUsageSupport support;
private ObjectClassDefinition ocd;
@@ -48,7 +44,13 @@
@SuppressWarnings("unchecked")
public void updated(Dictionary properties) throws ConfigurationException
{
- final Object thresholdValue = properties.get(PROP_DUMP_THRESHOLD);
+ // ensure default values if there is no config or config is deleted
+ if (properties == null)
+ {
+ properties = new Hashtable();
+ }
+
+ final Object thresholdValue = properties.get(MemoryUsageConstants.PROP_DUMP_THRESHOLD);
if (thresholdValue != null)
{
final int threshold;
@@ -78,12 +80,20 @@
throw failure(iae.getMessage());
}
}
+ else
+ {
+ support.setThreshold(-1);
+ }
- final Object locationValue = properties.get(PROP_DUMP_LOCATION);
+ final Object locationValue = properties.get(MemoryUsageConstants.PROP_DUMP_LOCATION);
if (locationValue instanceof String)
{
support.setDumpLocation((String) locationValue);
}
+ else
+ {
+ support.setDumpLocation(null);
+ }
}
public String[] getLocales()
@@ -93,7 +103,7 @@
public ObjectClassDefinition getObjectClassDefinition(String id, String locale)
{
- if (!NAME.equals(id))
+ if (!MemoryUsageConstants.PID.equals(id))
{
return null;
}
@@ -102,11 +112,11 @@
{
final ArrayList<AttributeDefinition> adList = new ArrayList<AttributeDefinition>();
- adList.add(new AttributeDefinitionImpl(PROP_DUMP_THRESHOLD, "Dump Threshold",
+ adList.add(new AttributeDefinitionImpl(MemoryUsageConstants.PROP_DUMP_THRESHOLD, "Dump Threshold",
"Threshold at which to automatically create a memory dump as a percentage in the range "
- + MemoryUsageSupport.MIN_DUMP_THRESHOLD + " to " + MemoryUsageSupport.MAX_DUMP_THRESHOLD
+ + MemoryUsageConstants.MIN_DUMP_THRESHOLD + " to " + MemoryUsageConstants.MAX_DUMP_THRESHOLD
+ " or zero to disable automatic dump creation.", AttributeDefinition.INTEGER, new String[]
- { String.valueOf(MemoryUsageSupport.DEFAULT_DUMP_THRESHOLD) }, 0, null, null)
+ { String.valueOf(MemoryUsageConstants.DEFAULT_DUMP_THRESHOLD) }, 0, null, null)
{
@Override
public String validate(String value)
@@ -114,11 +124,10 @@
try
{
int threshold = Integer.parseInt(value);
- if (threshold != 0
- && (threshold < MemoryUsageSupport.MIN_DUMP_THRESHOLD || threshold > MemoryUsageSupport.MAX_DUMP_THRESHOLD))
+ if (!MemoryUsageConstants.isThresholdValid(threshold))
{
- return "Threshold must in the range " + MemoryUsageSupport.MIN_DUMP_THRESHOLD + " to "
- + MemoryUsageSupport.MAX_DUMP_THRESHOLD + " or zero";
+ return "Threshold must in the range " + MemoryUsageConstants.MIN_DUMP_THRESHOLD + " to "
+ + MemoryUsageConstants.MAX_DUMP_THRESHOLD + " or zero";
}
return ""; // everything ok
}
@@ -128,7 +137,7 @@
}
}
});
- adList.add(new AttributeDefinitionImpl(PROP_DUMP_LOCATION, "Dumpe Location",
+ adList.add(new AttributeDefinitionImpl(MemoryUsageConstants.PROP_DUMP_LOCATION, "Dumpe Location",
"The filesystem location where heap dumps are stored. If this is null or empty (the default) the dumps are stored in "
+ support.getDefaultDumpLocation(), ""));
@@ -149,7 +158,7 @@
public String getID()
{
- return NAME;
+ return MemoryUsageConstants.PID;
}
public String getDescription()
@@ -169,9 +178,9 @@
private ConfigurationException failure(final Object invalidValue)
{
- return new ConfigurationException(PROP_DUMP_THRESHOLD, "Invalid Dump Threshold value '" + invalidValue
- + "': Must be an integer number in the range " + MemoryUsageSupport.MIN_DUMP_THRESHOLD + " to "
- + MemoryUsageSupport.MAX_DUMP_THRESHOLD + " or zero to disable");
+ return new ConfigurationException(MemoryUsageConstants.PROP_DUMP_THRESHOLD, "Invalid Dump Threshold value '"
+ + invalidValue + "': Must be an integer number in the range " + MemoryUsageConstants.MIN_DUMP_THRESHOLD
+ + " to " + MemoryUsageConstants.MAX_DUMP_THRESHOLD + " or zero to disable");
}
private static class AttributeDefinitionImpl implements AttributeDefinition
diff --git a/webconsole-plugins/memoryusage/src/main/java/org/apache/felix/webconsole/plugins/memoryusage/internal/MemoryUsageConstants.java b/webconsole-plugins/memoryusage/src/main/java/org/apache/felix/webconsole/plugins/memoryusage/internal/MemoryUsageConstants.java
new file mode 100644
index 0000000..a89ff98
--- /dev/null
+++ b/webconsole-plugins/memoryusage/src/main/java/org/apache/felix/webconsole/plugins/memoryusage/internal/MemoryUsageConstants.java
@@ -0,0 +1,92 @@
+/*
+ * 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.plugins.memoryusage.internal;
+
+/**
+ * The <code>MemoryUsageConstants</code> provides some basic constants for
+ * the MemoryUsage support bundle
+ */
+final class MemoryUsageConstants
+{
+
+ /**
+ * Service PID for the Configuration Admin configuration object to be
+ * provided to configure the memory usage support.
+ */
+ static final String PID = "org.apache.felix.webconsole.plugins.memoryusage.internal.MemoryUsageConfigurator";
+
+ /**
+ * The label (or address) under which the Memory Usage Web Console Plugin
+ * is accessible.
+ */
+ static final String LABEL = "memoryusage";
+
+ /**
+ * The name of the property providing the filesystem location where the
+ * memory dumps should be placed. If this location is relative it is located
+ * inside the bundle private data area.
+ * <p>
+ * This property may be set as a framework property or as a property of
+ * configuration provided by the Configuration Admin Service for the service
+ * {@link #PID}.
+ */
+ static final String PROP_DUMP_LOCATION = "felix.memoryusage.dump.location";
+
+ /**
+ * The name of the property providing threshold as a percentage of the
+ * maximum available memory at which an automatic memory dumps should
+ * be created.
+ * <p>
+ * This property may be set as a framework property or as a property of
+ * configuration provided by the Configuration Admin Service for the service
+ * {@link #PID}.
+ * <p>
+ * The property must be an integer value or be parseable to an integer
+ * value. The value must be zero to disable automatic dump generation or in
+ * the range [{@link #MIN_DUMP_THRESHOLD}..{@link #MAX_DUMP_THRESHOLD}].
+ */
+ static final String PROP_DUMP_THRESHOLD = "felix.memoryusage.dump.threshold";
+
+ /**
+ * The default automatic heap dump threshold if none has been configured
+ * (or no configuration has yet been provided).
+ */
+ static final int DEFAULT_DUMP_THRESHOLD = 95;
+ /**
+ * The maximum allowed automatic heap dump threshold.
+ */
+ static final int MAX_DUMP_THRESHOLD = 99;
+ /**
+ * The minimum allowed automatic heap dump threshold.
+ */
+ static final int MIN_DUMP_THRESHOLD = 50;
+
+ /**
+ * Returns <code>true</code> if the given <code>threshold</code>value is
+ * valid; that is if the vaue is either zero or in the range [
+ * {@link #MIN_DUMP_THRESHOLD}..{@link #MAX_DUMP_THRESHOLD}].
+ *
+ * @param threshold The threshold value (percentage) to validate
+ * @return <code>true</code> if the value is valid
+ */
+ static boolean isThresholdValid(final int threshold)
+ {
+ return threshold == 0 || (threshold >= MIN_DUMP_THRESHOLD && threshold <= MAX_DUMP_THRESHOLD);
+ }
+}
diff --git a/webconsole-plugins/memoryusage/src/main/java/org/apache/felix/webconsole/plugins/memoryusage/internal/MemoryUsagePanel.java b/webconsole-plugins/memoryusage/src/main/java/org/apache/felix/webconsole/plugins/memoryusage/internal/MemoryUsagePanel.java
index a20341f..3e54f43 100644
--- a/webconsole-plugins/memoryusage/src/main/java/org/apache/felix/webconsole/plugins/memoryusage/internal/MemoryUsagePanel.java
+++ b/webconsole-plugins/memoryusage/src/main/java/org/apache/felix/webconsole/plugins/memoryusage/internal/MemoryUsagePanel.java
@@ -40,11 +40,12 @@
import org.apache.felix.webconsole.ConfigurationPrinter;
import org.apache.felix.webconsole.DefaultVariableResolver;
import org.apache.felix.webconsole.WebConsoleUtil;
+import org.osgi.framework.BundleContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@SuppressWarnings("serial")
-public class MemoryUsagePanel extends AbstractWebConsolePlugin implements ConfigurationPrinter, AttachmentProvider
+class MemoryUsagePanel extends AbstractWebConsolePlugin implements ConfigurationPrinter, AttachmentProvider
{
/** default log */
@@ -52,9 +53,10 @@
private final MemoryUsageSupport support;
- public MemoryUsagePanel(final MemoryUsageSupport support)
+ MemoryUsagePanel(final BundleContext bundleContext, final MemoryUsageSupport support)
{
this.support = support;
+ activate(bundleContext);
}
// ---------- AbstractWebConsolePlugin
@@ -62,7 +64,7 @@
@Override
public String getLabel()
{
- return "memoryusage";
+ return MemoryUsageConstants.LABEL;
}
@Override
diff --git a/webconsole-plugins/memoryusage/src/main/java/org/apache/felix/webconsole/plugins/memoryusage/internal/MemoryUsageSupport.java b/webconsole-plugins/memoryusage/src/main/java/org/apache/felix/webconsole/plugins/memoryusage/internal/MemoryUsageSupport.java
index be79755..705c419 100644
--- a/webconsole-plugins/memoryusage/src/main/java/org/apache/felix/webconsole/plugins/memoryusage/internal/MemoryUsageSupport.java
+++ b/webconsole-plugins/memoryusage/src/main/java/org/apache/felix/webconsole/plugins/memoryusage/internal/MemoryUsageSupport.java
@@ -31,6 +31,7 @@
import java.util.Date;
import java.util.List;
import java.util.NoSuchElementException;
+import java.util.TreeSet;
import javax.management.ListenerNotFoundException;
import javax.management.MBeanServer;
@@ -46,22 +47,6 @@
final class MemoryUsageSupport implements NotificationListener
{
- /**
- * The minimum allowed automatic heap dump threshold (value is 50).
- */
- static final int MIN_DUMP_THRESHOLD = 50;
-
- /**
- * The maximum allowed automatic heap dump threshold (value is 99).
- */
- static final int MAX_DUMP_THRESHOLD = 99;
-
- /**
- * The default automatic heap dump threshold if none has been configured
- * (or no configuration has yet been provided) (value is 95).
- */
- static final int DEFAULT_DUMP_THRESHOLD = 95;
-
// This is the name of the HotSpot Diagnostic MBean
private static final String HOTSPOT_BEAN_NAME = "com.sun.management:type=HotSpotDiagnostic";
@@ -71,6 +56,9 @@
// or the current working directory
private final File defaultDumpLocation;
+ // the default threshold value
+ private final int defaultThreshold;
+
// the configured dump location
private File dumpLocation;
@@ -79,13 +67,25 @@
MemoryUsageSupport(final BundleContext context)
{
- // get the dump location
- File dumps = context.getDataFile("dumps");
- if (dumps == null)
+
+ // the default dump location
+ String propDumps = context.getProperty(MemoryUsageConstants.PROP_DUMP_LOCATION);
+ if (propDumps == null)
{
- dumps = new File("dumps");
+ propDumps = "dumps";
}
- defaultDumpLocation = dumps.getAbsoluteFile();
+
+ // ensure dump location is an absolute path/location
+ File dumps = new File(propDumps);
+ if (!dumps.isAbsolute())
+ {
+ File bundleDumps = context.getDataFile(propDumps);
+ if (bundleDumps != null)
+ {
+ dumps = bundleDumps;
+ }
+ }
+ this.defaultDumpLocation = dumps.getAbsoluteFile();
// prepare the dump location
setDumpLocation(null);
@@ -95,7 +95,37 @@
memEmitter.addNotificationListener(this, null, null);
// set the initial automatic dump threshold
- setThreshold(DEFAULT_DUMP_THRESHOLD);
+ int defaultThreshold;
+ String propThreshold = context.getProperty(MemoryUsageConstants.PROP_DUMP_THRESHOLD);
+ if (propThreshold != null)
+ {
+ try
+ {
+ defaultThreshold = Integer.parseInt(propThreshold);
+ setThreshold(defaultThreshold);
+ }
+ catch (Exception e)
+ {
+ // NumberFormatException - if propTreshold cannot be parsed to
+ // int
+ // IllegalArgumentException - if threshold is invalid
+ defaultThreshold = -1;
+ }
+ }
+ else
+ {
+ defaultThreshold = -1;
+ }
+
+ // default threshold has not been configured (correctly), assume fixed
+ // default
+ if (defaultThreshold < 0)
+ {
+ defaultThreshold = MemoryUsageConstants.DEFAULT_DUMP_THRESHOLD;
+ setThreshold(defaultThreshold);
+ }
+
+ this.defaultThreshold = defaultThreshold;
}
void dispose()
@@ -117,15 +147,23 @@
* @param percentage The threshold as a percentage of memory consumption.
* This value may be 0 (zero) to switch off automatic heap dumps
* or in the range {@link #MIN_DUMP_THRESHOLD} to
- * {@link #MAX_DUMP_THRESHOLD}.
+ * {@link #MAX_DUMP_THRESHOLD}. If set to a negative value,
+ * the default threshold is assumed.
* @throws IllegalArgumentException if the percentage value is outside of
* the valid range of thresholds. The message is the percentage
* value which is not accepted.
*/
- final void setThreshold(final int percentage)
+ final void setThreshold(int percentage)
{
- if (threshold == 0 || (threshold >= MIN_DUMP_THRESHOLD && threshold <= MAX_DUMP_THRESHOLD))
+ if (percentage < 0)
{
+ percentage = defaultThreshold;
+ }
+
+ if (MemoryUsageConstants.isThresholdValid(percentage))
+ {
+ TreeSet<String> thresholdPools = new TreeSet<String>();
+ TreeSet<String> noThresholdPools = new TreeSet<String>();
List<MemoryPoolMXBean> pools = getMemoryPools();
for (MemoryPoolMXBean pool : pools)
{
@@ -133,13 +171,21 @@
{
long threshold = pool.getUsage().getMax() * percentage / 100;
pool.setUsageThreshold(threshold);
+ thresholdPools.add(pool.getName());
+ }
+ else
+ {
+ noThresholdPools.add(pool.getName());
}
}
this.threshold = percentage;
+
+ log.info("Setting Automatic Memory Dump Threshold to {}% for pools {}", threshold, thresholdPools);
+ log.info("Automatic Memory Dump cannot be set for pools {}", noThresholdPools);
}
else
{
- throw new IllegalArgumentException(String.valueOf(threshold));
+ throw new IllegalArgumentException(String.valueOf(percentage));
}
}
@@ -304,6 +350,8 @@
{
this.dumpLocation = new File(dumpLocation).getAbsoluteFile();
}
+
+ log.info("Storing Memory Dumps in {}", this.dumpLocation);
}
final File getDumpLocation()