You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by or...@apache.org on 2016/02/05 23:58:00 UTC

svn commit: r1728772 - in /qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server: logging/messages/ model/ model/adapter/

Author: orudyy
Date: Fri Feb  5 22:58:00 2016
New Revision: 1728772

URL: http://svn.apache.org/viewvc?rev=1728772&view=rev
Log:
QPID-6932: Enhance model object to expose key JVM statistics such as heap memory, garbage collection, etc. Add security checks and operational logs for broker operations

Added:
    qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/model/BrokerAttributeInjector.java
Modified:
    qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/logging/messages/BrokerMessages.java
    qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/logging/messages/Broker_logmessages.properties
    qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/model/AbstractConfiguredObject.java
    qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/model/Broker.java
    qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObject.java
    qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/model/adapter/BrokerAdapter.java

Modified: qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/logging/messages/BrokerMessages.java
URL: http://svn.apache.org/viewvc/qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/logging/messages/BrokerMessages.java?rev=1728772&r1=1728771&r2=1728772&view=diff
==============================================================================
--- qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/logging/messages/BrokerMessages.java (original)
+++ qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/logging/messages/BrokerMessages.java Fri Feb  5 22:58:00 2016
@@ -54,6 +54,7 @@ public class BrokerMessages
     public static final String FLOW_TO_DISK_ACTIVE_LOG_HIERARCHY = DEFAULT_LOG_HIERARCHY_PREFIX + "broker.flow_to_disk_active";
     public static final String MAX_MEMORY_LOG_HIERARCHY = DEFAULT_LOG_HIERARCHY_PREFIX + "broker.max_memory";
     public static final String PLATFORM_LOG_HIERARCHY = DEFAULT_LOG_HIERARCHY_PREFIX + "broker.platform";
+    public static final String OPERATION_LOG_HIERARCHY = DEFAULT_LOG_HIERARCHY_PREFIX + "broker.operation";
     public static final String PROCESS_LOG_HIERARCHY = DEFAULT_LOG_HIERARCHY_PREFIX + "broker.process";
     public static final String SHUTTING_DOWN_LOG_HIERARCHY = DEFAULT_LOG_HIERARCHY_PREFIX + "broker.shutting_down";
     public static final String MANAGEMENT_MODE_LOG_HIERARCHY = DEFAULT_LOG_HIERARCHY_PREFIX + "broker.management_mode";
@@ -73,6 +74,7 @@ public class BrokerMessages
         LoggerFactory.getLogger(FLOW_TO_DISK_ACTIVE_LOG_HIERARCHY);
         LoggerFactory.getLogger(MAX_MEMORY_LOG_HIERARCHY);
         LoggerFactory.getLogger(PLATFORM_LOG_HIERARCHY);
+        LoggerFactory.getLogger(OPERATION_LOG_HIERARCHY);
         LoggerFactory.getLogger(PROCESS_LOG_HIERARCHY);
         LoggerFactory.getLogger(SHUTTING_DOWN_LOG_HIERARCHY);
         LoggerFactory.getLogger(MANAGEMENT_MODE_LOG_HIERARCHY);
@@ -573,6 +575,64 @@ public class BrokerMessages
             }
 
             @Override
