summaryrefslogtreecommitdiff
path: root/java/management/core/src
diff options
context:
space:
mode:
authorRafael H. Schloming <rhs@apache.org>2006-09-19 22:06:50 +0000
committerRafael H. Schloming <rhs@apache.org>2006-09-19 22:06:50 +0000
commit913489deb2ee9dbf44455de5f407ddaf4bd8c540 (patch)
tree7ea442d6867d0076f1c9ea4f4265664059e7aff5 /java/management/core/src
downloadqpid-python-913489deb2ee9dbf44455de5f407ddaf4bd8c540.tar.gz
Import of qpid from etp:
URL: https://etp.108.redhat.com/svn/etp/trunk/blaze Repository Root: https://etp.108.redhat.com/svn/etp Repository UUID: 06e15bec-b515-0410-bef0-cc27a458cf48 Revision: 608 git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid@447994 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'java/management/core/src')
-rw-r--r--java/management/core/src/log4j.properties6
-rw-r--r--java/management/core/src/org/apache/qpid/management/ManagementConnection.java120
-rw-r--r--java/management/core/src/org/apache/qpid/management/jmx/AMQConsole.java95
-rw-r--r--java/management/core/src/org/apache/qpid/management/jmx/AMQMBeanInfo.java40
-rw-r--r--java/management/core/src/org/apache/qpid/management/jmx/CMLMBean.java298
-rw-r--r--java/management/core/src/org/apache/qpid/management/jmx/JmxConstants.java23
-rw-r--r--java/management/core/src/org/apache/qpid/management/jmx/MBeanInfoRegistry.java201
-rw-r--r--java/management/core/src/org/apache/qpid/management/jmx/MBeanRegistrar.java141
-rw-r--r--java/management/core/src/org/apache/qpid/management/jmx/UnsupportedCMLTypeException.java36
-rw-r--r--java/management/core/src/org/apache/qpid/management/messaging/CMLMessageFactory.java59
-rw-r--r--java/management/core/src/org/apache/qpid/management/messaging/ManagementDestination.java43
11 files changed, 1062 insertions, 0 deletions
diff --git a/java/management/core/src/log4j.properties b/java/management/core/src/log4j.properties
new file mode 100644
index 0000000000..367153b2d9
--- /dev/null
+++ b/java/management/core/src/log4j.properties
@@ -0,0 +1,6 @@
+log4j.rootCategory=${amqj.logging.level}, console
+
+log4j.appender.console=org.apache.log4j.ConsoleAppender
+log4j.appender.console.Threshold=DEBUG
+log4j.appender.console.layout=org.apache.log4j.PatternLayout
+log4j.appender.console.layout.ConversionPattern=%t %d %p [%c{4}] %m%n
diff --git a/java/management/core/src/org/apache/qpid/management/ManagementConnection.java b/java/management/core/src/org/apache/qpid/management/ManagementConnection.java
new file mode 100644
index 0000000000..1dbfe6826c
--- /dev/null
+++ b/java/management/core/src/org/apache/qpid/management/ManagementConnection.java
@@ -0,0 +1,120 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed 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.management;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.url.URLSyntaxException;
+import org.apache.qpid.management.messaging.ManagementDestination;
+import org.apache.qpid.jms.Session;
+import org.apache.qpid.jms.MessageProducer;
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQQueue;
+import org.apache.log4j.Logger;
+
+import javax.jms.*;
+
+public class ManagementConnection
+{
+ private static final Logger _log = Logger.getLogger(ManagementConnection.class);
+
+ private String _brokerHost;
+
+ private int _brokerPort;
+
+ private String _username;
+
+ private String _password;
+
+ private String _virtualPath;
+
+ private AMQConnection _connection;
+
+ private Session _session;
+
+ private MessageConsumer _consumer;
+
+ private MessageProducer _producer;
+
+ private AMQQueue _replyQueue;
+
+ public ManagementConnection(String brokerHost, int brokerPort, String username,
+ String password, String virtualPath)
+ {
+ _brokerHost = brokerHost;
+ _brokerPort = brokerPort;
+ _username = username;
+ _password = password;
+ _virtualPath = virtualPath;
+ }
+
+ public void connect() throws AMQException, JMSException, URLSyntaxException
+ {
+ _connection = new AMQConnection(_brokerHost, _brokerPort, _username, _password,
+ "clientName" + System.currentTimeMillis(), _virtualPath);
+ _connection.setExceptionListener(new ExceptionListener()
+ {
+ public void onException(JMSException jmsException)
+ {
+ _log.error("Error occurred: " + jmsException, jmsException);
+ try
+ {
+ _connection.close();
+ }
+ catch (JMSException e)
+ {
+ _log.error("Error closing connection: " + e, e);
+ }
+ }
+ });
+ _session = (Session)_connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
+ _replyQueue = new AMQQueue("response", true)
+ {
+ public String getEncodedName()
+ {
+ return getQueueName();
+ }
+ };
+ _consumer = _session.createConsumer(_replyQueue, 100, true, true, null);
+
+ _producer = (MessageProducer) _session.createProducer(new ManagementDestination());
+ _connection.start();
+ }
+
+ /**
+ * Send a request and wait for a response.
+ * @param xmlRequest the request to send
+ * @return the response received from the broker
+ * @throws AMQException when an AMQ error occurs
+ * @throws JMSException when a JMS error occurs
+ */
+ public TextMessage sendRequest(String xmlRequest) throws AMQException, JMSException
+ {
+ TextMessage requestMsg = _session.createTextMessage(xmlRequest);
+ requestMsg.setJMSReplyTo(_replyQueue);
+ _producer.send(requestMsg);
+ return (TextMessage) _consumer.receive();
+ }
+
+ public void close() throws AMQException, JMSException
+ {
+ if (_connection != null)
+ {
+ _connection.close();
+ }
+ }
+}
diff --git a/java/management/core/src/org/apache/qpid/management/jmx/AMQConsole.java b/java/management/core/src/org/apache/qpid/management/jmx/AMQConsole.java
new file mode 100644
index 0000000000..c312ef63bf
--- /dev/null
+++ b/java/management/core/src/org/apache/qpid/management/jmx/AMQConsole.java
@@ -0,0 +1,95 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed 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.management.jmx;
+
+import org.apache.log4j.Logger;
+import org.apache.xmlbeans.XmlException;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.url.URLSyntaxException;
+import org.apache.qpid.management.ManagementConnection;
+import org.apache.qpid.management.messaging.CMLMessageFactory;
+import org.apache.qpid.schema.cml.CmlDocument;
+
+import javax.jms.JMSException;
+import javax.jms.TextMessage;
+import javax.management.MBeanServer;
+import java.lang.management.ManagementFactory;
+
+/**
+ * Main entry point for AMQ console implementation.
+ *
+ */
+public class AMQConsole
+{
+ private static final Logger _log = Logger.getLogger(AMQConsole.class);
+
+ private ManagementConnection _connection;
+
+ private MBeanInfoRegistry _mbeanInfoRegistry;
+
+ private MBeanRegistrar _mbeanRegistrar;
+
+ private MBeanServer _mbeanServer;
+
+ public AMQConsole(String host, int port, String username, String password,
+ String context)
+ {
+ _connection = new ManagementConnection(host, port, username, password, context);
+ }
+
+ public void initialise() throws AMQException, JMSException, XmlException, URLSyntaxException
+ {
+ _connection.connect();
+ createMBeanInfo();
+ _mbeanServer = ManagementFactory.getPlatformMBeanServer();
+ _mbeanRegistrar = new MBeanRegistrar(_mbeanServer, _connection, _mbeanInfoRegistry);
+ }
+
+ public void registerAllMBeans() throws JMSException, AMQException
+ {
+ _mbeanRegistrar.registerAllMBeans();
+ }
+
+ private void createMBeanInfo() throws JMSException, AMQException, XmlException
+ {
+ TextMessage tm = _connection.sendRequest(CMLMessageFactory.createSchemaRequest());
+ if (_log.isDebugEnabled())
+ {
+ _log.debug("Response document: \n" + tm.getText());
+ }
+ CmlDocument cmlDoc = CmlDocument.Factory.parse(tm.getText());
+ _mbeanInfoRegistry = new MBeanInfoRegistry(cmlDoc);
+ }
+
+ public static void main(String[] args)
+ {
+ AMQConsole console = new AMQConsole(args[0], Integer.parseInt(args[1]), args[2], args[3],
+ args[4]);
+ try
+ {
+ console.initialise();
+ _log.info("Registering all MBeans...");
+ console.registerAllMBeans();
+ _log.info("MBean registration completed successfully");
+ }
+ catch (Exception e)
+ {
+ _log.error("Console initialisation error: " + e, e);
+ }
+ }
+}
diff --git a/java/management/core/src/org/apache/qpid/management/jmx/AMQMBeanInfo.java b/java/management/core/src/org/apache/qpid/management/jmx/AMQMBeanInfo.java
new file mode 100644
index 0000000000..9663a7f783
--- /dev/null
+++ b/java/management/core/src/org/apache/qpid/management/jmx/AMQMBeanInfo.java
@@ -0,0 +1,40 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed 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.management.jmx;
+
+import javax.management.openmbean.OpenMBeanAttributeInfo;
+import java.util.Map;
+import java.util.HashMap;
+
+public class AMQMBeanInfo
+{
+ private Map<String, OpenMBeanAttributeInfo> _name2AttributeInfoMap = new HashMap<String, OpenMBeanAttributeInfo>();
+
+ public AMQMBeanInfo(OpenMBeanAttributeInfo[] attributeInfos)
+ {
+ for (OpenMBeanAttributeInfo attributeInfo: attributeInfos)
+ {
+ _name2AttributeInfoMap.put(attributeInfo.getName(), attributeInfo);
+ }
+ }
+
+ public OpenMBeanAttributeInfo getAttributeInfo(String name)
+ {
+ return _name2AttributeInfoMap.get(name);
+ }
+}
diff --git a/java/management/core/src/org/apache/qpid/management/jmx/CMLMBean.java b/java/management/core/src/org/apache/qpid/management/jmx/CMLMBean.java
new file mode 100644
index 0000000000..2d1dafb9f0
--- /dev/null
+++ b/java/management/core/src/org/apache/qpid/management/jmx/CMLMBean.java
@@ -0,0 +1,298 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed 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.management.jmx;
+
+import org.apache.log4j.Logger;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.management.ManagementConnection;
+import org.apache.qpid.management.messaging.CMLMessageFactory;
+import org.apache.qpid.schema.cml.CmlDocument;
+import org.apache.qpid.schema.cml.FieldType;
+import org.apache.qpid.schema.cml.InspectReplyType;
+import org.apache.qpid.schema.cml.MethodReplyType;
+
+import javax.jms.JMSException;
+import javax.jms.TextMessage;
+import javax.management.*;
+import javax.management.openmbean.OpenMBeanAttributeInfo;
+import javax.management.openmbean.OpenMBeanInfoSupport;
+import javax.management.openmbean.OpenType;
+import javax.management.openmbean.SimpleType;
+import java.util.Hashtable;
+
+public class CMLMBean implements DynamicMBean
+{
+ private static final Logger _log = Logger.getLogger(CMLMBean.class);
+
+ /**
+ * The number of milliseconds after which data values are considered "stale" and will be
+ * refreshed by querying the broker. This is a way of ensure that reading attributes
+ * repeatedly does not hit the broker heavily.
+ */
+ private static final long REFRESH_IN_MILLIS = 2000;
+
+ /**
+ * Name of the attribute for the parent MBean
+ */
+ public static final String PARENT_ATTRIBUTE = "__parent";
+
+ private OpenMBeanInfoSupport _mbeanInfo;
+
+ private AMQMBeanInfo _extraMbeanInfo;
+
+ /**
+ * The cached inspect reply. This is used to read attribute values and is refreshed automatically
+ * if a request for an attribute is made after the time interval specified in REFRESH_IN_MILLIS
+ */
+ private InspectReplyType _inspectReply;
+
+ private CMLMBean _parent;
+
+ private ObjectName _objectName;
+
+ private ManagementConnection _connection;
+
+ private int _objectId;
+
+ private long _lastRefreshTime = System.currentTimeMillis();
+
+ public CMLMBean(CMLMBean parent, OpenMBeanInfoSupport mbeanInfo, AMQMBeanInfo extraMbeanInfo,
+ InspectReplyType inspectReply, ManagementConnection connection, int objectId)
+ {
+ _mbeanInfo = mbeanInfo;
+ _extraMbeanInfo = extraMbeanInfo;
+ _inspectReply = inspectReply;
+ _parent = parent;
+ _connection = connection;
+ _objectId = objectId;
+ }
+
+ /**
+ * Utility method that populates all the type infos up to the root. Used when
+ * constructing the ObjectName.
+ * We end up with properties of the form "className", "objectId" in the map.
+ * @param leaf the child node. Must not be null. Note that the child types are not populated since the
+ * convention is different for the child where instead of "className" the word "type" is
+ * used. See the JMX Best Practices document on the Sun JMX website for details.
+ * @param properties
+ */
+ public static void populateAllTypeInfo(Hashtable<String, String> properties, CMLMBean leaf)
+ {
+ CMLMBean current = leaf.getParent();
+ while (current != null)
+ {
+ properties.put(current.getType(), Integer.toString(current.getObjectId()));
+ current = current.getParent();
+ }
+ }
+
+ public String getType()
+ {
+ return _inspectReply.getClass1();
+ }
+
+ public int getObjectId()
+ {
+ return _inspectReply.getObject2();
+ }
+
+ public InspectReplyType getInspectReply()
+ {
+ return _inspectReply;
+ }
+
+ public CMLMBean getParent()
+ {
+ return _parent;
+ }
+
+ public ObjectName getObjectName()
+ {
+ return _objectName;
+ }
+
+ public void setObjectName(ObjectName objectName)
+ {
+ _objectName = objectName;
+ }
+
+ public Object getAttribute(String attribute)
+ throws AttributeNotFoundException, MBeanException, ReflectionException
+ {
+ if (PARENT_ATTRIBUTE.equals(attribute))
+ {
+ if (_parent == null)
+ {
+ return null;
+ }
+ else
+ {
+ return _parent.getObjectName();
+ }
+ }
+ if (needRefresh())
+ {
+ refreshValues();
+ }
+ String nsDecl = "declare namespace cml='http://www.amqp.org/schema/cml';";
+ FieldType[] fields = (FieldType[]) _inspectReply.selectPath(nsDecl + "$this/cml:field[@name='" +
+ attribute + "']");
+ if (fields == null || fields.length == 0)
+ {
+ throw new AttributeNotFoundException("Attribute " + attribute + " not found");
+ }
+ else
+ {
+ OpenMBeanAttributeInfo attrInfo = _extraMbeanInfo.getAttributeInfo(attribute);
+ OpenType openType = attrInfo.getOpenType();
+ String value = fields[0].getStringValue();
+ try
+ {
+ return createAttributeValue(openType, value, attrInfo.getName());
+ }
+ catch (MalformedObjectNameException e)
+ {
+ throw new MBeanException(e);
+ }
+ }
+ }
+
+ private boolean needRefresh()
+ {
+ return ((System.currentTimeMillis() - _lastRefreshTime) > REFRESH_IN_MILLIS);
+ }
+
+ private void refreshValues() throws MBeanException
+ {
+ _log.debug("Refreshing values...");
+ try
+ {
+ TextMessage response = _connection.sendRequest(CMLMessageFactory.createInspectRequest(_objectId));
+
+ CmlDocument cmlDoc = CmlDocument.Factory.parse(response.getText());
+ _inspectReply = cmlDoc.getCml().getInspectReply();
+ _lastRefreshTime = System.currentTimeMillis();
+ }
+ catch (Exception e)
+ {
+ throw new MBeanException(e);
+ }
+ }
+
+ private Object createAttributeValue(OpenType openType, String value, String mbeanType)
+ throws MalformedObjectNameException
+ {
+ if (openType.equals(SimpleType.STRING))
+ {
+ return value;
+ }
+ else if (openType.equals(SimpleType.BOOLEAN))
+ {
+ return Boolean.valueOf(value);
+ }
+ else if (openType.equals(SimpleType.INTEGER))
+ {
+ return Integer.valueOf(value);
+ }
+ else if (openType.equals(SimpleType.DOUBLE))
+ {
+ return Double.valueOf(value);
+ }
+ else if (openType.equals(SimpleType.OBJECTNAME))
+ {
+ Hashtable<String, String> props = new Hashtable<String, String>();
+ props.put("objectid", value);
+ props.put("type", mbeanType);
+ // this populates all type info for parents
+ populateAllTypeInfo(props, this);
+ // add in type info for this level. This information is available from the inspect reply xml fragment
+ props.put(_inspectReply.getClass1(), Integer.toString(_inspectReply.getObject2()));
+ return new ObjectName(JmxConstants.JMX_DOMAIN, props);
+ }
+ else
+ {
+ _log.warn("Unsupported open type: " + openType + " - returning string value");
+ return value;
+ }
+ }
+
+ public void setAttribute(Attribute attribute) throws AttributeNotFoundException, InvalidAttributeValueException,
+ MBeanException, ReflectionException
+ {
+
+ }
+
+ public AttributeList getAttributes(String[] attributes)
+ {
+ AttributeList al = new AttributeList(attributes.length);
+ for (String name : attributes)
+ {
+ try
+ {
+ Object value = getAttribute(name);
+ final Attribute attr = new Attribute(name, value);
+ al.add(attr);
+ }
+ catch (Exception e)
+ {
+ _log.error("Unable to get value for attribute: " + name, e);
+ }
+ }
+ return al;
+ }
+
+ public AttributeList setAttributes(AttributeList attributes)
+ {
+ return null;
+ }
+
+ public Object invoke(String actionName, Object params[], String signature[]) throws MBeanException,
+ ReflectionException
+ {
+ _log.debug("Invoke called on action " + actionName);
+ try
+ {
+ TextMessage response = _connection.sendRequest(CMLMessageFactory.createMethodRequest(_objectId, actionName));
+ CmlDocument cmlDoc = CmlDocument.Factory.parse(response.getText());
+ CmlDocument.Cml cml = cmlDoc.getCml();
+ MethodReplyType methodReply = cml.getMethodReply();
+ if (methodReply.getStatus() != MethodReplyType.Status.OK)
+ {
+ throw new MBeanException(new Exception("Response code from method: " + methodReply.getStatus()));
+ }
+ return null;
+ }
+ catch (AMQException e)
+ {
+ throw new MBeanException(e);
+ }
+ catch (JMSException e)
+ {
+ throw new MBeanException(e);
+ }
+ catch (org.apache.xmlbeans.XmlException e)
+ {
+ throw new MBeanException(e);
+ }
+ }
+
+ public MBeanInfo getMBeanInfo()
+ {
+ return _mbeanInfo;
+ }
+}
diff --git a/java/management/core/src/org/apache/qpid/management/jmx/JmxConstants.java b/java/management/core/src/org/apache/qpid/management/jmx/JmxConstants.java
new file mode 100644
index 0000000000..a1944bfeb1
--- /dev/null
+++ b/java/management/core/src/org/apache/qpid/management/jmx/JmxConstants.java
@@ -0,0 +1,23 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed 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.management.jmx;
+
+public interface JmxConstants
+{
+ String JMX_DOMAIN = "org.apache.qpid";
+}
diff --git a/java/management/core/src/org/apache/qpid/management/jmx/MBeanInfoRegistry.java b/java/management/core/src/org/apache/qpid/management/jmx/MBeanInfoRegistry.java
new file mode 100644
index 0000000000..f6abb5028b
--- /dev/null
+++ b/java/management/core/src/org/apache/qpid/management/jmx/MBeanInfoRegistry.java
@@ -0,0 +1,201 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed 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.management.jmx;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.schema.cml.CmlDocument;
+import org.apache.qpid.schema.cml.FieldType;
+import org.apache.qpid.schema.cml.MethodType;
+import org.apache.qpid.schema.cml.SchemaReplyType;
+
+import javax.management.modelmbean.DescriptorSupport;
+import javax.management.openmbean.*;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Stores all OpenMBeanInfo instances.
+ * <p/>
+ * Builds MBeanInfo instances from the CML schema (which is parsed by XMLBeans) and
+ * stores these indexed by CML class name.
+ * <p/>
+ * When constructing a DynamicMBean this registry is consulted for the MBeanInfo.
+ *
+ */
+public class MBeanInfoRegistry
+{
+ private Map<String, OpenMBeanInfoSupport> _cmlClass2OpenMBeanInfoMap = new HashMap<String, OpenMBeanInfoSupport>();
+
+ private Map<String, AMQMBeanInfo> _cmlClass2AMQMBeanInfoMap = new HashMap<String, AMQMBeanInfo>();
+
+ public MBeanInfoRegistry(CmlDocument cmlDocument) throws AMQException
+ {
+ initialise(cmlDocument);
+ }
+
+ private void initialise(CmlDocument cmlDocument) throws AMQException
+ {
+ CmlDocument.Cml cml = cmlDocument.getCml();
+ SchemaReplyType schema = cml.getSchemaReply();
+ for (org.apache.qpid.schema.cml.ClassType c : schema.getClass1List())
+ {
+ OpenMBeanAttributeInfo[] attributes = createAttributeInfos(c.getFieldList());
+ OpenMBeanOperationInfo[] operations = createOperationInfos(c.getMethodList());
+ String className = c.getName();
+ OpenMBeanInfoSupport support = new OpenMBeanInfoSupport(className, null, attributes,
+ null, operations, null);
+ // we need to store the extra information separately since we cannot subclass
+ // OpenMBeanInfoSupport. Doing so means we need to have an AMQMBeanInfo class on each client
+ // which defeats the point of OpenMBeans. The extra info is only used by the CMLBean implementation
+ // to assist with runtime value lookups.
+ AMQMBeanInfo extra = new AMQMBeanInfo(attributes);
+ _cmlClass2OpenMBeanInfoMap.put(className, support);
+ _cmlClass2AMQMBeanInfoMap.put(className, extra);
+ }
+ }
+
+ public OpenMBeanInfoSupport getOpenMBeanInfo(String cmlType)
+ {
+ return _cmlClass2OpenMBeanInfoMap.get(cmlType);
+ }
+
+ public AMQMBeanInfo getAMQMBeanInfo(String cmlType)
+ {
+ return _cmlClass2AMQMBeanInfoMap.get(cmlType);
+ }
+
+ private OpenMBeanAttributeInfo[] createAttributeInfos(List<FieldType> fields)
+ throws AMQException
+ {
+ OpenMBeanAttributeInfo[] attributes = new OpenMBeanAttributeInfo[fields.size() + 1];
+
+ // we up the parent attribute which is always present
+ try
+ {
+ DescriptorSupport descriptor = new DescriptorSupport(new String[]{"hidden=true"});
+ attributes[attributes.length - 1] = new OpenMBeanAttributeInfoSupport(CMLMBean.PARENT_ATTRIBUTE,
+ "Parent", SimpleType.OBJECTNAME,
+ true, false, false);
+ //descriptor); JDK 1.6 only
+ }
+ catch (Exception e)
+ {
+ // should never happen
+ throw new AMQException("Unable to create Parent attribute", e);
+ }
+ // add all the type-specific attributes
+ for (int i = 0; i < attributes.length - 1; i++)
+ {
+ FieldType field = fields.get(i);
+ OpenType openType = getOpenType(field.getType(), field.getModify());
+ String description = field.getLabel();
+ attributes[i] = new OpenMBeanAttributeInfoSupport(field.getName(),
+ description != null ? description:"No description",
+ openType,
+ true,
+ field.getModify(),
+ openType == SimpleType.BOOLEAN);
+ }
+
+ return attributes;
+ }
+
+ private static OpenType getOpenType(FieldType.Type.Enum type, boolean isArray)
+ throws UnsupportedCMLTypeException, AMQException
+ {
+ SimpleType simpleType;
+ boolean primitive;
+ switch (type.intValue())
+ {
+ // the constants are not public (bug in xmlbeans) so we cannot use
+ // the constants that are defined
+ // TODO: raise defect with xmlbeans projects
+ case 1:
+ simpleType = SimpleType.BOOLEAN;
+ primitive = true;
+ break;
+ case 2:
+ simpleType = SimpleType.STRING;
+ primitive = false;
+ break;
+ case 3:
+ simpleType = SimpleType.INTEGER;
+ primitive = true;
+ break;
+ case 4:
+ simpleType = SimpleType.OBJECTNAME;
+ primitive = false;
+ break;
+ case 5:
+ simpleType = SimpleType.DATE;
+ primitive = false;
+ break;
+ default:
+ throw new UnsupportedCMLTypeException(type.toString());
+ }
+ if (isArray)
+ {
+ try
+ {
+ //return new ArrayType(simpleType, primitive);
+ return new ArrayType(1, simpleType);
+ }
+ catch (OpenDataException e)
+ {
+ throw new AMQException("Error constructing array type: " + e, e);
+ }
+ }
+ else
+ {
+ return simpleType;
+ }
+ }
+
+ private OpenMBeanOperationInfo[] createOperationInfos(List<MethodType> methods)
+ throws AMQException
+ {
+ OpenMBeanOperationInfo[] methodInfos = new OpenMBeanOperationInfo[methods.size()];
+ for (int i = 0; i < methodInfos.length; i++)
+ {
+ MethodType methodType = methods.get(i);
+ OpenMBeanParameterInfo[] parameters = createParameterInfos(methodType.getFieldList());
+ methodInfos[i] = new OpenMBeanOperationInfoSupport(methodType.getName(), "No description",
+ parameters, SimpleType.VOID,
+ OpenMBeanOperationInfoSupport.ACTION);
+ }
+ return methodInfos;
+ }
+
+ private OpenMBeanParameterInfo[] createParameterInfos(List<FieldType> parameters)
+ throws AMQException
+ {
+ OpenMBeanParameterInfo[] paramInfos = new OpenMBeanParameterInfo[parameters.size()];
+ for (int i = 0; i < paramInfos.length; i++)
+ {
+ FieldType field = parameters.get(i);
+ String description = field.getLabel();
+ OpenType openType = getOpenType(field.getType(), field.getModify());
+ paramInfos[i] = new OpenMBeanParameterInfoSupport(field.getName(),
+ description==null?"No description":description,
+ openType);
+ }
+ return paramInfos;
+ }
+}
+
diff --git a/java/management/core/src/org/apache/qpid/management/jmx/MBeanRegistrar.java b/java/management/core/src/org/apache/qpid/management/jmx/MBeanRegistrar.java
new file mode 100644
index 0000000000..bdc3772553
--- /dev/null
+++ b/java/management/core/src/org/apache/qpid/management/jmx/MBeanRegistrar.java
@@ -0,0 +1,141 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed 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.management.jmx;
+
+import org.apache.log4j.Logger;
+import org.apache.xmlbeans.XmlException;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.management.ManagementConnection;
+import org.apache.qpid.management.messaging.CMLMessageFactory;
+import org.apache.qpid.schema.cml.CmlDocument;
+import org.apache.qpid.schema.cml.FieldType;
+import org.apache.qpid.schema.cml.InspectReplyType;
+
+import javax.jms.JMSException;
+import javax.jms.TextMessage;
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.management.openmbean.OpenMBeanAttributeInfo;
+import javax.management.openmbean.SimpleType;
+import javax.management.openmbean.OpenMBeanInfoSupport;
+import java.util.Hashtable;
+
+/**
+ * Responsible for registering MBeans. This class will navigate through
+ * our hierarchy of MBeans, registering them with the appropriate ObjectNames.
+ *
+ */
+public class MBeanRegistrar
+{
+ private static final Logger _log = Logger.getLogger(MBeanRegistrar.class);
+
+ /** The MBean server with which all MBeans will be registered. */
+ private MBeanServer _targetMBeanServer;
+
+ /** The connection used to communicate with the broker */
+ private ManagementConnection _connection;
+
+ private MBeanInfoRegistry _mbeanInfoRegistry;
+
+ /**
+ * Create a registrar for the specified MBean server
+ * @param targetMBeanServer the MBean server with which all MBeans will be registered
+ */
+ public MBeanRegistrar(MBeanServer targetMBeanServer, ManagementConnection connection,
+ MBeanInfoRegistry mbeanInfoRegistry)
+ {
+ _targetMBeanServer = targetMBeanServer;
+ _connection = connection;
+ _mbeanInfoRegistry = mbeanInfoRegistry;
+ }
+
+ public void registerAllMBeans() throws AMQException, JMSException
+ {
+ registerMBean(null, 0);
+ }
+
+ /**
+ * Asks the broker for details of a particular object id then creates and registers an
+ * MBean with the MBeanServer.
+ * @param objectId id of the object we want to inspect
+ * @return the registered bean, from which the underlying inspect response can be retrieved if required
+ * @throws AMQException
+ * @throws JMSException
+ */
+ private CMLMBean registerMBean(CMLMBean parent, int objectId) throws AMQException, JMSException
+ {
+ TextMessage response = _connection.sendRequest(CMLMessageFactory.createInspectRequest(objectId));
+ try
+ {
+ CmlDocument cmlDoc = CmlDocument.Factory.parse(response.getText());
+ CmlDocument.Cml cml = cmlDoc.getCml();
+ InspectReplyType inspect = cml.getInspectReply();
+ if (_log.isDebugEnabled())
+ {
+ _log.debug("Inspect reply: " + inspect);
+ }
+ OpenMBeanInfoSupport mbeanInfo = _mbeanInfoRegistry.getOpenMBeanInfo(inspect.getClass1());
+ AMQMBeanInfo extraMbeanInfo = _mbeanInfoRegistry.getAMQMBeanInfo(inspect.getClass1());
+ CMLMBean mbean = new CMLMBean(parent, mbeanInfo, extraMbeanInfo, inspect, _connection, objectId);
+ Hashtable<String, String> props = new Hashtable<String, String>();
+ props.put("objectid", Integer.toString(objectId));
+ props.put("type", mbean.getType());
+ CMLMBean.populateAllTypeInfo(props, mbean);
+ ObjectName mbeanObjectName = new ObjectName("org.apache.qpid", props);
+ mbean.setObjectName(mbeanObjectName);
+ _targetMBeanServer.registerMBean(mbean, mbeanObjectName);
+
+ // recursively register all beans
+ String nsDecl = "declare namespace cml='http://www.amqp.org/schema/cml';";
+ for (MBeanAttributeInfo attributeInfo: mbeanInfo.getAttributes())
+ {
+ OpenMBeanAttributeInfo openAttributeInfo = (OpenMBeanAttributeInfo) attributeInfo;
+ if (openAttributeInfo.getOpenType().equals(SimpleType.OBJECTNAME) &&
+ !"__parent".equals(openAttributeInfo.getName()))
+ {
+ if (_log.isDebugEnabled())
+ {
+ _log.debug("Searching for fields with name: " + openAttributeInfo.getName());
+ }
+ FieldType[] fields = (FieldType[]) inspect.selectPath(nsDecl + "$this/cml:field[@name='" +
+ openAttributeInfo.getName() + "']");
+ if (fields == null || fields.length == 0)
+ {
+ throw new AMQException("inspect xml did not contain field value for field " +
+ attributeInfo.getName());
+ }
+ for (FieldType field : fields)
+ {
+ registerMBean(mbean, Integer.parseInt(field.getStringValue()));
+ }
+ }
+ }
+ return mbean;
+ }
+ catch (XmlException e)
+ {
+ throw new AMQException(_log, "Error parsing broker response: " + e, e);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ throw new AMQException(_log, "Error registering MBean: " + e, e);
+ }
+ }
+}
diff --git a/java/management/core/src/org/apache/qpid/management/jmx/UnsupportedCMLTypeException.java b/java/management/core/src/org/apache/qpid/management/jmx/UnsupportedCMLTypeException.java
new file mode 100644
index 0000000000..bb866f8d17
--- /dev/null
+++ b/java/management/core/src/org/apache/qpid/management/jmx/UnsupportedCMLTypeException.java
@@ -0,0 +1,36 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed 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.management.jmx;
+
+import org.apache.qpid.AMQException;
+
+public class UnsupportedCMLTypeException extends AMQException
+{
+ private String _type;
+
+ public UnsupportedCMLTypeException(String type)
+ {
+ super("CML type " + type + " is unsupported by the JMX layer");
+ _type = type;
+ }
+
+ public String getType()
+ {
+ return _type;
+ }
+}
diff --git a/java/management/core/src/org/apache/qpid/management/messaging/CMLMessageFactory.java b/java/management/core/src/org/apache/qpid/management/messaging/CMLMessageFactory.java
new file mode 100644
index 0000000000..e47eb66c65
--- /dev/null
+++ b/java/management/core/src/org/apache/qpid/management/messaging/CMLMessageFactory.java
@@ -0,0 +1,59 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed 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.management.messaging;
+
+import org.apache.qpid.schema.cml.CmlDocument;
+import org.apache.qpid.schema.cml.InspectRequestType;
+import org.apache.qpid.schema.cml.MethodRequestType;
+
+public class CMLMessageFactory
+{
+ public static String createSchemaRequest()
+ {
+ CmlDocument cmlDoc = CmlDocument.Factory.newInstance();
+ CmlDocument.Cml cml = createStandardCml(cmlDoc);
+ cml.addNewSchemaRequest();
+ return cmlDoc.toString();
+ }
+
+ public static String createInspectRequest(int objectId)
+ {
+ CmlDocument cmlDoc = CmlDocument.Factory.newInstance();
+ CmlDocument.Cml cml = createStandardCml(cmlDoc);
+ InspectRequestType inspect = cml.addNewInspectRequest();
+ inspect.setObject(objectId);
+ return cmlDoc.toString();
+ }
+
+ public static String createMethodRequest(int objectId, String methodName)
+ {
+ CmlDocument cmlDoc = CmlDocument.Factory.newInstance();
+ CmlDocument.Cml cml = createStandardCml(cmlDoc);
+ MethodRequestType methodReq = cml.addNewMethodRequest();
+ methodReq.setObject(objectId);
+ methodReq.setName(methodName);
+ return cmlDoc.toString();
+ }
+
+ private static CmlDocument.Cml createStandardCml(CmlDocument cmlDoc)
+ {
+ CmlDocument.Cml cml = cmlDoc.addNewCml();
+ cml.setVersion("1.0");
+ return cml;
+ }
+}
diff --git a/java/management/core/src/org/apache/qpid/management/messaging/ManagementDestination.java b/java/management/core/src/org/apache/qpid/management/messaging/ManagementDestination.java
new file mode 100644
index 0000000000..f6edb9394a
--- /dev/null
+++ b/java/management/core/src/org/apache/qpid/management/messaging/ManagementDestination.java
@@ -0,0 +1,43 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed 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.management.messaging;
+
+import org.apache.qpid.client.AMQDestination;
+
+public class ManagementDestination extends AMQDestination
+{
+ public ManagementDestination()
+ {
+ super("amq.system", "system", "amq.console");
+ }
+
+ public boolean isNameRequired()
+ {
+ return false;
+ }
+
+ public String getEncodedName()
+ {
+ return null;
+ }
+
+ public String getRoutingKey()
+ {
+ return getDestinationName();
+ }
+}