You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@activemq.apache.org by cs...@apache.org on 2019/07/31 18:09:50 UTC

[activemq] 02/04: AMQ-7094 - track the objectName with an annotated mbean such that the jmx audit log event can extract that target of an mbean operation, fix and test

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

cshannon pushed a commit to branch activemq-5.15.x
in repository https://gitbox.apache.org/repos/asf/activemq.git

commit 70b2a4318375a573bdbda61303f5cfc19d33ff7d
Author: gtully <ga...@gmail.com>
AuthorDate: Thu Nov 8 12:10:01 2018 +0000

    AMQ-7094 - track the objectName with an annotated mbean such that the jmx audit log event can extract that target of an mbean operation, fix and test
    
    (cherry picked from commit d2b0affedb38c5439bce2fb5a8e321bc5d0ec713)
---
 .../apache/activemq/broker/jmx/AnnotatedMBean.java | 26 +++++++-
 .../activemq/broker/jmx/AsyncAnnotatedMBean.java   | 12 ++--
 .../activemq/broker/util/JMXAuditLogEntry.java     | 13 +++-
 .../java/org/apache/activemq/jmx/DLQRetryTest.java |  1 +
 .../org/apache/activemq/jmx/JmxAuditLogTest.java   | 75 ++++++++++++++++++++++
 .../org/apache/activemq/jmx/JmxCreateNCTest.java   |  3 +
 6 files changed, 120 insertions(+), 10 deletions(-)

diff --git a/activemq-broker/src/main/java/org/apache/activemq/broker/jmx/AnnotatedMBean.java b/activemq-broker/src/main/java/org/apache/activemq/broker/jmx/AnnotatedMBean.java
index c75d8a8..dc772c2 100644
--- a/activemq-broker/src/main/java/org/apache/activemq/broker/jmx/AnnotatedMBean.java
+++ b/activemq-broker/src/main/java/org/apache/activemq/broker/jmx/AnnotatedMBean.java
@@ -68,6 +68,8 @@ public class AnnotatedMBean extends StandardMBean {
         }
     }
 