+            public boolean equals(final Object o)
+            {
+                if (this == o)
+                {
+                    return true;
+                }
+                if (o == null || getClass() != o.getClass())
+                {
+                    return false;
+                }
+
+                final LogMessage that = (LogMessage) o;
+
+                return getLogHierarchy().equals(that.getLogHierarchy()) && toString().equals(that.toString());
+
+            }
+
+            @Override
+            public int hashCode()
+            {
+                int result = toString().hashCode();
+                result = 31 * result + getLogHierarchy().hashCode();
+                return result;
+            }
+        };
+    }
+
+    /**
+     * Log a Broker message of the Format:
+     * <pre>BRK-1018 : Operation : {0}</pre>
+     * Optional values are contained in [square brackets] and are numbered
+     * sequentially in the method call.
+     *
+     */
+    public static LogMessage OPERATION(String param1)
+    {
+        String rawMessage = _messages.getString("OPERATION");
+
+        final Object[] messageArguments = {param1};
+        // Create a new MessageFormat to ensure thread safety.
+        // Sharing a MessageFormat and using applyPattern is not thread safe
+        MessageFormat formatter = new MessageFormat(rawMessage, _currentLocale);
+
+        final String message = formatter.format(messageArguments);
+
+        return new LogMessage()
+        {
+            public String toString()
+            {
+                return message;
+            }
+
+            public String getLogHierarchy()
+            {
+                return OPERATION_LOG_HIERARCHY;
+            }
+
+            @Override
             public boolean equals(final Object o)
             {
                 if (this == o)

Modified: qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/logging/messages/Broker_logmessages.properties
URL: http://svn.apache.org/viewvc/qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/logging/messages/Broker_logmessages.properties?rev=1728772&r1=1728771&r2=1728772&view=diff
==============================================================================
--- qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/logging/messages/Broker_logmessages.properties (original)
+++ qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/logging/messages/Broker_logmessages.properties Fri Feb  5 22:58:00 2016
@@ -58,3 +58,6 @@ FATAL_ERROR = BRK-1016 : Fatal error : {
 
 # 0 - pid
 PROCESS = BRK-1017 : Process : PID : {0}
+
+# 0 - operation name
+OPERATION = BRK-1018 : Operation : {0}

Modified: qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/model/AbstractConfiguredObject.java
URL: http://svn.apache.org/viewvc/qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/model/AbstractConfiguredObject.java?rev=1728772&r1=1728771&r2=1728772&view=diff
==============================================================================
--- qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/model/AbstractConfiguredObject.java (original)
+++ qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/model/AbstractConfiguredObject.java Fri Feb  5 22:58:00 2016
@@ -177,6 +177,7 @@ public abstract class AbstractConfigured
     private boolean _openComplete;
     private boolean _openFailed;
     private volatile State _state = State.UNINITIALIZED;
+    private volatile long _lastOpenedTime;
 
     protected static Map<Class<? extends ConfiguredObject>, ConfiguredObject<?>> parentsMap(ConfiguredObject<?>... parents)
     {
@@ -946,6 +947,7 @@ public abstract class AbstractConfigured
                 }
             });
             _openComplete = true;
+            _lastOpenedTime = System.currentTimeMillis();
         }
     }
 
@@ -2758,6 +2760,11 @@ public abstract class AbstractConfigured
         }
     }
 
+    @Override
+    public final long getLastOpenedTime()
+    {
+        return _lastOpenedTime;
+    }
     //=========================================================================================
 
     static String interpolate(ConfiguredObject<?> object, String value)

Modified: qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/model/Broker.java
URL: http://svn.apache.org/viewvc/qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/model/Broker.java?rev=1728772&r1=1728771&r2=1728772&view=diff
==============================================================================
--- qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/model/Broker.java (original)
+++ qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/model/Broker.java Fri Feb  5 22:58:00 2016
@@ -21,6 +21,7 @@
 package org.apache.qpid.server.model;
 
 import java.util.Collection;
+import java.util.List;
 
 import org.apache.qpid.server.logging.EventLogger;
 import org.apache.qpid.server.logging.EventLoggerProvider;
@@ -160,6 +161,61 @@ public interface Broker<X extends Broker
     @ManagedOperation(nonModifying = true, description = "Initiates an orderly shutdown of the Broker.")
     void initiateShutdown();
 
+    @DerivedAttribute(description = "Maximum heap memory size")
+    long getMaximumHeapMemorySize();
+
+    @DerivedAttribute(description = "Maximum direct memory size which can be consumed by broker")
+    long getMaximumDirectMemorySize();
+
+    @DerivedAttribute(description = "JVM arguments specified on startup")
+    List<String> getJVMArguments();
+
+    @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME,
+                      units = StatisticUnit.COUNT,
+                      label = "Live threads",
+                      description = "Number of live threads")
+    int getNumberOfLiveThreads();
+
+    @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME,
+                      units = StatisticUnit.BYTES,
+                      label = "Used Heap Memory Size",
+                      description = "Size of used heap memory")
+    long getUsedHeapMemorySize();
+
+    @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME,
+                      units = StatisticUnit.BYTES,
+                      label = "Used Direct Memory Size",
+                      description = "Size of used direct memory")
+    long getUsedDirectMemorySize();
+
+    @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME,
+                      units = StatisticUnit.BYTES,
+                      label = "Direct Memory Total Capacity",
+                      description = "Total capacity of direct memory allocated for the Broker process")
+    long getDirectMemoryTotalCapacity();
+
+    @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME,
+                      units = StatisticUnit.COUNT,
+                      label = "Number Of Object Pending Finalization",
+                      description = "Number of objects pending finalization")
+    int getNumberOfObjectsPendingFinalization();
+
+    @ManagedOperation(nonModifying = true, description = "Initiates garbage collection")
+    void performGC();
+
+    @ManagedOperation(nonModifying = true,
+                      description = "Collects thread stack traces and dead locks. Dumps stack traces into logs if requested")
+    Content getThreadStackTraces(@Param(name="appendToLog",
+                                        defaultValue = "false",
+                                        description = "If true, appends stack traces into logs")
+                                 boolean appendToLog);
+
+    @ManagedOperation(nonModifying = true,
+            description = "Collects thread stack traces for the threads with names containing matching characters for given regular expression")
+    Content findThreadStackTraces(@Param(name="threadNameFindExpression",
+                                        description = "Regular expression to find threads with names containing matching characters")
+                                 String threadNameFindExpression);
+
     //children
     Collection<VirtualHostNode<?>> getVirtualHostNodes();
 

