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>
+ * &lt;jar destfile="build/lib/qpid-broker-plugins-management-qmf2.jar"
+ *      basedir="build/scratch/qpid-broker-plugins-management-qmf2"&gt;
+ *
+ *      &lt;service type="org.apache.qpid.server.plugin.PluginFactory" 
+ *               provider="org.apache.qpid.server.qmf2.QmfManagementFactory"/&gt;
+ * &lt;/jar&gt;
+ * </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