+    private final ObjectName objectName;
+
     private static byte byteFromProperty(String s) {
         byte val = OFF;
         String config = System.getProperty(s, "").toLowerCase(Locale.ENGLISH);
@@ -88,7 +90,7 @@ public class AnnotatedMBean extends StandardMBean {
 
         for (Class c : object.getClass().getInterfaces()) {
             if (mbeanName.equals(c.getName())) {
-                context.registerMBean(new AnnotatedMBean(object, c), objectName);
+                context.registerMBean(new AnnotatedMBean(object, c, objectName), objectName);
                 return;
             }
         }
@@ -97,13 +99,15 @@ public class AnnotatedMBean extends StandardMBean {
     }
 
     /** Instance where the MBean interface is implemented by another object. */
-    public <T> AnnotatedMBean(T impl, Class<T> mbeanInterface) throws NotCompliantMBeanException {
+    public <T> AnnotatedMBean(T impl, Class<T> mbeanInterface, ObjectName objectName) throws NotCompliantMBeanException {
         super(impl, mbeanInterface);
+        this.objectName = objectName;
     }
 
     /** Instance where the MBean interface is implemented by this object. */
-    protected AnnotatedMBean(Class<?> mbeanInterface) throws NotCompliantMBeanException {
+    protected AnnotatedMBean(Class<?> mbeanInterface, ObjectName objectName) throws NotCompliantMBeanException {
         super(mbeanInterface);
+        this.objectName = objectName;
     }
 
     /** {@inheritDoc} */
@@ -212,6 +216,7 @@ public class AnnotatedMBean extends StandardMBean {
             entry = new JMXAuditLogEntry();
             entry.setUser(caller);
             entry.setTimestamp(System.currentTimeMillis());
+            entry.setTarget(extractTargetTypeProperty(objectName));
             entry.setOperation(this.getMBeanInfo().getClassName() + "." + s);
 
             try
@@ -245,6 +250,21 @@ public class AnnotatedMBean extends StandardMBean {
         return result;
     }
 
+    // keep brokerName last b/c objectNames include the brokerName
+    final static String[] targetPropertiesCandidates = new String[] {"destinationName", "networkConnectorName", "connectorName", "connectionName", "brokerName"};
+    private String extractTargetTypeProperty(ObjectName objectName) {
+        String result = null;
+        for (String attr: targetPropertiesCandidates) {
+            try {
+                result = objectName.getKeyProperty(attr);
+                if (result != null) {
+                    break;
+                }
+            } catch (NullPointerException ok) {}
+        }
+        return result;
+    }
+
     private Method getMBeanMethod(Class clazz, String methodName, String[] signature) throws ReflectiveOperationException {
         Class[] parameterTypes = new Class[signature.length];
         for (int i = 0; i < signature.length; i++) {
diff --git a/activemq-broker/src/main/java/org/apache/activemq/broker/jmx/AsyncAnnotatedMBean.java b/activemq-broker/src/main/java/org/apache/activemq/broker/jmx/AsyncAnnotatedMBean.java
index 7460e16..7871a21 100644
--- a/activemq-broker/src/main/java/org/apache/activemq/broker/jmx/AsyncAnnotatedMBean.java
+++ b/activemq-broker/src/main/java/org/apache/activemq/broker/jmx/AsyncAnnotatedMBean.java
@@ -36,15 +36,15 @@ public class AsyncAnnotatedMBean extends AnnotatedMBean {
     private ExecutorService executor;
     private long timeout = 0;
 
-    public <T> AsyncAnnotatedMBean(ExecutorService executor, long timeout, T impl, Class<T> mbeanInterface) throws NotCompliantMBeanException {
-        super(impl, mbeanInterface);
+    public <T> AsyncAnnotatedMBean(ExecutorService executor, long timeout, T impl, Class<T> mbeanInterface, ObjectName objectName) throws NotCompliantMBeanException {
+        super(impl, mbeanInterface, objectName);
 
         this.executor = executor;
         this.timeout = timeout;
     }
 
-    protected AsyncAnnotatedMBean(Class<?> mbeanInterface) throws NotCompliantMBeanException {
-        super(mbeanInterface);
+    protected AsyncAnnotatedMBean(Class<?> mbeanInterface, ObjectName objectName) throws NotCompliantMBeanException {
+        super(mbeanInterface, objectName);
     }
 
     protected Object asyncInvole(String s, Object[] objects, String[] strings) throws MBeanException, ReflectionException {
@@ -67,9 +67,9 @@ public class AsyncAnnotatedMBean extends AnnotatedMBean {
         for (Class c : object.getClass().getInterfaces()) {
             if (mbeanName.equals(c.getName())) {
                 if (timeout == 0) {
-                    context.registerMBean(new AnnotatedMBean(object, c), objectName);
+                    context.registerMBean(new AnnotatedMBean(object, c, objectName), objectName);
                 } else {
-                    context.registerMBean(new AsyncAnnotatedMBean(executor, timeout, object, c), objectName);
+                    context.registerMBean(new AsyncAnnotatedMBean(executor, timeout, object, c, objectName), objectName);
                 }
                 return;
             }
diff --git a/activemq-broker/src/main/java/org/apache/activemq/broker/util/JMXAuditLogEntry.java b/activemq-broker/src/main/java/org/apache/activemq/broker/util/JMXAuditLogEntry.java
index 7e0e0e3..3ced281 100644
--- a/activemq-broker/src/main/java/org/apache/activemq/broker/util/JMXAuditLogEntry.java
+++ b/activemq-broker/src/main/java/org/apache/activemq/broker/util/JMXAuditLogEntry.java
@@ -21,14 +21,25 @@ import java.util.Arrays;
 public class JMXAuditLogEntry extends AuditLogEntry {
     public static final String[] VERBS = new String[] {" called ", " ended "};
     private int state = 0;
+    protected String target;
 
     public void complete() {
         setTimestamp(System.currentTimeMillis());
         state = 1;
     }
 
+    public String getTarget() {
+        return target;
+    }
+
+    public void setTarget(String target) {
+        this.target = target;
+    }
+
     @Override
     public String toString() {
-        return user.trim() + VERBS[state] + operation + Arrays.toString((Object[])parameters.get("arguments")) + " at " + getFormattedTime();
+        return user.trim() + VERBS[state] + operation + Arrays.toString((Object[])parameters.get("arguments"))
+                + (target != null ? " on " + target : "")
+                + " at " + getFormattedTime();
     }
 }
diff --git a/activemq-unit-tests/src/test/java/org/apache/activemq/jmx/DLQRetryTest.java b/activemq-unit-tests/src/test/java/org/apache/activemq/jmx/DLQRetryTest.java
index e2875fb..e4f3c16 100644
--- a/activemq-unit-tests/src/test/java/org/apache/activemq/jmx/DLQRetryTest.java
+++ b/activemq-unit-tests/src/test/java/org/apache/activemq/jmx/DLQRetryTest.java
@@ -151,6 +151,7 @@ public class DLQRetryTest extends EmbeddedBrokerTestSupport {
     }
 
     protected void setUp() throws Exception {
+        System.setProperty("org.apache.activemq.audit", "all");
         bindAddress = "tcp://localhost:0";
         useTopic = false;
         super.setUp();
diff --git a/activemq-unit-tests/src/test/java/org/apache/activemq/jmx/JmxAuditLogTest.java b/activemq-unit-tests/src/test/java/org/apache/activemq/jmx/JmxAuditLogTest.java
index e6f1083..5256b96 100644
--- a/activemq-unit-tests/src/test/java/org/apache/activemq/jmx/JmxAuditLogTest.java
+++ b/activemq-unit-tests/src/test/java/org/apache/activemq/jmx/JmxAuditLogTest.java
@@ -30,6 +30,8 @@ import java.util.concurrent.atomic.AtomicInteger;
 
 import org.apache.activemq.TestSupport;
 import org.apache.activemq.broker.BrokerService;
+import org.apache.activemq.broker.TransportConnector;
+import org.apache.activemq.broker.jmx.BrokerMBeanSupport;
 import org.apache.activemq.broker.jmx.ManagementContext;
 import org.apache.activemq.command.ActiveMQDestination;
 import org.apache.activemq.command.ActiveMQQueue;
@@ -62,10 +64,13 @@ public class JmxAuditLogTest extends TestSupport
 
       broker = new BrokerService();
       broker.setUseJmx(true);
+      broker.setDeleteAllMessagesOnStartup(true);
       portToUse = findOpenPort();
       broker.setManagementContext(createManagementContext("broker", portToUse));
       broker.setPopulateUserNameInMBeans(true);
       broker.setDestinations(createDestinations());
+      TransportConnector transportConnector = broker.addConnector("tcp://0.0.0.0:0");
+      transportConnector.setName("TCP");
       broker.start();
    }
 
@@ -154,4 +159,74 @@ public class JmxAuditLogTest extends TestSupport
       assertEquals("got two messages", 2, logCount.get());
 
    }
+
+   @Test
+   public void testNameTargetVisible() throws Exception
+   {
+      Logger log4jLogger = Logger.getLogger("org.apache.activemq.audit");
+      log4jLogger.setLevel(Level.INFO);
+      final AtomicInteger logCount = new AtomicInteger(0);
+      final AtomicBoolean gotEnded = new AtomicBoolean(false);
+      final AtomicBoolean gotQueueName = new AtomicBoolean(false);
+      final AtomicBoolean gotBrokerName = new AtomicBoolean(false);
+      final AtomicBoolean gotConnectorName = new AtomicBoolean(false);
+
+      final String queueName = queue.getQueueName();
+      Appender appender = new DefaultTestAppender()
+      {
+         @Override
+         public void doAppend(LoggingEvent event)
+         {
+            if (event.getMessage() instanceof String)
+            {
+               String message = (String) event.getMessage();
+               System.out.println(message);
+               if (message.contains(VERBS[0])) {
+                  if (message.contains(queueName)) {
+                     gotQueueName.set(true);
+                  }
+                  if (message.contains(broker.getBrokerName())) {
+                     gotBrokerName.set(true);
+                  }
+
+                  if (message.contains("TCP")) {
+                     gotConnectorName.set(true);
+                  }
+               }
+
+               if (message.contains(VERBS[1])) {
+                  gotEnded.set(true);
+               }
+            }
+            logCount.incrementAndGet();
+         }
+      };
+      log4jLogger.addAppender(appender);
+
+      MBeanServerConnection conn = createJMXConnector(portToUse);
+      ObjectName queueObjName = new ObjectName(broker.getBrokerObjectName() + ",destinationType=Queue,destinationName=" + queueName);
+
+      Object[] params = {};
+      String[] signature = {};
+
+      conn.invoke(queueObjName, "purge", params, signature);
+
+      assertTrue("got ended statement", gotEnded.get());
+      assertEquals("got two messages", 2, logCount.get());
+      assertTrue("got queueName in called statement", gotQueueName.get());
+
+      // call broker to verify brokerName
+      conn.invoke(broker.getBrokerObjectName(), "resetStatistics", params, signature);
+      assertEquals("got 4 messages", 4, logCount.get());
+      assertTrue("got brokerName in called statement", gotBrokerName.get());
+
+
+      ObjectName transportConnectorON = BrokerMBeanSupport.createConnectorName(broker.getBrokerObjectName(), "clientConnectors", "TCP");
+      conn.invoke(transportConnectorON, "stop", params, signature);
+      assertEquals("got messages", 6, logCount.get());
+      assertTrue("got connectorName in called statement", gotConnectorName.get());
+
+      log4jLogger.removeAppender(appender);
+
+   }
 }
diff --git a/activemq-unit-tests/src/test/java/org/apache/activemq/jmx/JmxCreateNCTest.java b/activemq-unit-tests/src/test/java/org/apache/activemq/jmx/JmxCreateNCTest.java
index e96c596..1d878b4 100644
--- a/activemq-unit-tests/src/test/java/org/apache/activemq/jmx/JmxCreateNCTest.java
+++ b/activemq-unit-tests/src/test/java/org/apache/activemq/jmx/JmxCreateNCTest.java
@@ -38,6 +38,9 @@ public class JmxCreateNCTest {
 
     @Test
     public void testBridgeRegistration() throws Exception {
+
+        System.setProperty("org.apache.activemq.audit", "all");
+
         BrokerService broker = new BrokerService();
         broker.setBrokerName(BROKER_NAME);
         broker.setUseJmx(true); // explicitly set this so no funny issues