Added: qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/model/BrokerAttributeInjector.java
URL: http://svn.apache.org/viewvc/qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/model/BrokerAttributeInjector.java?rev=1728772&view=auto
==============================================================================
--- qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/model/BrokerAttributeInjector.java (added)
+++ qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/model/BrokerAttributeInjector.java Fri Feb  5 22:58:00 2016
@@ -0,0 +1,398 @@
+/*
+ *
+ * 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.qpid.server.model;
+
+import java.lang.management.GarbageCollectorMXBean;
+import java.lang.management.ManagementFactory;
+import java.lang.management.MemoryPoolMXBean;
+import java.lang.management.PlatformManagedObject;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.qpid.server.configuration.IllegalConfigurationException;
+import org.apache.qpid.server.logging.messages.BrokerMessages;
+import org.apache.qpid.server.plugin.ConfiguredObjectAttributeInjector;
+import org.apache.qpid.server.plugin.PluggableService;
+import org.apache.qpid.server.security.access.Operation;
+import org.apache.qpid.server.util.ParameterizedTypeImpl;
+
+@PluggableService
+public class BrokerAttributeInjector implements ConfiguredObjectAttributeInjector
+{
+    private static final Logger LOGGER = LoggerFactory.getLogger(BrokerAttributeInjector.class);
+
+    private final InjectedAttributeOrStatistic.TypeValidator _typeValidator =
+            new InjectedAttributeOrStatistic.TypeValidator()
+            {
+                @Override
+                public boolean appliesToType(final Class<? extends ConfiguredObject<?>> type)
+                {
+                    return Broker.class.isAssignableFrom(type);
+                }
+            };
+
+
+    @Override
+    public Collection<ConfiguredObjectInjectedAttribute<?, ?>> getInjectedAttributes()
+    {
+        List<ConfiguredObjectInjectedAttribute<?, ?>> attributes = new ArrayList<>();
+        List<MemoryPoolMXBean> memoryPoolMXBeans = ManagementFactory.getMemoryPoolMXBeans();
+        for (MemoryPoolMXBean memoryPoolMXBean : memoryPoolMXBeans)
+        {
+
+            String poolName = memoryPoolMXBean.getName().replace(" ", "");
+            String attributeName = "jvmMemoryMaximum" + poolName;
+            try
+            {
+                Method getMemoryPoolMaximum = BrokerAttributeInjector.class.getDeclaredMethod("getMemoryPoolMaximum",
+                                                                                              Broker.class,
+                                                                                              MemoryPoolMXBean.class);
+
+                final ConfiguredObjectInjectedAttribute<?, ?> injectedStatistic =
+                        new ConfiguredDerivedInjectedAttribute<>(attributeName,
+                                                                 getMemoryPoolMaximum,
+                                                                 new Object[]{memoryPoolMXBean},
+                                                                 false,
+                                                                 false,
+                                                                 "",
+                                                                 false,
+                                                                 "",
+                                                                 "Maximum size of memory pool",
+                                                                 _typeValidator);
+                attributes.add(injectedStatistic);
+            }
+            catch (NoSuchMethodException e)
+            {
+                LOGGER.warn("Failed to inject attribute '{}'", attributeName, e);
+            }
+        }
+        return attributes;
+    }
+
+    @Override
+    public Collection<ConfiguredObjectInjectedStatistic<?, ?>> getInjectedStatistics()
+    {
+        List<ConfiguredObjectInjectedStatistic<?, ?>> statistics = new ArrayList<>();
+        List<MemoryPoolMXBean> memoryPoolMXBeans = ManagementFactory.getMemoryPoolMXBeans();
+        for (MemoryPoolMXBean memoryPoolMXBean : memoryPoolMXBeans)
+        {
+            String poolName = memoryPoolMXBean.getName().replace(" ", "");
+            String statisticName = "jvmMemoryUsed" + poolName;
+            try
+            {
+                Method getMemoryPoolUsed = BrokerAttributeInjector.class.getDeclaredMethod("getMemoryPoolUsed",
+                                                                                           Broker.class,
+                                                                                           MemoryPoolMXBean.class);
+
+                final ConfiguredObjectInjectedStatistic<?, ?> injectedStatistic =
+                        new ConfiguredObjectInjectedStatistic<>(statisticName,
+                                                                getMemoryPoolUsed,
+                                                                new Object[]{memoryPoolMXBean},
+                                                                "Usage of memory in pool",
+                                                                _typeValidator,
+                                                                StatisticUnit.BYTES,
+                                                                StatisticType.POINT_IN_TIME,
+                                                                memoryPoolMXBean.getName() + " Memory Used");
+                statistics.add(injectedStatistic);
+            }
+            catch (NoSuchMethodException e)
+            {
+                LOGGER.warn("Failed to inject statistic '{}'", statisticName, e);
+            }
+        }
+
+        for (GarbageCollectorMXBean garbageCollectorMXBean : ManagementFactory.getGarbageCollectorMXBeans())
+        {
+            String gcName = garbageCollectorMXBean.getName().replace(" ", "");
+            String jvmGCCollectionTimeStatisticName = "jvmGCCollectionTime" + gcName;
+            try
+            {
+                Method getGCCollectionTime = BrokerAttributeInjector.class.getDeclaredMethod("getGCCollectionTime",
+                                                                                             Broker.class,
+                                                                                             GarbageCollectorMXBean.class);
+                final ConfiguredObjectInjectedStatistic<?, ?> injectedStatistic =
+                        new ConfiguredObjectInjectedStatistic<>(jvmGCCollectionTimeStatisticName,
+                                                                getGCCollectionTime,
+                                                                new Object[]{garbageCollectorMXBean},
+                                                                "Cumulative time in ms taken by GC to perform collections",
+                                                                _typeValidator,
+                                                                StatisticUnit.COUNT,
+                                                                StatisticType.CUMULATIVE,
+                                                                garbageCollectorMXBean.getName()
+                                                                + " GC Collection Time");
+                statistics.add(injectedStatistic);
+            }
+            catch (NoSuchMethodException e)
+            {
+                LOGGER.warn("Failed to inject statistic '{}'", jvmGCCollectionTimeStatisticName, e);
+            }
+            String jvmGCCollectionCountStatisticName = "jvmGCCollectionCount" + gcName;
+            try
+            {
+                Method getGCCollectionCount = BrokerAttributeInjector.class.getDeclaredMethod("getGCCollectionCount",
+                                                                                              Broker.class,
+                                                                                              GarbageCollectorMXBean.class);
+                final ConfiguredObjectInjectedStatistic<?, ?> injectedStatistic =
+                        new ConfiguredObjectInjectedStatistic<>(jvmGCCollectionCountStatisticName,
+                                                                getGCCollectionCount,
+                                                                new Object[]{garbageCollectorMXBean},
+                                                                "Cumulative number of GC collections",
+                                                                _typeValidator,
+                                                                StatisticUnit.COUNT,
+                                                                StatisticType.CUMULATIVE,
+                                                                garbageCollectorMXBean.getName()
+                                                                + " GC Collection Count");
+                statistics.add(injectedStatistic);
+            }
+            catch (NoSuchMethodException e)
+            {
+                LOGGER.warn("Failed to inject statistic '{}'", jvmGCCollectionCountStatisticName, e);
+            }
+        }
+        return statistics;
+    }
+
+    @Override
+    public Collection<ConfiguredObjectInjectedOperation<?>> getInjectedOperations()
+    {
+        List<ConfiguredObjectInjectedOperation<?>> operations = new ArrayList<>();
+
+        try
+        {
+            ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
+            final Class<?> hotSpotDiagnosticMXBeanClass =
+                    Class.forName("com.sun.management.HotSpotDiagnosticMXBean", true, systemClassLoader);
+            final PlatformManagedObject hotSpotDiagnosticMXBean =
+                    ManagementFactory.getPlatformMXBean((Class<? extends PlatformManagedObject>) hotSpotDiagnosticMXBeanClass);
+
+            ConfiguredObjectInjectedOperation<?> setJVMOptions =
+                    injectSetJVMOptions(hotSpotDiagnosticMXBeanClass, hotSpotDiagnosticMXBean);
+            if (setJVMOptions != null)
+            {
+                operations.add(setJVMOptions);
+            }
+
+            ConfiguredObjectInjectedOperation<?> heapDump =
+                    injectDumpHeap(hotSpotDiagnosticMXBeanClass, hotSpotDiagnosticMXBean);
+            if (heapDump != null)
+            {
+                operations.add(heapDump);
+            }
+        }
+        catch (ClassNotFoundException e)
+        {
+            LOGGER.warn("Cannot find com.sun.management.HotSpotDiagnosticMXBean MXBean: " + e.getMessage());
+        }
+
+
+        return operations;
+    }
+
+    private ConfiguredObjectInjectedOperation<?> injectDumpHeap(
+            final Class<?> hotSpotDiagnosticMXBeanClass,
+            final PlatformManagedObject hotSpotDiagnosticMXBean)
+    {
+        try
+        {
+            Method heapDumpMethod =
+                    hotSpotDiagnosticMXBeanClass.getDeclaredMethod("dumpHeap", String.class, boolean.class);
+
+            Method method = BrokerAttributeInjector.class.getDeclaredMethod("dumpHeap",
+                                                                            Broker.class,
+                                                                            PlatformManagedObject.class,
+                                                                            Method.class,
+                                                                            String.class,
+                                                                            boolean.class);
+
+            final OperationParameter[] params = new OperationParameter[2];
+
+            params[0] = new OperationParameterFromInjection("outputFile",
+                                                            String.class,
+                                                            String.class,
+                                                            "",
+                                                            "the system-dependent filename",
+                                                            new String[0]);
+            params[1] = new OperationParameterFromInjection("live",
+                                                            boolean.class,
+                                                            boolean.class,
+                                                            "true",
+                                                            "if true dump only live objects i.e. objects that are reachable from others",
+                                                            new String[]{Boolean.TRUE.toString(), Boolean.FALSE.toString()});
+            ConfiguredObjectInjectedOperation<?> setVMOptionOperation = new ConfiguredObjectInjectedOperation(
+                    "dumpHeap",
+                    "Dumps the heap to the outputFile file in the same format as the hprof heap dump.",
+                    true,
+                    params,
+                    method,
+                    new Object[]{hotSpotDiagnosticMXBean, heapDumpMethod},
+                    _typeValidator);
+            return setVMOptionOperation;
+        }
+        catch (NoSuchMethodException e)
+        {
+            LOGGER.warn("Failed to inject operation dumpHeap", e);
+        }
+        return null;
+    }
+
+    private ConfiguredObjectInjectedOperation<?> injectSetJVMOptions(
+            final Class<?> hotSpotDiagnosticMXBeanClass,
+            final PlatformManagedObject hotSpotDiagnosticMXBean)
+    {
+        try
+        {
+            Method setVMOptionMethod =
+                    hotSpotDiagnosticMXBeanClass.getDeclaredMethod("setVMOption", String.class, String.class);
+
+            Method method = BrokerAttributeInjector.class.getDeclaredMethod("setJVMOptions",
+                                                                            Broker.class,
+                                                                            PlatformManagedObject.class,
+                                                                            Method.class,
+                                                                            Map.class);
+
+            final OperationParameter[] params =
+                    new OperationParameter[]{new OperationParameterFromInjection("options",
+                                                                                 Map.class,
+                                                                                 new ParameterizedTypeImpl(
+                                                                                         Map.class,
+                                                                                         String.class,
+                                                                                         String.class),
+                                                                                 "",
+                                                                                 "JVM options map",
+                                                                                 new String[0])};
+            ConfiguredObjectInjectedOperation<?> setVMOptionOperation = new ConfiguredObjectInjectedOperation(
+                    "setJVMOptions",
+                    "Sets given JVM options",
+                    true,
+                    params,
+                    method,
+                    new Object[]{hotSpotDiagnosticMXBean, setVMOptionMethod},
+                    _typeValidator);
+            return setVMOptionOperation;
+        }
+        catch (NoSuchMethodException e)
+        {
+            LOGGER.warn("Failed to inject operation setJVMOptions", e);
+        }
+        return null;
+    }
+
+    @Override
+    public String getType()
+    {
+        return "Broker";
+    }
+
+    public static long getMemoryPoolUsed(Broker<?> broker, MemoryPoolMXBean memoryPoolMXBean)
+    {
+        return memoryPoolMXBean.getUsage().getUsed();
+    }
+
+    public static long getMemoryPoolMaximum(Broker<?> broker, MemoryPoolMXBean memoryPoolMXBean)
+    {
+        return memoryPoolMXBean.getUsage().getMax();
+    }
+
+    public static long getGCCollectionTime(Broker<?> broker, GarbageCollectorMXBean garbageCollectorMXBean)
+    {
+        return garbageCollectorMXBean.getCollectionTime();
+    }
+
+    public static long getGCCollectionCount(Broker<?> broker, GarbageCollectorMXBean garbageCollectorMXBean)
+    {
+        return garbageCollectorMXBean.getCollectionCount();
+    }
+
+    public static void setJVMOptions(Broker<?> broker,
+                                     PlatformManagedObject hotSpotDiagnosticMXBean,
+                                     Method setVMOption,
+                                     Map<String, String> options)
+    {
+        broker.getSecurityManager().authorise(Operation.CONFIGURE, broker);
+        broker.getEventLogger().message(BrokerMessages.OPERATION("setJVMOptions"));
+        StringBuilder exceptionMessages = new StringBuilder();
+        for (Map.Entry<String, String> entry : options.entrySet())
+        {
+            try
+            {
+                setVMOption.invoke(hotSpotDiagnosticMXBean, entry.getKey(), entry.getValue());
+            }
+            catch (IllegalAccessException e)
+            {
+                LOGGER.warn("Cannot access setVMOption " + setVMOption);
+            }
+            catch (InvocationTargetException e)
+            {
+                if (exceptionMessages.length() > 0)
+                {
+                    exceptionMessages.append(";");
+                }
+                exceptionMessages.append(e.getTargetException().toString());
+                LOGGER.warn("Cannot set option {} to {} due to {}",
+                            entry.getKey(),
+                            entry.getValue(),
+                            e.getTargetException().toString());
+            }
+
+            if (exceptionMessages.length() > 0)
+            {
+                throw new IllegalConfigurationException("Exception(s) occurred whilst setting JVM options : " +
+                                                        exceptionMessages.toString());
+            }
+        }
+    }
+
+    public static void dumpHeap(Broker<?> broker,
+                                PlatformManagedObject hotSpotDiagnosticMXBean,
+                                Method dumpHeapMethod,
+                                String outputFile,
+                                boolean live)
+    {
+        broker.getSecurityManager().authorise(Operation.CONFIGURE, broker);
+        broker.getEventLogger().message(BrokerMessages.OPERATION("dumpHeap"));
+        try
+        {
+            dumpHeapMethod.invoke(hotSpotDiagnosticMXBean, outputFile, live);
+        }
+        catch (IllegalAccessException e)
+        {
+            LOGGER.warn("Cannot access dumpHeap " + dumpHeapMethod);
+        }
+        catch (InvocationTargetException e)
+        {
+            String causeAsString = e.getTargetException().toString();
+            LOGGER.warn("Cannot collect heap dump into {} (with parameter 'live' set to '{}') due to {}",
+                        outputFile,
+                        live,
+                        causeAsString);
+            throw new IllegalConfigurationException("Unexpected exception on collecting heap dump : "
+                                                    + causeAsString,
+                                                    e.getTargetException());
+        }
+    }
+}

Modified: qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObject.java
URL: http://svn.apache.org/viewvc/qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObject.java?rev=1728772&r1=1728771&r2=1728772&view=diff
==============================================================================
--- qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObject.java (original)
+++ qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObject.java Fri Feb  5 22:58:00 2016
@@ -125,6 +125,8 @@ public interface ConfiguredObject<X exte
     @DerivedAttribute
     State getState();
 
+    @DerivedAttribute
+    long getLastOpenedTime();
 
     /**
      * Add a listener which will be informed of all changes to this configuration object

Modified: qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/model/adapter/BrokerAdapter.java
URL: http://svn.apache.org/viewvc/qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/model/adapter/BrokerAdapter.java?rev=1728772&r1=1728771&r2=1728772&view=diff
==============================================================================
--- qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/model/adapter/BrokerAdapter.java (original)
+++ qpid/java/trunk/broker-core/src/main/java/org/apache/qpid/server/model/adapter/BrokerAdapter.java Fri Feb  5 22:58:00 2016
@@ -20,11 +20,19 @@
  */
 package org.apache.qpid.server.model.adapter;
 
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.management.BufferPoolMXBean;
+import java.lang.management.LockInfo;
 import java.lang.management.ManagementFactory;
