You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by fa...@apache.org on 2013/04/08 17:19:09 UTC
svn commit: r1465662 [20/26] - in /qpid/trunk/qpid/tools/src/java: ./ bin/
bin/qpid-web/ bin/qpid-web/authentication/ bin/qpid-web/web/
bin/qpid-web/web/itablet/ bin/qpid-web/web/itablet/css/
bin/qpid-web/web/itablet/images/ bin/qpid-web/web/itablet/im...
Added: qpid/trunk/qpid/tools/src/java/src/qpid-broker-plugins-management-qmf2/java/org/apache/qpid/server/qmf2/QmfManagementAgent.java
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/tools/src/java/src/qpid-broker-plugins-management-qmf2/java/org/apache/qpid/server/qmf2/QmfManagementAgent.java?rev=1465662&view=auto
==============================================================================
--- qpid/trunk/qpid/tools/src/java/src/qpid-broker-plugins-management-qmf2/java/org/apache/qpid/server/qmf2/QmfManagementAgent.java (added)
+++ qpid/trunk/qpid/tools/src/java/src/qpid-broker-plugins-management-qmf2/java/org/apache/qpid/server/qmf2/QmfManagementAgent.java Mon Apr 8 15:19:04 2013
@@ -0,0 +1,592 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.server.qmf2;
+
+// Misc Imports
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+// Simple Logging Facade 4 Java
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+// QMF2 Imports
+import org.apache.qpid.qmf2.agent.Agent;
+import org.apache.qpid.qmf2.agent.MethodCallParams;
+import org.apache.qpid.qmf2.agent.MethodCallWorkItem;
+import org.apache.qpid.qmf2.agent.QmfAgentData;
+import org.apache.qpid.qmf2.common.ObjectId;
+import org.apache.qpid.qmf2.common.QmfData;
+import org.apache.qpid.qmf2.common.QmfEvent;
+import org.apache.qpid.qmf2.common.QmfEventListener;
+import org.apache.qpid.qmf2.common.QmfException;
+import org.apache.qpid.qmf2.common.QmfType;
+import org.apache.qpid.qmf2.common.WorkItem;
+import org.apache.qpid.qmf2.util.ConnectionHelper;
+import static org.apache.qpid.qmf2.common.WorkItem.WorkItemType.*;
+
+// Java Broker model Imports
+import org.apache.qpid.server.model.Binding;
+import org.apache.qpid.server.model.Broker;
+import org.apache.qpid.server.model.ConfigurationChangeListener;
+import org.apache.qpid.server.model.ConfiguredObject;
+import org.apache.qpid.server.model.Connection;
+import org.apache.qpid.server.model.Consumer;
+import org.apache.qpid.server.model.Exchange;
+import org.apache.qpid.server.model.LifetimePolicy;
+import org.apache.qpid.server.model.Port;
+import org.apache.qpid.server.model.Publisher;
+import org.apache.qpid.server.model.Queue;
+import org.apache.qpid.server.model.Session;
+import org.apache.qpid.server.model.State;
+import org.apache.qpid.server.model.VirtualHost;
+
+/**
+ * This class implements a QMF2 Agent providing access to the Java broker Management Objects via QMF2 thus
+ * allowing the Java broker to be managed in the same way to the C++ broker.
+ * <p>
+ * The intention is for the QmfManagementAgent to conform to the same Management Schema as the C++ broker
+ * (e.g. as specified in <qpid>/specs/management-schema.xml) in order to provide maximum cohesion between
+ * the to broker implementations, however that's not entirely possible given differences between the underlying
+ * Management models.
+ * <p>
+ * This Plugin attempts to map properties from the Java org.apache.qpid.server.model.* classes to equivalent
+ * properties and statistics in the C++ broker's Management Schema rather than expose them "natively", this is
+ * in order to try and maximise alignment between the two implementations and to try to allow the Java broker
+ * to be managed by the Command Line tools used with the C++ broker such as qpid-config etc. it's also to
+ * enable the Java broker to be accessed via the QMF2 REST API and GUI.
+ *
+ * @author Fraser Adams
+ */
+public class QmfManagementAgent implements ConfigurationChangeListener, QmfEventListener
+{
+ private static final Logger _log = LoggerFactory.getLogger(QmfManagementAgent.class);
+
+ // Set heartbeat interval to 10 seconds. TODO Should probably be config driven, but I *think* that this is
+ // different than "heartbeat.delay" and "heartbeat.timeoutFactor" currently present in the config?
+ private static final int HEARTBEAT_INTERVAL = 10;
+ private Agent _agent = null;
+
+ // The first Connection Object relates to the QmfManagementAgent, we use this flag to avoid mapping that Connection
+ // to a QMF Object thus hiding it from Consoles. This is done to provide consistency with the C++ broker which
+ // also "hides" its own private AMQP Connections, Queues & Bindings.
+ private boolean agentConnection = true;
+
+ private final Broker _broker; // Passed in by Plugin bootstrapping.
+ private final String _defaultVirtualHost; // Pulled from the broker attributes.
+
+ /**
+ * A Map of QmfAgentData keyed by ConfiguredObject. This is mainly used for Management Object "lifecycle management".
+ * In an ideal world the Agent class could retain all information, but I want to track ConfiguredObject state and
+ * use that to create and delete QmfAgentData data, which means I need to be able to *find* the QmfAgentData and
+ * the *official* Agent API doesn't have a public method to query Objects (though the evaluateQuery() method used
+ * by Query Subscriptions could be used, but it's not really a "public API method" so probably best not to use it)
+ * Arguably this is what the AgentExternal subclass of Agent is for whereby queries are handled in the Agent
+ * implementation by handling "(wi.getType() == QUERY)" but the AgentExternal API forces some constructs that are
+ * actually likely to be less efficient, as an example sending a separate queryResponse() for each object forces a
+ * look up of a List of QmfAgentData objects keyed by the consoleHandle for each call. There is also the need to
+ * separately iterate through the List of QmfAgentData objects thus created to create the mapEncoded list needed
+ * for sending via the QMF2 protocol.
+ * <p>
+ * So rather than go through all that faff we simply retain an additional Map as below which allows navigation
+ * between the ConfiguredObject and QmfAgentData. The subclasses of QmfAgentData will contain references to
+ * allow navigation back to the concrete subclasses of ConfiguredObject if necessary.
+ * The capacity of 100 is pretty arbitrary but the default of 16 seems too low for a ManagementAgent.
+ */
+ private Map<ConfiguredObject, QmfAgentData> _objects = new ConcurrentHashMap<ConfiguredObject, QmfAgentData>(100);
+
+ /**
+ * Constructor. Creates the AMQP Connection to the broker and starts the QMF2 Agent.
+ * @param url the Connection URL to be used to construct the AMQP Connection.
+ * @param broker the root Broker Management Object from which the other Management Objects may be obtained.
+ * to work without explicitly setting a Virtual Host, which I think is necessary because the C++ broker and
+ * the python command line tools aren't currently Virtual Host aware (are they?). The intention is to mark
+ * queues and exchanges with [vhost:<vhost-name>/]<object-name> in other words if we want to add things to
+ * the non-default Virtual Host prefix their names with [vhost:<vhost-name>/]. This approach *ought* to allow
+ * non-Virtual Host aware command line tools the ability to add queues/exchanges to a particular vhost.
+ */
+ public QmfManagementAgent(final String url, final Broker broker)
+ {
+ _broker = broker;
+ _defaultVirtualHost = (String)broker.getAttribute("defaultVirtualHost");
+
+ try
+ {
+ // Create the actual JMS Connection. ConnectionHelper allows us to work with a variety of URL
+ // formats so we can abstract away from the somewhat complex Java AMQP URL format.
+ javax.jms.Connection connection = ConnectionHelper.createConnection(url);
+ if (connection == null)
+ {
+ _log.info("QmfManagementAgent Constructor failed due to null AMQP Connection");
+ }
+ else
+ {
+ _agent = new Agent(this, HEARTBEAT_INTERVAL);
+ // Vendor and Product are deliberately set to be the same as for the C++ broker.
+ _agent.setVendor("apache.org");
+ _agent.setProduct("qpidd");
+ _agent.setConnection(connection);
+
+ // Register the schema for the Management Objects. These don't have to be completely populated
+ // the minimum is to register package name and class name for the QmfAgentData.
+ _agent.registerObjectClass(org.apache.qpid.server.qmf2.agentdata.Broker.getSchema());
+ _agent.registerObjectClass(org.apache.qpid.server.qmf2.agentdata.Connection.getSchema());
+ _agent.registerEventClass(org.apache.qpid.server.qmf2.agentdata.Connection.getClientConnectSchema());
+ _agent.registerEventClass(org.apache.qpid.server.qmf2.agentdata.Connection.getClientDisconnectSchema());
+
+ _agent.registerObjectClass(org.apache.qpid.server.qmf2.agentdata.Exchange.getSchema());
+ _agent.registerEventClass(org.apache.qpid.server.qmf2.agentdata.Exchange.getExchangeDeclareSchema());
+ _agent.registerEventClass(org.apache.qpid.server.qmf2.agentdata.Exchange.getExchangeDeleteSchema());
+
+ _agent.registerObjectClass(org.apache.qpid.server.qmf2.agentdata.Queue.getSchema());
+ _agent.registerEventClass(org.apache.qpid.server.qmf2.agentdata.Queue.getQueueDeclareSchema());
+ _agent.registerEventClass(org.apache.qpid.server.qmf2.agentdata.Queue.getQueueDeleteSchema());
+
+ _agent.registerObjectClass(org.apache.qpid.server.qmf2.agentdata.Binding.getSchema());
+ _agent.registerEventClass(org.apache.qpid.server.qmf2.agentdata.Binding.getBindSchema());
+ _agent.registerEventClass(org.apache.qpid.server.qmf2.agentdata.Binding.getUnbindSchema());
+
+ _agent.registerObjectClass(org.apache.qpid.server.qmf2.agentdata.Subscription.getSchema());
+ _agent.registerEventClass(org.apache.qpid.server.qmf2.agentdata.Subscription.getSubscribeSchema());
+ _agent.registerEventClass(org.apache.qpid.server.qmf2.agentdata.Subscription.getUnsubscribeSchema());
+
+ // Initialise QmfAgentData Objects and track changes to the broker Management Objects.
+ registerConfigurationChangeListeners();
+ }
+ }
+ catch (QmfException qmfe)
+ {
+ _log.info("QmfException {} caught in QmfManagementAgent Constructor", qmfe.getMessage());
+ }
+ catch (Exception e)
+ {
+ _log.info("Exception {} caught in QmfManagementAgent Constructor", e.getMessage());
+ }
+ }
+
+ /**
+ * Close the QmfManagementAgent clearing the QMF2 Agent and freeing its resources.
+ */
+ public void close()
+ {
+ if (isConnected())
+ {
+ _agent.destroy();
+ }
+ }
+
+ /**
+ * Returns whether the Agent is connected and running.
+ * @return true if the Agent is connected and running otherwise return false.
+ */
+ public boolean isConnected()
+ {
+ return _agent != null;
+ }
+
+ /**
+ * This method initialises the initial set of QmfAgentData Objects and tracks changes to the broker Management
+ * Objects via the childAdded() method call.
+ */
+ private void registerConfigurationChangeListeners()
+ {
+ childAdded(null, _broker);
+
+ for (VirtualHost vhost : _broker.getVirtualHosts())
+ {
+ // We don't add QmfAgentData VirtualHost objects. Possibly TODO, but it's a bit awkward at the moment
+ // becase (as of Qpid 0.20) the C++ broker doesn't *seem* to do much with them and the command line
+ // tools such as qpid-config don't appear to be VirtualHost aware. A way to stay compatible is to
+ // mark queues, exchanges etc with [vhost:<vhost-name>/]<object-name> (see Constructor comments).
+ vhost.addChangeListener(this);
+
+ for (Connection connection : vhost.getConnections())
+ {
+ childAdded(vhost, connection);
+
+ for (Session session : connection.getSessions())
+ {
+ childAdded(connection, session);
+
+ // session.getSubscriptions() returns null in Qpid 0.23 TODO fix that.
+ if (session.getSubscriptions() != null)
+ {
+ for (Consumer subscription : session.getSubscriptions())
+ {
+ childAdded(session, subscription);
+ }
+ }
+ }
+ }
+
+ // The code blocks for adding Bindings (and adding Queues) contain checks to see if what is being added
+ // relates to Queues or Bindings for the QmfManagementAgent. If they are QmfManagementAgent related
+ // we avoid registering the Object as a QMF Object, in other words we "hide" QmfManagementAgent QMF Objects.
+ // This is done to be consistent with the C++ broker which also "hides" its own Connection, Queue & Binding.
+ for (Exchange exchange : vhost.getExchanges())
+ {
+ childAdded(vhost, exchange);
+
+ for (Binding binding : exchange.getBindings())
+ {
+ String key = binding.getName();
+ if (key.equals("broker") || key.equals("console.request.agent_locate") ||
+ key.startsWith("apache.org:qpidd:") || key.startsWith("TempQueue"))
+ { // Don't add QMF related Bindings in registerConfigurationChangeListeners as those will relate
+ } // to the Agent and we want to "hide" those.
+ else
+ {
+ childAdded(exchange, binding);
+ }
+ }
+ }
+
+ for (Queue queue : vhost.getQueues())
+ {
+ boolean agentQueue = false;
+ for (Binding binding : queue.getBindings())
+ {
+ String key = binding.getName();
+ if (key.equals("broker") || key.equals("console.request.agent_locate") ||
+ key.startsWith("apache.org:qpidd:"))
+ {
+ agentQueue = true;
+ break;
+ }
+ }
+
+ // Don't add QMF related bindings or Queues in registerConfigurationChangeListeners as those will
+ // relate to the Agent itself and we want to "hide" those to be consistent with the C++ Broker.
+ if (!agentQueue)
+ {
+ childAdded(vhost, queue);
+
+ for (Binding binding : queue.getBindings())
+ {
+ childAdded(queue, binding);
+ }
+
+ for (Consumer subscription : queue.getConsumers())
+ {
+ childAdded(queue, subscription);
+ }
+ }
+ }
+ }
+ }
+
+
+ // ************************* ConfigurationChangeListener implementation methods *************************
+
+ /**
+ * ConfigurationChangeListener method called when the state is changed (ignored here).
+ * @param object the object being modified.
+ * @param oldState the state of the object prior to this method call.
+ * @param newState the desired state of the object.
+ */
+ @Override
+ public void stateChanged(final ConfiguredObject object, final State oldState, final State newState)
+ {
+ // no-op
+ }
+
+ /**
+ * ConfigurationChangeListener method called when an attribute is set (ignored here).
+ * @param object the object being modified.
+ * @param attributeName the name of the object attribute that we want to change.
+ * @param oldAttributeValue the value of the attribute prior to this method call.
+ * @param newAttributeValue the desired value of the attribute.
+ */
+ @Override
+ public void attributeSet(ConfiguredObject object, String attributeName,
+ Object oldAttributeValue, Object newAttributeValue)
+ {
+ // no-op
+ }
+
+ /**
+ * ConfigurationChangeListener method called when a child ConfiguredObject is added.
+ * <p>
+ * This method checks the type of the child ConfiguredObject that has been added and creates the equivalent
+ * QMF2 Management Object if one doesn't already exist. In most cases it's a one-to-one mapping, but for
+ * Binding for example the Binding child is added to both Queue and Exchange so we only create the Binding
+ * QMF2 Management Object once and add the queueRef and exchangeRef reference properties referencing the Queue
+ * and Exchange parent Objects respectively.
+ * <p>
+ * This method is also responsible for raising the appropriate QMF2 Events when Management Objects are created.
+ * @param object the parent object that the child is being added to.
+ * @param child the child object being added.
+ */
+ @Override
+ public void childAdded(final ConfiguredObject object, final ConfiguredObject child)
+ {
+//System.out.println("childAdded() " + child.getClass().getSimpleName() + "." + child.getName());
+
+ QmfAgentData data = null;
+
+ if (child instanceof Broker)
+ {
+ data = new org.apache.qpid.server.qmf2.agentdata.Broker((Broker)child);
+ }
+ else if (child instanceof Connection)
+ {
+ if (!agentConnection && !_objects.containsKey(child))
+ {
+ // If the parent object is the default vhost set it to null so that the Connection ignores it.
+ VirtualHost vhost = (object.getName().equals(_defaultVirtualHost)) ? null : (VirtualHost)object;
+ data = new org.apache.qpid.server.qmf2.agentdata.Connection(vhost, (Connection)child);
+ _objects.put(child, data);
+
+ // Raise a Client Connect Event.
+ _agent.raiseEvent(((org.apache.qpid.server.qmf2.agentdata.Connection)data).createClientConnectEvent());
+ }
+ agentConnection = false; // Only ignore the first Connection, which is the one from the Agent.
+ }
+ else if (child instanceof Session)
+ { // TODO
+
+ }
+ else if (child instanceof Exchange)
+ {
+ if (!_objects.containsKey(child))
+ {
+ // If the parent object is the default vhost set it to null so that the Connection ignores it.
+ VirtualHost vhost = (object.getName().equals(_defaultVirtualHost)) ? null : (VirtualHost)object;
+ data = new org.apache.qpid.server.qmf2.agentdata.Exchange(vhost, (Exchange)child);
+ _objects.put(child, data);
+
+ // Raise an Exchange Declare Event.
+ _agent.raiseEvent(((org.apache.qpid.server.qmf2.agentdata.Exchange)data).createExchangeDeclareEvent());
+
+ }
+ }
+ else if (child instanceof Queue)
+ {
+ if (!_objects.containsKey(child))
+ {
+ // If the parent object is the default vhost set it to null so that the Connection ignores it.
+ VirtualHost vhost = (object.getName().equals(_defaultVirtualHost)) ? null : (VirtualHost)object;
+ data = new org.apache.qpid.server.qmf2.agentdata.Queue(vhost, (Queue)child);
+ _objects.put(child, data);
+
+ // Raise a Queue Declare Event.
+ _agent.raiseEvent(((org.apache.qpid.server.qmf2.agentdata.Queue)data).createQueueDeclareEvent());
+ }
+ }
+ else if (child instanceof Binding)
+ {
+ // Bindings are a little more complex because in QMF bindings contain exchangeRef and queueRef properties
+ // whereas with the Java Broker model Binding is a child of Queue and Exchange. To cope with this we
+ // first try to create or retrieve the QMF Binding Object then add either the Queue or Exchange reference
+ // depending on whether Queue or Exchange was the parent of this addChild() call.
+ if (!_objects.containsKey(child))
+ {
+ data = new org.apache.qpid.server.qmf2.agentdata.Binding((Binding)child);
+ _objects.put(child, data);
+
+ String eName = child.getAttribute("exchange").toString();
+ if (!eName.equals("<<default>>")) // Don't send Event for Binding to default direct.
+ {
+ // Raise a Bind Event.
+ _agent.raiseEvent(((org.apache.qpid.server.qmf2.agentdata.Binding)data).createBindEvent());
+ }
+ }
+
+ org.apache.qpid.server.qmf2.agentdata.Binding binding =
+ (org.apache.qpid.server.qmf2.agentdata.Binding)_objects.get(child);
+
+ QmfAgentData ref = _objects.get(object);
+ if (ref != null)
+ {
+ if (object instanceof Queue)
+ {
+ binding.setQueueRef(ref.getObjectId());
+ }
+ else if (object instanceof Exchange)
+ {
+ binding.setExchangeRef(ref.getObjectId());
+ }
+ }
+ }
+ else if (child instanceof Consumer) // AKA Subscription
+ {
+ // Subscriptions are a little more complex because in QMF Subscriptions contain sessionRef and queueRef
+ // properties whereas with the Java Broker model Consumer is a child of Queue and Session. To cope with
+ // this we first try to create or retrieve the QMF Subscription Object then add either the Queue or
+ // Session reference depending on whether Queue or Session was the parent of this addChild() call.
+ if (!_objects.containsKey(child))
+ {
+ data = new org.apache.qpid.server.qmf2.agentdata.Subscription((Consumer)child);
+ _objects.put(child, data);
+ }
+
+ org.apache.qpid.server.qmf2.agentdata.Subscription subscription =
+ (org.apache.qpid.server.qmf2.agentdata.Subscription)_objects.get(child);
+
+ QmfAgentData ref = _objects.get(object);
+ if (ref != null)
+ {
+ if (object instanceof Queue)
+ {
+ subscription.setQueueRef(ref.getObjectId(), (Queue)object);
+ // Raise a Subscribe Event - N.B. Need to do it *after* we've set the queueRef.
+ _agent.raiseEvent(((org.apache.qpid.server.qmf2.agentdata.Subscription)data).createSubscribeEvent());
+ }
+ else if (object instanceof Session) // Won't get called in Qpid 0.20.
+ { // TODO the association between Session and Subscription isn't implemented in the 0.20 Java Broker.
+ //System.out.println("subscription.setSessionRef");
+ subscription.setSessionRef(ref.getObjectId());
+ }
+ }
+ }
+
+
+ try
+ {
+ // If we've created new QmfAgentData we register it with the Agent.
+ if (data != null)
+ {
+ _agent.addObject(data);
+ }
+ }
+ catch (QmfException qmfe)
+ {
+ _log.info("QmfException {} caught in QmfManagementAgent.addObject()", qmfe.getMessage());
+ }
+
+ child.addChangeListener(this);
+ }
+
+
+ /**
+ * ConfigurationChangeListener method called when a child ConfiguredObject is removed.
+ * <p>
+ * This method checks the type of the child ConfiguredObject that has been removed and raises the appropriate
+ * QMF2 Events, it then destroys the QMF2 Management Object and removes the mapping between child and the QMF Object.
+ *
+ * @param object the parent object that the child is being removed from.
+ * @param child the child object being removed.
+ */
+ @Override
+ public void childRemoved(final ConfiguredObject object, final ConfiguredObject child)
+ {
+//System.out.println("childRemoved: " + child.getClass().getSimpleName() + "." + child.getName());
+
+ child.removeChangeListener(this);
+
+ // Look up the associated QmfAgentData and mark it for deletion by the Agent.
+ QmfAgentData data = _objects.get(child);
+ if (data != null)
+ {
+ if (child instanceof Connection)
+ {
+ // Raise a Client Disconnect Event.
+ _agent.raiseEvent(((org.apache.qpid.server.qmf2.agentdata.Connection)data).createClientDisconnectEvent());
+ }
+ else if (child instanceof Session)
+ { // TODO
+
+ }
+ else if (child instanceof Exchange)
+ {
+ // Raise an Exchange Delete Event.
+ _agent.raiseEvent(((org.apache.qpid.server.qmf2.agentdata.Exchange)data).createExchangeDeleteEvent());
+ }
+ else if (child instanceof Queue)
+ {
+ // Raise a Queue Delete Event.
+ _agent.raiseEvent(((org.apache.qpid.server.qmf2.agentdata.Queue)data).createQueueDeleteEvent());
+ }
+ else if (child instanceof Binding)
+ {
+ String eName = child.getAttribute("exchange").toString();
+ if (!eName.equals("<<default>>")) // Don't send Event for Unbinding from default direct.
+ {
+ // Raise an Unbind Event.
+ _agent.raiseEvent(((org.apache.qpid.server.qmf2.agentdata.Binding)data).createUnbindEvent());
+ }
+ }
+ else if (child instanceof Consumer)
+ {
+ // Raise an Unsubscribe Event.
+ _agent.raiseEvent(((org.apache.qpid.server.qmf2.agentdata.Subscription)data).createUnsubscribeEvent());
+ }
+
+ data.destroy();
+ }
+
+ // Remove the mapping from the internal ConfiguredObject->QmfAgentData Map.
+ _objects.remove(child);
+ }
+
+ // ******************************* QmfEventListener implementation method *******************************
+
+ /**
+ * Callback method triggered when the underlying QMF2 Agent has WorkItems available for processing.
+ * The purpose of this method is mainly to handle the METHOD_CALL WorkItem and demultiplex & delegate
+ * to the invokeMethod() call on the relevant concrete QmfAgentData Object.
+ * @param wi the WorkItem that has been passed by the QMF2 Agent to be processed here (mainly METHOD_CALL).
+ */
+ @Override
+ public void onEvent(final WorkItem wi)
+ {
+ if (wi.getType() == METHOD_CALL)
+ {
+ MethodCallWorkItem item = (MethodCallWorkItem)wi;
+ MethodCallParams methodCallParams = item.getMethodCallParams();
+
+ String methodName = methodCallParams.getName();
+ ObjectId objectId = methodCallParams.getObjectId();
+
+ // Look up QmfAgentData by ObjectId from the Agent's internal Object store.
+ QmfAgentData object = _agent.getObject(objectId);
+ if (object == null)
+ {
+ _agent.raiseException(item.getHandle(), "No object found with ID=" + objectId);
+ }
+ else
+ {
+ // If we've found a valid QmfAgentData check it's a Broker or Queue and if so call the generic
+ // invokeMethod on these objects, if not send an Exception as we don't support methods on
+ // other classes yet.
+ if (object instanceof org.apache.qpid.server.qmf2.agentdata.Broker)
+ {
+ org.apache.qpid.server.qmf2.agentdata.Broker broker =
+ (org.apache.qpid.server.qmf2.agentdata.Broker) object;
+ broker.invokeMethod(_agent, item.getHandle(), methodName, methodCallParams.getArgs());
+ }
+ else if (object instanceof org.apache.qpid.server.qmf2.agentdata.Queue)
+ {
+ org.apache.qpid.server.qmf2.agentdata.Queue queue =
+ (org.apache.qpid.server.qmf2.agentdata.Queue) object;
+ queue.invokeMethod(_agent, item.getHandle(), methodName, methodCallParams.getArgs());
+ }
+ else
+ {
+ _agent.raiseException(item.getHandle(), "Unknown Method " + methodName + " on " +
+ object.getClass().getSimpleName());
+ }
+ }
+ }
+ }
+
+}
Propchange: qpid/trunk/qpid/tools/src/java/src/qpid-broker-plugins-management-qmf2/java/org/apache/qpid/server/qmf2/QmfManagementAgent.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: qpid/trunk/qpid/tools/src/java/src/qpid-broker-plugins-management-qmf2/java/org/apache/qpid/server/qmf2/QmfManagementAgent.java
------------------------------------------------------------------------------
svn:keywords = Rev Date
Added: qpid/trunk/qpid/tools/src/java/src/qpid-broker-plugins-management-qmf2/java/org/apache/qpid/server/qmf2/QmfManagementFactory.java
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/tools/src/java/src/qpid-broker-plugins-management-qmf2/java/org/apache/qpid/server/qmf2/QmfManagementFactory.java?rev=1465662&view=auto
==============================================================================
--- qpid/trunk/qpid/tools/src/java/src/qpid-broker-plugins-management-qmf2/java/org/apache/qpid/server/qmf2/QmfManagementFactory.java (added)
+++ qpid/trunk/qpid/tools/src/java/src/qpid-broker-plugins-management-qmf2/java/org/apache/qpid/server/qmf2/QmfManagementFactory.java Mon Apr 8 15:19:04 2013
@@ -0,0 +1,79 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.server.qmf2;
+
+// Misc Imports
+import java.util.Map;
+import java.util.UUID;
+
+// Java Broker Management Imports
+import org.apache.qpid.server.model.Broker;
+import org.apache.qpid.server.model.Plugin;
+import org.apache.qpid.server.plugin.PluginFactory;
+
+/**
+ * This class is an implementation of org.apache.qpid.server.plugin.PluginFactory which is the interface
+ * used by the Qpid Java Broker to create Management Plugins.
+ * <p>
+ * The factory method is createInstance() which returns a concrete instance of org.apache.qpid.server.model.Plugin
+ * in this case the concrete instance is QmfManagementPlugin.
+ * <p>
+ * The Java broker uses org.apache.qpid.server.plugin.QpidServiceLoader, which wraps java.util.ServiceLoader to
+ * load Plugins. This has a prerequisite of having a services file specified in the META-INF see
+ * <a href=http://docs.oracle.com/javase/6/docs/api/java/util/ServiceLoader.html>ServiceLoader</a> e.g.
+ * <pre>
+ * META-INF/services/org.apache.qpid.server.plugin.PluginFactory
+ * </pre>
+ * This is best done by using the ServiceProvider block in the jar ant task e.g.
+ * <pre>
+ * <jar destfile="build/lib/qpid-broker-plugins-management-qmf2.jar"
+ * basedir="build/scratch/qpid-broker-plugins-management-qmf2">
+ *
+ * <service type="org.apache.qpid.server.plugin.PluginFactory"
+ * provider="org.apache.qpid.server.qmf2.QmfManagementFactory"/>
+ * </jar>
+ * </pre>
+ * @author Fraser Adams
+ */
+public class QmfManagementFactory implements PluginFactory
+{
+ /**
+ * This factory method creates an instance of QmfManagementPlugin called via the QpidServiceLoader.
+ * @param id the UUID of the Plugin.
+ * @param attributes a Map containing configuration information for the Plugin.
+ * @param broker the root Broker Management Object from which the other Management Objects may be obtained.
+ * @return the QmfManagementPlugin instance which creates a QMF2 Agent able to interrogate the broker Management
+ * Objects and return their properties as QmfData.
+ */
+ @Override
+ public Plugin createInstance(UUID id, Map<String, Object> attributes, Broker broker)
+ {
+ if (QmfManagementPlugin.PLUGIN_TYPE.equals(attributes.get(PLUGIN_TYPE)))
+ {
+ return new QmfManagementPlugin(id, broker, attributes);
+ }
+ else
+ {
+ return null;
+ }
+ }
+}
Propchange: qpid/trunk/qpid/tools/src/java/src/qpid-broker-plugins-management-qmf2/java/org/apache/qpid/server/qmf2/QmfManagementFactory.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: qpid/trunk/qpid/tools/src/java/src/qpid-broker-plugins-management-qmf2/java/org/apache/qpid/server/qmf2/QmfManagementFactory.java
------------------------------------------------------------------------------
svn:keywords = Rev Date
Added: qpid/trunk/qpid/tools/src/java/src/qpid-broker-plugins-management-qmf2/java/org/apache/qpid/server/qmf2/QmfManagementPlugin.java
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/tools/src/java/src/qpid-broker-plugins-management-qmf2/java/org/apache/qpid/server/qmf2/QmfManagementPlugin.java?rev=1465662&view=auto
==============================================================================
--- qpid/trunk/qpid/tools/src/java/src/qpid-broker-plugins-management-qmf2/java/org/apache/qpid/server/qmf2/QmfManagementPlugin.java (added)
+++ qpid/trunk/qpid/tools/src/java/src/qpid-broker-plugins-management-qmf2/java/org/apache/qpid/server/qmf2/QmfManagementPlugin.java Mon Apr 8 15:19:04 2013
@@ -0,0 +1,300 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.server.qmf2;
+
+// Misc Imports
+import java.lang.reflect.Type;
+import java.net.InetSocketAddress;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.UUID;
+
+// Simple Logging Facade 4 Java
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+// Java Broker Management Imports
+import org.apache.qpid.server.logging.actors.CurrentActor;
+import org.apache.qpid.server.logging.messages.ManagementConsoleMessages;
+
+import org.apache.qpid.server.model.Broker;
+import org.apache.qpid.server.model.Exchange;
+import org.apache.qpid.server.model.LifetimePolicy;
+import org.apache.qpid.server.model.Plugin;
+import org.apache.qpid.server.model.State;
+import org.apache.qpid.server.model.VirtualHost;
+import org.apache.qpid.server.model.adapter.AbstractPluginAdapter;
+
+import org.apache.qpid.server.plugin.PluginFactory;
+import org.apache.qpid.server.util.MapValueConverter;
+
+/**
+ * This class is a Qpid Java Broker Plugin which follows the Plugin API added in Qpid 0.22 it implements
+ * org.apache.qpid.server.model.Plugin and extends org.apache.qpid.server.model.adapter.AbstractPluginAdapter.
+ * <p>
+ * This Plugin provides access to the Java broker Management Objects via QMF2 thus allowing the Java broker to
+ * be managed and monitored in the same way as the C++ broker.
+ * <p>
+ * The intention is for the Java broker QmfManagementPlugin to conform to the same Management Schema as the C++
+ * broker (e.g. as specified in <qpid>/specs/management-schema.xml) in order to provide maximum cohesion between
+ * the to broker implementations, however that's not entirely possible given differences between the underlying
+ * Management models. The ultimate aim is to align the Management models of the two Qpid brokers and migrate
+ * to the AMQP 1.0 Management architecture when it becomes available.
+ * <p>
+ * This Plugin attempts to map properties from the Java org.apache.qpid.server.model.* classes to equivalent
+ * properties and statistics in the C++ broker's Management Schema rather than expose them "natively", this is
+ * in order to try and maximise alignment between the two implementations and to try to allow the Java broker
+ * to be managed by the Command Line tools used with the C++ broker such as qpid-config etc. it's also to
+ * enable the Java broker to be accessed via the QMF2 REST API and GUI.
+ * <p>
+ * This class only bootstraps the ManagementPlugin, the actual business logic is run from QmfManagementAgent.
+ * It's worth also mentioning that this Plugin actually establishes an AMQP Connection to the Broker via JMS.
+ * As it's a Broker Plugin it could conceivably use the low level Broker internal transport, this would probably
+ * be a little more efficient, but OTOH by using the JMS based approach I can use the QMF2 Agent code
+ * directly and implementing a complete QMF2 Agent for the Java Broker becomes "fairly simple" only requiring
+ * mappings between the org.apache.qpid.server.model.* classes and their QmfAgentData equivalents.
+ * <p>
+ * This Plugin requires config to be set, if this is not done the Plugin will not bootstrap. Config may be
+ * set in $QPID_WORK/config.json as part of the "plugins" config e.g.
+ * <pre>
+ * "plugins" : [ {
+ * "id" : "26887211-842c-3c4a-ab09-b1a1f64de369",
+ * "name" : "qmf2Management",
+ * "pluginType" : "MANAGEMENT-QMF2",
+ * "connectionURL" : "amqp://guest:guest@/?brokerlist='tcp://0.0.0.0:5672'"
+ * }]
+ * </pre>
+ * @author Fraser Adams
+ */
+public class QmfManagementPlugin extends AbstractPluginAdapter
+{
+ private static final Logger _log = LoggerFactory.getLogger(QmfManagementPlugin.class);
+
+ private static final String OPERATIONAL_LOGGING_NAME = "QMF2";
+
+ /************* Static initialiser used to implement org.apache.qpid.server.model.Plugin *************/
+
+ public static final String PLUGIN_TYPE = "MANAGEMENT-QMF2";
+
+ // attributes
+ public static final String NAME = "name";
+ public static final String CONNECTION_URL = "connectionURL";
+
+ // default values
+ public static final String DEFAULT_NAME = "qmf2Management";
+ public static final String DEFAULT_CONNECTION_URL = "amqp://guest:guest@/?brokerlist='tcp://0.0.0.0:5672'";
+
+ @SuppressWarnings("serial")
+ private static final Collection<String> AVAILABLE_ATTRIBUTES = Collections.unmodifiableCollection(
+ new HashSet<String>(Plugin.AVAILABLE_ATTRIBUTES){{
+ add(NAME);
+ add(CONNECTION_URL);
+ add(PluginFactory.PLUGIN_TYPE);
+ }});
+
+ @SuppressWarnings("serial")
+ private static final Map<String, Object> DEFAULTS = new HashMap<String, Object>(){{
+ put(NAME, DEFAULT_NAME);
+ put(CONNECTION_URL, DEFAULT_CONNECTION_URL);
+ put(PluginFactory.PLUGIN_TYPE, PLUGIN_TYPE);
+ }};
+
+ @SuppressWarnings("serial")
+ private static final Map<String, Type> ATTRIBUTE_TYPES = new HashMap<String, Type>(){{
+ put(NAME, String.class);
+ put(CONNECTION_URL, String.class);
+ put(PluginFactory.PLUGIN_TYPE, String.class);
+ }};
+
+ /************************************ End of Static initialiser *************************************/
+
+ private final Broker _broker; // Passed in by Plugin bootstrapping.
+ private final String _defaultVirtualHost; // Pulled from the broker attributes.
+ private final String _connectionURL; // Pulled from the Plugin config.
+ private QmfManagementAgent _agent;
+
+ /**
+ * Constructor, called at broker startup by QmfManagementFactory.createInstance().
+ * @param id the UUID of the Plugin.
+ * @param attributes a Map containing configuration information for the Plugin.
+ * @param broker the root Broker Management Object from which the other Management Objects may be obtained.
+ */
+ public QmfManagementPlugin(UUID id, Broker broker, Map<String, Object> attributes)
+ {
+ super(id, DEFAULTS, MapValueConverter.convert(attributes, ATTRIBUTE_TYPES), broker.getTaskExecutor());
+ addParent(Broker.class, broker);
+ _broker = broker;
+ _defaultVirtualHost = (String)broker.getAttribute("defaultVirtualHost");
+ _connectionURL = (String)getAttribute("connectionURL");
+ }
+
+ /**
+ * Set the state of the Plugin, I believe that this is called from the BrokerAdapter object when it
+ * has its own state set to State.ACTIVE or State.STOPPED.
+ * When State.ACTIVE is set this calls the start() method to startup the Plugin, when State.STOPPED
+ * is set this calls the stop() method to shutdown the Plugin.
+ * @param currentState the current state of the Plugin (ignored).
+ * @param desiredState the desired state of the Plugin (either State.ACTIVE or State.STOPPED).
+ * @return true if a valid state has been set, otherwise false.
+ */
+ @Override // From org.apache.qpid.server.model.adapter.AbstractAdapter
+ protected boolean setState(State currentState, State desiredState)
+ {
+ if (desiredState == State.ACTIVE)
+ {
+ start();
+ return true;
+ }
+ else if (desiredState == State.STOPPED)
+ {
+ stop();
+ return true;
+ }
+ else
+ {
+ _log.info("QmfManagementPlugin.setState() received invalid desiredState {}", desiredState);
+ return false;
+ }
+ }
+
+ /**
+ * Start the Plugin. Note that we bind the QMF Connection the the default Virtual Host, this is important
+ * in order to allow C++ or Python QMF Consoles to control the Java Broker, as they know nothing of Virtual
+ * Hosts and their Connection URL formats don't have a mechanism to specify Virtual Hosts.
+ * <p>
+ * Note too that it may be necessary to create the "qmf.default.direct" and "qmf.default.topic" exchanges
+ * as these don't exist by default on the Java Broker, however we have to check if they already exist
+ * as attempting to add an Exchange that already exists will cause IllegalArgumentException.
+ */
+ private void start()
+ {
+ // Log "QMF2 Management Startup" message.
+ CurrentActor.get().message(ManagementConsoleMessages.STARTUP(OPERATIONAL_LOGGING_NAME));
+
+ // Wrap main startup logic in a try/catch block catching Exception. The idea is that if anything goes
+ // wrong with QmfManagementPlugin startup it shouldn't fatally prevent the Broker from starting, though
+ // clearly QMF2 management will not be available.
+ try
+ {
+ // Iterate through the Virtual Hosts looking for the default Virtual Host. When we find the default
+ // we create the QMF exchanges then construct the QmfManagementAgent passing it the ConnectionURL.
+ boolean foundDefaultVirtualHost = false;
+ for (VirtualHost vhost : _broker.getVirtualHosts())
+ {
+ if (vhost.getName().equals(_defaultVirtualHost))
+ {
+ foundDefaultVirtualHost = true;
+
+ // Check if "qmf.default.direct" or "qmf.default.topic" already exist. It is important to
+ // check as attempting to add an Exchange that already exists will cause IllegalArgumentException.
+ boolean needDefaultDirect = true;
+ boolean needDefaultTopic = true;
+ for (Exchange exchange : vhost.getExchanges())
+ {
+ if (exchange.getName().equals("qmf.default.direct"))
+ {
+ needDefaultDirect = false;
+ }
+ else if (exchange.getName().equals("qmf.default.topic"))
+ {
+ needDefaultTopic = false;
+ }
+ }
+
+ // Create the QMF2 exchanges if necessary.
+ Map<String, Object> attributes = Collections.emptyMap();
+ if (needDefaultDirect)
+ {
+ vhost.createExchange("qmf.default.direct", State.ACTIVE, true,
+ LifetimePolicy.PERMANENT, 0l, "direct", attributes);
+ }
+
+ if (needDefaultTopic)
+ {
+ vhost.createExchange("qmf.default.topic", State.ACTIVE, true,
+ LifetimePolicy.PERMANENT, 0l, "topic", attributes);
+ }
+
+ // Now create the *real* Agent which maps Broker Management Objects to QmdAgentData Objects.
+ _agent = new QmfManagementAgent(_connectionURL, _broker);
+ }
+ }
+
+ // If we can't find a defaultVirtualHost we log that fact, the Plugin can't start in this case.
+ // Question. If defaultVirtualHost isn't configured or it doesn't match the name of one of the actual
+ // Virtual Hosts should we make the first one we find the de facto default for this Plugin??
+ if (!foundDefaultVirtualHost)
+ {
+ _log.info("QmfManagementPlugin.start() could not find defaultVirtualHost");
+ }
+ else if (_agent.isConnected())
+ {
+ // Log QMF2 Management Ready message.
+ CurrentActor.get().message(ManagementConsoleMessages.READY(OPERATIONAL_LOGGING_NAME));
+ }
+ }
+ catch (Exception e) // Catch and log any Exception so we avoid Plugin failures stopping Broker startup.
+ {
+ _log.info("Exception {} caught in QmfManagementPlugin.start()", e.getMessage());
+ }
+ }
+
+ /**
+ * Stop the Plugin, closing the QMF Connection and logging "QMF2 Management Stopped".
+ */
+ private void stop()
+ {
+ // When the Plugin state gets set to STOPPED we close the QMF Connection.
+ if (_agent != null)
+ {
+ _agent.close();
+ }
+
+ // Log "QMF2 Management Stopped" message (may not get displayed).
+ CurrentActor.get().message(ManagementConsoleMessages.STOPPED(OPERATIONAL_LOGGING_NAME));
+ }
+
+ /**
+ * Get the name of this Plugin.
+ * @return the Plugin name (default is "qmf2Management").
+ */
+ @Override // From org.apache.qpid.server.model.ConfiguredObject
+ public String getName()
+ {
+ return (String)getAttribute(NAME);
+ }
+
+ /**
+ * Accessor to retrieve the names of the available attributes. It is important to provide this overridden
+ * method because the Constructor uses this information when populating the underlying AbstractPlugin
+ * information. If we don't provide this override method getAttribute(name) will return the default values.
+ * @return the names of the available Plugin config attributes as a Collection.
+ */
+ @Override // From org.apache.qpid.server.model.adapter.AbstractPluginAdapter
+ public Collection<String> getAttributeNames()
+ {
+ return AVAILABLE_ATTRIBUTES;
+ }
+}
Propchange: qpid/trunk/qpid/tools/src/java/src/qpid-broker-plugins-management-qmf2/java/org/apache/qpid/server/qmf2/QmfManagementPlugin.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: qpid/trunk/qpid/tools/src/java/src/qpid-broker-plugins-management-qmf2/java/org/apache/qpid/server/qmf2/QmfManagementPlugin.java
------------------------------------------------------------------------------
svn:keywords = Rev Date
Added: qpid/trunk/qpid/tools/src/java/src/qpid-broker-plugins-management-qmf2/java/org/apache/qpid/server/qmf2/agentdata/Binding.java
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/tools/src/java/src/qpid-broker-plugins-management-qmf2/java/org/apache/qpid/server/qmf2/agentdata/Binding.java?rev=1465662&view=auto
==============================================================================
--- qpid/trunk/qpid/tools/src/java/src/qpid-broker-plugins-management-qmf2/java/org/apache/qpid/server/qmf2/agentdata/Binding.java (added)
+++ qpid/trunk/qpid/tools/src/java/src/qpid-broker-plugins-management-qmf2/java/org/apache/qpid/server/qmf2/agentdata/Binding.java Mon Apr 8 15:19:04 2013
@@ -0,0 +1,203 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.server.qmf2.agentdata;
+
+// Misc Imports
+import java.util.Map;
+
+// Simple Logging Facade 4 Java
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+// QMF2 Imports
+import org.apache.qpid.qmf2.agent.QmfAgentData;
+import org.apache.qpid.qmf2.common.QmfEvent;
+import org.apache.qpid.qmf2.common.ObjectId;
+import org.apache.qpid.qmf2.common.QmfEvent;
+import org.apache.qpid.qmf2.common.SchemaEventClass;
+//import org.apache.qpid.qmf2.common.SchemaMethod;
+import org.apache.qpid.qmf2.common.SchemaObjectClass;
+//import org.apache.qpid.qmf2.common.SchemaProperty;
+
+import org.apache.qpid.server.model.Statistics;
+
+/**
+ * This class provides a concrete implementation of QmfAgentData for the Binding Management Object.
+ * In general it's possible to use QmfAgentData without sub-classing as it's really a "bean" style class
+ * that retains its properties in a Map, but in the case of the Java Broker Management Agent it's useful
+ * to sub-class as we need to map between the properties/statistics as specified in the Java Broker
+ * management model and those specified in qpid/spec/management-schema.xml which is what the C++ broker
+ * uses. This class retains a reference to its peer org.apache.qpid.server.model.Binding and does the
+ * necessary mapping when its mapEncode() method is called (which is used to serialise the QmfAgentData).
+ *
+ * @author Fraser Adams
+ */
+public class Binding extends QmfAgentData
+{
+ private static final Logger _log = LoggerFactory.getLogger(Binding.class);
+
+ /**
+ * This static initialiser block initialises the QMF2 Schema information needed by the Agent to find
+ * QmfAgentData and QmfEvent Objects of a given type.
+ */
+ private static final SchemaObjectClass _schema;
+ private static final SchemaEventClass _bindSchema;
+ private static final SchemaEventClass _unbindSchema;
+
+ /**
+ * Returns the schema for the Binding class.
+ * @return the SchemaObjectClass for the Binding class.
+ */
+ public static SchemaObjectClass getSchema()
+ {
+ return _schema;
+ }
+
+ /**
+ * Returns the schema for the Bind Event.
+ * @return the SchemaEventClass for the Bind Event.
+ */
+ public static SchemaEventClass getBindSchema()
+ {
+ return _bindSchema;
+ }
+
+ /**
+ * Returns the schema for the Unbind Event.
+ * @return the SchemaEventClass for the Unbind Event.
+ */
+ public static SchemaEventClass getUnbindSchema()
+ {
+ return _unbindSchema;
+ }
+
+ static
+ {
+ // Declare the schema for the QMF2 broker class.
+ _schema = new SchemaObjectClass("org.apache.qpid.broker", "binding");
+
+ // TODO
+ //_schema.addProperty(new SchemaProperty("whatHappened", QmfType.TYPE_STRING));
+
+ // Declare the schema for the QMF2 bind Event class.
+ _bindSchema = new SchemaEventClass("org.apache.qpid.broker", "bind");
+
+ // Declare the schema for the QMF2 unbind Event class.
+ _unbindSchema = new SchemaEventClass("org.apache.qpid.broker", "unbind");
+ }
+ // End of static initialiser.
+
+ private final org.apache.qpid.server.model.Binding _binding;
+
+ /**
+ * Constructor.
+ * @param binding the Binding ConfiguredObject from the broker model.
+ */
+ public Binding(final org.apache.qpid.server.model.Binding binding)
+ {
+ super(getSchema());
+ _binding = binding; // Will eventually be used in mapEncode() to retrieve statistics.
+ setValue("bindingKey", binding.getName());
+
+ Map<String, Object> arguments = binding.getArguments();
+ // binding.getArguments() always returns a Map, but with the C++ broker if there are no arguments
+ // the property isn't populated, so we only add it if the _arguments.size() > 0
+ if (arguments.size() > 0)
+ {
+ setValue("arguments", arguments);
+ }
+
+ // origin not implemented in Qpid 0.20 - not really sure what the origin property means anyway???
+ }
+
+ /**
+ * Set the exchangeRef property.
+ * @param exchangeRef the exchangeRef ObjectId.
+ */
+ public void setExchangeRef(final ObjectId exchangeRef)
+ {
+ setRefValue("exchangeRef", exchangeRef);
+ }
+
+ /**
+ * Set the queueRef property.
+ * @param queueRef the queueRef ObjectId.
+ */
+ public void setQueueRef(final ObjectId queueRef)
+ {
+ setRefValue("queueRef", queueRef);
+ }
+
+ /**
+ * Factory method to create a Bind Event Object with timestamp of now.
+ * @return the newly created Bind Event Object.
+ */
+ public QmfEvent createBindEvent()
+ {
+ QmfEvent bind = new QmfEvent(_bindSchema);
+ bind.setSeverity("info");
+ bind.setValue("args", _binding.getArguments());
+ bind.setValue("exName", _binding.getAttribute("exchange"));
+ bind.setValue("key", _binding.getName());
+ bind.setValue("qName", _binding.getAttribute("queue"));
+ // TODO Not sure of a way to get these for Java Broker Exchange.
+ //bind.setValue("rhost", _connection.getName());
+ //bind.setValue("user", getStringValue("authIdentity"));
+ return bind;
+ }
+
+ /**
+ * Factory method to create an Unbind Event Object with timestamp of now.
+ * @return the newly created Unbind Event Object.
+ */
+ public QmfEvent createUnbindEvent()
+ {
+ QmfEvent unbind = new QmfEvent(_unbindSchema);
+ unbind.setSeverity("info");
+ unbind.setValue("exName", _binding.getAttribute("exchange"));
+ unbind.setValue("key", _binding.getName());
+ unbind.setValue("qName", _binding.getAttribute("queue"));
+ // TODO Not sure of a way to get these for Java Broker Exchange.
+ //unbind.setValue("rhost", _connection.getName());
+ //unbind.setValue("user", getStringValue("authIdentity"));
+ return unbind;
+ }
+
+ /**
+ * This method maps the org.apache.qpid.server.model.Binding to QMF2 broker properties where possible then
+ * serialises into the underlying Map for transmission via AMQP. This method is called by handleQueryRequest()
+ * in the org.apache.qpid.qmf2.agent.Agent class implementing the main QMF2 Agent behaviour.
+ *
+ * @return the underlying map.
+ */
+ @Override
+ public Map<String, Object> mapEncode()
+ {
+ // Statistics
+ //Statistics stats = _binding.getStatistics();
+ // not implemented in Qpid 0.20 despite the property actually existing!!
+ //setValue("msgMatched", stats.getStatistic("matchedMessages"));
+
+ //update(); // No statistics have been updated ('cause there aren't any yet...)
+ return super.mapEncode();
+ }
+}
Propchange: qpid/trunk/qpid/tools/src/java/src/qpid-broker-plugins-management-qmf2/java/org/apache/qpid/server/qmf2/agentdata/Binding.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: qpid/trunk/qpid/tools/src/java/src/qpid-broker-plugins-management-qmf2/java/org/apache/qpid/server/qmf2/agentdata/Binding.java
------------------------------------------------------------------------------
svn:keywords = Rev Date
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org