diff options
author | Robert Godfrey <rgodfrey@apache.org> | 2014-05-02 09:43:19 +0000 |
---|---|---|
committer | Robert Godfrey <rgodfrey@apache.org> | 2014-05-02 09:43:19 +0000 |
commit | 05f4e2a5113a02e35f0e03345b153422fb9c8d1f (patch) | |
tree | 2fe33d14669f650dec936f3822528c98bbce0629 | |
parent | 23954de4a3bc293b2a598b562279915ee42dfbd4 (diff) | |
download | qpid-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
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> - * <jar destfile="build/lib/qpid-broker-plugins-management-qmf2.jar" - * basedir="build/scratch/qpid-broker-plugins-management-qmf2"> - * - * <service type="org.apache.qpid.server.plugin.PluginFactory" - * provider="org.apache.qpid.server.qmf2.QmfManagementFactory"/> - * </jar> - * </pre> - * @author Fraser Adams - */ -public class QmfManagementFactory implements PluginFactory -{ - /** - * This factory method creates an instance of QmfManagementPlugin called via the QpidServiceLoader. - * @param id the UUID of the Plugin. - * @param attributes a Map containing configuration information for the Plugin. - * @param broker the root Broker Management Object from which the other Management Objects may be obtained. - * @return the QmfManagementPlugin instance which creates a QMF2 Agent able to interrogate the broker Management - * Objects and return their properties as QmfData. - */ - @Override - public Plugin createInstance(UUID id, Map<String, Object> attributes, Broker broker) - { - if (QmfManagementPlugin.PLUGIN_TYPE.equals(attributes.get(PLUGIN_TYPE))) - { - return new QmfManagementPlugin(id, broker, attributes); - } - else - { - return null; - } - } - - @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 |