diff options
| author | Rafael H. Schloming <rhs@apache.org> | 2006-09-19 22:06:50 +0000 |
|---|---|---|
| committer | Rafael H. Schloming <rhs@apache.org> | 2006-09-19 22:06:50 +0000 |
| commit | 913489deb2ee9dbf44455de5f407ddaf4bd8c540 (patch) | |
| tree | 7ea442d6867d0076f1c9ea4f4265664059e7aff5 /java/management/core/src | |
| download | qpid-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')
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(); + } +} |
