summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Godfrey <rgodfrey@apache.org>2014-05-02 09:43:19 +0000
committerRobert Godfrey <rgodfrey@apache.org>2014-05-02 09:43:19 +0000
commit05f4e2a5113a02e35f0e03345b153422fb9c8d1f (patch)
tree2fe33d14669f650dec936f3822528c98bbce0629
parent23954de4a3bc293b2a598b562279915ee42dfbd4 (diff)
downloadqpid-python-05f4e2a5113a02e35f0e03345b153422fb9c8d1f.tar.gz
QPID-5610 , QPID-5578 , QPID-5715 : Update the QMF2 plugin for changes to VirtualHost(Node) model and ConfiguredObject model
git-svn-id: https://svn.apache.org/repos/asf/qpid/branches/QPID-5610-maven3-build-qmf-tools@1591845 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r--qpid/tools/src/java/qpid-broker-plugins-management-qmf2/pom.xml7
-rw-r--r--qpid/tools/src/java/qpid-broker-plugins-management-qmf2/src/main/java/org/apache/qpid/server/qmf2/QmfManagementAgent.java23
-rw-r--r--qpid/tools/src/java/qpid-broker-plugins-management-qmf2/src/main/java/org/apache/qpid/server/qmf2/QmfManagementFactory.java85
-rw-r--r--qpid/tools/src/java/qpid-broker-plugins-management-qmf2/src/main/java/org/apache/qpid/server/qmf2/QmfManagementPlugin.java280
-rw-r--r--qpid/tools/src/java/qpid-broker-plugins-management-qmf2/src/main/java/org/apache/qpid/server/qmf2/QmfManagementPluginImpl.java255
-rw-r--r--qpid/tools/src/java/qpid-broker-plugins-management-qmf2/src/main/java/org/apache/qpid/server/qmf2/agentdata/Broker.java63
-rw-r--r--qpid/tools/src/java/qpid-broker-plugins-management-qmf2/src/main/resources/META-INF/services/org.apache.qpid.server.plugin.PluginFactory19
7 files changed, 311 insertions, 421 deletions
diff --git a/qpid/tools/src/java/qpid-broker-plugins-management-qmf2/pom.xml b/qpid/tools/src/java/qpid-broker-plugins-management-qmf2/pom.xml
index 04d2554523..10228911eb 100644
--- a/qpid/tools/src/java/qpid-broker-plugins-management-qmf2/pom.xml
+++ b/qpid/tools/src/java/qpid-broker-plugins-management-qmf2/pom.xml
@@ -44,6 +44,13 @@
</dependency>
<dependency>
+ <groupId>org.apache.qpid</groupId>
+ <artifactId>qpid-broker-codegen</artifactId>
+ <version>${project.version}</version>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j-version}</version>
diff --git a/qpid/tools/src/java/qpid-broker-plugins-management-qmf2/src/main/java/org/apache/qpid/server/qmf2/QmfManagementAgent.java b/qpid/tools/src/java/qpid-broker-plugins-management-qmf2/src/main/java/org/apache/qpid/server/qmf2/QmfManagementAgent.java
index 9b0aaafba3..4246bd7336 100644
--- a/qpid/tools/src/java/qpid-broker-plugins-management-qmf2/src/main/java/org/apache/qpid/server/qmf2/QmfManagementAgent.java
+++ b/qpid/tools/src/java/qpid-broker-plugins-management-qmf2/src/main/java/org/apache/qpid/server/qmf2/QmfManagementAgent.java
@@ -22,29 +22,24 @@
package org.apache.qpid.server.qmf2;
// Misc Imports
+
+import static org.apache.qpid.qmf2.common.WorkItem.WorkItemType.METHOD_CALL;
+
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;
@@ -52,13 +47,15 @@ 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;
+import org.apache.qpid.server.model.VirtualHostNode;
+
+// Simple Logging Facade 4 Java
+// QMF2 Imports
+// Java Broker model Imports
/**
* This class implements a QMF2 Agent providing access to the Java broker Management Objects via QMF2 thus
@@ -215,8 +212,10 @@ public class QmfManagementAgent implements ConfigurationChangeListener, QmfEvent
{
childAdded(null, _broker);
- for (VirtualHost<?> vhost : _broker.getVirtualHosts())
+ for (VirtualHostNode<?> vhostNode : _broker.getVirtualHostNodes())
{
+ VirtualHost<?,?,?> vhost = vhostNode.getVirtualHost();
+
// We don't add QmfAgentData VirtualHost objects. Possibly TODO, but it's a bit awkward at the moment
// because 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,
diff --git a/qpid/tools/src/java/qpid-broker-plugins-management-qmf2/src/main/java/org/apache/qpid/server/qmf2/QmfManagementFactory.java b/qpid/tools/src/java/qpid-broker-plugins-management-qmf2/src/main/java/org/apache/qpid/server/qmf2/QmfManagementFactory.java
deleted file mode 100644
index ec4ed37556..0000000000
--- a/qpid/tools/src/java/qpid-broker-plugins-management-qmf2/src/main/java/org/apache/qpid/server/qmf2/QmfManagementFactory.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- *
- * 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;
- }
- }
-
- @Override
- public String getType()
- {
- return "QMF2 Management";
- }
-}
diff --git a/qpid/tools/src/java/qpid-broker-plugins-management-qmf2/src/main/java/org/apache/qpid/server/qmf2/QmfManagementPlugin.java b/qpid/tools/src/java/qpid-broker-plugins-management-qmf2/src/main/java/org/apache/qpid/server/qmf2/QmfManagementPlugin.java
index 978ecc15d4..d8e7a73a13 100644
--- a/qpid/tools/src/java/qpid-broker-plugins-management-qmf2/src/main/java/org/apache/qpid/server/qmf2/QmfManagementPlugin.java
+++ b/qpid/tools/src/java/qpid-broker-plugins-management-qmf2/src/main/java/org/apache/qpid/server/qmf2/QmfManagementPlugin.java
@@ -18,287 +18,19 @@
* 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.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.ManagedAttribute;
+import org.apache.qpid.server.model.ManagedObject;
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 the management-schema.xml) in order to provide maximum cohesion between the
- * two 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<QmfManagementPlugin>
+@ManagedObject( category = false, type = "MANAGEMENT-QMF2" )
+public interface QmfManagementPlugin<X extends QmfManagementPlugin<X>> extends Plugin<X>
{
- 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 Map<String, Object> DEFAULTS = Collections.unmodifiableMap(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 = Collections.unmodifiableMap(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);
- addParent(Broker.class, broker);
- _broker = broker;
- _defaultVirtualHost = (String)broker.getAttribute("defaultVirtualHost");
- _connectionURL = (String)getAttribute(CONNECTION_URL);
- }
-
- /**
- * 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.
- getBroker().getEventLogger().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, "direct", attributes);
- }
-
- if (needDefaultTopic)
- {
- vhost.createExchange("qmf.default.topic", State.ACTIVE, true,
- LifetimePolicy.PERMANENT, "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.
- getBroker().getEventLogger().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).
- getBroker().getEventLogger().message(ManagementConsoleMessages.STOPPED(OPERATIONAL_LOGGING_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 getAttributeNames(QmfManagementPlugin.class);
- }
-
- /**
- * Accessor to retrieve the Plugin Type.
- * @return the Plugin Type e.g. the String "MANAGEMENT-QMF2".
- */
- @Override // From org.apache.qpid.server.model.Plugin
- public String getPluginType()
- {
- return PLUGIN_TYPE;
- }
+ String CONNECTION_URL = "connectionURL";
- /**
- * Accessor to retrieve the connectionURL attribute.
- * @return the JMS connectionURL of the Plugin.
- */
- @ManagedAttribute
- public String getConnectionURL()
- {
- return (String)getAttribute(CONNECTION_URL);
- }
+ @ManagedAttribute( automate = true , defaultValue = "amqp://guest:guest@/?brokerlist='tcp://0.0.0.0:5672'")
+ String getConnectionURL();
}
diff --git a/qpid/tools/src/java/qpid-broker-plugins-management-qmf2/src/main/java/org/apache/qpid/server/qmf2/QmfManagementPluginImpl.java b/qpid/tools/src/java/qpid-broker-plugins-management-qmf2/src/main/java/org/apache/qpid/server/qmf2/QmfManagementPluginImpl.java
new file mode 100644
index 0000000000..2e89805994
--- /dev/null
+++ b/qpid/tools/src/java/qpid-broker-plugins-management-qmf2/src/main/java/org/apache/qpid/server/qmf2/QmfManagementPluginImpl.java
@@ -0,0 +1,255 @@
+/*
+ *
+ * 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.HashMap;
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.qpid.exchange.ExchangeDefaults;
+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.ManagedAttributeField;
+import org.apache.qpid.server.model.ManagedObjectFactoryConstructor;
+import org.apache.qpid.server.model.State;
+import org.apache.qpid.server.model.VirtualHost;
+import org.apache.qpid.server.model.VirtualHostNode;
+import org.apache.qpid.server.model.adapter.AbstractPluginAdapter;
+
+// Simple Logging Facade 4 Java
+// Java Broker Management Imports
+
+/**
+ * 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 the management-schema.xml) in order to provide maximum cohesion between the
+ * two 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 QmfManagementPluginImpl extends AbstractPluginAdapter<QmfManagementPluginImpl>
+{
+ private static final Logger _log = LoggerFactory.getLogger(QmfManagementPluginImpl.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";
+ public static final String QMF_DEFAULT_DIRECT = "qmf.default.direct";
+ public static final String QMF_DEFAULT_TOPIC = "qmf.default.topic";
+
+
+ /************************************ End of Static initialiser *************************************/
+
+ private final Broker<?> _broker; // Passed in by Plugin bootstrapping.
+ private String _defaultVirtualHost; // Pulled from the broker attributes.
+
+ @ManagedAttributeField
+ private String _connectionURL; // Pulled from the Plugin config.
+ private QmfManagementAgent _agent;
+
+ /**
+ * Constructor, called at broker startup by QmfManagementFactory.createInstance().
+ * @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.
+ */
+ @ManagedObjectFactoryConstructor
+ public QmfManagementPluginImpl(Map<String, Object> attributes, Broker broker)
+ {
+ super(attributes, broker);
+ _broker = broker;
+ }
+
+ @Override
+ protected void onOpen()
+ {
+ super.onOpen();
+ _defaultVirtualHost = _broker.getDefaultVirtualHost();
+ }
+
+ /**
+ * 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 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 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.
+ getBroker().getEventLogger().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(VirtualHostNode<?> node : _broker.getVirtualHostNodes())
+ {
+ VirtualHost<?, ?, ?> vhost = node.getVirtualHost();
+
+ if (vhost.getName().equals(_defaultVirtualHost))
+ {
+ foundDefaultVirtualHost = true;
+
+ // Create the QMF2 exchanges if necessary.
+ if (vhost.getChildByName(Exchange.class, QMF_DEFAULT_DIRECT) == null)
+ {
+ Map<String, Object> attributes = new HashMap<>();
+ attributes.put(Exchange.NAME, QMF_DEFAULT_DIRECT);
+ attributes.put(Exchange.TYPE, ExchangeDefaults.DIRECT_EXCHANGE_CLASS);
+ attributes.put(Exchange.STATE, State.ACTIVE);
+ attributes.put(Exchange.LIFETIME_POLICY, LifetimePolicy.PERMANENT);
+ attributes.put(Exchange.DURABLE, true);
+ vhost.createExchange(attributes);
+ }
+
+ if (vhost.getChildByName(Exchange.class, QMF_DEFAULT_TOPIC) == null)
+ {
+ Map<String, Object> attributes = new HashMap<>();
+ attributes.put(Exchange.NAME, QMF_DEFAULT_TOPIC);
+ attributes.put(Exchange.TYPE, ExchangeDefaults.TOPIC_EXCHANGE_CLASS);
+ attributes.put(Exchange.STATE, State.ACTIVE);
+ attributes.put(Exchange.LIFETIME_POLICY, LifetimePolicy.PERMANENT);
+ attributes.put(Exchange.DURABLE, true);
+ vhost.createExchange(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.
+ getBroker().getEventLogger().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).
+ getBroker().getEventLogger().message(ManagementConsoleMessages.STOPPED(OPERATIONAL_LOGGING_NAME));
+ }
+
+ /**
+ * Accessor to retrieve the connectionURL attribute.
+ * @return the JMS connectionURL of the Plugin.
+ */
+ public String getConnectionURL()
+ {
+ return _connectionURL;
+ }
+}
diff --git a/qpid/tools/src/java/qpid-broker-plugins-management-qmf2/src/main/java/org/apache/qpid/server/qmf2/agentdata/Broker.java b/qpid/tools/src/java/qpid-broker-plugins-management-qmf2/src/main/java/org/apache/qpid/server/qmf2/agentdata/Broker.java
index 644b25fd03..f33a07ecdd 100644
--- a/qpid/tools/src/java/qpid-broker-plugins-management-qmf2/src/main/java/org/apache/qpid/server/qmf2/agentdata/Broker.java
+++ b/qpid/tools/src/java/qpid-broker-plugins-management-qmf2/src/main/java/org/apache/qpid/server/qmf2/agentdata/Broker.java
@@ -22,30 +22,20 @@
package org.apache.qpid.server.qmf2.agentdata;
// Misc Imports
+
import java.util.Collections;
import java.util.HashMap;
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.Agent;
import org.apache.qpid.qmf2.agent.QmfAgentData;
import org.apache.qpid.qmf2.common.Handle;
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.SchemaEventClass;
-import org.apache.qpid.qmf2.common.SchemaMethod;
import org.apache.qpid.qmf2.common.SchemaObjectClass;
-import org.apache.qpid.qmf2.common.SchemaProperty;
-
-// Java Broker model Imports
import org.apache.qpid.server.model.Binding;
import org.apache.qpid.server.model.Exchange;
import org.apache.qpid.server.model.LifetimePolicy;
@@ -55,6 +45,15 @@ import org.apache.qpid.server.model.Queue;
import org.apache.qpid.server.model.State;
import org.apache.qpid.server.model.Transport;
import org.apache.qpid.server.model.VirtualHost;
+import org.apache.qpid.server.model.VirtualHostNode;
+
+// Simple Logging Facade 4 Java
+// QMF2 Imports
+/*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;*/
+// Java Broker model Imports
/**
* This class provides a concrete implementation of QmfAgentData for the Broker Management Object.
@@ -112,8 +111,8 @@ public class Broker extends QmfAgentData
*/
private class NameParser
{
- private String _vhostName = _defaultVirtualHost;
- private VirtualHost<?> _vhost = null;
+ private String _vhostName;
+ private VirtualHost<?,?,?> _vhost = null;
private String _exchangeName = "";
private Exchange<?> _exchange = null;
private String _queueName = "";
@@ -148,13 +147,18 @@ public class Broker extends QmfAgentData
_vhostName = _vhostName.substring(6, _vhostName.length());
}
}
+ else
+ {
+ _vhostName = _defaultVirtualHost;
+ }
// If the vhostName isn't malformed then try to find the actual Virtual Host that it relates to.
// If it is malformed the vhost stays set to null, which will cause an exception to be returned later.
if (!malformedVHostName)
{
- for (VirtualHost vhost : _broker.getVirtualHosts())
+ for (VirtualHostNode<?> vhostNode : _broker.getVirtualHostNodes())
{
+ VirtualHost<?,?,?> vhost = vhostNode.getVirtualHost();
if (vhost.getName().equals(_vhostName))
{
_vhost = vhost;
@@ -539,22 +543,19 @@ System.out.println("properties = " + properties);
return;
}
- // TODO delete this block when adding an AlternateExchange is implemented.
- if (alternateExchange != null)
- {
- agent.raiseException(handle,
- "Setting an Alternate Exchange on an Exchange is not yet implemented.");
- return;
- }
-
// Note that for Qpid 0.20 the "qpid.msg_sequence=1" and "qpid.ive=1" properties are
// not suppored, indeed no exchange properties seem to be supported yet.
- vhost.createExchange(nameParser.getExchangeName(), State.ACTIVE, durable,
- LifetimePolicy.PERMANENT, exchangeType, properties);
- if (alternateExchange != null)
- {
- // TODO set Alternate Exchange. There doesn't seem to be a way to do this yet!!!
- }
+ Map<String,Object> attributes = new HashMap<>();
+ attributes.put(Exchange.NAME, nameParser.getExchangeName());
+ attributes.put(Exchange.STATE, State.ACTIVE);
+ attributes.put(Exchange.DURABLE, durable);
+ attributes.put(Exchange.LIFETIME_POLICY, LifetimePolicy.PERMANENT);
+ attributes.put(Exchange.TYPE, exchangeType);
+ attributes.put(Exchange.ALTERNATE_EXCHANGE, alternateExchange);
+
+
+ vhost.createExchange(attributes);
+
} // End of create exchange.
else if (type.equals("queue")) // create queue.
{
@@ -583,7 +584,6 @@ System.out.println("properties = " + properties);
attributes.put(Queue.DURABLE, durable);
attributes.put(Queue.LIFETIME_POLICY, LifetimePolicy.PERMANENT);
- Queue queue = vhost.createQueue(attributes);
// Set the queue's alternateExchange, which is just a little bit involved......
// The queue.setAttribute() method needs an org.apache.qpid.server.model.Exchange instance
@@ -600,13 +600,14 @@ System.out.println("properties = " + properties);
QmfAgentData object = agent.getObject(objectId);
if (object != null)
{
- org.apache.qpid.server.qmf2.agentdata.Exchange ex =
+ org.apache.qpid.server.qmf2.agentdata.Exchange ex =
(org.apache.qpid.server.qmf2.agentdata.Exchange)object;
Exchange altEx = ex.getExchange();
- queue.setAttribute("alternateExchange", null, altEx);
+ attributes.put(Queue.ALTERNATE_EXCHANGE, altEx.getId());
}
}
+ Queue queue = vhost.createQueue(attributes);
}
else if (type.equals("binding")) // create binding.
{
diff --git a/qpid/tools/src/java/qpid-broker-plugins-management-qmf2/src/main/resources/META-INF/services/org.apache.qpid.server.plugin.PluginFactory b/qpid/tools/src/java/qpid-broker-plugins-management-qmf2/src/main/resources/META-INF/services/org.apache.qpid.server.plugin.PluginFactory
deleted file mode 100644
index 762879a325..0000000000
--- a/qpid/tools/src/java/qpid-broker-plugins-management-qmf2/src/main/resources/META-INF/services/org.apache.qpid.server.plugin.PluginFactory
+++ /dev/null
@@ -1,19 +0,0 @@
-#
-# 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.
-#
-org.apache.qpid.server.qmf2.QmfManagementFactory