mirror of https://github.com/apache/activemq.git
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 commit is contained in:
parent
85859fd8dc
commit
d2b0affedb
|
@ -68,6 +68,8 @@ public class AnnotatedMBean extends StandardMBean {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private final ObjectName objectName;
|
||||||
|
|
||||||
private static byte byteFromProperty(String s) {
|
private static byte byteFromProperty(String s) {
|
||||||
byte val = OFF;
|
byte val = OFF;
|
||||||
String config = System.getProperty(s, "").toLowerCase(Locale.ENGLISH);
|
String config = System.getProperty(s, "").toLowerCase(Locale.ENGLISH);
|
||||||
|
@ -88,7 +90,7 @@ public class AnnotatedMBean extends StandardMBean {
|
||||||
|
|
||||||
for (Class c : object.getClass().getInterfaces()) {
|
for (Class c : object.getClass().getInterfaces()) {
|
||||||
if (mbeanName.equals(c.getName())) {
|
if (mbeanName.equals(c.getName())) {
|
||||||
context.registerMBean(new AnnotatedMBean(object, c), objectName);
|
context.registerMBean(new AnnotatedMBean(object, c, objectName), objectName);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -97,13 +99,15 @@ public class AnnotatedMBean extends StandardMBean {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Instance where the MBean interface is implemented by another object. */
|
/** 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);
|
super(impl, mbeanInterface);
|
||||||
|
this.objectName = objectName;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Instance where the MBean interface is implemented by this object. */
|
/** 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);
|
super(mbeanInterface);
|
||||||
|
this.objectName = objectName;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritDoc} */
|
/** {@inheritDoc} */
|
||||||
|
@ -212,6 +216,7 @@ public class AnnotatedMBean extends StandardMBean {
|
||||||
entry = new JMXAuditLogEntry();
|
entry = new JMXAuditLogEntry();
|
||||||
entry.setUser(caller);
|
entry.setUser(caller);
|
||||||
entry.setTimestamp(System.currentTimeMillis());
|
entry.setTimestamp(System.currentTimeMillis());
|
||||||
|
entry.setTarget(extractTargetTypeProperty(objectName));
|
||||||
entry.setOperation(this.getMBeanInfo().getClassName() + "." + s);
|
entry.setOperation(this.getMBeanInfo().getClassName() + "." + s);
|
||||||
|
|
||||||
try
|
try
|
||||||
|
@ -245,6 +250,21 @@ public class AnnotatedMBean extends StandardMBean {
|
||||||
return result;
|
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 {
|
private Method getMBeanMethod(Class clazz, String methodName, String[] signature) throws ReflectiveOperationException {
|
||||||
Class[] parameterTypes = new Class[signature.length];
|
Class[] parameterTypes = new Class[signature.length];
|
||||||
for (int i = 0; i < signature.length; i++) {
|
for (int i = 0; i < signature.length; i++) {
|
||||||
|
|
|
@ -36,15 +36,15 @@ public class AsyncAnnotatedMBean extends AnnotatedMBean {
|
||||||
private ExecutorService executor;
|
private ExecutorService executor;
|
||||||
private long timeout = 0;
|
private long timeout = 0;
|
||||||
|
|
||||||
public <T> AsyncAnnotatedMBean(ExecutorService executor, long timeout, T impl, Class<T> mbeanInterface) throws NotCompliantMBeanException {
|
public <T> AsyncAnnotatedMBean(ExecutorService executor, long timeout, T impl, Class<T> mbeanInterface, ObjectName objectName) throws NotCompliantMBeanException {
|
||||||
super(impl, mbeanInterface);
|
super(impl, mbeanInterface, objectName);
|
||||||
|
|
||||||
this.executor = executor;
|
this.executor = executor;
|
||||||
this.timeout = timeout;
|
this.timeout = timeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected AsyncAnnotatedMBean(Class<?> mbeanInterface) throws NotCompliantMBeanException {
|
protected AsyncAnnotatedMBean(Class<?> mbeanInterface, ObjectName objectName) throws NotCompliantMBeanException {
|
||||||
super(mbeanInterface);
|
super(mbeanInterface, objectName);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Object asyncInvole(String s, Object[] objects, String[] strings) throws MBeanException, ReflectionException {
|
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()) {
|
for (Class c : object.getClass().getInterfaces()) {
|
||||||
if (mbeanName.equals(c.getName())) {
|
if (mbeanName.equals(c.getName())) {
|
||||||
if (timeout == 0) {
|
if (timeout == 0) {
|
||||||
context.registerMBean(new AnnotatedMBean(object, c), objectName);
|
context.registerMBean(new AnnotatedMBean(object, c, objectName), objectName);
|
||||||
} else {
|
} else {
|
||||||
context.registerMBean(new AsyncAnnotatedMBean(executor, timeout, object, c), objectName);
|
context.registerMBean(new AsyncAnnotatedMBean(executor, timeout, object, c, objectName), objectName);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,14 +21,25 @@ import java.util.Arrays;
|
||||||
public class JMXAuditLogEntry extends AuditLogEntry {
|
public class JMXAuditLogEntry extends AuditLogEntry {
|
||||||
public static final String[] VERBS = new String[] {" called ", " ended "};
|
public static final String[] VERBS = new String[] {" called ", " ended "};
|
||||||
private int state = 0;
|
private int state = 0;
|
||||||
|
protected String target;
|
||||||
|
|
||||||
public void complete() {
|
public void complete() {
|
||||||
setTimestamp(System.currentTimeMillis());
|
setTimestamp(System.currentTimeMillis());
|
||||||
state = 1;
|
state = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getTarget() {
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTarget(String target) {
|
||||||
|
this.target = target;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -151,6 +151,7 @@ public class DLQRetryTest extends EmbeddedBrokerTestSupport {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void setUp() throws Exception {
|
protected void setUp() throws Exception {
|
||||||
|
System.setProperty("org.apache.activemq.audit", "all");
|
||||||
bindAddress = "tcp://localhost:0";
|
bindAddress = "tcp://localhost:0";
|
||||||
useTopic = false;
|
useTopic = false;
|
||||||
super.setUp();
|
super.setUp();
|
||||||
|
|
|
@ -30,6 +30,8 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
import org.apache.activemq.TestSupport;
|
import org.apache.activemq.TestSupport;
|
||||||
import org.apache.activemq.broker.BrokerService;
|
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.broker.jmx.ManagementContext;
|
||||||
import org.apache.activemq.command.ActiveMQDestination;
|
import org.apache.activemq.command.ActiveMQDestination;
|
||||||
import org.apache.activemq.command.ActiveMQQueue;
|
import org.apache.activemq.command.ActiveMQQueue;
|
||||||
|
@ -62,10 +64,13 @@ public class JmxAuditLogTest extends TestSupport
|
||||||
|
|
||||||
broker = new BrokerService();
|
broker = new BrokerService();
|
||||||
broker.setUseJmx(true);
|
broker.setUseJmx(true);
|
||||||
|
broker.setDeleteAllMessagesOnStartup(true);
|
||||||
portToUse = findOpenPort();
|
portToUse = findOpenPort();
|
||||||
broker.setManagementContext(createManagementContext("broker", portToUse));
|
broker.setManagementContext(createManagementContext("broker", portToUse));
|
||||||
broker.setPopulateUserNameInMBeans(true);
|
broker.setPopulateUserNameInMBeans(true);
|
||||||
broker.setDestinations(createDestinations());
|
broker.setDestinations(createDestinations());
|
||||||
|
TransportConnector transportConnector = broker.addConnector("tcp://0.0.0.0:0");
|
||||||
|
transportConnector.setName("TCP");
|
||||||
broker.start();
|
broker.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,4 +159,74 @@ public class JmxAuditLogTest extends TestSupport
|
||||||
assertEquals("got two messages", 2, logCount.get());
|
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);
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,6 +38,9 @@ public class JmxCreateNCTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testBridgeRegistration() throws Exception {
|
public void testBridgeRegistration() throws Exception {
|
||||||
|
|
||||||
|
System.setProperty("org.apache.activemq.audit", "all");
|
||||||
|
|
||||||
BrokerService broker = new BrokerService();
|
BrokerService broker = new BrokerService();
|
||||||
broker.setBrokerName(BROKER_NAME);
|
broker.setBrokerName(BROKER_NAME);
|
||||||
broker.setUseJmx(true); // explicitly set this so no funny issues
|
broker.setUseJmx(true); // explicitly set this so no funny issues
|
||||||
|
|
Loading…
Reference in New Issue