+import java.lang.management.MonitorInfo;
 import java.lang.management.PlatformManagedObject;
 import java.lang.management.RuntimeMXBean;
+import java.lang.management.ThreadInfo;
+import java.lang.management.ThreadMXBean;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
+import java.nio.charset.Charset;
 import java.security.AccessControlException;
 import java.security.PrivilegedAction;
 import java.util.ArrayList;
@@ -117,6 +125,10 @@ public class BrokerAdapter extends Abstr
     private final boolean _virtualHostPropertiesNodeEnabled;
     private Collection<BrokerLogger> _brokerLoggersToClose;
     private int _networkBufferSize = DEFAULT_NETWORK_BUFFER_SIZE;
+    private final long _maximumHeapHize = Runtime.getRuntime().maxMemory();
+    private final long _maximumDirectMemorySize = getMaxDirectMemorySize();
+    private final BufferPoolMXBean _bufferPoolMXBean;
+    private final List<String> _inputArguments;
 
     @ManagedObjectFactoryConstructor
     public BrokerAdapter(Map<String, Object> attributes,
@@ -149,6 +161,19 @@ public class BrokerAdapter extends Abstr
         _dataDelivered = new StatisticsCounter("bytes-delivered");
         _messagesReceived = new StatisticsCounter("messages-received");
         _dataReceived = new StatisticsCounter("bytes-received");
+
+        BufferPoolMXBean bufferPoolMXBean = null;
+        List<BufferPoolMXBean> bufferPoolMXBeans = ManagementFactory.getPlatformMXBeans(BufferPoolMXBean.class);
+        for(BufferPoolMXBean mBean : bufferPoolMXBeans)
+        {
+            if (mBean.getName().equals("direct"))
+            {
+                bufferPoolMXBean = mBean;
+                break;
+            }
+        }
+        _bufferPoolMXBean = bufferPoolMXBean;
+        _inputArguments = ManagementFactory.getRuntimeMXBean().getInputArguments();
     }
 
     private void updateEncrypter(final String encryptionProviderType)
@@ -307,6 +332,7 @@ public class BrokerAdapter extends Abstr
     public void initiateShutdown()
     {
         _securityManager.authorise(Operation.SHUTDOWN, this);
+        getEventLogger().message(BrokerMessages.OPERATION("initiateShutdown"));
         _parent.closeAsync();
     }
 
@@ -982,4 +1008,228 @@ public class BrokerAdapter extends Abstr
     {
         return _networkBufferSize;
     }
+
+    @Override
+    public int getNumberOfLiveThreads()
+    {
+        return ManagementFactory.getThreadMXBean().getThreadCount();
+    }
+
+    @Override
+    public long getMaximumHeapMemorySize()
+    {
+        return _maximumHeapHize;
+    }
+
+    @Override
+    public long getUsedHeapMemorySize()
+    {
+        return Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
+    }
+
+    @Override
+    public long getMaximumDirectMemorySize()
+    {
+        return _maximumDirectMemorySize;
+    }
+
+    @Override
+    public long getUsedDirectMemorySize()
+    {
+        if (_bufferPoolMXBean == null)
+        {
+            return -1;
+        }
+        return _bufferPoolMXBean.getMemoryUsed();
+    }
+
+    @Override
+    public long getDirectMemoryTotalCapacity()
+    {
+        if (_bufferPoolMXBean == null)
+        {
+            return -1;
+        }
+        return _bufferPoolMXBean.getTotalCapacity();
+    }
+
+    @Override
+    public int getNumberOfObjectsPendingFinalization()
+    {
+        return ManagementFactory.getMemoryMXBean().getObjectPendingFinalizationCount();
+    }
+
+    @Override
+    public List<String> getJVMArguments()
+    {
+        return _inputArguments;
+    }
+
+    @Override
+    public void performGC()
+    {
+        _securityManager.authorise(Operation.CONFIGURE, this);
+        getEventLogger().message(BrokerMessages.OPERATION("performGC"));
+        System.gc();
+    }
+
+    @Override
+    public Content getThreadStackTraces(boolean appendToLog)
+    {
+        _securityManager.authorise(Operation.CONFIGURE, this);
+        getEventLogger().message(BrokerMessages.OPERATION("getThreadStackTraces"));
+        ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
+        ThreadInfo[] threadInfos = threadMXBean.dumpAllThreads(true, true);
+        StringBuilder threadDump = new StringBuilder();
+        for (ThreadInfo threadInfo : threadInfos)
+        {
+            threadDump.append(getThreadStackTraces(threadInfo));
+        }
+        long[] deadLocks = threadMXBean.findDeadlockedThreads();
+        if (deadLocks != null && deadLocks.length > 0)
+        {
+            ThreadInfo[] deadlockedThreads = threadMXBean.getThreadInfo(deadLocks);
+            threadDump.append(System.lineSeparator()).append("Deadlock is detected!").append(System.lineSeparator());
+            for (ThreadInfo threadInfo : deadlockedThreads)
+            {
+                threadDump.append(getThreadStackTraces(threadInfo));
+            }
+        }
+        String threadStackTraces = threadDump.toString();
+        if (appendToLog)
+        {
+            LOGGER.warn("Thread dump:{} {}", System.lineSeparator(), threadStackTraces);
+        }
+        return new ThreadStackContent(threadStackTraces);
+    }
+
+    @Override
+    public Content findThreadStackTraces(String threadNameFindExpression)
+    {
+        _securityManager.authorise(Operation.CONFIGURE, this);
+        getEventLogger().message(BrokerMessages.OPERATION("findThreadStackTraces"));
+        ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
+        ThreadInfo[] threadInfos = threadMXBean.dumpAllThreads(true, true);
+        StringBuilder threadDump = new StringBuilder();
+        Pattern pattern = threadNameFindExpression == null || threadNameFindExpression.equals("") ? null : Pattern.compile(
+                threadNameFindExpression);
+        for (ThreadInfo threadInfo : threadInfos)
+        {
+            if (pattern== null || pattern.matcher(threadInfo.getThreadName()).find())
+            {
+                threadDump.append(getThreadStackTraces(threadInfo));
+            }
+        }
+        return new ThreadStackContent(threadDump.toString());
+    }
+
+    private String getThreadStackTraces(final ThreadInfo threadInfo)
+    {
+        String lineSeparator = System.lineSeparator();
+        StringBuilder dump = new StringBuilder();
+        dump.append("\"").append(threadInfo.getThreadName()).append("\"").append(" Id=")
+            .append(threadInfo.getThreadId()).append( " ").append(threadInfo.getThreadState());
+        if (threadInfo.getLockName() != null)
+        {
+            dump.append(" on ").append(threadInfo.getLockName());
+        }
+        if (threadInfo.getLockOwnerName() != null)
+        {
+            dump.append(" owned by \"").append(threadInfo.getLockOwnerName())
+                .append("\" Id=").append(threadInfo.getLockOwnerId());
+        }
+        if (threadInfo.isSuspended())
+        {
+            dump.append(" (suspended)");
+        }
+        if (threadInfo.isInNative())
+        {
+            dump.append(" (in native)");
+        }
+        dump.append(lineSeparator);
+        StackTraceElement[] stackTrace = threadInfo.getStackTrace();
+        for (int i = 0; i < stackTrace.length; i++)
+        {
+            StackTraceElement stackTraceElement = stackTrace[i];
+            dump.append("    at ").append(stackTraceElement.toString()).append(lineSeparator);
+
+            LockInfo lockInfo = threadInfo.getLockInfo();
+            if (i == 0 && lockInfo != null)
+            {
+                Thread.State threadState = threadInfo.getThreadState();
+                switch (threadState)
+                {
+                    case BLOCKED:
+                        dump.append("    -  blocked on ").append(lockInfo).append(lineSeparator);
+                        break;
+                    case WAITING:
+                        dump.append("    -  waiting on ").append(lockInfo).append(lineSeparator);
+                        break;
+                    case TIMED_WAITING:
+                        dump.append("    -  waiting on ").append(lockInfo).append(lineSeparator);
+                        break;
+                    default:
+                }
+            }
+
+            for (MonitorInfo mi : threadInfo.getLockedMonitors())
+            {
+                if (mi.getLockedStackDepth() == i)
+                {
+                    dump.append("    -  locked ").append(mi).append(lineSeparator);
+                }
+            }
+        }
+
+        LockInfo[] locks = threadInfo.getLockedSynchronizers();
+        if (locks.length > 0)
+        {
+            dump.append(lineSeparator).append("    Number of locked synchronizers = ").append(locks.length);
+            dump.append(lineSeparator);
+            for (LockInfo li : locks)
+            {
+                dump.append("    - " + li);
+                dump.append(lineSeparator);
+            }
+        }
+        dump.append(lineSeparator);
+        return dump.toString();
+    }
+
+    public static class ThreadStackContent implements Content, CustomRestHeaders
+    {
+        private final String _threadStackTraces;
+
+        public ThreadStackContent(final String threadStackTraces)
+        {
+            _threadStackTraces = threadStackTraces;
+        }
+
+        @Override
+        public void write(final OutputStream outputStream) throws IOException
+        {
+            if (_threadStackTraces != null)
+            {
+                outputStream.write(_threadStackTraces.getBytes(Charset.forName("UTF-8")));
+            }
+        }
+
+        @Override
+        public void release()
+        {
+            // noop; nothing to release
+        }
+
+        @RestContentHeader("Content-Type")
+        public String getContentType()
+        {
+            return "text/plain;charset=utf-8";
+        }
+
+        @RestContentHeader("Content-Length")
+        public long getSize()
+        {
+            return _threadStackTraces == null ? 0 : _threadStackTraces.length();
+        }
+    }
 }




---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org