diff options
313 files changed, 23899 insertions, 7481 deletions
diff --git a/qpid/doc/book/src/java-broker/MessageStore-Tool.xml b/qpid/doc/book/src/java-broker/MessageStore-Tool.xml new file mode 100644 index 0000000000..fdcb3cd560 --- /dev/null +++ b/qpid/doc/book/src/java-broker/MessageStore-Tool.xml @@ -0,0 +1,150 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + + 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. + +--> + +<section><title> + MessageStore Tool + </title><section role="h2" id="MessageStoreTool-MessageStoreTool"><title> + MessageStore Tool + </title> + + <para> + We have a number of implementations of the Qpid MessageStore + interface. This tool allows the interrogation of these stores + while the broker is offline. + </para> + + <section role="h3" id="MessageStoreTool-MessageStoreImplementations"><title> + MessageStore + Implementations + </title> + + <itemizedlist> + <listitem><para> + <xref linkend="qpid_BDBMessageStore--3rd-Party-"/> + </para></listitem> + <listitem><para> + <xref linkend="qpid_JDBCStore"/> + </para></listitem> + <listitem><para> + <xref linkend="qpid_MemoryMessageStore"/> + </para></listitem> + </itemizedlist> +<!--h3--></section> + + <section role="h3" id="MessageStoreTool-Introduction"><title> + Introduction + </title> + + <para> + Each of the MessageStore implementations provide different back + end storage for their messages and so would need a different tool + to be able to interrogate their contents at the back end. + </para><para> + What this tool does is to utilise the Java broker code base to + access the contents of the storage providing the user with a + consistent means to inspect the storage contents in broker + memory. The tool allows the current messages in the store to be + inspected and copied/moved between queues. The tool uses the + message instance in memory for all its access paths, but changes + made will be reflected in the physical store (if one exists). + </para> +<!--h3--></section> + + <section role="h3" id="MessageStoreTool-Usage"><title> + Usage + </title> + + <para> + The tools-distribution currently includes a unix shell command + 'msTool.sh' this script will launch the java tool. + </para><para> + The tool loads $QPID_HOME/etc/config.xml by default. If an + alternative broker configuration is required this should be + provided on the command line as would be done for the broker. + </para> + <programlisting> +msTool.sh -c <path to different config.xml> +</programlisting> + <para> + On startup the user is present with a command prompt + </para> + <programlisting> +$ msTool.sh +MessageStoreTool - for examining Persistent Qpid Broker MessageStore instances +bdb$ +</programlisting> +<!--h3--></section> + + <section role="h3" id="MessageStoreTool-AvailableCommands"><title> + Available + Commands + </title> + + <para> + The available commands in the tool can be seen through the use of + the 'help' command. + </para> + <programlisting> +bdb$ help ++----------------------------------------------------------------+ +| Available Commands | ++----------------------------------------------------------------+ +| Command | Description | ++----------------------------------------------------------------+ +| quit | Quit the tool. | +| list | list available items. | +| dump | Dump selected message content. Default: show=content | +| load | Loads specified broker configuration file. | +| clear | Clears any selection. | +| show | Shows the messages headers. | +| select | Perform a selection. | +| help | Provides detailed help on commands. | ++----------------------------------------------------------------+ +bdb$ +</programlisting> + <para> + A brief description is displayed and further usage information is + shown with 'help <command>' + </para> + <programlisting> +bdb$ help list +list availble items. +Usage:list queues [<exchange>] | exchanges | bindings [<exchange>] | all +bdb$ +</programlisting> +<!--h3--></section> + + + <section role="h3" id="MessageStoreTool-FutureWork"><title> + Future Work + </title> + + <para> + Currently the tool only works whilst the broker is offline i.e. + it is up, but not accepting AMQP connections. This requires a + stop/start of the broker. If this functionality was incorporated + into the broker then a telnet functionality could be provided + allowing online management. + </para> +<!--h3--></section> +<!--h2--></section> +</section> diff --git a/qpid/java/bdbstore/build.xml b/qpid/java/bdbstore/build.xml index 7df048c691..7c305c7c2f 100644 --- a/qpid/java/bdbstore/build.xml +++ b/qpid/java/bdbstore/build.xml @@ -17,7 +17,7 @@ - under the License. --> <project name="bdbstore" xmlns:ivy="antlib:org.apache.ivy.ant" default="build"> - <property name="module.depends" value="management/common common broker" /> + <property name="module.depends" value="common broker" /> <property name="module.test.depends" value="test client common/test broker/test management/common systests" /> <property name="module.genpom" value="true"/> diff --git a/qpid/java/bdbstore/jmx/MANIFEST.MF b/qpid/java/bdbstore/jmx/MANIFEST.MF new file mode 100644 index 0000000000..7046c4326d --- /dev/null +++ b/qpid/java/bdbstore/jmx/MANIFEST.MF @@ -0,0 +1,20 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Qpid Bdbstore-Plugins JMX +Bundle-SymbolicName: bdbstore-plugins-jmx +Bundle-Description: Bdbstore Management plugin for Qpid. +Bundle-License: http://www.apache.org/licenses/LICENSE-2.0.txt +Bundle-DocURL: http://www.apache.org/ +Bundle-Version: 1.0.0 +Bundle-RequiredExecutionEnvironment: JavaSE-1.6 +Bundle-ClassPath: . +Fragment-Host: broker-plugins-jmx +Import-Package: org.apache.qpid, + org.apache.qpid.management.common.mbeans.annotations, + org.apache.qpid.server.model, + org.apache.qpid.server.virtualhost, + org.apache.qpid.server.store.berkeleydb, + org.apache.log4j;version=1.2.16, + javax.management, + javax.management.openmbean +Export-Package: org.apache.qpid.server.store.berkeleydb.jmx diff --git a/qpid/java/broker-plugins/experimental/shutdown/build.xml b/qpid/java/bdbstore/jmx/build.xml index 96f97ee437..2015b0cbb5 100644 --- a/qpid/java/broker-plugins/experimental/shutdown/build.xml +++ b/qpid/java/bdbstore/jmx/build.xml @@ -1,5 +1,4 @@ <!-- - - - 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 @@ -7,25 +6,24 @@ - 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. - - --> -<project name="AMQ Broker Shutdown Plugin" default="build"> - <property name="module.depends" value="common broker management/common broker-plugins"/> - <property name="module.test.depends" value="test broker/test management/common client systests"/> - <property name="module.manifest" value="MANIFEST.MF"/> - <property name="module.plugin" value="true"/> +<project name="bdbstore-jmx" default="build"> + <property name="module.depends" value="common broker broker-plugins broker-plugins/jmx management/common bdbstore" /> + <property name="module.test.depends" value="test broker/test common/test management/common client systests bdbstore/test" /> - <import file="../../../module.xml"/> + <property name="module.manifest" value="MANIFEST.MF" /> + <property name="module.plugin" value="true" /> - <target name="bundle" depends="bundle-tasks"/> + <import file="../../module.xml" /> + <target name="bundle" depends="bundle-tasks" /> </project> diff --git a/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/BDBHAMessageStoreManagerMBean.java b/qpid/java/bdbstore/jmx/src/main/java/org/apache/qpid/server/store/berkeleydb/jmx/BDBHAMessageStoreManagerMBean.java index c2c7bf4c86..455573f7bc 100644 --- a/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/BDBHAMessageStoreManagerMBean.java +++ b/qpid/java/bdbstore/jmx/src/main/java/org/apache/qpid/server/store/berkeleydb/jmx/BDBHAMessageStoreManagerMBean.java @@ -17,14 +17,13 @@ * under the License. * */ -package org.apache.qpid.server.store.berkeleydb; +package org.apache.qpid.server.store.berkeleydb.jmx; import java.io.IOException; import java.util.List; import java.util.Map; import javax.management.JMException; -import javax.management.NotCompliantMBeanException; import javax.management.openmbean.CompositeData; import javax.management.openmbean.CompositeDataSupport; import javax.management.openmbean.CompositeType; @@ -37,8 +36,19 @@ import javax.management.openmbean.TabularType; import org.apache.log4j.Logger; import org.apache.qpid.AMQStoreException; -import org.apache.qpid.server.management.AMQManagedObject; - +import org.apache.qpid.server.jmx.AMQManagedObject; +import org.apache.qpid.server.jmx.ManagedObject; +import org.apache.qpid.server.store.berkeleydb.BDBHAMessageStore; + +/** + * Management mbean for BDB HA. + * <p> + * At runtime, the classloader loading this clas must have visibility of the other Qpid JMX classes. This is + * currently arranged through OSGI using the <b>fragment</b> feature so that this bundle shares the + * same classloader as broker-plugins-jmx. See the <b>Fragment-Host:</b> header within the MANIFEST.MF + * of this bundle. + * </p> + */ public class BDBHAMessageStoreManagerMBean extends AMQManagedObject implements ManagedBDBHAMessageStore { private static final Logger LOGGER = Logger.getLogger(BDBHAMessageStoreManagerMBean.class); @@ -70,10 +80,12 @@ public class BDBHAMessageStoreManagerMBean extends AMQManagedObject implements M private final BDBHAMessageStore _store; - protected BDBHAMessageStoreManagerMBean(BDBHAMessageStore store) throws NotCompliantMBeanException + protected BDBHAMessageStoreManagerMBean(BDBHAMessageStore store, ManagedObject parent) throws JMException { - super(ManagedBDBHAMessageStore.class, ManagedBDBHAMessageStore.TYPE); + super(ManagedBDBHAMessageStore.class, ManagedBDBHAMessageStore.TYPE, ((AMQManagedObject)parent).getRegistry()); + LOGGER.debug("Creating BDBHAMessageStoreManagerMBean"); _store = store; + register(); } @Override @@ -211,4 +223,10 @@ public class BDBHAMessageStoreManagerMBean extends AMQManagedObject implements M } } + @Override + public ManagedObject getParentObject() + { + return null; + } + } diff --git a/qpid/java/bdbstore/jmx/src/main/java/org/apache/qpid/server/store/berkeleydb/jmx/BDBHAMessageStoreManagerMBeanProvider.java b/qpid/java/bdbstore/jmx/src/main/java/org/apache/qpid/server/store/berkeleydb/jmx/BDBHAMessageStoreManagerMBeanProvider.java new file mode 100644 index 0000000000..837da1eef3 --- /dev/null +++ b/qpid/java/bdbstore/jmx/src/main/java/org/apache/qpid/server/store/berkeleydb/jmx/BDBHAMessageStoreManagerMBeanProvider.java @@ -0,0 +1,73 @@ +/* + * + * 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.store.berkeleydb.jmx; + +import javax.management.JMException; +import javax.management.StandardMBean; + +import org.apache.log4j.Logger; +import org.apache.qpid.server.jmx.MBeanProvider; +import org.apache.qpid.server.jmx.ManagedObject; +import org.apache.qpid.server.model.ConfiguredObject; +import org.apache.qpid.server.model.VirtualHost; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.store.berkeleydb.BDBHAMessageStore; +import org.apache.qpid.server.virtualhost.VirtualHostRegistry; + +/** + * This provide will create a {@link BDBHAMessageStoreManagerMBean} if the child is a virtual + * host and of type {@link BDBHAMessageStore#BDB_HA_STORE_TYPE}. + * + */ +public class BDBHAMessageStoreManagerMBeanProvider implements MBeanProvider +{ + private static final Logger LOGGER = Logger.getLogger(BDBHAMessageStoreManagerMBeanProvider.class); + + public BDBHAMessageStoreManagerMBeanProvider() + { + super(); + } + + @Override + public boolean isChildManageableByMBean(ConfiguredObject child) + { + return (child instanceof VirtualHost + && BDBHAMessageStore.BDB_HA_STORE_TYPE.equals(child.getAttribute(VirtualHost.STORE_TYPE))); + } + + @Override + public StandardMBean createMBean(ConfiguredObject child, StandardMBean parent) throws JMException + { + VirtualHost virtualHostChild = (VirtualHost) child; + + VirtualHostRegistry virtualHostRegistry = ApplicationRegistry.getInstance().getVirtualHostRegistry(); + org.apache.qpid.server.virtualhost.VirtualHost vhost = virtualHostRegistry.getVirtualHost(virtualHostChild.getName()); + + BDBHAMessageStore messageStore = (BDBHAMessageStore) vhost.getMessageStore(); + + if (LOGGER.isDebugEnabled()) + { + LOGGER.debug("Creating mBean for child " + child); + } + + return new BDBHAMessageStoreManagerMBean(messageStore, (ManagedObject) parent); + } +} diff --git a/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/ManagedBDBHAMessageStore.java b/qpid/java/bdbstore/jmx/src/main/java/org/apache/qpid/server/store/berkeleydb/jmx/ManagedBDBHAMessageStore.java index 6499ea04e0..b85e44526b 100644 --- a/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/ManagedBDBHAMessageStore.java +++ b/qpid/java/bdbstore/jmx/src/main/java/org/apache/qpid/server/store/berkeleydb/jmx/ManagedBDBHAMessageStore.java @@ -17,7 +17,7 @@ * under the License. * */ -package org.apache.qpid.server.store.berkeleydb; +package org.apache.qpid.server.store.berkeleydb.jmx; import java.io.IOException; diff --git a/qpid/java/bdbstore/jmx/src/main/resources/services/org.apache.qpid.server.jmx.MBeanProvider b/qpid/java/bdbstore/jmx/src/main/resources/services/org.apache.qpid.server.jmx.MBeanProvider new file mode 100644 index 0000000000..b5bc947612 --- /dev/null +++ b/qpid/java/bdbstore/jmx/src/main/resources/services/org.apache.qpid.server.jmx.MBeanProvider @@ -0,0 +1 @@ +org.apache.qpid.server.store.berkeleydb.jmx.BDBHAMessageStoreManagerMBeanProvider diff --git a/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/HAClusterManagementTest.java b/qpid/java/bdbstore/jmx/src/test/java/org/apache/qpid/server/store/berkeleydb/HAClusterManagementTest.java index b01f169715..45038bf050 100644 --- a/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/HAClusterManagementTest.java +++ b/qpid/java/bdbstore/jmx/src/test/java/org/apache/qpid/server/store/berkeleydb/HAClusterManagementTest.java @@ -35,6 +35,7 @@ import javax.management.openmbean.TabularData; import org.apache.log4j.Logger; import org.apache.qpid.jms.ConnectionURL; +import org.apache.qpid.server.store.berkeleydb.jmx.ManagedBDBHAMessageStore; import org.apache.qpid.test.utils.JMXTestUtils; import org.apache.qpid.test.utils.QpidBrokerTestCase; diff --git a/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/HAClusterTwoNodeTest.java b/qpid/java/bdbstore/jmx/src/test/java/org/apache/qpid/server/store/berkeleydb/HAClusterTwoNodeTest.java index 294859832f..22877ec36c 100644 --- a/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/HAClusterTwoNodeTest.java +++ b/qpid/java/bdbstore/jmx/src/test/java/org/apache/qpid/server/store/berkeleydb/HAClusterTwoNodeTest.java @@ -29,6 +29,7 @@ import javax.jms.MessageConsumer; import javax.jms.Session; import org.apache.qpid.jms.ConnectionURL; +import org.apache.qpid.server.store.berkeleydb.jmx.ManagedBDBHAMessageStore; import org.apache.qpid.test.utils.JMXTestUtils; import org.apache.qpid.test.utils.QpidBrokerTestCase; diff --git a/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/BDBHAMessageStoreManagerMBeanTest.java b/qpid/java/bdbstore/jmx/src/test/java/org/apache/qpid/server/store/berkeleydb/jmx/BDBHAMessageStoreManagerMBeanTest.java index b64a213756..49b3ddd3dc 100644 --- a/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/BDBHAMessageStoreManagerMBeanTest.java +++ b/qpid/java/bdbstore/jmx/src/test/java/org/apache/qpid/server/store/berkeleydb/jmx/BDBHAMessageStoreManagerMBeanTest.java @@ -17,7 +17,7 @@ * under the License. * */ -package org.apache.qpid.server.store.berkeleydb; +package org.apache.qpid.server.store.berkeleydb.jmx; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; @@ -37,9 +37,14 @@ import javax.management.openmbean.TabularData; import junit.framework.TestCase; import org.apache.qpid.AMQStoreException; +import org.apache.qpid.server.jmx.AMQManagedObject; +import org.apache.qpid.server.jmx.ManagedObjectRegistry; import org.apache.qpid.server.logging.SystemOutMessageLogger; import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.logging.actors.TestLogActor; +import org.apache.qpid.server.store.berkeleydb.BDBHAMessageStore; +import org.apache.qpid.server.store.berkeleydb.jmx.BDBHAMessageStoreManagerMBean; +import org.apache.qpid.server.store.berkeleydb.jmx.ManagedBDBHAMessageStore; public class BDBHAMessageStoreManagerMBeanTest extends TestCase { @@ -54,6 +59,7 @@ public class BDBHAMessageStoreManagerMBeanTest extends TestCase private BDBHAMessageStore _store; private BDBHAMessageStoreManagerMBean _mBean; + private AMQManagedObject _mBeanParent; @Override protected void setUp() throws Exception @@ -62,7 +68,9 @@ public class BDBHAMessageStoreManagerMBeanTest extends TestCase CurrentActor.set(new TestLogActor(new SystemOutMessageLogger())); _store = mock(BDBHAMessageStore.class); - _mBean = new BDBHAMessageStoreManagerMBean(_store); + _mBeanParent = mock(AMQManagedObject.class); + when(_mBeanParent.getRegistry()).thenReturn(mock(ManagedObjectRegistry.class)); + _mBean = new BDBHAMessageStoreManagerMBean(_store, _mBeanParent); } @Override diff --git a/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/BDBHAMessageStore.java b/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/BDBHAMessageStore.java index ab54d7d16a..c40f24dbc3 100644 --- a/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/BDBHAMessageStore.java +++ b/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/BDBHAMessageStore.java @@ -105,6 +105,8 @@ public class BDBHAMessageStore extends AbstractBDBMessageStore implements HAMess put(ReplicationConfig.LOG_FLUSH_TASK_INTERVAL, "1 min"); }}); + public static final String BDB_HA_STORE_TYPE = "BDB-HA"; + private String _groupName; private String _nodeName; private String _nodeHostPort; @@ -113,8 +115,6 @@ public class BDBHAMessageStore extends AbstractBDBMessageStore implements HAMess private String _name; - private BDBHAMessageStoreManagerMBean _managedObject; - private CommitThreadWrapper _commitThreadWrapper; private boolean _coalescingSync; private boolean _designatedPrimary; @@ -149,8 +149,6 @@ public class BDBHAMessageStore extends AbstractBDBMessageStore implements HAMess throw new ConfigurationException("Coalescing sync cannot be used with master sync policy " + SyncPolicy.SYNC + "! Please set highAvailability.coalescingSync to false in store configuration."); } - _managedObject = new BDBHAMessageStoreManagerMBean(this); - _managedObject.register(); super.configure(name, storeConfig); } @@ -394,28 +392,18 @@ public class BDBHAMessageStore extends AbstractBDBMessageStore implements HAMess @Override protected void closeInternal() throws Exception { + substituteNoOpStateChangeListenerOn(getReplicatedEnvironment()); + try { - substituteNoOpStateChangeListenerOn(getReplicatedEnvironment()); - - try - { - if(_coalescingSync) - { - _commitThreadWrapper.stopCommitThread(); - } - } - finally + if(_coalescingSync) { - super.closeInternal(); + _commitThreadWrapper.stopCommitThread(); } } finally { - if (_managedObject != null) - { - _managedObject.unregister(); - } + super.closeInternal(); } } @@ -610,4 +598,10 @@ public class BDBHAMessageStore extends AbstractBDBMessageStore implements HAMess { } } + + @Override + public String getStoreType() + { + return BDB_HA_STORE_TYPE; + } } diff --git a/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/BDBMessageStore.java b/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/BDBMessageStore.java index d5bf5374bc..82bc3d8564 100644 --- a/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/BDBMessageStore.java +++ b/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/BDBMessageStore.java @@ -42,6 +42,7 @@ import com.sleepycat.je.EnvironmentConfig; public class BDBMessageStore extends AbstractBDBMessageStore { private static final Logger LOGGER = Logger.getLogger(BDBMessageStore.class); + private static final String BDB_STORE_TYPE = "BDB"; private CommitThreadWrapper _commitThreadWrapper; @Override @@ -103,4 +104,11 @@ public class BDBMessageStore extends AbstractBDBMessageStore return _commitThreadWrapper.commit(tx, syncCommit); } + + @Override + public String getStoreType() + { + return BDB_STORE_TYPE; + } + } diff --git a/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/upgrade/UpgradeFrom5To6.java b/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/upgrade/UpgradeFrom5To6.java index 3265fb6823..97a3d61df1 100644 --- a/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/upgrade/UpgradeFrom5To6.java +++ b/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/upgrade/UpgradeFrom5To6.java @@ -45,6 +45,7 @@ import org.apache.qpid.server.model.Exchange; import org.apache.qpid.server.model.LifetimePolicy; import org.apache.qpid.server.model.Queue; import org.apache.qpid.server.model.UUIDGenerator; +import org.apache.qpid.server.queue.AMQQueueFactory; import org.apache.qpid.server.store.berkeleydb.AMQShortStringEncoding; import org.apache.qpid.server.store.berkeleydb.FieldTableEncoding; import org.apache.qpid.server.util.MapJsonSerializer; @@ -93,6 +94,8 @@ public class UpgradeFrom5To6 extends AbstractStoreUpgrade private MapJsonSerializer _serializer = new MapJsonSerializer(); + private static final boolean _moveNonExclusiveQueueOwnerToDescription = Boolean.parseBoolean(System.getProperty("qpid.move_non_exclusive_queue_owner_to_description", Boolean.TRUE.toString())); + /** * Upgrades from a v5 database to a v6 database * @@ -554,17 +557,49 @@ public class UpgradeFrom5To6 extends AbstractStoreUpgrade private UpgradeConfiguredObjectRecord createQueueConfiguredObjectRecord(String queueName, String owner, boolean exclusive, FieldTable arguments) { + Map<String, Object> attributesMap = buildQueueArgumentMap(queueName, + owner, exclusive, arguments); + String json = _serializer.serialize(attributesMap); + UpgradeConfiguredObjectRecord configuredObject = new UpgradeConfiguredObjectRecord(Queue.class.getName(), json); + return configuredObject; + } + + private Map<String, Object> buildQueueArgumentMap(String queueName, + String owner, boolean exclusive, FieldTable arguments) + { + Map<String, Object> attributesMap = new HashMap<String, Object>(); attributesMap.put(Queue.NAME, queueName); - attributesMap.put(Queue.OWNER, owner); attributesMap.put(Queue.EXCLUSIVE, exclusive); + + FieldTable argumentsCopy = new FieldTable(); if (arguments != null) { - attributesMap.put("ARGUMENTS", FieldTable.convertToMap(arguments)); + argumentsCopy.addAll(arguments); } - String json = _serializer.serialize(attributesMap); - UpgradeConfiguredObjectRecord configuredObject = new UpgradeConfiguredObjectRecord(Queue.class.getName(), json); - return configuredObject; + + if (moveNonExclusiveOwnerToDescription(owner, exclusive)) + { + _logger.info("Non-exclusive owner " + owner + " for queue " + queueName + " moved to " + AMQQueueFactory.X_QPID_DESCRIPTION); + + attributesMap.put(Queue.OWNER, null); + argumentsCopy.put(AMQShortString.valueOf(AMQQueueFactory.X_QPID_DESCRIPTION), owner); + } + else + { + attributesMap.put(Queue.OWNER, owner); + } + if (!argumentsCopy.isEmpty()) + { + attributesMap.put(Queue.ARGUMENTS, FieldTable.convertToMap(argumentsCopy)); + } + return attributesMap; + } + + private boolean moveNonExclusiveOwnerToDescription(String owner, + boolean exclusive) + { + return exclusive == false && owner != null && _moveNonExclusiveQueueOwnerToDescription; } private UpgradeConfiguredObjectRecord createExchangeConfiguredObjectRecord(String exchangeName, String exchangeType, diff --git a/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/BDBMessageStoreConfigurationTest.java b/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/BDBMessageStoreConfigurationTest.java index 687c671566..5cc436a22a 100644 --- a/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/BDBMessageStoreConfigurationTest.java +++ b/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/BDBMessageStoreConfigurationTest.java @@ -1,3 +1,23 @@ +/* + * + * 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.store.berkeleydb; import org.apache.qpid.server.store.DurableConfigurationStoreTest; diff --git a/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/BDBMessageStoreTest.java b/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/BDBMessageStoreTest.java index 591bc27d1e..e97323c5f2 100644 --- a/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/BDBMessageStoreTest.java +++ b/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/BDBMessageStoreTest.java @@ -55,7 +55,7 @@ import org.apache.qpid.transport.MessageTransfer; /** * Subclass of MessageStoreTest which runs the standard tests from the superclass against - * the BDB Store as well as additional tests specific to the DBB store-implementation. + * the BDB Store as well as additional tests specific to the BDB store-implementation. */ public class BDBMessageStoreTest extends org.apache.qpid.server.store.MessageStoreTest { diff --git a/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/upgrade/AbstractUpgradeTestCase.java b/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/upgrade/AbstractUpgradeTestCase.java index 36991b90d0..c0d74bc847 100644 --- a/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/upgrade/AbstractUpgradeTestCase.java +++ b/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/upgrade/AbstractUpgradeTestCase.java @@ -52,8 +52,8 @@ public abstract class AbstractUpgradeTestCase extends QpidTestCase } public static final String[] QUEUE_NAMES = { "clientid:myDurSubName", "clientid:mySelectorDurSubName", "myUpgradeQueue", - "queue-non-durable" }; - public static int[] QUEUE_SIZES = { 1, 1, 10, 3 }; + "queue-non-durable", "nonexclusive-with-erroneous-owner" }; + public static int[] QUEUE_SIZES = { 1, 1, 10, 3, 0}; public static int TOTAL_MESSAGE_NUMBER = 15; protected static final LogSubject LOG_SUBJECT = new TestBlankSubject(); @@ -98,7 +98,7 @@ public abstract class AbstractUpgradeTestCase extends QpidTestCase finally { _environment = null; - deleteDirectoryIfExists(_storeLocation); + //deleteDirectoryIfExists(_storeLocation); } super.tearDown(); } diff --git a/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/upgrade/UpgradeFrom4to5Test.java b/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/upgrade/UpgradeFrom4to5Test.java index 3f9e4e4aa1..65a8bb03fb 100644 --- a/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/upgrade/UpgradeFrom4to5Test.java +++ b/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/upgrade/UpgradeFrom4to5Test.java @@ -23,10 +23,13 @@ package org.apache.qpid.server.store.berkeleydb.upgrade; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; import org.apache.qpid.common.AMQPFilterTypes; import org.apache.qpid.framing.AMQShortString; @@ -49,6 +52,7 @@ public class UpgradeFrom4to5Test extends AbstractUpgradeTestCase { private static final String NON_DURABLE_QUEUE = BDBStoreUpgradeTestPreparer.NON_DURABLE_QUEUE_NAME; private static final String DURABLE_QUEUE = BDBStoreUpgradeTestPreparer.QUEUE_NAME; + private static final String NON_EXCLUSIVE_WITH_ERRONEOUS_OWNER = "nonexclusive-with-erroneous-owner"; private static final String DURABLE_SUBSCRIPTION_QUEUE_WITH_SELECTOR = "clientid:mySelectorDurSubName"; private static final String DURABLE_SUBSCRIPTION_QUEUE = "clientid:myDurSubName"; private static final String EXCHANGE_DB_NAME = "exchangeDb_v5"; @@ -87,6 +91,10 @@ public class UpgradeFrom4to5Test extends AbstractUpgradeTestCase BDBStoreUpgradeTestPreparer.SELECTOR_TOPIC_NAME, "testprop='true'"); assertBindingRecord(queueBindings, DURABLE_QUEUE, "amq.direct", DURABLE_QUEUE, null); assertBindingRecord(queueBindings, NON_DURABLE_QUEUE, "amq.direct", NON_DURABLE_QUEUE, null); + assertBindingRecord(queueBindings, NON_EXCLUSIVE_WITH_ERRONEOUS_OWNER, "amq.direct", NON_EXCLUSIVE_WITH_ERRONEOUS_OWNER, null); + + assertQueueHasOwner(NON_EXCLUSIVE_WITH_ERRONEOUS_OWNER, "misused-owner-as-description"); + assertContent(); } @@ -94,7 +102,7 @@ public class UpgradeFrom4to5Test extends AbstractUpgradeTestCase { UpgradeFrom4To5 upgrade = new UpgradeFrom4To5(); upgrade.performUpgrade(_environment, new StaticAnswerHandler(UpgradeInteractionResponse.NO), getVirtualHostName()); - assertQueues(new HashSet<String>(Arrays.asList(DURABLE_SUBSCRIPTION_QUEUE, DURABLE_SUBSCRIPTION_QUEUE_WITH_SELECTOR, DURABLE_QUEUE))); + assertQueues(new HashSet<String>(Arrays.asList(DURABLE_SUBSCRIPTION_QUEUE, DURABLE_SUBSCRIPTION_QUEUE_WITH_SELECTOR, DURABLE_QUEUE, NON_EXCLUSIVE_WITH_ERRONEOUS_OWNER))); assertDatabaseRecordCount(DELIVERY_DB_NAME, 12); assertDatabaseRecordCount(MESSAGE_META_DATA_DB_NAME, 12); @@ -112,6 +120,9 @@ public class UpgradeFrom4to5Test extends AbstractUpgradeTestCase assertBindingRecord(queueBindings, DURABLE_SUBSCRIPTION_QUEUE_WITH_SELECTOR, "amq.topic", BDBStoreUpgradeTestPreparer.SELECTOR_TOPIC_NAME, "testprop='true'"); assertBindingRecord(queueBindings, DURABLE_QUEUE, "amq.direct", DURABLE_QUEUE, null); + + assertQueueHasOwner(NON_EXCLUSIVE_WITH_ERRONEOUS_OWNER, "misused-owner-as-description"); + assertContent(); } @@ -257,7 +268,7 @@ public class UpgradeFrom4to5Test extends AbstractUpgradeTestCase private void assertQueues(Set<String> expectedQueueNames) { - List<AMQShortString> durableSubNames = new ArrayList<AMQShortString>(); + List<AMQShortString> durableSubNames = Collections.emptyList(); final UpgradeFrom4To5.QueueRecordBinding binding = new UpgradeFrom4To5.QueueRecordBinding(durableSubNames); final Set<String> actualQueueNames = new HashSet<String>(); @@ -278,6 +289,35 @@ public class UpgradeFrom4to5Test extends AbstractUpgradeTestCase assertEquals("Unexpected queue names", expectedQueueNames, actualQueueNames); } + private void assertQueueHasOwner(String queueName, final String expectedOwner) + { + List<AMQShortString> durableSubNames = Collections.emptyList(); + final UpgradeFrom4To5.QueueRecordBinding binding = new UpgradeFrom4To5.QueueRecordBinding(durableSubNames); + final AtomicReference<String> actualOwner = new AtomicReference<String>(); + final AtomicBoolean foundQueue = new AtomicBoolean(false); + + CursorOperation queueNameCollector = new CursorOperation() + { + + @Override + public void processEntry(Database sourceDatabase, Database targetDatabase, Transaction transaction, + DatabaseEntry key, DatabaseEntry value) + { + QueueRecord record = binding.entryToObject(value); + String queueName = record.getNameShortString().asString(); + if (queueName.equals(queueName)) + { + foundQueue.set(true); + actualOwner.set(AMQShortString.toString(record.getOwner())); + } + } + }; + new DatabaseTemplate(_environment, "queueDb_v5", null).run(queueNameCollector); + + assertTrue("Could not find queue in database", foundQueue.get()); + assertEquals("Queue has unexpected owner", expectedOwner, actualOwner.get()); + } + private void assertContent() { final UpgradeFrom4To5.ContentBinding contentBinding = new UpgradeFrom4To5.ContentBinding(); diff --git a/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/upgrade/UpgradeFrom5To6Test.java b/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/upgrade/UpgradeFrom5To6Test.java index 5297692820..0031447140 100644 --- a/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/upgrade/UpgradeFrom5To6Test.java +++ b/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/upgrade/UpgradeFrom5To6Test.java @@ -29,6 +29,7 @@ import static org.apache.qpid.server.store.berkeleydb.upgrade.UpgradeFrom5To6.OL import static org.apache.qpid.server.store.berkeleydb.upgrade.UpgradeFrom5To6.OLD_XID_DB_NAME; import java.io.File; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -41,6 +42,7 @@ import org.apache.qpid.server.model.Binding; import org.apache.qpid.server.model.Exchange; import org.apache.qpid.server.model.Queue; import org.apache.qpid.server.model.UUIDGenerator; +import org.apache.qpid.server.queue.AMQQueueFactory; import org.apache.qpid.server.store.berkeleydb.entry.Xid; import org.apache.qpid.server.store.berkeleydb.tuple.XidBinding; import org.apache.qpid.server.store.berkeleydb.upgrade.UpgradeFrom5To6.CompoundKey; @@ -260,7 +262,7 @@ public class UpgradeFrom5To6Test extends AbstractUpgradeTestCase private void assertDatabaseRecordCounts() { - assertDatabaseRecordCount(CONFIGURED_OBJECTS_DB_NAME, 9); + assertDatabaseRecordCount(CONFIGURED_OBJECTS_DB_NAME, 12); assertDatabaseRecordCount(NEW_DELIVERY_DB_NAME, 12); assertDatabaseRecordCount(NEW_METADATA_DB_NAME, 12); @@ -270,64 +272,25 @@ public class UpgradeFrom5To6Test extends AbstractUpgradeTestCase private void assertConfiguredObjects() { Map<UUID, UpgradeConfiguredObjectRecord> configuredObjects = loadConfiguredObjects(); - assertEquals("Unexpected number of configured objects", 9, configuredObjects.size()); - - Set<Map<String, Object>> expected = new HashSet<Map<String, Object>>(9); - Map<String, Object> queue1 = new HashMap<String, Object>(); - queue1.put("exclusive", Boolean.FALSE); - queue1.put("name", "myUpgradeQueue"); - queue1.put("owner", null); - expected.add(queue1); - Map<String, Object> queue2 = new HashMap<String, Object>(); - queue2.put("exclusive", Boolean.TRUE); - queue2.put("name", "clientid:mySelectorDurSubName"); - queue2.put("owner", "clientid"); - expected.add(queue2); - Map<String, Object> queue3 = new HashMap<String, Object>(); - queue3.put("exclusive", Boolean.TRUE); - queue3.put("name", "clientid:myDurSubName"); - queue3.put("owner", "clientid"); - expected.add(queue3); - - Map<String, Object> queueBinding1 = new HashMap<String, Object>(); - queueBinding1.put("queue", UUIDGenerator.generateUUID("myUpgradeQueue", getVirtualHostName()).toString()); - queueBinding1.put("name", "myUpgradeQueue"); - queueBinding1.put("exchange", UUIDGenerator.generateUUID("<<default>>", getVirtualHostName()).toString()); - expected.add(queueBinding1); - Map<String, Object> queueBinding2 = new HashMap<String, Object>(); - queueBinding2.put("queue", UUIDGenerator.generateUUID("myUpgradeQueue", getVirtualHostName()).toString()); - queueBinding2.put("name", "myUpgradeQueue"); - queueBinding2.put("exchange", UUIDGenerator.generateUUID("amq.direct", getVirtualHostName()).toString()); - Map<String, Object> arguments2 = new HashMap<String, Object>(); - arguments2.put("x-filter-jms-selector", ""); - queueBinding2.put("arguments", arguments2); - expected.add(queueBinding2); - Map<String, Object> queueBinding3 = new HashMap<String, Object>(); - queueBinding3.put("queue", UUIDGenerator.generateUUID("clientid:myDurSubName", getVirtualHostName()).toString()); - queueBinding3.put("name", "myUpgradeTopic"); - queueBinding3.put("exchange", UUIDGenerator.generateUUID("amq.topic", getVirtualHostName()).toString()); - Map<String, Object> arguments3 = new HashMap<String, Object>(); - arguments3.put("x-filter-jms-selector", ""); - queueBinding3.put("arguments", arguments3); - expected.add(queueBinding3); - Map<String, Object> queueBinding4 = new HashMap<String, Object>(); - queueBinding4.put("queue", UUIDGenerator.generateUUID("clientid:mySelectorDurSubName", getVirtualHostName()).toString()); - queueBinding4.put("name", "mySelectorUpgradeTopic"); - queueBinding4.put("exchange", UUIDGenerator.generateUUID("amq.topic", getVirtualHostName()).toString()); - Map<String, Object> arguments4 = new HashMap<String, Object>(); - arguments4.put("x-filter-jms-selector", "testprop='true'"); - queueBinding4.put("arguments", arguments4); - expected.add(queueBinding4); - Map<String, Object> queueBinding5 = new HashMap<String, Object>(); - queueBinding5.put("queue", UUIDGenerator.generateUUID("clientid:myDurSubName", getVirtualHostName()).toString()); - queueBinding5.put("name", "clientid:myDurSubName"); - queueBinding5.put("exchange", UUIDGenerator.generateUUID("<<default>>", getVirtualHostName()).toString()); - expected.add(queueBinding5); - Map<String, Object> queueBinding6 = new HashMap<String, Object>(); - queueBinding6.put("queue", UUIDGenerator.generateUUID("clientid:mySelectorDurSubName", getVirtualHostName()).toString()); - queueBinding6.put("name", "clientid:mySelectorDurSubName"); - queueBinding6.put("exchange", UUIDGenerator.generateUUID("<<default>>", getVirtualHostName()).toString()); - expected.add(queueBinding6); + assertEquals("Unexpected number of configured objects", 12, configuredObjects.size()); + + Set<Map<String, Object>> expected = new HashSet<Map<String, Object>>(12); + expected.add(createExpectedQueueMap("myUpgradeQueue", Boolean.FALSE, null, null)); + expected.add(createExpectedQueueMap("clientid:mySelectorDurSubName", Boolean.TRUE, "clientid", null)); + expected.add(createExpectedQueueMap("clientid:myDurSubName", Boolean.TRUE, "clientid", null)); + expected.add(createExpectedQueueMap("nonexclusive-with-erroneous-owner", Boolean.FALSE, null, + Collections.singletonMap(AMQQueueFactory.X_QPID_DESCRIPTION, "misused-owner-as-description"))); + + expected.add(createExpectedQueueBindingMap("myUpgradeQueue","myUpgradeQueue", "<<default>>", null)); + expected.add(createExpectedQueueBindingMap("myUpgradeQueue", "myUpgradeQueue", "amq.direct", null)); + expected.add(createExpectedQueueBindingMap("clientid:myDurSubName", "myUpgradeTopic", "amq.topic", + Collections.singletonMap("x-filter-jms-selector", ""))); + expected.add(createExpectedQueueBindingMap("clientid:mySelectorDurSubName", "mySelectorUpgradeTopic", "amq.topic", + Collections.singletonMap("x-filter-jms-selector", "testprop='true'"))); + expected.add(createExpectedQueueBindingMap("clientid:myDurSubName", "clientid:myDurSubName", "<<default>>", null)); + expected.add(createExpectedQueueBindingMap("clientid:mySelectorDurSubName", "clientid:mySelectorDurSubName", "<<default>>", null)); + expected.add(createExpectedQueueBindingMap("nonexclusive-with-erroneous-owner", "nonexclusive-with-erroneous-owner", "amq.direct", null)); + expected.add(createExpectedQueueBindingMap("nonexclusive-with-erroneous-owner","nonexclusive-with-erroneous-owner", "<<default>>", null)); Set<String> expectedTypes = new HashSet<String>(); expectedTypes.add(Queue.class.getName()); @@ -337,11 +300,11 @@ public class UpgradeFrom5To6Test extends AbstractUpgradeTestCase for (Entry<UUID, UpgradeConfiguredObjectRecord> entry : configuredObjects.entrySet()) { UpgradeConfiguredObjectRecord object = entry.getValue(); - UUID key = entry.getKey(); Map<String, Object> deserialized = jsonSerializer.deserialize(object.getAttributes()); assertTrue("Unexpected entry:" + object.getAttributes(), expected.remove(deserialized)); String type = object.getType(); assertTrue("Unexpected type:" + type, expectedTypes.contains(type)); + UUID key = entry.getKey(); if (type.equals(Exchange.class.getName()) || type.equals(Queue.class.getName())) { assertEquals("Unexpected key", key, UUIDGenerator.generateUUID(((String) deserialized.get("name")), getVirtualHostName())); @@ -354,6 +317,32 @@ public class UpgradeFrom5To6Test extends AbstractUpgradeTestCase assertTrue("Not all expected configured objects found:" + expected, expected.isEmpty()); } + private Map<String, Object> createExpectedQueueBindingMap(String queue, String bindingName, String exchangeName, Map<String, String> argumentMap) + { + Map<String, Object> expectedQueueBinding = new HashMap<String, Object>(); + expectedQueueBinding.put(Binding.QUEUE, UUIDGenerator.generateUUID(queue, getVirtualHostName()).toString()); + expectedQueueBinding.put(Binding.NAME, bindingName); + expectedQueueBinding.put(Binding.EXCHANGE, UUIDGenerator.generateUUID(exchangeName, getVirtualHostName()).toString()); + if (argumentMap != null) + { + expectedQueueBinding.put(Binding.ARGUMENTS, argumentMap); + } + return expectedQueueBinding; + } + + private Map<String, Object> createExpectedQueueMap(String name, boolean exclusiveFlag, String owner, Map<String, String> argumentMap) + { + Map<String, Object> expectedQueueEntry = new HashMap<String, Object>(); + expectedQueueEntry.put(Queue.NAME, name); + expectedQueueEntry.put(Queue.EXCLUSIVE, exclusiveFlag); + expectedQueueEntry.put(Queue.OWNER, owner); + if (argumentMap != null) + { + expectedQueueEntry.put(Queue.ARGUMENTS, argumentMap); + } + return expectedQueueEntry; + } + private Map<UUID, UpgradeConfiguredObjectRecord> loadConfiguredObjects() { final Map<UUID, UpgradeConfiguredObjectRecord> configuredObjectsRecords = new HashMap<UUID, UpgradeConfiguredObjectRecord>(); diff --git a/qpid/java/bdbstore/src/test/resources/upgrade/bdbstore-v4/test-store/00000000.jdb b/qpid/java/bdbstore/src/test/resources/upgrade/bdbstore-v4/test-store/00000000.jdb Binary files differindex 167ab7f0ca..f5ed9aa5a2 100644 --- a/qpid/java/bdbstore/src/test/resources/upgrade/bdbstore-v4/test-store/00000000.jdb +++ b/qpid/java/bdbstore/src/test/resources/upgrade/bdbstore-v4/test-store/00000000.jdb diff --git a/qpid/java/bdbstore/src/test/resources/upgrade/bdbstore-v5/test-store/00000000.jdb b/qpid/java/bdbstore/src/test/resources/upgrade/bdbstore-v5/test-store/00000000.jdb Binary files differindex d44b21a83e..f5ed9aa5a2 100644 --- a/qpid/java/bdbstore/src/test/resources/upgrade/bdbstore-v5/test-store/00000000.jdb +++ b/qpid/java/bdbstore/src/test/resources/upgrade/bdbstore-v5/test-store/00000000.jdb diff --git a/qpid/java/bdbstore/src/test/resources/upgrade/bdbstore-v5/test-store/00000001.jdb b/qpid/java/bdbstore/src/test/resources/upgrade/bdbstore-v5/test-store/00000001.jdb Binary files differindex 9b85860c19..d5ae8c1096 100644 --- a/qpid/java/bdbstore/src/test/resources/upgrade/bdbstore-v5/test-store/00000001.jdb +++ b/qpid/java/bdbstore/src/test/resources/upgrade/bdbstore-v5/test-store/00000001.jdb diff --git a/qpid/java/broker-plugins/access-control/MANIFEST.MF b/qpid/java/broker-plugins/access-control/MANIFEST.MF index 78072850e4..a8fb99995e 100644 --- a/qpid/java/broker-plugins/access-control/MANIFEST.MF +++ b/qpid/java/broker-plugins/access-control/MANIFEST.MF @@ -13,12 +13,10 @@ Bundle-ActivationPolicy: lazy Import-Package: org.apache.qpid, org.apache.qpid.exchange, org.apache.qpid.framing, - org.apache.qpid.junit.extensions.util, org.apache.qpid.protocol, org.apache.qpid.server.configuration, org.apache.qpid.server.configuration.plugins, org.apache.qpid.server.exchange, - org.apache.qpid.server.management, org.apache.qpid.server.logging, org.apache.qpid.server.logging.actors, org.apache.qpid.server.logging.subjects, diff --git a/qpid/java/broker-plugins/experimental/shutdown/MANIFEST.MF b/qpid/java/broker-plugins/experimental/shutdown/MANIFEST.MF deleted file mode 100644 index 0bd0a835e4..0000000000 --- a/qpid/java/broker-plugins/experimental/shutdown/MANIFEST.MF +++ /dev/null @@ -1,16 +0,0 @@ -Manifest-Version: 1.0 -Bundle-ManifestVersion: 2 -Bundle-Name: Experimental Shutdown -Bundle-Description: Experimental Qpid Broker Shutdown Plugin -Bundle-License: http://www.apache.org/licenses/LICENSE-2.0.txt -Bundle-DocURL: http://qpid.apache.org/ -Bundle-SymbolicName: broker-plugins-experimental-shutdown;singleton:=true -Bundle-Version: 1.0.0 -Bundle-Activator: org.apache.qpid.shutdown.Activator -Import-Package: javax.management;resolution:=optional, - org.apache.log4j, - org.osgi.framework, - org.apache.qpid.server.management -Bundle-RequiredExecutionEnvironment: J2SE-1.5 -Bundle-ActivationPolicy: lazy - diff --git a/qpid/java/broker-plugins/experimental/shutdown/src/main/java/org/apache/qpid/shutdown/Activator.java b/qpid/java/broker-plugins/experimental/shutdown/src/main/java/org/apache/qpid/shutdown/Activator.java deleted file mode 100644 index 2b7fa33784..0000000000 --- a/qpid/java/broker-plugins/experimental/shutdown/src/main/java/org/apache/qpid/shutdown/Activator.java +++ /dev/null @@ -1,57 +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.shutdown; - - -import org.apache.log4j.Logger; -import org.osgi.framework.BundleActivator; -import org.osgi.framework.BundleContext; - -public class Activator implements BundleActivator -{ - private static final Logger _logger = Logger.getLogger(Activator.class); - - private Shutdown _shutdown = null; - - /** @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext) */ - public void start(BundleContext ctx) throws Exception { - _shutdown = new Shutdown(); - if (ctx != null) - { - ctx.registerService(ShutdownMBean.class.getName(), _shutdown, null); - } - - _shutdown.register(); - - _logger.info("Shutdown plugin MBean registered"); - } - - /** @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext) */ - public void stop(BundleContext ctx) throws Exception - { - if (_shutdown != null) - { - _shutdown.unregister(); - _shutdown = null; - } - - _logger.info("Shutdown plugin MBean unregistered"); - } -} diff --git a/qpid/java/broker-plugins/experimental/shutdown/src/main/java/shutdown.bnd b/qpid/java/broker-plugins/experimental/shutdown/src/main/java/shutdown.bnd deleted file mode 100755 index 60af4b89e8..0000000000 --- a/qpid/java/broker-plugins/experimental/shutdown/src/main/java/shutdown.bnd +++ /dev/null @@ -1,25 +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. -# - -ver: 0.17.0 - -Bundle-SymbolicName: qpid-shutdown-plugin -Bundle-Version: ${ver} -Export-Package: *;version=${ver} -Bundle-RequiredExecutionEnvironment: J2SE-1.5 diff --git a/qpid/java/broker-plugins/firewall/MANIFEST.MF b/qpid/java/broker-plugins/firewall/MANIFEST.MF index 6ceea119da..a302921d03 100644 --- a/qpid/java/broker-plugins/firewall/MANIFEST.MF +++ b/qpid/java/broker-plugins/firewall/MANIFEST.MF @@ -12,12 +12,10 @@ Bundle-ClassPath: . Bundle-ActivationPolicy: lazy Import-Package: org.apache.qpid, org.apache.qpid.framing, - org.apache.qpid.junit.extensions.util, org.apache.qpid.protocol, org.apache.qpid.server.configuration, org.apache.qpid.server.configuration.plugins, org.apache.qpid.server.exchange, - org.apache.qpid.server.management, org.apache.qpid.server.plugins, org.apache.qpid.server.queue, org.apache.qpid.server.security, diff --git a/qpid/java/broker-plugins/jmx/MANIFEST.MF b/qpid/java/broker-plugins/jmx/MANIFEST.MF new file mode 100644 index 0000000000..b13ff7f132 --- /dev/null +++ b/qpid/java/broker-plugins/jmx/MANIFEST.MF @@ -0,0 +1,65 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Qpid Broker-Plugins JMX +Bundle-SymbolicName: broker-plugins-jmx +Bundle-Description: Management plugin for Qpid. +Bundle-License: http://www.apache.org/licenses/LICENSE-2.0.txt +Bundle-DocURL: http://www.apache.org/ +Bundle-Version: 1.0.0 +Bundle-Activator: org.apache.qpid.server.jmx.JMXActivator +Bundle-RequiredExecutionEnvironment: JavaSE-1.6 +Bundle-ClassPath: . +Bundle-ActivationPolicy: lazy +Import-Package: org.apache.qpid, + org.apache.qpid.framing, + org.apache.qpid.protocol, + org.apache.qpid.common, + org.apache.qpid.management.common.mbeans, + org.apache.qpid.management.common.mbeans.annotations, + org.apache.qpid.server.security.auth, + org.apache.qpid.server.security.auth.manager, + org.apache.qpid.server.security.auth.rmi, + org.apache.qpid.server.security.auth.sasl, + org.apache.qpid.server.binding, + org.apache.qpid.server.exchange, + org.apache.qpid.server.logging, + org.apache.qpid.server.logging.actors, + org.apache.qpid.server.logging.messages, + org.apache.qpid.server.message, + org.apache.qpid.server.model, + org.apache.qpid.server.model.adapter, + org.apache.qpid.server.model.impl, + org.apache.qpid.server.configuration, + org.apache.qpid.server.configuration.plugins, + org.apache.qpid.server.connection, + org.apache.qpid.server.plugins, + org.apache.qpid.server.protocol, + org.apache.qpid.server.queue, + org.apache.qpid.server.registry, + org.apache.qpid.server.security, + org.apache.qpid.server.security.access, + org.apache.qpid.server.stats, + org.apache.qpid.server.virtualhost, + org.apache.qpid.util, + org.apache.commons.codec;version=1.3.0, + org.apache.commons.codec.binary;version=1.3.0, + org.apache.commons.configuration;version=1.0.0, + org.apache.commons.lang;version=1.0.0, + org.apache.commons.lang.builder;version=1.0.0, + org.apache.commons.lang.time;version=1.0.0, + org.apache.log4j;version=1.2.16, + org.codehaus.jackson;version=1.9.0, + org.codehaus.jackson.map;version=1.9.0, + javax.management.remote.rmi, + javax.management.remote, + javax.servlet, + javax.servlet.http, + javax.management;version=1.0.0, + javax.management.monitor;version=1.0.0, + javax.management.openmbean;version=1.0.0, + javax.security.auth.login;version=1.0.0, + javax.security.auth;version=1.0.0, + javax.rmi.ssl;version=1.0.0, + org.osgi.util.tracker;version=1.0.0, + org.osgi.framework;version=1.3 +Export-Package: org.apache.qpid.server.jmx;uses:="org.osgi.framework" diff --git a/qpid/java/broker-plugins/jmx/build.xml b/qpid/java/broker-plugins/jmx/build.xml new file mode 100644 index 0000000000..4deb0196e7 --- /dev/null +++ b/qpid/java/broker-plugins/jmx/build.xml @@ -0,0 +1,43 @@ +<!-- + - 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. + --> +<project name="Qpid Broker-Plugins JMX" default="build"> + + <condition property="systests.optional.depends" value="bdbstore" else=""> + <or> + <and> + <contains string="${modules.opt}" substring="bdbstore"/> + <contains string="${profile}" substring="bdb"/> + </and> + <and> + <istrue value="${optional}"/> + <contains string="${profile}" substring="bdb"/> + </and> + </or> + </condition> + + <property name="module.depends" value="common broker broker-plugins broker-plugins-jmx management/common" /> + <property name="module.test.depends" value="systests test broker/test common/test management/common client ${systests.optional.depends}" /> + + <property name="module.manifest" value="MANIFEST.MF" /> + <property name="module.plugin" value="true" /> + + <import file="../../module.xml" /> + + <target name="bundle" depends="bundle-tasks" /> +</project> diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/AMQManagedObject.java b/qpid/java/broker-plugins/jmx/src/main/java/org/apache/qpid/server/jmx/AMQManagedObject.java index 5c57c01f6e..5c39a0c26a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/AMQManagedObject.java +++ b/qpid/java/broker-plugins/jmx/src/main/java/org/apache/qpid/server/jmx/AMQManagedObject.java @@ -18,11 +18,9 @@ * under the License. * */ -package org.apache.qpid.server.management; +package org.apache.qpid.server.jmx; -import org.apache.qpid.server.logging.LogActor; -import org.apache.qpid.server.logging.actors.CurrentActor; -import org.apache.qpid.server.logging.actors.ManagementActor; +import java.util.concurrent.atomic.AtomicLong; import javax.management.ListenerNotFoundException; import javax.management.NotCompliantMBeanException; @@ -32,7 +30,7 @@ import javax.management.NotificationFilter; import javax.management.NotificationListener; /** - * This class provides additinal feature of Notification Broadcaster to the + * This class provides additional feature of Notification Broadcaster to the * DefaultManagedObject. * @author Bhupendra Bhardwaj * @version 0.1 @@ -40,19 +38,17 @@ import javax.management.NotificationListener; public abstract class AMQManagedObject extends DefaultManagedObject implements NotificationBroadcaster { - private NotificationBroadcasterSupport _broadcaster = new NotificationBroadcasterSupport(); + private final NotificationBroadcasterSupport _broadcaster = new NotificationBroadcasterSupport(); - private long _notificationSequenceNumber = 0; + private AtomicLong _notificationSequenceNumber = new AtomicLong(); - private LogActor _logActor; - - protected AMQManagedObject(Class<?> managementInterface, String typeName) + protected AMQManagedObject(Class<?> managementInterface, String typeName, ManagedObjectRegistry registry) throws NotCompliantMBeanException { - super(managementInterface, typeName); + super(managementInterface, typeName, registry); // CurrentActor will be defined as these objects are created during // broker startup. - _logActor = new ManagementActor(CurrentActor.get().getRootMessageLogger()); + } // notification broadcaster implementation @@ -79,27 +75,10 @@ public abstract class AMQManagedObject extends DefaultManagedObject return _broadcaster; } - /** - * sequence number for notifications - */ - protected long getNotificationSequenceNumber() - { - return _notificationSequenceNumber; - } - - protected void setNotificationSequenceNumber(long notificationSequenceNumber) - { - _notificationSequenceNumber = notificationSequenceNumber; - } - protected long incrementAndGetSequenceNumber() { - return ++_notificationSequenceNumber; + return _notificationSequenceNumber.incrementAndGet(); } - protected LogActor getLogActor() - { - return _logActor; - } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java b/qpid/java/broker-plugins/jmx/src/main/java/org/apache/qpid/server/jmx/DefaultManagedObject.java index 10d7503800..4446f96802 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/DefaultManagedObject.java +++ b/qpid/java/broker-plugins/jmx/src/main/java/org/apache/qpid/server/jmx/DefaultManagedObject.java @@ -18,12 +18,10 @@ * under the License. * */ -package org.apache.qpid.server.management; +package org.apache.qpid.server.jmx; import org.apache.log4j.Logger; -import org.apache.qpid.server.registry.ApplicationRegistry; - import javax.management.JMException; import javax.management.MBeanInfo; import javax.management.MBeanNotificationInfo; @@ -49,15 +47,21 @@ public abstract class DefaultManagedObject extends StandardMBean implements Mana private ManagedObjectRegistry _registry; - protected DefaultManagedObject(Class<?> managementInterface, String typeName) + protected DefaultManagedObject(Class<?> managementInterface, String typeName, ManagedObjectRegistry registry) throws NotCompliantMBeanException { super(managementInterface); + _registry = registry; _managementInterface = managementInterface; _typeName = typeName; _mbeanInfo = buildMBeanInfo(); } + public ManagedObjectRegistry getRegistry() + { + return _registry; + } + @Override public MBeanInfo getMBeanInfo() { @@ -74,18 +78,15 @@ public abstract class DefaultManagedObject extends StandardMBean implements Mana return _managementInterface; } - public ManagedObject getParentObject() - { - return null; - } + public abstract ManagedObject getParentObject(); + public void register() throws JMException { - _registry = ApplicationRegistry.getInstance().getManagedObjectRegistry(); _registry.registerObject(this); } - public void unregister() + public void unregister() throws JMException { try { @@ -94,10 +95,6 @@ public abstract class DefaultManagedObject extends StandardMBean implements Mana _registry.unregisterObject(this); } } - catch (JMException e) - { - LOGGER.error("Error unregistering managed object: " + this + ": " + e, e); - } finally { _registry = null; @@ -112,7 +109,7 @@ public abstract class DefaultManagedObject extends StandardMBean implements Mana /** * Created the ObjectName as per the JMX Specs * @return ObjectName - * @throws MalformedObjectNameException + * @throws javax.management.MalformedObjectNameException */ public ObjectName getObjectName() throws MalformedObjectNameException { diff --git a/qpid/java/broker-plugins/jmx/src/main/java/org/apache/qpid/server/jmx/JMXActivator.java b/qpid/java/broker-plugins/jmx/src/main/java/org/apache/qpid/server/jmx/JMXActivator.java new file mode 100644 index 0000000000..c588b40de7 --- /dev/null +++ b/qpid/java/broker-plugins/jmx/src/main/java/org/apache/qpid/server/jmx/JMXActivator.java @@ -0,0 +1,136 @@ +/* + * + * 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.jmx; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.apache.log4j.Logger; +import org.apache.qpid.server.configuration.plugins.ConfigurationPluginFactory; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceRegistration; + +public class JMXActivator implements BundleActivator +{ + private static final Logger LOGGER = Logger.getLogger(JMXActivator.class); + + private String _bundleName; + private JMXService _jmxService; + + private List<ServiceRegistration> _registeredServices; + + + public void start(final BundleContext ctx) throws Exception + { + boolean jmxManagementEnabled = ApplicationRegistry.getInstance().getConfiguration().getJMXManagementEnabled(); + + if (jmxManagementEnabled) + { + _jmxService = new JMXService(); + startJmsService(_jmxService); + + _bundleName = ctx.getBundle().getSymbolicName(); + + _registeredServices = registerServices(ctx); + } + else + { + LOGGER.debug("Skipping registration of JMX plugin as JMX Management disabled in config. "); + } + } + + public void stop(final BundleContext bundleContext) throws Exception + { + try + { + if (_jmxService != null) + { + if (LOGGER.isInfoEnabled()) + { + LOGGER.info("Stopping jmx plugin: " + _bundleName); + } + _jmxService.close(); + } + + if (_registeredServices != null) + { + unregisterServices(); + } + } + finally + { + _jmxService = null; + _registeredServices = null; + } + } + + + private List<ServiceRegistration> registerServices(BundleContext ctx) + { + if (LOGGER.isInfoEnabled()) + { + LOGGER.info("Registering jmx plugin: " + _bundleName); + } + + List<ServiceRegistration> serviceRegistrations = new ArrayList<ServiceRegistration>(); + + ServiceRegistration jmxServiceRegistration = ctx.registerService(JMXService.class.getName(), _jmxService, null); + ServiceRegistration jmxConfigFactoryRegistration = ctx.registerService(ConfigurationPluginFactory.class.getName(), JMXConfiguration.FACTORY, null); + + serviceRegistrations.add(jmxServiceRegistration); + serviceRegistrations.add(jmxConfigFactoryRegistration); + return serviceRegistrations; + } + + private void startJmsService(JMXService jmxService) throws Exception + { + if (LOGGER.isInfoEnabled()) + { + LOGGER.info("Starting JMX service"); + } + boolean startedSuccessfully = false; + try + { + jmxService.start(); + startedSuccessfully = true; + } + finally + { + if (!startedSuccessfully) + { + LOGGER.error("JMX failed to start normally, closing service"); + jmxService.close(); + } + } + } + + private void unregisterServices() + { + for (Iterator<ServiceRegistration> iterator = _registeredServices.iterator(); iterator.hasNext();) + { + ServiceRegistration service = iterator.next(); + service.unregister(); + } + } +} diff --git a/qpid/java/broker-plugins/jmx/src/main/java/org/apache/qpid/server/jmx/JMXConfiguration.java b/qpid/java/broker-plugins/jmx/src/main/java/org/apache/qpid/server/jmx/JMXConfiguration.java new file mode 100644 index 0000000000..dc9a712f90 --- /dev/null +++ b/qpid/java/broker-plugins/jmx/src/main/java/org/apache/qpid/server/jmx/JMXConfiguration.java @@ -0,0 +1,76 @@ +/* + * + * 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.jmx; + +import org.apache.commons.configuration.CompositeConfiguration; +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.commons.configuration.XMLConfiguration; +import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; +import org.apache.qpid.server.configuration.plugins.ConfigurationPluginFactory; + +import java.util.Arrays; +import java.util.List; + +public class JMXConfiguration extends ConfigurationPlugin +{ + CompositeConfiguration _finalConfig; + + public static final ConfigurationPluginFactory FACTORY = new ConfigurationPluginFactory() + { + public ConfigurationPlugin newInstance(String path, Configuration config) throws ConfigurationException + { + ConfigurationPlugin instance = new JMXConfiguration(); + instance.setConfiguration(path, config); + return instance; + } + + public List<String> getParentPaths() + { + return Arrays.asList("jmx"); + } + }; + + public String[] getElementsProcessed() + { + return new String[] { "" }; + } + + public Configuration getConfiguration() + { + return _finalConfig; + } + + + @Override + public void validateConfiguration() throws ConfigurationException + { + // Valid Configuration either has xml links to new files + _finalConfig = new CompositeConfiguration(getConfig()); + List subFiles = getConfig().getList("xml[@fileName]"); + for (Object subFile : subFiles) + { + _finalConfig.addConfiguration(new XMLConfiguration((String) subFile)); + } + + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java b/qpid/java/broker-plugins/jmx/src/main/java/org/apache/qpid/server/jmx/JMXManagedObjectRegistry.java index 869a816cf1..0648235077 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java +++ b/qpid/java/broker-plugins/jmx/src/main/java/org/apache/qpid/server/jmx/JMXManagedObjectRegistry.java @@ -18,8 +18,38 @@ * under the License. * */ -package org.apache.qpid.server.management; +package org.apache.qpid.server.jmx; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.logging.messages.ManagementConsoleMessages; + +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.registry.IApplicationRegistry; + +import org.apache.qpid.server.security.auth.rmi.RMIPasswordAuthenticator; +import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; + +import javax.management.JMException; +import javax.management.MBeanServer; +import javax.management.MBeanServerFactory; +import javax.management.Notification; +import javax.management.NotificationFilterSupport; +import javax.management.NotificationListener; +import javax.management.ObjectName; +import javax.management.remote.JMXConnectionNotification; +import javax.management.remote.JMXConnectorServer; +import javax.management.remote.JMXServiceURL; +import javax.management.remote.MBeanServerForwarder; +import javax.management.remote.rmi.RMIConnection; +import javax.management.remote.rmi.RMIConnectorServer; +import javax.management.remote.rmi.RMIJRMPServerImpl; +import javax.management.remote.rmi.RMIServerImpl; +import javax.rmi.ssl.SslRMIClientSocketFactory; +import javax.rmi.ssl.SslRMIServerSocketFactory; +import javax.security.auth.Subject; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; @@ -38,39 +68,12 @@ import java.rmi.registry.Registry; import java.rmi.server.RMIClientSocketFactory; import java.rmi.server.RMIServerSocketFactory; import java.rmi.server.UnicastRemoteObject; -import java.security.Principal; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -import javax.management.JMException; -import javax.management.MBeanServer; -import javax.management.MBeanServerFactory; -import javax.management.Notification; -import javax.management.NotificationFilterSupport; -import javax.management.NotificationListener; -import javax.management.ObjectName; -import javax.management.remote.JMXConnectionNotification; -import javax.management.remote.JMXConnectorServer; -import javax.management.remote.JMXServiceURL; -import javax.management.remote.MBeanServerForwarder; -import javax.management.remote.rmi.RMIConnection; -import javax.management.remote.rmi.RMIConnectorServer; -import javax.management.remote.rmi.RMIJRMPServerImpl; -import javax.management.remote.rmi.RMIServerImpl; -import javax.rmi.ssl.SslRMIClientSocketFactory; -import javax.rmi.ssl.SslRMIServerSocketFactory; -import javax.security.auth.Subject; -import org.apache.commons.configuration.ConfigurationException; -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.server.logging.actors.CurrentActor; -import org.apache.qpid.server.logging.messages.ManagementConsoleMessages; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.registry.IApplicationRegistry; -import org.apache.qpid.server.security.auth.rmi.RMIPasswordAuthenticator; /** - * This class starts up an MBeanserver. If out of the box agent has been enabled then there are no + * This class starts up an MBeanserver. If out of the box agent has been enabled then there are no * security features implemented like user authentication and authorisation. */ public class JMXManagedObjectRegistry implements ManagedObjectRegistry @@ -195,8 +198,7 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry } //add a JMXAuthenticator implementation the env map to authenticate the RMI based JMX connector server - RMIPasswordAuthenticator rmipa = new RMIPasswordAuthenticator(); - rmipa.setAuthenticationManager(appRegistry.getAuthenticationManager(new InetSocketAddress(_jmxPortRegistryServer))); + RMIPasswordAuthenticator rmipa = new RMIPasswordAuthenticator(new InetSocketAddress(_jmxPortRegistryServer)); HashMap<String,Object> env = new HashMap<String,Object>(); env.put(JMXConnectorServer.AUTHENTICATOR, rmipa); @@ -236,14 +238,14 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry * An instance of NotificationListener (mapCleanupListener) will be responsible for removing these Map * entries. * - * @see javax.management.remote.rmi.RMIJRMPServerImpl#makeClient(java.lang.String, javax.security.auth.Subject) + * @see javax.management.remote.rmi.RMIJRMPServerImpl#makeClient(String, javax.security.auth.Subject) */ @Override protected RMIConnection makeClient(String connectionId, Subject subject) throws IOException { final RMIConnection makeClient = super.makeClient(connectionId, subject); - final Principal principal = subject.getPrincipals().iterator().next(); - connectionIdUsernameMap.put(connectionId, principal.getName()); + final UsernamePrincipal usernamePrincipalFromSubject = UsernamePrincipal.getUsernamePrincipalFromSubject(subject); + connectionIdUsernameMap.put(connectionId, usernamePrincipalFromSubject.getName()); return makeClient; } }; @@ -252,7 +254,6 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry final NotificationListener mapCleanupListener = new NotificationListener() { - @Override public void handleNotification(Notification notification, Object handback) { final String connectionId = ((JMXConnectionNotification) notification).getConnectionId(); @@ -310,6 +311,8 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry } catch (NotBoundException nbe) { + // TODO consider if we want to keep new logging + _log.error("Failed to unbind jmxrmi", nbe); //ignore } @@ -433,6 +436,8 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry //Stops the JMXConnectorServer and RMIRegistry, then unregisters any remaining MBeans from the MBeanServer public void close() { + _log.debug("close() called"); + if (_cs != null) { // Stopping the JMX ConnectorServer @@ -443,24 +448,28 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry } catch (IOException e) { - _log.error("Exception while closing the JMX ConnectorServer: " + e.getMessage()); + _log.error("Exception while closing the JMX ConnectorServer: ", e); } } - + if (_rmiRegistry != null) { // Stopping the RMI registry CurrentActor.get().message(ManagementConsoleMessages.SHUTTING_DOWN("RMI Registry", _jmxPortRegistryServer)); try { - UnicastRemoteObject.unexportObject(_rmiRegistry, false); + boolean success = UnicastRemoteObject.unexportObject(_rmiRegistry, false); + if (!success) + { + _log.warn("Failed to unexport object " + _rmiRegistry); + } } catch (NoSuchObjectException e) { - _log.error("Exception while closing the RMI Registry: " + e.getMessage()); + _log.error("Exception while closing the RMI Registry: ", e); } } - + //ObjectName query to gather all Qpid related MBeans ObjectName mbeanNameQuery = null; try diff --git a/qpid/java/broker-plugins/jmx/src/main/java/org/apache/qpid/server/jmx/JMXService.java b/qpid/java/broker-plugins/jmx/src/main/java/org/apache/qpid/server/jmx/JMXService.java new file mode 100644 index 0000000000..7519cea4db --- /dev/null +++ b/qpid/java/broker-plugins/jmx/src/main/java/org/apache/qpid/server/jmx/JMXService.java @@ -0,0 +1,189 @@ +/* + * + * 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.jmx; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.ServiceLoader; + +import javax.management.JMException; +import javax.management.StandardMBean; + +import org.apache.commons.configuration.ConfigurationException; +import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.server.jmx.mbeans.UserManagementMBean; +import org.apache.qpid.server.jmx.mbeans.ConfigurationManagementMBean; +import org.apache.qpid.server.jmx.mbeans.ServerInformationMBean; +import org.apache.qpid.server.jmx.mbeans.Shutdown; +import org.apache.qpid.server.jmx.mbeans.VirtualHostMBean; +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.PasswordCredentialManagingAuthenticationProvider; +import org.apache.qpid.server.model.State; +import org.apache.qpid.server.model.VirtualHost; +import org.apache.qpid.server.registry.ApplicationRegistry; + + +public class JMXService implements ConfigurationChangeListener +{ + private static final ClassLoader BUNDLE_CLASSLOADER = JMXService.class.getClassLoader(); + + private static final Logger LOGGER = Logger.getLogger(JMXService.class); + + private final Broker _broker; + private final JMXManagedObjectRegistry _objectRegistry; + private final Shutdown _shutdown; + private final ServerInformationMBean _serverInfo; + private final ConfigurationManagementMBean _configManagement; + + private final Map<ConfiguredObject, AMQManagedObject> _children = new HashMap<ConfiguredObject, AMQManagedObject>(); + + public JMXService() throws AMQException, JMException + { + _broker = ApplicationRegistry.getInstance().getBroker(); + _objectRegistry = new JMXManagedObjectRegistry(); + + _broker.addChangeListener(this); + synchronized (_children) + { + for(VirtualHost virtualHost : _broker.getVirtualHosts()) + { + if(!_children.containsKey(virtualHost)) + { + _children.put(virtualHost, new VirtualHostMBean(virtualHost, _objectRegistry)); + } + } + } + _shutdown = new Shutdown(_objectRegistry); + _serverInfo = new ServerInformationMBean(_objectRegistry, _broker); + _configManagement = new ConfigurationManagementMBean(_objectRegistry); + } + + public void start() throws IOException, ConfigurationException + { + _objectRegistry.start(); + } + + public void close() + { + _broker.removeChangeListener(this); + + _objectRegistry.close(); + } + + public void stateChanged(ConfiguredObject object, State oldState, State newState) + { + + } + + public void childAdded(ConfiguredObject object, ConfiguredObject child) + { + synchronized (_children) + { + try + { + AMQManagedObject mbean; + if(child instanceof VirtualHost) + { + VirtualHost vhostChild = (VirtualHost)child; + mbean = new VirtualHostMBean(vhostChild, _objectRegistry); + } + else if(child instanceof PasswordCredentialManagingAuthenticationProvider) + { + mbean = new UserManagementMBean((PasswordCredentialManagingAuthenticationProvider) child, _objectRegistry); + } + else + { + mbean = null; + } + + if (mbean != null) + { + createAdditionalMBeansFromProviders(child, mbean); + } + } + catch(JMException e) + { + LOGGER.error("Error creating mbean", e); + // TODO - Implement error reporting on mbean creation + } + } + } + + + public void childRemoved(ConfiguredObject object, ConfiguredObject child) + { + // TODO - implement vhost removal (possibly just removing the instanceof check below) + + synchronized (_children) + { + if(child instanceof PasswordCredentialManagingAuthenticationProvider) + { + AMQManagedObject mbean = _children.remove(child); + if(mbean != null) + { + try + { + mbean.unregister(); + } + catch(JMException e) + { + LOGGER.error("Error creating mbean", e); + //TODO - report error on removing child MBean + } + } + } + + } + } + + private void createAdditionalMBeansFromProviders(ConfiguredObject child, AMQManagedObject mbean) throws JMException + { + _children.put(child, mbean); + + for (Iterator<MBeanProvider> iterator = getMBeanProviderIterator(); iterator.hasNext();) + { + MBeanProvider provider = iterator.next(); + LOGGER.debug("Consulting mbean provider : " + provider + " for child : " + child); + if (provider.isChildManageableByMBean(child)) + { + LOGGER.debug("Provider will create mbean "); + StandardMBean bean = provider.createMBean(child, mbean); + // TODO track the mbeans that have been created on behalf of a child in a map, then + // if the child is ever removed, destroy these beans too. + } + } + } + + /** + * Finds all classes implementing the {@link MBeanProvider} interface. This will find + * <b>only</b> those classes which are visible to the classloader of this OSGI bundle. + */ + private Iterator<MBeanProvider> getMBeanProviderIterator() + { + return ServiceLoader.load(MBeanProvider.class, BUNDLE_CLASSLOADER).iterator(); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanIntrospector.java b/qpid/java/broker-plugins/jmx/src/main/java/org/apache/qpid/server/jmx/MBeanIntrospector.java index 89b74f939d..79ddc8cfc0 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanIntrospector.java +++ b/qpid/java/broker-plugins/jmx/src/main/java/org/apache/qpid/server/jmx/MBeanIntrospector.java @@ -18,7 +18,7 @@ * under the License. * */ -package org.apache.qpid.server.management; +package org.apache.qpid.server.jmx; import org.apache.qpid.management.common.mbeans.annotations.MBeanAttribute; import org.apache.qpid.management.common.mbeans.annotations.MBeanConstructor; @@ -43,7 +43,8 @@ import java.util.List; * @author Bhupendra Bhardwaj * @version 0.1 */ -class MBeanIntrospector { +class MBeanIntrospector +{ private static final String _defaultAttributeDescription = "Management attribute"; private static final String _defaultOerationDescription = "Management operation"; @@ -58,7 +59,7 @@ class MBeanIntrospector { * Introspects the management interface class for MBean attributes. * @param interfaceClass * @return MBeanAttributeInfo[] - * @throws NotCompliantMBeanException + * @throws javax.management.NotCompliantMBeanException */ static MBeanAttributeInfo[] getMBeanAttributesInfo(Class interfaceClass) throws NotCompliantMBeanException @@ -221,7 +222,7 @@ class MBeanIntrospector { * @param attribute * @param list * @return attribute index no. -1 if attribtue doesn't exist - * @throws NotCompliantMBeanException + * @throws javax.management.NotCompliantMBeanException */ private static int getIndexIfAlreadyExists(MBeanAttributeInfo attribute, List<MBeanAttributeInfo> list) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java b/qpid/java/broker-plugins/jmx/src/main/java/org/apache/qpid/server/jmx/MBeanInvocationHandlerImpl.java index 651372db16..49f06d5121 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java +++ b/qpid/java/broker-plugins/jmx/src/main/java/org/apache/qpid/server/jmx/MBeanInvocationHandlerImpl.java @@ -18,10 +18,11 @@ * under the License. * */ -package org.apache.qpid.server.management; +package org.apache.qpid.server.jmx; import org.apache.log4j.Logger; +import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.logging.actors.ManagementActor; import org.apache.qpid.server.logging.messages.ManagementConsoleMessages; import org.apache.qpid.server.registry.ApplicationRegistry; @@ -174,41 +175,40 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler, Notificati } methodName = getMethodName(method, args); - if (isAccessMethod(methodName) || impact == MBeanOperationInfo.INFO) - { - // Check for read-only method invocation permission + if (isAccessMethod(methodName) || impact == MBeanOperationInfo.INFO) + { + // Check for read-only method invocation permission if (!security.authoriseMethod(Operation.ACCESS, type, methodName)) { throw new SecurityException("Permission denied: Access " + methodName); } - } - else - { - // Check for setting properties permission - if (!security.authoriseMethod(Operation.UPDATE, type, methodName)) - { - throw new SecurityException("Permission denied: Update " + methodName); - } - } - - boolean oldAccessChecksDisabled = false; - if(_managementRightsInferAllAccess) - { - oldAccessChecksDisabled = SecurityManager.setAccessChecksDisabled(true); - } - - try - { - // Actually invoke the method - return method.invoke(_mbs, args); - } - finally - { - if(_managementRightsInferAllAccess) - { - SecurityManager.setAccessChecksDisabled(oldAccessChecksDisabled); - } - } + } + else + { + // Check for setting properties permission + if (!security.authoriseMethod(Operation.UPDATE, type, methodName)) + { + throw new SecurityException("Permission denied: Update " + methodName); + } + } + + boolean oldAccessChecksDisabled = false; + if(_managementRightsInferAllAccess) + { + oldAccessChecksDisabled = SecurityManager.setAccessChecksDisabled(true); + } + + try + { + return doInvokeWrappingWithManagementActor(method, args); + } + finally + { + if(_managementRightsInferAllAccess) + { + SecurityManager.setAccessChecksDisabled(oldAccessChecksDisabled); + } + } } catch (InvocationTargetException e) { @@ -216,25 +216,40 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler, Notificati } } + private Object doInvokeWrappingWithManagementActor(Method method, + Object[] args) throws IllegalAccessException, + InvocationTargetException + { + try + { + CurrentActor.set(_logActor); + return method.invoke(_mbs, args); + } + finally + { + CurrentActor.remove(); + } + } + private String getType(Method method, Object[] args) - { - if (args[0] instanceof ObjectName) - { - ObjectName object = (ObjectName) args[0]; - String type = object.getKeyProperty("type"); - - return type; - } - return null; + { + if (args[0] instanceof ObjectName) + { + ObjectName object = (ObjectName) args[0]; + String type = object.getKeyProperty("type"); + + return type; + } + return null; } private String getVirtualHost(Method method, Object[] args) - { + { if (args[0] instanceof ObjectName) { ObjectName object = (ObjectName) args[0]; String vhost = object.getKeyProperty("VirtualHost"); - + if(vhost != null) { try @@ -253,7 +268,7 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler, Notificati } return null; } - + private String getMethodName(Method method, Object[] args) { String methodName = method.getName(); @@ -274,7 +289,7 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler, Notificati methodName = (String) args[1]; } } - + return methodName; } @@ -289,7 +304,7 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler, Notificati { return -1; } - + try { //Get the impact attribute diff --git a/qpid/java/broker-plugins/jmx/src/main/java/org/apache/qpid/server/jmx/MBeanProvider.java b/qpid/java/broker-plugins/jmx/src/main/java/org/apache/qpid/server/jmx/MBeanProvider.java new file mode 100644 index 0000000000..83909dbe72 --- /dev/null +++ b/qpid/java/broker-plugins/jmx/src/main/java/org/apache/qpid/server/jmx/MBeanProvider.java @@ -0,0 +1,52 @@ +/* + * + * 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.jmx; + +import java.util.ServiceLoader; + +import javax.management.JMException; +import javax.management.StandardMBean; + +import org.apache.qpid.server.model.ConfiguredObject; + +/** + * A provider of an mbean implementation. + * + * Provider implementations are advertised as services and loaded via {@link ServiceLoader}. + */ +public interface MBeanProvider +{ + /** + * Tests whether a <code>child</code> can be managed by the mbean + * provided by this provider. + */ + boolean isChildManageableByMBean(ConfiguredObject child); + + /** + * Creates a mbean for this child. This method should only be called if + * {@link #isChildManageableByMBean(ConfiguredObject)} has previously returned true. + * + * @return newly created mbean + */ + StandardMBean createMBean(ConfiguredObject child, StandardMBean parent) throws JMException; + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObject.java b/qpid/java/broker-plugins/jmx/src/main/java/org/apache/qpid/server/jmx/ManagedObject.java index 483b325455..40b778fd93 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObject.java +++ b/qpid/java/broker-plugins/jmx/src/main/java/org/apache/qpid/server/jmx/ManagedObject.java @@ -18,9 +18,7 @@ * under the License. * */ -package org.apache.qpid.server.management; - -import org.apache.qpid.AMQException; +package org.apache.qpid.server.jmx; import javax.management.JMException; import javax.management.MalformedObjectNameException; @@ -46,14 +44,14 @@ public interface ManagedObject ManagedObject getParentObject(); - void register() throws AMQException, JMException; + void register() throws JMException; - void unregister() throws AMQException; + void unregister() throws JMException; /** * Returns the ObjectName required for the mbeanserver registration. * @return ObjectName - * @throws MalformedObjectNameException + * @throws javax.management.MalformedObjectNameException */ ObjectName getObjectName() throws MalformedObjectNameException; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObjectRegistry.java b/qpid/java/broker-plugins/jmx/src/main/java/org/apache/qpid/server/jmx/ManagedObjectRegistry.java index b3323c569c..2ae0ac7052 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObjectRegistry.java +++ b/qpid/java/broker-plugins/jmx/src/main/java/org/apache/qpid/server/jmx/ManagedObjectRegistry.java @@ -18,10 +18,9 @@ * under the License. * */ -package org.apache.qpid.server.management; +package org.apache.qpid.server.jmx; import org.apache.commons.configuration.ConfigurationException; - import org.apache.qpid.common.Closeable; import javax.management.JMException; diff --git a/qpid/java/broker-plugins/jmx/src/main/java/org/apache/qpid/server/jmx/mbeans/AbstractStatisticsGatheringMBean.java b/qpid/java/broker-plugins/jmx/src/main/java/org/apache/qpid/server/jmx/mbeans/AbstractStatisticsGatheringMBean.java new file mode 100644 index 0000000000..4115f9f363 --- /dev/null +++ b/qpid/java/broker-plugins/jmx/src/main/java/org/apache/qpid/server/jmx/mbeans/AbstractStatisticsGatheringMBean.java @@ -0,0 +1,196 @@ +package org.apache.qpid.server.jmx.mbeans; + +import javax.management.NotCompliantMBeanException; +import org.apache.qpid.server.model.ConfiguredObject; +import org.apache.qpid.server.model.Connection; +import org.apache.qpid.server.jmx.AMQManagedObject; +import org.apache.qpid.server.jmx.ManagedObjectRegistry; +import org.apache.qpid.server.model.VirtualHost; + +/** + * 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 + * <p/> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p/> + * 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. + */ +abstract class AbstractStatisticsGatheringMBean<T extends ConfiguredObject> extends AMQManagedObject +{ + private long _lastStatUpdateTime; + private long _statUpdatePeriod = 5000L; + private long _lastMessagesReceived; + private long _lastMessagesSent; + private long _lastBytesReceived; + private long _lastBytesSent; + private double _messageReceivedRate; + private double _messageSentRate; + private double _bytesReceivedRate; + private double _bytesSentRate; + private double _peakMessageReceivedRate; + private double _peakMessageSentRate; + private double _peakBytesReceivedRate; + private double _peakBytesSentRate; + private final T _configuredObject; + + protected AbstractStatisticsGatheringMBean(Class<?> managementInterface, + String typeName, + ManagedObjectRegistry registry, + T object) throws NotCompliantMBeanException + { + super(managementInterface, typeName, registry); + _configuredObject = object; + initStats(); + } + + protected void initStats() + { + _lastStatUpdateTime = System.currentTimeMillis(); + } + + protected synchronized void updateStats() + { + long time = System.currentTimeMillis(); + final long period = time - _lastStatUpdateTime; + if(period > _statUpdatePeriod) + { + long messagesReceived = getStatistic(VirtualHost.MESSAGES_IN); + long messagesSent = getStatistic(VirtualHost.MESSAGES_OUT); + long bytesReceived = getStatistic(VirtualHost.BYTES_IN); + long bytesSent = getStatistic(VirtualHost.BYTES_OUT); + + double messageReceivedRate = (double)(messagesReceived - _lastMessagesReceived) / (double)period; + double messageSentRate = (double)(messagesSent - _lastMessagesSent) / (double)period; + double bytesReceivedRate = (double)(bytesReceived - _lastBytesReceived) / (double)period; + double bytesSentRate = (double)(bytesSent - _lastBytesSent) / (double)period; + + _lastMessagesReceived = messagesReceived; + _lastMessagesSent = messagesSent; + _lastBytesReceived = bytesReceived; + _lastBytesSent = bytesSent; + + _messageReceivedRate = messageReceivedRate; + _messageSentRate = messageSentRate; + _bytesReceivedRate = bytesReceivedRate; + _bytesSentRate = bytesSentRate; + + if(messageReceivedRate > _peakMessageReceivedRate) + { + _peakMessageReceivedRate = messageReceivedRate; + } + + if(messageSentRate > _peakMessageSentRate) + { + _peakMessageSentRate = messageSentRate; + } + + if(bytesReceivedRate > _peakBytesReceivedRate) + { + _peakBytesReceivedRate = bytesReceivedRate; + } + + if(bytesSentRate > _peakBytesSentRate) + { + _peakBytesSentRate = bytesSentRate; + } + + } + } + + private long getStatistic(String name) + { + return (Long) getConfiguredObject().getStatistics().getStatistic(name); + } + + public synchronized void resetStatistics() throws Exception + { + updateStats(); + //TODO - implement resetStatistics() + } + + public synchronized double getPeakMessageDeliveryRate() + { + updateStats(); + return _peakMessageSentRate; + } + + public synchronized double getPeakDataDeliveryRate() + { + updateStats(); + return _peakBytesSentRate; + } + + public synchronized double getMessageDeliveryRate() + { + updateStats(); + return _messageSentRate; + } + + public synchronized double getDataDeliveryRate() + { + updateStats(); + return _bytesSentRate; + } + + public synchronized long getTotalMessagesDelivered() + { + updateStats(); + return getStatistic(Connection.MESSAGES_OUT); + } + + public synchronized long getTotalDataDelivered() + { + updateStats(); + return getStatistic(Connection.BYTES_OUT); + } + + protected final T getConfiguredObject() + { + return _configuredObject; + } + + public synchronized double getPeakMessageReceiptRate() + { + updateStats(); + return _peakMessageReceivedRate; + } + + public synchronized double getPeakDataReceiptRate() + { + updateStats(); + return _peakBytesReceivedRate; + } + + public synchronized double getMessageReceiptRate() + { + updateStats(); + return _messageReceivedRate; + } + + public synchronized double getDataReceiptRate() + { + updateStats(); + return _bytesReceivedRate; + } + + public synchronized long getTotalMessagesReceived() + { + updateStats(); + return getStatistic(Connection.MESSAGES_IN); + } + + public synchronized long getTotalDataReceived() + { + updateStats(); + return getStatistic(Connection.BYTES_IN); + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/management/ConfigurationManagementMBean.java b/qpid/java/broker-plugins/jmx/src/main/java/org/apache/qpid/server/jmx/mbeans/ConfigurationManagementMBean.java index f0ca5dc139..beffb4eaa9 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/management/ConfigurationManagementMBean.java +++ b/qpid/java/broker-plugins/jmx/src/main/java/org/apache/qpid/server/jmx/mbeans/ConfigurationManagementMBean.java @@ -18,20 +18,24 @@ * under the License. * */ -package org.apache.qpid.server.configuration.management; +package org.apache.qpid.server.jmx.mbeans; import org.apache.qpid.management.common.mbeans.ConfigurationManagement; -import org.apache.qpid.server.management.AMQManagedObject; +import org.apache.qpid.server.jmx.AMQManagedObject; +import org.apache.qpid.server.jmx.ManagedObject; +import org.apache.qpid.server.jmx.ManagedObjectRegistry; import org.apache.qpid.server.registry.ApplicationRegistry; +import javax.management.JMException; import javax.management.NotCompliantMBeanException; public class ConfigurationManagementMBean extends AMQManagedObject implements ConfigurationManagement { - public ConfigurationManagementMBean() throws NotCompliantMBeanException + public ConfigurationManagementMBean(ManagedObjectRegistry registry) throws JMException { - super(ConfigurationManagement.class, ConfigurationManagement.TYPE); + super(ConfigurationManagement.class, ConfigurationManagement.TYPE, registry); + register(); } public String getObjectInstanceName() @@ -44,4 +48,9 @@ public class ConfigurationManagementMBean extends AMQManagedObject implements Co ApplicationRegistry.getInstance().getConfiguration().reparseConfigFileSecuritySections(); } + @Override + public ManagedObject getParentObject() + { + return null; + } } diff --git a/qpid/java/broker-plugins/jmx/src/main/java/org/apache/qpid/server/jmx/mbeans/ConnectionMBean.java b/qpid/java/broker-plugins/jmx/src/main/java/org/apache/qpid/server/jmx/mbeans/ConnectionMBean.java new file mode 100644 index 0000000000..024ee39318 --- /dev/null +++ b/qpid/java/broker-plugins/jmx/src/main/java/org/apache/qpid/server/jmx/mbeans/ConnectionMBean.java @@ -0,0 +1,183 @@ +/* + * + * 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.jmx.mbeans; + +import java.io.IOException; +import java.util.Collection; +import java.util.Date; +import javax.management.JMException; +import javax.management.ObjectName; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.CompositeDataSupport; +import javax.management.openmbean.CompositeType; +import javax.management.openmbean.OpenType; +import javax.management.openmbean.SimpleType; +import javax.management.openmbean.TabularData; +import javax.management.openmbean.TabularDataSupport; +import javax.management.openmbean.TabularType; + +import org.apache.qpid.management.common.mbeans.ManagedConnection; +import org.apache.qpid.server.jmx.ManagedObject; +import org.apache.qpid.server.model.Connection; +import org.apache.qpid.server.model.Session; +import org.apache.qpid.server.model.Statistics; + +public class ConnectionMBean extends AbstractStatisticsGatheringMBean<Connection> implements ManagedConnection +{ + private static final OpenType[] CHANNEL_ATTRIBUTE_TYPES = + { SimpleType.INTEGER, SimpleType.BOOLEAN, SimpleType.STRING, SimpleType.INTEGER, SimpleType.BOOLEAN }; + private static final CompositeType CHANNEL_TYPE; + private static final TabularType CHANNELS_TYPE; + + static + { + try + { + CHANNEL_TYPE = new CompositeType("Channel", "Channel Details", COMPOSITE_ITEM_NAMES_DESC.toArray(new String[COMPOSITE_ITEM_NAMES_DESC.size()]), + COMPOSITE_ITEM_NAMES_DESC.toArray(new String[COMPOSITE_ITEM_NAMES_DESC.size()]), + CHANNEL_ATTRIBUTE_TYPES); + CHANNELS_TYPE = new TabularType("Channels", "Channels", CHANNEL_TYPE, (String[]) TABULAR_UNIQUE_INDEX.toArray(new String[TABULAR_UNIQUE_INDEX.size()])); + } + catch (JMException ex) + { + // This is not expected to ever occur. + throw new RuntimeException("Got JMException in static initializer.", ex); + } + } + + + private final VirtualHostMBean _virtualHostMBean; + + public ConnectionMBean(Connection conn, VirtualHostMBean virtualHostMBean) throws JMException + { + super(ManagedConnection.class, ManagedConnection.TYPE, virtualHostMBean.getRegistry(), conn); + _virtualHostMBean = virtualHostMBean; + register(); + } + + public String getObjectInstanceName() + { + return ObjectName.quote(getRemoteAddress()); + } + + @Override + public ManagedObject getParentObject() + { + return _virtualHostMBean; + } + + public String getClientId() + { + return (String) getConfiguredObject().getAttribute(Connection.CLIENT_ID); + } + + public String getAuthorizedId() + { + return (String) getConfiguredObject().getAttribute(Connection.PRINCIPAL); + } + + public String getVersion() + { + return (String) getConfiguredObject().getAttribute(Connection.CLIENT_VERSION); + } + + public String getRemoteAddress() + { + return (String) getConfiguredObject().getAttribute(Connection.REMOTE_ADDRESS); + } + + public Date getLastIoTime() + { + Long lastIo = (Long) getConfiguredObject().getStatistics().getStatistic(Connection.LAST_IO_TIME); + return new Date(lastIo); + } + + public Long getMaximumNumberOfChannels() + { + return (Long) getConfiguredObject().getAttribute(Connection.SESSION_COUNT_LIMIT); + } + + public TabularData channels() throws IOException, JMException + { + TabularDataSupport sessionTable = new TabularDataSupport(CHANNELS_TYPE); + Collection<Session> list = getConfiguredObject().getSessions(); + + for (Session session : list) + { + Statistics statistics = session.getStatistics(); + Long txnBegins = (Long) statistics.getStatistic(Session.LOCAL_TRANSACTION_BEGINS); + Integer channelId = (Integer) session.getAttribute(Session.CHANNEL_ID); + int unacknowledgedSize = ((Number) statistics.getStatistic(Session.UNACKNOWLEDGED_MESSAGES)).intValue(); + boolean blocked = (Boolean) session.getAttribute(Session.PRODUCER_FLOW_BLOCKED); + boolean isTransactional = (txnBegins>0l); + + Object[] itemValues = + { + channelId, + isTransactional, + null, // TODO - default queue (which is meaningless) + unacknowledgedSize, + blocked + }; + + CompositeData sessionData = new CompositeDataSupport(CHANNEL_TYPE, + COMPOSITE_ITEM_NAMES_DESC.toArray(new String[COMPOSITE_ITEM_NAMES_DESC.size()]), itemValues); + sessionTable.put(sessionData); + } + + return sessionTable; + } + + public void commitTransactions(int channelId) throws JMException + { + throw buildUnsupportedException(); + } + + public void rollbackTransactions(int channelId) throws JMException + { + throw buildUnsupportedException(); + } + + public void closeConnection() throws Exception + { + getConfiguredObject().delete(); + } + + public boolean isStatisticsEnabled() + { + return true; + } + + public void setStatisticsEnabled(boolean enabled) + { + // TODO - Implement setStatisticsEnabled + updateStats(); + } + + private JMException buildUnsupportedException() throws JMException + { + String msg = "Operation not supported"; + JMException jmException = new JMException(msg); + jmException.initCause(new UnsupportedOperationException(msg)); + return jmException; + } +} diff --git a/qpid/java/broker-plugins/jmx/src/main/java/org/apache/qpid/server/jmx/mbeans/ExchangeMBean.java b/qpid/java/broker-plugins/jmx/src/main/java/org/apache/qpid/server/jmx/mbeans/ExchangeMBean.java new file mode 100644 index 0000000000..eb7e716af8 --- /dev/null +++ b/qpid/java/broker-plugins/jmx/src/main/java/org/apache/qpid/server/jmx/mbeans/ExchangeMBean.java @@ -0,0 +1,323 @@ +/* + * + * 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.jmx.mbeans; + +import org.apache.qpid.management.common.mbeans.ManagedExchange; +import org.apache.qpid.management.common.mbeans.ManagedQueue; +import org.apache.qpid.management.common.mbeans.annotations.MBeanOperationParameter; +import org.apache.qpid.server.jmx.AMQManagedObject; +import org.apache.qpid.server.jmx.ManagedObject; +import org.apache.qpid.server.model.Binding; +import org.apache.qpid.server.model.Exchange; +import org.apache.qpid.server.model.LifetimePolicy; +import org.apache.qpid.server.model.Queue; +import org.apache.qpid.server.model.VirtualHost; + +import javax.management.JMException; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; +import javax.management.openmbean.ArrayType; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.CompositeDataSupport; +import javax.management.openmbean.CompositeType; +import javax.management.openmbean.OpenDataException; +import javax.management.openmbean.OpenType; +import javax.management.openmbean.SimpleType; +import javax.management.openmbean.TabularData; +import javax.management.openmbean.TabularDataSupport; +import javax.management.openmbean.TabularType; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class ExchangeMBean extends AMQManagedObject implements ManagedExchange +{ + + private static final String[] TABULAR_UNIQUE_INDEX_ARRAY = + TABULAR_UNIQUE_INDEX.toArray(new String[TABULAR_UNIQUE_INDEX.size()]); + + private static final String[] COMPOSITE_ITEM_NAMES_ARRAY = + COMPOSITE_ITEM_NAMES.toArray(new String[COMPOSITE_ITEM_NAMES.size()]); + + private static final String[] COMPOSITE_ITEM_DESCRIPTIONS_ARRAY = + COMPOSITE_ITEM_DESCRIPTIONS.toArray(new String[COMPOSITE_ITEM_DESCRIPTIONS.size()]); + + private static final OpenType[] BINDING_ITEM_TYPES; + private static final CompositeType BINDING_DATA_TYPE; + private static final OpenType[] HEADERS_BINDING_ITEM_TYPES; + + + private static final CompositeType HEADERS_BINDING_DATA_TYPE; + + private static final String[] HEADERS_COMPOSITE_ITEM_NAMES_ARRAY = + HEADERS_COMPOSITE_ITEM_NAMES.toArray(new String[HEADERS_COMPOSITE_ITEM_NAMES.size()]); + + private static final String[] HEADERS_COMPOSITE_ITEM_DESCS_ARRAY = + HEADERS_COMPOSITE_ITEM_DESC.toArray(new String[HEADERS_COMPOSITE_ITEM_DESC.size()]); + private static final String[] HEADERS_TABULAR_UNIQUE_INDEX_ARRAY = + HEADERS_TABULAR_UNIQUE_INDEX.toArray(new String[HEADERS_TABULAR_UNIQUE_INDEX.size()]); + public static final String HEADERS_EXCHANGE_TYPE = "headers"; + + static + { + try + { + BINDING_ITEM_TYPES = new OpenType[] {SimpleType.STRING, new ArrayType(1, SimpleType.STRING)}; + + BINDING_DATA_TYPE= new CompositeType("Exchange Binding", "Binding key and Queue names", + COMPOSITE_ITEM_NAMES_ARRAY, + COMPOSITE_ITEM_DESCRIPTIONS_ARRAY, + BINDING_ITEM_TYPES); + + HEADERS_BINDING_ITEM_TYPES = new OpenType[] {SimpleType.INTEGER, + SimpleType.STRING, + new ArrayType(1, SimpleType.STRING)}; + + HEADERS_BINDING_DATA_TYPE = new CompositeType("Exchange Binding", "Queue name and header bindings", + HEADERS_COMPOSITE_ITEM_NAMES_ARRAY, + HEADERS_COMPOSITE_ITEM_DESCS_ARRAY, + HEADERS_BINDING_ITEM_TYPES); + + + } + catch(OpenDataException e) + { + throw new RuntimeException("Unexpected Error creating ArrayType", e); + } + } + + + private final Exchange _exchange; + private final VirtualHostMBean _vhostMBean; + + protected ExchangeMBean(Exchange exchange, VirtualHostMBean virtualHostMBean) + throws JMException + { + super(ManagedExchange.class, ManagedExchange.TYPE, virtualHostMBean.getRegistry()); + _exchange = exchange; + _vhostMBean = virtualHostMBean; + + register(); + } + + public String getObjectInstanceName() + { + return ObjectName.quote(getName()); + } + + @Override + public ManagedObject getParentObject() + { + return _vhostMBean; + } + + public ObjectName getObjectName() throws MalformedObjectNameException + { + String objNameString = super.getObjectName().toString(); + objNameString = objNameString + ",ExchangeType=" + getExchangeType(); + return new ObjectName(objNameString); + } + + + public String getName() + { + return _exchange.getName(); + } + + public String getExchangeType() + { + return _exchange.getExchangeType(); + } + + public Integer getTicketNo() + { + return 0; + } + + public boolean isDurable() + { + return _exchange.isDurable(); + } + + public boolean isAutoDelete() + { + return _exchange.getLifetimePolicy() == LifetimePolicy.AUTO_DELETE; + } + + public TabularData bindings() throws IOException, JMException + { + if(HEADERS_EXCHANGE_TYPE.equals(_exchange.getExchangeType())) + { + return getHeadersBindings(_exchange.getBindings()); + } + else + { + return getNonHeadersBindings(_exchange.getBindings()); + } + } + + + private TabularData getHeadersBindings(Collection<Binding> bindings) throws OpenDataException + { + TabularType bindinglistDataType = + new TabularType("Exchange Bindings", "List of exchange bindings for " + getName(), + HEADERS_BINDING_DATA_TYPE, + HEADERS_TABULAR_UNIQUE_INDEX_ARRAY); + + TabularDataSupport bindingList = new TabularDataSupport(bindinglistDataType); + int count = 1; + for (Binding binding : bindings) + { + + String queueName = binding.getParent(Queue.class).getName(); + + + Map<String,Object> headerMappings = binding.getArguments(); + + final List<String> mappingList = new ArrayList<String>(); + + if(headerMappings != null) + { + for(Map.Entry<String,Object> entry : headerMappings.entrySet()) + { + + mappingList.add(entry.getKey() + "=" + entry.getValue()); + } + } + + + Object[] bindingItemValues = {count++, queueName, mappingList.toArray(new String[0])}; + CompositeData bindingData = new CompositeDataSupport(HEADERS_BINDING_DATA_TYPE, + HEADERS_COMPOSITE_ITEM_NAMES_ARRAY, + bindingItemValues); + bindingList.put(bindingData); + } + + return bindingList; + + } + + private TabularData getNonHeadersBindings(Collection<Binding> bindings) throws OpenDataException + { + + TabularType bindinglistDataType = + new TabularType("Exchange Bindings", "Exchange Bindings for " + getName(), + BINDING_DATA_TYPE, + TABULAR_UNIQUE_INDEX_ARRAY); + + TabularDataSupport bindingList = new TabularDataSupport(bindinglistDataType); + + Map<String, List<String>> bindingMap = new HashMap<String, List<String>>(); + + for (Binding binding : bindings) + { + String key = "fanout".equals(_exchange.getExchangeType()) ? "*" : binding.getName(); + List<String> queueList = bindingMap.get(key); + if(queueList == null) + { + queueList = new ArrayList<String>(); + bindingMap.put(key, queueList); + } + queueList.add(binding.getParent(Queue.class).getName()); + + } + + for(Map.Entry<String, List<String>> entry : bindingMap.entrySet()) + { + Object[] bindingItemValues = {entry.getKey(), entry.getValue().toArray(new String[0])}; + CompositeData bindingData = new CompositeDataSupport(BINDING_DATA_TYPE, + COMPOSITE_ITEM_NAMES_ARRAY, + bindingItemValues); + bindingList.put(bindingData); + } + + return bindingList; + } + + public void createNewBinding(String queueName, String binding) throws JMException + { + final Map<String,Object> arguments = new HashMap<String, Object>(); + + if(HEADERS_EXCHANGE_TYPE.equals(_exchange.getExchangeType())) + { + final String[] bindings = binding.split(","); + for (int i = 0; i < bindings.length; i++) + { + final String[] keyAndValue = bindings[i].split("="); + if (keyAndValue == null || keyAndValue.length == 0 || keyAndValue.length > 2 || keyAndValue[0].length() == 0) + { + throw new JMException("Format for headers binding should be \"<attribute1>=<value1>,<attribute2>=<value2>\" "); + } + + if(keyAndValue.length == 1) + { + //no value was given, only a key. Use an empty value to signal match on key presence alone + arguments.put(keyAndValue[0], ""); + } + else + { + arguments.put(keyAndValue[0], keyAndValue[1]); + } + } + } + + Queue queue = null; + VirtualHost vhost = _exchange.getParent(VirtualHost.class); + for(Queue aQueue : vhost.getQueues()) + { + if(aQueue.getName().equals(queueName)) + { + queue = aQueue; + break; + } + } + _exchange.createBinding(binding, queue, arguments, Collections.EMPTY_MAP); + } + + public void removeBinding(String queueName, String bindingKey) + throws IOException, JMException + { + Queue queue = null; + VirtualHost vhost = _exchange.getParent(VirtualHost.class); + for(Queue aQueue : vhost.getQueues()) + { + if(aQueue.getName().equals(queueName)) + { + queue = aQueue; + break; + } + } + + for(Binding binding : _exchange.getBindings()) + { + if(queue.equals(binding.getParent(Queue.class)) && bindingKey.equals(binding.getName())) + { + binding.delete(); + } + } + + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java b/qpid/java/broker-plugins/jmx/src/main/java/org/apache/qpid/server/jmx/mbeans/LoggingManagementMBean.java index c699dff175..9ff45979ca 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java +++ b/qpid/java/broker-plugins/jmx/src/main/java/org/apache/qpid/server/jmx/mbeans/LoggingManagementMBean.java @@ -18,7 +18,7 @@ * * */ -package org.apache.qpid.server.logging.management; +package org.apache.qpid.server.jmx.mbeans; import org.apache.log4j.Level; import org.apache.log4j.LogManager; @@ -27,16 +27,17 @@ import org.apache.log4j.xml.Log4jEntityResolver; import org.apache.log4j.xml.QpidLog4JConfigurator; import org.apache.log4j.xml.QpidLog4JConfigurator.IllegalLoggerLevelException; import org.apache.log4j.xml.QpidLog4JConfigurator.QpidLog4JSaxErrorHandler; +import org.apache.qpid.management.common.mbeans.LoggingManagement; +import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription; +import org.apache.qpid.server.jmx.AMQManagedObject; +import org.apache.qpid.server.jmx.ManagedObject; +import org.apache.qpid.server.jmx.ManagedObjectRegistry; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; import org.xml.sax.ErrorHandler; import org.xml.sax.SAXException; -import org.apache.qpid.management.common.mbeans.LoggingManagement; -import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription; -import org.apache.qpid.server.management.AMQManagedObject; - import javax.management.JMException; import javax.management.openmbean.CompositeData; import javax.management.openmbean.CompositeDataSupport; @@ -107,11 +108,14 @@ public class LoggingManagementMBean extends AMQManagedObject implements LoggingM } } - public LoggingManagementMBean(String log4jConfigFileName, int log4jLogWatchInterval) throws JMException + public LoggingManagementMBean(String log4jConfigFileName, + int log4jLogWatchInterval, + ManagedObjectRegistry registry) throws JMException { - super(LoggingManagement.class, LoggingManagement.TYPE); + super(LoggingManagement.class, LoggingManagement.TYPE, registry); _log4jConfigFileName = log4jConfigFileName; _log4jLogWatchInterval = log4jLogWatchInterval; + register(); } public String getObjectInstanceName() @@ -819,4 +823,10 @@ public class LoggingManagementMBean extends AMQManagedObject implements LoggingM LOCK.unlock(); } } + + @Override + public ManagedObject getParentObject() + { + return null; + } } diff --git a/qpid/java/broker-plugins/jmx/src/main/java/org/apache/qpid/server/jmx/mbeans/QueueMBean.java b/qpid/java/broker-plugins/jmx/src/main/java/org/apache/qpid/server/jmx/mbeans/QueueMBean.java new file mode 100644 index 0000000000..76d545a5f7 --- /dev/null +++ b/qpid/java/broker-plugins/jmx/src/main/java/org/apache/qpid/server/jmx/mbeans/QueueMBean.java @@ -0,0 +1,692 @@ +/* + * + * 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.jmx.mbeans; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicLong; +import javax.management.JMException; +import javax.management.MBeanNotificationInfo; +import javax.management.Notification; +import javax.management.ObjectName; +import javax.management.OperationsException; +import javax.management.monitor.MonitorNotification; +import javax.management.openmbean.ArrayType; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.CompositeDataSupport; +import javax.management.openmbean.CompositeType; +import javax.management.openmbean.OpenDataException; +import javax.management.openmbean.OpenType; +import javax.management.openmbean.SimpleType; +import javax.management.openmbean.TabularData; +import javax.management.openmbean.TabularDataSupport; +import javax.management.openmbean.TabularType; +import org.apache.commons.lang.time.FastDateFormat; +import org.apache.qpid.management.common.mbeans.ManagedQueue; +import org.apache.qpid.server.jmx.AMQManagedObject; +import org.apache.qpid.server.jmx.ManagedObject; +import org.apache.qpid.server.message.AMQMessageHeader; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.model.ConfiguredObjectFinder; +import org.apache.qpid.server.model.Exchange; +import org.apache.qpid.server.model.LifetimePolicy; +import org.apache.qpid.server.model.Queue; +import org.apache.qpid.server.model.QueueNotificationListener; +import org.apache.qpid.server.model.VirtualHost; +import org.apache.qpid.server.queue.NotificationCheck; +import org.apache.qpid.server.queue.QueueEntry; +import org.apache.qpid.server.queue.QueueEntryVisitor; + +public class QueueMBean extends AMQManagedObject implements ManagedQueue, QueueNotificationListener +{ + private static final String[] VIEW_MSGS_COMPOSITE_ITEM_NAMES_DESC_ARRAY = + VIEW_MSGS_COMPOSITE_ITEM_NAMES_DESC.toArray(new String[VIEW_MSGS_COMPOSITE_ITEM_NAMES_DESC.size()]); + + private static final OpenType[] MSG_ATTRIBUTE_TYPES; + private static final CompositeType MSG_DATA_TYPE; + private static final TabularType MSG_LIST_DATA_TYPE; + private static final CompositeType MSG_CONTENT_TYPE; + private static final String[] VIEW_MSG_COMPOSIT_ITEM_NAMES_ARRAY = VIEW_MSG_CONTENT_COMPOSITE_ITEM_NAMES_DESC.toArray( + new String[VIEW_MSG_CONTENT_COMPOSITE_ITEM_NAMES_DESC.size()]); + + static + { + + try + { + MSG_ATTRIBUTE_TYPES = new OpenType[] { + SimpleType.LONG, // For message id + new ArrayType(1, SimpleType.STRING), // For header attributes + SimpleType.LONG, // For size + SimpleType.BOOLEAN, // For redelivered + SimpleType.LONG, // For queue position + SimpleType.INTEGER // For delivery count} + }; + + MSG_DATA_TYPE = new CompositeType("Message", "AMQ Message", + VIEW_MSGS_COMPOSITE_ITEM_NAMES_DESC_ARRAY, + VIEW_MSGS_COMPOSITE_ITEM_NAMES_DESC_ARRAY, MSG_ATTRIBUTE_TYPES); + + MSG_LIST_DATA_TYPE = new TabularType("Messages", "List of messages", MSG_DATA_TYPE, + VIEW_MSGS_TABULAR_UNIQUE_INDEX.toArray(new String[VIEW_MSGS_TABULAR_UNIQUE_INDEX.size()])); + + OpenType[] msgContentAttrs = new OpenType[] { + SimpleType.LONG, // For message id + SimpleType.STRING, // For MimeType + SimpleType.STRING, // For MimeType + new ArrayType(SimpleType.BYTE, true) // For message content + }; + + + MSG_CONTENT_TYPE = new CompositeType("Message Content", "AMQ Message Content", + VIEW_MSG_CONTENT_COMPOSITE_ITEM_NAMES_DESC.toArray(new String[VIEW_MSG_CONTENT_COMPOSITE_ITEM_NAMES_DESC.size()]), + VIEW_MSG_CONTENT_COMPOSITE_ITEM_NAMES_DESC.toArray(new String[VIEW_MSG_CONTENT_COMPOSITE_ITEM_NAMES_DESC.size()]), + msgContentAttrs); + + } + catch (OpenDataException e) + { + throw new RuntimeException(e); + } + } + + private final Queue _queue; + private final VirtualHostMBean _vhostMBean; + + /** Date/time format used for message expiration and message timestamp formatting */ + public static final String JMSTIMESTAMP_DATETIME_FORMAT = "MM-dd-yy HH:mm:ss.SSS z"; + + private static final FastDateFormat FAST_DATE_FORMAT = FastDateFormat.getInstance(JMSTIMESTAMP_DATETIME_FORMAT); + + public QueueMBean(Queue queue, VirtualHostMBean virtualHostMBean) throws JMException + { + super(ManagedQueue.class, ManagedQueue.TYPE, virtualHostMBean.getRegistry()); + _queue = queue; + _vhostMBean = virtualHostMBean; + register(); + _queue.setNotificationListener(this); + } + + public ManagedObject getParentObject() + { + return _vhostMBean; + } + + public String getObjectInstanceName() + { + return ObjectName.quote(getName()); + } + + public String getName() + { + return _queue.getName(); + } + + + public Integer getMessageCount() + { + return getStatisticValue(Queue.QUEUE_DEPTH_MESSAGES).intValue(); + } + + private Number getStatisticValue(String name) + { + final Number statistic = (Number) _queue.getStatistics().getStatistic(name); + return statistic == null ? Integer.valueOf(0) : statistic; + } + + public Integer getMaximumDeliveryCount() + { + return (Integer) _queue.getAttribute(Queue.MAXIMUM_DELIVERY_ATTEMPTS); + } + + public Long getReceivedMessageCount() + { + return getStatisticValue(Queue.TOTAL_ENQUEUED_MESSAGES).longValue(); + } + + public Long getQueueDepth() + { + return getStatisticValue(Queue.QUEUE_DEPTH_BYTES).longValue(); + } + + public Integer getActiveConsumerCount() + { + return getStatisticValue(Queue.CONSUMER_COUNT_WITH_CREDIT).intValue(); + } + + public Integer getConsumerCount() + { + return getStatisticValue(Queue.CONSUMER_COUNT).intValue(); + } + + public String getOwner() + { + return (String) _queue.getAttribute(Queue.OWNER); + } + + @Override + public String getQueueType() + { + return (String) _queue.getAttribute(Queue.TYPE); + } + + public boolean isDurable() + { + return _queue.isDurable(); + } + + public boolean isAutoDelete() + { + return _queue.getLifetimePolicy() == LifetimePolicy.AUTO_DELETE; + } + + public Long getMaximumMessageAge() + { + return (Long) _queue.getAttribute(Queue.ALERT_THRESHOLD_MESSAGE_AGE); + } + + public void setMaximumMessageAge(Long age) + { + _queue.setAttribute(Queue.ALERT_THRESHOLD_MESSAGE_AGE, getMaximumMessageAge(), age); + } + + public Long getMaximumMessageSize() + { + return (Long) _queue.getAttribute(Queue.ALERT_THRESHOLD_MESSAGE_SIZE); + } + + public void setMaximumMessageSize(Long size) + { + _queue.setAttribute(Queue.ALERT_THRESHOLD_MESSAGE_SIZE, getMaximumMessageSize(), size); + } + + public Long getMaximumMessageCount() + { + return (Long) _queue.getAttribute(Queue.ALERT_THRESHOLD_QUEUE_DEPTH_MESSAGES); + } + + public void setMaximumMessageCount(Long value) + { + _queue.setAttribute(Queue.ALERT_THRESHOLD_QUEUE_DEPTH_MESSAGES, getMaximumMessageCount(), value); + } + + public Long getMaximumQueueDepth() + { + return (Long) _queue.getAttribute(Queue.ALERT_THRESHOLD_QUEUE_DEPTH_BYTES); + } + + public void setMaximumQueueDepth(Long value) + { + _queue.setAttribute(Queue.ALERT_THRESHOLD_QUEUE_DEPTH_BYTES, getMaximumQueueDepth(), value); + } + + public Long getCapacity() + { + return (Long) _queue.getAttribute(Queue.QUEUE_FLOW_CONTROL_SIZE_BYTES); + } + + public void setCapacity(Long value) + { + _queue.setAttribute(Queue.QUEUE_FLOW_CONTROL_SIZE_BYTES, getCapacity(), value); + } + + public Long getFlowResumeCapacity() + { + return (Long) _queue.getAttribute(Queue.QUEUE_FLOW_RESUME_SIZE_BYTES); + } + + public void setFlowResumeCapacity(Long value) + { + _queue.setAttribute(Queue.QUEUE_FLOW_RESUME_SIZE_BYTES, getFlowResumeCapacity(), value); + } + + public boolean isFlowOverfull() + { + return (Boolean)_queue.getAttribute(Queue.QUEUE_FLOW_STOPPED); + } + + public boolean isExclusive() + { + return (Boolean) _queue.getAttribute(Queue.EXCLUSIVE); + } + + public void setExclusive(boolean exclusive) + { + _queue.setAttribute(Queue.EXCLUSIVE, isExclusive(), exclusive); + } + + public void setAlternateExchange(String exchangeName) throws OperationsException + { + if (exchangeName == null || "".equals(exchangeName)) + { + _queue.setAttribute(Queue.ALTERNATE_EXCHANGE, getAlternateExchange(), null); + } + else + { + VirtualHost virtualHost = _queue.getParent(VirtualHost.class); + Exchange exchange = findExchangeFromExchangeName(virtualHost, exchangeName); + + _queue.setAttribute(Queue.ALTERNATE_EXCHANGE, getAlternateExchange(), exchange); + } + } + + public String getAlternateExchange() + { + Exchange alternateExchange = (Exchange) _queue.getAttribute(Queue.ALTERNATE_EXCHANGE); + return alternateExchange == null ? null : alternateExchange.getName(); + } + + public TabularData viewMessages(int fromIndex, int toIndex) + throws IOException, JMException + { + return viewMessages((long)fromIndex, (long)toIndex); + } + + public TabularData viewMessages(long startPosition, long endPosition) + throws IOException, JMException + { + if ((startPosition > endPosition) || (startPosition < 1)) + { + throw new OperationsException("From Index = " + startPosition + ", To Index = " + endPosition + + "\n\"From Index\" should be greater than 0 and less than \"To Index\""); + } + + if ((endPosition - startPosition) > Integer.MAX_VALUE) + { + throw new OperationsException("Specified MessageID interval is too large. Intervals must be less than 2^31 in size"); + } + + + List<QueueEntry> messages = getMessages(startPosition, endPosition); + + TabularDataSupport messageTable = new TabularDataSupport(MSG_LIST_DATA_TYPE); + + + // Create the tabular list of message header contents + long position = startPosition; + + for (QueueEntry queueEntry : messages) + { + ServerMessage serverMsg = queueEntry.getMessage(); + AMQMessageHeader header = serverMsg.getMessageHeader(); + String[] headerAttributes = + {"reply-to = " + header.getReplyTo(), + "propertyFlags = ", + "ApplicationID = " + header.getAppId(), + "ClusterID = ", + "UserId = " + header.getUserId(), + "JMSMessageID = " + header.getMessageId(), + "JMSCorrelationID = " + header.getCorrelationId(), + "JMSDeliveryMode = " + (serverMsg.isPersistent() ? "Persistent" : "Non_Persistent"), + "JMSPriority = " + header.getPriority(), + "JMSType = " + header.getType(), + "JMSExpiration = " + (header.getExpiration() == 0 ? null : FAST_DATE_FORMAT.format(header.getExpiration())), + "JMSTimestamp = " + (header.getTimestamp() == 0 ? null : FAST_DATE_FORMAT.format(header.getTimestamp())) + }; + + Object[] itemValues = new Object[]{ serverMsg.getMessageNumber(), + headerAttributes, + serverMsg.getSize(), + queueEntry.isRedelivered(), + position, + queueEntry.getDeliveryCount()}; + + position++; + + CompositeData messageData = + new CompositeDataSupport(MSG_DATA_TYPE, VIEW_MSGS_COMPOSITE_ITEM_NAMES_DESC_ARRAY, itemValues); + messageTable.put(messageData); + } + + return messageTable; + + } + + public CompositeData viewMessageContent(long messageId) + throws IOException, JMException + { + QueueEntry entry = getMessage(messageId); + if(entry == null) + { + throw new OperationsException("AMQMessage with message id = " + messageId + " is not in the " + _queue.getName()); + } + + ServerMessage serverMsg = entry.getMessage(); + final int bodySize = (int) serverMsg.getSize(); + + byte[] msgContent = new byte[bodySize]; + + ByteBuffer buf = ByteBuffer.wrap(msgContent); + int position = 0; + + while(position < bodySize) + { + position += serverMsg.getContent(buf, position); + + } + + AMQMessageHeader header = serverMsg.getMessageHeader(); + + String mimeType = null, encoding = null; + if (header != null) + { + mimeType = header.getMimeType(); + + encoding = header.getEncoding(); + } + + + Object[] itemValues = { messageId, mimeType, encoding, msgContent }; + + return new CompositeDataSupport(MSG_CONTENT_TYPE, VIEW_MSG_COMPOSIT_ITEM_NAMES_ARRAY, itemValues); + + + } + + private QueueEntry getMessage(long messageId) + { + GetMessageVisitor visitor = new GetMessageVisitor(messageId); + _queue.visit(visitor); + return visitor.getEntry(); + + } + + public void deleteMessageFromTop() throws IOException, JMException + { + VirtualHost vhost = _queue.getParent(VirtualHost.class); + vhost.executeTransaction(new VirtualHost.TransactionalOperation() + { + public void withinTransaction(final VirtualHost.Transaction txn) + { + _queue.visit(new QueueEntryVisitor() + { + + public boolean visit(final QueueEntry entry) + { + if(entry.acquire()) + { + txn.dequeue(entry); + return true; + } + return false; + } + }); + + } + }); + + } + + public Long clearQueue() throws IOException, JMException + { + VirtualHost vhost = _queue.getParent(VirtualHost.class); + final AtomicLong count = new AtomicLong(); + + vhost.executeTransaction(new VirtualHost.TransactionalOperation() + { + public void withinTransaction(final VirtualHost.Transaction txn) + { + _queue.visit(new QueueEntryVisitor() + { + + public boolean visit(final QueueEntry entry) + { + final ServerMessage message = entry.getMessage(); + if(message != null) + { + txn.dequeue(entry); + count.incrementAndGet(); + + } + return false; + } + }); + + } + }); + return count.get(); + } + + public void moveMessages(final long fromMessageId, final long toMessageId, String toQueue) + throws IOException, JMException + { + if ((fromMessageId > toMessageId) || (fromMessageId < 1)) + { + throw new OperationsException("\"From MessageId\" should be greater than 0 and less than \"To MessageId\""); + } + + VirtualHost vhost = _queue.getParent(VirtualHost.class); + final Queue destinationQueue = findQueueFromQueueName(vhost, toQueue); + + vhost.executeTransaction(new VirtualHost.TransactionalOperation() + { + public void withinTransaction(final VirtualHost.Transaction txn) + { + _queue.visit(new QueueEntryVisitor() + { + + public boolean visit(final QueueEntry entry) + { + final ServerMessage message = entry.getMessage(); + if(message != null) + { + final long messageId = message.getMessageNumber(); + + if ((messageId >= fromMessageId) + && (messageId <= toMessageId)) + { + txn.move(entry, destinationQueue); + } + + } + return false; + } + }); + } + }); + } + + public void deleteMessages(final long fromMessageId, final long toMessageId) + throws IOException, JMException + { + VirtualHost vhost = _queue.getParent(VirtualHost.class); + vhost.executeTransaction(new VirtualHost.TransactionalOperation() + { + public void withinTransaction(final VirtualHost.Transaction txn) + { + _queue.visit(new QueueEntryVisitor() + { + + public boolean visit(final QueueEntry entry) + { + final ServerMessage message = entry.getMessage(); + if(message != null) + { + final long messageId = message.getMessageNumber(); + + if ((messageId >= fromMessageId) + && (messageId <= toMessageId)) + { + txn.dequeue(entry); + return true; + } + return false; + } + return true; + } + }); + } + }); + } + + public void copyMessages(final long fromMessageId, final long toMessageId, String toQueue) + throws IOException, JMException + { + if ((fromMessageId > toMessageId) || (fromMessageId < 1)) + { + throw new OperationsException("\"From MessageId\" should be greater than 0 and less than \"To MessageId\""); + } + + VirtualHost vhost = _queue.getParent(VirtualHost.class); + final Queue destinationQueue = findQueueFromQueueName(vhost, toQueue); + + vhost.executeTransaction(new VirtualHost.TransactionalOperation() + { + public void withinTransaction(final VirtualHost.Transaction txn) + { + _queue.visit(new QueueEntryVisitor() + { + + public boolean visit(final QueueEntry entry) + { + final ServerMessage message = entry.getMessage(); + if(message != null) + { + final long messageId = message.getMessageNumber(); + + if ((messageId >= fromMessageId) + && (messageId <= toMessageId)) + { + txn.copy(entry, destinationQueue); + } + + } + return false; + } + }); + } + }); + } + + private List<QueueEntry> getMessages(final long first, final long last) + { + final List<QueueEntry> messages = new ArrayList<QueueEntry>((int)(last-first)+1); + _queue.visit(new QueueEntryVisitor() + { + private long position = 1; + + public boolean visit(QueueEntry entry) + { + if(position >= first && position <= last) + { + messages.add(entry); + } + position++; + return position > last; + } + }); + return messages; + } + + + private static class GetMessageVisitor implements QueueEntryVisitor + { + + private final long _messageNumber; + private QueueEntry _entry; + + public GetMessageVisitor(long messageId) + { + _messageNumber = messageId; + } + + public boolean visit(QueueEntry entry) + { + if(entry.getMessage().getMessageNumber() == _messageNumber) + { + _entry = entry; + return true; + } + return false; + } + + public QueueEntry getEntry() + { + return _entry; + } + } + + @Override + public void notifyClients(NotificationCheck notification, Queue queue, String notificationMsg) + { + notificationMsg = notification.name() + " " + notificationMsg; + + Notification note = new Notification(MonitorNotification.THRESHOLD_VALUE_EXCEEDED, this, + incrementAndGetSequenceNumber(), System.currentTimeMillis(), notificationMsg); + + getBroadcaster().sendNotification(note); + } + + /** + * returns Notifications sent by this MBean. + */ + @Override + public MBeanNotificationInfo[] getNotificationInfo() + { + String[] notificationTypes = new String[] { MonitorNotification.THRESHOLD_VALUE_EXCEEDED }; + String name = MonitorNotification.class.getName(); + String description = "Either Message count or Queue depth or Message size has reached threshold high value"; + MBeanNotificationInfo info1 = new MBeanNotificationInfo(notificationTypes, name, description); + + return new MBeanNotificationInfo[] { info1 }; + } + + @Override + public String getDescription() + { + return (String) _queue.getAttribute(Queue.DESCRIPTION); + } + + @Override + public void setDescription(String description) + { + _queue.setAttribute(Queue.DESCRIPTION, getDescription(), description); + } + + private Queue findQueueFromQueueName(VirtualHost virtualHost, String queueName) throws OperationsException + { + Queue queue = ConfiguredObjectFinder.findConfiguredObjectByName(virtualHost.getQueues(), queueName); + if (queue == null) + { + throw new OperationsException("No such queue \""+queueName+"\""); + } + else + { + return queue; + } + } + + private Exchange findExchangeFromExchangeName(VirtualHost virtualHost, String exchangeName) throws OperationsException + { + Exchange exchange = ConfiguredObjectFinder.findConfiguredObjectByName(virtualHost.getExchanges(), exchangeName); + if (exchange == null) + { + throw new OperationsException("No such exchange \""+exchangeName+"\""); + } + else + { + return exchange; + } + } +} diff --git a/qpid/java/broker-plugins/jmx/src/main/java/org/apache/qpid/server/jmx/mbeans/ServerInformationMBean.java b/qpid/java/broker-plugins/jmx/src/main/java/org/apache/qpid/server/jmx/mbeans/ServerInformationMBean.java new file mode 100644 index 0000000000..597b98ccaa --- /dev/null +++ b/qpid/java/broker-plugins/jmx/src/main/java/org/apache/qpid/server/jmx/mbeans/ServerInformationMBean.java @@ -0,0 +1,93 @@ +/* + * 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.jmx.mbeans; + +import java.io.IOException; + +import javax.management.JMException; +import javax.management.NotCompliantMBeanException; + +import org.apache.qpid.common.QpidProperties; +import org.apache.qpid.management.common.mbeans.ServerInformation; +import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription; +import org.apache.qpid.server.jmx.ManagedObject; +import org.apache.qpid.server.jmx.ManagedObjectRegistry; +import org.apache.qpid.server.model.Broker; + +@MBeanDescription("Server Information Interface") +public class ServerInformationMBean extends AbstractStatisticsGatheringMBean<Broker> implements ServerInformation +{ + private String _buildVersion; + private String _productVersion; + + public ServerInformationMBean(ManagedObjectRegistry registry, Broker broker) + throws NotCompliantMBeanException, JMException + { + super(ServerInformation.class, ServerInformation.TYPE, registry, broker); + + _buildVersion = QpidProperties.getBuildVersion(); + _productVersion = QpidProperties.getReleaseVersion(); + + register(); + } + + @Override + public String getObjectInstanceName() + { + return ServerInformation.TYPE; + } + + @Override + public Integer getManagementApiMajorVersion() throws IOException + { + return QPID_JMX_API_MAJOR_VERSION; + } + + @Override + public Integer getManagementApiMinorVersion() throws IOException + { + return QPID_JMX_API_MINOR_VERSION; + } + + @Override + public String getBuildVersion() throws IOException + { + return _buildVersion; + } + + @Override + public String getProductVersion() throws IOException + { + return _productVersion; + } + + @Override + public boolean isStatisticsEnabled() + { + return false; + } + + @Override + public ManagedObject getParentObject() + { + // does not have a parent + return null; + } +} diff --git a/qpid/java/broker-plugins/experimental/shutdown/src/main/java/org/apache/qpid/shutdown/Shutdown.java b/qpid/java/broker-plugins/jmx/src/main/java/org/apache/qpid/server/jmx/mbeans/Shutdown.java index cef4a42b64..62733168ef 100644 --- a/qpid/java/broker-plugins/experimental/shutdown/src/main/java/org/apache/qpid/shutdown/Shutdown.java +++ b/qpid/java/broker-plugins/jmx/src/main/java/org/apache/qpid/server/jmx/mbeans/Shutdown.java @@ -17,8 +17,14 @@ * under the License. * */ -package org.apache.qpid.shutdown; +package org.apache.qpid.server.jmx.mbeans; +import org.apache.log4j.Logger; +import org.apache.qpid.server.jmx.DefaultManagedObject; +import org.apache.qpid.server.jmx.ManagedObject; +import org.apache.qpid.server.jmx.ManagedObjectRegistry; + +import javax.management.JMException; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; @@ -27,11 +33,6 @@ import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; -import javax.management.NotCompliantMBeanException; - -import org.apache.log4j.Logger; -import org.apache.qpid.server.management.DefaultManagedObject; - /** * Implementation of the JMX broker shutdown plugin. */ @@ -46,9 +47,10 @@ public class Shutdown extends DefaultManagedObject implements ShutdownMBean private final Runnable _shutdown = new SystemExiter(); - public Shutdown() throws NotCompliantMBeanException + public Shutdown(ManagedObjectRegistry registry) throws JMException { - super(ShutdownMBean.class, ShutdownMBean.TYPE); + super(ShutdownMBean.class, ShutdownMBean.TYPE, registry); + register(); } /** @see ShutdownMBean#shutdown() */ @@ -108,6 +110,12 @@ public class Shutdown extends DefaultManagedObject implements ShutdownMBean EXECUTOR.schedule(_shutdown, delay, TimeUnit.MILLISECONDS); } + @Override + public ManagedObject getParentObject() + { + return null; + } + /** * Shutting down the system in another thread to avoid JMX exceptions being thrown. */ @@ -120,9 +128,8 @@ public class Shutdown extends DefaultManagedObject implements ShutdownMBean } /** - * @see org.apache.qpid.server.management.ManagedObject#getObjectInstanceName() + * @see ManagedObject#getObjectInstanceName() */ - @Override public String getObjectInstanceName() { return "Shutdown"; diff --git a/qpid/java/broker-plugins/experimental/shutdown/src/main/java/org/apache/qpid/shutdown/ShutdownMBean.java b/qpid/java/broker-plugins/jmx/src/main/java/org/apache/qpid/server/jmx/mbeans/ShutdownMBean.java index 5c54fb3e21..ed69c351f7 100644 --- a/qpid/java/broker-plugins/experimental/shutdown/src/main/java/org/apache/qpid/shutdown/ShutdownMBean.java +++ b/qpid/java/broker-plugins/jmx/src/main/java/org/apache/qpid/server/jmx/mbeans/ShutdownMBean.java @@ -17,13 +17,13 @@ * under the License. * */ -package org.apache.qpid.shutdown; - -import javax.management.MBeanOperationInfo; +package org.apache.qpid.server.jmx.mbeans; import org.apache.qpid.management.common.mbeans.annotations.MBeanOperation; import org.apache.qpid.management.common.mbeans.annotations.MBeanOperationParameter; +import javax.management.MBeanOperationInfo; + /** * Shutdown plugin JMX MBean interface. * @@ -45,7 +45,7 @@ public interface ShutdownMBean * @param delay the number of ms to wait */ @MBeanOperation(name="shutdown", description="Shutdown after the specified delay (ms)", impact = MBeanOperationInfo.ACTION) - public void shutdown(@MBeanOperationParameter(name="when", description="delay (ms)")long delay); + public void shutdown(@MBeanOperationParameter(name = "when", description = "delay (ms)") long delay); /** * Broker will be shutdown at the specified date and time. @@ -53,5 +53,6 @@ public interface ShutdownMBean * @param when the date and time to shutdown */ @MBeanOperation(name="shutdownAt", description="Shutdown at the specified date and time (yyyy/MM/dd HH:mm:ss)", impact = MBeanOperationInfo.ACTION) - public void shutdownAt(@MBeanOperationParameter(name="when", description="shutdown date/time (yyyy/MM/dd HH:mm:ss)")String when); + public void shutdownAt(@MBeanOperationParameter(name = "when", + description = "shutdown date/time (yyyy/MM/dd HH:mm:ss)") String when); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/management/AMQUserManagementMBean.java b/qpid/java/broker-plugins/jmx/src/main/java/org/apache/qpid/server/jmx/mbeans/UserManagementMBean.java index 1314a5d6a6..c7aade34b4 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/management/AMQUserManagementMBean.java +++ b/qpid/java/broker-plugins/jmx/src/main/java/org/apache/qpid/server/jmx/mbeans/UserManagementMBean.java @@ -18,16 +18,16 @@ * * */ -package org.apache.qpid.server.security.auth.management; +package org.apache.qpid.server.jmx.mbeans; import org.apache.log4j.Logger; import org.apache.qpid.management.common.mbeans.UserManagement; import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription; -import org.apache.qpid.management.common.mbeans.annotations.MBeanOperation; -import org.apache.qpid.server.management.AMQManagedObject; -import org.apache.qpid.server.security.auth.database.PrincipalDatabase; -import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; +import org.apache.qpid.server.jmx.AMQManagedObject; +import org.apache.qpid.server.jmx.ManagedObject; +import org.apache.qpid.server.jmx.ManagedObjectRegistry; +import org.apache.qpid.server.model.PasswordCredentialManagingAuthenticationProvider; import javax.management.JMException; import javax.management.openmbean.CompositeData; @@ -40,17 +40,16 @@ import javax.management.openmbean.TabularData; import javax.management.openmbean.TabularDataSupport; import javax.management.openmbean.TabularType; import javax.security.auth.login.AccountNotFoundException; + import java.io.IOException; -import java.security.Principal; -import java.util.List; +import java.util.Map; -/** MBean class for AMQUserManagementMBean. It implements all the management features exposed for managing users. */ @MBeanDescription("User Management Interface") -public class AMQUserManagementMBean extends AMQManagedObject implements UserManagement +public class UserManagementMBean extends AMQManagedObject implements UserManagement { - private static final Logger _logger = Logger.getLogger(AMQUserManagementMBean.class); + private static final Logger _logger = Logger.getLogger(UserManagementMBean.class); - private PrincipalDatabase _principalDatabase; + private PasswordCredentialManagingAuthenticationProvider _authProvider; // Setup for the TabularType private static final TabularType _userlistDataType; // Datatype for representing User Lists @@ -79,45 +78,46 @@ public class AMQUserManagementMBean extends AMQManagedObject implements UserMana } } - public AMQUserManagementMBean() throws JMException + public UserManagementMBean(PasswordCredentialManagingAuthenticationProvider provider, ManagedObjectRegistry registry) throws JMException { - super(UserManagement.class, UserManagement.TYPE); + super(UserManagement.class, UserManagement.TYPE, registry); + register(); + _authProvider = provider; } + @Override public String getObjectInstanceName() { return UserManagement.TYPE; } + @Override public boolean setPassword(String username, String password) { try { - //delegate password changes to the Principal Database - return _principalDatabase.updatePassword(new UsernamePrincipal(username), password.toCharArray()); + _authProvider.setPassword(username, password); } catch (AccountNotFoundException e) { - _logger.warn("Attempt to set password of non-existent user'" + username + "'"); + _logger.warn("Attempt to set password of non-existent user '" + username + "'"); return false; } + return true; } + @Override public boolean createUser(String username, String password) { - if (_principalDatabase.createPrincipal(new UsernamePrincipal(username), password.toCharArray())) - { - return true; - } - - return false; + return _authProvider.createUser(username, password, null); } + @Override public boolean deleteUser(String username) { try { - _principalDatabase.deletePrincipal(new UsernamePrincipal(username)); + _authProvider.deleteUser(username); } catch (AccountNotFoundException e) { @@ -128,37 +128,36 @@ public class AMQUserManagementMBean extends AMQManagedObject implements UserMana return true; } + @Override public boolean reloadData() { try { - _principalDatabase.reload(); + _authProvider.reload(); + return true; } catch (IOException e) { - _logger.warn("Reload failed due to:", e); + _logger.error("Unable to reload user data", e); return false; } - // Reload successful - return true; } - - @MBeanOperation(name = "viewUsers", description = "All users that are currently available to the system.") + @Override public TabularData viewUsers() { - List<Principal> users = _principalDatabase.getUsers(); + Map<String, Map<String, String>> users = _authProvider.getUsers(); TabularDataSupport userList = new TabularDataSupport(_userlistDataType); try { // Create the tabular list of message header contents - for (Principal user : users) + for (String user : users.keySet()) { // Create header attributes list - // Read,Write,Admin items are depcreated and we return always false. - Object[] itemData = {user.getName(), false, false, false}; + // Read,Write,Admin items are deprecated and we return always false. + Object[] itemData = {user, false, false, false}; CompositeData messageData = new CompositeDataSupport(_userDataType, COMPOSITE_ITEM_NAMES.toArray(new String[COMPOSITE_ITEM_NAMES.size()]), itemData); userList.put(messageData); } @@ -172,15 +171,9 @@ public class AMQUserManagementMBean extends AMQManagedObject implements UserMana return userList; } - /*** Broker Methods **/ - - /** - * setPrincipalDatabase - * - * @param database set The Database to use for user lookup - */ - public void setPrincipalDatabase(PrincipalDatabase database) + @Override + public ManagedObject getParentObject() { - _principalDatabase = database; + return null; } } diff --git a/qpid/java/broker-plugins/jmx/src/main/java/org/apache/qpid/server/jmx/mbeans/VirtualHostMBean.java b/qpid/java/broker-plugins/jmx/src/main/java/org/apache/qpid/server/jmx/mbeans/VirtualHostMBean.java new file mode 100644 index 0000000000..85f53d9c0d --- /dev/null +++ b/qpid/java/broker-plugins/jmx/src/main/java/org/apache/qpid/server/jmx/mbeans/VirtualHostMBean.java @@ -0,0 +1,208 @@ +/* + * + * 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.jmx.mbeans; + +import org.apache.qpid.server.jmx.AMQManagedObject; +import org.apache.qpid.server.jmx.ManagedObject; +import org.apache.qpid.server.jmx.ManagedObjectRegistry; +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.Exchange; +import org.apache.qpid.server.model.Queue; +import org.apache.qpid.server.model.State; +import org.apache.qpid.server.model.VirtualHost; +import org.apache.qpid.server.virtualhost.ManagedVirtualHost; + +import javax.management.JMException; +import javax.management.ObjectName; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +public class VirtualHostMBean extends AMQManagedObject implements ManagedVirtualHost, ConfigurationChangeListener +{ + private final VirtualHost _virtualHost; + + private final Map<ConfiguredObject, AMQManagedObject> _children = + new HashMap<ConfiguredObject, AMQManagedObject>(); + private VirtualHostManagerMBean _managerMBean; + + public VirtualHostMBean(VirtualHost virtualHost, ManagedObjectRegistry registry) throws JMException + { + super(ManagedVirtualHost.class, ManagedVirtualHost.TYPE, registry); + _virtualHost = virtualHost; + virtualHost.addChangeListener(this); + + initQueues(); + initExchanges(); + initConnections(); + + //This is the actual JMX bean for this 'VirtualHostMBean', leave it alone. + _managerMBean = new VirtualHostManagerMBean(this); + } + + private void initQueues() throws JMException + { + synchronized (_children) + { + for(Queue queue : _virtualHost.getQueues()) + { + if(!_children.containsKey(queue)) + { + _children.put(queue, new QueueMBean(queue, this)); + } + } + } + } + + private void initExchanges() throws JMException + { + synchronized (_children) + { + for(Exchange exchange : _virtualHost.getExchanges()) + { + if(!_children.containsKey(exchange)) + { + _children.put(exchange, new ExchangeMBean(exchange, this)); + } + } + } + } + + private void initConnections() throws JMException + { + synchronized (_children) + { + for(Connection conn : _virtualHost.getConnections()) + { + if(!_children.containsKey(conn)) + { + _children.put(conn, new ConnectionMBean(conn, this)); + } + } + } + } + + public String getObjectInstanceName() + { + return ObjectName.quote(_virtualHost.getName()); + } + + public String getName() + { + return _virtualHost.getName(); + } + + public void stateChanged(ConfiguredObject object, State oldState, State newState) + { + // ignore + } + + public void childAdded(ConfiguredObject object, ConfiguredObject child) + { + synchronized (_children) + { + try + { + if(child instanceof Queue) + { + QueueMBean queueMB = new QueueMBean((Queue)child, this); + _children.put(child, queueMB); + + } + else if(child instanceof Exchange) + { + ExchangeMBean exchangeMBean = new ExchangeMBean((Exchange)child, this); + _children.put(child, exchangeMBean); + + } + else if(child instanceof Connection) + { + ConnectionMBean connectionMBean = new ConnectionMBean((Connection)child, this); + _children.put(child, connectionMBean); + + } + else + { + // TODO + } + + } + catch(JMException e) + { + e.printStackTrace(); //TODO - report error on adding child MBean + } + } + } + + public void childRemoved(ConfiguredObject object, ConfiguredObject child) + { + synchronized (_children) + { + AMQManagedObject mbean = _children.remove(child); + if(mbean != null) + { + try + { + mbean.unregister(); + } + catch(JMException e) + { + e.printStackTrace(); //TODO - report error on removing child MBean + } + } + } + } + + @Override + public ManagedObject getParentObject() + { + return null; + } + + protected VirtualHost getVirtualHost() + { + return _virtualHost; + } + + public Collection<QueueMBean> getQueues() + { + Collection<AMQManagedObject> children; + synchronized (_children) + { + children = new ArrayList<AMQManagedObject>(_children.values()); + } + Collection<QueueMBean> queues = new ArrayList<QueueMBean>(); + + for(AMQManagedObject child : children) + { + if(child instanceof QueueMBean) + { + queues.add((QueueMBean) child); + } + } + + return queues; + } +} diff --git a/qpid/java/broker-plugins/jmx/src/main/java/org/apache/qpid/server/jmx/mbeans/VirtualHostManagerMBean.java b/qpid/java/broker-plugins/jmx/src/main/java/org/apache/qpid/server/jmx/mbeans/VirtualHostManagerMBean.java new file mode 100644 index 0000000000..7ccb706c80 --- /dev/null +++ b/qpid/java/broker-plugins/jmx/src/main/java/org/apache/qpid/server/jmx/mbeans/VirtualHostManagerMBean.java @@ -0,0 +1,239 @@ +/* + * + * 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.jmx.mbeans; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.management.JMException; +import javax.management.MBeanException; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; + +import org.apache.log4j.Logger; +import org.apache.qpid.management.common.mbeans.ManagedBroker; +import org.apache.qpid.management.common.mbeans.ManagedQueue; +import org.apache.qpid.management.common.mbeans.annotations.MBeanConstructor; +import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription; +import org.apache.qpid.management.common.mbeans.annotations.MBeanOperationParameter; +import org.apache.qpid.server.jmx.ManagedObject; +import org.apache.qpid.server.model.Exchange; +import org.apache.qpid.server.model.LifetimePolicy; +import org.apache.qpid.server.model.Queue; +import org.apache.qpid.server.model.State; +import org.apache.qpid.server.model.VirtualHost; +import org.apache.qpid.server.queue.AMQQueueFactory; + +@MBeanDescription("This MBean exposes the broker level management features") +public class VirtualHostManagerMBean extends AbstractStatisticsGatheringMBean<VirtualHost> implements ManagedBroker +{ + private static final Logger LOGGER = Logger.getLogger(VirtualHostManagerMBean.class); + + private static final boolean _moveNonExclusiveQueueOwnerToDescription = Boolean.parseBoolean(System.getProperty("qpid.move_non_exclusive_queue_owner_to_description", Boolean.TRUE.toString())); + + private final VirtualHostMBean _virtualHostMBean; + + @MBeanConstructor("Creates the Broker Manager MBean") + public VirtualHostManagerMBean(VirtualHostMBean virtualHostMBean) throws JMException + { + super(ManagedBroker.class, ManagedBroker.TYPE, virtualHostMBean.getRegistry(), virtualHostMBean.getVirtualHost()); + _virtualHostMBean = virtualHostMBean; + register(); + } + + + public String getObjectInstanceName() + { + return ObjectName.quote(_virtualHostMBean.getName()); + } + + @Override + public ManagedObject getParentObject() + { + return _virtualHostMBean; + } + + public String[] getExchangeTypes() throws IOException + { + Collection<String> exchangeTypes = _virtualHostMBean.getVirtualHost().getExchangeTypes(); + return exchangeTypes.toArray(new String[exchangeTypes.size()]); + } + + public List<String> retrieveQueueAttributeNames() throws IOException + { + return ManagedQueue.QUEUE_ATTRIBUTES; + } + + public List<List<Object>> retrieveQueueAttributeValues( + @MBeanOperationParameter(name = "attributes", description = "Attributes to retrieve") String[] attributes) + throws IOException + { + int attributesLength = attributes.length; + + List<List<Object>> queueAttributesList = new ArrayList<List<Object>>(); + + for(QueueMBean queue : _virtualHostMBean.getQueues()) + { + + if(queue == null) + { + continue; + } + + List<Object> attributeValues = new ArrayList<Object>(attributesLength); + + for(int i=0; i < attributesLength; i++) + { + try + { + attributeValues.add(queue.getAttribute(attributes[i])); + } + catch (Exception e) + { + attributeValues.add("-"); + } + } + + queueAttributesList.add(attributeValues); + } + + return queueAttributesList; + + } + + public void createNewExchange(String name, String type, boolean durable) + throws IOException, JMException, MBeanException + { + getConfiguredObject().createExchange(name, State.ACTIVE, durable, + LifetimePolicy.PERMANENT, 0l, type, Collections.EMPTY_MAP); + + } + + public void unregisterExchange(String exchangeName) + throws IOException, JMException, MBeanException + { + Exchange theExchange = null; + for(Exchange exchange : _virtualHostMBean.getVirtualHost().getExchanges()) + { + if(exchange.getName().equals(exchangeName)) + { + theExchange = exchange; + break; + } + } + if(theExchange != null) + { + try + { + theExchange.delete(); + } + catch (IllegalStateException ex) + { + final JMException jme = new JMException(ex.toString()); + throw new MBeanException(jme, "Error in unregistering exchange " + exchangeName); + } + } + } + + public void createNewQueue(String queueName, String owner, boolean durable) + throws IOException, JMException, MBeanException + { + createNewQueue(queueName, owner, durable, Collections.EMPTY_MAP); + } + + public void createNewQueue(String queueName, String owner, boolean durable, Map<String, Object> originalArguments) + throws IOException, JMException + { + final Map<String, Object> createArgs = processNewQueueArguments(queueName, owner, originalArguments); + getConfiguredObject().createQueue(queueName, State.ACTIVE, durable, false, LifetimePolicy.PERMANENT, 0l, createArgs); + } + + + /** + * Some users have been abusing the owner field to store a queue description. As the owner field + * only makes sense if exclusive=true, and it is currently impossible to create an exclusive queue via + * the JMX interface, if the user specifies a owner, then we assume that they actually mean to pass a description. + */ + private Map<String, Object> processNewQueueArguments(String queueName, + String owner, Map<String, Object> arguments) + { + final Map<String, Object> argumentsCopy; + if (_moveNonExclusiveQueueOwnerToDescription && owner != null) + { + argumentsCopy = new HashMap<String, Object>(arguments == null ? new HashMap<String, Object>() : arguments); + if (!argumentsCopy.containsKey(AMQQueueFactory.X_QPID_DESCRIPTION)) + { + LOGGER.warn("Non-exclusive owner " + owner + " for new queue " + queueName + " moved to " + AMQQueueFactory.X_QPID_DESCRIPTION); + + argumentsCopy.put(AMQQueueFactory.X_QPID_DESCRIPTION, owner); + } + else + { + LOGGER.warn("Non-exclusive owner " + owner + " for new queue " + queueName + " ignored."); + } + } + else + { + argumentsCopy = arguments; + } + return argumentsCopy; + } + + public void deleteQueue( + @MBeanOperationParameter(name = ManagedQueue.TYPE, description = "Queue Name") String queueName) + throws IOException, JMException, MBeanException + { + Queue theQueue = null; + for(Queue queue : _virtualHostMBean.getVirtualHost().getQueues()) + { + if(queue.getName().equals(queueName)) + { + theQueue = queue; + break; + } + } + if(theQueue != null) + { + theQueue.delete(); + } + } + + + @Override + public ObjectName getObjectName() throws MalformedObjectNameException + { + return getObjectNameForSingleInstanceMBean(); + } + + + public synchronized boolean isStatisticsEnabled() + { + updateStats(); + return false; //TODO - implement isStatisticsEnabled + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/NoopManagedObjectRegistry.java b/qpid/java/broker-plugins/jmx/src/test/java/org/apache/qpid/server/jmx/NoopManagedObjectRegistry.java index e77350c3e4..a2631bab7f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/NoopManagedObjectRegistry.java +++ b/qpid/java/broker-plugins/jmx/src/test/java/org/apache/qpid/server/jmx/NoopManagedObjectRegistry.java @@ -18,29 +18,18 @@ * under the License. * */ -package org.apache.qpid.server.management; - -import org.apache.log4j.Logger; +package org.apache.qpid.server.jmx; import javax.management.JMException; -/** - * This managed object registry does not actually register MBeans. This can be used in tests when management is - * not required or when management has been disabled. - * - */ public class NoopManagedObjectRegistry implements ManagedObjectRegistry { - private static final Logger _log = Logger.getLogger(NoopManagedObjectRegistry.class); - public NoopManagedObjectRegistry() { - _log.info("Management is disabled"); } public void start() { - //no-op } public void registerObject(ManagedObject managedObject) throws JMException @@ -53,6 +42,5 @@ public class NoopManagedObjectRegistry implements ManagedObjectRegistry public void close() { - } } diff --git a/qpid/java/broker-plugins/jmx/src/test/java/org/apache/qpid/server/jmx/mbeans/ConnectionMBeanTest.java b/qpid/java/broker-plugins/jmx/src/test/java/org/apache/qpid/server/jmx/mbeans/ConnectionMBeanTest.java new file mode 100644 index 0000000000..f294c85c99 --- /dev/null +++ b/qpid/java/broker-plugins/jmx/src/test/java/org/apache/qpid/server/jmx/mbeans/ConnectionMBeanTest.java @@ -0,0 +1,235 @@ +/* + * 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.jmx.mbeans; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.Collections; +import java.util.Date; + +import javax.management.JMException; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.TabularData; + +import junit.framework.TestCase; + +import org.apache.commons.beanutils.PropertyUtils; +import org.apache.qpid.management.common.mbeans.ManagedConnection; +import org.apache.qpid.server.jmx.ManagedObject; +import org.apache.qpid.server.jmx.ManagedObjectRegistry; +import org.apache.qpid.server.model.Connection; +import org.apache.qpid.server.model.Session; +import org.apache.qpid.server.model.Statistics; + +public class ConnectionMBeanTest extends TestCase +{ + private ConnectionMBean _connectionMBean; + private Connection _mockConnection; + private VirtualHostMBean _mockVirtualHostMBean; + private ManagedObjectRegistry _mockManagedObjectRegistry; + + @Override + protected void setUp() throws Exception + { + _mockConnection = mock(Connection.class); + _mockVirtualHostMBean = mock(VirtualHostMBean.class); + + _mockManagedObjectRegistry = mock(ManagedObjectRegistry.class); + when(_mockVirtualHostMBean.getRegistry()).thenReturn(_mockManagedObjectRegistry); + + _connectionMBean = new ConnectionMBean(_mockConnection, _mockVirtualHostMBean); + } + + public void testMBeanRegistersItself() throws Exception + { + ConnectionMBean connectionMBean = new ConnectionMBean(_mockConnection, _mockVirtualHostMBean); + verify(_mockManagedObjectRegistry).registerObject(connectionMBean); + } + + public void testCloseConnection() throws Exception + { + _connectionMBean.closeConnection(); + verify(_mockConnection).delete(); + } + + public void testCommitTransactions() + { + try + { + _connectionMBean.commitTransactions(0); + fail("Exception not thrown"); + } + catch(JMException e) + { + assertTrue("Cause should be an UnsupportedOperationException", e.getCause() instanceof UnsupportedOperationException); + } + } + + public void testRollbackTransactions() + { + try + { + _connectionMBean.rollbackTransactions(0); + fail("Exception not thrown"); + } + catch(JMException e) + { + assertTrue("Cause should be an UnsupportedOperationException", e.getCause() instanceof UnsupportedOperationException); + } + } + + public void testChannelsWithSingleTransactionalSession() throws Exception + { + int channelId = 10; + int unacknowledgedMessages = 2; + long localTransactionBegins = 1; + boolean transactional = true; + boolean blocked = false; + + Session mockSession = createMockedSession(channelId, unacknowledgedMessages, localTransactionBegins, blocked); + + when(_mockConnection.getSessions()).thenReturn(Collections.singletonList(mockSession)); + + TabularData table = _connectionMBean.channels(); + assertEquals("Unexpected number of rows in table", 1, table.size()); + + final CompositeData row = table.get(new Integer[] {channelId} ); + assertChannelRow(row, channelId, unacknowledgedMessages, transactional, blocked); + } + + public void testChannelsWithSingleNonTransactionalSession() throws Exception + { + int channelId = 10; + int unacknowledgedMessages = 2; + long localTransactionBegins = 0; + boolean transactional = false; + boolean blocked = false; + + Session mockSession = createMockedSession(channelId, unacknowledgedMessages, localTransactionBegins, blocked); + + when(_mockConnection.getSessions()).thenReturn(Collections.singletonList(mockSession)); + + TabularData table = _connectionMBean.channels(); + assertEquals("Unexpected number of rows in table", 1, table.size()); + + final CompositeData row = table.get(new Integer[] {channelId} ); + assertChannelRow(row, channelId, unacknowledgedMessages, transactional, blocked); + } + + public void testChannelsWithSessionBlocked() throws Exception + { + int channelId = 10; + int unacknowledgedMessages = 2; + long localTransactionBegins = 0; + boolean transactional = false; + boolean blocked = true; + + Session mockSession = createMockedSession(channelId, unacknowledgedMessages, localTransactionBegins, blocked); + + when(_mockConnection.getSessions()).thenReturn(Collections.singletonList(mockSession)); + + TabularData table = _connectionMBean.channels(); + assertEquals("Unexpected number of rows in table", 1, table.size()); + + final CompositeData row = table.get(new Integer[] {channelId} ); + assertChannelRow(row, channelId, unacknowledgedMessages, transactional, blocked); + } + + public void testParentObjectIsVirtualHost() + { + ManagedObject parent = _connectionMBean.getParentObject(); + assertEquals(_mockVirtualHostMBean, parent); + } + + public void testGetObjectInstanceName() + { + String remoteAddress = "testRemoteAddress"; + String quotedRemoteAddress = "\"testRemoteAddress\""; + when(_mockConnection.getAttribute(Connection.REMOTE_ADDRESS)).thenReturn(remoteAddress); + String objectInstanceName = _connectionMBean.getObjectInstanceName(); + assertEquals(quotedRemoteAddress, objectInstanceName); + } + + public void testGetAuthorizedId() throws Exception + { + assertAttribute("authorizedId", "testAuthorizedId", Connection.PRINCIPAL); + } + + public void testGetVersion() throws Exception + { + assertAttribute("version", "testVersion", Connection.CLIENT_VERSION); + } + + public void testGetRemoteAddress() throws Exception + { + assertAttribute("remoteAddress", "testRemoteAddress", Connection.REMOTE_ADDRESS); + } + + public void testGetLastIoTime() + { + Statistics mockStatistics = mock(Statistics.class); + when(_mockConnection.getStatistics()).thenReturn(mockStatistics); + when(mockStatistics.getStatistic(Connection.LAST_IO_TIME)).thenReturn(1L); + + Object actualValue = _connectionMBean.getLastIoTime(); + assertEquals("Unexpected lastIoTime", new Date(1L), actualValue); + } + + public void testGetMaximumNumberOfChannels() throws Exception + { + assertAttribute("maximumNumberOfChannels", 10l, Connection.SESSION_COUNT_LIMIT); + } + + public void testIsStatisticsEnabledAlwaysTrue() throws Exception + { + assertTrue(_connectionMBean.isStatisticsEnabled()); + } + + private void assertAttribute(String jmxAttributeName, Object expectedValue, String underlyingAttributeName) throws Exception + { + when(_mockConnection.getAttribute(underlyingAttributeName)).thenReturn(expectedValue); + + Object actualValue = PropertyUtils.getSimpleProperty(_connectionMBean, jmxAttributeName); + assertEquals("Unexpected " + jmxAttributeName, expectedValue, actualValue); + } + + private void assertChannelRow(final CompositeData row, int channelId, int unacknowledgedMessages, boolean isTransactional, boolean flowBlocked) + { + assertNotNull("No row for channel id " + channelId, row); + assertEquals("Unexpected channel id", channelId, row.get(ManagedConnection.CHAN_ID)); + assertEquals("Unexpected transactional flag", isTransactional, row.get(ManagedConnection.TRANSACTIONAL)); + assertEquals("Unexpected unacknowledged message count", unacknowledgedMessages, row.get(ManagedConnection.UNACKED_COUNT)); + assertEquals("Unexpected flow blocked", flowBlocked, row.get(ManagedConnection.FLOW_BLOCKED)); + } + + private Session createMockedSession(int channelId, int unacknowledgedMessages, long localTransactionBegins, boolean blocked) + { + Session mockSession = mock(Session.class); + Statistics mockSessionStatistics = mock(Statistics.class); + when(mockSessionStatistics.getStatistic(Session.LOCAL_TRANSACTION_BEGINS)).thenReturn(localTransactionBegins); + when(mockSessionStatistics.getStatistic(Session.UNACKNOWLEDGED_MESSAGES)).thenReturn(unacknowledgedMessages); + + when(mockSession.getStatistics()).thenReturn(mockSessionStatistics); + when(mockSession.getAttribute(Session.CHANNEL_ID)).thenReturn(channelId); + when(mockSession.getAttribute(Session.PRODUCER_FLOW_BLOCKED)).thenReturn(blocked); + return mockSession; + } +} diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/logging/management/LoggingManagementMBeanTest.java b/qpid/java/broker-plugins/jmx/src/test/java/org/apache/qpid/server/jmx/mbeans/LoggingManagementMBeanTest.java index f9ad81ae74..64b942c9a9 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/logging/management/LoggingManagementMBeanTest.java +++ b/qpid/java/broker-plugins/jmx/src/test/java/org/apache/qpid/server/jmx/mbeans/LoggingManagementMBeanTest.java @@ -14,15 +14,18 @@ * "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. + * under the License. + * * - * */ -package org.apache.qpid.server.logging.management; +package org.apache.qpid.server.jmx.mbeans; + +import static org.mockito.Mockito.*; import org.apache.log4j.Level; import org.apache.log4j.Logger; +import org.apache.qpid.server.jmx.ManagedObjectRegistry; import org.apache.qpid.server.util.InternalBrokerBaseCase; import static org.apache.qpid.management.common.mbeans.LoggingManagement.LOGGER_LEVEL; @@ -41,6 +44,7 @@ import java.util.Map; public class LoggingManagementMBeanTest extends InternalBrokerBaseCase { + private static final String TEST_LOGGER = "LoggingManagementMBeanTestLogger"; private static final String TEST_LOGGER_CHILD1 = "LoggingManagementMBeanTestLogger.child1"; private static final String TEST_LOGGER_CHILD2 = "LoggingManagementMBeanTestLogger.child2"; @@ -53,13 +57,15 @@ public class LoggingManagementMBeanTest extends InternalBrokerBaseCase private File _testConfigFile; + private ManagedObjectRegistry _registry = mock(ManagedObjectRegistry.class); + @Override public void setUp() throws Exception { super.setUp(); _testConfigFile = createTempTestLog4JConfig(); } - + @Override public void tearDown() throws Exception { @@ -68,9 +74,9 @@ public class LoggingManagementMBeanTest extends InternalBrokerBaseCase { oldTestConfigFile.delete(); } - + _testConfigFile.delete(); - + super.tearDown(); } @@ -89,7 +95,7 @@ public class LoggingManagementMBeanTest extends InternalBrokerBaseCase writer.write("<!DOCTYPE log4j:configuration SYSTEM \"log4j.dtd\">"+NEWLINE); writer.write("<log4j:configuration xmlns:log4j=\"http://jakarta.apache.org/log4j/\" debug=\"null\" " + - "threshold=\"null\">"+NEWLINE); + "threshold=\"null\">"+NEWLINE); writer.write(" <appender class=\"org.apache.log4j.ConsoleAppender\" name=\"STDOUT\">"+NEWLINE); writer.write(" <layout class=\"org.apache.log4j.PatternLayout\">"+NEWLINE); @@ -137,13 +143,13 @@ public class LoggingManagementMBeanTest extends InternalBrokerBaseCase //******* Test Methods ******* // - + public void testSetRuntimeLoggerLevel() { LoggingManagementMBean lm = null; try { - lm = new LoggingManagementMBean(_testConfigFile.getAbsolutePath(), 0); + lm = new LoggingManagementMBean(_testConfigFile.getAbsolutePath(), 0, _registry); } catch (JMException e) { @@ -156,26 +162,26 @@ public class LoggingManagementMBeanTest extends InternalBrokerBaseCase //create child1 test logger, check its *effective* level is the same as the parent, "info" Logger log1 = Logger.getLogger(TEST_LOGGER_CHILD1); - assertTrue("Test logger's level was not the expected value", + assertTrue("Test logger's level was not the expected value", log1.getEffectiveLevel().toString().equalsIgnoreCase("info")); //now change its level to "warn" assertTrue("Failed to set logger level", lm.setRuntimeLoggerLevel(TEST_LOGGER_CHILD1, "warn")); //check the change, see its actual level is "warn - assertTrue("Test logger's level was not the expected value", + assertTrue("Test logger's level was not the expected value", log1.getLevel().toString().equalsIgnoreCase("warn")); //try an invalid level assertFalse("Trying to set an invalid level succeded", lm.setRuntimeLoggerLevel(TEST_LOGGER_CHILD1, "made.up.level")); } - + public void testSetRuntimeRootLoggerLevel() { LoggingManagementMBean lm = null; try { - lm = new LoggingManagementMBean(_testConfigFile.getAbsolutePath(), 0); + lm = new LoggingManagementMBean(_testConfigFile.getAbsolutePath(), 0, _registry); } catch (JMException e) { @@ -183,27 +189,27 @@ public class LoggingManagementMBeanTest extends InternalBrokerBaseCase } Logger log = Logger.getRootLogger(); - + //get current root logger level Level origLevel = log.getLevel(); - + //change level twice to ensure a new level is actually selected - + //set root loggers level to info assertTrue("Failed to set root logger level", lm.setRuntimeRootLoggerLevel("debug")); //check it is now actually info Level currentLevel = log.getLevel(); assertTrue("Logger level was not expected value", currentLevel.equals(Level.toLevel("debug"))); - + //try an invalid level assertFalse("Trying to set an invalid level succeded", lm.setRuntimeRootLoggerLevel("made.up.level")); - + //set root loggers level to warn assertTrue("Failed to set logger level", lm.setRuntimeRootLoggerLevel("info")); //check it is now actually warn currentLevel = log.getLevel(); assertTrue("Logger level was not expected value", currentLevel.equals(Level.toLevel("info"))); - + //restore original level log.setLevel(origLevel); } @@ -213,7 +219,7 @@ public class LoggingManagementMBeanTest extends InternalBrokerBaseCase LoggingManagementMBean lm = null; try { - lm = new LoggingManagementMBean(_testConfigFile.getAbsolutePath(), 0); + lm = new LoggingManagementMBean(_testConfigFile.getAbsolutePath(), 0, _registry); } catch (JMException e) { @@ -221,18 +227,18 @@ public class LoggingManagementMBeanTest extends InternalBrokerBaseCase } Logger log = Logger.getRootLogger(); - + //get current root logger level Level origLevel = log.getLevel(); - + //change level twice to ensure a new level is actually selected - + //set root loggers level to debug log.setLevel(Level.toLevel("debug")); //check it is now actually debug assertTrue("Logger level was not expected value", lm.getRuntimeRootLoggerLevel().equalsIgnoreCase("debug")); - - + + //set root loggers level to warn log.setLevel(Level.toLevel("info")); //check it is now actually warn @@ -241,13 +247,13 @@ public class LoggingManagementMBeanTest extends InternalBrokerBaseCase //restore original level log.setLevel(origLevel); } - + public void testViewEffectiveRuntimeLoggerLevels() { LoggingManagementMBean lm = null; try { - lm = new LoggingManagementMBean(_testConfigFile.getAbsolutePath(), 0); + lm = new LoggingManagementMBean(_testConfigFile.getAbsolutePath(), 0, _registry); } catch (JMException e) { @@ -257,7 +263,7 @@ public class LoggingManagementMBeanTest extends InternalBrokerBaseCase //(re)create a parent test logger, set its level explicitly Logger log = Logger.getLogger(TEST_LOGGER); log.setLevel(Level.toLevel("info")); - + //retrieve the current effective runtime logger level values TabularDataSupport levels = (TabularDataSupport) lm.viewEffectiveRuntimeLoggerLevels(); Collection<Object> records = levels.values(); @@ -267,13 +273,13 @@ public class LoggingManagementMBeanTest extends InternalBrokerBaseCase CompositeData data = (CompositeData) o; list.put(data.get(LOGGER_NAME).toString(), data.get(LOGGER_LEVEL).toString()); } - + //check child2 does not exist already assertFalse("Did not expect this logger to exist already", list.containsKey(TEST_LOGGER_CHILD2)); //create child2 test logger Logger log2 = Logger.getLogger(TEST_LOGGER_CHILD2); - + //retrieve the current effective runtime logger level values levels = (TabularDataSupport) lm.viewEffectiveRuntimeLoggerLevels(); records = levels.values(); @@ -287,14 +293,14 @@ public class LoggingManagementMBeanTest extends InternalBrokerBaseCase //verify the parent and child2 loggers are present in returned values assertTrue(TEST_LOGGER + " logger was not in the returned list", list.containsKey(TEST_LOGGER)); assertTrue(TEST_LOGGER_CHILD2 + " logger was not in the returned list", list.containsKey(TEST_LOGGER_CHILD2)); - + //check child2's effective level is the same as the parent, "info" - assertTrue("Test logger's level was not the expected value", + assertTrue("Test logger's level was not the expected value", list.get(TEST_LOGGER_CHILD2).equalsIgnoreCase("info")); //now change its level explicitly to "warn" log2.setLevel(Level.toLevel("warn")); - + //retrieve the current effective runtime logger level values levels = (TabularDataSupport) lm.viewEffectiveRuntimeLoggerLevels(); records = levels.values(); @@ -306,7 +312,7 @@ public class LoggingManagementMBeanTest extends InternalBrokerBaseCase } //check child2's effective level is now "warn" - assertTrue("Test logger's level was not the expected value", + assertTrue("Test logger's level was not the expected value", list.get(TEST_LOGGER_CHILD2).equalsIgnoreCase("warn")); } @@ -315,7 +321,7 @@ public class LoggingManagementMBeanTest extends InternalBrokerBaseCase LoggingManagementMBean lm =null; try { - lm = new LoggingManagementMBean(_testConfigFile.getAbsolutePath(), 0); + lm = new LoggingManagementMBean(_testConfigFile.getAbsolutePath(), 0, _registry); } catch (JMException e) { @@ -378,13 +384,13 @@ public class LoggingManagementMBeanTest extends InternalBrokerBaseCase assertTrue(TEST_CATEGORY_LEVEL + " logger's level was incorrect", list.get(TEST_CATEGORY_LEVEL).equalsIgnoreCase("error")); assertTrue(TEST_LOGGER_LEVEL + " logger's level was incorrect", list.get(TEST_LOGGER_LEVEL).equalsIgnoreCase("trace")); } - + public void testGetAndSetConfigFileRootLoggerLevel() throws Exception { LoggingManagementMBean lm =null; try { - lm = new LoggingManagementMBean(_testConfigFile.getAbsolutePath(), 0); + lm = new LoggingManagementMBean(_testConfigFile.getAbsolutePath(), 0, _registry); } catch (JMException e) { @@ -399,7 +405,7 @@ public class LoggingManagementMBeanTest extends InternalBrokerBaseCase //try an invalid level assertFalse("Use of an invalid RootLogger level was successfull", lm.setConfigFileRootLoggerLevel("made.up.level")); - + //change the level to warn assertTrue("Failed to set new RootLogger level", lm.setConfigFileRootLoggerLevel("warn")); @@ -415,7 +421,7 @@ public class LoggingManagementMBeanTest extends InternalBrokerBaseCase LoggingManagementMBean lm =null; try { - lm = new LoggingManagementMBean(_testConfigFile.getAbsolutePath(), 5000); + lm = new LoggingManagementMBean(_testConfigFile.getAbsolutePath(), 5000, _registry); } catch (JMException e) { diff --git a/qpid/java/broker-plugins/jmx/src/test/java/org/apache/qpid/server/jmx/mbeans/QueueMBeanTest.java b/qpid/java/broker-plugins/jmx/src/test/java/org/apache/qpid/server/jmx/mbeans/QueueMBeanTest.java new file mode 100644 index 0000000000..ceaad0d29b --- /dev/null +++ b/qpid/java/broker-plugins/jmx/src/test/java/org/apache/qpid/server/jmx/mbeans/QueueMBeanTest.java @@ -0,0 +1,202 @@ +/* + * 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.jmx.mbeans; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.mockito.Mockito.verify; +import static org.mockito.Matchers.isNull; +import static org.mockito.Matchers.argThat; + +import java.util.Arrays; +import java.util.Collections; + +import javax.management.ListenerNotFoundException; +import javax.management.Notification; +import javax.management.NotificationListener; +import javax.management.OperationsException; + +import org.apache.qpid.server.jmx.ManagedObjectRegistry; +import org.apache.qpid.server.model.Exchange; +import org.apache.qpid.server.model.Queue; +import org.apache.qpid.server.model.VirtualHost; +import org.apache.qpid.server.queue.NotificationCheck; +import org.mockito.ArgumentMatcher; + +import junit.framework.TestCase; + +public class QueueMBeanTest extends TestCase +{ + private static final String QUEUE_NAME = "QUEUE_NAME"; + private static final String QUEUE_DESCRIPTION = "QUEUE_DESCRIPTION"; + private static final String QUEUE_TYPE = "QUEUE_TYPE"; + private static final String QUEUE_ALTERNATE_EXCHANGE = "QUEUE_ALTERNATE_EXCHANGE"; + + private Queue _mockQueue; + private VirtualHostMBean _mockVirtualHostMBean; + private ManagedObjectRegistry _mockManagedObjectRegistry; + private QueueMBean _queueMBean; + + @Override + protected void setUp() throws Exception + { + _mockQueue = mock(Queue.class); + when(_mockQueue.getName()).thenReturn(QUEUE_NAME); + _mockVirtualHostMBean = mock(VirtualHostMBean.class); + + _mockManagedObjectRegistry = mock(ManagedObjectRegistry.class); + when(_mockVirtualHostMBean.getRegistry()).thenReturn(_mockManagedObjectRegistry); + + _queueMBean = new QueueMBean(_mockQueue, _mockVirtualHostMBean); + } + + public void testQueueName() + { + assertEquals(QUEUE_NAME, _queueMBean.getName()); + } + + public void testGetQueueDescription() + { + when(_mockQueue.getAttribute(Queue.DESCRIPTION)).thenReturn(QUEUE_DESCRIPTION); + + assertEquals(QUEUE_DESCRIPTION, _queueMBean.getDescription()); + } + + public void testSetQueueDescription() + { + _queueMBean.setDescription(QUEUE_DESCRIPTION); + verify(_mockQueue).setAttribute(Queue.DESCRIPTION, null, QUEUE_DESCRIPTION); + } + + public void testQueueType() + { + when(_mockQueue.getAttribute(Queue.TYPE)).thenReturn(QUEUE_TYPE); + + assertEquals(QUEUE_TYPE, _queueMBean.getQueueType()); + } + + public void testGetAlternateExchange() + { + Exchange mockAlternateExchange = mock(Exchange.class); + when(mockAlternateExchange.getName()).thenReturn(QUEUE_ALTERNATE_EXCHANGE); + + when(_mockQueue.getAttribute(Queue.ALTERNATE_EXCHANGE)).thenReturn(mockAlternateExchange); + + assertEquals(QUEUE_ALTERNATE_EXCHANGE, _queueMBean.getAlternateExchange()); + } + + public void testGetAlternateExchangeWhenQueueHasNone() + { + when(_mockQueue.getAttribute(Queue.ALTERNATE_EXCHANGE)).thenReturn(null); + + assertNull(_queueMBean.getAlternateExchange()); + } + + public void testSetAlternateExchange() throws Exception + { + Exchange mockExchange1 = mock(Exchange.class); + when(mockExchange1.getName()).thenReturn("exchange1"); + + Exchange mockExchange2 = mock(Exchange.class); + when(mockExchange2.getName()).thenReturn("exchange2"); + + Exchange mockExchange3 = mock(Exchange.class); + when(mockExchange3.getName()).thenReturn("exchange3"); + + VirtualHost mockVirtualHost = mock(VirtualHost.class); + when(mockVirtualHost.getExchanges()).thenReturn(Arrays.asList(new Exchange[] {mockExchange1, mockExchange2, mockExchange3})); + when(_mockQueue.getParent(VirtualHost.class)).thenReturn(mockVirtualHost); + + _queueMBean.setAlternateExchange("exchange2"); + verify(_mockQueue).setAttribute(Queue.ALTERNATE_EXCHANGE, null, mockExchange2); + } + + public void testSetAlternateExchangeWithUnknownExchangeName() throws Exception + { + Exchange mockExchange = mock(Exchange.class); + when(mockExchange.getName()).thenReturn("exchange1"); + + VirtualHost mockVirtualHost = mock(VirtualHost.class); + when(mockVirtualHost.getExchanges()).thenReturn(Collections.singletonList(mockExchange)); + when(_mockQueue.getParent(VirtualHost.class)).thenReturn(mockVirtualHost); + + try + { + _queueMBean.setAlternateExchange("notknown"); + fail("Exception not thrown"); + } + catch(OperationsException oe) + { + // PASS + } + } + + public void testRemoveAlternateExchange() throws Exception + { + _queueMBean.setAlternateExchange(""); + verify(_mockQueue).setAttribute(Queue.ALTERNATE_EXCHANGE, null, null); + } + + public void testNotificationListenerCalled() throws Exception + { + NotificationListener listener = mock(NotificationListener.class); + _queueMBean.addNotificationListener(listener, null, null); + + NotificationCheck notification = mock(NotificationCheck.class); + String notificationMsg = "Test notification message"; + + _queueMBean.notifyClients(notification, _mockQueue, notificationMsg); + verify(listener).handleNotification(isNotificationWithMessage(notificationMsg), + isNull()); + } + + public void testAddRemoveNotificationListener() throws Exception + { + NotificationListener listener1 = mock(NotificationListener.class); + _queueMBean.addNotificationListener(listener1, null, null); + _queueMBean.removeNotificationListener(listener1); + } + + public void testRemoveUnknownNotificationListener() throws Exception + { + NotificationListener listener1 = mock(NotificationListener.class); + try + { + _queueMBean.removeNotificationListener(listener1); + fail("Exception not thrown"); + } + catch (ListenerNotFoundException e) + { + // PASS + } + } + + private Notification isNotificationWithMessage(final String expectedMessage) + { + return argThat( new ArgumentMatcher<Notification>() + { + @Override + public boolean matches(Object argument) + { + Notification actual = (Notification) argument; + return actual.getMessage().endsWith(expectedMessage); + } + }); + } +} diff --git a/qpid/java/broker-plugins/jmx/src/test/java/org/apache/qpid/server/jmx/mbeans/UserManagementMBeanTest.java b/qpid/java/broker-plugins/jmx/src/test/java/org/apache/qpid/server/jmx/mbeans/UserManagementMBeanTest.java new file mode 100644 index 0000000000..8ca6c521eb --- /dev/null +++ b/qpid/java/broker-plugins/jmx/src/test/java/org/apache/qpid/server/jmx/mbeans/UserManagementMBeanTest.java @@ -0,0 +1,157 @@ +/* + * + * 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.jmx.mbeans; + +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.io.IOException; +import java.util.Collections; +import java.util.Map; + +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.TabularData; +import javax.security.auth.login.AccountNotFoundException; + +import junit.framework.TestCase; + +import org.apache.qpid.management.common.mbeans.UserManagement; +import org.apache.qpid.server.jmx.ManagedObjectRegistry; +import org.apache.qpid.server.model.PasswordCredentialManagingAuthenticationProvider; + +public class UserManagementMBeanTest extends TestCase +{ + private UserManagementMBean _userManagement; + private ManagedObjectRegistry _mockRegistry; + private PasswordCredentialManagingAuthenticationProvider _mockProvider; + + private static final String TEST_USERNAME = "testuser"; + private static final String TEST_PASSWORD = "password"; + + @Override + public void setUp() throws Exception + { + super.setUp(); + + _mockProvider = mock(PasswordCredentialManagingAuthenticationProvider.class); + _mockRegistry = mock(ManagedObjectRegistry.class); + _userManagement = new UserManagementMBean(_mockProvider, _mockRegistry); + } + + public void testMBeanRegistersItself() throws Exception + { + UserManagementMBean userManagementMBean = new UserManagementMBean(_mockProvider, _mockRegistry); + verify(_mockRegistry).registerObject(userManagementMBean); + } + + public void testDeleteUser() throws Exception + { + boolean deleteSuccess = _userManagement.deleteUser(TEST_USERNAME); + assertTrue("Expected successful delete", deleteSuccess); + + verify(_mockProvider).deleteUser(TEST_USERNAME); + } + + public void testDeleteUserWhereUserDoesNotExist() throws Exception + { + doThrow(AccountNotFoundException.class).when(_mockProvider).deleteUser(TEST_USERNAME); + + boolean deleteSuccess = _userManagement.deleteUser(TEST_USERNAME); + assertFalse("Expected unsuccessful delete", deleteSuccess); + } + + public void testCreateUser() throws Exception + { + when(_mockProvider.createUser(TEST_USERNAME, TEST_PASSWORD, null)).thenReturn(true); + + boolean createSuccess = _userManagement.createUser(TEST_USERNAME, TEST_PASSWORD); + assertTrue(createSuccess); + } + + public void testCreateUserWhereUserAlreadyExists() + { + when(_mockProvider.createUser(TEST_USERNAME, TEST_PASSWORD, null)).thenReturn(false); + + boolean createSuccess = _userManagement.createUser(TEST_USERNAME, TEST_PASSWORD); + assertFalse(createSuccess); + } + + public void testSetPassword() throws Exception + { + boolean setPasswordSuccess = _userManagement.setPassword(TEST_USERNAME, TEST_PASSWORD); + assertTrue(setPasswordSuccess); + + assertTrue("Set password should return true to flag successful change", setPasswordSuccess); + + verify(_mockProvider).setPassword(TEST_USERNAME, TEST_PASSWORD); + } + + public void testSetPasswordWhereUserDoesNotExist() throws Exception + { + doThrow(AccountNotFoundException.class).when(_mockProvider).setPassword(TEST_USERNAME, TEST_PASSWORD); + + boolean setPasswordSuccess = _userManagement.setPassword(TEST_USERNAME, TEST_PASSWORD); + + assertFalse("Set password should return false to flag unsuccessful change", setPasswordSuccess); + } + + public void testReload() throws Exception + { + boolean reloadSuccess = _userManagement.reloadData(); + + assertTrue("Reload should return true to flag succesful update", reloadSuccess); + + verify(_mockProvider).reload(); + } + + public void testReloadFails() throws Exception + { + doThrow(IOException.class).when(_mockProvider).reload(); + + boolean reloadSuccess = _userManagement.reloadData(); + + assertFalse("Expected reload to fail", reloadSuccess); + } + + public void testViewUsers() throws Exception + { + Map<String,String> args = Collections.emptyMap(); + when(_mockProvider.getUsers()).thenReturn(Collections.singletonMap(TEST_USERNAME, args)); + + TabularData userList = _userManagement.viewUsers(); + + assertNotNull(userList); + assertEquals("Unexpected number of users in user list", 1, userList.size()); + assertTrue(userList.containsKey(new Object[]{TEST_USERNAME})); + + // Check the deprecated read, write and admin items continue to exist but return false. + CompositeData userRec = userList.get(new Object[]{TEST_USERNAME}); + assertTrue(userRec.containsKey(UserManagement.RIGHTS_READ_ONLY)); + assertEquals(false, userRec.get(UserManagement.RIGHTS_READ_ONLY)); + assertEquals(false, userRec.get(UserManagement.RIGHTS_READ_WRITE)); + assertTrue(userRec.containsKey(UserManagement.RIGHTS_READ_WRITE)); + assertTrue(userRec.containsKey(UserManagement.RIGHTS_ADMIN)); + assertEquals(false, userRec.get(UserManagement.RIGHTS_ADMIN)); + } +} diff --git a/qpid/java/broker-plugins/jmx/src/test/java/org/apache/qpid/server/jmx/mbeans/VirtualHostManagerMBeanTest.java b/qpid/java/broker-plugins/jmx/src/test/java/org/apache/qpid/server/jmx/mbeans/VirtualHostManagerMBeanTest.java new file mode 100644 index 0000000000..7f021bdb32 --- /dev/null +++ b/qpid/java/broker-plugins/jmx/src/test/java/org/apache/qpid/server/jmx/mbeans/VirtualHostManagerMBeanTest.java @@ -0,0 +1,85 @@ +/* + * 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.jmx.mbeans; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +import java.util.Collections; +import java.util.Map; + +import junit.framework.TestCase; + +import org.apache.qpid.server.jmx.ManagedObjectRegistry; +import org.apache.qpid.server.model.LifetimePolicy; +import org.apache.qpid.server.model.State; +import org.apache.qpid.server.model.VirtualHost; +import org.apache.qpid.server.queue.AMQQueueFactory; + +public class VirtualHostManagerMBeanTest extends TestCase +{ + private static final String TEST_QUEUE_NAME = "QUEUE_NAME"; + private static final String TEST_OWNER = "OWNER"; + private static final String TEST_DESCRIPTION = "DESCRIPTION"; + + private static final Map<String, Object> EMPTY_ARGUMENT_MAP = Collections.emptyMap(); + + private VirtualHost _mockVirtualHost; + private ManagedObjectRegistry _mockManagedObjectRegistry; + private VirtualHostManagerMBean _virtualHostManagerMBean; + + @Override + protected void setUp() throws Exception + { + _mockVirtualHost = mock(VirtualHost.class); + _mockManagedObjectRegistry = mock(ManagedObjectRegistry.class); + + _virtualHostManagerMBean = new VirtualHostManagerMBean(new VirtualHostMBean(_mockVirtualHost, _mockManagedObjectRegistry)); + } + + public void testCreateQueueWithNoOwner() throws Exception + { + _virtualHostManagerMBean.createNewQueue(TEST_QUEUE_NAME, null, true); + + verify(_mockVirtualHost).createQueue(TEST_QUEUE_NAME, State.ACTIVE, true, false, LifetimePolicy.PERMANENT, 0, EMPTY_ARGUMENT_MAP); + } + + /** + * Some users have been abusing the owner parameter as a description. Decision has been taken to map this parameter + * through to the description field (if the description field is passed, the owner is discarded). + */ + public void testCreateQueueWithOwnerMappedThroughToDescription() throws Exception + { + _virtualHostManagerMBean.createNewQueue(TEST_QUEUE_NAME, TEST_OWNER, true); + + Map<String, Object> expectedArguments = Collections.singletonMap(AMQQueueFactory.X_QPID_DESCRIPTION, (Object)TEST_OWNER); + verify(_mockVirtualHost).createQueue(TEST_QUEUE_NAME, State.ACTIVE, true, false, LifetimePolicy.PERMANENT, 0, expectedArguments); + } + + public void testCreateQueueWithOwnerAndDescriptionDiscardsOwner() throws Exception + { + Map<String, Object> arguments = Collections.singletonMap(AMQQueueFactory.X_QPID_DESCRIPTION, (Object)TEST_DESCRIPTION); + _virtualHostManagerMBean.createNewQueue(TEST_QUEUE_NAME, TEST_OWNER, true, arguments); + + Map<String, Object> expectedArguments = Collections.singletonMap(AMQQueueFactory.X_QPID_DESCRIPTION, (Object)TEST_DESCRIPTION); + verify(_mockVirtualHost).createQueue(TEST_QUEUE_NAME, State.ACTIVE, true, false, LifetimePolicy.PERMANENT, 0, expectedArguments); + } + +} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/ManagedBrokerMBeanTest.java b/qpid/java/broker-plugins/jmx/src/test/java/org/apache/qpid/systest/management/jmx/BrokerManagementTest.java index ba0f955d76..5e6c570e8c 100644 --- a/qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/ManagedBrokerMBeanTest.java +++ b/qpid/java/broker-plugins/jmx/src/test/java/org/apache/qpid/systest/management/jmx/BrokerManagementTest.java @@ -16,26 +16,22 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.qpid.management.jmx; +package org.apache.qpid.systest.management.jmx; import org.apache.qpid.exchange.ExchangeDefaults; import org.apache.qpid.management.common.mbeans.ManagedBroker; import org.apache.qpid.management.common.mbeans.ManagedExchange; -import org.apache.qpid.management.common.mbeans.ManagedQueue; -import org.apache.qpid.server.queue.AMQQueueFactory; import org.apache.qpid.test.utils.JMXTestUtils; import org.apache.qpid.test.utils.QpidBrokerTestCase; import javax.management.MBeanException; import javax.management.ObjectName; -import java.util.Collections; -import java.util.Map; /** * Tests the JMX API for the Managed Broker. * */ -public class ManagedBrokerMBeanTest extends QpidBrokerTestCase +public class BrokerManagementTest extends QpidBrokerTestCase { /** * Test virtual host @@ -140,25 +136,4 @@ public class ManagedBrokerMBeanTest extends QpidBrokerTestCase assertNotNull("Exchange should exist", defaultExchange); } - /** - * Tests queue creation with {@link AMQQueueFactory#X_QPID_MAXIMUM_DELIVERY_COUNT} argument. Also tests - * that the attribute is exposed correctly through {@link ManagedQueue#getMaximumDeliveryCount()}. - */ - public void testCreateQueueWithMaximumDeliveryCountSet() throws Exception - { - final String queueName = getName(); - final ManagedBroker managedBroker = _jmxUtils.getManagedBroker(VIRTUAL_HOST); - - final Integer deliveryCount = 1; - final Map<String, Object> args = Collections.singletonMap(AMQQueueFactory.X_QPID_MAXIMUM_DELIVERY_COUNT, (Object)deliveryCount); - managedBroker.createNewQueue(queueName, "testowner", true, args); - - // Ensure the queue exists - assertNotNull("Queue object name expected to exist", _jmxUtils.getQueueObjectName("test", queueName)); - assertNotNull("Manager queue expected to be available", _jmxUtils.getManagedQueue(queueName)); - - final ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName); - assertEquals("Unexpected maximum delivery count", deliveryCount, managedQueue.getMaximumDeliveryCount()); - } - } diff --git a/qpid/java/broker-plugins/jmx/src/test/java/org/apache/qpid/systest/management/jmx/ConnectionManagementTest.java b/qpid/java/broker-plugins/jmx/src/test/java/org/apache/qpid/systest/management/jmx/ConnectionManagementTest.java new file mode 100644 index 0000000000..28d7bf4aed --- /dev/null +++ b/qpid/java/broker-plugins/jmx/src/test/java/org/apache/qpid/systest/management/jmx/ConnectionManagementTest.java @@ -0,0 +1,283 @@ +/* + * 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.systest.management.jmx; + +import java.io.IOException; +import java.util.Date; +import java.util.Iterator; +import java.util.List; + +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.Queue; +import javax.jms.Session; +import javax.management.JMException; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.CompositeDataSupport; +import javax.management.openmbean.TabularData; + +import org.apache.commons.lang.StringUtils; +import org.apache.qpid.common.QpidProperties; +import org.apache.qpid.management.common.mbeans.ManagedConnection; +import org.apache.qpid.management.common.mbeans.ManagedQueue; +import org.apache.qpid.test.utils.JMXTestUtils; +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +public class ConnectionManagementTest extends QpidBrokerTestCase +{ + private static final String VIRTUAL_HOST_NAME = "test"; + + private JMXTestUtils _jmxUtils; + private Connection _connection; + + public void setUp() throws Exception + { + _jmxUtils = new JMXTestUtils(this); + _jmxUtils.setUp(); // modifies broker config therefore must be done before super.setUp() + super.setUp(); + _jmxUtils.open(); + } + + public void tearDown() throws Exception + { + try + { + if (_jmxUtils != null) + { + _jmxUtils.close(); + } + } + finally + { + super.tearDown(); + } + } + + public void testNumberOfManagedConnectionsMatchesNumberOfClientConnections() throws Exception + { + assertEquals("Expected no managed connections", 0, getManagedConnections().size()); + + _connection = getConnection(); + assertEquals("Expected one managed connection", 1, getManagedConnections().size()); + + _connection.close(); + assertEquals("Expected no managed connections after client connection closed", 0, getManagedConnections().size()); + } + + public void testGetAttributes() throws Exception + { + _connection = getConnection(); + final ManagedConnection mBean = getConnectionMBean(); + + checkAuthorisedId(mBean); + checkClientVersion(mBean); + checkClientId(mBean); + } + + public void testNonTransactedSession() throws Exception + { + _connection = getConnection(); + + boolean transactional = false; + boolean flowBlocked = false; + + _connection.createSession(transactional, Session.AUTO_ACKNOWLEDGE); + + final ManagedConnection mBean = getConnectionMBean(); + final CompositeDataSupport row = getTheOneChannelRow(mBean); + assertChannelRowData(row, 0, transactional, flowBlocked); + } + + public void testTransactedSessionWithUnackMessages() throws Exception + { + _connection = getConnection(); + _connection.start(); + + boolean transactional = true; + int numberOfMessages = 2; + final Session session = _connection.createSession(transactional, Session.SESSION_TRANSACTED); + final Destination destination = session.createQueue(getTestQueueName()); + final MessageConsumer consumer = session.createConsumer(destination); + + sendMessage(session, destination, numberOfMessages); + receiveMessagesWithoutCommit(consumer, numberOfMessages); + + final ManagedConnection mBean = getConnectionMBean(); + final CompositeDataSupport row = getTheOneChannelRow(mBean); + boolean flowBlocked = false; + assertChannelRowData(row, numberOfMessages, transactional, flowBlocked); + + // check that commit advances the lastIoTime + final Date initialLastIOTime = mBean.getLastIoTime(); + session.commit(); + assertTrue("commit should have caused last IO time to advance", mBean.getLastIoTime().after(initialLastIOTime)); + + // check that channels() now returns one session with no unacknowledged messages + final CompositeDataSupport rowAfterCommit = getTheOneChannelRow(mBean); + final Number unackCountAfterCommit = (Number) rowAfterCommit.get(ManagedConnection.UNACKED_COUNT); + assertEquals("Unexpected number of unacknowledged messages", 0, unackCountAfterCommit); + } + + + public void testProducerFlowBlocked() throws Exception + { + _connection = getConnection(); + _connection.start(); + + String queueName = getTestQueueName(); + Session session = _connection.createSession(true, Session.SESSION_TRANSACTED); + Queue queue = session.createQueue(queueName); + createQueueOnBroker(session, queue); + + ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName); + managedQueue.setFlowResumeCapacity(DEFAULT_MESSAGE_SIZE * 2l); + managedQueue.setCapacity(DEFAULT_MESSAGE_SIZE * 3l); + + final ManagedConnection managedConnection = getConnectionMBean(); + + // Check that producer flow is not block before test + final CompositeDataSupport rowBeforeSend = getTheOneChannelRow(managedConnection); + assertFlowBlocked(rowBeforeSend, false); + + + // Check that producer flow does not become block too soon + sendMessage(session, queue, 3); + final CompositeDataSupport rowBeforeFull = getTheOneChannelRow(managedConnection); + assertFlowBlocked(rowBeforeFull, false); + + // Fourth message will over-fill the queue (but as we are not sending more messages, client thread wont't block) + sendMessage(session, queue, 1); + final CompositeDataSupport rowAfterFull = getTheOneChannelRow(managedConnection); + assertFlowBlocked(rowAfterFull, true); + + // Consume two to bring the queue down to the resume capacity + MessageConsumer consumer = session.createConsumer(queue); + assertNotNull("Could not receive first message", consumer.receive(1000)); + assertNotNull("Could not receive second message", consumer.receive(1000)); + session.commit(); + + // Check that producer flow is no longer blocked + final CompositeDataSupport rowAfterReceive = getTheOneChannelRow(managedConnection); + assertFlowBlocked(rowAfterReceive, false); + } + + private void createQueueOnBroker(Session session, Destination destination) throws JMSException + { + session.createConsumer(destination).close(); // Create a consumer only to cause queue creation + } + + private void assertChannelRowData(final CompositeData row, int unacknowledgedMessages, boolean isTransactional, boolean flowBlocked) + { + assertNotNull(row); + assertEquals("Unexpected transactional flag", isTransactional, row.get(ManagedConnection.TRANSACTIONAL)); + assertEquals("Unexpected unacknowledged message count", unacknowledgedMessages, row.get(ManagedConnection.UNACKED_COUNT)); + assertEquals("Unexpected flow blocked", flowBlocked, row.get(ManagedConnection.FLOW_BLOCKED)); + } + + private void assertFlowBlocked(final CompositeData row, boolean flowBlocked) + { + assertNotNull(row); + assertEquals("Unexpected flow blocked", flowBlocked, row.get(ManagedConnection.FLOW_BLOCKED)); + } + + private void checkAuthorisedId(ManagedConnection mBean) throws Exception + { + assertEquals("Unexpected authorized id", GUEST_USERNAME, mBean.getAuthorizedId()); + } + + private void checkClientVersion(ManagedConnection mBean) throws Exception + { + String expectedVersion = QpidProperties.getReleaseVersion(); + assertTrue(StringUtils.isNotBlank(expectedVersion)); + + assertEquals("Unexpected version", expectedVersion, mBean.getVersion()); + } + + private void checkClientId(ManagedConnection mBean) throws Exception + { + String expectedClientId = _connection.getClientID(); + assertTrue(StringUtils.isNotBlank(expectedClientId)); + + assertEquals("Unexpected ClientId", expectedClientId, mBean.getClientId()); + } + + private ManagedConnection getConnectionMBean() + { + List<ManagedConnection> connections = getManagedConnections(); + assertNotNull("Connection MBean is not found", connections); + assertEquals("Unexpected number of connection mbeans", 1, connections.size()); + final ManagedConnection mBean = connections.get(0); + assertNotNull("Connection MBean is null", mBean); + return mBean; + } + + private List<ManagedConnection> getManagedConnections() + { + return _jmxUtils.getManagedConnections(VIRTUAL_HOST_NAME); + } + + private CompositeDataSupport getTheOneChannelRow(final ManagedConnection mBean) throws Exception + { + TabularData channelsData = getChannelsDataWithRetry(mBean); + + assertEquals("Unexpected number of rows in channel table", 1, channelsData.size()); + + @SuppressWarnings("unchecked") + final Iterator<CompositeDataSupport> rowItr = (Iterator<CompositeDataSupport>) channelsData.values().iterator(); + final CompositeDataSupport row = rowItr.next(); + return row; + } + + private void receiveMessagesWithoutCommit(final MessageConsumer consumer, int numberOfMessages) throws Exception + { + for (int i = 0; i < numberOfMessages; i++) + { + final Message m = consumer.receive(1000l); + assertNotNull("Message " + i + " is not received", m); + } + } + + private TabularData getChannelsDataWithRetry(final ManagedConnection mBean) + throws IOException, JMException + { + TabularData channelsData = mBean.channels(); + int retries = 0; + while(channelsData.size() == 0 && retries < 5) + { + sleep(); + channelsData = mBean.channels(); + retries++; + } + return channelsData; + } + + private void sleep() + { + try + { + Thread.sleep(50); + } + catch (InterruptedException ie) + { + Thread.currentThread().interrupt(); + } + }} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/ManagementActorLoggingTest.java b/qpid/java/broker-plugins/jmx/src/test/java/org/apache/qpid/systest/management/jmx/ManagementActorLoggingTest.java index 0e2875235f..47b38381c5 100644 --- a/qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/ManagementActorLoggingTest.java +++ b/qpid/java/broker-plugins/jmx/src/test/java/org/apache/qpid/systest/management/jmx/ManagementActorLoggingTest.java @@ -18,7 +18,7 @@ * under the License. * */ -package org.apache.qpid.management.jmx; +package org.apache.qpid.systest.management.jmx; import org.apache.qpid.management.common.mbeans.ManagedBroker; import org.apache.qpid.management.common.mbeans.ManagedConnection; diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/ManagementLoggingTest.java b/qpid/java/broker-plugins/jmx/src/test/java/org/apache/qpid/systest/management/jmx/ManagementLoggingTest.java index c8a6d02761..6100d5a23e 100644 --- a/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/ManagementLoggingTest.java +++ b/qpid/java/broker-plugins/jmx/src/test/java/org/apache/qpid/systest/management/jmx/ManagementLoggingTest.java @@ -18,10 +18,11 @@ * under the License. * */ -package org.apache.qpid.server.logging; +package org.apache.qpid.systest.management.jmx; import org.apache.qpid.server.configuration.ServerConfiguration; +import org.apache.qpid.server.logging.AbstractTestLogging; import org.apache.qpid.test.utils.JMXTestUtils; import org.apache.qpid.util.LogMonitor; @@ -177,7 +178,7 @@ public class ManagementLoggingTest extends AbstractTestLogging if (isJavaBroker()) { startBrokerAndCreateMonitor(true, false); - + List<String> results = waitAndFindMatches("MNG-1002"); // Validation diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/ManagedQueueMBeanTest.java b/qpid/java/broker-plugins/jmx/src/test/java/org/apache/qpid/systest/management/jmx/QueueManagementTest.java index 244e547e02..ad6777d0ea 100644 --- a/qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/ManagedQueueMBeanTest.java +++ b/qpid/java/broker-plugins/jmx/src/test/java/org/apache/qpid/systest/management/jmx/QueueManagementTest.java @@ -16,15 +16,20 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.qpid.management.jmx; +package org.apache.qpid.systest.management.jmx; import org.apache.commons.lang.time.FastDateFormat; import org.apache.log4j.Logger; import org.apache.qpid.client.AMQSession; import org.apache.qpid.configuration.ClientProperties; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.management.common.mbeans.ManagedBroker; import org.apache.qpid.management.common.mbeans.ManagedQueue; -import org.apache.qpid.server.queue.AMQQueueMBean; +import org.apache.qpid.server.queue.AMQQueueFactory; +import org.apache.qpid.server.queue.NotificationCheckTest; +import org.apache.qpid.server.queue.SimpleAMQQueueTest; +import org.apache.qpid.test.client.destination.AddressBasedDestinationTest; import org.apache.qpid.test.utils.JMXTestUtils; import org.apache.qpid.test.utils.QpidBrokerTestCase; @@ -34,12 +39,16 @@ import javax.jms.JMSException; import javax.jms.Message; import javax.jms.MessageConsumer; import javax.jms.MessageListener; +import javax.jms.Queue; import javax.jms.Session; +import javax.management.Notification; +import javax.management.NotificationListener; import javax.management.openmbean.CompositeData; import javax.management.openmbean.TabularData; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; @@ -49,14 +58,19 @@ import java.util.TreeSet; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; /** * Tests the JMX API for the Managed Queue. * */ -public class ManagedQueueMBeanTest extends QpidBrokerTestCase +public class QueueManagementTest extends QpidBrokerTestCase { - protected static final Logger LOGGER = Logger.getLogger(ManagedQueueMBeanTest.class); + + private static final Logger LOGGER = Logger.getLogger(QueueManagementTest.class); + + private static final String VIRTUAL_HOST = "test"; + private static final String TEST_QUEUE_DESCRIPTION = "my description"; private JMXTestUtils _jmxUtils; private Connection _connection; @@ -69,6 +83,7 @@ public class ManagedQueueMBeanTest extends QpidBrokerTestCase private ManagedQueue _managedSourceQueue; private ManagedQueue _managedDestinationQueue; + public void setUp() throws Exception { _jmxUtils = new JMXTestUtils(this); @@ -102,6 +117,218 @@ public class ManagedQueueMBeanTest extends QpidBrokerTestCase super.tearDown(); } + public void testQueueAttributes() throws Exception + { + Queue queue = _session.createQueue(getTestQueueName()); + createQueueOnBroker(queue); + + final String queueName = queue.getQueueName(); + + final ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName); + assertEquals("Unexpected name", queueName, managedQueue.getName()); + assertEquals("Unexpected queue type", "standard", managedQueue.getQueueType()); + } + + public void testExclusiveQueueHasJmsClientIdAsOwner() throws Exception + { + Queue tmpQueue = _session.createTemporaryQueue(); + + final String queueName = tmpQueue.getQueueName(); + + final ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName); + assertNotNull(_connection.getClientID()); + assertEquals("Unexpected owner", _connection.getClientID(), managedQueue.getOwner()); + } + + public void testNonExclusiveQueueHasNoOwner() throws Exception + { + Queue nonExclusiveQueue = _session.createQueue(getTestQueueName()); + createQueueOnBroker(nonExclusiveQueue); + + final String queueName = nonExclusiveQueue.getQueueName(); + + final ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName); + assertNull("Unexpected owner", managedQueue.getOwner()); + } + + public void testSetNewQueueDescriptionOnExistingQueue() throws Exception + { + Queue queue = _session.createQueue(getTestQueueName()); + createQueueOnBroker(queue); + + final String queueName = queue.getQueueName(); + + final ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName); + assertNull("Unexpected description", managedQueue.getDescription()); + + managedQueue.setDescription(TEST_QUEUE_DESCRIPTION); + assertEquals(TEST_QUEUE_DESCRIPTION, managedQueue.getDescription()); + } + + public void testNewQueueWithDescription() throws Exception + { + String queueName = getTestQueueName(); + Map<String, Object> arguments = Collections.singletonMap(AMQQueueFactory.X_QPID_DESCRIPTION, (Object)TEST_QUEUE_DESCRIPTION); + ((AMQSession<?, ?>)_session).createQueue(AMQShortString.valueOf(queueName), false, true, false, arguments); + + final ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName); + assertEquals(TEST_QUEUE_DESCRIPTION, managedQueue.getDescription()); + } + + /** + * Requires persistent store. + */ + public void testQueueDescriptionSurvivesRestart() throws Exception + { + String queueName = getTestQueueName(); + Map<String, Object> arguments = Collections.singletonMap(AMQQueueFactory.X_QPID_DESCRIPTION, (Object)TEST_QUEUE_DESCRIPTION); + + ((AMQSession<?, ?>)_session).createQueue(AMQShortString.valueOf(queueName), false, true, false, arguments); + + ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName); + assertEquals(TEST_QUEUE_DESCRIPTION, managedQueue.getDescription()); + + restartBroker(); + + managedQueue = _jmxUtils.getManagedQueue(queueName); + assertEquals(TEST_QUEUE_DESCRIPTION, managedQueue.getDescription()); + } + + /** + * Tests queue creation with {@link AMQQueueFactory#X_QPID_MAXIMUM_DELIVERY_COUNT} argument. Also tests + * that the attribute is exposed correctly through {@link ManagedQueue#getMaximumDeliveryCount()}. + */ + public void testCreateQueueWithMaximumDeliveryCountSet() throws Exception + { + final String queueName = getName(); + final ManagedBroker managedBroker = _jmxUtils.getManagedBroker(VIRTUAL_HOST); + + final Integer deliveryCount = 1; + final Map<String, Object> arguments = Collections.singletonMap(AMQQueueFactory.X_QPID_MAXIMUM_DELIVERY_COUNT, (Object)deliveryCount); + managedBroker.createNewQueue(queueName, null, true, arguments); + + // Ensure the queue exists + assertNotNull("Queue object name expected to exist", _jmxUtils.getQueueObjectName("test", queueName)); + assertNotNull("Manager queue expected to be available", _jmxUtils.getManagedQueue(queueName)); + + final ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName); + assertEquals("Unexpected maximum delivery count", deliveryCount, managedQueue.getMaximumDeliveryCount()); + } + + /** + * Requires 0-10 as relies on ADDR addresses. + * @see AddressBasedDestinationTest for the testing of message routing to the alternate exchange + */ + public void testGetSetAlternateExchange() throws Exception + { + String queueName = getTestQueueName(); + String altExchange = "amq.fanout"; + String addrWithAltExch = String.format("ADDR:%s;{create:always,node:{type:queue,x-declare:{alternate-exchange:'%s'}}}", queueName, altExchange); + Queue queue = _session.createQueue(addrWithAltExch); + + createQueueOnBroker(queue); + + final ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName); + assertEquals("Newly created queue does not have expected alternate exchange", altExchange, managedQueue.getAlternateExchange()); + + String newAltExch = "amq.topic"; + managedQueue.setAlternateExchange(newAltExch); + assertEquals("Unexpected alternate exchange after set", newAltExch, managedQueue.getAlternateExchange()); + } + + /** + * Requires 0-10 as relies on ADDR addresses. + */ + public void testRemoveAlternateExchange() throws Exception + { + String queueName = getTestQueueName(); + String altExchange = "amq.fanout"; + String addrWithAltExch = String.format("ADDR:%s;{create:always,node:{type:queue,x-declare:{alternate-exchange:'%s'}}}", queueName, altExchange); + Queue queue = _session.createQueue(addrWithAltExch); + + createQueueOnBroker(queue); + + final ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName); + assertEquals("Newly created queue does not have expected alternate exchange", altExchange, managedQueue.getAlternateExchange()); + + managedQueue.setAlternateExchange(""); + assertNull("Unexpected alternate exchange after set", managedQueue.getAlternateExchange()); + } + + /** + * Requires persistent store + * Requires 0-10 as relies on ADDR addresses. + */ + public void testAlternateExchangeSurvivesRestart() throws Exception + { + String queueName1 = getTestQueueName() + "1"; + String altExchange1 = "amq.fanout"; + String addr1WithAltExch = String.format("ADDR:%s;{create:always,node:{durable: true,type:queue,x-declare:{alternate-exchange:'%s'}}}", queueName1, altExchange1); + Queue queue1 = _session.createQueue(addr1WithAltExch); + + String queueName2 = getTestQueueName() + "2"; + String addr2WithoutAltExch = String.format("ADDR:%s;{create:always,node:{durable: true,type:queue,}}", queueName2); + Queue queue2 = _session.createQueue(addr2WithoutAltExch); + + createQueueOnBroker(queue1); + createQueueOnBroker(queue2); + + ManagedQueue managedQueue1 = _jmxUtils.getManagedQueue(queueName1); + assertEquals("Newly created queue1 does not have expected alternate exchange", altExchange1, managedQueue1.getAlternateExchange()); + + ManagedQueue managedQueue2 = _jmxUtils.getManagedQueue(queueName2); + assertNull("Newly created queue2 does not have expected alternate exchange", managedQueue2.getAlternateExchange()); + + String altExchange2 = "amq.fanout"; + managedQueue2.setAlternateExchange(altExchange2); + + restartBroker(); + + managedQueue1 = _jmxUtils.getManagedQueue(queueName1); + assertEquals("Queue1 does not have expected alternate exchange after restart", altExchange1, managedQueue1.getAlternateExchange()); + + managedQueue2 = _jmxUtils.getManagedQueue(queueName2); + assertEquals("Queue2 does not have expected updated alternate exchange after restart", altExchange2, managedQueue2.getAlternateExchange()); + } + + /** + * Tests the ability to receive queue alerts as JMX notifications. + * + * @see NotificationCheckTest + * @see SimpleAMQQueueTest#testNotificationFiredAsync() + * @see SimpleAMQQueueTest#testNotificationFiredOnEnqueue() + */ + public void testQueueNotification() throws Exception + { + final String queueName = getName(); + final long maximumMessageCount = 3; + + Queue queue = _session.createQueue(queueName); + createQueueOnBroker(queue); + + ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName); + managedQueue.setMaximumMessageCount(maximumMessageCount); + + RecordingNotificationListener listener = new RecordingNotificationListener(1); + + _jmxUtils.addNotificationListener(_jmxUtils.getQueueObjectName(VIRTUAL_HOST, queueName), listener, null, null); + + // Send two messages - this should *not* trigger the notification + sendMessage(_session, queue, 2); + + assertEquals("Premature notification received", 0, listener.getNumberOfNotificationsReceived()); + + // A further message should trigger the message count alert + sendMessage(_session, queue, 1); + + listener.awaitExpectedNotifications(5, TimeUnit.SECONDS); + + assertEquals("Unexpected number of JMX notifications received", 1, listener.getNumberOfNotificationsReceived()); + + Notification notification = listener.getLastNotification(); + assertEquals("Unexpected notification message", "MESSAGE_COUNT_ALERT 3: Maximum count on queue threshold (3) breached.", notification.getMessage()); + } + /** * Tests {@link ManagedQueue#viewMessages(long, long)} interface. */ @@ -129,7 +356,7 @@ public class ManagedQueueMBeanTest extends QpidBrokerTestCase final Map<String, String> headers = headerArrayToMap(headerArray); final String expectedJMSMessageID = isBroker010() ? sentMessage.getJMSMessageID().replace("ID:", "") : sentMessage.getJMSMessageID(); - final String expectedFormattedJMSTimestamp = FastDateFormat.getInstance(AMQQueueMBean.JMSTIMESTAMP_DATETIME_FORMAT).format(sentMessage.getJMSTimestamp()); + final String expectedFormattedJMSTimestamp = FastDateFormat.getInstance(ManagedQueue.JMSTIMESTAMP_DATETIME_FORMAT).format(sentMessage.getJMSTimestamp()); assertEquals("Unexpected JMSMessageID within header", expectedJMSMessageID, headers.get("JMSMessageID")); assertEquals("Unexpected JMSPriority within header", String.valueOf(sentMessage.getJMSPriority()), headers.get("JMSPriority")); assertEquals("Unexpected JMSTimestamp within header", expectedFormattedJMSTimestamp, headers.get("JMSTimestamp")); @@ -224,7 +451,7 @@ public class ManagedQueueMBeanTest extends QpidBrokerTestCase asyncConnection.stop(); // The exact number of messages moved will be non deterministic, as the number of messages processed - // by the consumer cannot be predicited. There is also the possibility that a message can remain + // by the consumer cannot be predicted. There is also the possibility that a message can remain // on the source queue. This situation will arise if a message has been acquired by the consumer, but not // yet delivered to the client application (i.e. MessageListener#onMessage()) when the Connection#stop() occurs. // @@ -342,4 +569,41 @@ public class ManagedQueueMBeanTest extends QpidBrokerTestCase ((AMQSession<?,?>)session).sync(); } + private final class RecordingNotificationListener implements NotificationListener + { + private final CountDownLatch _notificationReceivedLatch; + private final AtomicInteger _numberOfNotifications; + private final AtomicReference<Notification> _lastNotification; + + private RecordingNotificationListener(int expectedNumberOfNotifications) + { + _notificationReceivedLatch = new CountDownLatch(expectedNumberOfNotifications); + _numberOfNotifications = new AtomicInteger(0); + _lastNotification = new AtomicReference<Notification>(); + } + + @Override + public void handleNotification(Notification notification, Object handback) + { + _lastNotification.set(notification); + _numberOfNotifications.incrementAndGet(); + _notificationReceivedLatch.countDown(); + } + + public int getNumberOfNotificationsReceived() + { + return _numberOfNotifications.get(); + } + + public Notification getLastNotification() + { + return _lastNotification.get(); + } + + public void awaitExpectedNotifications(long timeout, TimeUnit timeunit) throws InterruptedException + { + _notificationReceivedLatch.await(timeout, timeunit); + } + } + } diff --git a/qpid/java/broker-plugins/jmx/src/test/java/org/apache/qpid/systest/management/jmx/StatisticsTest.java b/qpid/java/broker-plugins/jmx/src/test/java/org/apache/qpid/systest/management/jmx/StatisticsTest.java new file mode 100644 index 0000000000..c3fff94923 --- /dev/null +++ b/qpid/java/broker-plugins/jmx/src/test/java/org/apache/qpid/systest/management/jmx/StatisticsTest.java @@ -0,0 +1,204 @@ +/* + * 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.systest.management.jmx; + +import java.util.List; + +import javax.jms.Connection; +import javax.jms.MessageConsumer; +import javax.jms.Queue; +import javax.jms.Session; + +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.management.common.mbeans.ManagedBroker; +import org.apache.qpid.management.common.mbeans.ManagedConnection; +import org.apache.qpid.management.common.mbeans.ServerInformation; +import org.apache.qpid.test.utils.JMXTestUtils; +import org.apache.qpid.test.utils.QpidBrokerTestCase; + +public class StatisticsTest extends QpidBrokerTestCase +{ + private static final String TEST_USER = "admin"; + private static final String TEST_PASSWORD = "admin"; + private static final int MESSAGE_COUNT_TEST = 5; + private static final int MESSAGE_COUNT_DEV = 9; + + private JMXTestUtils _jmxUtils; + private Connection _test1, _dev; + private Session _testSession, _developmentSession; + private Queue _developmentQueue, _testQueue; + protected String _brokerUrl; + + @Override + public void setUp() throws Exception + { + _jmxUtils = new JMXTestUtils(this, TEST_USER, TEST_PASSWORD); + _jmxUtils.setUp(); + + super.setUp(); + + _brokerUrl = getBroker().toString(); + _test1 = new AMQConnection(_brokerUrl, TEST_USER, TEST_PASSWORD, "clientid", "test"); + _dev = new AMQConnection(_brokerUrl, TEST_USER, TEST_PASSWORD, "clientid", "development"); + _test1.start(); + _dev.start(); + + _testSession = _test1.createSession(true, Session.SESSION_TRANSACTED); + _developmentSession = _dev.createSession(true, Session.SESSION_TRANSACTED); + + _developmentQueue = _developmentSession.createQueue(getTestQueueName()); + _testQueue = _testSession.createQueue(getTestQueueName()); + + //Create queues by opening and closing consumers + final MessageConsumer testConsumer = _testSession.createConsumer(_testQueue); + testConsumer.close(); + final MessageConsumer developmentConsumer = _developmentSession.createConsumer(_developmentQueue); + developmentConsumer.close(); + + _jmxUtils.open(); + } + + @Override + public void tearDown() throws Exception + { + _jmxUtils.close(); + + super.tearDown(); + } + + public void testInitialStatisticValues() throws Exception + { + //Check initial values + checkSingleConnectionOnVHostStatistics("test", 0, 0, 0, 0); + checkVHostStatistics("test", 0, 0, 0, 0); + checkSingleConnectionOnVHostStatistics("development", 0, 0, 0, 0); + checkVHostStatistics("development", 0, 0, 0, 0); + checkBrokerStatistics(0, 0, 0, 0); + } + + public void testSendOnSingleVHost() throws Exception + { + sendMessagesAndSync(_testSession, _testQueue, MESSAGE_COUNT_TEST); + + //Check values + checkSingleConnectionOnVHostStatistics("test", MESSAGE_COUNT_TEST, 0, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE, 0); + checkVHostStatistics("test", MESSAGE_COUNT_TEST, 0, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE, 0); + checkSingleConnectionOnVHostStatistics("development", 0, 0, 0, 0); + checkVHostStatistics("development", 0, 0, 0, 0); + checkBrokerStatistics(MESSAGE_COUNT_TEST, 0, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE, 0); + } + + public void testSendOnTwoVHosts() throws Exception + { + sendMessagesAndSync(_testSession, _testQueue, MESSAGE_COUNT_TEST); + sendMessagesAndSync(_developmentSession, _developmentQueue, MESSAGE_COUNT_DEV); + + //Check values + checkSingleConnectionOnVHostStatistics("test", MESSAGE_COUNT_TEST, 0, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE, 0); + checkVHostStatistics("test", MESSAGE_COUNT_TEST, 0, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE, 0); + checkSingleConnectionOnVHostStatistics("development", MESSAGE_COUNT_DEV, 0, MESSAGE_COUNT_DEV * DEFAULT_MESSAGE_SIZE, 0); + checkVHostStatistics("development", MESSAGE_COUNT_DEV, 0, MESSAGE_COUNT_DEV * DEFAULT_MESSAGE_SIZE, 0); + checkBrokerStatistics(MESSAGE_COUNT_TEST + MESSAGE_COUNT_DEV, 0, (MESSAGE_COUNT_TEST + MESSAGE_COUNT_DEV) * DEFAULT_MESSAGE_SIZE, 0); + } + + public void testSendAndConsumeOnSingleVHost() throws Exception + { + sendMessagesAndSync(_testSession, _testQueue, MESSAGE_COUNT_TEST); + consumeMessages(_testSession, _testQueue, MESSAGE_COUNT_TEST); + + //Check values + checkSingleConnectionOnVHostStatistics("test", MESSAGE_COUNT_TEST, MESSAGE_COUNT_TEST, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE); + checkVHostStatistics("test", MESSAGE_COUNT_TEST, MESSAGE_COUNT_TEST, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE); + checkSingleConnectionOnVHostStatistics("development", 0, 0, 0, 0); + checkVHostStatistics("development", 0, 0, 0, 0); + checkBrokerStatistics(MESSAGE_COUNT_TEST, MESSAGE_COUNT_TEST, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE); + } + + public void testSendAndConsumeOnTwoVHosts() throws Exception + { + sendMessagesAndSync(_testSession, _testQueue, MESSAGE_COUNT_TEST); + sendMessagesAndSync(_developmentSession, _developmentQueue, MESSAGE_COUNT_DEV); + consumeMessages(_testSession, _testQueue, MESSAGE_COUNT_TEST); + consumeMessages(_developmentSession, _developmentQueue, MESSAGE_COUNT_DEV); + + //Check values + checkSingleConnectionOnVHostStatistics("test", MESSAGE_COUNT_TEST, MESSAGE_COUNT_TEST, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE); + checkVHostStatistics("test", MESSAGE_COUNT_TEST, MESSAGE_COUNT_TEST, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE); + checkSingleConnectionOnVHostStatistics("development", MESSAGE_COUNT_DEV, MESSAGE_COUNT_DEV, MESSAGE_COUNT_DEV * DEFAULT_MESSAGE_SIZE, MESSAGE_COUNT_DEV * DEFAULT_MESSAGE_SIZE); + checkVHostStatistics("development", MESSAGE_COUNT_DEV, MESSAGE_COUNT_DEV, MESSAGE_COUNT_DEV * DEFAULT_MESSAGE_SIZE, MESSAGE_COUNT_DEV * DEFAULT_MESSAGE_SIZE); + checkBrokerStatistics(MESSAGE_COUNT_TEST + MESSAGE_COUNT_DEV, MESSAGE_COUNT_TEST + MESSAGE_COUNT_DEV, (MESSAGE_COUNT_TEST + MESSAGE_COUNT_DEV) * DEFAULT_MESSAGE_SIZE, (MESSAGE_COUNT_TEST + MESSAGE_COUNT_DEV) * DEFAULT_MESSAGE_SIZE); + } + + private void sendMessagesAndSync(Session session, Queue queue, int numberOfMessages) throws Exception + { + //Send messages via connection on and sync + sendMessage(session, queue, numberOfMessages); + ((AMQSession<?,?>)session).sync(); + } + + private void consumeMessages(Session session, Queue queue, int numberOfMessages) throws Exception + { + //consume the messages on the virtual host + final MessageConsumer consumer = session.createConsumer(queue); + for (int i = 0 ; i < numberOfMessages ; i++) + { + assertNotNull("an expected message was not received", consumer.receive(1500)); + } + session.commit(); + consumer.close(); + } + + private void checkSingleConnectionOnVHostStatistics(String vHostName, long messagesSent, long messagesReceived, long dataSent, long dataReceived) + { + List<ManagedConnection> managedConnections = _jmxUtils.getManagedConnections(vHostName); + assertEquals(1, managedConnections.size()); + + ManagedConnection managedConnection = managedConnections.get(0); + + assertEquals(messagesSent, managedConnection.getTotalMessagesReceived()); + assertEquals(messagesReceived, managedConnection.getTotalMessagesDelivered()); + + assertEquals(dataSent, managedConnection.getTotalDataReceived()); + assertEquals(dataReceived, managedConnection.getTotalDataDelivered()); + } + + private void checkVHostStatistics(String vHostName, long messagesSent, long messagesReceived, long dataSent, long dataReceived) + { + ManagedBroker vhost = _jmxUtils.getManagedBroker(vHostName); + + assertEquals(messagesSent, vhost.getTotalMessagesReceived()); + assertEquals(messagesReceived, vhost.getTotalMessagesDelivered()); + + assertEquals(dataSent, vhost.getTotalDataReceived()); + assertEquals(dataReceived, vhost.getTotalDataDelivered()); + } + + private void checkBrokerStatistics(long messagesSent, long messagesReceived, long dataSent, long dataReceived) + { + ServerInformation broker = _jmxUtils.getServerInformation(); + + assertEquals(messagesSent, broker.getTotalMessagesReceived()); + assertEquals(messagesReceived, broker.getTotalMessagesDelivered()); + + assertEquals(dataSent, broker.getTotalDataReceived()); + assertEquals(dataReceived, broker.getTotalDataDelivered()); + } +} diff --git a/qpid/java/broker-plugins/jmx/src/test/java/org/apache/qpid/systest/management/jmx/UserManagementTest.java b/qpid/java/broker-plugins/jmx/src/test/java/org/apache/qpid/systest/management/jmx/UserManagementTest.java new file mode 100644 index 0000000000..62b1b554a9 --- /dev/null +++ b/qpid/java/broker-plugins/jmx/src/test/java/org/apache/qpid/systest/management/jmx/UserManagementTest.java @@ -0,0 +1,251 @@ +/* + * 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.systest.management.jmx; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; + +import javax.jms.Connection; +import javax.jms.JMSException; + +import org.apache.qpid.management.common.mbeans.UserManagement; +import org.apache.qpid.server.security.auth.database.PlainPasswordFilePrincipalDatabase; +import org.apache.qpid.server.security.auth.database.PrincipalDatabase; +import org.apache.qpid.test.utils.JMXTestUtils; +import org.apache.qpid.test.utils.QpidBrokerTestCase; +import org.apache.qpid.tools.security.Passwd; + +/** + * System test for User Management. + * + */ +public class UserManagementTest extends QpidBrokerTestCase +{ + private static final String TEST_NEWPASSWORD = "newpassword"; + private static final String TEST_PASSWORD = "password"; + private JMXTestUtils _jmxUtils; + private String _testUserName; + private File _passwordFile; + private UserManagement _userManagement; + private Passwd _passwd; + + public void setUp() throws Exception + { + _passwd = createPasswordEncodingUtility(); + _passwordFile = createTemporaryPasswordFileWithJmxAdminUser(); + + setConfigurationProperty("security.pd-auth-manager.principal-database.class", getPrincipalDatabaseImplClass().getName()); + setConfigurationProperty("security.pd-auth-manager.principal-database.attributes.attribute.name", "passwordFile"); + setConfigurationProperty("security.pd-auth-manager.principal-database.attributes.attribute.value", _passwordFile.getAbsolutePath()); + + _jmxUtils = new JMXTestUtils(this); + _jmxUtils.setUp(); + + super.setUp(); + _jmxUtils.open(); + + _testUserName = getTestName() + System.currentTimeMillis(); + + _userManagement = _jmxUtils.getUserManagement(); + } + + + public void tearDown() throws Exception + { + try + { + if (_jmxUtils != null) + { + _jmxUtils.close(); + } + } + finally + { + super.tearDown(); + } + } + + public void testCreateUser() throws Exception + { + final int initialNumberOfUsers = _userManagement.viewUsers().size(); + assertFileDoesNotContainsPasswordForUser(_testUserName); + + boolean success = _userManagement.createUser(_testUserName, TEST_PASSWORD); + assertTrue("Should have been able to create new user " + _testUserName, success); + assertEquals("Unexpected number of users after add", initialNumberOfUsers + 1, _userManagement.viewUsers().size()); + + assertFileContainsPasswordForUser(_testUserName); + } + + public void testJmsLoginForNewUser() throws Exception + { + assertJmsConnectionFails(_testUserName, TEST_PASSWORD); + testCreateUser(); + + assertJmsConnectionSucceeds(_testUserName, TEST_PASSWORD); + } + + public void testDeleteUser() throws Exception + { + final int initialNumberOfUsers = _userManagement.viewUsers().size(); + + testCreateUser(); + + boolean success = _userManagement.deleteUser(_testUserName); + assertTrue("Should have been able to delete new user " + _testUserName, success); + assertEquals("Unexpected number of users after delete", initialNumberOfUsers, _userManagement.viewUsers().size()); + assertFileDoesNotContainsPasswordForUser(_testUserName); + } + + public void testJmsLoginNotPossibleForDeletedUser() throws Exception + { + testDeleteUser(); + + assertJmsConnectionFails(_testUserName, TEST_PASSWORD); + } + + public void testSetPassword() throws Exception + { + testCreateUser(); + + _userManagement.setPassword(_testUserName, TEST_NEWPASSWORD); + + assertFileContainsPasswordForUser(_testUserName); + } + + public void testJmsLoginForPasswordChangedUser() throws Exception + { + testSetPassword(); + + assertJmsConnectionSucceeds(_testUserName, TEST_NEWPASSWORD); + assertJmsConnectionFails(_testUserName, TEST_PASSWORD); + } + + public void testReload() throws Exception + { + writePasswordFile(_passwordFile, JMXTestUtils.DEFAULT_USERID, JMXTestUtils.DEFAULT_PASSWORD, _testUserName, TEST_PASSWORD); + + assertJmsConnectionFails(_testUserName, TEST_PASSWORD); + + _userManagement.reloadData(); + + assertJmsConnectionSucceeds(_testUserName, TEST_PASSWORD); + } + + protected Passwd createPasswordEncodingUtility() + { + return new Passwd() + { + @Override + public String getOutput(String username, String password) + { + return username + ":" + password; + } + }; + } + + protected Class<? extends PrincipalDatabase> getPrincipalDatabaseImplClass() + { + return PlainPasswordFilePrincipalDatabase.class; + } + + private File createTemporaryPasswordFileWithJmxAdminUser() throws Exception + { + File passwordFile = File.createTempFile("passwd", "pwd"); + passwordFile.deleteOnExit(); + writePasswordFile(passwordFile, JMXTestUtils.DEFAULT_USERID, JMXTestUtils.DEFAULT_PASSWORD); + return passwordFile; + } + + private void writePasswordFile(File passwordFile, String... userNamePasswordPairs) throws Exception + { + FileWriter writer = null; + try + { + writer = new FileWriter(passwordFile); + for (int i = 0; i < userNamePasswordPairs.length; i=i+2) + { + String username = userNamePasswordPairs[i]; + String password = userNamePasswordPairs[i+1]; + writer.append(_passwd.getOutput(username, password) + "\n"); + } + } + finally + { + writer.close(); + } + } + + + private void assertFileContainsPasswordForUser(String username) throws IOException + { + assertTrue("Could not find password for user " + username + " within " + _passwordFile, passwordFileContainsUser(username)); + } + + private void assertFileDoesNotContainsPasswordForUser(String username) throws IOException + { + assertFalse("Could not find password for user " + username + " within " + _passwordFile, passwordFileContainsUser(username)); + } + + private boolean passwordFileContainsUser(String username) throws IOException + { + BufferedReader reader = null; + try + { + reader = new BufferedReader(new FileReader(_passwordFile)); + String line = reader.readLine(); + while(line != null) + { + if (line.startsWith(username)) + { + return true; + } + line = reader.readLine(); + } + + return false; + } + finally + { + reader.close(); + } + } + + private void assertJmsConnectionSucceeds(String username, String password) throws Exception + { + Connection connection = getConnection(username, password); + assertNotNull(connection); + } + + private void assertJmsConnectionFails(String username, String password) throws Exception + { + try + { + getConnection(username, password); + fail("Exception not thrown"); + } + catch (JMSException e) + { + // PASS + } + } +} diff --git a/qpid/java/broker-plugins/jmx/src/test/java/org/apache/qpid/systest/management/jmx/UserManagementWithBase64MD5PasswordsTest.java b/qpid/java/broker-plugins/jmx/src/test/java/org/apache/qpid/systest/management/jmx/UserManagementWithBase64MD5PasswordsTest.java new file mode 100644 index 0000000000..84a66232ce --- /dev/null +++ b/qpid/java/broker-plugins/jmx/src/test/java/org/apache/qpid/systest/management/jmx/UserManagementWithBase64MD5PasswordsTest.java @@ -0,0 +1,39 @@ +/* + * 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.systest.management.jmx; + +import org.apache.qpid.server.security.auth.database.Base64MD5PasswordFilePrincipalDatabase; +import org.apache.qpid.server.security.auth.database.PrincipalDatabase; +import org.apache.qpid.tools.security.Passwd; + +public class UserManagementWithBase64MD5PasswordsTest extends UserManagementTest +{ + @Override + protected Passwd createPasswordEncodingUtility() + { + return new Passwd(); + } + + @Override + protected Class<? extends PrincipalDatabase> getPrincipalDatabaseImplClass() + { + return Base64MD5PasswordFilePrincipalDatabase.class; + } + +} diff --git a/qpid/java/broker-plugins/management/MANIFEST.MF b/qpid/java/broker-plugins/management/MANIFEST.MF new file mode 100644 index 0000000000..d817ac5302 --- /dev/null +++ b/qpid/java/broker-plugins/management/MANIFEST.MF @@ -0,0 +1,66 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Qpid Broker-Plugins Management +Bundle-SymbolicName: broker-plugins-management +Bundle-Description: Management plugin for Qpid. +Bundle-License: http://www.apache.org/licenses/LICENSE-2.0.txt +Bundle-DocURL: http://www.apache.org/ +Bundle-Version: 1.0.0 +Bundle-Activator: org.apache.qpid.server.management.plugin.ManagementActivator +Bundle-RequiredExecutionEnvironment: JavaSE-1.6 +Bundle-ClassPath: . +Bundle-ActivationPolicy: lazy +Import-Package: org.apache.qpid, + org.apache.qpid.framing, + org.apache.qpid.protocol, + org.apache.qpid.common, + org.apache.qpid.server.security.auth, + org.apache.qpid.server.security.auth.manager, + org.apache.qpid.server.security.auth.sasl, + org.apache.qpid.server.binding, + org.apache.qpid.server.exchange, + org.apache.qpid.server.logging, + org.apache.qpid.server.message, + org.apache.qpid.server.model, + org.apache.qpid.server.model.adapter, + org.apache.qpid.server.model.impl, + org.apache.qpid.server.configuration, + org.apache.qpid.server.configuration.plugins, + org.apache.qpid.server.connection, + org.apache.qpid.server.plugins, + org.apache.qpid.server.protocol, + org.apache.qpid.server.queue, + org.apache.qpid.server.registry, + org.apache.qpid.server.security, + org.apache.qpid.server.security.access, + org.apache.qpid.server.stats, + org.apache.qpid.server.virtualhost, + org.apache.qpid.util, + org.eclipse.jetty.server;version=7.6.3, + org.eclipse.jetty.server.session;version=7.6.3, + org.eclipse.jetty.security;version=7.6.3, + org.eclipse.jetty.http;version=7.6.3, + org.eclipse.jetty.io;version=7.6.3, + org.eclipse.jetty.io.nio;version=7.6.3, + org.eclipse.jetty.servlet;version=7.6.3, + org.apache.commons.codec;version=1.3.0, + org.apache.commons.codec.binary;version=1.3.0, + org.apache.commons.configuration;version=1.0.0, + org.apache.commons.lang;version=1.0.0, + org.apache.commons.lang.builder;version=1.0.0, + org.apache.log4j;version=1.0.0, + org.codehaus.jackson;version=1.9.0, + org.codehaus.jackson.map;version=1.9.0, + javax.crypto, + javax.crypto.spec, + javax.security.auth, + javax.security.auth.callback, + javax.security.sasl, + javax.servlet, + javax.servlet.http, + javax.management;version=1.0.0, + javax.management.openmbean;version=1.0.0, + org.osgi.util.tracker;version=1.0.0, + org.osgi.framework;version=1.3 +Private-Package: org.apache.qpid.server.management.plugin.impl +Export-Package: org.apache.qpid.server.management.plugin;uses:="org.osgi.framework" diff --git a/qpid/java/broker-plugins/management/build.xml b/qpid/java/broker-plugins/management/build.xml new file mode 100644 index 0000000000..4a28ff2659 --- /dev/null +++ b/qpid/java/broker-plugins/management/build.xml @@ -0,0 +1,39 @@ +<!-- + - 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. + --> +<project name="Qpid Broker-Plugins Management" default="build"> + <property name="module.depends" value="common broker broker-plugins broker-plugins-management" /> + <property name="module.test.depends" value="test broker/test common/test management/common" /> + + <property name="module.manifest" value="MANIFEST.MF" /> + <property name="module.plugin" value="true" /> + + <import file="../../module.xml" /> + + <target name="precompile"> + <unwar src="${project.root}/${dojo}" dest="${module.classes}/resources/dojo"> + <patternset> + <exclude name="META-INF/**"/> + <exclude name="WEB-INF/**"/> + <exclude name="**/*.uncompressed.js"/> + </patternset> + </unwar> + </target> + + <target name="bundle" depends="bundle-tasks" /> +</project> diff --git a/qpid/java/broker-plugins/management/src/main/java/org/apache/qpid/server/management/plugin/Management.java b/qpid/java/broker-plugins/management/src/main/java/org/apache/qpid/server/management/plugin/Management.java new file mode 100644 index 0000000000..589f46749d --- /dev/null +++ b/qpid/java/broker-plugins/management/src/main/java/org/apache/qpid/server/management/plugin/Management.java @@ -0,0 +1,155 @@ +/* + * + * 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.management.plugin; + +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.util.ArrayList; +import java.util.Collection; +import org.apache.log4j.Logger; +import org.apache.qpid.server.management.plugin.servlet.DefinedFileServlet; +import org.apache.qpid.server.management.plugin.servlet.FileServlet; +import org.apache.qpid.server.management.plugin.servlet.api.ExchangesServlet; +import org.apache.qpid.server.management.plugin.servlet.api.VhostsServlet; +import org.apache.qpid.server.management.plugin.servlet.rest.*; +import org.apache.qpid.server.model.*; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.SessionManager; +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.servlet.ServletHolder; + +public class Management +{ + + private final Logger _logger = Logger.getLogger(Management.class); + + private Broker _broker; + + private Collection<Server> _servers = new ArrayList<Server>(); + + + public Management() + { + _broker = ApplicationRegistry.getInstance().getBroker(); + + Collection<Port> ports = _broker.getPorts(); + for(Port port : ports) + { + // TODO - cover cases where more than just HTTP supported, and SSL as a transport + if(port.getProtocols().contains(Protocol.HTTP)) + { + if(port.getTransports().contains(Transport.TCP)) + { + int portNumber = port.getPort(); + if (_logger.isInfoEnabled()) + { + _logger.info("Creating web server on port " + portNumber); + } + _servers.add(createServer(portNumber)); + } + } + } + + if (_logger.isDebugEnabled()) + { + _logger.info(_servers.size() + " server(s) defined"); + } + + } + + private Server createServer(int port) + { + _logger.info("Starting up web server on port " + port); + + Server server = new Server(port); + SocketAddress socketAddress = new InetSocketAddress(port); + + ServletContextHandler root = new ServletContextHandler(ServletContextHandler.SESSIONS); + root.setContextPath("/"); + server.setHandler(root); + + root.addServlet(new ServletHolder(new VhostsServlet(_broker)), "/api/vhosts/*"); + root.addServlet(new ServletHolder(new ExchangesServlet(_broker)), "/api/exchanges/*"); + + addRestServlet(root, "broker", socketAddress); + addRestServlet(root, "virtualhost", socketAddress, VirtualHost.class); + addRestServlet(root, "authenticationprovider", socketAddress, AuthenticationProvider.class); + addRestServlet(root, "user", socketAddress, AuthenticationProvider.class, User.class); + addRestServlet(root, "exchange", socketAddress, VirtualHost.class, Exchange.class); + addRestServlet(root, "queue", socketAddress, VirtualHost.class, Queue.class); + addRestServlet(root, "connection", socketAddress, VirtualHost.class, Connection.class); + addRestServlet(root, "binding", socketAddress, VirtualHost.class, Exchange.class, Queue.class, Binding.class); + addRestServlet(root, "port", socketAddress, Port.class); + addRestServlet(root, "session", socketAddress, VirtualHost.class, Connection.class, Session.class); + + root.addServlet(new ServletHolder(new StructureServlet(_broker, socketAddress)), "/rest/structure"); + root.addServlet(new ServletHolder(new MessageServlet(_broker, socketAddress)), "/rest/message/*"); + root.addServlet(new ServletHolder(new MessageContentServlet(_broker, socketAddress)), "/rest/message-content/*"); + + root.addServlet(new ServletHolder(new LogRecordsServlet(_broker, socketAddress)), "/rest/logrecords"); + + + root.addServlet(new ServletHolder(new SaslServlet(_broker, socketAddress)), "/rest/sasl"); + + root.addServlet(new ServletHolder(new DefinedFileServlet("management.html")),"/management"); + + + root.addServlet(new ServletHolder(FileServlet.INSTANCE), "*.js"); + root.addServlet(new ServletHolder(FileServlet.INSTANCE), "*.css"); + root.addServlet(new ServletHolder(FileServlet.INSTANCE), "*.html"); + root.addServlet(new ServletHolder(FileServlet.INSTANCE), "*.png"); + root.addServlet(new ServletHolder(FileServlet.INSTANCE), "*.gif"); + root.addServlet(new ServletHolder(FileServlet.INSTANCE), "*.jpg"); + root.addServlet(new ServletHolder(FileServlet.INSTANCE), "*.jpeg"); + root.addServlet(new ServletHolder(FileServlet.INSTANCE), "*.json"); + root.addServlet(new ServletHolder(FileServlet.INSTANCE), "*.txt"); + root.addServlet(new ServletHolder(FileServlet.INSTANCE), "*.xsl"); + + final SessionManager sessionManager = root.getSessionHandler().getSessionManager(); + + sessionManager.setMaxInactiveInterval(60 * 15); + + return server; + } + + private void addRestServlet(ServletContextHandler root, String name, SocketAddress socketAddress, Class<? extends ConfiguredObject>... hierarchy) + { + root.addServlet(new ServletHolder(new RestServlet(_broker, socketAddress, hierarchy)), "/rest/"+name+"/*"); + } + + public void start() throws Exception + { + for(Server server : _servers) + { + server.start(); + } + } + + public void stop() throws Exception + { + for(Server server : _servers) + { + server.stop(); + } + } + +} diff --git a/qpid/java/broker-plugins/management/src/main/java/org/apache/qpid/server/management/plugin/ManagementActivator.java b/qpid/java/broker-plugins/management/src/main/java/org/apache/qpid/server/management/plugin/ManagementActivator.java new file mode 100644 index 0000000000..2600d8a7bf --- /dev/null +++ b/qpid/java/broker-plugins/management/src/main/java/org/apache/qpid/server/management/plugin/ManagementActivator.java @@ -0,0 +1,72 @@ +/* + * + * 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.management.plugin; + +import org.apache.log4j.Logger; +import org.apache.qpid.server.configuration.plugins.ConfigurationPluginFactory; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; + +public class ManagementActivator implements BundleActivator +{ + private static final Logger _logger = Logger.getLogger(ManagementActivator.class); + + + private BundleContext _ctx; + private String _bundleName; + private Management _managementService; + + + public void start(final BundleContext ctx) throws Exception + { + _ctx = ctx; + if (!ApplicationRegistry.getInstance().getConfiguration().getHTTPManagementEnabled()) + { + _logger.info("Management plugin is diabled!"); + ctx.getBundle().uninstall(); + return; + } + _managementService = new Management(); + _managementService.start(); + _bundleName = ctx.getBundle().getSymbolicName(); + + // register the service + _logger.info("Registering management plugin: " + _bundleName); + _ctx.registerService(Management.class.getName(), _managementService, null); + _ctx.registerService(ConfigurationPluginFactory.class.getName(), ManagementConfiguration.FACTORY, null); + } + + public void stop(final BundleContext bundleContext) throws Exception + { + if (_managementService != null) + { + _logger.info("Stopping management plugin: " + _bundleName); + + _managementService.stop(); + + // null object references + _managementService = null; + } + _ctx = null; + } + +} diff --git a/qpid/java/broker-plugins/management/src/main/java/org/apache/qpid/server/management/plugin/ManagementConfiguration.java b/qpid/java/broker-plugins/management/src/main/java/org/apache/qpid/server/management/plugin/ManagementConfiguration.java new file mode 100644 index 0000000000..3866da8f89 --- /dev/null +++ b/qpid/java/broker-plugins/management/src/main/java/org/apache/qpid/server/management/plugin/ManagementConfiguration.java @@ -0,0 +1,77 @@ +/* + * + * 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.management.plugin; + +import org.apache.commons.configuration.CompositeConfiguration; +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.commons.configuration.XMLConfiguration; + +import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; +import org.apache.qpid.server.configuration.plugins.ConfigurationPluginFactory; + +import java.util.Arrays; +import java.util.List; + +public class ManagementConfiguration extends ConfigurationPlugin +{ + CompositeConfiguration _finalConfig; + + public static final ConfigurationPluginFactory FACTORY = new ConfigurationPluginFactory() + { + public ConfigurationPlugin newInstance(String path, Configuration config) throws ConfigurationException + { + ConfigurationPlugin instance = new ManagementConfiguration(); + instance.setConfiguration(path, config); + return instance; + } + + public List<String> getParentPaths() + { + return Arrays.asList("management"); + } + }; + + public String[] getElementsProcessed() + { + return new String[] { "" }; + } + + public Configuration getConfiguration() + { + return _finalConfig; + } + + + @Override + public void validateConfiguration() throws ConfigurationException + { + // Valid Configuration either has xml links to new files + _finalConfig = new CompositeConfiguration(getConfig()); + List subFiles = getConfig().getList("xml[@fileName]"); + for (Object subFile : subFiles) + { + _finalConfig.addConfiguration(new XMLConfiguration((String) subFile)); + } + + } + +} diff --git a/qpid/java/broker-plugins/management/src/main/java/org/apache/qpid/server/management/plugin/servlet/DefinedFileServlet.java b/qpid/java/broker-plugins/management/src/main/java/org/apache/qpid/server/management/plugin/servlet/DefinedFileServlet.java new file mode 100644 index 0000000000..d66555787f --- /dev/null +++ b/qpid/java/broker-plugins/management/src/main/java/org/apache/qpid/server/management/plugin/servlet/DefinedFileServlet.java @@ -0,0 +1,79 @@ +package org.apache.qpid.server.management.plugin.servlet; + +import java.io.IOException; +import java.io.InputStream; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * 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 + * <p/> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p/> + * 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. + */ +public class DefinedFileServlet extends HttpServlet +{ + + private static final String FILENAME_INIT_PARAMETER = "filename"; + + private String _filename; + + public DefinedFileServlet() + { + super(); + } + + public DefinedFileServlet(String filename) + { + _filename = filename; + } + + @Override + public void init() throws ServletException + { + ServletConfig config = getServletConfig(); + String fileName = config.getInitParameter(FILENAME_INIT_PARAMETER); + if (fileName != null && !"".equals(fileName)) + { + _filename = fileName; + } + } + + @Override + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + { + final ServletOutputStream output = response.getOutputStream(); + InputStream fileInput = getClass().getResourceAsStream("/resources/"+_filename); + + if(fileInput != null) + { + byte[] buffer = new byte[1024]; + response.setStatus(HttpServletResponse.SC_OK); + int read = 0; + + while((read = fileInput.read(buffer)) > 0) + { + output.write(buffer, 0, read); + } + } + else + { + response.sendError(404, "unknown file: "+ _filename); + } + } +} diff --git a/qpid/java/broker-plugins/management/src/main/java/org/apache/qpid/server/management/plugin/servlet/FileServlet.java b/qpid/java/broker-plugins/management/src/main/java/org/apache/qpid/server/management/plugin/servlet/FileServlet.java new file mode 100644 index 0000000000..f8ca082d79 --- /dev/null +++ b/qpid/java/broker-plugins/management/src/main/java/org/apache/qpid/server/management/plugin/servlet/FileServlet.java @@ -0,0 +1,109 @@ +/* + * + * 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.management.plugin.servlet; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import javax.servlet.ServletException; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +public class FileServlet extends HttpServlet +{ + public static final FileServlet INSTANCE = new FileServlet(); + + private static final Map<String, String> CONTENT_TYPES; + + static + { + + Map<String, String> contentTypes = new HashMap<String, String>(); + contentTypes.put("js", "application/javascript"); + contentTypes.put("html", "text/html"); + contentTypes.put("css", "text/css"); + contentTypes.put("json", "application/json"); + contentTypes.put("jpg", "image/jpg"); + contentTypes.put("png", "image/png"); + contentTypes.put("gif", "image/gif"); + CONTENT_TYPES = Collections.unmodifiableMap(contentTypes); + } + + + public FileServlet() + { + } + + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + { + String filename = request.getServletPath(); + if(filename.contains(".")) + { + String suffix = filename.substring(filename.lastIndexOf('.')+1); + String contentType = CONTENT_TYPES.get(suffix); + if(contentType != null) + { + response.setContentType(contentType); + } + } + URL resourceURL = getClass().getResource("/resources" + filename); + if(resourceURL != null) + { + response.setStatus(HttpServletResponse.SC_OK); + InputStream fileInput = resourceURL.openStream(); + try + { + byte[] buffer = new byte[1024]; + int read = 0; + ServletOutputStream output = response.getOutputStream(); + try + { + while((read = fileInput.read(buffer)) != -1) + { + output.write(buffer, 0, read); + } + } + finally + { + output.close(); + } + } + finally + { + fileInput.close(); + } + } + else + { + response.sendError(404, "unknown file: "+ filename); + } + + } + +} diff --git a/qpid/java/broker-plugins/management/src/main/java/org/apache/qpid/server/management/plugin/servlet/api/ExchangesServlet.java b/qpid/java/broker-plugins/management/src/main/java/org/apache/qpid/server/management/plugin/servlet/api/ExchangesServlet.java new file mode 100644 index 0000000000..a3c5ec68a2 --- /dev/null +++ b/qpid/java/broker-plugins/management/src/main/java/org/apache/qpid/server/management/plugin/servlet/api/ExchangesServlet.java @@ -0,0 +1,208 @@ +/* + * + * 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.management.plugin.servlet.api; + +import org.codehaus.jackson.map.ObjectMapper; +import org.codehaus.jackson.map.ObjectReader; + +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.State; +import org.apache.qpid.server.model.VirtualHost; +import org.apache.qpid.server.registry.ApplicationRegistry; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +public class ExchangesServlet extends HttpServlet +{ + + + private Broker _broker; + + public ExchangesServlet() + { + super(); + _broker = ApplicationRegistry.getInstance().getBroker(); + } + + public ExchangesServlet(Broker broker) + { + _broker = broker; + } + + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + { + response.setContentType("application/json"); + response.setStatus(HttpServletResponse.SC_OK); + + Collection<VirtualHost> vhosts = _broker.getVirtualHosts(); + Collection<Exchange> exchanges = new ArrayList<Exchange>(); + Collection<Map<String,Object>> outputObject = new ArrayList<Map<String,Object>>(); + + final PrintWriter writer = response.getWriter(); + + ObjectMapper mapper = new ObjectMapper(); + String vhostName = null; + String exchangeName = null; + + if(request.getPathInfo() != null && request.getPathInfo().length()>0) + { + String path = request.getPathInfo().substring(1); + String[] parts = path.split("/"); + vhostName = parts.length == 0 ? "" : parts[0]; + if(parts.length > 1) + { + exchangeName = parts[1]; + } + } + + for(VirtualHost vhost : vhosts) + { + if(vhostName == null || vhostName.equals(vhost.getName())) + { + for(Exchange exchange : vhost.getExchanges()) + { + if(exchangeName == null || exchangeName.equals(exchange.getName())) + { + outputObject.add(convertToObject(exchange)); + if(exchangeName != null) + { + break; + } + } + } + if(vhostName != null) + { + break; + } + } + } + + mapper.writeValue(writer, outputObject); + + } + + private Map<String,Object> convertToObject(final Exchange exchange) + { + Map<String, Object> object = new LinkedHashMap<String, Object>(); + object.put("name",exchange.getName()); + object.put("type", exchange.getExchangeType()); + object.put("durable", exchange.isDurable()); + object.put("auto-delete", exchange.getLifetimePolicy() == LifetimePolicy.AUTO_DELETE); + + Map<String,Object> arguments = new HashMap<String, Object>(); + for(String key : exchange.getAttributeNames()) + { + if(!key.equals(Exchange.TYPE)) + { + arguments.put(key, exchange.getAttribute(key)); + } + } + object.put("arguments", arguments); + return object; + } + + protected void doPut(final HttpServletRequest request, final HttpServletResponse response) + throws ServletException, IOException + { + + response.setContentType("application/json"); + + + String vhostName = null; + String exchangeName = null; + if(request.getPathInfo() != null && request.getPathInfo().length()>0) + { + String path = request.getPathInfo().substring(1); + String[] parts = path.split("/"); + vhostName = parts.length == 0 ? "" : parts[0]; + if(parts.length > 1) + { + exchangeName = parts[1]; + } + } + if(vhostName == null) + { + response.setStatus(HttpServletResponse.SC_PRECONDITION_FAILED); + } + else if (exchangeName == null) + { + response.setStatus(HttpServletResponse.SC_PRECONDITION_FAILED); + } + else + { + VirtualHost vhost = null; + for(VirtualHost host : _broker.getVirtualHosts()) + { + if(host.getName().equals(vhostName)) + { + vhost = host; + } + } + if(vhost == null) + { + response.setStatus(HttpServletResponse.SC_PRECONDITION_FAILED); + } + else + { + response.setStatus(HttpServletResponse.SC_NO_CONTENT); + ObjectMapper mapper = new ObjectMapper(); + Map<String,Object> exchangeObject = mapper.readValue(request.getInputStream(), LinkedHashMap.class); + + final boolean isDurable = exchangeObject.get("durable") instanceof Boolean + && ((Boolean)exchangeObject.get("durable")); + final boolean isAutoDelete = exchangeObject.get("auto_delete") instanceof Boolean + && ((Boolean)exchangeObject.get("auto_delete")); + + final String type = (String) exchangeObject.get("type"); + final Map<String, Object> attributes = new HashMap<String, Object>(exchangeObject); + attributes.remove("durable"); + attributes.remove("auto_delete"); + attributes.remove("type"); + + vhost.createExchange(exchangeName, State.ACTIVE, isDurable, + isAutoDelete ? LifetimePolicy.AUTO_DELETE : LifetimePolicy.PERMANENT, + 0l, + type, + attributes); + } + + + + } + + + + } +} diff --git a/qpid/java/broker-plugins/management/src/main/java/org/apache/qpid/server/management/plugin/servlet/api/VhostsServlet.java b/qpid/java/broker-plugins/management/src/main/java/org/apache/qpid/server/management/plugin/servlet/api/VhostsServlet.java new file mode 100644 index 0000000000..b2c0fcfe52 --- /dev/null +++ b/qpid/java/broker-plugins/management/src/main/java/org/apache/qpid/server/management/plugin/servlet/api/VhostsServlet.java @@ -0,0 +1,118 @@ +/* + * + * 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.management.plugin.servlet.api; + +import org.codehaus.jackson.map.ObjectMapper; + +import org.apache.qpid.common.QpidProperties; +import org.apache.qpid.server.model.Broker; +import org.apache.qpid.server.model.LifetimePolicy; +import org.apache.qpid.server.model.State; +import org.apache.qpid.server.model.VirtualHost; +import org.apache.qpid.server.protocol.AMQConnectionModel; +import org.apache.qpid.server.registry.ApplicationRegistry; + + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.*; + +public class VhostsServlet extends HttpServlet +{ + + + private Broker _broker; + + public VhostsServlet() + { + super(); + _broker = ApplicationRegistry.getInstance().getBroker(); + } + + public VhostsServlet(Broker broker) + { + _broker = broker; + } + + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + { +System.out.println("Get /api/vhosts"); + response.setContentType("application/json"); + response.setStatus(HttpServletResponse.SC_OK); + + Collection<VirtualHost> vhosts = _broker.getVirtualHosts(); + + + + final PrintWriter writer = response.getWriter(); + + ObjectMapper mapper = new ObjectMapper(); + + if(request.getPathInfo() == null || request.getPathInfo().length()==0) + { + + LinkedHashMap<String, Object> vhostObject = new LinkedHashMap<String, Object>(); + List<Map> vhostList = new ArrayList<Map>(); + + for(VirtualHost vhost : vhosts) + { + vhostList.add(Collections.singletonMap("name", vhost.getName())); + } + mapper.writeValue(writer, vhostList); + } + else + { + LinkedHashMap<String, Object> vhostObject = new LinkedHashMap<String, Object>(); + String vhostName = request.getPathInfo().substring(1); + + for(VirtualHost vhost : vhosts) + { + if(vhostName.equals(vhost.getName())) + { + vhostObject.put("name", vhost.getName()); + break; + } + } + mapper.writeValue(writer, vhostObject); + } + } + + + protected void doPut(final HttpServletRequest request, final HttpServletResponse response) + throws ServletException, IOException + { + + response.setContentType("application/json"); + response.setStatus(HttpServletResponse.SC_NO_CONTENT); + + if(request.getPathInfo() != null && request.getPathInfo().length()>0) + { + String vhostName = request.getPathInfo().substring(1); + _broker.createVirtualHost(vhostName, State.ACTIVE, true, LifetimePolicy.PERMANENT, 0L, Collections.EMPTY_MAP); + } + + + } +} diff --git a/qpid/java/broker-plugins/management/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/AbstractServlet.java b/qpid/java/broker-plugins/management/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/AbstractServlet.java new file mode 100644 index 0000000000..123f352ec1 --- /dev/null +++ b/qpid/java/broker-plugins/management/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/AbstractServlet.java @@ -0,0 +1,215 @@ +/* + * + * 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.management.plugin.servlet.rest; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.security.Principal; +import java.util.Collections; +import javax.security.auth.Subject; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; +import org.apache.commons.codec.binary.Base64; +import org.apache.qpid.server.model.Broker; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.security.auth.AuthenticationResult; +import org.apache.qpid.server.security.auth.manager.AnonymousAuthenticationManager; +import org.apache.qpid.server.security.auth.manager.AuthenticationManager; + +public abstract class AbstractServlet extends HttpServlet +{ + private final Broker _broker; + private SocketAddress _socketAddress; + + protected AbstractServlet() + { + super(); + _broker = ApplicationRegistry.getInstance().getBroker(); + _socketAddress = null; + } + + protected AbstractServlet(Broker broker, SocketAddress socketAddress) + { + _broker = broker; + _socketAddress = socketAddress; + } + + @Override + protected final void doGet(HttpServletRequest request, HttpServletResponse resp) throws ServletException, IOException + { + setAuthorizedSubject(request); + try + { + onGet(request, resp); + } + finally + { + clearAuthorizedSubject(); + } + } + + protected void onGet(HttpServletRequest request, HttpServletResponse resp) throws IOException, ServletException + { + super.doGet(request, resp); + } + + private void clearAuthorizedSubject() + { + org.apache.qpid.server.security.SecurityManager.setThreadSubject(null); + } + + + private void setAuthorizedSubject(HttpServletRequest request) + { + HttpSession session = request.getSession(true); + Subject subject = (Subject) session.getAttribute("subject"); + + if(subject == null) + { + Principal principal = request.getUserPrincipal(); + if(principal != null) + { + subject = new Subject(false, Collections.singleton(principal),Collections.emptySet(), + Collections.emptySet()); + } + else + { + String header = request.getHeader("Authorization"); + + /* + * TODO - Should configure whether basic authentication is allowed... and in particular whether it + * should be allowed over non-ssl connections + * */ + + if (header != null) + { + String[] tokens = header.split("\\s"); + if(tokens.length >= 2 + && "BASIC".equalsIgnoreCase(tokens[0])) + { + String[] credentials = (new String(Base64.decodeBase64(tokens[1].getBytes()))).split(":",2); + if(credentials.length == 2) + { + SocketAddress address = getSocketAddress(request); + AuthenticationManager authenticationManager = + ApplicationRegistry.getInstance().getAuthenticationManager(address); + AuthenticationResult authResult = + authenticationManager.authenticate(credentials[0], credentials[1]); + subject = authResult.getSubject(); + + } + } + } + } + } + if (subject == null) + { + subject = AnonymousAuthenticationManager.ANONYMOUS_SUBJECT; + } + org.apache.qpid.server.security.SecurityManager.setThreadSubject(subject); + + } + + protected Subject getSubject(HttpSession session) + { + return (Subject)session.getAttribute("subject"); + } + + @Override + protected final void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException + { + setAuthorizedSubject(req); + try + { + onPost(req, resp); + } + finally + { + clearAuthorizedSubject(); + } + + } + + protected void onPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException + { + super.doPost(req, resp); + } + + @Override + protected final void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException + { + setAuthorizedSubject(req); + try + { + onPut(req, resp); + + } + finally + { + clearAuthorizedSubject(); + } + } + + protected void onPut(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException + { + super.doPut(req,resp); + } + + @Override + protected final void doDelete(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException + { + setAuthorizedSubject(req); + try + { + onDelete(req, resp); + } + finally + { + clearAuthorizedSubject(); + } + } + + protected void onDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException + { + super.doDelete(req, resp); + } + + + protected Broker getBroker() + { + return _broker; + } + + protected SocketAddress getSocketAddress(HttpServletRequest request) + { + if (_socketAddress == null) + { + return InetSocketAddress.createUnresolved(request.getServerName(), request.getServerPort()); + } + return _socketAddress; + } +} diff --git a/qpid/java/broker-plugins/management/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/KeyComparator.java b/qpid/java/broker-plugins/management/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/KeyComparator.java new file mode 100644 index 0000000000..3d862ce321 --- /dev/null +++ b/qpid/java/broker-plugins/management/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/KeyComparator.java @@ -0,0 +1,53 @@ +/* + * + * 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.management.plugin.servlet.rest; + +import java.util.Comparator; +import java.util.Map; + +class KeyComparator implements Comparator<Map> +{ + private String _key; + + public KeyComparator(final String key) + { + _key = key; + } + + public int compare(final Map o1, final Map o2) + { + Comparable left = (Comparable) o1.get(_key); + Comparable right = (Comparable) o2.get(_key); + + int result; + if(left == null) + { + result = right == null ? 0 : -1; + } + else + { + result = left.compareTo(right); + } + + return result; + + } +} diff --git a/qpid/java/broker-plugins/management/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/LogRecordsServlet.java b/qpid/java/broker-plugins/management/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/LogRecordsServlet.java new file mode 100644 index 0000000000..7a4b92f907 --- /dev/null +++ b/qpid/java/broker-plugins/management/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/LogRecordsServlet.java @@ -0,0 +1,86 @@ +/* + * 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.management.plugin.servlet.rest; + +import java.io.IOException; +import java.io.PrintWriter; +import java.net.SocketAddress; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.apache.qpid.server.logging.LogRecorder; +import org.apache.qpid.server.model.Broker; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.codehaus.jackson.map.ObjectMapper; +import org.codehaus.jackson.map.SerializationConfig; + +public class LogRecordsServlet extends AbstractServlet +{ + public LogRecordsServlet() + { + super(ApplicationRegistry.getInstance().getBroker(), null); + } + + public LogRecordsServlet(Broker broker, SocketAddress socketaddress) + { + super(broker, socketaddress); + } + + @Override + protected void onGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + { + response.setContentType("application/json"); + response.setStatus(HttpServletResponse.SC_OK); + + response.setHeader("Cache-Control","no-cache"); + response.setHeader("Pragma","no-cache"); + response.setDateHeader ("Expires", 0); + + ApplicationRegistry applicationRegistry = (ApplicationRegistry) ApplicationRegistry.getInstance(); + List<Map<String,Object>> logRecords = new ArrayList<Map<String, Object>>(); + + for(LogRecorder.Record record : applicationRegistry.getLogRecorder()) + { + logRecords.add(logRecordToObject(record)); + } + + final PrintWriter writer = response.getWriter(); + ObjectMapper mapper = new ObjectMapper(); + mapper.configure(SerializationConfig.Feature.INDENT_OUTPUT, true); + mapper.writeValue(writer, logRecords); + + response.setStatus(HttpServletResponse.SC_OK); + + } + + private Map<String, Object> logRecordToObject(LogRecorder.Record record) + { + Map<String, Object> recordMap = new LinkedHashMap<String, Object>(); + recordMap.put("id",record.getId()); + recordMap.put("timestamp", record.getTimestamp()); + recordMap.put("level", record.getLevel()); + recordMap.put("thread", record.getThreadName()); + recordMap.put("logger", record.getLogger()); + recordMap.put("message", record.getMessage()); + return recordMap; + } + +} diff --git a/qpid/java/broker-plugins/management/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MapComparator.java b/qpid/java/broker-plugins/management/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MapComparator.java new file mode 100644 index 0000000000..84d987813b --- /dev/null +++ b/qpid/java/broker-plugins/management/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MapComparator.java @@ -0,0 +1,74 @@ +/* + * + * 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.management.plugin.servlet.rest; + +import java.util.Collections; +import java.util.Comparator; +import java.util.Map; + +class MapComparator implements Comparator<Map> +{ + private Comparator<Map>[] _sortKeys; + + public MapComparator(final String[] sortKeys) + { + _sortKeys = parseKeys(sortKeys); + } + + private static Comparator<Map>[] parseKeys(final String[] sortKeys) + { + Comparator<Map>[] comparators = new Comparator[sortKeys.length]; + for(int i = 0; i < sortKeys.length; i++) + { + String key = sortKeys[i]; + + if(key.startsWith("+") || key.startsWith(" ")) + { + comparators[i] = new KeyComparator(key.substring(1)); + } + else if(key.startsWith("-")) + { + comparators[i] = Collections.reverseOrder(new KeyComparator(key.substring(1))); + } + else + { + comparators[i] = new KeyComparator(key); + } + } + return comparators; + } + + + public int compare(final Map o1, final Map o2) + { + int result = 0; + for(int i = 0; i < _sortKeys.length; i++) + { + result = _sortKeys[i].compare(o1, o2); + if(result != 0) + { + return result; + } + } + return 0; + } + +} diff --git a/qpid/java/broker-plugins/management/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MessageContentServlet.java b/qpid/java/broker-plugins/management/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MessageContentServlet.java new file mode 100644 index 0000000000..4d58a9f3b0 --- /dev/null +++ b/qpid/java/broker-plugins/management/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MessageContentServlet.java @@ -0,0 +1,177 @@ +/* + * 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.management.plugin.servlet.rest; + +import java.io.IOException; +import java.net.SocketAddress; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.qpid.server.message.MessageReference; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.model.Broker; +import org.apache.qpid.server.model.Queue; +import org.apache.qpid.server.model.VirtualHost; +import org.apache.qpid.server.queue.QueueEntry; +import org.apache.qpid.server.queue.QueueEntryVisitor; + +public class MessageContentServlet extends AbstractServlet +{ + public MessageContentServlet() + { + super(); + } + + public MessageContentServlet(Broker broker, SocketAddress socketaddress) + { + super(broker, socketaddress); + } + + @Override + protected void onGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + { + + if(request.getPathInfo() != null && request.getPathInfo().length()>0 && request.getPathInfo().substring(1).split("/").length > 2) + { + getMessageContent(request, response); + } + + } + + private void getMessageContent(HttpServletRequest request, HttpServletResponse response) throws IOException + { + Queue queue = getQueueFromRequest(request); + String path[] = request.getPathInfo().substring(1).split("/"); + MessageFinder finder = new MessageFinder(Long.parseLong(path[2])); + queue.visit(finder); + if(finder.isFound()) + { + response.setContentType(finder.getMimeType()); + response.setContentLength((int) finder.getSize()); + response.getOutputStream().write(finder.getContent()); + + } + + } + + private Queue getQueueFromRequest(HttpServletRequest request) + { + List<String> names = new ArrayList<String>(); + // TODO - validation that there is a vhost and queue and only those in the path + if(request.getPathInfo() != null && request.getPathInfo().length()>0) + { + String path = request.getPathInfo().substring(1); + names.addAll(Arrays.asList(path.split("/"))); + } + String vhostName = names.get(0); + String queueName = names.get(1); + + VirtualHost vhost = null; + + for(VirtualHost vh : getBroker().getVirtualHosts()) + { + if(vh.getName().equals(vhostName)) + { + vhost = vh; + break; + } + } + + return getQueueFromVirtualHost(queueName, vhost); + } + + private Queue getQueueFromVirtualHost(String queueName, VirtualHost vhost) + { + Queue queue = null; + + for(Queue q : vhost.getQueues()) + { + if(q.getName().equals(queueName)) + { + queue = q; + break; + } + } + return queue; + } + + private class MessageFinder implements QueueEntryVisitor + { + private final long _messageNumber; + private String _mimeType; + private long _size; + private byte[] _content; + private boolean _found; + + private MessageFinder(long messageNumber) + { + _messageNumber = messageNumber; + } + + + public boolean visit(QueueEntry entry) + { + ServerMessage message = entry.getMessage(); + if(message != null) + { + if(_messageNumber == message.getMessageNumber()) + { + MessageReference reference = message.newReference(); + + _mimeType = message.getMessageHeader().getMimeType(); + _size = message.getSize(); + _content = new byte[(int)_size]; + _found = true; + message.getContent(ByteBuffer.wrap(_content),0); + reference.release(); + return true; + } + + } + return false; + } + + public String getMimeType() + { + return _mimeType; + } + + public long getSize() + { + return _size; + } + + public byte[] getContent() + { + return _content; + } + + public boolean isFound() + { + return _found; + } + } + + +} diff --git a/qpid/java/broker-plugins/management/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MessageServlet.java b/qpid/java/broker-plugins/management/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MessageServlet.java new file mode 100644 index 0000000000..b47dc8b28e --- /dev/null +++ b/qpid/java/broker-plugins/management/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MessageServlet.java @@ -0,0 +1,503 @@ +/* + * 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.management.plugin.servlet.rest; + +import java.io.IOException; +import java.io.PrintWriter; +import java.net.SocketAddress; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.log4j.Logger; +import org.apache.qpid.server.message.AMQMessageHeader; +import org.apache.qpid.server.message.MessageReference; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.model.Broker; +import org.apache.qpid.server.model.Queue; +import org.apache.qpid.server.model.VirtualHost; +import org.apache.qpid.server.queue.QueueEntry; +import org.apache.qpid.server.queue.QueueEntryVisitor; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.registry.IApplicationRegistry; +import org.apache.qpid.server.security.SecurityManager; +import org.apache.qpid.server.security.access.Operation; +import org.apache.qpid.server.subscription.Subscription; +import org.codehaus.jackson.map.ObjectMapper; +import org.codehaus.jackson.map.SerializationConfig; + +public class MessageServlet extends AbstractServlet +{ + private static final Logger LOGGER = Logger.getLogger(MessageServlet.class); + + public MessageServlet() + { + super(); + } + + public MessageServlet(Broker broker, SocketAddress socketaddress) + { + super(broker, socketaddress); + } + + @Override + protected void onGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + { + + if(request.getPathInfo() != null && request.getPathInfo().length()>0 && request.getPathInfo().substring(1).split("/").length > 2) + { + getMessageContent(request, response); + } + else + { + getMessageList(request, response); + } + + } + + private void getMessageContent(HttpServletRequest request, HttpServletResponse response) throws IOException + { + Queue queue = getQueueFromRequest(request); + String path[] = request.getPathInfo().substring(1).split("/"); + MessageFinder messageFinder = new MessageFinder(Long.parseLong(path[2])); + queue.visit(messageFinder); + + response.setStatus(HttpServletResponse.SC_OK); + + response.setHeader("Cache-Control","no-cache"); + response.setHeader("Pragma","no-cache"); + response.setDateHeader ("Expires", 0); + + final PrintWriter writer = response.getWriter(); + ObjectMapper mapper = new ObjectMapper(); + mapper.configure(SerializationConfig.Feature.INDENT_OUTPUT, true); + mapper.writeValue(writer, messageFinder.getMessageObject()); + } + + private void getMessageList(HttpServletRequest request, HttpServletResponse response) throws IOException + { + Queue queue = getQueueFromRequest(request); + + int first = -1; + int last = -1; + String range = request.getHeader("Range"); + if(range != null) + { + String[] boundaries = range.split("=")[1].split("-"); + first = Integer.parseInt(boundaries[0]); + last = Integer.parseInt(boundaries[1]); + } + final MessageCollector messageCollector = new MessageCollector(first, last); + queue.visit(messageCollector); + + response.setContentType("application/json"); + final List<Map<String, Object>> messages = messageCollector.getMessages(); + int queueSize = ((Number) queue.getStatistics().getStatistic(Queue.QUEUE_DEPTH_MESSAGES)).intValue(); + String min = messages.isEmpty() ? "0" : messages.get(0).get("position").toString(); + String max = messages.isEmpty() ? "0" : messages.get(messages.size()-1).get("position").toString(); + response.setHeader("Content-Range", (min + "-" + max + "/" + queueSize)); + response.setStatus(HttpServletResponse.SC_OK); + + response.setHeader("Cache-Control","no-cache"); + response.setHeader("Pragma","no-cache"); + response.setDateHeader ("Expires", 0); + + final PrintWriter writer = response.getWriter(); + ObjectMapper mapper = new ObjectMapper(); + mapper.configure(SerializationConfig.Feature.INDENT_OUTPUT, true); + mapper.writeValue(writer, messages); + } + + private Queue getQueueFromRequest(HttpServletRequest request) + { + List<String> names = new ArrayList<String>(); + // TODO - validation that there is a vhost and queue and only those in the path + if(request.getPathInfo() != null && request.getPathInfo().length()>0) + { + String path = request.getPathInfo().substring(1); + names.addAll(Arrays.asList(path.split("/"))); + } + String vhostName = names.get(0); + String queueName = names.get(1); + + VirtualHost vhost = null; + + for(VirtualHost vh : getBroker().getVirtualHosts()) + { + if(vh.getName().equals(vhostName)) + { + vhost = vh; + break; + } + } + + return getQueueFromVirtualHost(queueName, vhost); + } + + private Queue getQueueFromVirtualHost(String queueName, VirtualHost vhost) + { + Queue queue = null; + + for(Queue q : vhost.getQueues()) + { + + if(q.getName().equals(queueName)) + { + queue = q; + break; + } + } + return queue; + } + + private abstract static class QueueEntryTransaction implements VirtualHost.TransactionalOperation + { + private final Queue _sourceQueue; + private final List _messageIds; + + protected QueueEntryTransaction(Queue sourceQueue, List messageIds) + { + _sourceQueue = sourceQueue; + _messageIds = messageIds; + } + + + public void withinTransaction(final VirtualHost.Transaction txn) + { + + _sourceQueue.visit(new QueueEntryVisitor() + { + + public boolean visit(final QueueEntry entry) + { + final ServerMessage message = entry.getMessage(); + if(message != null) + { + final long messageId = message.getMessageNumber(); + if (_messageIds.remove(messageId) || (messageId <= (long) Integer.MAX_VALUE + && _messageIds.remove(Integer.valueOf((int)messageId)))) + { + updateEntry(entry, txn); + } + } + return _messageIds.isEmpty(); + } + }); + } + + + protected abstract void updateEntry(QueueEntry entry, VirtualHost.Transaction txn); + } + + private static class MoveTransaction extends QueueEntryTransaction + { + private final Queue _destinationQueue; + + public MoveTransaction(Queue sourceQueue, List<Long> messageIds, Queue destinationQueue) + { + super(sourceQueue, messageIds); + _destinationQueue = destinationQueue; + } + + protected void updateEntry(QueueEntry entry, VirtualHost.Transaction txn) + { + txn.move(entry, _destinationQueue); + } + } + + private static class CopyTransaction extends QueueEntryTransaction + { + private final Queue _destinationQueue; + + public CopyTransaction(Queue sourceQueue, List<Long> messageIds, Queue destinationQueue) + { + super(sourceQueue, messageIds); + _destinationQueue = destinationQueue; + } + + protected void updateEntry(QueueEntry entry, VirtualHost.Transaction txn) + { + txn.copy(entry, _destinationQueue); + } + } + + private static class DeleteTransaction extends QueueEntryTransaction + { + public DeleteTransaction(Queue sourceQueue, List<Long> messageIds) + { + super(sourceQueue, messageIds); + } + + protected void updateEntry(QueueEntry entry, VirtualHost.Transaction txn) + { + txn.dequeue(entry); + } + } + + + + private class MessageCollector implements QueueEntryVisitor + { + private final int _first; + private final int _last; + private int _position = -1; + private final List<Map<String, Object>> _messages = new ArrayList<Map<String, Object>>(); + + private MessageCollector(int first, int last) + { + _first = first; + _last = last; + } + + + public boolean visit(QueueEntry entry) + { + + _position++; + if((_first == -1 || _position >= _first) && (_last == -1 || _position <= _last)) + { + final Map<String, Object> messageObject = convertToObject(entry, false); + messageObject.put("position", _position); + _messages.add(messageObject); + } + return _last != -1 && _position > _last; + } + + public List<Map<String, Object>> getMessages() + { + return _messages; + } + } + + + private class MessageFinder implements QueueEntryVisitor + { + private final long _messageNumber; + private Map<String, Object> _messageObject; + + private MessageFinder(long messageNumber) + { + _messageNumber = messageNumber; + } + + + public boolean visit(QueueEntry entry) + { + ServerMessage message = entry.getMessage(); + if(message != null) + { + if(_messageNumber == message.getMessageNumber()) + { + MessageReference reference = message.newReference(); + _messageObject = convertToObject(entry, true); + reference.release(); + return true; + } + } + return false; + } + + public Map<String, Object> getMessageObject() + { + return _messageObject; + } + } + + private Map<String, Object> convertToObject(QueueEntry entry, boolean includeContent) + { + Map<String, Object> object = new LinkedHashMap<String, Object>(); + object.put("size", entry.getSize()); + object.put("deliveryCount", entry.getDeliveryCount()); + object.put("state",entry.isAvailable() + ? "Available" + : entry.isAcquired() + ? "Acquired" + : ""); + final Subscription deliveredSubscription = entry.getDeliveredSubscription(); + object.put("deliveredTo", deliveredSubscription == null ? null : deliveredSubscription.getSubscriptionID()); + ServerMessage message = entry.getMessage(); + + if(message != null) + { + convertMessageProperties(object, message); + if(includeContent) + { + convertMessageHeaders(object, message); + } + } + + return object; + } + + private void convertMessageProperties(Map<String, Object> object, ServerMessage message) + { + object.put("id", message.getMessageNumber()); + object.put("arrivalTime",message.getArrivalTime()); + object.put("persistent", message.isPersistent()); + + final AMQMessageHeader messageHeader = message.getMessageHeader(); + if(messageHeader != null) + { + addIfPresent(object, "messageId", messageHeader.getMessageId()); + addIfPresent(object, "expirationTime", messageHeader.getExpiration()); + addIfPresent(object, "applicationId", messageHeader.getAppId()); + addIfPresent(object, "correlationId", messageHeader.getCorrelationId()); + addIfPresent(object, "encoding", messageHeader.getEncoding()); + addIfPresent(object, "mimeType", messageHeader.getMimeType()); + addIfPresent(object, "priority", messageHeader.getPriority()); + addIfPresent(object, "replyTo", messageHeader.getReplyTo()); + addIfPresent(object, "timestamp", messageHeader.getTimestamp()); + addIfPresent(object, "type", messageHeader.getType()); + addIfPresent(object, "userId", messageHeader.getUserId()); + } + + } + + private void addIfPresent(Map<String, Object> object, String name, Object property) + { + if(property != null) + { + object.put(name, property); + } + } + + private void convertMessageHeaders(Map<String, Object> object, ServerMessage message) + { + final AMQMessageHeader messageHeader = message.getMessageHeader(); + if(messageHeader != null) + { + Map<String, Object> headers = new HashMap<String,Object>(); + for(String headerName : messageHeader.getHeaderNames()) + { + headers.put(headerName, messageHeader.getHeader(headerName)); + } + object.put("headers", headers); + } + } + + /* + * POST moves or copies messages to the given queue from a queue specified in the posted JSON data + */ + @Override + protected void onPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + { + + try + { + final Queue sourceQueue = getQueueFromRequest(request); + + ObjectMapper mapper = new ObjectMapper(); + + @SuppressWarnings("unchecked") + Map<String,Object> providedObject = mapper.readValue(request.getInputStream(), LinkedHashMap.class); + + String destQueueName = (String) providedObject.get("destinationQueue"); + Boolean move = (Boolean) providedObject.get("move"); + + final VirtualHost vhost = sourceQueue.getParent(VirtualHost.class); + + boolean isMoveTransaction = move != null && Boolean.valueOf(move); + + // FIXME: added temporary authorization check until we introduce management layer + // and review current ACL rules to have common rules for all management interfaces + String methodName = isMoveTransaction? "moveMessages":"copyMessages"; + if (isQueueUpdateMethodAuthorized(methodName, vhost.getName())) + { + final Queue destinationQueue = getQueueFromVirtualHost(destQueueName, vhost); + final List messageIds = new ArrayList((List) providedObject.get("messages")); + QueueEntryTransaction txn = + isMoveTransaction + ? new MoveTransaction(sourceQueue, messageIds, destinationQueue) + : new CopyTransaction(sourceQueue, messageIds, destinationQueue); + vhost.executeTransaction(txn); + response.setStatus(HttpServletResponse.SC_OK); + } + else + { + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + } + } + catch(RuntimeException e) + { + LOGGER.error("Failure to perform message opertion", e); + response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + } + } + + + /* + * DELETE removes messages from the queue + */ + @Override + protected void onDelete(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + { + + final Queue sourceQueue = getQueueFromRequest(request); + + final VirtualHost vhost = sourceQueue.getParent(VirtualHost.class); + + + final List<Long> messageIds = new ArrayList<Long>(); + for(String idStr : request.getParameterValues("id")) + { + messageIds.add(Long.valueOf(idStr)); + } + + // FIXME: added temporary authorization check until we introduce management layer + // and review current ACL rules to have common rules for all management interfaces + if (isQueueUpdateMethodAuthorized("deleteMessages", vhost.getName())) + { + vhost.executeTransaction(new DeleteTransaction(sourceQueue, messageIds)); + response.setStatus(HttpServletResponse.SC_OK); + } + else + { + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + } + + } + + private boolean isQueueUpdateMethodAuthorized(String methodName, String virtualHost) + { + SecurityManager securityManager = getSecurityManager(virtualHost); + return securityManager.authoriseMethod(Operation.UPDATE, "VirtualHost.Queue", methodName); + } + + private SecurityManager getSecurityManager(String virtualHost) + { + IApplicationRegistry appRegistry = ApplicationRegistry.getInstance(); + SecurityManager security; + if (virtualHost == null) + { + security = appRegistry.getSecurityManager(); + } + else + { + security = appRegistry.getVirtualHostRegistry().getVirtualHost(virtualHost).getSecurityManager(); + } + return security; + } + +} diff --git a/qpid/java/broker-plugins/management/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/RestServlet.java b/qpid/java/broker-plugins/management/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/RestServlet.java new file mode 100644 index 0000000000..96e260da56 --- /dev/null +++ b/qpid/java/broker-plugins/management/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/RestServlet.java @@ -0,0 +1,576 @@ +package org.apache.qpid.server.management.plugin.servlet.rest; + +import java.io.IOException; +import java.io.PrintWriter; +import java.net.SocketAddress; +import java.util.*; +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.apache.qpid.AMQSecurityException; +import org.apache.qpid.server.model.*; +import org.codehaus.jackson.map.ObjectMapper; +import org.codehaus.jackson.map.SerializationConfig; + +/** + * 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 + * <p/> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p/> + * 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. + */ +public class RestServlet extends AbstractServlet +{ + /** + * An initialization parameter to specify hierarchy + */ + private static final String HIERARCHY_INIT_PARAMETER = "hierarchy"; + + public static final String DEPTH_PARAM = "depth"; + public static final String SORT_PARAM = "sort"; + + public static final Set<String> RESERVED_PARAMS = new HashSet<String>(Arrays.asList(DEPTH_PARAM, SORT_PARAM)); + + private Class<? extends ConfiguredObject>[] _hierarchy; + + private volatile boolean initializationRequired = false; + + public RestServlet() + { + super(); + initializationRequired = true; + } + + public RestServlet(Broker broker, SocketAddress socketaddress, Class<? extends ConfiguredObject>... hierarchy) + { + super(broker, socketaddress); + _hierarchy = hierarchy; + } + + @Override + public void init() throws ServletException + { + if (initializationRequired) + { + doInitialization(); + initializationRequired = false; + } + } + + @SuppressWarnings("unchecked") + private void doInitialization() throws ServletException + { + ServletConfig config = getServletConfig(); + String hierarchy = config.getInitParameter(HIERARCHY_INIT_PARAMETER); + if (hierarchy != null && !"".equals(hierarchy)) + { + List<Class<? extends ConfiguredObject>> classes = new ArrayList<Class<? extends ConfiguredObject>>(); + String[] hierarchyItems = hierarchy.split(","); + for (String item : hierarchyItems) + { + Class<?> itemClass = null; + try + { + itemClass = Class.forName(item); + } + catch (ClassNotFoundException e) + { + try + { + itemClass = Class.forName("org.apache.qpid.server.model." + item); + } + catch (ClassNotFoundException e1) + { + throw new ServletException("Unknown configured object class '" + item + + "' is specified in hierarchy for " + config.getServletName()); + } + } + Class<? extends ConfiguredObject> clazz = (Class<? extends ConfiguredObject>)itemClass; + classes.add(clazz); + } + Class<? extends ConfiguredObject>[] hierachyClasses = (Class<? extends ConfiguredObject>[])new Class[classes.size()]; + _hierarchy = classes.toArray(hierachyClasses); + } + else + { + _hierarchy = (Class<? extends ConfiguredObject>[])new Class[0]; + } + } + + protected Collection<ConfiguredObject> getObjects(HttpServletRequest request) + { + List<String> names = new ArrayList<String>(); + if(request.getPathInfo() != null && request.getPathInfo().length()>0) + { + String path = request.getPathInfo().substring(1); + names.addAll(Arrays.asList(path.split("/"))); + + if(names.size() > _hierarchy.length) + { + throw new IllegalArgumentException("Too many entries in path"); + } + } + + Collection<ConfiguredObject> parents = Collections.singleton((ConfiguredObject) getBroker()); + Collection<ConfiguredObject> children = new ArrayList<ConfiguredObject>(); + + Map<Class<? extends ConfiguredObject>, String> filters = + new HashMap<Class<? extends ConfiguredObject>, String>(); + + for(int i = 0; i < _hierarchy.length; i++) + { + if(i == 0 || Model.getChildTypes(_hierarchy[i - 1]).contains(_hierarchy[i])) + { + + for(ConfiguredObject parent : parents) + { + if(names.size() > i + && names.get(i) != null + && !names.get(i).equals("*") + && names.get(i).trim().length() != 0) + { + for(ConfiguredObject child : parent.getChildren(_hierarchy[i])) + { + if(child.getName().equals(names.get(i))) + { + children.add(child); + } + } + } + else + { + children.addAll(parent.getChildren(_hierarchy[i])); + } + } + } + else + { + children = parents; + if(names.size() > i + && names.get(i) != null + && !names.get(i).equals("*") + && names.get(i).trim().length() != 0) + { + filters.put(_hierarchy[i], names.get(i)); + } + } + + parents = children; + children = new ArrayList<ConfiguredObject>(); + } + + if(!filters.isEmpty()) + { + Collection<ConfiguredObject> potentials = parents; + parents = new ArrayList<ConfiguredObject>(); + + for(ConfiguredObject o : potentials) + { + + boolean match = true; + + for(Map.Entry<Class<? extends ConfiguredObject>, String> entry : filters.entrySet()) + { + Collection<? extends ConfiguredObject> ancestors = + getAncestors(getConfiguredClass(),entry.getKey(), o); + match = false; + for(ConfiguredObject ancestor : ancestors) + { + if(ancestor.getName().equals(entry.getValue())) + { + match = true; + break; + } + } + if(!match) + { + break; + } + } + if(match) + { + parents.add(o); + } + + } + } + + return filter(parents, request); + } + + private Collection<ConfiguredObject> filter(Collection<ConfiguredObject> objects, HttpServletRequest request) + { + + + Map<String, Collection<String>> filters = new HashMap<String, Collection<String>>(); + + for(String param : (Collection<String>) Collections.list(request.getParameterNames())) + { + if(!RESERVED_PARAMS.contains(param)) + { + filters.put(param, Arrays.asList(request.getParameterValues(param))); + } + } + + if(filters.isEmpty()) + { + return objects; + } + + Collection<ConfiguredObject> filteredObj = new ArrayList<ConfiguredObject>(objects); + + Iterator<ConfiguredObject> iter = filteredObj.iterator(); + + while(iter.hasNext()) + { + ConfiguredObject obj = iter.next(); + for(Map.Entry<String, Collection<String>> entry : filters.entrySet()) + { + Object value = obj.getAttribute(entry.getKey()); + if(!entry.getValue().contains(String.valueOf(value))) + { + iter.remove(); + } + } + + } + + return filteredObj; + } + + private Collection<? extends ConfiguredObject> getAncestors(Class<? extends ConfiguredObject> childType, + Class<? extends ConfiguredObject> ancestorType, + ConfiguredObject child) + { + Collection<ConfiguredObject> ancestors = new HashSet<ConfiguredObject>(); + Collection<Class<? extends ConfiguredObject>> parentTypes = Model.getParentTypes(childType); + + for(Class<? extends ConfiguredObject> parentClazz : parentTypes) + { + if(parentClazz == ancestorType) + { + ConfiguredObject parent = child.getParent(parentClazz); + if(parent != null) + { + ancestors.add(parent); + } + } + else + { + ConfiguredObject parent = child.getParent(parentClazz); + if(parent != null) + { + ancestors.addAll(getAncestors(parentClazz, ancestorType, parent)); + } + } + } + + return ancestors; + } + + + protected Map<String, Object> convertObjectToMap(final ConfiguredObject confObject, + Class<? extends ConfiguredObject> clazz, + int depth) + { + Map<String, Object> object = new LinkedHashMap<String, Object>(); + + for(String name : confObject.getAttributeNames()) + { + Object value = confObject.getAttribute(name); + if(value != null) + { + object.put(name, value); + } + } + + Statistics statistics = confObject.getStatistics(); + Map<String, Object> statMap = new HashMap<String, Object>(); + for(String name : statistics.getStatisticNames()) + { + Object value = statistics.getStatistic(name); + if(value != null) + { + statMap.put(name, value); + } + } + + if(!statMap.isEmpty()) + { + object.put("statistics", statMap); + } + + if(depth > 0) + { + for(Class<? extends ConfiguredObject> childClass : Model.getChildTypes(clazz)) + { + Collection<? extends ConfiguredObject> children = confObject.getChildren(childClass); + if(children != null) + { + List<Map<String, Object>> childObjects = new ArrayList<Map<String, Object>>(); + + for(ConfiguredObject child : children) + { + childObjects.add(convertObjectToMap(child, childClass, depth-1)); + } + + if(!childObjects.isEmpty()) + { + object.put(childClass.getSimpleName().toLowerCase()+"s",childObjects); + } + } + } + } + return object; + } + + @Override + protected void onGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + { + response.setContentType("application/json"); + response.setStatus(HttpServletResponse.SC_OK); + + response.setHeader("Cache-Control","no-cache"); + response.setHeader("Pragma","no-cache"); + response.setDateHeader ("Expires", 0); + + Collection<ConfiguredObject> allObjects = getObjects(request); + + @SuppressWarnings("unchecked") + Map params = new HashMap(request.getParameterMap()); + + int depth = 1; + try + { + depth = Integer.parseInt(String.valueOf(params.remove("depth"))); + } + catch (NumberFormatException e) + { + // Ignore + } + + List<Map<String, Object>> output = new ArrayList<Map<String, Object>>(); + + // TODO - depth and sort special params, everything else should act as a filter + if(request.getParameter(DEPTH_PARAM)!=null) + { + try + { + depth = Integer.parseInt(request.getParameter(DEPTH_PARAM)); + } + catch (NumberFormatException e) + { + + } + } + + for(ConfiguredObject configuredObject : allObjects) + { + output.add(convertObjectToMap(configuredObject, getConfiguredClass(),depth)); + } + + final PrintWriter writer = response.getWriter(); + ObjectMapper mapper = new ObjectMapper(); + mapper.configure(SerializationConfig.Feature.INDENT_OUTPUT, true); + mapper.writeValue(writer, output); + + response.setContentType("application/json"); + response.setStatus(HttpServletResponse.SC_OK); + + } + + private Class<? extends ConfiguredObject> getConfiguredClass() + { + return _hierarchy.length == 0 ? Broker.class : _hierarchy[_hierarchy.length-1]; + } + + @Override + protected void onPut(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + { + response.setContentType("application/json"); + + ObjectMapper mapper = new ObjectMapper(); + @SuppressWarnings("unchecked") + Map<String,Object> providedObject = mapper.readValue(request.getInputStream(), LinkedHashMap.class); + + + List<String> names = new ArrayList<String>(); + if(request.getPathInfo() != null && request.getPathInfo().length()>0) + { + String path = request.getPathInfo().substring(1); + names.addAll(Arrays.asList(path.split("/"))); + + if(names.size() != _hierarchy.length) + { + throw new IllegalArgumentException("Path to object to create must be fully specified"); + } + } + + + providedObject.put("name", names.get(names.size()-1)); + + @SuppressWarnings("unchecked") + Collection<ConfiguredObject>[] objects = new Collection[_hierarchy.length]; + if(_hierarchy.length == 1) + { + try + { + getBroker().createChild(_hierarchy[0], providedObject); + } + catch (RuntimeException e) + { + setResponseStatus(response, e); + return; + } + + } + else + { + for(int i = 0; i < _hierarchy.length-1; i++) + { + objects[i] = new HashSet<ConfiguredObject>(); + if(i == 0) + { + for(ConfiguredObject object : getBroker().getChildren(_hierarchy[0])) + { + if(object.getName().equals(names.get(0))) + { + objects[0].add(object); + break; + } + } + } + else + { + for(int j = i-1; j >=0; j--) + { + if(Model.getChildTypes(_hierarchy[j]).contains(_hierarchy[i])) + { + for(ConfiguredObject parent : objects[j]) + { + for(ConfiguredObject object : parent.getChildren(_hierarchy[i])) + { + if(object.getName().equals(names.get(i))) + { + objects[i].add(object); + } + } + } + break; + } + } + } + + } + List<ConfiguredObject> parents = new ArrayList<ConfiguredObject>(); + Class<? extends ConfiguredObject> objClass = getConfiguredClass(); + Collection<Class<? extends ConfiguredObject>> parentClasses = Model.getParentTypes(objClass); + for(int i = _hierarchy.length-2; i >=0 ; i--) + { + if(parentClasses.contains(_hierarchy[i])) + { + if(objects[i].size() == 1) + { + parents.add(objects[i].iterator().next()); + } + else + { + throw new IllegalArgumentException("Cannot deduce parent of class " + + _hierarchy[i].getSimpleName()); + } + } + + } + ConfiguredObject theParent = parents.remove(0); + ConfiguredObject[] otherParents = parents.toArray(new ConfiguredObject[parents.size()]); + + try + { + + Collection<? extends ConfiguredObject> existingChildren = theParent.getChildren(objClass); + for(ConfiguredObject obj: existingChildren) + { + if((providedObject.containsKey("id") && String.valueOf(providedObject.get("id")).equals(obj.getId().toString())) + || (obj.getName().equals(providedObject.get("name")) && equalParents(obj, otherParents))) + { + doUpdate(obj, providedObject); + } + } + theParent.createChild(objClass, providedObject, otherParents); + } + catch (RuntimeException e) + { + setResponseStatus(response, e); + return; + } + + } + response.setStatus(HttpServletResponse.SC_CREATED); + } + + private void doUpdate(ConfiguredObject obj, Map<String, Object> providedObject) + { + for(Map.Entry<String,Object> entry : providedObject.entrySet()) + { + obj.setAttribute(entry.getKey(), obj.getAttribute(entry.getKey()), entry.getValue()); + } + //TODO - Implement. + } + + private boolean equalParents(ConfiguredObject obj, ConfiguredObject[] otherParents) + { + if(otherParents == null || otherParents.length == 0) + { + return true; + } + return false; //TODO - Implement. + } + + private void setResponseStatus(HttpServletResponse response, RuntimeException e) throws IOException + { + if (e.getCause() instanceof AMQSecurityException) + { + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + } + else + { + // TODO + response.setStatus(HttpServletResponse.SC_CONFLICT); + } + } + + @Override + protected void onDelete(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + { + response.setContentType("application/json"); + response.setStatus(HttpServletResponse.SC_OK); + + response.setHeader("Cache-Control","no-cache"); + response.setHeader("Pragma","no-cache"); + response.setDateHeader ("Expires", 0); + try + { + Collection<ConfiguredObject> allObjects = getObjects(request); + for(ConfiguredObject o : allObjects) + { + o.setDesiredState(o.getActualState(), State.DELETED); + } + + response.setStatus(HttpServletResponse.SC_OK); + } + catch(RuntimeException e) + { + setResponseStatus(response, e); + } + } +} diff --git a/qpid/java/broker-plugins/management/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/SaslServlet.java b/qpid/java/broker-plugins/management/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/SaslServlet.java new file mode 100644 index 0000000000..4ca2d270dd --- /dev/null +++ b/qpid/java/broker-plugins/management/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/SaslServlet.java @@ -0,0 +1,253 @@ +/* + * + * 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.management.plugin.servlet.rest; + +import org.apache.commons.codec.binary.Base64; +import org.codehaus.jackson.map.ObjectMapper; +import org.codehaus.jackson.map.SerializationConfig; + +import org.apache.qpid.server.model.Broker; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.security.auth.manager.AuthenticationManager; +import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; + +import javax.security.auth.Subject; +import javax.security.sasl.SaslException; +import javax.security.sasl.SaslServer; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; +import java.io.IOException; +import java.io.PrintWriter; +import java.net.SocketAddress; +import java.security.Principal; +import java.security.SecureRandom; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Random; + +public class SaslServlet extends AbstractServlet +{ + + private static final SecureRandom SECURE_RANDOM = new SecureRandom(); + private static final String ATTR_RANDOM = "SaslServlet.Random"; + private static final String ATTR_ID = "SaslServlet.ID"; + private static final String ATTR_SASL_SERVER = "SaslServlet.SaslServer"; + private static final String ATTR_EXPIRY = "SaslServlet.Expiry"; + private static final long SASL_EXCHANGE_EXPIRY = 1000L; + + + public SaslServlet() + { + super(); + } + + public SaslServlet(Broker broker, SocketAddress socketaddress) + { + super(broker, socketaddress); + } + + protected void onGet(HttpServletRequest request, HttpServletResponse response) throws + ServletException, + IOException + { + response.setContentType("application/json"); + response.setStatus(HttpServletResponse.SC_OK); + + response.setHeader("Cache-Control","no-cache"); + response.setHeader("Pragma","no-cache"); + response.setDateHeader ("Expires", 0); + + HttpSession session = request.getSession(); + Random rand = getRandom(session); + + AuthenticationManager authManager = ApplicationRegistry.getInstance().getAuthenticationManager(getSocketAddress(request)); + String[] mechanisms = authManager.getMechanisms().split(" "); + Map<String, Object> outputObject = new LinkedHashMap<String, Object>(); + final Subject subject = (Subject) session.getAttribute("subject"); + if(subject != null) + { + final Principal principal = subject.getPrincipals().iterator().next(); + outputObject.put("user", principal.getName()); + } + + outputObject.put("mechanisms", (Object) mechanisms); + + final PrintWriter writer = response.getWriter(); + + ObjectMapper mapper = new ObjectMapper(); + mapper.configure(SerializationConfig.Feature.INDENT_OUTPUT, true); + mapper.writeValue(writer, outputObject); + + } + + private Random getRandom(final HttpSession session) + { + Random rand = (Random) session.getAttribute(ATTR_RANDOM); + if(rand == null) + { + synchronized (SECURE_RANDOM) + { + rand = new Random(SECURE_RANDOM.nextLong()); + } + session.setAttribute(ATTR_RANDOM, rand); + } + return rand; + } + + + @Override + protected void onPost(final HttpServletRequest request, final HttpServletResponse response) + throws ServletException, IOException + { + try + { + response.setContentType("application/json"); + response.setHeader("Cache-Control","no-cache"); + response.setHeader("Pragma","no-cache"); + response.setDateHeader("Expires", 0); + + HttpSession session = request.getSession(); + + String mechanism = request.getParameter("mechanism"); + String id = request.getParameter("id"); + String saslResponse = request.getParameter("response"); + + AuthenticationManager authManager = ApplicationRegistry.getInstance().getAuthenticationManager(getSocketAddress(request)); + + if(mechanism != null) + { + if(id == null) + { + SaslServer saslServer = authManager.createSaslServer(mechanism, request.getServerName(), null/*TODO*/); + evaluateSaslResponse(response, session, saslResponse, saslServer); + } + else + { + response.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED); + session.removeAttribute(ATTR_ID); + session.removeAttribute(ATTR_SASL_SERVER); + session.removeAttribute(ATTR_EXPIRY); + + } + + } + else + { + if(id != null) + { + if(id.equals(session.getAttribute(ATTR_ID)) && System.currentTimeMillis() < (Long) session.getAttribute(ATTR_EXPIRY)) + { + SaslServer saslServer = (SaslServer) session.getAttribute(ATTR_SASL_SERVER); + evaluateSaslResponse(response, session, saslResponse, saslServer); + + } + else + { + response.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED); + session.removeAttribute(ATTR_ID); + session.removeAttribute(ATTR_SASL_SERVER); + session.removeAttribute(ATTR_EXPIRY); + } + } + else + { + response.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED); + session.removeAttribute(ATTR_ID); + session.removeAttribute(ATTR_SASL_SERVER); + session.removeAttribute(ATTR_EXPIRY); + + } + } + } + catch(IOException e) + { + //TODO + e.printStackTrace(); + throw e; + } + catch(RuntimeException e) + { + //TODO + e.printStackTrace(); + throw e; + } + + } + + private void evaluateSaslResponse(final HttpServletResponse response, + final HttpSession session, + final String saslResponse, final SaslServer saslServer) throws IOException + { + final String id; + byte[] challenge; + try + { + challenge = saslServer.evaluateResponse(saslResponse == null ? new byte[0] : Base64.decodeBase64(saslResponse.getBytes())); + } + catch(SaslException e) + { + + session.removeAttribute(ATTR_ID); + session.removeAttribute(ATTR_SASL_SERVER); + session.removeAttribute(ATTR_EXPIRY); + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + + return; + } + + if(saslServer.isComplete()) + { + final Subject subject = new Subject(); + subject.getPrincipals().add(new UsernamePrincipal(saslServer.getAuthorizationID())); + session.setAttribute("subject", subject); + session.removeAttribute(ATTR_ID); + session.removeAttribute(ATTR_SASL_SERVER); + session.removeAttribute(ATTR_EXPIRY); + + response.setStatus(HttpServletResponse.SC_OK); + + + } + else + { + Random rand = getRandom(session); + id = String.valueOf(rand.nextLong()); + session.setAttribute(ATTR_ID, id); + session.setAttribute(ATTR_SASL_SERVER, saslServer); + session.setAttribute(ATTR_EXPIRY, System.currentTimeMillis() + SASL_EXCHANGE_EXPIRY); + + response.setStatus(HttpServletResponse.SC_OK); + + Map<String, Object> outputObject = new LinkedHashMap<String, Object>(); + outputObject.put("id", id); + outputObject.put("challenge", new String(Base64.encodeBase64(challenge))); + + final PrintWriter writer = response.getWriter(); + + ObjectMapper mapper = new ObjectMapper(); + mapper.configure(SerializationConfig.Feature.INDENT_OUTPUT, true); + mapper.writeValue(writer, outputObject); + + } + } +} diff --git a/qpid/java/broker-plugins/management/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/StructureServlet.java b/qpid/java/broker-plugins/management/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/StructureServlet.java new file mode 100644 index 0000000000..6295d74b42 --- /dev/null +++ b/qpid/java/broker-plugins/management/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/StructureServlet.java @@ -0,0 +1,104 @@ +/** + * 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 + * <p/> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p/> + * 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.management.plugin.servlet.rest; + +import java.io.IOException; +import java.io.PrintWriter; +import java.net.SocketAddress; +import java.util.ArrayList; +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.qpid.server.model.Broker; +import org.apache.qpid.server.model.ConfiguredObject; +import org.apache.qpid.server.model.Model; +import org.codehaus.jackson.map.ObjectMapper; +import org.codehaus.jackson.map.SerializationConfig; + +public class StructureServlet extends AbstractServlet +{ + public StructureServlet() + { + super(); + } + + public StructureServlet(Broker broker, SocketAddress socketaddress) + { + super(broker, socketaddress); + } + + @Override + protected void onGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + { + response.setContentType("application/json"); + response.setStatus(HttpServletResponse.SC_OK); + + response.setHeader("Cache-Control","no-cache"); + response.setHeader("Pragma","no-cache"); + response.setDateHeader ("Expires", 0); + + Map<String,Object> structure = generateStructure(getBroker(), Broker.class); + + final PrintWriter writer = response.getWriter(); + ObjectMapper mapper = new ObjectMapper(); + mapper.configure(SerializationConfig.Feature.INDENT_OUTPUT, true); + mapper.writeValue(writer, structure); + + response.setStatus(HttpServletResponse.SC_OK); + + } + + private Map<String, Object> generateStructure(ConfiguredObject object, Class<? extends ConfiguredObject> clazz) + { + Map<String, Object> structure = new LinkedHashMap<String, Object>(); + structure.put("id", object.getId()); + structure.put("name", object.getName()); + + for(Class<? extends ConfiguredObject> childClass : Model.getChildTypes(clazz)) + { + Collection<? extends ConfiguredObject> children = object.getChildren(childClass); + if(children != null) + { + List<Map<String, Object>> childObjects = new ArrayList<Map<String, Object>>(); + + for(ConfiguredObject child : children) + { + childObjects.add(generateStructure(child, childClass)); + } + + if(!childObjects.isEmpty()) + { + structure.put(pluralize(childClass),childObjects); + } + } + } + + return structure; + } + + private String pluralize(Class<? extends ConfiguredObject> childClass) + { + String name = childClass.getSimpleName().toLowerCase(); + return name + (name.endsWith("s") ? "es" : "s"); + } +} diff --git a/qpid/java/broker-plugins/management/src/main/java/resources/addBinding.html b/qpid/java/broker-plugins/management/src/main/java/resources/addBinding.html new file mode 100644 index 0000000000..8dbd219c8d --- /dev/null +++ b/qpid/java/broker-plugins/management/src/main/java/resources/addBinding.html @@ -0,0 +1,42 @@ +<!-- + ~ 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. + --> +<div class="dijitHidden"> + <div data-dojo-type="dijit.Dialog" style="width:600px;" data-dojo-props="title:'Add Binding'" id="addBinding"> + <form id="formAddBinding" method="post" dojoType="dijit.form.Form"> + <table cellpadding="0" cellspacing="2"> + <tr> + <td valign="top"><strong>Exchange Name*: </strong></td> + <td><div id="addBinding.selectExchangeDiv"></div></td> + </tr> + <tr> + <td valign="top"><strong>Queue Name*: </strong></td> + <td><div id="addBinding.selectQueueDiv"></div></td> + </tr> + <tr> + <td valign="top"><strong>Binding Key*: </strong></td> + <td><input type="text" required="true" name="name" id="formAddbinding.bindingKey" placeholder="Binding Key" + dojoType="dijit.form.ValidationTextBox" missingMessage="A name must be supplied" /></td> + </tr> + </table> + <br/> + + <!-- submit buttons --> + <input type="submit" value="Create Binding" label="Create Binding" dojoType="dijit.form.Button" /> + + </form> + </div> +</div> diff --git a/qpid/java/broker-plugins/management/src/main/java/resources/addExchange.html b/qpid/java/broker-plugins/management/src/main/java/resources/addExchange.html new file mode 100644 index 0000000000..cccdfbd00c --- /dev/null +++ b/qpid/java/broker-plugins/management/src/main/java/resources/addExchange.html @@ -0,0 +1,53 @@ +<!-- + - + - 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. + - + --> +<div class="dijitHidden"> + <div data-dojo-type="dijit.Dialog" style="width:600px;" data-dojo-props="title:'Add Exchange'" id="addExchange"> + <form id="formAddExchange" method="post" dojoType="dijit.form.Form"> + <table cellpadding="0" cellspacing="2"> + <tr> + <td valign="top"><strong>Exchange Name*: </strong></td> + <td><input type="text" required="true" name="name" id="formAddExchange.name" placeholder="Exchange Name" + dojoType="dijit.form.ValidationTextBox" missingMessage="A name must be supplied" /></td> + </tr> + <tr> + <td valign="top"><strong>Durable? </strong></td> + <td><input type="checkbox" name="durable" id="formAddExchange.durable" value="durable" checked="checked" dojoType="dijit.form.CheckBox" /></td> + </tr> + <tr> + <td valign="top"><strong>Exchange Type: </strong></td> + <td> + <select name="type" id="formAddExchange.type" dojoType="dijit.form.FilteringSelect"> + <option value="direct">direct</option> + <option value="topic">topic</option> + <option value="headers">headers</option> + <option value="fanout">fanout</option> + </select> + </td> + </tr> + </table> + <br/> + + <!-- submit buttons --> + <input type="submit" value="Create Exchange" label="Create Exchange" dojoType="dijit.form.Button" /> + + </form> + </div> +</div> diff --git a/qpid/java/broker-plugins/management/src/main/java/resources/addQueue.html b/qpid/java/broker-plugins/management/src/main/java/resources/addQueue.html new file mode 100644 index 0000000000..8154f053cd --- /dev/null +++ b/qpid/java/broker-plugins/management/src/main/java/resources/addQueue.html @@ -0,0 +1,174 @@ +<!-- + - + - 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. + - + --> +<div class="dijitHidden"> + <div data-dojo-type="dijit.Dialog" style="width:600px;" data-dojo-props="title:'Add Queue'" id="addQueue"> + <form id="formAddQueue" method="post" dojoType="dijit.form.Form"> + <table cellpadding="0" cellspacing="2"> + <tr> + <td valign="top"><strong>Queue Name*: </strong></td> + <td><input type="text" required="true" name="name" id="formAddQueue.name" placeholder="Queue Name" + dojoType="dijit.form.ValidationTextBox" missingMessage="A name must be supplied" /></td> + </tr> + <tr> + <td valign="top"><strong>Durable? </strong></td> + <td><input type="checkbox" name="durable" id="formAddQueue.durable" value="durable" checked="checked" dojoType="dijit.form.CheckBox" /></td> + </tr> + <tr> + <td valign="top"><strong>Queue Type: </strong></td> + <td> + <input type="radio" id="formAddQueueTypeStandard" name="type" value="standard" checked="checked" dojoType="dijit.form.RadioButton" /> + <label for="formAddQueueTypeStandard">Standard</label> + + <input type="radio" id="formAddQueueTypePriority" name="type" value="priority" dojoType="dijit.form.RadioButton" /> + <label for="formAddQueueTypePriority">Priority</label> + + <input type="radio" id="formAddQueueTypeLVQ" name="type" value="lvq" dojoType="dijit.form.RadioButton" /> + <label for="formAddQueueTypeLVQ">LVQ</label> + + <input type="radio" id="formAddQueueTypeSorted" name="type" value="sorted" dojoType="dijit.form.RadioButton" /> + <label for="formAddQueueTypeSorted">Sorted</label> + </td> + </tr> + </table> + <br/> + + <div id="formAddQueueTypePriority:fields" style="display:none" + data-dojo-type="dijit.TitlePane" data-dojo-props="title: 'Priority Queue Settings'"> + <table cellpadding="0" cellspacing="2"> + <tr> + <td valign="top"><strong>Priorities: </strong></td> + <td><input data-dojo-type="dijit.form.NumberSpinner" id="formAddQueue.priorities" + name="numPriorities" value="3" smallDelta="1" constraints="{min:1,max:10,places:0}"/> + </tr> + </table> + </div> + + + <div id="formAddQueueTypeLVQ:fields" style="display:none" + data-dojo-type="dijit.TitlePane" data-dojo-props="title: 'Last Value Queue Settings'"> + <table cellpadding="0" cellspacing="2"> + <tr> + <td valign="top"><strong>LVQ Message Property: </strong></td> + <td><input type="text" name="lvqKey" id="formAddQueue.lvqkey" + placeholder="qpid.LVQ_key" dojoType="dijit.form.ValidationTextBox" /></td> + </tr> + </table> + </div> + + <div id="formAddQueueTypeSorted:fields" style="display:none" + data-dojo-type="dijit.TitlePane" data-dojo-props="title: 'Sorted Queue Settings'"> + <table cellpadding="0" cellspacing="2"> + <tr> + <td valign="top"><strong>Sort Message Property: </strong></td> + <td><input type="text" name="sortKey" id="formAddQueue.sortkey" + placeholder="" dojoType="dijit.form.ValidationTextBox" /></td> + </tr> + </table> + </div> + + <br/> + <div data-dojo-type="dijit.TitlePane" data-dojo-props="title: 'Flow Control Settings', open: false"> + <table cellpadding="0" cellspacing="2"> + + <!-- x-qpid-capacity --> + <tr> + <td valign="top"><strong>Capacity: </strong></td> + <td><input type="text" required="false" name="queueFlowControlSizeBytes" id="formAddQueue.capacity" placeholder="Size in bytes" + dojoType="dijit.form.ValidationTextBox" + trim="true" + regexp="(^[0-9]+(b|K(b)?|M(b)?|G(b)?)?$)" + invalidMessage= "Invalid value"/></td> + </tr> + <!-- x-qpid-flow-resume-capacity --> + <tr> + <td valign="top"><strong>Resume Capacity: </strong></td> + <td><input type="text" required="false" name="queueFlowResumeSizeBytes" id="formAddQueue.flowResumeCapacity" placeholder="Size in bytes" + dojoType="dijit.form.ValidationTextBox" + trim="true" + regexp="(^[0-9]+(b|K(b)?|M(b)?|G(b)?)?$)" + invalidMessage= "Invalid value"/></td> + </tr> + </table> + </div> + <br/> + <div data-dojo-type="dijit.TitlePane" data-dojo-props="title: 'Alerting Settings', open: false"> + <table cellpadding="0" cellspacing="2"> + <tr> + <td valign="top"><strong>Maximum Message Age: </strong></td> + <td><input type="text" required="false" name="alertThresholdMessageAge" id="formAddQueue.maximumMessageAge" placeholder="Time in ms" + dojoType="dijit.form.ValidationTextBox" + trim="true" + regexp="(^[0-9]+(s(ec(ond(s)?)?)?|m(in(ute)?(s)?)?|h|d|w|M|y)?$)" + invalidMessage= "Invalid value" /></td> + </tr> + <!-- x-qpid-maximum-message-size --> + <tr> + <td valign="top"><strong>Maximum Message Size: </strong></td> + <td><input type="text" required="false" name="alertThresholdMessageSize" id="formAddQueue.maximumMessageSize" placeholder="Size in bytes" + dojoType="dijit.form.ValidationTextBox" + trim="true" + regexp="(^[0-9]+(b|K(b)?|M(b)?|G(b)?)?$)" + invalidMessage= "Invalid value" /></td> + </tr> + <!-- x-qpid-maximum-message-count --> + <tr> + <td valign="top"><strong>Maximum Number in Queue: </strong></td> + <td><input type="text" required="false" name="alertThresholdQueueDepthMessages" id="formAddQueue.maximumMessageCount" placeholder="Count of messages" + dojoType="dijit.form.ValidationTextBox" + trim="true" + regexp="[0-9]+" + invalidMessage= "Invalid value"/></td> + </tr> + <!-- x-qpid-minimum-alert-repeat-gap --> + <tr> + <td valign="top"><strong>Gap between alerts: </strong></td> + <td><input type="text" required="false" name="alertRepeatGap" id="formAddQueue.minimumAlertRepeatGap" placeholder="Time in ms" + dojoType="dijit.form.ValidationTextBox" + trim="true" + regexp="(^[0-9]+(s(ec(ond(s)?)?)?|m(in(ute)?(s)?)?|h|d|w|M|y)?$)" + invalidMessage= "Invalid value" /></td> + </tr> + </table> + </div> + <br/> + <div data-dojo-type="dijit.TitlePane" data-dojo-props="title: 'Other Settings', open: false"> + <table cellpadding="0" cellspacing="2"> + + <!-- x-qpid-maximum-delivery-count --> + <tr> + <td valign="top"><strong>Maximum Delivery Retries: </strong></td> + <td><input type="text" required="false" name="maximumDeliveryAttempts" id="formAddQueue.maximumDeliveryCount" + dojoType="dijit.form.ValidationTextBox" + trim="true" + regexp="[0-9]+" + invalidMessage= "Invalid value"/></td> + </tr> + + + </table> + </div> + <br/> + <!-- submit buttons --> + <input type="submit" value="Create Queue" label="Create Queue" dojoType="dijit.form.Button" /> + + </form> + </div> +</div> diff --git a/qpid/java/broker-plugins/management/src/main/java/resources/authenticationprovider/addUser.html b/qpid/java/broker-plugins/management/src/main/java/resources/authenticationprovider/addUser.html new file mode 100644 index 0000000000..785605f694 --- /dev/null +++ b/qpid/java/broker-plugins/management/src/main/java/resources/authenticationprovider/addUser.html @@ -0,0 +1,42 @@ +<!-- + - + - 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. + - + --> +<div class="dijitHidden"> + <div data-dojo-type="dijit.Dialog" style="width:600px;" data-dojo-props="title:'Add User'" id="addUser"> + <form id="formAddUser" method="post" dojoType="dijit.form.Form"> + <table cellpadding="0" cellspacing="2"> + <tr> + <td valign="top"><strong>User Name*: </strong></td> + <td><input type="text" required="true" name="name" id="formAddUser.name" placeholder="User Name" + dojoType="dijit.form.ValidationTextBox" missingMessage="A name must be supplied" /></td> + </tr> + <tr> + <td valign="top"><strong>Password*</strong></td> + <td><input type="password" required="true" name="password" id="formAddUser.password" dojoType="dijit.form.ValidationTextBox"/></td> + </tr> + </table> + <br/> + + <!-- submit buttons --> + <input type="submit" value="Create User" label="Create User" dojoType="dijit.form.Button" /> + + </form> + </div> +</div> diff --git a/qpid/java/broker-plugins/management/src/main/java/resources/authenticationprovider/setPassword.html b/qpid/java/broker-plugins/management/src/main/java/resources/authenticationprovider/setPassword.html new file mode 100644 index 0000000000..3d67463abd --- /dev/null +++ b/qpid/java/broker-plugins/management/src/main/java/resources/authenticationprovider/setPassword.html @@ -0,0 +1,42 @@ +<!-- + - + - 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. + - + --> +<div class="dijitHidden"> + <div data-dojo-type="dijit.Dialog" style="width:600px;" data-dojo-props="title:'Set Password'" id="setPassword"> + <form id="formSetPassword" method="post" dojoType="dijit.form.Form"> + <table cellpadding="0" cellspacing="2"> + <tr> + <td valign="top"><strong>User Name: </strong></td> + <td><input type="text" required="true" name="name" id="formSetPassword.name" placeholder="User Name" + dojoType="dijit.form.TextBox" enabled="false" /></td> + </tr> + <tr> + <td valign="top"><strong>Password*</strong></td> + <td><input type="password" required="true" name="password" id="formSetPassword.password" dojoType="dijit.form.ValidationTextBox"/></td> + </tr> + </table> + <br/> + + <!-- submit buttons --> + <input type="submit" value="Set Password" label="Set Password" dojoType="dijit.form.Button" /> + + </form> + </div> +</div> diff --git a/qpid/java/broker-plugins/management/src/main/java/resources/authenticationprovider/showPrincipalDatabaseAuthenticationManager.html b/qpid/java/broker-plugins/management/src/main/java/resources/authenticationprovider/showPrincipalDatabaseAuthenticationManager.html new file mode 100644 index 0000000000..baadc8c35f --- /dev/null +++ b/qpid/java/broker-plugins/management/src/main/java/resources/authenticationprovider/showPrincipalDatabaseAuthenticationManager.html @@ -0,0 +1,29 @@ +<!-- + - + - 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. + - + --> +<div class="PrincipalDatabaseAuthenticationManager"> + <div data-dojo-type="dijit.TitlePane" data-dojo-props="title: 'Users'"> + <div class="users"></div> + <button data-dojo-type="dijit.form.Button" class="addUserButton">Add User</button> + <button data-dojo-type="dijit.form.Button" class="deleteUserButton">Delete Users</button> + + </div> + +</div> diff --git a/qpid/java/broker-plugins/management/src/main/java/resources/css/common.css b/qpid/java/broker-plugins/management/src/main/java/resources/css/common.css new file mode 100644 index 0000000000..78780edcd9 --- /dev/null +++ b/qpid/java/broker-plugins/management/src/main/java/resources/css/common.css @@ -0,0 +1,92 @@ +/* + * + * 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. + * + */ +* { + outline: none !important; +} + +html, body { + height: 100%; + margin: 0; + margin-right: 40px; + padding: 0; + overflow: hidden; + font-family: Lucida Sans,Lucida Grande,Arial !important; + font-size: 13px !important; + background: white; + color: #333; +} + +#pageLayout { + height: 100%; +} +button { + -webkit-transition: background-color 0.2s linear; + border-radius:4px; + -moz-border-radius: 4px 4px 4px 4px; + -moz-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15); + background-color: #E4F2FF; + background-image: url("../dojo/dijit/themes/claro/form/images/button.png"); + background-position: center top; + background-repeat: repeat-x; + border: 1px solid #769DC0; + padding: 2px 8px 4px; + font-size:1em; +} + +button:hover { + background-color: #AFD9FF; + color: #000000; +} + +h1 { + font-size:1.5em; +} + +.header { + height:100px; + background:url("../images/qpid-logo.png") left center no-repeat +} + +.logo { + text-align:left; + vertical-align: top; + font-weight:600; + height: 90px; + padding-left: 200px; + padding-top: 1px; + padding-bottom: 10px; + font-size:14px; + font-family:"Verdana", cursive; +} + +.footer { + color:#000000; + clear:both; + text-align:center; + font-size:11px; + line-height:17px; + +} + +div .messages { + width: 100%; + height: 350px; +}
\ No newline at end of file diff --git a/qpid/java/broker-plugins/management/src/main/java/resources/footer.html b/qpid/java/broker-plugins/management/src/main/java/resources/footer.html new file mode 100644 index 0000000000..fa84825e80 --- /dev/null +++ b/qpid/java/broker-plugins/management/src/main/java/resources/footer.html @@ -0,0 +1,28 @@ +<!-- + - + - 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. + - + --> + +<div class="footer"><p>© 2004-<span class="currentYear">2012</span> The Apache Software Foundation. + <br/> + Apache Qpid, Qpid, Apache, the Apache feather logo, and the Apache Qpid project logo are trademarks of + The Apache Software Foundation. + <br/> + All other marks mentioned may be trademarks or registered trademarks of their respective owners. +</div>
\ No newline at end of file diff --git a/qpid/java/broker-plugins/management/src/main/java/resources/images/qpid-logo.png b/qpid/java/broker-plugins/management/src/main/java/resources/images/qpid-logo.png Binary files differnew file mode 100644 index 0000000000..95d49ea469 --- /dev/null +++ b/qpid/java/broker-plugins/management/src/main/java/resources/images/qpid-logo.png diff --git a/qpid/java/broker-plugins/management/src/main/java/resources/js/qpid/authorization/sasl.js b/qpid/java/broker-plugins/management/src/main/java/resources/js/qpid/authorization/sasl.js new file mode 100644 index 0000000000..152504da86 --- /dev/null +++ b/qpid/java/broker-plugins/management/src/main/java/resources/js/qpid/authorization/sasl.js @@ -0,0 +1,213 @@ +/* + * + * 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. + * + */ +require(["dijit/form/DropDownButton", "dijit/TooltipDialog", "dijit/form/TextBox", + "dojo/_base/xhr", "dojox/encoding/base64", "dojox/encoding/digests/_base", "dojox/encoding/digests/MD5"]); +var button; +var usernameSpan; + +var encodeUTF8 = function encodeUTF8(str) { + var byteArray = []; + for (var i = 0; i < str.length; i++) { + if (str.charCodeAt(i) <= 0x7F) { + byteArray.push(str.charCodeAt(i)); + } + else { + var h = encodeURIComponent(str.charAt(i)).substr(1).split('%'); + for (var j = 0; j < h.length; j++) + byteArray.push(parseInt(h[j], 16)); + } + } + return byteArray; +}; + +var decodeUTF8 = function decodeUTF8(byteArray) +{ + var str = ''; + for (var i = 0; i < byteArray.length; i++) + str += byteArray[i] <= 0x7F? + byteArray[i] === 0x25 ? "%25" : + String.fromCharCode(byteArray[i]) : + "%" + byteArray[i].toString(16).toUpperCase(); + return decodeURIComponent(str); +}; + + +var saslPlain = function saslPlain(user, password) +{ + var responseArray = [ 0 ].concat(encodeUTF8( user )).concat( [ 0 ] ).concat( encodeUTF8( password ) ); + var plainResponse = dojox.encoding.base64.encode(responseArray); + + // Using dojo.xhrGet, as very little information is being sent + dojo.xhrPost({ + // The URL of the request + url: "rest/sasl", + content: { + mechanism: "PLAIN", + response: plainResponse + }, + handleAs: "json", + failOk: true + }).then(function() + { + updateAuthentication(); + }, + function(error) + { + if(error.status == 401) + { + alert("Authentication Failed"); + } + else + { + alert(error); + } + updateAuthentication(); + }); +}; + +var saslCramMD5 = function saslCramMD5(user, password) +{ + + // Using dojo.xhrGet, as very little information is being sent + dojo.xhrPost({ + // The URL of the request + url: "rest/sasl", + content: { + mechanism: "CRAM-MD5" + }, + handleAs: "json", + failOk: true + }).then(function(data) + { + + var challengeBytes = dojox.encoding.base64.decode(data.challenge); + var wa=[]; + var bitLength = challengeBytes.length*8; + for(var i=0; i<bitLength; i+=8) + { + wa[i>>5] |= (challengeBytes[i/8] & 0xFF)<<(i%32); + } + var challengeStr = dojox.encoding.digests.wordToString(wa).substring(0,challengeBytes.length); + + var digest = user + " " + dojox.encoding.digests.MD5._hmac(challengeStr, password, dojox.encoding.digests.outputTypes.Hex); + var id = data.id; + + var response = dojox.encoding.base64.encode(encodeUTF8( digest )); + + dojo.xhrPost({ + // The URL of the request + url: "rest/sasl", + content: { + id: id, + response: response + }, + handleAs: "json", + failOk: true + }).then(function() + { + updateAuthentication(); + }, + function(error) + { + if(error.status == 401) + { + alert("Authentication Failed"); + } + else + { + alert(error); + } + updateAuthentication(); + }); + + }, + function(error) + { + if(error.status == 401) + { + alert("Authentication Failed"); + } + else + { + alert(error); + } + }); +}; + +var doAuthenticate = function doAuthenticate() +{ + saslCramMD5(dojo.byId("username").value, dojo.byId("pass").value); + updateAuthentication(); +}; + + +var updateAuthentication = function updateAuthentication() +{ + dojo.xhrGet({ + // The URL of the request + url: "rest/sasl", + handleAs: "json" + }).then(function(data) + { + if(data.user) + { + dojo.byId("authenticatedUser").innerHTML = data.user; + dojo.style(button.domNode, {visibility: 'hidden'}); + dojo.style(usernameSpan, {visibility: 'visible'}); + } + else + { + dojo.style(button.domNode, {visibility: 'visible'}); + dojo.style(usernameSpan, {visibility: 'hidden'}); + } + } + ); +}; + +require(["dijit/form/DropDownButton", "dijit/TooltipDialog", "dijit/form/TextBox", "dojo/_base/xhr", "dojo/dom", "dojo/dom-construct", "dojo/domReady!"], + function(DropDownButton, TooltipDialog, TextBox, xhr, dom, domConstruct){ + var dialog = new TooltipDialog({ + content: + '<strong><label for="username" style="display:inline-block;width:100px;">Username:</label></strong>' + + '<div data-dojo-type="dijit.form.TextBox" id="username"></div><br/>' + + '<strong><label for="pass" style="display:inline-block;width:100px;">Password:</label></strong>' + + '<div data-dojo-type="dijit.form.TextBox" type="password" id="pass"></div><br/>' + + '<button data-dojo-type="dijit.form.Button" data-dojo-props="onClick:doAuthenticate" type="submit">Login</button>' + }); + + button = new DropDownButton({ + label: "Login", + dropDown: dialog + }); + + usernameSpan = domConstruct.create("span", { innerHTML: '<strong>User: </strong><span id="authenticatedUser"></span>', + style: { visibility: "hidden" }}); + + + var loginDiv = dom.byId("login"); + loginDiv.appendChild(button.domNode); + loginDiv.appendChild(usernameSpan); + + + + + updateAuthentication(); +});
\ No newline at end of file diff --git a/qpid/java/broker-plugins/management/src/main/java/resources/js/qpid/common/UpdatableStore.js b/qpid/java/broker-plugins/management/src/main/java/resources/js/qpid/common/UpdatableStore.js new file mode 100644 index 0000000000..f7ede1a7f7 --- /dev/null +++ b/qpid/java/broker-plugins/management/src/main/java/resources/js/qpid/common/UpdatableStore.js @@ -0,0 +1,110 @@ +/* + * + * 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. + * + */ +define(["dojo/store/Memory", + "dojox/grid/DataGrid", + "dojo/data/ObjectStore", + "dojo/store/Observable"], function (Memory, DataGrid, ObjectStore, Observable) { + + function UpdatableStore( data, divName, structure, func, props, Grid ) { + + var that = this; + var GridType = DataGrid; + + that.store = Observable(Memory({data: data, idProperty: "id"})); + that.dataStore = ObjectStore({objectStore: that.store}); + + var gridProperties = { store: that.dataStore, + structure: structure, + autoHeight: true + }; + if(props) { + for(var prop in props) { + if(props.hasOwnProperty(prop)) + { + gridProperties[ prop ] = props[ prop ]; + } + } + } + + if(Grid) + { + GridType = Grid; + } + + that.grid = new GridType(gridProperties, divName); + + // since we created this grid programmatically, call startup to render it + that.grid.startup(); + + if( func ) + { + func(that); + } + + } + + UpdatableStore.prototype.update = function(data) + { + + var store = this.store; + var theItem; + + // handle deletes + // iterate over existing store... if not in new data then remove + store.query({ }).forEach(function(object) { + if(data) { + for(var i=0; i < data.length; i++) { + if(data[i].id == object.id) { + return; + } + } + } + store.remove(object.id); + + }); + + // iterate over data... + if(data) { + for(var i=0; i < data.length; i++) { + if(theItem = store.get(data[i].id)) { + var modified; + for(var propName in data[i]) { + if(data[i].hasOwnProperty(propName)) { + if(theItem[ propName ] != data[i][ propName ]) { + theItem[ propName ] = data[i][ propName ]; + modified = true; + } + } + } + if(modified) { + // ... check attributes for updates + store.notify(theItem, data[i].id); + } + } else { + // ,,, if not in the store then add + store.put(data[i]); + } + } + } + + }; + return UpdatableStore; +}); diff --git a/qpid/java/broker-plugins/management/src/main/java/resources/js/qpid/common/footer.js b/qpid/java/broker-plugins/management/src/main/java/resources/js/qpid/common/footer.js new file mode 100644 index 0000000000..ea13b1fc53 --- /dev/null +++ b/qpid/java/broker-plugins/management/src/main/java/resources/js/qpid/common/footer.js @@ -0,0 +1,30 @@ +/* + * + * 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. + * + */ +define(["dojo/_base/xhr", "dojo/query", "dojo/domReady!"], function (xhr, query) { + query('div[qpid-type="footer"]').forEach(function(node, index, arr) { + xhr.get({url: "footer.html", + sync: true, + load: function(data) { + node.innerHTML = data; + } }); + }); +}); + diff --git a/qpid/java/broker-plugins/management/src/main/java/resources/js/qpid/common/formatter.js b/qpid/java/broker-plugins/management/src/main/java/resources/js/qpid/common/formatter.js new file mode 100644 index 0000000000..2f8683ee1c --- /dev/null +++ b/qpid/java/broker-plugins/management/src/main/java/resources/js/qpid/common/formatter.js @@ -0,0 +1,99 @@ +/* + * + * 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. + * + */ + +define(function () { + return { + + formatBytes: function formatBytes(amount) + { + var returnVal = { units: "B", + value: "0"}; + + + if(amount < 1000) + { + returnVal.value = amount.toPrecision(3);; + } + else if(amount < 1000 * 1024) + { + returnVal.units = "KB"; + returnVal.value = (amount / 1024).toPrecision(3); + } + else if(amount < 1000 * 1024 * 1024) + { + returnVal.units = "MB"; + returnVal.value = (amount / (1024 * 1024)).toPrecision(3); + } + else if(amount < 1000 * 1024 * 1024 * 1024) + { + returnVal.units = "GB"; + returnVal.value = (amount / (1024 * 1024 * 1024)).toPrecision(3); + } + + return returnVal; + + }, + + formatTime: function formatTime(amount) + { + var returnVal = { units: "ms", + value: "0"}; + + if(amount < 1000) + { + returnVal.units = "ms"; + returnVal.value = amount.toString(); + } + else if(amount < 1000 * 60) + { + returnVal.units = "s"; + returnVal.value = (amount / 1000).toPrecision(3); + } + else if(amount < 1000 * 60 * 60) + { + returnVal.units = "min"; + returnVal.value = (amount / (1000 * 60)).toPrecision(3); + } + else if(amount < 1000 * 60 * 60 * 24) + { + returnVal.units = "hr"; + returnVal.value = (amount / (1000 * 60 * 60)).toPrecision(3); + } + else if(amount < 1000 * 60 * 60 * 24 * 7) + { + returnVal.units = "d"; + returnVal.value = (amount / (1000 * 60 * 60 * 24)).toPrecision(3); + } + else if(amount < 1000 * 60 * 60 * 24 * 365) + { + returnVal.units = "wk"; + returnVal.value = (amount / (1000 * 60 * 60 * 24 * 7)).toPrecision(3); + } + else + { + returnVal.units = "yr"; + returnVal.value = (amount / (1000 * 60 * 60 * 24 * 365)).toPrecision(3); + } + + return returnVal; + } + }; +});
\ No newline at end of file diff --git a/qpid/java/broker-plugins/management/src/main/java/resources/js/qpid/common/properties.js b/qpid/java/broker-plugins/management/src/main/java/resources/js/qpid/common/properties.js new file mode 100644 index 0000000000..8d85345b74 --- /dev/null +++ b/qpid/java/broker-plugins/management/src/main/java/resources/js/qpid/common/properties.js @@ -0,0 +1,26 @@ +/* + * + * 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. + * + */ +define(["dojo/has", "dojo/_base/sniff", "dojo/domReady!"], + function (has) { + var properties = {}; + properties.useSyncGet = (has("ie") <= 8); + return properties; + });
\ No newline at end of file diff --git a/qpid/java/broker-plugins/management/src/main/java/resources/js/qpid/common/updater.js b/qpid/java/broker-plugins/management/src/main/java/resources/js/qpid/common/updater.js new file mode 100644 index 0000000000..86bbaa46ba --- /dev/null +++ b/qpid/java/broker-plugins/management/src/main/java/resources/js/qpid/common/updater.js @@ -0,0 +1,45 @@ +/* + * + * 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. + * + */ +define(function () { + var updateList = new Array(); + + setInterval(function() { + for(var i = 0; i < updateList.length; i++) { + var obj = updateList[i]; + obj.update(); + } + }, 5000); // TODO: Should make this configurable + + return { + add: function(obj) { + updateList.push(obj); + }, + + remove: function(obj) { + for(var i = 0; i < updateList.length; i++) { + if(updateList[i] === obj) { + updateList.splice(i,1); + return; + } + } + } + }; +});
\ No newline at end of file diff --git a/qpid/java/broker-plugins/management/src/main/java/resources/js/qpid/common/util.js b/qpid/java/broker-plugins/management/src/main/java/resources/js/qpid/common/util.js new file mode 100644 index 0000000000..d7917b640e --- /dev/null +++ b/qpid/java/broker-plugins/management/src/main/java/resources/js/qpid/common/util.js @@ -0,0 +1,56 @@ +/* + * + * 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. + * + */ +define([], + function () { + var util = {}; + if (Array.isArray) { + util.isArray = function (object) { + return Array.isArray(object); + }; + } else { + util.isArray = function (object) { + return object instanceof Array; + }; + } + + util.flattenStatistics = function (data) { + var attrName, stats, propName, theList; + for(attrName in data) { + if(data.hasOwnProperty(attrName)) { + if(attrName == "statistics") { + stats = data.statistics; + for(propName in stats) { + if(stats.hasOwnProperty( propName )) { + data[ propName ] = stats[ propName ]; + } + } + } else if(data[ attrName ] instanceof Array) { + theList = data[ attrName ]; + + for(var i=0; i < theList.length; i++) { + util.flattenStatistics( theList[i] ); + } + } + } + } + }; + return util; + });
\ No newline at end of file diff --git a/qpid/java/broker-plugins/management/src/main/java/resources/js/qpid/management/AuthenticationProvider.js b/qpid/java/broker-plugins/management/src/main/java/resources/js/qpid/management/AuthenticationProvider.js new file mode 100644 index 0000000000..7613fd5d71 --- /dev/null +++ b/qpid/java/broker-plugins/management/src/main/java/resources/js/qpid/management/AuthenticationProvider.js @@ -0,0 +1,122 @@ +/* + * + * 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. + * + */ +define(["dojo/_base/xhr", + "dojo/parser", + "dojo/query", + "dojo/_base/connect", + "qpid/common/properties", + "qpid/common/updater", + "qpid/common/util", + "qpid/common/UpdatableStore", + "dojox/grid/EnhancedGrid", + "dojox/grid/enhanced/plugins/Pagination", + "dojox/grid/enhanced/plugins/IndirectSelection", + "dojo/domReady!"], + function (xhr, parser, query, connect, properties, updater, util, UpdatableStore, EnhancedGrid) { + + function AuthenticationProvider(name, parent, controller) { + this.name = name; + this.controller = controller; + this.modelObj = { type: "authenticationprovider", name: name }; + if(parent) { + this.modelObj.parent = {}; + this.modelObj.parent[ parent.type] = parent; + } + } + + AuthenticationProvider.prototype.getTitle = function() { + return "AuthenticationProvider"; + }; + + AuthenticationProvider.prototype.open = function(contentPane) { + var that = this; + this.contentPane = contentPane; + xhr.get({url: "showAuthProvider.html", + sync: true, + load: function(data) { + contentPane.containerNode.innerHTML = data; + parser.parse(contentPane.containerNode); + + that.authProviderAdapter = new AuthProviderUpdater(contentPane.containerNode, that.modelObj, that.controller); + + updater.add( that.authProviderAdapter ); + + that.authProviderAdapter.update(); + + }}); + }; + + AuthenticationProvider.prototype.close = function() { + updater.remove( this.authProviderAdapter ); + }; + + function AuthProviderUpdater(node, authProviderObj, controller) + { + this.controller = controller; + this.name = query(".name", node)[0]; + /*this.state = dom.byId("state"); + this.durable = dom.byId("durable"); + this.lifetimePolicy = dom.byId("lifetimePolicy"); + */ + this.query = "rest/authenticationprovider/"+encodeURIComponent(authProviderObj.name); + + var that = this; + + xhr.get({url: this.query, sync: properties.useSyncGet, handleAs: "json"}) + .then(function(data) + { + that.authProviderData = data[0]; + + util.flattenStatistics( that.authProviderData ); + + that.updateHeader(); + + require(["qpid/management/authenticationprovider/"+that.authProviderData.type], + function(SpecificProvider) { + that.details = new SpecificProvider(node, authProviderObj, controller); + that.details.update(); + }); + + }); + + } + + AuthProviderUpdater.prototype.updateHeader = function() + { + this.name.innerHTML = this.authProviderData[ "name" ]; + /* this.state.innerHTML = this.brokerData[ "state" ]; + this.durable.innerHTML = this.brokerData[ "durable" ]; + this.lifetimePolicy.innerHTML = this.brokerData[ "lifetimePolicy" ]; +*/ + }; + + AuthProviderUpdater.prototype.update = function() + { + + var that = this; + + + }; + + + + return AuthenticationProvider; + }); diff --git a/qpid/java/broker-plugins/management/src/main/java/resources/js/qpid/management/Broker.js b/qpid/java/broker-plugins/management/src/main/java/resources/js/qpid/management/Broker.js new file mode 100644 index 0000000000..dcf6711073 --- /dev/null +++ b/qpid/java/broker-plugins/management/src/main/java/resources/js/qpid/management/Broker.js @@ -0,0 +1,205 @@ +/* + * + * 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. + * + */ +define(["dojo/_base/xhr", + "dojo/parser", + "dojo/query", + "dojo/_base/connect", + "qpid/common/properties", + "qpid/common/updater", + "qpid/common/util", + "qpid/common/UpdatableStore", + "dojox/grid/EnhancedGrid", + "dojox/grid/enhanced/plugins/Pagination", + "dojox/grid/enhanced/plugins/IndirectSelection", + "dojo/domReady!"], + function (xhr, parser, query, connect, properties, updater, util, UpdatableStore, EnhancedGrid) { + + function Broker(name, parent, controller) { + this.name = name; + this.controller = controller; + this.modelObj = { type: "broker", name: name }; + if(parent) { + this.modelObj.parent = {}; + this.modelObj.parent[ parent.type] = parent; + } + } + + Broker.prototype.getTitle = function() + { + return "Broker"; + }; + + Broker.prototype.open = function(contentPane) { + var that = this; + this.contentPane = contentPane; + xhr.get({url: "showBroker.html", + sync: true, + load: function(data) { + contentPane.containerNode.innerHTML = data; + parser.parse(contentPane.containerNode); + + that.brokerUpdater = new BrokerUpdater(contentPane.containerNode, that.modelObj, that.controller); + + updater.add( that.brokerUpdater ); + + that.brokerUpdater.update(); + + }}); + }; + + Broker.prototype.close = function() { + updater.remove( this.brokerUpdater ); + }; + + function BrokerUpdater(node, brokerObj, controller) + { + this.controller = controller; + this.name = query(".broker-name", node)[0]; + /*this.state = dom.byId("state"); + this.durable = dom.byId("durable"); + this.lifetimePolicy = dom.byId("lifetimePolicy"); + */ + this.query = "rest/broker"; + + var that = this; + + xhr.get({url: this.query, sync: properties.useSyncGet, handleAs: "json"}) + .then(function(data) + { + that.brokerData= data[0]; + + util.flattenStatistics( that.brokerData); + + that.updateHeader(); + that.vhostsGrid = + new UpdatableStore(that.brokerData.vhosts, query(".broker-virtualhosts")[0], + [ { name: "Virtual Host", field: "name", width: "120px"}, + { name: "Connections", field: "connectionCount", width: "80px"}, + { name: "Queues", field: "queueCount", width: "80px"}, + { name: "Exchanges", field: "exchangeCount", width: "100%"} + ], function(obj) { + connect.connect(obj.grid, "onRowDblClick", obj.grid, + function(evt){ + var idx = evt.rowIndex, + theItem = this.getItem(idx); + var name = obj.dataStore.getValue(theItem,"name"); + that.controller.show("virtualhost", name, brokerObj); + }); + }); + + that.portsGrid = + new UpdatableStore(that.brokerData.ports, query(".broker-ports")[0], + [ { name: "Address", field: "bindingAddress", width: "70px"}, + { name: "Port", field: "port", width: "70px"}, + { name: "Transports", field: "transports", width: "150px"}, + { name: "Protocols", field: "protocols", width: "100%"} + ], function(obj) { + connect.connect(obj.grid, "onRowDblClick", obj.grid, + function(evt){ + var idx = evt.rowIndex, + theItem = this.getItem(idx); + var name = obj.dataStore.getValue(theItem,"name"); + that.controller.show("port", name, brokerObj); + }); + }); + + }); + + xhr.get({url: "rest/logrecords", sync: properties.useSyncGet, handleAs: "json"}) + .then(function(data) + { + that.logData = data; + + var gridProperties = { + height: 400, + plugins: { + pagination: { + pageSizes: ["10", "25", "50", "100"], + description: true, + sizeSwitch: true, + pageStepper: true, + gotoButton: true, + maxPageStep: 4, + position: "bottom" + } + }}; + + + that.logfileGrid = + new UpdatableStore(that.logData, query(".broker-logfile")[0], + [ { name: "Timestamp", field: "timestamp", width: "200px", + formatter: function(val) { + var d = new Date(0); + d.setUTCSeconds(val/1000); + + return d.toLocaleString(); + }}, + { name: "Level", field: "level", width: "60px"}, + { name: "Logger", field: "logger", width: "280px"}, + { name: "Thread", field: "thread", width: "120px"}, + { name: "Log Message", field: "message", width: "100%"} + + ], null, gridProperties, EnhancedGrid); + }); + } + + BrokerUpdater.prototype.updateHeader = function() + { + this.name.innerHTML = this.brokerData[ "name" ]; + /* this.state.innerHTML = this.brokerData[ "state" ]; + this.durable.innerHTML = this.brokerData[ "durable" ]; + this.lifetimePolicy.innerHTML = this.brokerData[ "lifetimePolicy" ]; +*/ + }; + + BrokerUpdater.prototype.update = function() + { + + var that = this; + + xhr.get({url: this.query, sync: properties.useSyncGet, handleAs: "json"}).then(function(data) + { + that.brokerData = data[0]; + util.flattenStatistics( that.brokerData ); + + that.updateHeader(); + + that.vhostsGrid.update(that.brokerData.virtualhosts); + + that.portsGrid.update(that.brokerData.ports); + + + }); + + + xhr.get({url: "rest/logrecords", sync: properties.useSyncGet, handleAs: "json"}) + .then(function(data) + { + that.logData = data; + that.logfileGrid.update(that.logData); + }); + + }; + + + + return Broker; + }); diff --git a/qpid/java/broker-plugins/management/src/main/java/resources/js/qpid/management/Connection.js b/qpid/java/broker-plugins/management/src/main/java/resources/js/qpid/management/Connection.js new file mode 100644 index 0000000000..01f9a325c5 --- /dev/null +++ b/qpid/java/broker-plugins/management/src/main/java/resources/js/qpid/management/Connection.js @@ -0,0 +1,213 @@ +/* + * + * 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. + * + */ +define(["dojo/_base/xhr", + "dojo/parser", + "dojo/query", + "dojo/_base/connect", + "qpid/common/properties", + "qpid/common/updater", + "qpid/common/util", + "qpid/common/formatter", + "qpid/common/UpdatableStore", + "dojo/domReady!"], + function (xhr, parser, query, connect, properties, updater, util, formatter, UpdatableStore) { + + function Connection(name, parent, controller) { + this.name = name; + this.controller = controller; + this.modelObj = { type: "exchange", name: name }; + if(parent) { + this.modelObj.parent = {}; + this.modelObj.parent[ parent.type] = parent; + } + } + + Connection.prototype.getTitle = function() + { + return "Connection: " + this.name; + }; + + Connection.prototype.open = function(contentPane) { + var that = this; + this.contentPane = contentPane; + xhr.get({url: "showConnection.html", + sync: true, + load: function(data) { + contentPane.containerNode.innerHTML = data; + parser.parse(contentPane.containerNode); + + that.connectionUpdater = new ConnectionUpdater(contentPane.containerNode, that.modelObj, that.controller); + + updater.add( that.connectionUpdater ); + + that.connectionUpdater.update(); + + }}); + }; + + Connection.prototype.close = function() { + updater.remove( this.connectionUpdater ); + }; + + function ConnectionUpdater(containerNode, connectionObj, controller) + { + var that = this; + + function findNode(name) { + return query("." + name, containerNode)[0]; + } + + function storeNodes(names) + { + for(var i = 0; i < names.length; i++) { + that[names[i]] = findNode(names[i]); + } + } + + storeNodes(["name", + "state", + "durable", + "lifetimePolicy", + "msgInRate", + "bytesInRate", + "bytesInRateUnits", + "msgOutRate", + "bytesOutRate", + "bytesOutRateUnits"]); + + + + this.query = "rest/connection/"+ encodeURIComponent(connectionObj.parent.virtualhost.name) + "/" + encodeURIComponent(connectionObj.name); + + xhr.get({url: this.query, sync: properties.useSyncGet, handleAs: "json"}).then(function(data) + { + that.connectionData = data[0]; + + util.flattenStatistics( that.connectionData ); + + that.updateHeader(); + that.sessionsGrid = new UpdatableStore(that.connectionData.sessions, findNode("sessions"), + [ { name: "Name", field: "name", width: "70px"}, + { name: "Mode", field: "distributionMode", width: "70px"}, + { name: "Msgs Rate", field: "msgRate", + width: "150px"}, + { name: "Bytes Rate", field: "bytesRate", + width: "100%"} + ]); + + + }); + + } + + ConnectionUpdater.prototype.updateHeader = function() + { + this.name.innerHTML = this.connectionData[ "name" ]; + this.state.innerHTML = this.connectionData[ "state" ]; + this.durable.innerHTML = this.connectionData[ "durable" ]; + this.lifetimePolicy.innerHTML = this.connectionData[ "lifetimePolicy" ]; + + }; + + ConnectionUpdater.prototype.update = function() + { + + var that = this; + + xhr.get({url: this.query, sync: properties.useSyncGet, handleAs: "json"}).then(function(data) + { + that.connectionData = data[0]; + + util.flattenStatistics( that.connectionData ); + + var sessions = that.connectionData[ "sessions" ]; + + that.updateHeader(); + + var sampleTime = new Date(); + var messageIn = that.connectionData["messagesIn"]; + var bytesIn = that.connectionData["bytesIn"]; + var messageOut = that.connectionData["messagesOut"]; + var bytesOut = that.connectionData["bytesOut"]; + + if(that.sampleTime) + { + var samplePeriod = sampleTime.getTime() - that.sampleTime.getTime(); + + var msgInRate = (1000 * (messageIn - that.messageIn)) / samplePeriod; + var msgOutRate = (1000 * (messageOut - that.messageOut)) / samplePeriod; + var bytesInRate = (1000 * (bytesIn - that.bytesIn)) / samplePeriod; + var bytesOutRate = (1000 * (bytesOut - that.bytesOut)) / samplePeriod; + + that.msgInRate.innerHTML = msgInRate.toFixed(0); + var bytesInFormat = formatter.formatBytes( bytesInRate ); + that.bytesInRate.innerHTML = "(" + bytesInFormat.value; + that.bytesInRateUnits.innerHTML = bytesInFormat.units + "/s)"; + + that.msgOutRate.innerHTML = msgOutRate.toFixed(0); + var bytesOutFormat = formatter.formatBytes( bytesOutRate ); + that.bytesOutRate.innerHTML = "(" + bytesOutFormat.value; + that.bytesOutRateUnits.innerHTML = bytesOutFormat.units + "/s)"; + + if(sessions && that.sessions) + { + for(var i=0; i < sessions.length; i++) + { + var session = sessions[i]; + for(var j = 0; j < that.sessions.length; j++) + { + var oldSession = that.sessions[j]; + if(oldSession.id == session.id) + { + var msgRate = (1000 * (session.messagesOut - oldSession.messagesOut)) / + samplePeriod; + session.msgRate = msgRate.toFixed(0) + "msg/s"; + + var bytesRate = (1000 * (session.bytesOut - oldSession.bytesOut)) / + samplePeriod; + var bytesRateFormat = formatter.formatBytes( bytesRate ); + session.bytesRate = bytesRateFormat.value + bytesRateFormat.units + "/s"; + } + + + } + + } + } + + } + + that.sampleTime = sampleTime; + that.messageIn = messageIn; + that.bytesIn = bytesIn; + that.messageOut = messageOut; + that.bytesOut = bytesOut; + that.sessions = sessions; + + + // update sessions + that.sessionsGrid.update(that.connectionData.sessions) + }); + }; + + + return Connection; + });
\ No newline at end of file diff --git a/qpid/java/broker-plugins/management/src/main/java/resources/js/qpid/management/Exchange.js b/qpid/java/broker-plugins/management/src/main/java/resources/js/qpid/management/Exchange.js new file mode 100644 index 0000000000..0450ef53ac --- /dev/null +++ b/qpid/java/broker-plugins/management/src/main/java/resources/js/qpid/management/Exchange.js @@ -0,0 +1,229 @@ +/* + * + * 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. + * + */ +define(["dojo/_base/xhr", + "dojo/parser", + "dojo/query", + "dojo/_base/connect", + "dijit/registry", + "qpid/common/properties", + "qpid/common/updater", + "qpid/common/util", + "qpid/common/formatter", + "qpid/common/UpdatableStore", + "qpid/management/addBinding", + "dojo/domReady!"], + function (xhr, parser, query, connect, registry, properties, updater, util, formatter, UpdatableStore, addBinding) { + + function Exchange(name, parent, controller) { + this.name = name; + this.controller = controller; + this.modelObj = { type: "exchange", name: name }; + if(parent) { + this.modelObj.parent = {}; + this.modelObj.parent[ parent.type] = parent; + } + } + + + Exchange.prototype.getExchangeName = function() + { + return this.name; + }; + + + Exchange.prototype.getVirtualHostName = function() + { + return this.modelObj.parent.virtualhost.name; + }; + + Exchange.prototype.getTitle = function() + { + return "Exchange: " + this.name; + }; + + Exchange.prototype.open = function(contentPane) { + var that = this; + this.contentPane = contentPane; + xhr.get({url: "showExchange.html", + sync: true, + load: function(data) { + contentPane.containerNode.innerHTML = data; + parser.parse(contentPane.containerNode); + + that.exchangeUpdater = new ExchangeUpdater(contentPane.containerNode, that.modelObj, that.controller); + + updater.add( that.exchangeUpdater ); + + that.exchangeUpdater.update(); + + + var addBindingButton = query(".addBindingButton", contentPane.containerNode)[0]; + connect.connect(registry.byNode(addBindingButton), "onClick", + function(evt){ + addBinding.show({ virtualhost: that.getVirtualHostName(), + exchange: that.getExchangeName()}); + }); + + }}); + }; + + Exchange.prototype.close = function() { + updater.remove( this.exchangeUpdater ); + }; + + function ExchangeUpdater(containerNode, exchangeObj, controller) + { + var that = this; + + function findNode(name) { + return query("." + name, containerNode)[0]; + } + + function storeNodes(names) + { + for(var i = 0; i < names.length; i++) { + that[names[i]] = findNode(names[i]); + } + } + + storeNodes(["name", + "state", + "durable", + "lifetimePolicy", + "alertRepeatGap", + "alertRepeatGapUnits", + "alertThresholdMessageAge", + "alertThresholdMessageAgeUnits", + "alertThresholdMessageSize", + "alertThresholdMessageSizeUnits", + "alertThresholdQueueDepthBytes", + "alertThresholdQueueDepthBytesUnits", + "alertThresholdQueueDepthMessages", + "msgInRate", + "bytesInRate", + "bytesInRateUnits", + "msgDropRate", + "bytesDropRate", + "bytesDropRateUnits"]); + + + + this.query = "rest/exchange/"+ encodeURIComponent(exchangeObj.parent.virtualhost.name) + "/" + encodeURIComponent(exchangeObj.name); + + xhr.get({url: this.query, sync: properties.useSyncGet, handleAs: "json"}).then(function(data) + { + that.exchangeData = data[0]; + util.flattenStatistics( that.exchangeData ); + + that.updateHeader(); + that.bindingsGrid = new UpdatableStore(that.exchangeData.bindings, findNode("bindings"), + [ { name: "Queue", field: "queue", width: "90px"}, + { name: "Binding Key", field: "name", width: "120px"}, + { name: "Arguments", field: "argumentString", width: "100%"} + ]); + + }); + + } + + ExchangeUpdater.prototype.updateHeader = function() + { + this.name.innerHTML = this.exchangeData[ "name" ]; + this.state.innerHTML = this.exchangeData[ "state" ]; + this.durable.innerHTML = this.exchangeData[ "durable" ]; + this.lifetimePolicy.innerHTML = this.exchangeData[ "lifetimePolicy" ]; + + }; + + ExchangeUpdater.prototype.update = function() + { + + var thisObj = this; + + xhr.get({url: this.query, sync: properties.useSyncGet, handleAs: "json"}).then(function(data) + { + thisObj.exchangeData = data[0]; + + util.flattenStatistics( thisObj.exchangeData ); + + var bindings = thisObj.exchangeData[ "bindings" ]; + + if(bindings) + { + for(var i=0; i < bindings.length; i++) + { + if(bindings[i].arguments) + { + bindings[i].argumentString = dojo.toJson(bindings[i].arguments); + } + else + { + bindings[i].argumentString = ""; + } + } + } + + + var sampleTime = new Date(); + + thisObj.updateHeader(); + + var messageIn = thisObj.exchangeData["messagesIn"]; + var bytesIn = thisObj.exchangeData["bytesIn"]; + var messageDrop = thisObj.exchangeData["messagesDropped"]; + var bytesDrop = thisObj.exchangeData["bytesDropped"]; + + if(thisObj.sampleTime) + { + var samplePeriod = sampleTime.getTime() - thisObj.sampleTime.getTime(); + + var msgInRate = (1000 * (messageIn - thisObj.messageIn)) / samplePeriod; + var msgDropRate = (1000 * (messageDrop - thisObj.messageDrop)) / samplePeriod; + var bytesInRate = (1000 * (bytesIn - thisObj.bytesIn)) / samplePeriod; + var bytesDropRate = (1000 * (bytesDrop - thisObj.bytesDrop)) / samplePeriod; + + thisObj.msgInRate.innerHTML = msgInRate.toFixed(0); + var bytesInFormat = formatter.formatBytes( bytesInRate ); + thisObj.bytesInRate.innerHTML = "(" + bytesInFormat.value; + thisObj.bytesInRateUnits.innerHTML = bytesInFormat.units + "/s)"; + + thisObj.msgDropRate.innerHTML = msgDropRate.toFixed(0); + var bytesDropFormat = formatter.formatBytes( bytesDropRate ); + thisObj.bytesDropRate.innerHTML = "(" + bytesDropFormat.value; + thisObj.bytesDropRateUnits.innerHTML = bytesDropFormat.units + "/s)" + + } + + thisObj.sampleTime = sampleTime; + thisObj.messageIn = messageIn; + thisObj.bytesIn = bytesIn; + thisObj.messageDrop = messageDrop; + thisObj.bytesDrop = bytesDrop; + + // update bindings + thisObj.bindingsGrid.update(thisObj.exchangeData.bindings) + + }); + }; + + + return Exchange; + }); diff --git a/qpid/java/broker-plugins/management/src/main/java/resources/js/qpid/management/Queue.js b/qpid/java/broker-plugins/management/src/main/java/resources/js/qpid/management/Queue.js new file mode 100644 index 0000000000..1eb0bfdd79 --- /dev/null +++ b/qpid/java/broker-plugins/management/src/main/java/resources/js/qpid/management/Queue.js @@ -0,0 +1,438 @@ +/* + * + * 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. + * + */ +define(["dojo/_base/xhr", + "dojo/parser", + "dojo/query", + "dijit/registry", + "dojo/_base/connect", + "dojo/_base/event", + "dojo/json", + "qpid/common/properties", + "qpid/common/updater", + "qpid/common/util", + "qpid/common/formatter", + "qpid/common/UpdatableStore", + "qpid/management/addBinding", + "qpid/management/moveCopyMessages", + "qpid/management/showMessage", + "dojo/store/JsonRest", + "dojox/grid/EnhancedGrid", + "dojo/data/ObjectStore", + "dojox/grid/enhanced/plugins/Pagination", + "dojox/grid/enhanced/plugins/IndirectSelection", + "dojo/domReady!"], + function (xhr, parser, query, registry, connect, event, json, properties, updater, util, formatter, + UpdatableStore, addBinding, moveMessages, showMessage, JsonRest, EnhancedGrid, ObjectStore) { + + function Queue(name, parent, controller) { + this.name = name; + this.controller = controller; + this.modelObj = { type: "queue", name: name }; + if(parent) { + this.modelObj.parent = {}; + this.modelObj.parent[ parent.type] = parent; + } + } + + Queue.prototype.getQueueName = function() + { + return this.name; + }; + + + Queue.prototype.getVirtualHostName = function() + { + return this.modelObj.parent.virtualhost.name; + }; + + Queue.prototype.getTitle = function() + { + return "Queue: " + this.name; + }; + + Queue.prototype.open = function(contentPane) { + var that = this; + this.contentPane = contentPane; + xhr.get({url: "showQueue.html", + sync: true, + load: function(data) { + contentPane.containerNode.innerHTML = data; + parser.parse(contentPane.containerNode); + + that.queueUpdater = new QueueUpdater(contentPane.containerNode, that, that.controller); + + updater.add( that.queueUpdater ); + + that.queueUpdater.update(); + + var myStore = new JsonRest({target:"rest/message/"+ encodeURIComponent(that.getVirtualHostName()) + + "/" + encodeURIComponent(that.getQueueName())}); + var messageGridDiv = query(".messages",contentPane.containerNode)[0]; + that.dataStore = new ObjectStore({objectStore: myStore}); + that.grid = new EnhancedGrid({ + store: that.dataStore, + autoHeight: 10, + keepSelection: true, + structure: [ + {name:"Size", field:"size", width: "60px"}, + {name:"State", field:"state", width: "120px"}, + + {name:"Arrival", field:"arrivalTime", width: "100%", + formatter: function(val) { + var d = new Date(0); + d.setUTCSeconds(val/1000); + + return d.toLocaleString(); + } } + ], + plugins: { + pagination: { + pageSizes: ["10", "25", "50", "100"], + description: true, + sizeSwitch: true, + pageStepper: true, + gotoButton: true, + maxPageStep: 4, + position: "bottom" + }, + indirectSelection: true + } + }, messageGridDiv); + + connect.connect(that.grid, "onRowDblClick", that.grid, + function(evt){ + var idx = evt.rowIndex, + theItem = this.getItem(idx); + var id = that.dataStore.getValue(theItem,"id"); + showMessage.show({ messageNumber: id, + queue: that.getQueueName(), + virtualhost: that.getVirtualHostName() }); + }); + + var deleteMessagesButton = query(".deleteMessagesButton", contentPane.containerNode)[0]; + var deleteWidget = registry.byNode(deleteMessagesButton); + connect.connect(deleteWidget, "onClick", + function(evt){ + event.stop(evt); + that.deleteMessages(); + }); + var moveMessagesButton = query(".moveMessagesButton", contentPane.containerNode)[0]; + connect.connect(registry.byNode(moveMessagesButton), "onClick", + function(evt){ + event.stop(evt); + that.moveOrCopyMessages({move: true}); + }); + + + var copyMessagesButton = query(".copyMessagesButton", contentPane.containerNode)[0]; + connect.connect(registry.byNode(copyMessagesButton), "onClick", + function(evt){ + event.stop(evt); + that.moveOrCopyMessages({move: false}); + }); + + var addBindingButton = query(".addBindingButton", contentPane.containerNode)[0]; + connect.connect(registry.byNode(addBindingButton), "onClick", + function(evt){ + event.stop(evt); + addBinding.show({ virtualhost: that.getVirtualHostName(), + queue: that.getQueueName()}); + }); + + }}); + + + + }; + + Queue.prototype.deleteMessages = function() { + var data = this.grid.selection.getSelected(); + if(data.length) { + var that = this; + if(confirm("Delete " + data.length + " messages?")) { + var i, queryParam; + for(i = 0; i<data.length; i++) { + if(queryParam) { + queryParam += "&"; + } else { + queryParam = "?"; + } + + queryParam += "id=" + data[i].id; + } + var query = "rest/message/"+ encodeURIComponent(that.getVirtualHostName()) + + "/" + encodeURIComponent(that.getQueueName()) + queryParam; + that.success = true + xhr.del({url: query, sync: true, handleAs: "json"}).then( + function(data) { + that.grid.setQuery({id: "*"}); + that.grid.selection.deselectAll(); + that.queueUpdater.update(); + }, + function(error) {that.success = false; that.failureReason = error;}); + if(!that.success ) { + alert("Error:" + this.failureReason); + } + } + } + }; + + Queue.prototype.moveOrCopyMessages = function(obj) { + var that = this; + var move = obj.move; + var data = this.grid.selection.getSelected(); + if(data.length) { + var that = this; + var i, putData = { messages:[] }; + if(move) { + putData.move = true; + } + for(i = 0; i<data.length; i++) { + putData.messages.push(data[i].id); + } + moveMessages.show({ virtualhost: this.getVirtualHostName(), + queue: this.getQueueName(), + data: putData}, function() { + if(move) + { + that.grid.setQuery({id: "*"}); + that.grid.selection.deselectAll(); + } + }); + + } + + + + }; + + Queue.prototype.startup = function() { + this.grid.startup(); + }; + + Queue.prototype.close = function() { + updater.remove( this.queueUpdater ); + }; + + function QueueUpdater(containerNode, queueObj, controller) + { + var that = this; + + function findNode(name) { + return query("." + name, containerNode)[0]; + } + + function storeNodes(names) + { + for(var i = 0; i < names.length; i++) { + that[names[i]] = findNode(names[i]); + } + } + + storeNodes(["name", + "state", + "durable", + "lifetimePolicy", + "alertRepeatGap", + "alertRepeatGapUnits", + "alertThresholdMessageAge", + "alertThresholdMessageAgeUnits", + "alertThresholdMessageSize", + "alertThresholdMessageSizeUnits", + "alertThresholdQueueDepthBytes", + "alertThresholdQueueDepthBytesUnits", + "alertThresholdQueueDepthMessages", + "queueDepthMessages", + "queueDepthBytes", + "queueDepthBytesUnits", + "unacknowledgedMessages", + "unacknowledgedBytes", + "unacknowledgedBytesUnits", + "msgInRate", + "bytesInRate", + "bytesInRateUnits", + "msgOutRate", + "bytesOutRate", + "bytesOutRateUnits"]); + + + + this.query = "rest/queue/"+ encodeURIComponent(queueObj.getVirtualHostName()) + "/" + encodeURIComponent(queueObj.getQueueName()); + + xhr.get({url: this.query, sync: properties.useSyncGet, handleAs: "json"}).then(function(data) + { + that.queueData = data[0]; + + util.flattenStatistics( that.queueData ); + + that.updateHeader(); + that.bindingsGrid = new UpdatableStore(that.queueData.bindings, findNode("bindings"), + [ { name: "Exchange", field: "exchange", width: "90px"}, + { name: "Binding Key", field: "name", width: "120px"}, + { name: "Arguments", field: "argumentString", width: "100%"} + ]); + + that.consumersGrid = new UpdatableStore(that.queueData.consumers, findNode("consumers"), + [ { name: "Name", field: "name", width: "70px"}, + { name: "Mode", field: "distributionMode", width: "70px"}, + { name: "Msgs Rate", field: "msgRate", + width: "150px"}, + { name: "Bytes Rate", field: "bytesRate", + width: "100%"} + ]); + + + + + }); + + } + + QueueUpdater.prototype.updateHeader = function() + { + + var bytesDepth; + this.name.innerHTML = this.queueData[ "name" ]; + this.state.innerHTML = this.queueData[ "state" ]; + this.durable.innerHTML = this.queueData[ "durable" ]; + this.lifetimePolicy.innerHTML = this.queueData[ "lifetimePolicy" ]; + + this.queueDepthMessages.innerHTML = this.queueData["queueDepthMessages"]; + bytesDepth = formatter.formatBytes( this.queueData["queueDepthBytes"] ); + this.queueDepthBytes.innerHTML = "(" + bytesDepth.value; + this.queueDepthBytesUnits.innerHTML = bytesDepth.units + ")"; + + this.unacknowledgedMessages.innerHTML = this.queueData["unacknowledgedMessages"]; + bytesDepth = formatter.formatBytes( this.queueData["unacknowledgedBytes"] ); + this.unacknowledgedBytes.innerHTML = "(" + bytesDepth.value; + this.unacknowledgedBytesUnits.innerHTML = bytesDepth.units + ")" + + + }; + + QueueUpdater.prototype.update = function() + { + + var thisObj = this; + + xhr.get({url: this.query, sync: properties.useSyncGet, handleAs: "json"}).then(function(data) { + var i,j; + thisObj.queueData = data[0]; + util.flattenStatistics( thisObj.queueData ); + + var bindings = thisObj.queueData[ "bindings" ]; + var consumers = thisObj.queueData[ "consumers" ]; + + for(i=0; i < bindings.length; i++) { + bindings[i].argumentString = json.stringify(bindings[i].arguments); + } + + thisObj.updateHeader(); + + + // update alerting info + var alertRepeatGap = formatter.formatTime( thisObj.queueData["alertRepeatGap"] ); + + thisObj.alertRepeatGap.innerHTML = alertRepeatGap.value; + thisObj.alertRepeatGapUnits.innerHTML = alertRepeatGap.units; + + + var alertMsgAge = formatter.formatTime( thisObj.queueData["alertThresholdMessageAge"] ); + + thisObj.alertThresholdMessageAge.innerHTML = alertMsgAge.value; + thisObj.alertThresholdMessageAgeUnits.innerHTML = alertMsgAge.units; + + var alertMsgSize = formatter.formatBytes( thisObj.queueData["alertThresholdMessageSize"] ); + + thisObj.alertThresholdMessageSize.innerHTML = alertMsgSize.value; + thisObj.alertThresholdMessageSizeUnits.innerHTML = alertMsgSize.units; + + var alertQueueDepth = formatter.formatBytes( thisObj.queueData["alertThresholdQueueDepthBytes"] ); + + thisObj.alertThresholdQueueDepthBytes.innerHTML = alertQueueDepth.value; + thisObj.alertThresholdQueueDepthBytesUnits.innerHTML = alertQueueDepth.units; + + thisObj.alertThresholdQueueDepthMessages.innerHTML = thisObj.queueData["alertThresholdQueueDepthMessages"]; + + var sampleTime = new Date(); + var messageIn = thisObj.queueData["totalEnqueuedMessages"]; + var bytesIn = thisObj.queueData["totalEnqueuedBytes"]; + var messageOut = thisObj.queueData["totalDequeuedMessages"]; + var bytesOut = thisObj.queueData["totalDequeuedBytes"]; + + if(thisObj.sampleTime) { + var samplePeriod = sampleTime.getTime() - thisObj.sampleTime.getTime(); + + var msgInRate = (1000 * (messageIn - thisObj.messageIn)) / samplePeriod; + var msgOutRate = (1000 * (messageOut - thisObj.messageOut)) / samplePeriod; + var bytesInRate = (1000 * (bytesIn - thisObj.bytesIn)) / samplePeriod; + var bytesOutRate = (1000 * (bytesOut - thisObj.bytesOut)) / samplePeriod; + + thisObj.msgInRate.innerHTML = msgInRate.toFixed(0); + var bytesInFormat = formatter.formatBytes( bytesInRate ); + thisObj.bytesInRate.innerHTML = "(" + bytesInFormat.value; + thisObj.bytesInRateUnits.innerHTML = bytesInFormat.units + "/s)"; + + thisObj.msgOutRate.innerHTML = msgOutRate.toFixed(0); + var bytesOutFormat = formatter.formatBytes( bytesOutRate ); + thisObj.bytesOutRate.innerHTML = "(" + bytesOutFormat.value; + thisObj.bytesOutRateUnits.innerHTML = bytesOutFormat.units + "/s)"; + + if(consumers && thisObj.consumers) { + for(i=0; i < consumers.length; i++) { + var consumer = consumers[i]; + for(j = 0; j < thisObj.consumers.length; j++) { + var oldConsumer = thisObj.consumers[j]; + if(oldConsumer.id == consumer.id) { + var msgRate = (1000 * (consumer.messagesOut - oldConsumer.messagesOut)) / + samplePeriod; + consumer.msgRate = msgRate.toFixed(0) + "msg/s"; + + var bytesRate = (1000 * (consumer.bytesOut - oldConsumer.bytesOut)) / + samplePeriod; + var bytesRateFormat = formatter.formatBytes( bytesRate ); + consumer.bytesRate = bytesRateFormat.value + bytesRateFormat.units + "/s"; + } + } + } + } + + } + + thisObj.sampleTime = sampleTime; + thisObj.messageIn = messageIn; + thisObj.bytesIn = bytesIn; + thisObj.messageOut = messageOut; + thisObj.bytesOut = bytesOut; + thisObj.consumers = consumers; + + // update bindings + thisObj.bindingsGrid.update(thisObj.queueData.bindings); + + // update consumers + thisObj.consumersGrid.update(thisObj.queueData.consumers) + + }); + }; + + + return Queue; + }); diff --git a/qpid/java/broker-plugins/management/src/main/java/resources/js/qpid/management/VirtualHost.js b/qpid/java/broker-plugins/management/src/main/java/resources/js/qpid/management/VirtualHost.js new file mode 100644 index 0000000000..ce24145930 --- /dev/null +++ b/qpid/java/broker-plugins/management/src/main/java/resources/js/qpid/management/VirtualHost.js @@ -0,0 +1,327 @@ +/* + * + * 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. + * + */ +define(["dojo/_base/xhr", + "dojo/parser", + "dojo/query", + "dojo/_base/connect", + "dijit/registry", + "qpid/common/properties", + "qpid/common/updater", + "qpid/common/util", + "qpid/common/formatter", + "qpid/common/UpdatableStore", + "qpid/management/addQueue", + "qpid/management/addExchange", + "dojo/domReady!"], + function (xhr, parser, query, connect, registry, properties, updater, util, formatter, UpdatableStore, addQueue, addExchange) { + + function VirtualHost(name, parent, controller) { + this.name = name; + this.controller = controller; + this.modelObj = { type: "virtualhost", name: name}; + if(parent) { + this.modelObj.parent = {}; + this.modelObj.parent[ parent.type] = parent; + } + } + + VirtualHost.prototype.getTitle = function() + { + return "VirtualHost: " + this.name; + }; + + VirtualHost.prototype.open = function(contentPane) { + var that = this; + this.contentPane = contentPane; + xhr.get({url: "showVirtualHost.html", + sync: true, + load: function(data) { + contentPane.containerNode.innerHTML = data; + parser.parse(contentPane.containerNode); + + that.vhostUpdater = new Updater(contentPane.containerNode, that.modelObj, that.controller); + + updater.add( that.vhostUpdater ); + + that.vhostUpdater.update(); + + var addQueueButton = query(".addQueueButton", contentPane.containerNode)[0]; + connect.connect(registry.byNode(addQueueButton), "onClick", function(evt){ addQueue.show(that.name) }); + + var addExchangeButton = query(".addExchangeButton", contentPane.containerNode)[0]; + connect.connect(registry.byNode(addExchangeButton), "onClick", function(evt){ addExchange.show(that.name) }); + }}); + + }; + + VirtualHost.prototype.close = function() { + updater.remove( this.vhostUpdater ); + }; + + + function Updater(node, vhost, controller) + { + + var that = this; + + function findNode(name) { + return query("." + name, node)[0]; + } + + function storeNodes(names) + { + for(var i = 0; i < names.length; i++) { + that[names[i]] = findNode(names[i]); + } + } + + storeNodes(["name", + "state", + "durable", + "lifetimePolicy", + "alertRepeatGap", + "alertRepeatGapUnits", + "alertThresholdMessageAge", + "alertThresholdMessageAgeUnits", + "alertThresholdMessageSize", + "alertThresholdMessageSizeUnits", + "alertThresholdQueueDepthBytes", + "alertThresholdQueueDepthBytesUnits", + "alertThresholdQueueDepthMessages", + "msgInRate", + "bytesInRate", + "bytesInRateUnits", + "msgOutRate", + "bytesOutRate", + "bytesOutRateUnits"]); + + this.query = "rest/virtualhost/"+ encodeURIComponent(vhost.name); + + var that = this; + + xhr.get({url: this.query, sync: properties.useSyncGet, handleAs: "json"}).then(function(data) { + that.vhostData = data[0]; + + // flatten statistics into attributes + util.flattenStatistics( that.vhostData ); + + that.updateHeader(); + that.queuesGrid = new UpdatableStore(that.vhostData.queues, findNode("queues"), + [ { name: "Name", field: "name", width: "90px"}, + { name: "Messages", field: "queueDepthMessages", width: "90px"}, + { name: "Arguments", field: "arguments", width: "100%"} + ], + function(obj) + { + connect.connect(obj.grid, "onRowDblClick", obj.grid, + function(evt){ + var idx = evt.rowIndex, + theItem = this.getItem(idx); + var queueName = obj.dataStore.getValue(theItem,"name"); + controller.show("queue", queueName, vhost); + }); + } ); + + that.exchangesGrid = new UpdatableStore(that.vhostData.exchanges, findNode("exchanges"), + [ { name: "Name", field: "name", width: "120px"}, + { name: "Type", field: "type", width: "120px"}, + { name: "Binding Count", field: "bindingCount", + width: "100%"} + ], + function(obj) + { + connect.connect(obj.grid, "onRowDblClick", obj.grid, + function(evt){ + var idx = evt.rowIndex, + theItem = this.getItem(idx); + var exchangeName = obj.dataStore.getValue(theItem,"name"); + controller.show("exchange", exchangeName, vhost); + }); + } ); + + + that.connectionsGrid = new UpdatableStore(that.vhostData.connections, + findNode("connections"), + [ { name: "Name", field: "name", width: "150px"}, + { name: "Sessions", field: "sessionCount", width: "70px"}, + { name: "Msgs In", field: "msgInRate", + width: "80px"}, + { name: "Bytes In", field: "bytesInRate", + width: "80px"}, + { name: "Msgs Out", field: "msgOutRate", + width: "80px"}, + { name: "Bytes Out", field: "bytesOutRate", + width: "100%"} + ], + function(obj) + { + connect.connect(obj.grid, "onRowDblClick", obj.grid, + function(evt){ + var idx = evt.rowIndex, + theItem = this.getItem(idx); + var connectionName = obj.dataStore.getValue(theItem,"name"); + controller.show("connection", connectionName, vhost); + }); + } ); + + + + }); + + } + + Updater.prototype.updateHeader = function() + { + this.name.innerHTML = this.vhostData[ "name" ]; + this.state.innerHTML = this.vhostData[ "state" ]; + this.durable.innerHTML = this.vhostData[ "durable" ]; + this.lifetimePolicy.innerHTML = this.vhostData[ "lifetimePolicy" ]; + + + }; + + Updater.prototype.update = function() + { + + var thisObj = this; + + xhr.get({url: this.query, sync: properties.useSyncGet, handleAs: "json"}) + .then(function(data) { + thisObj.vhostData = data[0]; + util.flattenStatistics( thisObj.vhostData ); + var connections = thisObj.vhostData[ "connections" ]; + var queues = thisObj.vhostData[ "queues" ]; + var exchanges = thisObj.vhostData[ "exchanges" ]; + + thisObj.updateHeader(); + + + // update alerting info + var alertRepeatGap = formatter.formatTime( thisObj.vhostData["alertRepeatGap"] ); + + thisObj.alertRepeatGap.innerHTML = alertRepeatGap.value; + thisObj.alertRepeatGapUnits.innerHTML = alertRepeatGap.units; + + + var alertMsgAge = formatter.formatTime( thisObj.vhostData["alertThresholdMessageAge"] ); + + thisObj.alertThresholdMessageAge.innerHTML = alertMsgAge.value; + thisObj.alertThresholdMessageAgeUnits.innerHTML = alertMsgAge.units; + + var alertMsgSize = formatter.formatBytes( thisObj.vhostData["alertThresholdMessageSize"] ); + + thisObj.alertThresholdMessageSize.innerHTML = alertMsgSize.value; + thisObj.alertThresholdMessageSizeUnits.innerHTML = alertMsgSize.units; + + var alertQueueDepth = formatter.formatBytes( thisObj.vhostData["alertThresholdQueueDepthBytes"] ); + + thisObj.alertThresholdQueueDepthBytes.innerHTML = alertQueueDepth.value; + thisObj.alertThresholdQueueDepthBytesUnits.innerHTML = alertQueueDepth.units; + + thisObj.alertThresholdQueueDepthMessages.innerHTML = thisObj.vhostData["alertThresholdQueueDepthMessages"]; + + var stats = thisObj.vhostData[ "statistics" ]; + + var sampleTime = new Date(); + var messageIn = stats["messagesIn"]; + var bytesIn = stats["bytesIn"]; + var messageOut = stats["messagesOut"]; + var bytesOut = stats["bytesOut"]; + + if(thisObj.sampleTime) + { + var samplePeriod = sampleTime.getTime() - thisObj.sampleTime.getTime(); + + var msgInRate = (1000 * (messageIn - thisObj.messageIn)) / samplePeriod; + var msgOutRate = (1000 * (messageOut - thisObj.messageOut)) / samplePeriod; + var bytesInRate = (1000 * (bytesIn - thisObj.bytesIn)) / samplePeriod; + var bytesOutRate = (1000 * (bytesOut - thisObj.bytesOut)) / samplePeriod; + + thisObj.msgInRate.innerHTML = msgInRate.toFixed(0); + var bytesInFormat = formatter.formatBytes( bytesInRate ); + thisObj.bytesInRate.innerHTML = "(" + bytesInFormat.value; + thisObj.bytesInRateUnits.innerHTML = bytesInFormat.units + "/s)"; + + thisObj.msgOutRate.innerHTML = msgOutRate.toFixed(0); + var bytesOutFormat = formatter.formatBytes( bytesOutRate ); + thisObj.bytesOutRate.innerHTML = "(" + bytesOutFormat.value; + thisObj.bytesOutRateUnits.innerHTML = bytesOutFormat.units + "/s)"; + + if(connections && thisObj.connections) + { + for(var i=0; i < connections.length; i++) + { + var connection = connections[i]; + for(var j = 0; j < thisObj.connections.length; j++) + { + var oldConnection = thisObj.connections[j]; + if(oldConnection.id == connection.id) + { + msgOutRate = (1000 * (connection.messagesOut - oldConnection.messagesOut)) / + samplePeriod; + connection.msgOutRate = msgOutRate.toFixed(0) + "msg/s"; + + bytesOutRate = (1000 * (connection.bytesOut - oldConnection.bytesOut)) / + samplePeriod; + var bytesOutRateFormat = formatter.formatBytes( bytesOutRate ); + connection.bytesOutRate = bytesOutRateFormat.value + bytesOutRateFormat.units + "/s"; + + + msgInRate = (1000 * (connection.messagesIn - oldConnection.messagesIn)) / + samplePeriod; + connection.msgInRate = msgInRate.toFixed(0) + "msg/s"; + + bytesInRate = (1000 * (connection.bytesIn - oldConnection.bytesIn)) / + samplePeriod; + var bytesInRateFormat = formatter.formatBytes( bytesInRate ); + connection.bytesInRate = bytesInRateFormat.value + bytesInRateFormat.units + "/s"; + } + + + } + + } + } + } + + thisObj.sampleTime = sampleTime; + thisObj.messageIn = messageIn; + thisObj.bytesIn = bytesIn; + thisObj.messageOut = messageOut; + thisObj.bytesOut = bytesOut; + thisObj.connections = connections; + + // update queues + thisObj.queuesGrid.update(thisObj.vhostData.queues); + + // update exchanges + thisObj.exchangesGrid.update(thisObj.vhostData.exchanges); + + // update connections + thisObj.connectionsGrid.update(thisObj.vhostData.connections) + + + }); + }; + + + return VirtualHost; + });
\ No newline at end of file diff --git a/qpid/java/broker-plugins/management/src/main/java/resources/js/qpid/management/addBinding.js b/qpid/java/broker-plugins/management/src/main/java/resources/js/qpid/management/addBinding.js new file mode 100644 index 0000000000..83e724d0e9 --- /dev/null +++ b/qpid/java/broker-plugins/management/src/main/java/resources/js/qpid/management/addBinding.js @@ -0,0 +1,223 @@ +/* + * 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. + */ +define(["dojo/_base/xhr", + "dojo/dom", + "dojo/dom-construct", + "dojo/_base/window", + "dijit/registry", + "dojo/parser", + "dojo/_base/array", + "dojo/_base/event", + 'dojo/_base/json', + "dojo/store/Memory", + "dijit/form/FilteringSelect", + "dijit/form/NumberSpinner", // required by the form + /* dojox/ validate resources */ + "dojox/validate/us", "dojox/validate/web", + /* basic dijit classes */ + "dijit/Dialog", + "dijit/form/CheckBox", "dijit/form/Textarea", + "dijit/form/FilteringSelect", "dijit/form/TextBox", + "dijit/form/ValidationTextBox", "dijit/form/DateTextBox", + "dijit/form/TimeTextBox", "dijit/form/Button", + "dijit/form/RadioButton", "dijit/form/Form", + "dijit/form/DateTextBox", + /* basic dojox classes */ + "dojox/form/BusyButton", "dojox/form/CheckedMultiSelect", + "dojo/domReady!"], + function (xhr, dom, construct, win, registry, parser, array, event, json, Memory, FilteringSelect) { + + var addBinding = {}; + + var node = construct.create("div", null, win.body(), "last"); + + var convertToBinding = function convertToBinding(formValues) + { + var newBinding = {}; + + newBinding.name = formValues.name; + for(var propName in formValues) + { + if(formValues.hasOwnProperty(propName)) + { + if(propName === "durable") + { + if (formValues.durable[0] && formValues.durable[0] == "durable") { + newBinding.durable = true; + } + } else { + if(formValues[ propName ] !== "") { + newBinding[ propName ] = formValues[propName]; + } + } + + } + } + if(addBinding.queue) { + newBinding.queue = addBinding.queue; + } + if(addBinding.exchange) { + newBinding.exchange = addBinding.exchange; + } + return newBinding; + }; + + + xhr.get({url: "addBinding.html", + sync: true, + load: function(data) { + var theForm; + node.innerHTML = data; + addBinding.dialogNode = dom.byId("addBinding"); + parser.instantiate([addBinding.dialogNode]); + + theForm = registry.byId("formAddBinding"); + array.forEach(theForm.getDescendants(), function(widget) + { + if(widget.name === "type") { + widget.on("change", function(isChecked) { + + var obj = registry.byId(widget.id + ":fields"); + if(obj) { + if(isChecked) { + obj.domNode.style.display = "block"; + obj.resize(); + } else { + obj.domNode.style.display = "none"; + obj.resize(); + } + } + }) + } + + }); + + theForm.on("submit", function(e) { + + event.stop(e); + if(theForm.validate()){ + + var newBinding = convertToBinding(theForm.getValues()); + var that = this; + + xhr.put({url: "rest/binding/"+encodeURIComponent(addBinding.vhost) + +"/"+encodeURIComponent(newBinding.exchange) + +"/"+encodeURIComponent(newBinding.queue) + +"/"+encodeURIComponent(newBinding.name), + sync: true, handleAs: "json", + headers: { "Content-Type": "application/json"}, + putData: json.toJson(newBinding), + load: function(x) {that.success = true; }, + error: function(error) {that.success = false; that.failureReason = error;}}); + + if(this.success === true) + { + registry.byId("addBinding").hide(); + } + else + { + alert("Error:" + this.failureReason); + } + + return false; + + + }else{ + alert('Form contains invalid data. Please correct first'); + return false; + } + + }); + }}); + + addBinding.show = function(obj) { + var that = this; + + addBinding.vhost = obj.virtualhost; + addBinding.queue = obj.queue; + addBinding.exchange = obj.exchange; + registry.byId("formAddBinding").reset(); + + + + xhr.get({url: "rest/queue/" + encodeURIComponent(obj.virtualhost) + "?depth=0", + handleAs: "json"}).then( + function(data) { + var queues = []; + for(var i=0; i < data.length; i++) { + queues[i] = {id: data[i].name, name: data[i].name}; + } + var queueStore = new Memory({ data: queues }); + + + if(that.queueChooser) { + that.queueChooser.destroy( false ); + } + var queueDiv = dom.byId("addBinding.selectQueueDiv"); + var input = construct.create("input", {id: "addBindingSelectQueue"}, queueDiv); + + that.queueChooser = new FilteringSelect({ id: "addBindingSelectQueue", + name: "queue", + store: queueStore, + searchAttr: "name"}, input); + + if(obj.queue) + { + that.queueChooser.set("value", obj.queue); + that.queueChooser.set("disabled", true); + } + + xhr.get({url: "rest/exchange/" + encodeURIComponent(obj.virtualhost) + "?depth=0", + handleAs: "json"}).then( + function(data) { + + var exchanges = []; + for(var i=0; i < data.length; i++) { + exchanges[i] = {id: data[i].name, name: data[i].name}; + } + var exchangeStore = new Memory({ data: exchanges }); + + + if(that.exchangeChooser) { + that.exchangeChooser.destroy( false ); + } + var exchangeDiv = dom.byId("addBinding.selectExchangeDiv"); + var input = construct.create("input", {id: "addBindingSelectExchange"}, exchangeDiv); + + that.exchangeChooser = new FilteringSelect({ id: "addBindingSelectExchange", + name: "exchange", + store: exchangeStore, + searchAttr: "name"}, input); + + if(obj.exchange) + { + that.exchangeChooser.set("value", obj.exchange); + that.exchangeChooser.set("disabled", true); + } + + + registry.byId("addBinding").show(); + }); + + + }); + + + }; + + return addBinding; + }); diff --git a/qpid/java/broker-plugins/management/src/main/java/resources/js/qpid/management/addExchange.js b/qpid/java/broker-plugins/management/src/main/java/resources/js/qpid/management/addExchange.js new file mode 100644 index 0000000000..f88daa54bb --- /dev/null +++ b/qpid/java/broker-plugins/management/src/main/java/resources/js/qpid/management/addExchange.js @@ -0,0 +1,147 @@ +/* + * + * 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. + * + */ +define(["dojo/_base/xhr", + "dojo/dom", + "dojo/dom-construct", + "dojo/_base/window", + "dijit/registry", + "dojo/parser", + "dojo/_base/array", + "dojo/_base/event", + 'dojo/_base/json', + "dijit/form/NumberSpinner", // required by the form + /* dojox/ validate resources */ + "dojox/validate/us", "dojox/validate/web", + /* basic dijit classes */ + "dijit/Dialog", + "dijit/form/CheckBox", "dijit/form/Textarea", + "dijit/form/FilteringSelect", "dijit/form/TextBox", + "dijit/form/ValidationTextBox", "dijit/form/DateTextBox", + "dijit/form/TimeTextBox", "dijit/form/Button", + "dijit/form/RadioButton", "dijit/form/Form", + "dijit/form/DateTextBox", + /* basic dojox classes */ + "dojox/form/BusyButton", "dojox/form/CheckedMultiSelect", + "dojo/domReady!"], + function (xhr, dom, construct, win, registry, parser, array, event, json) { + + var addExchange = {}; + + var node = construct.create("div", null, win.body(), "last"); + + var convertToExchange = function convertToExchange(formValues) + { + var newExchange = {}; + newExchange.name = formValues.name; + for(var propName in formValues) + { + if(formValues.hasOwnProperty(propName)) + { + if(propName === "durable") + { + if (formValues.durable[0] && formValues.durable[0] == "durable") { + newExchange.durable = true; + } + } else { + if(formValues[ propName ] !== "") { + newExchange[ propName ] = formValues[propName]; + } + } + + } + } + + return newExchange; + }; + + + xhr.get({url: "addExchange.html", + sync: true, + load: function(data) { + var theForm; + node.innerHTML = data; + addExchange.dialogNode = dom.byId("addExchange"); + parser.instantiate([addExchange.dialogNode]); + + theForm = registry.byId("formAddExchange"); + array.forEach(theForm.getDescendants(), function(widget) + { + if(widget.name === "type") { + widget.on("change", function(isChecked) { + + var obj = registry.byId(widget.id + ":fields"); + if(obj) { + if(isChecked) { + obj.domNode.style.display = "block"; + obj.resize(); + } else { + obj.domNode.style.display = "none"; + obj.resize(); + } + } + }) + } + + }); + + theForm.on("submit", function(e) { + + event.stop(e); + if(theForm.validate()){ + + var newExchange = convertToExchange(theForm.getValues()); + var that = this; + + xhr.put({url: "rest/exchange/"+encodeURIComponent(addExchange.vhost) + + "/"+encodeURIComponent(newExchange.name), sync: true, handleAs: "json", + headers: { "Content-Type": "application/json"}, + putData: json.toJson(newExchange), + load: function(x) {that.success = true; }, + error: function(error) {that.success = false; that.failureReason = error;}}); + + if(this.success === true) + { + registry.byId("addExchange").hide(); + } + else + { + alert("Error:" + this.failureReason); + } + + return false; + + + }else{ + alert('Form contains invalid data. Please correct first'); + return false; + } + + }); + }}); + + addExchange.show = function(vhost) { + addExchange.vhost = vhost; + registry.byId("formAddExchange").reset(); + registry.byId("addExchange").show(); + }; + + return addExchange; + });
\ No newline at end of file diff --git a/qpid/java/broker-plugins/management/src/main/java/resources/js/qpid/management/addQueue.js b/qpid/java/broker-plugins/management/src/main/java/resources/js/qpid/management/addQueue.js new file mode 100644 index 0000000000..4a2dccde5f --- /dev/null +++ b/qpid/java/broker-plugins/management/src/main/java/resources/js/qpid/management/addQueue.js @@ -0,0 +1,158 @@ +/* + * + * 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. + * + */ +define(["dojo/_base/xhr", + "dojo/dom", + "dojo/dom-construct", + "dojo/_base/window", + "dijit/registry", + "dojo/parser", + "dojo/_base/array", + "dojo/_base/event", + 'dojo/_base/json', + "dijit/form/NumberSpinner", // required by the form + /* dojox/ validate resources */ + "dojox/validate/us", "dojox/validate/web", + /* basic dijit classes */ + "dijit/Dialog", + "dijit/form/CheckBox", "dijit/form/Textarea", + "dijit/form/FilteringSelect", "dijit/form/TextBox", + "dijit/form/ValidationTextBox", "dijit/form/DateTextBox", + "dijit/form/TimeTextBox", "dijit/form/Button", + "dijit/form/RadioButton", "dijit/form/Form", + "dijit/form/DateTextBox", + /* basic dojox classes */ + "dojox/form/BusyButton", "dojox/form/CheckedMultiSelect", + "dojo/domReady!"], + function (xhr, dom, construct, win, registry, parser, array, event, json) { + + var addQueue = {}; + + var node = construct.create("div", null, win.body(), "last"); + + var typeSpecificFields = { + numPriorities: "priority", + lvqKey: "lvq", + sortKey: "sorted" + }; + + + var convertToQueue = function convertToQueue(formValues) + { + var newQueue = {}; + newQueue.name = formValues.name; + for(var propName in formValues) + { + if(formValues.hasOwnProperty(propName)) + { + if(propName === "durable") + { + if (formValues.durable[0] && formValues.durable[0] == "durable") { + newQueue.durable = true; + } + } else if (!typeSpecificFields.hasOwnProperty(propName) || + formValues.type === typeSpecificFields[ propName ]) { + if(formValues[ propName ] !== "") { + newQueue[ propName ] = formValues[propName]; + } + } + + } + } + + return newQueue; + }; + + + xhr.get({url: "addQueue.html", + sync: true, + load: function(data) { + var theForm; + node.innerHTML = data; + addQueue.dialogNode = dom.byId("addQueue"); + parser.instantiate([addQueue.dialogNode]); + + // for children which have name type, add a function to make all the associated rows + // visible / invisible as the radio button is checked / unchecked + + theForm = registry.byId("formAddQueue"); + array.forEach(theForm.getDescendants(), function(widget) + { + if(widget.name === "type") { + widget.on("change", function(isChecked) { + + var obj = registry.byId(widget.id + ":fields"); + if(obj) { + if(isChecked) { + obj.domNode.style.display = "block"; + obj.resize(); + } else { + obj.domNode.style.display = "none"; + obj.resize(); + } + } + }) + } + + }); + + theForm.on("submit", function(e) { + + event.stop(e); + if(theForm.validate()){ + + var newQueue = convertToQueue(theForm.getValues()); + var that = this; + + xhr.put({url: "rest/queue/"+encodeURIComponent(addQueue.vhost) + +"/"+encodeURIComponent(newQueue.name), sync: true, handleAs: "json", + headers: { "Content-Type": "application/json"}, + putData: json.toJson(newQueue), + load: function(x) {that.success = true; }, + error: function(error) {that.success = false; that.failureReason = error;}}); + + if(this.success === true) + { + registry.byId("addQueue").hide(); + } + else + { + alert("Error:" + this.failureReason); + } + + return false; + + + }else{ + alert('Form contains invalid data. Please correct first'); + return false; + } + + }); + }}); + + addQueue.show = function(vhost) { + addQueue.vhost = vhost; + registry.byId("formAddQueue").reset(); + registry.byId("addQueue").show(); + }; + + return addQueue; + });
\ No newline at end of file diff --git a/qpid/java/broker-plugins/management/src/main/java/resources/js/qpid/management/authenticationprovider/PrincipalDatabaseAuthenticationManager.js b/qpid/java/broker-plugins/management/src/main/java/resources/js/qpid/management/authenticationprovider/PrincipalDatabaseAuthenticationManager.js new file mode 100644 index 0000000000..ffebc98af7 --- /dev/null +++ b/qpid/java/broker-plugins/management/src/main/java/resources/js/qpid/management/authenticationprovider/PrincipalDatabaseAuthenticationManager.js @@ -0,0 +1,327 @@ +/* + * + * 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. + * + */ +define(["dojo/_base/xhr", + "dojo/dom", + "dojo/parser", + "dojo/query", + "dojo/dom-construct", + "dojo/_base/connect", + "dojo/_base/window", + "dojo/_base/event", + "dojo/_base/json", + "dijit/registry", + "qpid/common/util", + "qpid/common/properties", + "qpid/common/updater", + "qpid/common/UpdatableStore", + "dojox/grid/EnhancedGrid", + "dojox/grid/enhanced/plugins/Pagination", + "dojox/grid/enhanced/plugins/IndirectSelection", + "dojox/validate/us", "dojox/validate/web", + "dijit/Dialog", + "dijit/form/TextBox", + "dijit/form/ValidationTextBox", + "dijit/form/TimeTextBox", "dijit/form/Button", + "dijit/form/Form", + "dijit/form/DateTextBox", + "dojo/domReady!"], + function (xhr, dom, parser, query, construct, connect, win, event, json, registry, util, properties, updater, UpdatableStore, EnhancedGrid) { + function DatabaseAuthManager(containerNode, authProviderObj, controller) { + var node = construct.create("div", null, containerNode, "last"); + var that = this; + this.name = authProviderObj.name; + xhr.get({url: "authenticationprovider/showPrincipalDatabaseAuthenticationManager.html", + sync: true, + load: function(data) { + node.innerHTML = data; + parser.parse(node); + + + that.authDatabaseUpdater= new AuthProviderUpdater(node, authProviderObj, controller); + + updater.add( that.authDatabaseUpdater); + + that.authDatabaseUpdater.update(); + + + }}); + } + + DatabaseAuthManager.prototype.update = function() { + this.authDatabaseUpdater.update(); + }; + + DatabaseAuthManager.prototype.close = function() { + updater.remove( this.authDatabaseUpdater ); + }; + + function AuthProviderUpdater(node, authProviderObj, controller) + { + this.controller = controller; + this.query = "rest/authenticationprovider/"+encodeURIComponent(authProviderObj.name); + this.name = authProviderObj.name; + var that = this; + + xhr.get({url: this.query, sync: properties.useSyncGet, handleAs: "json"}) + .then(function(data) { + that.authProviderData = data[0]; + + util.flattenStatistics( that.authProviderData ); + + var userDiv = query(".users")[0]; + + var gridProperties = { + height: 400, + keepSelection: true, + plugins: { + pagination: { + pageSizes: ["10", "25", "50", "100"], + description: true, + sizeSwitch: true, + pageStepper: true, + gotoButton: true, + maxPageStep: 4, + position: "bottom" + }, + indirectSelection: true + + }}; + + + that.usersGrid = + new UpdatableStore(that.authProviderData.users, userDiv, + [ { name: "User Name", field: "name", width: "100%" } + ], function(obj) { + connect.connect(obj.grid, "onRowDblClick", obj.grid, + function(evt){ + var idx = evt.rowIndex, + theItem = this.getItem(idx); + var name = obj.dataStore.getValue(theItem,"name"); + var id = obj.dataStore.getValue(theItem,"id"); + setPassword.show(authProviderObj.name, {name: name, id: id}); + }); + }, gridProperties, EnhancedGrid); + + + var addUserButton = query(".addUserButton", node)[0]; + connect.connect(registry.byNode(addUserButton), "onClick", function(evt){ addUser.show(authProviderObj.name) }); + + var deleteMessagesButton = query(".deleteUserButton", node)[0]; + var deleteWidget = registry.byNode(deleteMessagesButton); + connect.connect(deleteWidget, "onClick", + function(evt){ + event.stop(evt); + that.deleteUsers(); + }); + }); + } + + AuthProviderUpdater.prototype.deleteUsers = function() + { + var grid = this.usersGrid.grid; + var data = grid.selection.getSelected(); + if(data.length) { + var that = this; + if(confirm("Delete " + data.length + " users?")) { + var i, queryParam; + for(i = 0; i<data.length; i++) { + if(queryParam) { + queryParam += "&"; + } else { + queryParam = "?"; + } + + queryParam += "id=" + data[i].id; + } + var query = "rest/user/"+ encodeURIComponent(that.name) + + queryParam; + that.success = true + xhr.del({url: query, sync: true, handleAs: "json"}).then( + function(data) { + grid.setQuery({id: "*"}); + grid.selection.deselectAll(); + that.update(); + }, + function(error) {that.success = false; that.failureReason = error;}); + if(!that.success ) { + alert("Error:" + this.failureReason); + } + } +} + }; + + AuthProviderUpdater.prototype.update = function() + { + + var that = this; + + xhr.get({url: this.query, sync: properties.useSyncGet, handleAs: "json"}) + .then(function(data) { + that.authProviderData = data[0]; + util.flattenStatistics( that.authProviderData ); + + that.usersGrid.update(that.authProviderData.users); + + }); + + + }; + + var addUser = {}; + + var node = construct.create("div", null, win.body(), "last"); + + var convertToUser = function convertToUser(formValues) { + var newUser = {}; + newUser.name = formValues.name; + for(var propName in formValues) + { + if(formValues.hasOwnProperty(propName)) { + if(formValues[ propName ] !== "") { + newUser[ propName ] = formValues[propName]; + } + } + } + + return newUser; + }; + + + xhr.get({url: "authenticationprovider/addUser.html", + sync: true, + load: function(data) { + var theForm; + node.innerHTML = data; + addUser.dialogNode = dom.byId("addUser"); + parser.instantiate([addUser.dialogNode]); + + var that = this; + + theForm = registry.byId("formAddUser"); + theForm.on("submit", function(e) { + + event.stop(e); + if(theForm.validate()){ + + var newUser = convertToUser(theForm.getValues()); + + + var url = "rest/user/"+encodeURIComponent(addUser.authProvider) + + "/"+encodeURIComponent(newUser.name); + + xhr.put({url: url, sync: true, handleAs: "json", + headers: { "Content-Type": "application/json"}, + putData: json.toJson(newUser), + load: function(x) {that.success = true; }, + error: function(error) {that.success = false; that.failureReason = error;}}); + + if(this.success === true) { + registry.byId("addUser").hide(); + } else { + alert("Error:" + this.failureReason); + } + + return false; + + + }else{ + alert('Form contains invalid data. Please correct first'); + return false; + } + + }); + }}); + + addUser.show = function(authProvider) { + addUser.authProvider = authProvider; + registry.byId("formAddUser").reset(); + registry.byId("addUser").show(); + }; + + + var setPassword = {}; + + var setPasswordNode = construct.create("div", null, win.body(), "last"); + + xhr.get({url: "authenticationprovider/setPassword.html", + sync: true, + load: function(data) { + var theForm; + setPasswordNode.innerHTML = data; + setPassword.dialogNode = dom.byId("setPassword"); + parser.instantiate([setPassword.dialogNode]); + + var that = this; + + theForm = registry.byId("formSetPassword"); + theForm.on("submit", function(e) { + + event.stop(e); + if(theForm.validate()){ + + var newUser = convertToUser(theForm.getValues()); + newUser.name = setPassword.name; + newUser.id = setPassword.id; + + var url = "rest/user/"+encodeURIComponent(setPassword.authProvider) + + "/"+encodeURIComponent(newUser.name); + + xhr.put({url: url, sync: true, handleAs: "json", + headers: { "Content-Type": "application/json"}, + putData: json.toJson(newUser), + load: function(x) {that.success = true; }, + error: function(error) {that.success = false; that.failureReason = error;}}); + + if(that.success === true) { + registry.byId("setPassword").hide(); + } else { + alert("Error:" + that.failureReason); + } + + return false; + + + }else{ + alert('Form contains invalid data. Please correct first'); + return false; + } + + }); + }}); + + setPassword.show = function(authProvider, user) { + setPassword.authProvider = authProvider; + setPassword.name = user.name; + setPassword.id = user.id; + registry.byId("formSetPassword").reset(); + + var namebox = registry.byId("formSetPassword.name"); + namebox.set("value", user.name); + namebox.set("disabled", true); + + registry.byId("setPassword").show(); + + }; + + + + return DatabaseAuthManager; + }); diff --git a/qpid/java/broker-plugins/management/src/main/java/resources/js/qpid/management/controller.js b/qpid/java/broker-plugins/management/src/main/java/resources/js/qpid/management/controller.js new file mode 100644 index 0000000000..1aa05a5a3c --- /dev/null +++ b/qpid/java/broker-plugins/management/src/main/java/resources/js/qpid/management/controller.js @@ -0,0 +1,104 @@ +/* + * + * 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. + * + */ +define(["dojo/dom", + "dijit/registry", + "dijit/layout/ContentPane", + "qpid/management/Broker", + "qpid/management/VirtualHost", + "qpid/management/Exchange", + "qpid/management/Queue", + "qpid/management/Connection", + "qpid/management/AuthenticationProvider", + "dojo/ready", + "dojo/domReady!"], + function (dom, registry, ContentPane, Broker, VirtualHost, Exchange, Queue, Connection, AuthProvider, ready) { + var controller = {}; + + var constructors = { broker: Broker, virtualhost: VirtualHost, exchange: Exchange, + queue: Queue, connection: Connection, authenticationprovider: AuthProvider }; + + var tabDiv = dom.byId("managedViews"); + + ready(function() { + controller.tabContainer = registry.byId("managedViews"); + }); + + + controller.viewedObjects = {}; + + controller.show = function(objType, name, parent) { + + function generateName(obj) + { + if(obj) { + var name = ""; + if(obj.parent) + { + for(var prop in obj.parent) { + if(obj.parent.hasOwnProperty(prop)) { + name = name + generateName( obj.parent[ prop ]); + } + } + + } + return name + parent.type +":" + parent.name + "/" + } + } + + var that = this; + var objId = generateName(parent) + objType+":"+name; + if( this.viewedObjects[ objId ] ) { + this.tabContainer.selectChild(this.viewedObjects[ objId ].contentPane); + } else { + var Constructor = constructors[ objType ]; + if(Constructor) { + var obj = new Constructor(name, parent, this); + this.viewedObjects[ objId ] = obj; + + var contentPane = new ContentPane({ region: "center" , + title: obj.getTitle(), + closable: true, + onClose: function() { + obj.close(); + delete that.viewedObjects[ objId ]; + return true; + } + }); + this.tabContainer.addChild( contentPane ); + obj.open(contentPane); + contentPane.startup(); + if(obj.startup) { + obj.startup(); + } + this.tabContainer.selectChild( contentPane ); + } + + } + + }; + + ready(function() { + controller.show("broker",""); + }); + + + return controller; + });
\ No newline at end of file diff --git a/qpid/java/broker-plugins/management/src/main/java/resources/js/qpid/management/moveCopyMessages.js b/qpid/java/broker-plugins/management/src/main/java/resources/js/qpid/management/moveCopyMessages.js new file mode 100644 index 0000000000..8cc488324f --- /dev/null +++ b/qpid/java/broker-plugins/management/src/main/java/resources/js/qpid/management/moveCopyMessages.js @@ -0,0 +1,137 @@ +/* + * 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. + */ + +define(["dojo/_base/xhr", + "dojo/dom", + "dojo/dom-construct", + "dojo/_base/window", + "dijit/registry", + "dojo/parser", + "dojo/_base/array", + "dojo/_base/event", + 'dojo/_base/json', + "dojo/store/Memory", + "dijit/form/FilteringSelect", + "dojo/query", + "dojo/_base/connect", + "dojo/domReady!"], + function (xhr, dom, construct, win, registry, parser, array, event, json, Memory, FilteringSelect, query, connect) { + + var moveMessages = {}; + + var node = construct.create("div", null, win.body(), "last"); + + xhr.get({url: "moveCopyMessages.html", + sync: true, + load: function(data) { + var theForm; + node.innerHTML = data; + moveMessages.dialogNode = dom.byId("moveMessages"); + parser.instantiate([moveMessages.dialogNode]); + + theForm = registry.byId("formMoveMessages"); + + + var cancelButton = query(".moveMessageCancel")[0]; + connect.connect(registry.byNode(cancelButton), "onClick", + function(evt){ + event.stop(evt); + registry.byId("moveMessages").hide(); + }); + + + theForm.on("submit", function(e) { + + event.stop(e); + if(theForm.validate()){ + + moveMessages.data.destinationQueue = theForm.getValues()["queue"]; + var that = this; + + xhr.post({url: "rest/message/"+encodeURIComponent(moveMessages.vhost) + +"/"+encodeURIComponent(moveMessages.queue), + sync: true, handleAs: "json", + headers: { "Content-Type": "application/json"}, + postData: json.toJson(moveMessages.data), + load: function(x) {that.success = true; }, + error: function(error) {that.success = false; that.failureReason = error;}}); + + if(this.success === true) { + registry.byId("moveMessages").hide(); + if(moveMessages.next) { + moveMessages.next(); + } + } else { + alert("Error:" + this.failureReason); + } + + return false; + + + }else{ + alert('Form contains invalid data. Please correct first'); + return false; + } + + }); + + }}); + + moveMessages.show = function(obj, next) { + var that = this; + + moveMessages.vhost = obj.virtualhost; + moveMessages.queue = obj.queue; + moveMessages.data = obj.data; + moveMessages.next = next; + registry.byId("formMoveMessages").reset(); + + + + xhr.get({url: "rest/queue/" + encodeURIComponent(obj.virtualhost) + "?depth=0", + handleAs: "json"}).then( + function(data) { + var queues = []; + for(var i=0; i < data.length; i++) { + queues[i] = {id: data[i].name, name: data[i].name}; + } + var queueStore = new Memory({ data: queues }); + + + if(that.queueChooser) { + that.queueChooser.destroy( false ); + } + var queueDiv = dom.byId("moveMessages.selectQueueDiv"); + var input = construct.create("input", {id: "moveMessagesSelectQueue"}, queueDiv); + + that.queueChooser = new FilteringSelect({ id: "moveMessagesSelectQueue", + name: "queue", + store: queueStore, + searchAttr: "name"}, input); + + + + registry.byId("moveMessages").show(); + + + }); + + + }; + + return moveMessages; + }); diff --git a/qpid/java/broker-plugins/management/src/main/java/resources/js/qpid/management/showMessage.js b/qpid/java/broker-plugins/management/src/main/java/resources/js/qpid/management/showMessage.js new file mode 100644 index 0000000000..b1ccc0ca07 --- /dev/null +++ b/qpid/java/broker-plugins/management/src/main/java/resources/js/qpid/management/showMessage.js @@ -0,0 +1,142 @@ +/* + * 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. + */ + +define(["dojo/_base/xhr", + "dojo/dom", + "dojo/dom-construct", + "dojo/dom-class", + "dojo/_base/window", + "dijit/registry", + "dojo/parser", + "dojo/_base/array", + "dojo/_base/event", + 'dojo/_base/json', + "dojo/query", + "dojo/_base/connect", + "qpid/common/properties", + "dojox/html/entities", + "dojo/domReady!"], + function (xhr, dom, construct, domClass, win, registry, parser, array, event, json, query, connect, properties, entities) { + + + function encode(val){ + return typeof val === 'string' ? entities.encode(val) : val; + } + + var showMessage = {}; + + showMessage.hide = function () { + if(this.populatedFields) { + for(var i = 0 ; i < this.populatedFields.length; i++) { + this.populatedFields[i].innerHTML = ""; + } + this.populatedFields = []; + } + registry.byId("showMessage").hide(); + }; + + showMessage.loadViewMessage = function(data) { + var that = this; + node.innerHTML = data; + showMessage.dialogNode = dom.byId("showMessage"); + parser.instantiate([showMessage.dialogNode]); + + var closeButton = query(".closeViewMessage")[0]; + connect.connect(closeButton, "onclick", + function (evt) { + event.stop(evt); + showMessage.hide(); + }); + }; + + showMessage.populateShowMessage = function(data) { + + this.populatedFields = []; + + for(var attrName in data) { + if(data.hasOwnProperty(attrName)) { + var fields = query(".message-"+attrName, this.dialogNode); + if(fields && fields.length != 0) { + var field = fields[0]; + this.populatedFields.push(field); + var val = data[attrName]; + if(val) { + if(domClass.contains(field,"map")) { + var tableStr = "<table style='border: 1pt'><tr><th style='width: 6em; font-weight: bold'>Header</th><th style='font-weight: bold'>Value</th></tr>"; + for(var name in val) { + if(val.hasOwnProperty(name)) { + + tableStr += "<tr><td>"+encode(name)+"</td>"; + tableStr += "<td>"+encode(val[ name ])+"</td></tr>"; + } + field.innerHTML = tableStr; + } + tableStr += "</table>"; + } else if(domClass.contains(field,"datetime")) { + var d = new Date(0); + d.setUTCSeconds(val/1000); + field.innerHTML = d.toLocaleString(); + } else { + field.innerHTML = encode(val); + } + } + } + } + } + var contentField = query(".message-content", this.dialogNode)[0]; + + if(data.mimeType && data.mimeType.match(/text\/.*/)) { + xhr.get({url: "rest/message-content/" + encodeURIComponent(showMessage.virtualhost) + + "/" + encodeURIComponent(showMessage.queue) + + "/" + encodeURIComponent(showMessage.messageNumber), + sync: true + + }).then(function(obj) { contentField.innerHTML = encode(obj) }); + } else { + contentField.innerHTML = "<a href=\"" + "rest/message-content/" + encodeURIComponent(showMessage.virtualhost) + + "/" + encodeURIComponent(showMessage.queue) + + "/" + encodeURIComponent(showMessage.messageNumber) + + "\" target=\"_blank\">Download</a>"; + } + this.populatedFields.push(contentField); + + registry.byId("showMessage").show(); + }; + + showMessage.show = function(obj) { + showMessage.virtualhost = obj.virtualhost; + showMessage.queue = obj.queue; + showMessage.messageNumber = obj.messageNumber; + + xhr.get({url: "rest/message/" + encodeURIComponent(obj.virtualhost) + + "/" + encodeURIComponent(obj.queue) + + "/" + encodeURIComponent(obj.messageNumber), + sync: properties.useSyncGet, + handleAs: "json", + load: this.populateShowMessage + }); + }; + + var node = construct.create("div", null, win.body(), "last"); + + xhr.get({url: "showMessage.html", + sync: true, + load: showMessage.loadViewMessage + }); + + return showMessage; + }); diff --git a/qpid/java/broker-plugins/management/src/main/java/resources/js/qpid/management/treeView.js b/qpid/java/broker-plugins/management/src/main/java/resources/js/qpid/management/treeView.js new file mode 100644 index 0000000000..b1d4abf8c1 --- /dev/null +++ b/qpid/java/broker-plugins/management/src/main/java/resources/js/qpid/management/treeView.js @@ -0,0 +1,313 @@ +/* + * + * 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. + * + */ +define(["dojo/_base/xhr", + "dojo/query", + "dojo/io-query", + "dijit/Tree", + "qpid/common/util", + "qpid/common/updater", + "qpid/management/controller", + "dojo/domReady!"], + function (xhr, query, ioQuery, Tree, util, updater, controller) { + + function TreeViewModel(queryString) { + this.query = queryString; + + this.onChildrenChange = function (parent, children) { + // fired when the set of children for an object change + }; + + this.onChange = function (object) { + // fired when the properties of an object change + }; + + this.onDelete = function (object) { + // fired when an object is deleted + }; + + } + + + TreeViewModel.prototype.buildModel = function (data) { + this.model = data; + + }; + + TreeViewModel.prototype.updateModel = function (data) { + var that = this; + + function checkForChanges(oldData, data) { + var propName; + if (oldData.name != data.name) { + that.onChange(data); + } + + var childChanges = false; + // Iterate over old childTypes, check all are in new + for (propName in oldData) { + if (oldData.hasOwnProperty(propName)) { + var oldChildren = oldData[ propName ]; + if (util.isArray(oldChildren)) { + + var newChildren = data[ propName ]; + + if (!(newChildren && util.isArray(newChildren))) { + childChanges = true; + } else { + var subChanges = false; + // iterate over elements in array, make sure in both, in which case recurse + for (var i = 0; i < oldChildren.length; i++) { + var matched = false; + for (var j = 0; j < newChildren.length; j++) { + if (oldChildren[i].id == newChildren[j].id) { + checkForChanges(oldChildren[i], newChildren[j]); + matched = true; + break; + } + } + if (!matched) { + subChanges = true; + } + } + if (subChanges == true || oldChildren.length != newChildren.length) { + that.onChildrenChange({ id:data.id + propName, _dummyChild:propName, data:data }, + newChildren); + } + } + } + } + } + + for (propName in data) { + if (data.hasOwnProperty(propName)) { + var prop = data[ propName ]; + if (util.isArray(prop)) { + if (!(oldData[ propName ] && util.isArray(oldData[propName]))) { + childChanges = true; + } + } + } + } + + if (childChanges) { + var children = []; + that.getChildren(data, function (theChildren) { + children = theChildren + }); + that.onChildrenChange(data, children); + } + } + + var oldData = this.model; + this.model = data; + + checkForChanges(oldData, data); + }; + + + TreeViewModel.prototype.fetchItemByIdentity = function (id) { + + function fetchItem(id, data) { + var propName; + + if (data.id == id) { + return data; + } else if (id.indexOf(data.id) == 0) { + return { id:id, _dummyChild:id.substring(id.length), data:data }; + } else { + for (propName in data) { + if (data.hasOwnProperty(propName)) { + var prop = data[ propName ]; + if (util.isArray(prop)) { + for (var i = 0; i < prop.length; i++) { + var theItem = fetchItem(id, prop[i]); + if (theItem) { + return theItem; + } + } + } + } + } + return null; + } + } + + return fetchItem(id, this.model); + }; + + TreeViewModel.prototype.getChildren = function (parentItem, onComplete) { + + if (parentItem) { + if (parentItem._dummyChild) { + onComplete(parentItem.data[ parentItem._dummyChild ]); + } else { + var children = []; + for (var propName in parentItem) { + if (parentItem.hasOwnProperty(propName)) { + var prop = parentItem[ propName ]; + + if (util.isArray(prop)) { + children.push({ id:parentItem.id + + propName, _dummyChild:propName, data:parentItem }); + } + } + } + onComplete(children); + } + } else { + onComplete([]); + } + }; + + TreeViewModel.prototype.getIdentity = function (theItem) { + if (theItem) { + return theItem.id; + } + + }; + + TreeViewModel.prototype.getLabel = function (theItem) { + if (theItem) { + if (theItem._dummyChild) { + return theItem._dummyChild; + } else { + return theItem.name; + } + } else { + return ""; + } + }; + + TreeViewModel.prototype.getRoot = function (onItem) { + onItem(this.model); + }; + + TreeViewModel.prototype.mayHaveChildren = function (theItem) { + if (theItem) { + if (theItem._dummyChild) { + return true; + } else { + for (var propName in theItem) { + if (theItem.hasOwnProperty(propName)) { + var prop = theItem[ propName ]; + if (util.isArray(prop)) { + return true; + } + } + } + return false; + } + } else { + return false; + } + }; + + TreeViewModel.prototype.relocate = function (theItem) { + + function findItemDetails(theItem, details, type, object) { + if (theItem.id == object.id) { + details.type = type; + details[ type ] = object.name; + } else { + details[ type ] = object.name; + + // iterate over children + for (var propName in object) { + if (object.hasOwnProperty(propName)) { + var prop = object[ propName ]; + if (util.isArray(prop)) { + for (var i = 0; i < prop.length; i++) { + findItemDetails(theItem, details, propName.substring(0, propName.length - 1), + prop[i]); + + if (details.type) { + break; + } + } + } + if (details.type) { + break; + } + } + } + + if (!details.type) { + details[ type ] = null; + } + } + } + + var details = new Object(); + + findItemDetails(theItem, details, "broker", this.model); + + if (details.type == "broker") { + controller.show("broker", ""); + } else if (details.type == "virtualhost") { + controller.show("virtualhost", details.virtualhost, {type:"broker", name:""}); + } else if (details.type == "exchange") { + controller.show("exchange", details.exchange, { type: "virtualhost", name: details.virtualhost, parent: {broker: {type:"broker", name:""}}}); + } else if (details.type == "queue") { + controller.show("queue", details.queue, { type: "virtualhost", name: details.virtualhost, parent: {broker: {type:"broker", name:""}}}); + } else if (details.type == "connection") { + controller.show("connection", details.connection, { type: "virtualhost", name: details.virtualhost, parent: {broker: {type:"broker", name:""}}}); + } else if (details.type == 'port') { + controller.show("port", details.port, { type: "virtualhost", name: details.virtualhost, parent: {broker: {type:"broker", name:""}}}); + } else if (details.type == 'authenticationprovider') { + controller.show("authenticationprovider", details.authenticationprovider, {broker: {type:"broker", name:""}}); + } + + + + }; + + TreeViewModel.prototype.update = function () { + var thisObj = this; + + xhr.get({url:this.query, sync: true, handleAs:"json"}) + .then(function (data) { + if (thisObj.model) { + thisObj.updateModel(data); + } + else { + thisObj.buildModel(data); + } + }); + + }; + + query('div[qpid-type="treeView"]').forEach(function(node, index, arr) { + var treeModel = new TreeViewModel("rest/structure"); + treeModel.update(); + var tree = new Tree({ model: treeModel }, node); + tree.on("dblclick", + function (object) { + if (object && !object._dummyChild) { + treeModel.relocate(object); + } + + }, true); + tree.startup(); + updater.add( treeModel ); + }); + + return TreeViewModel; + });
\ No newline at end of file diff --git a/qpid/java/broker-plugins/management/src/main/java/resources/management.html b/qpid/java/broker-plugins/management/src/main/java/resources/management.html new file mode 100644 index 0000000000..a8345a8503 --- /dev/null +++ b/qpid/java/broker-plugins/management/src/main/java/resources/management.html @@ -0,0 +1,92 @@ +<!DOCTYPE HTML> +<!-- + ~ 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. + --> +<html lang="en"> +<head> + <meta charset="utf-8"> + <title>Qpid Management</title> + <link rel="stylesheet" href="dojo/dojo/resources/dojo.css"> + <link rel="stylesheet" href="dojo/dijit/themes/claro/claro.css"> + <link rel="stylesheet" href="dojo/dojox/grid/resources/claroGrid.css"> + <link rel="stylesheet" href="dojo/dojox/grid/enhanced/resources/claro/EnhancedGrid.css"> + <link rel="stylesheet" href="dojo/dojox/grid/enhanced/resources/EnhancedGrid_rtl.css"> + <link rel="stylesheet" href="css/common.css" media="screen"> + <script> + function getContextPath() + { + var contextPath = "/"; + var documentURL = document.URL; + var managementPageStart = documentURL.lastIndexOf("/"); + var firstSlashPos = documentURL.indexOf("/", documentURL.indexOf("//") + 2); + if (managementPageStart > firstSlashPos) + { + contextPath = documentURL.substring(firstSlashPos, managementPageStart); + } + return contextPath; + } + + var dojoConfig = { + tlmSiblingOfDojo:false, + parseOnLoad:true, + async:true, + baseUrl: getContextPath(), + packages:[ + { name:"dojo", location:"dojo/dojo" }, + { name:"dijit", location:"dojo/dijit" }, + { name:"dojox", location:"dojo/dojox" }, + { name:"qpid", location:"js/qpid" } + ] + }; + + </script> + <script src="dojo/dojo/dojo.js"> + </script> + + <script> + require(["dijit/layout/BorderContainer", + "dijit/layout/TabContainer", + "dijit/layout/ContentPane", + "dijit/TitlePane", + "dojo/parser", + "qpid/management/treeView", + "qpid/management/controller", + "qpid/common/footer", + "qpid/authorization/sasl"]); + </script> + +</head> +<body class="claro"> + +<div id="pageLayout" data-dojo-type="dijit.layout.BorderContainer" data-dojo-props="design: 'headline', gutters: false"> + <div data-dojo-type="dijit.layout.ContentPane" data-dojo-props="region:'top'"> + <div id="header" class="header"></div> + </div> + <div data-dojo-type="dijit.layout.ContentPane" data-dojo-props="region:'top'"> + <div id="login"></div> + </div> + <div data-dojo-type="dijit.layout.ContentPane" data-dojo-props="region:'leading', splitter: true"> + <div qpid-type="treeView" qpid-props="query: 'rest/structure'" ></div> + </div> + <div id="managedViews" data-dojo-type="dijit.layout.TabContainer" data-dojo-props="region:'center', tabPosition: 'top'"> + </div> + <div data-dojo-type="dijit.layout.ContentPane" data-dojo-props="region:'bottom'"> + <div qpid-type="footer"></div> + </div> +</div> + +</body> +</html>
\ No newline at end of file diff --git a/qpid/java/broker-plugins/management/src/main/java/resources/moveCopyMessages.html b/qpid/java/broker-plugins/management/src/main/java/resources/moveCopyMessages.html new file mode 100644 index 0000000000..f188c3001c --- /dev/null +++ b/qpid/java/broker-plugins/management/src/main/java/resources/moveCopyMessages.html @@ -0,0 +1,36 @@ +<!-- + ~ 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. + --> + +<div class="dijitHidden"> + <div data-dojo-type="dijit.Dialog" style="width:600px;" data-dojo-props="title:'Move/Copy Messages'" id="moveMessages"> + <form id="formMoveMessages" method="post" dojoType="dijit.form.Form"> + <table cellpadding="0" cellspacing="2"> + <tr> + <td valign="top"><strong>Queue: </strong></td> + <td><div id="moveMessages.selectQueueDiv"></div></td> + </tr> + </table> + <br/> + + <!-- submit buttons --> + + <input type="button" value="Cancel" label="Cancel" dojoType="dijit.form.Button" class="moveMessageCancel"/> + <input type="submit" value="Move Messages" label="Move Messages" dojoType="dijit.form.Button" /> + + </form> + </div> +</div> diff --git a/qpid/java/broker-plugins/management/src/main/java/resources/showAuthProvider.html b/qpid/java/broker-plugins/management/src/main/java/resources/showAuthProvider.html new file mode 100644 index 0000000000..c5d4e48a75 --- /dev/null +++ b/qpid/java/broker-plugins/management/src/main/java/resources/showAuthProvider.html @@ -0,0 +1,25 @@ +<!-- + - + - 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. + - + --> +<div class="authorizationProvider"> + <span style="">Name:</span><span class="name" style="position:absolute; left:6em"></span> + <br/> + <span style="">Type:</span><span class="type" style="position:absolute; left:6em"></span> +</div>
\ No newline at end of file diff --git a/qpid/java/broker-plugins/management/src/main/java/resources/showBroker.html b/qpid/java/broker-plugins/management/src/main/java/resources/showBroker.html new file mode 100644 index 0000000000..cb2f4a4b9a --- /dev/null +++ b/qpid/java/broker-plugins/management/src/main/java/resources/showBroker.html @@ -0,0 +1,25 @@ +<div class="broker"> + <span>Broker:</span><span class="broker-name" style="position:absolute; left:6em"></span> + <br/> +<!-- <span>State:</span><span class="broker-state" style="position:absolute; left:6em"></span> + <br/> + <span>Durable:</span><span class="broker-durable" style="position:absolute; left:6em"></span> + <br/> + <span>Lifespan:</span><span class="broker-lifetimePolicy" style="position:absolute; left:6em" ></span> + <br/> --> + <br/> + <div data-dojo-type="dijit.TitlePane" data-dojo-props="title: 'Virtual Hosts'"> + <div class="broker-virtualhosts"></div> + </div> + <br/> + <div data-dojo-type="dijit.TitlePane" data-dojo-props="title: 'Ports'"> + <div class="broker-ports"></div> + </div> + <br/> + + <div data-dojo-type="dijit.TitlePane" data-dojo-props="title: 'Log File', open: false"> + <div class="broker-logfile"></div> + </div> + <br/> +</div> + diff --git a/qpid/java/broker-plugins/management/src/main/java/resources/showConnection.html b/qpid/java/broker-plugins/management/src/main/java/resources/showConnection.html new file mode 100644 index 0000000000..84854daf47 --- /dev/null +++ b/qpid/java/broker-plugins/management/src/main/java/resources/showConnection.html @@ -0,0 +1,47 @@ +<!-- + - + - 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. + - + --> +<div class="connection"> + <span style="">Name:</span><span class="name" style="position:absolute; left:6em"></span> + <br/> + <span style="">State:</span><span class="state" style="position:absolute; left:6em"></span> + <span style="position:absolute; left:26em">Pre-fetched:</span> + <br/> + <span style="">Durable:</span><span class="durable" style="position:absolute; left:6em"></span> + <span style="position:absolute; left:26em">Inbound:</span> + <span class="msgInRate" style="position:absolute; right:9.5em"></span> + <span style="position:absolute; right: 5em; width: 4em"> msg/s</span> + <span class="bytesInRate" style="position:absolute; right: 3.3em"></span> + <span class="bytesInRateUnits" style="position:absolute; right: 0em; width: 3em"></span> + <br/> + <span style="">Lifespan:</span><span style="position:absolute; left:6em" class="lifetimePolicy"></span> + <span style="position:absolute; left:26em">Outbound:</span> + <span class="msgOutRate" style="position:absolute; right:9.5em"></span> + <span style="position:absolute; right: 5em; width: 4em"> msg/s</span> + <span class="bytesOutRate" style="position:absolute; right: 3.3em"></span> + <span class="bytesOutRateUnits" style="position:absolute; right: 0em; width: 3em"></span> + <br/> + <br/> + <div data-dojo-type="dijit.TitlePane" data-dojo-props="title: 'Sessions'"> + <div class="sessions"></div> + </div> + <br/> + +</div> diff --git a/qpid/java/broker-plugins/management/src/main/java/resources/showExchange.html b/qpid/java/broker-plugins/management/src/main/java/resources/showExchange.html new file mode 100644 index 0000000000..64f351d218 --- /dev/null +++ b/qpid/java/broker-plugins/management/src/main/java/resources/showExchange.html @@ -0,0 +1,46 @@ +<!-- + - + - 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. + - + --> +<div class="exchange"> + <span style="">Exchange:</span><span class="name" style="position:absolute; left:6em"></span> + <br/> + <span style="">State:</span><span class="state" style="position:absolute; left:6em"></span> + <br/> + <span style="">Durable:</span><span class="durable" style="position:absolute; left:6em"></span> + <span style="position:absolute; left:26em">Inbound:</span> + <span class="msgInRate" style="position:absolute; right:9.5em"></span> + <span style="position:absolute; right: 5em; width: 4em"> msg/s</span> + <span class="bytesInRate" style="position:absolute; right: 3.3em"></span> + <span class="bytesInRateUnits" style="position:absolute; right: 0em; width: 3em"></span> + <br/> + <span style="">Lifespan:</span><span style="position:absolute; left:6em" class="lifetimePolicy"></span> + <span style="position:absolute; left:26em">Dropped:</span> + <span class="msgDropRate" style="position:absolute; right:9.5em"></span> + <span style="position:absolute; right: 5em; width: 4em"> msg/s</span> + <span class="bytesDropRate" style="position:absolute; right: 3.3em"></span> + <span class="bytesDropRateUnits" style="position:absolute; right: 0em; width: 3em"></span> + <br/> + <br/> + <div data-dojo-type="dijit.TitlePane" data-dojo-props="title: 'Bindings'"> + <div class="bindings"></div> + <button data-dojo-type="dijit.form.Button" class="addBindingButton">Add Binding</button> + </div> + <br/> +</div> diff --git a/qpid/java/broker-plugins/management/src/main/java/resources/showMessage.html b/qpid/java/broker-plugins/management/src/main/java/resources/showMessage.html new file mode 100644 index 0000000000..0dea508c60 --- /dev/null +++ b/qpid/java/broker-plugins/management/src/main/java/resources/showMessage.html @@ -0,0 +1,73 @@ +<!-- + ~ 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. + --> + +<div class="dijitHidden"> + <div data-dojo-type="dijit.Dialog" style="width:600px;" data-dojo-props="title:'View Message'" id="showMessage"> + + <table style="border: 0;"> + <tr style="margin-bottom: 4pt"> + <td style="width: 10em; vertical-align: top"><span style="font-weight: bold;">Message Number:</span></td> + <td><span class="message-id"></span></td> + </tr> + <tr style="margin-bottom: 4pt"> + <td style="width: 10em; vertical-align: top"><span style="font-weight: bold;">Message Id:</span></td> + <td><span class="message-messageId"></span></td> + </tr> + <tr style="margin-bottom: 4pt"> + <td style="width: 10em; vertical-align: top"><span style="font-weight: bold;">State:</span></td> + <td><span class="message-state"></span></td> + </tr> + <tr style="margin-bottom: 4pt"> + <td style="width: 10em; vertical-align: top"><span style="font-weight: bold;">Persistent:</span></td> + <td><span class="message-persistent boolean"></span></td> + </tr> + <tr style="margin-bottom: 4pt"> + <td style="width: 10em; vertical-align: top"><span style="font-weight: bold;">Priority:</span></td> + <td><span class="message-priority"></span></td> + </tr> + <tr style="margin-bottom: 4pt"> + <td style="width: 10em; vertical-align: top"><span style="font-weight: bold;">Arrival Time:</span> + </td><td><span class="message-arrivalTime datetime"></span></td> + </tr> + <tr style="margin-bottom: 4pt"> + <td style="width: 10em; vertical-align: top"><span style="font-weight: bold;">Expiration:</span></td> + <td><span class="message-expiration datetime"></span></td> + </tr> + <tr style="margin-bottom: 4pt"> + <td style="width: 10em; vertical-align: top"><span style="font-weight: bold;">MIME Type:</span></td> + <td><span class="message-mimeType"></span></td> + </tr> + <tr style="margin-bottom: 4pt"> + <td style="width: 10em; vertical-align: top"><span style="font-weight: bold;">User:</span></td> + <td><span class="message-userId"></span></td> + </tr> + <tr style="margin-bottom: 4pt"> + <td style="width: 10em; vertical-align: top"><span style="font-weight: bold;">Headers:</span></td> + <td><div class="message-headers map"></div></td> + </tr> + + <tr style="margin-bottom: 4pt"> + <td style="width: 10em; vertical-align: top"><span style="font-weight: bold;">Content:</span></td> + <td><div class="message-content"></div></td> + </tr> + </table> + <br/> + <input type="button" value="Close" label="Close" dojoType="dijit.form.Button" class="closeViewMessage"/> + + </div> +</div> + diff --git a/qpid/java/broker-plugins/management/src/main/java/resources/showQueue.html b/qpid/java/broker-plugins/management/src/main/java/resources/showQueue.html new file mode 100644 index 0000000000..c87a462760 --- /dev/null +++ b/qpid/java/broker-plugins/management/src/main/java/resources/showQueue.html @@ -0,0 +1,97 @@ +<!-- + - + - 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. + - + --> +<div class="queue"> + <span style="">Queue:</span><span class="name" style="position:absolute; left:6em"></span> + <span style="position:absolute; left:26em">Size:</span> + <span class="queueDepthMessages" style="position:absolute; right:9.5em"></span> + <span style="position:absolute; right: 5em; width: 4em"> msgs</span> + <span class="queueDepthBytes" style="position:absolute; right: 3.3em">(</span> + <span class="queueDepthBytesUnits" style="position:absolute; right: 0em; width: 3em">)</span> + <br/> + <span style="">State:</span><span class="state" style="position:absolute; left:6em"></span> + <span style="position:absolute; left:26em">Pre-fetched:</span> + <span class="unacknowledgedMessages" style="position:absolute; right:9.5em"></span> + <span style="position:absolute; right: 5em; width: 4em"> msgs</span> + <span class="unacknowledgedBytes" style="position:absolute; right: 3.3em"></span> + <span class="unacknowledgedBytesUnits" style="position:absolute; right: 0em; width: 3em"></span> + <br/> + <span style="">Durable:</span><span class="durable" style="position:absolute; left:6em"></span> + <span style="position:absolute; left:26em">Inbound:</span> + <span class="msgInRate" style="position:absolute; right:9.5em"></span> + <span style="position:absolute; right: 5em; width: 4em"> msg/s</span> + <span class="bytesInRate" style="position:absolute; right: 3.3em"></span> + <span class="bytesInRateUnits" style="position:absolute; right: 0em; width: 3em"></span> + <br/> + <span style="">Lifespan:</span><span style="position:absolute; left:6em" class="lifetimePolicy"></span> + <span style="position:absolute; left:26em">Outbound:</span> + <span class="msgOutRate" style="position:absolute; right:9.5em"></span> + <span style="position:absolute; right: 5em; width: 4em"> msg/s</span> + <span class="bytesOutRate" style="position:absolute; right: 3.3em"></span> + <span class="bytesOutRateUnits" style="position:absolute; right: 0em; width: 3em"></span> + <br/> + <br/> + <div data-dojo-type="dijit.TitlePane" data-dojo-props="title: 'Bindings'"> + <div class="bindings"></div> + <button data-dojo-type="dijit.form.Button" class="addBindingButton" type="button">Add Binding</button> + </div> + <br/> + <div data-dojo-type="dijit.TitlePane" data-dojo-props="title: 'Consumers'"> + <div class="consumers"></div> + </div> + <br/> + <div data-dojo-type="dijit.TitlePane" data-dojo-props="title: 'Messages'"> + <div class="messages"></div> + <button data-dojo-type="dijit.form.Button" class="deleteMessagesButton" type="button">Delete Messages</button> + <button data-dojo-type="dijit.form.Button" class="moveMessagesButton" type="button">Move Messages</button> + <button data-dojo-type="dijit.form.Button" class="copyMessagesButton" type="button">Copy Messages</button> + </div> + <br/> + <div data-dojo-type="dijit.TitlePane" data-dojo-props="title: 'Alerting Thresholds', open: false"> + <span style="">Max. Queue Size:</span> + <span class="alertThresholdQueueDepthMessages" + style="position:absolute; left:8em; width:8em; text-align:right"></span> + <span style="position:absolute; left:16.2em">msgs</span> + + <span class="alertThresholdQueueDepthBytes" + style="position:absolute; left:20em; width:8em; text-align:right"></span> + <span class="alertThresholdQueueDepthBytesUnits" style="position:absolute; left:28.2em"></span> + <br> + <span style="">Max. Message Age:</span> + <span class="alertThresholdMessageAge" + style="position:absolute; left:8em; width:8em; text-align:right"></span> + <span class="alertThresholdMessageAgeUnits" style="position:absolute; left:16.2em"></span> + + <span style="position:absolute; left:21em">Size: </span> + <span class="alertThresholdMessageSize" + style="position:absolute; left:23em; width:5em; text-align:right"></span> + <span class="alertThresholdMessageSizeUnits" style="position:absolute; left:28.2em"></span> + <br/> + <br/> + <span style="">Alert frequency:</span> + <span class="alertRepeatGap" + style="position:absolute; left:8em; width:8em; text-align:right"></span> + <span class="alertRepeatGapUnits" style="position:absolute; left:16.2em"></span> + + + + </div> +</div> + diff --git a/qpid/java/broker-plugins/management/src/main/java/resources/showVirtualHost.html b/qpid/java/broker-plugins/management/src/main/java/resources/showVirtualHost.html new file mode 100644 index 0000000000..9d16d523d6 --- /dev/null +++ b/qpid/java/broker-plugins/management/src/main/java/resources/showVirtualHost.html @@ -0,0 +1,84 @@ +<!DOCTYPE HTML> +<!-- + - + - 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. + - + --> + +<div class="virtualhost"> + <span style="">Name:</span><span class="name" style="position:absolute; left:6em"></span> + <br/> + <span style="">State:</span><span class="state" style="position:absolute; left:6em"></span> + <br/> + <span style="">Durable:</span><span class="durable" style="position:absolute; left:6em"></span> + <span style="position:absolute; left:26em">Inbound:</span> + <span class="msgInRate" style="position:absolute; right:9.5em"></span> + <span style="position:absolute; right: 5em; width: 4em"> msg/s</span> + <span class="bytesInRate" style="position:absolute; right: 3.3em"></span> + <span class="bytesInRateUnits" style="position:absolute; right: 0em; width: 3em"></span> + <br/> + <span style="">Lifespan:</span><span style="position:absolute; left:6em" class="lifetimePolicy"></span> + <span style="position:absolute; left:26em">Outbound:</span> + <span class="msgOutRate" style="position:absolute; right:9.5em"></span> + <span style="position:absolute; right: 5em; width: 4em"> msg/s</span> + <span class="bytesOutRate" style="position:absolute; right: 3.3em"></span> + <span class="bytesOutRateUnits" style="position:absolute; right: 0em; width: 3em"></span> + <br/> + <br/> + <div data-dojo-type="dijit.TitlePane" data-dojo-props="title: 'Exchanges'"> + <div class="exchanges"></div> + <button data-dojo-type="dijit.form.Button" class="addExchangeButton">Add Exchange</button> + </div> + <br/> + <div data-dojo-type="dijit.TitlePane" data-dojo-props="title: 'Queues'"> + <div class="queues"></div> + <button data-dojo-type="dijit.form.Button" class="addQueueButton">Add Queue</button> + </div> + <br/> + <div data-dojo-type="dijit.TitlePane" data-dojo-props="title: 'Connections'"> + <div class="connections"></div> + </div> + <br/> + <div data-dojo-type="dijit.TitlePane" data-dojo-props="title: 'Alerting Thresholds', open: false"> + <span style="">Max. Queue Size:</span> + <span class="alertThresholdQueueDepthMessages" + style="position:absolute; left:8em; width:8em; text-align:right"></span> + <span style="position:absolute; left:16.2em">msgs</span> + + <span class="alertThresholdQueueDepthBytes" + style="position:absolute; left:20em; width:8em; text-align:right"></span> + <span class="alertThresholdQueueDepthBytesUnits" style="position:absolute; left:28.2em"></span> + <br> + <span style="">Max. Message Age:</span> + <span class="alertThresholdMessageAge" + style="position:absolute; left:8em; width:8em; text-align:right"></span> + <span class="alertThresholdMessageAgeUnits" style="position:absolute; left:16.2em"></span> + + <span style="position:absolute; left:21em">Size: </span> + <span class="alertThresholdMessageSize" + style="position:absolute; left:23em; width:5em; text-align:right"></span> + <span class="alertThresholdMessageSizeUnits" style="position:absolute; left:28.2em"></span> + <br/> + <br/> + <span style="">Alert frequency:</span> + <span class="alertRepeatGap" + style="position:absolute; left:8em; width:8em; text-align:right"></span> + <span class="alertRepeatGapUnits" style="position:absolute; left:16.2em"></span> + </div> +</div> + diff --git a/qpid/java/broker-web/build.xml b/qpid/java/broker-web/build.xml new file mode 100644 index 0000000000..fb747f50e3 --- /dev/null +++ b/qpid/java/broker-web/build.xml @@ -0,0 +1,107 @@ +<!-- + - 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. + --> +<project name="broker-web" xmlns:ivy="antlib:org.apache.ivy.ant" default="build"> + + <condition property="bdbstore" value="bdbstore" else=""> + <contains string="${modules.opt}" substring="bdbstore"/> + </condition> + + <import file="../common.xml"/> + <findSubProjects name="broker-plugins" dir="../broker-plugins"/> + <property name="module.depends" value="common management/common amqp-1-0-common broker ${bdbstore} ${broker-plugins}" /> + <property name="module.test.depends" value="test client common/test broker/test management/common systests" /> + <property name="module.genpom" value="true"/> + + <import file="../module.xml"/> + + <scriptdef name="string-replace" language="javascript"> + <attribute name="string" /> + <attribute name="token" /> + <attribute name="value" /> + <attribute name="property" /> + <![CDATA[ + var string = attributes.get("string"); + var token = attributes.get("token"); + var value = attributes.get("value"); + project.setProperty(attributes.get("property"), string.replace(token, value)); + ]]> + </scriptdef> + + <!-- war is built as part of build task and stored in module release folder --> + <target name="postbuild" description="Create war" > + + <property name="war.dir" value="../build/war"/> + <mkdir dir="${war.dir}/WEB-INF/lib"/> + + <!-- copy third-party dependencies into WEB-INF/lib --> + <copy todir="${war.dir}/WEB-INF/lib" flatten="true"> + <fileset dir="${project.root}" includes="${module.depends.libs}" + excludes="**/jetty-* **/*servlet*"/> + </copy> + + <!-- copy qpid dependencies into WEB-INF/lib --> + <foreach property="dependency" list="${module.depends}"> + <string-replace string="qpid-${dependency}" token="/" value="-" property="dependency.path"/> + <copy todir="${war.dir}/WEB-INF/lib"> + <fileset dir="${project.root}/build/lib" includes="**/${dependency.path}*.jar" + excludes="*-tests-*.jar *-sources.jar *.osgi.jar"/> + </copy> + </foreach> + + <!-- copy management jar into WEB-INF/lib in order to use servlets from it--> + <copy todir="${war.dir}/WEB-INF/lib"> + <fileset dir="${project.root}/build/lib/plugins" includes="qpid-broker-plugins-management*.jar"/> + </copy> + + <mkdir dir="${war.dir}/WEB-INF/etc"/> + <mkdir dir="${war.dir}/WEB-INF/work/log"/> + + <!-- copy default broker configuration into /WEB-INF/etc--> + <copy todir="${war.dir}/WEB-INF/etc"> + <fileset dir="${project.root}/broker/etc" excludes="config.xml virtualhosts.xml"/> + </copy> + + <copy todir="${war.dir}/WEB-INF/etc"> + <fileset dir="src/main/resources/WEB-INF/etc/"/> + </copy> + + <!-- copy management.html into index.html --> + <copy tofile="${war.dir}/index.html" + file="../broker-plugins/management/src/main/java/resources/management.html"/> + + <!-- extract dojo --> + <unwar src="${project.root}/${dojo}" dest="${war.dir}/dojo"> + <patternset> + <exclude name="META-INF/**"/> + <exclude name="WEB-INF/**"/> + <exclude name="**/*.uncompressed.js"/> + </patternset> + </unwar> + + <!-- build war --> + <war destfile="release/qpid.war" webxml="src/main/resources/WEB-INF/web.xml"> + <lib file="${module.jar}"/> + <fileset dir="../broker-plugins/management/src/main/java/resources"/> + <fileset dir="${war.dir}"/> + </war> + + <copy file="release/qpid.war" tofile="release/qpid-${project.version}.war"/> + </target> + +</project> diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/Managable.java b/qpid/java/broker-web/src/main/java/org/apache/qpid/web/listener/BrokerOptionsBuilder.java index 166a2a376d..3d929826f2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/Managable.java +++ b/qpid/java/broker-web/src/main/java/org/apache/qpid/web/listener/BrokerOptionsBuilder.java @@ -7,9 +7,9 @@ * 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 @@ -18,17 +18,19 @@ * under the License. * */ -package org.apache.qpid.server.management; +package org.apache.qpid.web.listener; + +import javax.servlet.ServletContext; + +import org.apache.qpid.server.BrokerOptions; /** - * Any object that can return a related MBean should implement this interface. - * - * This enables other classes to get the managed object, which in turn is useful when - * constructing relationships between managed objects without having to maintain - * separate data structures containing MBeans. - * + * Defines operations to build {@link BrokerOptions} from {@link ServletContext}. */ -public interface Managable +public interface BrokerOptionsBuilder { - ManagedObject getManagedObject(); + /** + * Builds {@link BrokerOptions} from {@link ServletContext}. + */ + BrokerOptions buildBrokerOptions(ServletContext context); } diff --git a/qpid/java/broker-web/src/main/java/org/apache/qpid/web/listener/InitParametersOptionsBuilder.java b/qpid/java/broker-web/src/main/java/org/apache/qpid/web/listener/InitParametersOptionsBuilder.java new file mode 100644 index 0000000000..61c7b09b26 --- /dev/null +++ b/qpid/java/broker-web/src/main/java/org/apache/qpid/web/listener/InitParametersOptionsBuilder.java @@ -0,0 +1,314 @@ +/* + * + * 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.web.listener; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; + +import javax.servlet.ServletContext; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.transform.TransformerFactoryConfigurationError; + +import org.apache.qpid.server.BrokerOptions; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.bootstrap.DOMImplementationRegistry; +import org.w3c.dom.ls.DOMImplementationLS; +import org.w3c.dom.ls.LSOutput; +import org.w3c.dom.ls.LSSerializer; + +/** + * Builder to build {@link BrokerOptions} from initialization parameters of servlet context. + * <p> + * The following init parameters are supported: + * <ul> + * <li>home, QPID_HOME setting + * <li>work, QPID_WORK setting + * <li>config, path to Qpid configuration file + * <li>logconfig, path to Qpid log configuration file + * <li>port, Qpid AMQP port + * <li>sslport, SSL port for AMQP + * <li>jmxregistryport, RMI port + * <li>jmxconnectorport, JMX connector port + * <li>bind, bind address + * <li>logwatch, log watch frequency + * </ul> + * <p> + * If parameters are not set then default configuration in WEB-INF/etc is used + * to start the broker + * <p> + * Examples of init configuration for web.xml + * <code> + * <context-param> + * <param-name>config</param-name> + * <param-value>/home/user/qpid/etc/config.xml</param-value> + * </context-param> + * + * <context-param> + * <param-name>work</param-name> + * <param-value>/home/user/qpid/work</param-value> + * </context-param> + * + * <context-param> + * <param-name>home</param-name> + * <param-value>/home/user/qpid</param-value> + * </context-param> + * + * <context-param> + * <param-name>port</param-name> + * <param-value>5671</param-value> + * </context-param> + * <context-param> + * <param-name>jmxregistryport</param-name> + * <param-value>8998</param-value> + * </context-param> + * <context-param> + * <param-name>jmxconnectorport</param-name> + * <param-value>9098</param-value> + * </context-param> + * </code> + */ +public class InitParametersOptionsBuilder implements BrokerOptionsBuilder +{ + private static final String INIT_PARAM_HOME_FOLDER = "home"; + + private static final String INIT_PARAM_WORK_FOLDER = "work"; + + private static final String INIT_PARAM_CONFIG_FILE = "config"; + + private static final String INIT_PARAM_LOG_CONFIG_FILE = "logconfig"; + + private static final String INIT_PARAM_PORT = "port"; + + private static final String INIT_PARAM_SSL_PORT = "sslport"; + + private static final String INIT_PARAM_JMX_PORT_REGISTRY_SERVER = "jmxregistryport"; + + private static final String INIT_PARAM_JMX_PORT_CONNECTOR_SERVER = "jmxconnectorport"; + + private static final String INIT_PARAM_BIND = "bind"; + + private static final String INIT_PARAM_LOG_WATCH = "logwatch"; + + @Override + public BrokerOptions buildBrokerOptions(ServletContext context) + { + BrokerOptions options = new BrokerOptions(); + + String homeFolder = context.getInitParameter(INIT_PARAM_HOME_FOLDER); + if (homeFolder == null) + { + homeFolder = context.getRealPath("/WEB-INF"); + } + options.setQpidHome(homeFolder); + + String workFolder = context.getInitParameter(INIT_PARAM_WORK_FOLDER); + if (workFolder == null) + { + workFolder = context.getRealPath("/WEB-INF/work"); + } + options.setQpidWork(workFolder); + + String configFile = context.getInitParameter(INIT_PARAM_CONFIG_FILE); + if (configFile == null) + { + configFile = context.getRealPath("/WEB-INF/" + BrokerOptions.DEFAULT_CONFIG_FILE); + } + options.setConfigFile(configFile); + + String logConfig = context.getInitParameter(INIT_PARAM_LOG_CONFIG_FILE); + if (logConfig == null) + { + logConfig = createLogConfigurationFromTemplate(context); + } + options.setLogConfigFile(logConfig); + + String port = context.getInitParameter(INIT_PARAM_PORT); + if (port != null) + { + int p = 0; + try + { + p = Integer.parseInt(port); + } + catch (Exception e) + { + throw new RuntimeException("Cannot parse broker port. Please specify correct value for a port!"); + } + options.addPort(p); + } + String sslport = context.getInitParameter(INIT_PARAM_SSL_PORT); + if (sslport != null) + { + int p = 0; + try + { + p = Integer.parseInt(sslport); + } + catch (Exception e) + { + throw new RuntimeException("Cannot parse broker ssl port. Please specify correct value for ssl port!"); + } + options.addSSLPort(p); + } + String jmxRegistryPort = context.getInitParameter(INIT_PARAM_JMX_PORT_REGISTRY_SERVER); + if (jmxRegistryPort != null) + { + int p = 0; + try + { + p = Integer.parseInt(jmxRegistryPort); + } + catch (Exception e) + { + throw new RuntimeException("Cannot parse broker RMI port. Please specify correct value for RMI port!"); + } + options.setJmxPortRegistryServer(p); + } + String jmxConnectorPort = context.getInitParameter(INIT_PARAM_JMX_PORT_CONNECTOR_SERVER); + if (jmxConnectorPort != null) + { + int p = 0; + try + { + p = Integer.parseInt(jmxConnectorPort); + } + catch (Exception e) + { + throw new RuntimeException("Cannot parse broker JMX connector port." + + " Please specify correct value for JMX connector port!"); + } + options.setJmxPortConnectorServer(p); + } + String logwatch = context.getInitParameter(INIT_PARAM_LOG_WATCH); + if (logwatch != null) + { + int logWatchFrequency = 0; + try + { + logWatchFrequency = Integer.parseInt(logwatch); + } + catch (Exception e) + { + throw new RuntimeException("Cannot parse broker log watch frequency." + + " Please specify correct value for log watch frequency!"); + } + options.setLogWatchFrequency(logWatchFrequency); + } + String bind = context.getInitParameter(INIT_PARAM_BIND); + if (bind != null) + { + options.setBind(bind); + } + return options; + } + + + /** + * Opens /WEB-INF/etc/log4j.xml, changes the location of the log file to + * "/WEB-INF/work/log/qpid.log" and stores log configuration in + * "/WEB-INF/work/log4j.xml" + */ + private String createLogConfigurationFromTemplate(ServletContext context) + { + String webInfPath = context.getRealPath("/WEB-INF"); + String template = webInfPath + "/" + BrokerOptions.DEFAULT_LOG_CONFIG_FILE; + String targetLogConfig = webInfPath + "/work/log4j.xml"; + String logFile = webInfPath + "/work/log/${logprefix}qpid${logsuffix}.log"; + transformLog(template, targetLogConfig, logFile); + return targetLogConfig; + } + + private void transformLog(String template, String targetLogConfig, String logFile) + throws TransformerFactoryConfigurationError + { + Document document = null; + try + { + DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); + documentBuilderFactory.setAttribute("http://xml.org/sax/features/namespaces", true); + documentBuilderFactory.setAttribute("http://xml.org/sax/features/validation", false); + documentBuilderFactory.setAttribute("http://apache.org/xml/features/nonvalidating/load-dtd-grammar", false); + documentBuilderFactory.setAttribute("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); + documentBuilderFactory.setNamespaceAware(true); + documentBuilderFactory.setIgnoringElementContentWhitespace(false); + documentBuilderFactory.setIgnoringComments(false); + documentBuilderFactory.setValidating(false); + + DocumentBuilder builder = documentBuilderFactory.newDocumentBuilder(); + document = builder.parse(new File(template)); + NodeList parameters = document.getDocumentElement().getElementsByTagName("param"); + for (int i = 0, l = parameters.getLength(); i < l; i++) + { + Node node = parameters.item(i); + if (node instanceof Element) + { + Element element = (Element) node; + String nameAttribute = element.getAttribute("name"); + if (nameAttribute != null && nameAttribute.equalsIgnoreCase("file")) + { + + element.setAttribute("value", logFile); + } + } + } + } + catch (Exception e) + { + throw new RuntimeException("Cannot open log4j configuration at " + template, e); + } + FileWriter fileWriter = null; + try + { + fileWriter = new FileWriter(targetLogConfig); + DOMImplementationLS ls = (DOMImplementationLS) DOMImplementationRegistry.newInstance() + .getDOMImplementation("LS"); + LSOutput lsout = ls.createLSOutput(); + lsout.setCharacterStream(fileWriter); + lsout.setEncoding(document.getXmlEncoding()); + LSSerializer serializer = ls.createLSSerializer(); + serializer.write(document, lsout); + } + catch (Exception e) + { + throw new RuntimeException("Cannot save log4j configuration at " + targetLogConfig, e); + } + finally + { + if (fileWriter != null) + { + try + { + fileWriter.close(); + } + catch (IOException e) + { + // ignore this + } + } + } + + } +} diff --git a/qpid/java/broker-web/src/main/java/org/apache/qpid/web/listener/QpidServletContextListener.java b/qpid/java/broker-web/src/main/java/org/apache/qpid/web/listener/QpidServletContextListener.java new file mode 100644 index 0000000000..a8aa272c10 --- /dev/null +++ b/qpid/java/broker-web/src/main/java/org/apache/qpid/web/listener/QpidServletContextListener.java @@ -0,0 +1,162 @@ +/* + * + * 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.web.listener; + +import java.util.Enumeration; +import java.util.Properties; + +import javax.servlet.ServletContext; +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; + +import org.apache.commons.configuration.interpol.ConfigurationInterpolator; +import org.apache.commons.lang.text.StrLookup; +import org.apache.qpid.server.Broker; +import org.apache.qpid.server.BrokerOptions; + +/** + * An implementation of {@link ServletContextListener} allowing to start Qpid + * broker in web container. + * <p> + * The listener instantiate {@link BrokerOptionsBuilder} specified in + * initialization parameter "broker-options-builder" and uses this builder to + * create {@link BrokerOptions} instance to start broker. + */ +public class QpidServletContextListener implements ServletContextListener +{ + private static final String INIT_PARAM_BROKER_OPTIONS_BUILDER = "broker-options-builder"; + + private Broker _broker; + + @Override + public void contextDestroyed(ServletContextEvent event) + { + if (_broker != null) + { + _broker.shutdown(); + } + } + + @Override + public void contextInitialized(ServletContextEvent event) + { + ServletContext context = event.getServletContext(); + BrokerOptions options = createBrokerOptions(context); + setConfigurationVariables(options, context); + startBroker(options); + } + + /** + * Starts broker with given {@link BrokerOptions}. + */ + private void startBroker(BrokerOptions options) + { + _broker = new Broker(); + try + { + _broker.startup(options); + } + catch (Exception e) + { + throw new RuntimeException("Broker cannot be started", e); + } + } + + /** + * Sets resolver for QPID_HOME and QPID_WORK configuration variables and all + * context initialization parameters, so, they can be used in default + * configuration files. + */ + private void setConfigurationVariables(BrokerOptions options, ServletContext context) + { + Properties properties = new Properties(); + @SuppressWarnings("unchecked") + Enumeration<String> parameterNames = context.getInitParameterNames(); + while (parameterNames.hasMoreElements()) + { + String name = parameterNames.nextElement(); + properties.put(name, context.getInitParameter(name)); + } + properties.put(BrokerOptions.QPID_HOME, options.getQpidHome()); + properties.put(BrokerOptions.QPID_WORK, options.getQpidWork()); + PropertiesLookup lookup = new PropertiesLookup(properties); + ConfigurationInterpolator.registerGlobalLookup("web", lookup); + } + + /** + * Creates {@link BrokerOptions} using initialization parameters of servlet + * context. + */ + private BrokerOptions createBrokerOptions(final ServletContext context) + { + BrokerOptionsBuilder builder = null; + String builderClassName = context.getInitParameter(INIT_PARAM_BROKER_OPTIONS_BUILDER); + if (builderClassName != null) + { + Class<?> builderClass = null; + try + { + builderClass = Class.forName(builderClassName); + } + catch (ClassNotFoundException e) + { + throw new RuntimeException("Invalid options builder class " + builderClassName + " is specified", e); + } + try + { + builder = (BrokerOptionsBuilder) builderClass.newInstance(); + } + catch (Exception e) + { + throw new RuntimeException("Cannot instantiate options builder", e); + } + } + else + { + builder = new InitParametersOptionsBuilder(); + } + return builder.buildBrokerOptions(context); + } + + /** + * A variable resolver to resolve variables set in given {@link Properties}. + * <p> + * It is used to resolve "QPID_HOME" and "QPID_WORK" and servlet context + * init parameters. + */ + private static class PropertiesLookup extends StrLookup + { + private Properties _properties; + + private PropertiesLookup(Properties properties) + { + _properties = properties; + } + + @Override + public String lookup(String varName) + { + return _properties.getProperty(varName); + } + + } + +} diff --git a/qpid/java/broker-web/src/main/resources/WEB-INF/etc/config.xml b/qpid/java/broker-web/src/main/resources/WEB-INF/etc/config.xml new file mode 100644 index 0000000000..3cd0b44f4f --- /dev/null +++ b/qpid/java/broker-web/src/main/resources/WEB-INF/etc/config.xml @@ -0,0 +1,107 @@ +<?xml version="1.0" encoding="ISO-8859-1"?> +<!-- + - + - 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. + - + --> +<broker> + <prefix>${web:QPID_HOME}</prefix> + <work>${web:QPID_WORK}</work> + <conf>${prefix}/etc</conf> + + <plugin-directory>${web:QPID_HOME}/lib/plugins</plugin-directory> + <cache-directory>${web:QPID_WORK}/cache</cache-directory> + + <connector> + <!-- To enable SSL edit the keystorePath and keystorePassword + and set enabled to true. + To disable Non-SSL port set sslOnly to true --> + <ssl> + <enabled>false</enabled> + <port>5671</port> + <sslOnly>false</sslOnly> + <keyStorePath>/path/to/keystore.ks</keyStorePath> + <keyStorePassword>keystorepass</keyStorePassword> + </ssl> + <port>5672</port> + <socketReceiveBuffer>262144</socketReceiveBuffer> + <socketSendBuffer>262144</socketSendBuffer> + </connector> + <management> + <enabled>false</enabled> + <platform-mbeanserver>false</platform-mbeanserver> + <http> + <enabled>false</enabled> + </http> + <jmxport> + <registryServer>8999</registryServer> + <!-- + If unspecified, connectorServer defaults to 100 + registryServer port. + <connectorServer>9099</connectionServer> + --> + </jmxport> + <ssl> + <enabled>false</enabled> + <!-- Update below path to your keystore location. --> + <keyStorePath>${conf}/qpid.keystore</keyStorePath> + <keyStorePassword>password</keyStorePassword> + </ssl> + </management> + <advanced> + <framesize>65535</framesize> + <locale>en_US</locale> + </advanced> + + <security> + <pd-auth-manager> + <principal-database> + <class>org.apache.qpid.server.security.auth.database.PlainPasswordFilePrincipalDatabase</class> + <attributes> + <attribute> + <name>passwordFile</name> + <value>${conf}/passwd</value> + </attribute> + </attributes> + </principal-database> + </pd-auth-manager> + + <!-- By default, all authenticated users have permissions to perform all actions --> + + <!-- ACL Example + This example illustrates securing the both Management (JMX) and Messaging. + <acl>${conf}/broker_example.acl</acl> + --> + + <msg-auth>false</msg-auth> + </security> + + <virtualhosts>${conf}/virtualhosts.xml</virtualhosts> + + <heartbeat> + <delay>0</delay> + <timeoutFactor>2.0</timeoutFactor> + </heartbeat> + <queue> + <auto_register>true</auto_register> + </queue> + + <status-updates>ON</status-updates> + +</broker> + + diff --git a/qpid/java/broker-web/src/main/resources/WEB-INF/etc/virtualhosts.xml b/qpid/java/broker-web/src/main/resources/WEB-INF/etc/virtualhosts.xml new file mode 100644 index 0000000000..44d9154f03 --- /dev/null +++ b/qpid/java/broker-web/src/main/resources/WEB-INF/etc/virtualhosts.xml @@ -0,0 +1,162 @@ +<?xml version="1.0" encoding="ISO-8859-1"?> +<!-- + - + - 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. + - + --> +<virtualhosts> + <default>test</default> + <virtualhost> + <name>localhost</name> + <localhost> + <store> + <class>org.apache.qpid.server.store.derby.DerbyMessageStore</class> + <environment-path>${web:QPID_WORK}/derbystore</environment-path> + </store> + + <housekeeping> + <threadCount>2</threadCount> + <checkPeriod>20000</checkPeriod> + </housekeeping> + + <exchanges> + <exchange> + <type>direct</type> + <name>test.direct</name> + <durable>true</durable> + </exchange> + <exchange> + <type>topic</type> + <name>test.topic</name> + </exchange> + </exchanges> + <queues> + <exchange>amq.direct</exchange> + <maximumQueueDepth>4235264</maximumQueueDepth> + <!-- 4Mb --> + <maximumMessageSize>2117632</maximumMessageSize> + <!-- 2Mb --> + <maximumMessageAge>600000</maximumMessageAge> + <!-- 10 mins --> + <maximumMessageCount>50</maximumMessageCount> + <!-- 50 messages --> + + <queue> + <name>queue</name> + </queue> + <queue> + <name>ping</name> + </queue> + <queue> + <name>test-queue</name> + <test-queue> + <exchange>test.direct</exchange> + <durable>true</durable> + </test-queue> + </queue> + <queue> + <name>test-ping</name> + <test-ping> + <exchange>test.direct</exchange> + </test-ping> + </queue> + + </queues> + </localhost> + </virtualhost> + + + <virtualhost> + <name>development</name> + <development> + <store> + <class>org.apache.qpid.server.store.derby.DerbyMessageStore</class> + <environment-path>${web:QPID_WORK}/derbystore</environment-path> + </store> + + <queues> + <minimumAlertRepeatGap>30000</minimumAlertRepeatGap> + <maximumMessageCount>50</maximumMessageCount> + <queue> + <name>queue</name> + <queue> + <exchange>amq.direct</exchange> + <maximumQueueDepth>4235264</maximumQueueDepth> + <!-- 4Mb --> + <maximumMessageSize>2117632</maximumMessageSize> + <!-- 2Mb --> + <maximumMessageAge>600000</maximumMessageAge> + <!-- 10 mins --> + </queue> + </queue> + <queue> + <name>ping</name> + <ping> + <exchange>amq.direct</exchange> + <maximumQueueDepth>4235264</maximumQueueDepth> + <!-- 4Mb --> + <maximumMessageSize>2117632</maximumMessageSize> + <!-- 2Mb --> + <maximumMessageAge>600000</maximumMessageAge> + <!-- 10 mins --> + </ping> + </queue> + </queues> + </development> + </virtualhost> + <virtualhost> + <name>test</name> + <test> + <store> + <class>org.apache.qpid.server.store.derby.DerbyMessageStore</class> + <environment-path>${web:QPID_WORK}/derbystore</environment-path> + </store> + + <queues> + <minimumAlertRepeatGap>30000</minimumAlertRepeatGap> + <maximumMessageCount>50</maximumMessageCount> + <queue> + <name>queue</name> + <queue> + <exchange>amq.direct</exchange> + <maximumQueueDepth>4235264</maximumQueueDepth> + <!-- 4Mb --> + <maximumMessageSize>2117632</maximumMessageSize> + <!-- 2Mb --> + <maximumMessageAge>600000</maximumMessageAge> + <!-- 10 mins --> + </queue> + </queue> + <queue> + <name>ping</name> + <ping> + <exchange>amq.direct</exchange> + <maximumQueueDepth>4235264</maximumQueueDepth> + <!-- 4Mb --> + <maximumMessageSize>2117632</maximumMessageSize> + <!-- 2Mb --> + <maximumMessageAge>600000</maximumMessageAge> + <!-- 10 mins --> + </ping> + </queue> + </queues> + </test> + </virtualhost> +</virtualhosts> + + diff --git a/qpid/java/broker-web/src/main/resources/WEB-INF/web.xml b/qpid/java/broker-web/src/main/resources/WEB-INF/web.xml new file mode 100644 index 0000000000..42322ceaa3 --- /dev/null +++ b/qpid/java/broker-web/src/main/resources/WEB-INF/web.xml @@ -0,0 +1,261 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + - 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. + --> +<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" +xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" +xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> + + <session-config><!-- 10 minutes --> + <session-timeout>10</session-timeout> + </session-config> + + <servlet> + <display-name>VhostsServlet</display-name> + <servlet-name>VhostsServlet</servlet-name> + <servlet-class>org.apache.qpid.server.management.plugin.servlet.api.VhostsServlet</servlet-class> + </servlet> + + <servlet> + <display-name>ExchangesServlet</display-name> + <servlet-name>ExchangesServlet</servlet-name> + <servlet-class>org.apache.qpid.server.management.plugin.servlet.api.ExchangesServlet</servlet-class> + </servlet> + + <servlet> + <display-name>BrokerRestServlet</display-name> + <servlet-name>BrokerRestServlet</servlet-name> + <servlet-class>org.apache.qpid.server.management.plugin.servlet.rest.RestServlet</servlet-class> + </servlet> + + <servlet> + <display-name>VirtualHostRestServlet</display-name> + <servlet-name>VirtualHostRestServlet</servlet-name> + <servlet-class>org.apache.qpid.server.management.plugin.servlet.rest.RestServlet</servlet-class> + <init-param> + <param-name>hierarchy</param-name> + <param-value>VirtualHost</param-value> + </init-param> + </servlet> + + <servlet> + <display-name>AuthenticationProviderRestServlet</display-name> + <servlet-name>AuthenticationProviderRestServlet</servlet-name> + <servlet-class>org.apache.qpid.server.management.plugin.servlet.rest.RestServlet</servlet-class> + <init-param> + <param-name>hierarchy</param-name> + <param-value>AuthenticationProvider</param-value> + </init-param> + </servlet> + + <servlet> + <display-name>UserRestServlet</display-name> + <servlet-name>UserRestServlet</servlet-name> + <servlet-class>org.apache.qpid.server.management.plugin.servlet.rest.RestServlet</servlet-class> + <init-param> + <param-name>hierarchy</param-name> + <param-value>AuthenticationProvider,User</param-value> + </init-param> + </servlet> + + + <servlet> + <display-name>ExchangeRestServlet</display-name> + <servlet-name>ExchangeRestServlet</servlet-name> + <servlet-class>org.apache.qpid.server.management.plugin.servlet.rest.RestServlet</servlet-class> + <init-param> + <param-name>hierarchy</param-name> + <param-value>VirtualHost,Exchange</param-value> + </init-param> + </servlet> + + <servlet> + <display-name>QueueRestServlet</display-name> + <servlet-name>QueueRestServlet</servlet-name> + <servlet-class>org.apache.qpid.server.management.plugin.servlet.rest.RestServlet</servlet-class> + <init-param> + <param-name>hierarchy</param-name> + <param-value>VirtualHost,Queue</param-value> + </init-param> + </servlet> + + <servlet> + <display-name>ConnectionRestServlet</display-name> + <servlet-name>ConnectionRestServlet</servlet-name> + <servlet-class>org.apache.qpid.server.management.plugin.servlet.rest.RestServlet</servlet-class> + <init-param> + <param-name>hierarchy</param-name> + <param-value>VirtualHost,Connection</param-value> + </init-param> + </servlet> + + <servlet> + <display-name>BindingRestServlet</display-name> + <servlet-name>BindingRestServlet</servlet-name> + <servlet-class>org.apache.qpid.server.management.plugin.servlet.rest.RestServlet</servlet-class> + <init-param> + <param-name>hierarchy</param-name> + <param-value>VirtualHost,Exchange,Queue,Binding</param-value> + </init-param> + </servlet> + + <servlet> + <display-name>PortRestServlet</display-name> + <servlet-name>PortRestServlet</servlet-name> + <servlet-class>org.apache.qpid.server.management.plugin.servlet.rest.RestServlet</servlet-class> + <init-param> + <param-name>hierarchy</param-name> + <param-value>Port</param-value> + </init-param> + </servlet> + + <servlet> + <display-name>SessionRestServlet</display-name> + <servlet-name>SessionRestServlet</servlet-name> + <servlet-class>org.apache.qpid.server.management.plugin.servlet.rest.RestServlet</servlet-class> + <init-param> + <param-name>hierarchy</param-name> + <param-value>VirtualHost,Connection,Session</param-value> + </init-param> + </servlet> + + <servlet> + <display-name>StructureServlet</display-name> + <servlet-name>StructureServlet</servlet-name> + <servlet-class>org.apache.qpid.server.management.plugin.servlet.rest.StructureServlet</servlet-class> + </servlet> + + <servlet> + <display-name>MessageServlet</display-name> + <servlet-name>MessageServlet</servlet-name> + <servlet-class>org.apache.qpid.server.management.plugin.servlet.rest.MessageServlet</servlet-class> + </servlet> + + <servlet> + <display-name>MessageContentServlet</display-name> + <servlet-name>MessageContentServlet</servlet-name> + <servlet-class>org.apache.qpid.server.management.plugin.servlet.rest.MessageContentServlet</servlet-class> + </servlet> + + <servlet> + <display-name>LogRecordsServlet</display-name> + <servlet-name>LogRecordsServlet</servlet-name> + <servlet-class>org.apache.qpid.server.management.plugin.servlet.rest.LogRecordsServlet</servlet-class> + </servlet> + + <servlet> + <display-name>SaslServlet</display-name> + <servlet-name>SaslServlet</servlet-name> + <servlet-class>org.apache.qpid.server.management.plugin.servlet.rest.SaslServlet</servlet-class> + </servlet> + + <servlet-mapping> + <servlet-name>VhostsServlet</servlet-name> + <url-pattern>/api/vhosts/*</url-pattern> + </servlet-mapping> + + <servlet-mapping> + <servlet-name>ExchangesServlet</servlet-name> + <url-pattern>/api/exchanges/*</url-pattern> + </servlet-mapping> + + <servlet-mapping> + <servlet-name>BrokerRestServlet</servlet-name> + <url-pattern>/rest/broker/*</url-pattern> + </servlet-mapping> + + <servlet-mapping> + <servlet-name>VirtualHostRestServlet</servlet-name> + <url-pattern>/rest/virtualhost/*</url-pattern> + </servlet-mapping> + + <servlet-mapping> + <servlet-name>AuthenticationProviderRestServlet</servlet-name> + <url-pattern>/rest/authenticationprovider/*</url-pattern> + </servlet-mapping> + + <servlet-mapping> + <servlet-name>UserRestServlet</servlet-name> + <url-pattern>/rest/user/*</url-pattern> + </servlet-mapping> + + <servlet-mapping> + <servlet-name>ExchangeRestServlet</servlet-name> + <url-pattern>/rest/exchange/*</url-pattern> + </servlet-mapping> + + <servlet-mapping> + <servlet-name>QueueRestServlet</servlet-name> + <url-pattern>/rest/queue/*</url-pattern> + </servlet-mapping> + + <servlet-mapping> + <servlet-name>ConnectionRestServlet</servlet-name> + <url-pattern>/rest/connection/*</url-pattern> + </servlet-mapping> + + <servlet-mapping> + <servlet-name>BindingRestServlet</servlet-name> + <url-pattern>/rest/binding/*</url-pattern> + </servlet-mapping> + + <servlet-mapping> + <servlet-name>PortRestServlet</servlet-name> + <url-pattern>/rest/port/*</url-pattern> + </servlet-mapping> + + <servlet-mapping> + <servlet-name>SessionRestServlet</servlet-name> + <url-pattern>/rest/session/*</url-pattern> + </servlet-mapping> + + <servlet-mapping> + <servlet-name>StructureServlet</servlet-name> + <url-pattern>/rest/structure</url-pattern> + </servlet-mapping> + + <servlet-mapping> + <servlet-name>MessageServlet</servlet-name> + <url-pattern>/rest/message/*</url-pattern> + </servlet-mapping> + + <servlet-mapping> + <servlet-name>MessageContentServlet</servlet-name> + <url-pattern>/rest/message-content/*</url-pattern> + </servlet-mapping> + + <servlet-mapping> + <servlet-name>LogRecordsServlet</servlet-name> + <url-pattern>/rest/logrecords</url-pattern> + </servlet-mapping> + + <servlet-mapping> + <servlet-name>SaslServlet</servlet-name> + <url-pattern>/rest/sasl</url-pattern> + </servlet-mapping> + + <listener> + <listener-class>org.apache.qpid.web.listener.QpidServletContextListener</listener-class> + </listener> + + <welcome-file-list> + <welcome-file>index.html</welcome-file> + <welcome-file>management.html</welcome-file> + </welcome-file-list> + +</web-app> diff --git a/qpid/java/broker/etc/broker_example.acl b/qpid/java/broker/etc/broker_example.acl index aae4ee3162..1f32f8463e 100644 --- a/qpid/java/broker/etc/broker_example.acl +++ b/qpid/java/broker/etc/broker_example.acl @@ -24,6 +24,8 @@ #Define a 'messaging-users' group with users 'client' and 'server' in it GROUP messaging-users client server +#Define a group for management web console users +GROUP webadmins webadmin ### MANAGEMENT #### @@ -74,6 +76,23 @@ ACL ALLOW-LOG server CONSUME QUEUE name="example.RequestQueue" ACL ALLOW-LOG server BIND EXCHANGE ACL ALLOW-LOG server PUBLISH EXCHANGE name="amq.direct" routingKey="TempQueue*" +# ACL for web management console admins +# All rules below are required for console admin users +# to perform create/update/delete operations +ACL ALLOW-LOG webadmins CREATE QUEUE +ACL ALLOW-LOG webadmins DELETE QUEUE +ACL ALLOW-LOG webadmins PURGE QUEUE +ACL ALLOW-LOG webadmins CREATE EXCHANGE +ACL ALLOW-LOG webadmins DELETE EXCHANGE +ACL ALLOW-LOG webadmins BIND EXCHANGE +ACL ALLOW-LOG webadmins UNBIND EXCHANGE +ACL ALLOW-LOG webadmins UPDATE METHOD + +# at the moment only the following UPDATE METHOD rules are supported by web management console +#ACL ALLOW-LOG webadmins UPDATE METHOD component="VirtualHost.Queue" name="moveMessages" +#ACL ALLOW-LOG webadmins UPDATE METHOD component="VirtualHost.Queue" name="copyMessages" +#ACL ALLOW-LOG webadmins UPDATE METHOD component="VirtualHost.Queue" name="deleteMessages" + ### DEFAULT ### #Deny all users from performing all operations diff --git a/qpid/java/broker/etc/config.xml b/qpid/java/broker/etc/config.xml index e1aacd43b5..3bf8e1afa3 100644 --- a/qpid/java/broker/etc/config.xml +++ b/qpid/java/broker/etc/config.xml @@ -43,7 +43,7 @@ <socketSendBuffer>262144</socketSendBuffer> </connector> <management> - <enabled>true</enabled> + <enabled>false</enabled> <jmxport> <registryServer>8999</registryServer> <!-- diff --git a/qpid/java/broker/etc/log4j.xml b/qpid/java/broker/etc/log4j.xml index 7dbb1bc87d..b881539a52 100644 --- a/qpid/java/broker/etc/log4j.xml +++ b/qpid/java/broker/etc/log4j.xml @@ -87,10 +87,6 @@ </layout> </appender> - <category additivity="true" name="org.apache.qpid.server.queue.AMQQueueMBean"> - <priority value="info"/> - </category> - <!-- Provide warnings to standard output --> <category additivity="true" name="org.apache.qpid"> <priority value="warn"/> @@ -101,8 +97,6 @@ <level value="info"/> </logger> - - <!-- Examples of additional logging settings --> <!-- Used to generate extra debug. See debug.log4j.xml --> diff --git a/qpid/java/broker/etc/passwd b/qpid/java/broker/etc/passwd index 99f0f05c6a..f0dcb80f25 100644 --- a/qpid/java/broker/etc/passwd +++ b/qpid/java/broker/etc/passwd @@ -21,3 +21,5 @@ client:guest server:guest admin:admin +webadmin:webadmin + diff --git a/qpid/java/broker/src/main/java/org/apache/log4j/xml/QpidLog4JConfigurator.java b/qpid/java/broker/src/main/java/org/apache/log4j/xml/QpidLog4JConfigurator.java index dca62f34b4..79bedb2a7e 100644 --- a/qpid/java/broker/src/main/java/org/apache/log4j/xml/QpidLog4JConfigurator.java +++ b/qpid/java/broker/src/main/java/org/apache/log4j/xml/QpidLog4JConfigurator.java @@ -26,8 +26,6 @@ import org.xml.sax.ErrorHandler; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; -import org.apache.qpid.server.logging.management.LoggingManagementMBean; - import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; @@ -65,7 +63,6 @@ public class QpidLog4JConfigurator LOCK.lock(); parseXMLConfigFile(filename); - checkLoggerLevels(filename); DOMConfigurator.configure(filename); @@ -84,7 +81,6 @@ public class QpidLog4JConfigurator SAXException, IllegalLoggerLevelException { parseXMLConfigFile(filename); - checkLoggerLevels(filename); QpidLog4JXMLWatchdog watchdog = new QpidLog4JXMLWatchdog(filename); watchdog.setDelay(delay); @@ -200,23 +196,6 @@ public class QpidLog4JConfigurator return; } - try - { - checkLoggerLevels(filename); - } - catch (Exception e) - { - //logger will be instantiated following first configuration success, which has been pre-validated - //and so the null check should never actually be required. - if(_logger != null) - { - _logger.warn("Errors were found when validating the logger level values in the " + - "log4j XML configuration file. The new configuration was not applied. " + - "Correct the issues to prompt another update attempt: " + e.getMessage()); - } - return; - } - //everything checked was ok, let the normal update process proceed super.doOnChange(); @@ -235,60 +214,7 @@ public class QpidLog4JConfigurator } } - - protected static void checkLoggerLevels(String filename) throws IllegalLoggerLevelException, IOException - { - //check that the logger levels specified in the XML are actually valid - try - { - LOCK.lock(); - - //get the Logger levels to check - Map<String, String> loggersLevels; - loggersLevels = LoggingManagementMBean.retrieveConfigFileLoggersLevels(filename); - //add the RootLogger to the list too - String rootLoggerlevelString = LoggingManagementMBean.retrieveConfigFileRootLoggerLevel(filename); - loggersLevels.put("Root", rootLoggerlevelString); - - - for (Map.Entry<String, String> entry : loggersLevels.entrySet()) - { - String loggerName = entry.getKey(); - String levelString = entry.getValue(); - - //let log4j replace any properties in the string - String log4jConfiguredString = domConfig.subst(levelString); - - if(log4jConfiguredString.equals("") && ! log4jConfiguredString.equals(levelString)) - { - //log4j has returned an empty string but this isnt what we gave it. - //There may have been an undefined property. Unlike an incorrect - //literal value, we will allow this case to proceed, but warn users. - - if(_logger != null) - { - _logger.warn("Unable to detect Level value from '" + levelString - +"' for logger '" + loggerName + "', Log4J will default this to DEBUG"); - } - else - { - System.err.println("Unable to detect Level value from '" + levelString - +"' for logger " + loggerName + ", Log4J will default this to DEBUG"); - } - - continue; - } - - checkLevel(loggerName,log4jConfiguredString); - } - } - finally - { - LOCK.unlock(); - } - } - private static void checkLevel(String loggerName, String levelString) throws IllegalLoggerLevelException { if("null".equalsIgnoreCase(levelString) || "inherited".equalsIgnoreCase(levelString)) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/ManagementExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/ManagementExchange.java index 034a4ae53c..0d48aec562 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/ManagementExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/ManagementExchange.java @@ -540,6 +540,11 @@ public class ManagementExchange implements Exchange, QMFService.Listener return getMsgReceives(); } + public long getMsgDrops() + { + return 0l; + } + public long getByteReceives() { return _bytesReceived.get(); @@ -550,6 +555,11 @@ public class ManagementExchange implements Exchange, QMFService.Listener return getByteReceives(); } + public long getByteDrops() + { + return 0l; + } + public long getCreateTime() { return _createTime; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFMessage.java index 787cede2b7..1b173c7e11 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFMessage.java @@ -21,6 +21,8 @@ package org.apache.qpid.qmf; +import java.util.Collection; +import java.util.Collections; import org.apache.commons.lang.NotImplementedException; import org.apache.qpid.framing.AMQShortString; @@ -111,6 +113,16 @@ public class QMFMessage implements ServerMessage, InboundMessage, AMQMessageHead return 0; } + public String getUserId() + { + return null; + } + + public String getAppId() + { + return null; + } + public String getMessageId() { return null; @@ -166,6 +178,12 @@ public class QMFMessage implements ServerMessage, InboundMessage, AMQMessageHead return false; } + @Override + public Collection<String> getHeaderNames() + { + return Collections.EMPTY_SET; + } + public boolean containsHeader(String name) { return false; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java deleted file mode 100644 index 0f32b98aa8..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBean.java +++ /dev/null @@ -1,410 +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; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.FieldTable; -import org.apache.qpid.management.common.mbeans.ManagedBroker; -import org.apache.qpid.management.common.mbeans.ManagedQueue; -import org.apache.qpid.management.common.mbeans.annotations.MBeanConstructor; -import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.exchange.ExchangeFactory; -import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.server.exchange.ExchangeType; -import org.apache.qpid.server.logging.actors.CurrentActor; -import org.apache.qpid.server.logging.actors.ManagementActor; -import org.apache.qpid.server.management.AMQManagedObject; -import org.apache.qpid.server.management.ManagedObject; -import org.apache.qpid.server.model.UUIDGenerator; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.queue.AMQQueueFactory; -import org.apache.qpid.server.queue.AMQQueueMBean; -import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.virtualhost.VirtualHostImpl; - -import javax.management.JMException; -import javax.management.MBeanException; -import javax.management.MalformedObjectNameException; -import javax.management.ObjectName; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.UUID; - -/** - * This MBean implements the broker management interface and exposes the - * Broker level management features like creating and deleting exchanges and queue. - */ -@MBeanDescription("This MBean exposes the broker level management features") -public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBroker -{ - private final QueueRegistry _queueRegistry; - private final ExchangeRegistry _exchangeRegistry; - private final ExchangeFactory _exchangeFactory; - - private final VirtualHostImpl.VirtualHostMBean _virtualHostMBean; - - @MBeanConstructor("Creates the Broker Manager MBean") - public AMQBrokerManagerMBean(VirtualHostImpl.VirtualHostMBean virtualHostMBean) throws JMException - { - super(ManagedBroker.class, ManagedBroker.TYPE); - - _virtualHostMBean = virtualHostMBean; - VirtualHost virtualHost = virtualHostMBean.getVirtualHost(); - - _queueRegistry = virtualHost.getQueueRegistry(); - _exchangeRegistry = virtualHost.getExchangeRegistry(); - _exchangeFactory = virtualHost.getExchangeFactory(); - } - - public String getObjectInstanceName() - { - return _virtualHostMBean.getVirtualHost().getName(); - } - - /** - * Returns an array of the exchange types available for creation. - * @since Qpid JMX API 1.3 - * @throws IOException - */ - public String[] getExchangeTypes() throws IOException - { - ArrayList<String> exchangeTypes = new ArrayList<String>(); - for(ExchangeType<? extends Exchange> ex : _exchangeFactory.getPublicCreatableTypes()) - { - exchangeTypes.add(ex.getName().toString()); - } - - return exchangeTypes.toArray(new String[0]); - } - - /** - * Returns a list containing the names of the attributes available for the Queue mbeans. - * @since Qpid JMX API 1.3 - * @throws IOException - */ - public List<String> retrieveQueueAttributeNames() throws IOException - { - return ManagedQueue.QUEUE_ATTRIBUTES; - } - - /** - * Returns a List of Object Lists containing the requested attribute values (in the same sequence requested) for each queue in the virtualhost. - * If a particular attribute cant be found or raises an mbean/reflection exception whilst being gathered its value is substituted with the String "-". - * @since Qpid JMX API 1.3 - * @throws IOException - */ - public List<List<Object>> retrieveQueueAttributeValues(String[] attributes) throws IOException - { - if(_queueRegistry.getQueues().size() == 0) - { - return new ArrayList<List<Object>>(); - } - - List<List<Object>> queueAttributesList = new ArrayList<List<Object>>(_queueRegistry.getQueues().size()); - - int attributesLength = attributes.length; - - for(AMQQueue queue : _queueRegistry.getQueues()) - { - AMQQueueMBean mbean = (AMQQueueMBean) queue.getManagedObject(); - - if(mbean == null) - { - continue; - } - - List<Object> attributeValues = new ArrayList<Object>(attributesLength); - - for(int i=0; i < attributesLength; i++) - { - try - { - attributeValues.add(mbean.getAttribute(attributes[i])); - } - catch (Exception e) - { - attributeValues.add("-"); - } - } - - queueAttributesList.add(attributeValues); - } - - return queueAttributesList; - } - - /** - * Creates new exchange and registers it with the registry. - * - * @param exchangeName - * @param type - * @param durable - * @throws JMException - * @throws MBeanException - */ - public void createNewExchange(String exchangeName, String type, boolean durable) throws JMException, MBeanException - { - CurrentActor.set(new ManagementActor(getLogActor().getRootMessageLogger())); - try - { - synchronized (_exchangeRegistry) - { - Exchange exchange = _exchangeRegistry.getExchange(new AMQShortString(exchangeName)); - if (exchange == null) - { - exchange = _exchangeFactory.createExchange(new AMQShortString(exchangeName), - new AMQShortString(type), durable, false, 0); - _exchangeRegistry.registerExchange(exchange); - if (durable) - { - getVirtualHost().getMessageStore().createExchange(exchange); - } - } - else - { - throw new JMException("The exchange \"" + exchangeName + "\" already exists."); - } - } - } - catch (AMQException ex) - { - JMException jme = new JMException(ex.toString()); - throw new MBeanException(jme, "Error in creating exchange " + exchangeName); - } - finally - { - CurrentActor.remove(); - } - } - - /** - * Unregisters the exchange from registry. - * - * @param exchangeName - * @throws JMException - * @throws MBeanException - */ - public void unregisterExchange(String exchangeName) throws JMException, MBeanException - { - // TODO - // Check if the exchange is in use. - - // Check if there are queue-bindings with the exchange and unregister - // when there are no bindings. - CurrentActor.set(new ManagementActor(getLogActor().getRootMessageLogger())); - try - { - _exchangeRegistry.unregisterExchange(new AMQShortString(exchangeName), false); - } - catch (AMQException ex) - { - JMException jme = new JMException(ex.toString()); - throw new MBeanException(jme, "Error in unregistering exchange " + exchangeName); - } - finally - { - CurrentActor.remove(); - } - } - - /** - * Creates a new queue and registers it with the registry and puts it - * in persistance storage if durable queue. - * - * @param queueName - * @param durable - * @param owner - * @throws JMException - * @throws MBeanException - */ - public void createNewQueue(String queueName, String owner, boolean durable) throws JMException, MBeanException - { - createNewQueue(queueName, owner, durable, null); - } - - public void createNewQueue(String queueName, String owner, boolean durable, Map<String,Object> arguments) throws JMException - { - final AMQShortString queueNameAsAMQShortString = new AMQShortString(queueName); - synchronized (_queueRegistry) - { - AMQQueue queue = _queueRegistry.getQueue(queueNameAsAMQShortString); - if (queue != null) - { - throw new JMException("The queue \"" + queueName + "\" already exists."); - } - - CurrentActor.set(new ManagementActor(getLogActor().getRootMessageLogger())); - try - { - FieldTable args = null; - if(arguments != null) - { - args = FieldTable.convertToFieldTable(arguments); - } - final VirtualHost virtualHost = getVirtualHost(); - - queue = AMQQueueFactory.createAMQQueueImpl(UUIDGenerator.generateUUID(), queueName, durable, owner, - false, false, getVirtualHost(), arguments); - if (queue.isDurable() && !queue.isAutoDelete()) - { - getVirtualHost().getMessageStore().createQueue(queue, args); - } - - virtualHost.getBindingFactory().addBinding(queueName, queue, _exchangeRegistry.getDefaultExchange(), null); - } - catch (AMQException ex) - { - JMException jme = new JMException(ex.toString()); - throw new MBeanException(jme, "Error in creating queue " + queueName); - } - finally - { - CurrentActor.remove(); - } - } - } - - private VirtualHost getVirtualHost() - { - return _virtualHostMBean.getVirtualHost(); - } - - /** - * Deletes the queue from queue registry and persistant storage. - * - * @param queueName - * @throws JMException - * @throws MBeanException - */ - public void deleteQueue(String queueName) throws JMException, MBeanException - { - AMQQueue queue = _queueRegistry.getQueue(new AMQShortString(queueName)); - if (queue == null) - { - throw new JMException("The Queue " + queueName + " is not a registered queue."); - } - - CurrentActor.set(new ManagementActor(getLogActor().getRootMessageLogger())); - try - { - queue.delete(); - if (queue.isDurable()) - { - getVirtualHost().getMessageStore().removeQueue(queue); - } - } - catch (AMQException ex) - { - JMException jme = new JMException(ex.toString()); - throw new MBeanException(jme, "Error in deleting queue " + queueName); - } - finally - { - CurrentActor.remove(); - } - } - - @Override - public ManagedObject getParentObject() - { - return _virtualHostMBean; - } - - // This will have a single instance for a virtual host, so not having the name property in the ObjectName - @Override - public ObjectName getObjectName() throws MalformedObjectNameException - { - return getObjectNameForSingleInstanceMBean(); - } - - public void resetStatistics() throws Exception - { - getVirtualHost().resetStatistics(); - } - - public double getPeakMessageDeliveryRate() - { - return getVirtualHost().getMessageDeliveryStatistics().getPeak(); - } - - public double getPeakDataDeliveryRate() - { - return getVirtualHost().getDataDeliveryStatistics().getPeak(); - } - - public double getMessageDeliveryRate() - { - return getVirtualHost().getMessageDeliveryStatistics().getRate(); - } - - public double getDataDeliveryRate() - { - return getVirtualHost().getDataDeliveryStatistics().getRate(); - } - - public long getTotalMessagesDelivered() - { - return getVirtualHost().getMessageDeliveryStatistics().getTotal(); - } - - public long getTotalDataDelivered() - { - return getVirtualHost().getDataDeliveryStatistics().getTotal(); - } - - public double getPeakMessageReceiptRate() - { - return getVirtualHost().getMessageReceiptStatistics().getPeak(); - } - - public double getPeakDataReceiptRate() - { - return getVirtualHost().getDataReceiptStatistics().getPeak(); - } - - public double getMessageReceiptRate() - { - return getVirtualHost().getMessageReceiptStatistics().getRate(); - } - - public double getDataReceiptRate() - { - return getVirtualHost().getDataReceiptStatistics().getRate(); - } - - public long getTotalMessagesReceived() - { - return getVirtualHost().getMessageReceiptStatistics().getTotal(); - } - - public long getTotalDataReceived() - { - return getVirtualHost().getDataReceiptStatistics().getTotal(); - } - - public boolean isStatisticsEnabled() - { - return getVirtualHost().isStatisticsEnabled(); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java index 4fd4e02220..819fe1f0e7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java @@ -140,7 +140,7 @@ public class AMQChannel implements SessionConfig, AMQSessionModel, AsyncAutoComm private UnacknowledgedMessageMap _unacknowledgedMessageMap = new UnacknowledgedMessageMapImpl(DEFAULT_PREFETCH); - // Set of messages being acknoweledged in the current transaction + // Set of messages being acknowledged in the current transaction private SortedSet<QueueEntry> _acknowledgedMessages = new TreeSet<QueueEntry>(); private final AtomicBoolean _suspended = new AtomicBoolean(false); @@ -263,6 +263,11 @@ public class AMQChannel implements SessionConfig, AMQSessionModel, AsyncAutoComm return _txnCount.get(); } + public Long getTxnStart() + { + return _txnStarts.get(); + } + public int getChannelId() { return _channelId; @@ -440,7 +445,7 @@ public class AMQChannel implements SessionConfig, AMQSessionModel, AsyncAutoComm * @param acks Are acks enabled for this subscriber * @param filters Filters to apply to this subscriber * - * @param noLocal Flag stopping own messages being receivied. + * @param noLocal Flag stopping own messages being received. * @param exclusive Flag requesting exclusive access to the queue * @return the consumer tag. This is returned to the subscriber and used in subsequent unsubscribe requests * @@ -1417,6 +1422,11 @@ public class AMQChannel implements SessionConfig, AMQSessionModel, AsyncAutoComm return false; } + public int getUnacknowledgedMessageCount() + { + return getUnacknowledgedMessageMap().size(); + } + private void flow(boolean flow) { MethodRegistry methodRegistry = _session.getMethodRegistry(); @@ -1424,6 +1434,7 @@ public class AMQChannel implements SessionConfig, AMQSessionModel, AsyncAutoComm _session.writeFrame(responseBody.generateFrame(_channelId)); } + @Override public boolean getBlocking() { return _blocking.get(); @@ -1587,7 +1598,7 @@ public class AMQChannel implements SessionConfig, AMQSessionModel, AsyncAutoComm _unfinishedCommandsQueue.add(new AsyncCommand(future, action)); } - public void completeAsyncCommands() + public boolean completeAsyncCommands() { AsyncCommand cmd; while((cmd = _unfinishedCommandsQueue.peek()) != null && cmd.isReadyForCompletion()) @@ -1601,6 +1612,7 @@ public class AMQChannel implements SessionConfig, AMQSessionModel, AsyncAutoComm cmd.awaitReadyForCompletion(); cmd.complete(); } + return _unfinishedCommandsQueue.isEmpty(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/Broker.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/Broker.java index 90603777d1..c843ce6a23 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/Broker.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/Broker.java @@ -25,24 +25,17 @@ import java.io.IOException; import java.io.InputStream; import java.net.InetAddress; import java.net.InetSocketAddress; -import java.util.EnumSet; -import java.util.HashSet; -import java.util.List; -import java.util.Properties; -import java.util.Set; +import java.util.*; import javax.net.ssl.SSLContext; import org.apache.log4j.Logger; import org.apache.log4j.PropertyConfigurator; import org.apache.log4j.xml.QpidLog4JConfigurator; import org.apache.qpid.server.configuration.ServerConfiguration; import org.apache.qpid.server.configuration.ServerNetworkTransportConfiguration; -import org.apache.qpid.server.configuration.management.ConfigurationManagementMBean; -import org.apache.qpid.server.information.management.ServerInformationMBean; import org.apache.qpid.server.logging.SystemOutMessageLogger; import org.apache.qpid.server.logging.actors.BrokerActor; import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.logging.actors.GenericActor; -import org.apache.qpid.server.logging.management.LoggingManagementMBean; import org.apache.qpid.server.logging.messages.BrokerMessages; import org.apache.qpid.server.protocol.AmqpProtocolVersion; import org.apache.qpid.server.protocol.MultiVersionProtocolEngineFactory; @@ -118,6 +111,14 @@ public class Broker ConfigurationFileApplicationRegistry config = new ConfigurationFileApplicationRegistry(configFile, options.getBundleContext()); ServerConfiguration serverConfig = config.getConfiguration(); + if (options.getQpidWork() != null) + { + serverConfig.setQpidWork(options.getQpidWork()); + } + if (options.getQpidHome() != null) + { + serverConfig.setQpidHome(options.getQpidHome()); + } updateManagementPorts(serverConfig, options.getJmxPortRegistryServer(), options.getJmxPortConnectorServer()); ApplicationRegistry.initialise(config); @@ -135,14 +136,6 @@ public class Broker try { - configureLoggingManagementMBean(logConfigFile, options.getLogWatchFrequency()); - - ConfigurationManagementMBean configMBean = new ConfigurationManagementMBean(); - configMBean.register(); - - ServerInformationMBean sysInfoMBean = new ServerInformationMBean(config); - sysInfoMBean.register(); - Set<Integer> ports = new HashSet<Integer>(options.getPorts()); if(ports.isEmpty()) { @@ -258,7 +251,7 @@ public class Broker transport.accept(settings, protocolEngineFactory, null); ApplicationRegistry.getInstance().addAcceptor(inetSocketAddress, - new QpidAcceptor(transport,"TCP")); + new QpidAcceptor(transport,QpidAcceptor.Transport.TCP, supported)); CurrentActor.get().message(BrokerMessages.LISTENING("TCP", port)); } } @@ -302,7 +295,7 @@ public class Broker transport.accept(settings, protocolEngineFactory, sslContext); ApplicationRegistry.getInstance().addAcceptor(inetSocketAddress, - new QpidAcceptor(transport,"TCP")); + new QpidAcceptor(transport,QpidAcceptor.Transport.SSL, supported)); CurrentActor.get().message(BrokerMessages.LISTENING("TCP/SSL", sslPort)); } } @@ -495,12 +488,6 @@ public class Broker } } - private void configureLoggingManagementMBean(File logConfigFile, int logWatchTime) throws Exception - { - LoggingManagementMBean blm = new LoggingManagementMBean(logConfigFile.getPath(),logWatchTime); - - blm.register(); - } private void addShutdownHook() { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/BrokerOptions.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/BrokerOptions.java index cec614881d..434d40d557 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/BrokerOptions.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/BrokerOptions.java @@ -33,6 +33,7 @@ public class BrokerOptions public static final String DEFAULT_CONFIG_FILE = "etc/config.xml"; public static final String DEFAULT_LOG_CONFIG_FILE = "etc/log4j.xml"; public static final String QPID_HOME = "QPID_HOME"; + public static final String QPID_WORK = "QPID_WORK"; private final Set<Integer> _ports = new HashSet<Integer>(); private final Set<Integer> _sslPorts = new HashSet<Integer>(); @@ -47,6 +48,8 @@ public class BrokerOptions private BundleContext _bundleContext; private Integer _logWatchFrequency = 0; + private String _qpidWorkFolder; + private String _qpidHomeFolder; public void addPort(final int port) { @@ -109,7 +112,7 @@ public class BrokerOptions } public String getQpidHome() { - return System.getProperty(QPID_HOME); + return _qpidHomeFolder == null? System.getProperty(QPID_HOME): _qpidHomeFolder; } public Set<Integer> getExcludedPorts(final ProtocolExclusion excludeProtocol) @@ -179,4 +182,19 @@ public class BrokerOptions Set<Integer> ports = _inclusionMap.get(includeProtocol); ports.add(port); } + + public String getQpidWork() + { + return _qpidWorkFolder; + } + + public void setQpidWork(String qpidWorkFolder) + { + _qpidWorkFolder = qpidWorkFolder; + } + + public void setQpidHome(String qpidHomeFolder) + { + _qpidHomeFolder = qpidHomeFolder; + } }
\ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ExchangeConfig.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ExchangeConfig.java index 41c51d9684..6633d93adf 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ExchangeConfig.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ExchangeConfig.java @@ -49,7 +49,12 @@ public interface ExchangeConfig extends ConfiguredObject<ExchangeConfigType, Exc long getMsgRoutes(); + long getMsgDrops(); + long getByteReceives(); long getByteRoutes(); + + long getByteDrops(); + }
\ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java index 40bafb4275..8f03383777 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/QueueConfiguration.java @@ -126,6 +126,11 @@ public class QueueConfiguration extends ConfigurationPlugin return _name; } + public String getDescription() + { + return getStringValue("description"); + } + public int getMaximumMessageAge() { return getIntValue("maximumMessageAge", _vHostConfig.getMaximumMessageAge()); @@ -226,4 +231,5 @@ public class QueueConfiguration extends ConfigurationPlugin } + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java index b48d8c5fdb..c23e58fdab 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java @@ -64,6 +64,7 @@ public class ServerConfiguration extends ConfigurationPlugin public static final long DEFAULT_HOUSEKEEPING_PERIOD = 30000L; public static final int DEFAULT_JMXPORT_REGISTRYSERVER = 8999; public static final int JMXPORT_CONNECTORSERVER_OFFSET = 100; + public static final int DEFAULT_HTTP_MANAGEMENT_PORT = 8080; public static final String QPID_HOME = "QPID_HOME"; public static final String QPID_WORK = "QPID_WORK"; @@ -75,6 +76,8 @@ public class ServerConfiguration extends ConfigurationPlugin private File _configFile; private File _vhostsFile; + private String _qpidWork; + private String _qpidHome; // Map of environment variables to config items private static final Map<String, String> envVarMap = new HashMap<String, String>(); @@ -110,6 +113,8 @@ public class ServerConfiguration extends ConfigurationPlugin envVarMap.put("QPID_MSGAUTH", "security.msg-auth"); envVarMap.put("QPID_AUTOREGISTER", "auto_register"); envVarMap.put("QPID_MANAGEMENTENABLED", "management.enabled"); + envVarMap.put("QPID_HTTPMANAGEMENTENABLED", "management.http.enabled"); + envVarMap.put("QPID_HTTPMANAGEMENTPORT", "management.http.port"); envVarMap.put("QPID_HEARTBEATDELAY", "heartbeat.delay"); envVarMap.put("QPID_HEARTBEATTIMEOUTFACTOR", "heartbeat.timeoutFactor"); envVarMap.put("QPID_MAXIMUMMESSAGEAGE", "maximumMessageAge"); @@ -511,12 +516,26 @@ public class ServerConfiguration extends ConfigurationPlugin public String getQpidWork() { - return System.getProperty(QPID_WORK, System.getProperty("java.io.tmpdir")); + if ( _qpidWork == null ) + { + return System.getProperty(QPID_WORK, System.getProperty("java.io.tmpdir")); + } + else + { + return _qpidWork; + } } public String getQpidHome() { - return System.getProperty(QPID_HOME); + if ( _qpidHome == null ) + { + return System.getProperty(QPID_HOME); + } + else + { + return _qpidHome; + } } public void setJMXPortRegistryServer(int registryServerPort) @@ -554,6 +573,16 @@ public class ServerConfiguration extends ConfigurationPlugin return getBooleanValue("management.platform-mbeanserver", true); } + public boolean getHTTPManagementEnabled() + { + return getBooleanValue("management.http.enabled", true); + } + + public int getHTTPManagementPort() + { + return getIntValue("management.http.port", 8080); + } + public String[] getVirtualHosts() { return _virtualHosts.keySet().toArray(new String[_virtualHosts.size()]); @@ -622,7 +651,7 @@ public class ServerConfiguration extends ConfigurationPlugin public boolean getManagementSSLEnabled() { - return getBooleanValue("management.ssl.enabled", true); + return getBooleanValue("management.ssl.enabled", false); } public String getManagementKeyStorePassword() @@ -636,16 +665,11 @@ public class ServerConfiguration extends ConfigurationPlugin return getBooleanValue("queue.auto_register", true); } - public boolean getManagementEnabled() + public boolean getJMXManagementEnabled() { return getBooleanValue("management.enabled", true); } - public void setManagementEnabled(boolean enabled) - { - getConfig().setProperty("management.enabled", enabled); - } - public int getHeartBeatDelay() { return getIntValue("heartbeat.delay", 5); @@ -981,4 +1005,14 @@ public class ServerConfiguration extends ConfigurationPlugin return reply == null ? null : AmqpProtocolVersion.valueOf(reply); } + + public void setQpidWork(String path) + { + _qpidWork = path; + } + + public void setQpidHome(String path) + { + _qpidHome = path; + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/connection/ConnectionRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/connection/ConnectionRegistry.java index a539743081..451754e6d8 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/connection/ConnectionRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/connection/ConnectionRegistry.java @@ -88,6 +88,13 @@ public class ConnectionRegistry implements IConnectionRegistry, Closeable } } } + synchronized (_listeners) + { + for(RegistryChangeListener listener : _listeners) + { + listener.connectionRegistered(connnection); + } + } } public void deregisterConnection(AMQConnectionModel connnection) @@ -104,6 +111,14 @@ public class ConnectionRegistry implements IConnectionRegistry, Closeable } } } + + synchronized (_listeners) + { + for(RegistryChangeListener listener : _listeners) + { + listener.connectionUnregistered(connnection); + } + } } public void addRegistryChangeListener(RegistryChangeListener listener) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java index 9493f400f2..e633ddd341 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java @@ -30,15 +30,12 @@ import org.apache.qpid.server.logging.LogSubject; import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.logging.messages.ExchangeMessages; import org.apache.qpid.server.logging.subjects.ExchangeLogSubject; -import org.apache.qpid.server.management.Managable; -import org.apache.qpid.server.management.ManagedObject; import org.apache.qpid.server.message.InboundMessage; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.BaseQueue; import org.apache.qpid.server.queue.QueueRegistry; import org.apache.qpid.server.virtualhost.VirtualHost; -import javax.management.JMException; import java.util.Collection; import java.util.Collections; import java.util.List; @@ -50,10 +47,8 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; -public abstract class AbstractExchange implements Exchange, Managable +public abstract class AbstractExchange implements Exchange { - - private AMQShortString _name; private final AtomicBoolean _closed = new AtomicBoolean(); @@ -66,9 +61,6 @@ public abstract class AbstractExchange implements Exchange, Managable private final List<Exchange.Task> _closeTaskList = new CopyOnWriteArrayList<Exchange.Task>(); - - private AbstractExchangeMBean _exchangeMbean; - /** * Whether the exchange is automatically deleted once all queues have detached from it */ @@ -86,6 +78,8 @@ public abstract class AbstractExchange implements Exchange, Managable private final AtomicLong _receivedMessageSize = new AtomicLong(); private final AtomicLong _routedMessageCount = new AtomicLong(); private final AtomicLong _routedMessageSize = new AtomicLong(); + private final AtomicLong _droppedMessageCount = new AtomicLong(); + private final AtomicLong _droppedMessageSize = new AtomicLong(); private final CopyOnWriteArrayList<Exchange.BindingListener> _listeners = new CopyOnWriteArrayList<Exchange.BindingListener>(); @@ -107,13 +101,6 @@ public abstract class AbstractExchange implements Exchange, Managable return _type.getName(); } - /** - * Concrete exchanges must implement this method in order to create the managed representation. This is - * called during initialisation (template method pattern). - * @return the MBean - */ - protected abstract AbstractExchangeMBean createMBean() throws JMException; - public void initialise(UUID id, VirtualHost host, AMQShortString name, boolean durable, int ticket, boolean autoDelete) throws AMQException { @@ -126,26 +113,12 @@ public abstract class AbstractExchange implements Exchange, Managable _id = id; getConfigStore().addConfiguredObject(this); - createAndRegisterMBean(); _logSubject = new ExchangeLogSubject(this, this.getVirtualHost()); // Log Exchange creation CurrentActor.get().message(ExchangeMessages.CREATED(String.valueOf(getTypeShortString()), String.valueOf(name), durable)); } - private void createAndRegisterMBean() - { - try - { - _exchangeMbean = createMBean(); - _exchangeMbean.register(); - } - catch (JMException e) - { - throw new RuntimeException("Failed to register mbean",e); - } - } - public ConfigStore getConfigStore() { return getVirtualHost().getConfigStore(); @@ -171,10 +144,6 @@ public abstract class AbstractExchange implements Exchange, Managable if(_closed.compareAndSet(false,true)) { - if (_exchangeMbean != null) - { - _exchangeMbean.unregister(); - } getConfigStore().removeConfiguredObject(this); if(_alternateExchange != null) { @@ -196,11 +165,6 @@ public abstract class AbstractExchange implements Exchange, Managable return getClass().getSimpleName() + "[" + getNameShortString() +"]"; } - public ManagedObject getManagedObject() - { - return _exchangeMbean; - } - public VirtualHost getVirtualHost() { return _virtualHost; @@ -359,6 +323,11 @@ public abstract class AbstractExchange implements Exchange, Managable _routedMessageCount.incrementAndGet(); _routedMessageSize.addAndGet(message.getSize()); } + else + { + _droppedMessageCount.incrementAndGet(); + _droppedMessageSize.addAndGet(message.getSize()); + } return queues; } @@ -374,6 +343,11 @@ public abstract class AbstractExchange implements Exchange, Managable return _routedMessageCount.get(); } + public long getMsgDrops() + { + return _droppedMessageCount.get(); + } + public long getByteReceives() { return _receivedMessageSize.get(); @@ -384,6 +358,11 @@ public abstract class AbstractExchange implements Exchange, Managable return _routedMessageSize.get(); } + public long getByteDrops() + { + return _droppedMessageSize.get(); + } + public long getCreateTime() { return _createTime; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchangeMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchangeMBean.java deleted file mode 100644 index 034331abd9..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchangeMBean.java +++ /dev/null @@ -1,215 +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.exchange; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.management.common.mbeans.ManagedExchange; -import org.apache.qpid.server.logging.actors.CurrentActor; -import org.apache.qpid.server.logging.actors.ManagementActor; -import org.apache.qpid.server.management.AMQManagedObject; -import org.apache.qpid.server.management.ManagedObject; -import org.apache.qpid.server.management.ManagedObjectRegistry; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.virtualhost.VirtualHost; - -import javax.management.JMException; -import javax.management.MBeanException; -import javax.management.MalformedObjectNameException; -import javax.management.NotCompliantMBeanException; -import javax.management.ObjectName; -import javax.management.openmbean.ArrayType; -import javax.management.openmbean.CompositeType; -import javax.management.openmbean.OpenDataException; -import javax.management.openmbean.OpenType; -import javax.management.openmbean.SimpleType; -import javax.management.openmbean.TabularType; -import java.util.Collections; - - -/** - * Abstract MBean class. This has some of the methods implemented from - * management intrerface for exchanges. Any implementaion of an - * Exchange MBean should extend this class. - */ -public abstract class AbstractExchangeMBean<T extends AbstractExchange> extends AMQManagedObject implements ManagedExchange -{ - // open mbean data types for representing exchange bindings - private OpenType[] _bindingItemTypes; - private CompositeType _bindingDataType; - private TabularType _bindinglistDataType; - - - private T _exchange; - - public AbstractExchangeMBean(final T abstractExchange) throws NotCompliantMBeanException - { - super(ManagedExchange.class, ManagedExchange.TYPE); - _exchange = abstractExchange; - } - - protected void init() throws OpenDataException - { - _bindingItemTypes = new OpenType[2]; - _bindingItemTypes[0] = SimpleType.STRING; - _bindingItemTypes[1] = new ArrayType(1, SimpleType.STRING); - _bindingDataType = new CompositeType("Exchange Binding", "Binding key and Queue names", - COMPOSITE_ITEM_NAMES.toArray(new String[COMPOSITE_ITEM_NAMES.size()]), - COMPOSITE_ITEM_DESCRIPTIONS.toArray(new String[COMPOSITE_ITEM_DESCRIPTIONS.size()]), _bindingItemTypes); - _bindinglistDataType = new TabularType("Exchange Bindings", "Exchange Bindings for " + getName(), - _bindingDataType, TABULAR_UNIQUE_INDEX.toArray(new String[TABULAR_UNIQUE_INDEX.size()])); - } - - public ManagedObject getParentObject() - { - return _exchange.getVirtualHost().getManagedObject(); - } - - public T getExchange() - { - return _exchange; - } - - - public String getObjectInstanceName() - { - return ObjectName.quote(_exchange.getName()); - } - - public String getName() - { - return _exchange.getName(); - } - - public String getExchangeType() - { - return _exchange.getTypeShortString().toString(); - } - - public Integer getTicketNo() - { - return _exchange.getTicket(); - } - - public boolean isDurable() - { - return _exchange.isDurable(); - } - - public boolean isAutoDelete() - { - return _exchange.isAutoDelete(); - } - - // Added exchangetype in the object name lets maangement apps to do any customization required - public ObjectName getObjectName() throws MalformedObjectNameException - { - String objNameString = super.getObjectName().toString(); - objNameString = objNameString + ",ExchangeType=" + getExchangeType(); - return new ObjectName(objNameString); - } - - protected ManagedObjectRegistry getManagedObjectRegistry() - { - return ApplicationRegistry.getInstance().getManagedObjectRegistry(); - } - - public void createNewBinding(String queueName, String binding) throws JMException - { - VirtualHost vhost = getExchange().getVirtualHost(); - AMQQueue queue = vhost.getQueueRegistry().getQueue(new AMQShortString(queueName)); - if (queue == null) - { - throw new JMException("Queue \"" + queueName + "\" is not registered with the virtualhost."); - } - - CurrentActor.set(new ManagementActor(getLogActor().getRootMessageLogger())); - try - { - vhost.getBindingFactory().addBinding(binding,queue,getExchange(),null); - } - catch (AMQException ex) - { - JMException jme = new JMException(ex.toString()); - throw new MBeanException(jme, "Error creating new binding " + binding); - } - CurrentActor.remove(); - } - - /** - * Removes a queue binding from the exchange. - * - * @see org.apache.qpid.server.binding.BindingFactory#removeBinding(String, AMQQueue, Exchange, java.util.Map) - */ - public void removeBinding(String queueName, String binding) throws JMException - { - VirtualHost vhost = getExchange().getVirtualHost(); - AMQQueue queue = vhost.getQueueRegistry().getQueue(new AMQShortString(queueName)); - if (queue == null) - { - throw new JMException("Queue \"" + queueName + "\" is not registered with the virtualhost."); - } - - CurrentActor.set(new ManagementActor(getLogActor().getRootMessageLogger())); - try - { - vhost.getBindingFactory().removeBinding(binding, queue, _exchange, Collections.<String, Object>emptyMap()); - } - catch (AMQException ex) - { - JMException jme = new JMException(ex.toString()); - throw new MBeanException(jme, "Error removing binding " + binding); - } - CurrentActor.remove(); - } - - - protected OpenType[] getBindingItemTypes() - { - return _bindingItemTypes; - } - - protected void setBindingItemTypes(OpenType[] bindingItemTypes) - { - _bindingItemTypes = bindingItemTypes; - } - - protected CompositeType getBindingDataType() - { - return _bindingDataType; - } - - protected void setBindingDataType(CompositeType bindingDataType) - { - _bindingDataType = bindingDataType; - } - - protected TabularType getBindinglistDataType() - { - return _bindinglistDataType; - } - - protected void setBindinglistDataType(TabularType bindinglistDataType) - { - _bindinglistDataType = bindinglistDataType; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java index bf4184bf0b..baf9cc3d09 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DefaultExchangeRegistry.java @@ -29,7 +29,9 @@ import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.server.store.DurableConfigurationStore; import org.apache.qpid.server.virtualhost.VirtualHost; +import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; @@ -46,6 +48,8 @@ public class DefaultExchangeRegistry implements ExchangeRegistry private Exchange _defaultExchange; private VirtualHost _host; + private final Collection<RegistryChangeListener> _listeners = + Collections.synchronizedCollection(new ArrayList<RegistryChangeListener>()); public DefaultExchangeRegistry(VirtualHost host) { @@ -68,6 +72,14 @@ public class DefaultExchangeRegistry implements ExchangeRegistry { _exchangeMap.put(exchange.getNameShortString(), exchange); _exchangeMapStr.put(exchange.getNameShortString().toString(), exchange); + synchronized (_listeners) + { + for(RegistryChangeListener listener : _listeners) + { + listener.exchangeRegistered(exchange); + } + + } } public void setDefaultExchange(Exchange exchange) @@ -114,6 +126,15 @@ public class DefaultExchangeRegistry implements ExchangeRegistry getDurableConfigurationStore().removeExchange(e); } e.close(); + + synchronized (_listeners) + { + for(RegistryChangeListener listener : _listeners) + { + listener.exchangeUnregistered(exchange); + } + } + } else { @@ -126,6 +147,16 @@ public class DefaultExchangeRegistry implements ExchangeRegistry unregisterExchange(new AMQShortString(name), inUse); } + public Collection<Exchange> getExchanges() + { + return new ArrayList<Exchange>(_exchangeMap.values()); + } + + public void addRegistryChangeListener(RegistryChangeListener listener) + { + _listeners.add(listener); + } + public Exchange getExchange(AMQShortString name) { if ((name == null) || name.length() == 0) @@ -158,16 +189,14 @@ public class DefaultExchangeRegistry implements ExchangeRegistry { final Exchange exchange = getExchange(exchangeName); - if (exchange instanceof AbstractExchange) + //TODO: this is a bit of a hack, what if the listeners aren't aware + //that we are just unregistering the MBean because of HA, and aren't + //actually removing the exchange as such. + synchronized (_listeners) { - AbstractExchange abstractExchange = (AbstractExchange) exchange; - try - { - abstractExchange.getManagedObject().unregister(); - } - catch (AMQException e) + for(RegistryChangeListener listener : _listeners) { - LOGGER.warn("Failed to unregister mbean", e); + listener.exchangeUnregistered(exchange); } } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java index af9322764a..92326412c1 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java @@ -127,11 +127,6 @@ public class DirectExchange extends AbstractExchange super(TYPE); } - protected AbstractExchangeMBean createMBean() throws JMException - { - return new DirectExchangeMBean(this); - } - public List<? extends BaseQueue> doRoute(InboundMessage payload) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchangeMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchangeMBean.java deleted file mode 100644 index 0bfaf7035d..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchangeMBean.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.exchange; - -import org.apache.qpid.management.common.mbeans.annotations.MBeanConstructor; -import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription; -import org.apache.qpid.server.binding.Binding; - -import javax.management.JMException; -import javax.management.openmbean.CompositeData; -import javax.management.openmbean.CompositeDataSupport; -import javax.management.openmbean.OpenDataException; -import javax.management.openmbean.TabularData; -import javax.management.openmbean.TabularDataSupport; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * MBean class implementing the management interfaces. - */ -@MBeanDescription("Management Bean for Direct Exchange") -final class DirectExchangeMBean extends AbstractExchangeMBean<DirectExchange> -{ - @MBeanConstructor("Creates an MBean for AMQ direct exchange") - public DirectExchangeMBean(final DirectExchange exchange) throws JMException - { - super(exchange); - - init(); - } - - public TabularData bindings() throws OpenDataException - { - TabularDataSupport bindingList = new TabularDataSupport(getBindinglistDataType()); - - Map<String, List<String>> bindingMap = new HashMap<String, List<String>>(); - - for (Binding binding : getExchange().getBindings()) - { - String key = binding.getBindingKey(); - List<String> queueList = bindingMap.get(key); - if(queueList == null) - { - queueList = new ArrayList<String>(); - bindingMap.put(key, queueList); - } - queueList.add(binding.getQueue().getNameShortString().toString()); - - } - - for(Map.Entry<String, List<String>> entry : bindingMap.entrySet()) - { - Object[] bindingItemValues = {entry.getKey(), entry.getValue().toArray(new String[0])}; - CompositeData bindingData = new CompositeDataSupport(getBindingDataType(), - COMPOSITE_ITEM_NAMES.toArray(new String[COMPOSITE_ITEM_NAMES.size()]), - bindingItemValues); - bindingList.put(bindingData); - } - - return bindingList; - } - - - -}// End of MBean class diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java index 795ae2e140..692a2b2b0d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/ExchangeRegistry.java @@ -7,9 +7,9 @@ * 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 @@ -57,4 +57,14 @@ public interface ExchangeRegistry void clearAndUnregisterMbeans(); Exchange getExchange(UUID exchangeId); + + Collection<Exchange> getExchanges(); + + void addRegistryChangeListener(RegistryChangeListener listener); + + interface RegistryChangeListener + { + void exchangeRegistered(Exchange exchange); + void exchangeUnregistered(Exchange exchange); + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java index 5ebcfd095f..5f4998f77f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchange.java @@ -48,11 +48,6 @@ public class FanoutExchange extends AbstractExchange */ private final ConcurrentHashMap<AMQQueue,Integer> _queues = new ConcurrentHashMap<AMQQueue,Integer>(); - protected AbstractExchangeMBean createMBean() throws JMException - { - return new FanoutExchangeMBean(this); - } - public static final ExchangeType<FanoutExchange> TYPE = new ExchangeType<FanoutExchange>() { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchangeMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchangeMBean.java deleted file mode 100644 index 61e23c896c..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/FanoutExchangeMBean.java +++ /dev/null @@ -1,74 +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.exchange; - -import org.apache.qpid.management.common.mbeans.annotations.MBeanConstructor; -import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription; -import org.apache.qpid.server.binding.Binding; - -import javax.management.JMException; -import javax.management.openmbean.CompositeData; -import javax.management.openmbean.CompositeDataSupport; -import javax.management.openmbean.OpenDataException; -import javax.management.openmbean.TabularData; -import javax.management.openmbean.TabularDataSupport; -import java.util.ArrayList; - -/** - * MBean class implementing the management interfaces. - */ -@MBeanDescription("Management Bean for Fanout Exchange") -final class FanoutExchangeMBean extends AbstractExchangeMBean<FanoutExchange> -{ - private static final String BINDING_KEY_SUBSTITUTE = "*"; - - @MBeanConstructor("Creates an MBean for AMQ fanout exchange") - public FanoutExchangeMBean(final FanoutExchange exchange) throws JMException - { - super(exchange); - init(); - } - - public TabularData bindings() throws OpenDataException - { - - TabularDataSupport bindingList = new TabularDataSupport(getBindinglistDataType()); - - - ArrayList<String> queueNames = new ArrayList<String>(); - - for (Binding binding : getExchange().getBindings()) - { - String queueName = binding.getQueue().getNameShortString().toString(); - queueNames.add(queueName); - } - - Object[] bindingItemValues = {BINDING_KEY_SUBSTITUTE, queueNames.toArray(new String[0])}; - CompositeData bindingData = new CompositeDataSupport(getBindingDataType(), - COMPOSITE_ITEM_NAMES.toArray(new String[COMPOSITE_ITEM_NAMES.size()]), - bindingItemValues); - bindingList.put(bindingData); - - return bindingList; - } - - -} // End of MBean class diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java index 16ba3c0431..6bad59c2ae 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchange.java @@ -227,11 +227,6 @@ public class HeadersExchange extends AbstractExchange return !getBindings().isEmpty(); } - protected AbstractExchangeMBean createMBean() throws JMException - { - return new HeadersExchangeMBean(this); - } - protected void onBind(final Binding binding) { String bindingKey = binding.getBindingKey(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchangeMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchangeMBean.java deleted file mode 100644 index 395c6c8a91..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/HeadersExchangeMBean.java +++ /dev/null @@ -1,158 +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.exchange; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.management.common.mbeans.annotations.MBeanConstructor; -import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription; -import org.apache.qpid.server.binding.Binding; -import org.apache.qpid.server.logging.actors.CurrentActor; -import org.apache.qpid.server.logging.actors.ManagementActor; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.virtualhost.VirtualHost; - -import javax.management.JMException; -import javax.management.MBeanException; -import javax.management.openmbean.ArrayType; -import javax.management.openmbean.CompositeData; -import javax.management.openmbean.CompositeDataSupport; -import javax.management.openmbean.CompositeType; -import javax.management.openmbean.OpenDataException; -import javax.management.openmbean.OpenType; -import javax.management.openmbean.SimpleType; -import javax.management.openmbean.TabularData; -import javax.management.openmbean.TabularDataSupport; -import javax.management.openmbean.TabularType; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * HeadersExchangeMBean class implements the management interface for the - * Header Exchanges. - */ -@MBeanDescription("Management Bean for Headers Exchange") -final class HeadersExchangeMBean extends AbstractExchangeMBean<HeadersExchange> -{ - - @MBeanConstructor("Creates an MBean for AMQ Headers exchange") - public HeadersExchangeMBean(final HeadersExchange headersExchange) throws JMException - { - super(headersExchange); - init(); - } - - /** - * initialises the OpenType objects. - */ - protected void init() throws OpenDataException - { - - setBindingItemTypes(new OpenType[3]); - getBindingItemTypes()[0] = SimpleType.INTEGER; - getBindingItemTypes()[1] = SimpleType.STRING; - getBindingItemTypes()[2] = new ArrayType(1, SimpleType.STRING); - setBindingDataType(new CompositeType("Exchange Binding", "Queue name and header bindings", - HEADERS_COMPOSITE_ITEM_NAMES.toArray(new String[HEADERS_COMPOSITE_ITEM_NAMES.size()]), - HEADERS_COMPOSITE_ITEM_DESC.toArray(new String[HEADERS_COMPOSITE_ITEM_DESC.size()]), getBindingItemTypes())); - setBindinglistDataType(new TabularType("Exchange Bindings", "List of exchange bindings for " + getName(), - getBindingDataType(), HEADERS_TABULAR_UNIQUE_INDEX.toArray(new String[HEADERS_TABULAR_UNIQUE_INDEX.size()]))); - } - - public TabularData bindings() throws OpenDataException - { - TabularDataSupport bindingList = new TabularDataSupport(getBindinglistDataType()); - int count = 1; - for (Binding binding : getExchange().getBindings()) - { - - String queueName = binding.getQueue().getNameShortString().toString(); - - - Map<String,Object> headerMappings = binding.getArguments(); - final List<String> mappingList = new ArrayList<String>(); - - if(headerMappings != null) - { - for(Map.Entry<String,Object> entry : headerMappings.entrySet()) - { - - mappingList.add(entry.getKey() + "=" + entry.getValue()); - } - } - - - Object[] bindingItemValues = {count++, queueName, mappingList.toArray(new String[0])}; - CompositeData bindingData = new CompositeDataSupport(getBindingDataType(), - HEADERS_COMPOSITE_ITEM_NAMES.toArray(new String[HEADERS_COMPOSITE_ITEM_NAMES.size()]), bindingItemValues); - bindingList.put(bindingData); - } - - return bindingList; - } - - @Override - public void createNewBinding(String queueName, String binding) throws JMException - { - VirtualHost vhost = getExchange().getVirtualHost(); - AMQQueue queue = vhost.getQueueRegistry().getQueue(new AMQShortString(queueName)); - if (queue == null) - { - throw new JMException("Queue \"" + queueName + "\" is not registered with the virtualhost."); - } - - CurrentActor.set(new ManagementActor(getLogActor().getRootMessageLogger())); - - final Map<String,Object> arguments = new HashMap<String, Object>(); - final String[] bindings = binding.split(","); - for (int i = 0; i < bindings.length; i++) - { - final String[] keyAndValue = bindings[i].split("="); - if (keyAndValue == null || keyAndValue.length == 0 || keyAndValue.length > 2 || keyAndValue[0].length() == 0) - { - throw new JMException("Format for headers binding should be \"<attribute1>=<value1>,<attribute2>=<value2>\" "); - } - - if(keyAndValue.length == 1) - { - //no value was given, only a key. Use an empty value to signal match on key presence alone - arguments.put(keyAndValue[0], ""); - } - else - { - arguments.put(keyAndValue[0], keyAndValue[1]); - } - } - try - { - vhost.getBindingFactory().addBinding(binding,queue,getExchange(),arguments); - } - catch (AMQException ex) - { - JMException jme = new JMException(ex.toString()); - throw new MBeanException(jme, "Error creating new binding " + binding); - } - CurrentActor.remove(); - } - -} // End of MBean class diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java index 7ea7a41826..480d4e4215 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java @@ -403,11 +403,6 @@ public class TopicExchange extends AbstractExchange } } - protected AbstractExchangeMBean createMBean() throws JMException - { - return new TopicExchangeMBean(this); - } - private Collection<AMQQueue> getMatchedQueues(InboundMessage message, AMQShortString routingKey) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchangeMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchangeMBean.java deleted file mode 100644 index 481a377fc4..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchangeMBean.java +++ /dev/null @@ -1,81 +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.exchange; - -import org.apache.qpid.management.common.mbeans.annotations.MBeanConstructor; -import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription; -import org.apache.qpid.server.binding.Binding; - -import javax.management.JMException; -import javax.management.openmbean.CompositeData; -import javax.management.openmbean.CompositeDataSupport; -import javax.management.openmbean.OpenDataException; -import javax.management.openmbean.TabularData; -import javax.management.openmbean.TabularDataSupport; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** TopicExchangeMBean class implements the management interface for the Topic exchanges. */ -@MBeanDescription("Management Bean for Topic Exchange") -final class TopicExchangeMBean extends AbstractExchangeMBean<TopicExchange> -{ - private TopicExchange _topicExchange; - - @MBeanConstructor("Creates an MBean for AMQ topic exchange") - public TopicExchangeMBean(final TopicExchange topicExchange) throws JMException - { - super(topicExchange); - init(); - } - - /** returns exchange bindings in tabular form */ - public TabularData bindings() throws OpenDataException - { - TabularDataSupport bindingList = new TabularDataSupport(getBindinglistDataType()); - Map<String, List<String>> bindingData = new HashMap<String, List<String>>(); - for (Binding binding : getExchange().getBindings()) - { - String key = binding.getBindingKey(); - List<String> queueNames = bindingData.get(key); - if(queueNames == null) - { - queueNames = new ArrayList<String>(); - bindingData.put(key, queueNames); - } - queueNames.add(binding.getQueue().getNameShortString().toString()); - - } - for(Map.Entry<String, List<String>> entry : bindingData.entrySet()) - { - Object[] bindingItemValues = {entry.getKey(), entry.getValue().toArray(new String[entry.getValue().size()]) }; - CompositeData bindingCompositeData = - new CompositeDataSupport(getBindingDataType(), - COMPOSITE_ITEM_NAMES.toArray(new String[COMPOSITE_ITEM_NAMES.size()]), - bindingItemValues); - bindingList.put(bindingCompositeData); - } - - return bindingList; - } - -} // End of MBean class diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/information/management/ServerInformationMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/information/management/ServerInformationMBean.java deleted file mode 100644 index 4d395f625a..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/information/management/ServerInformationMBean.java +++ /dev/null @@ -1,145 +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.information.management; - -import org.apache.qpid.common.QpidProperties; -import org.apache.qpid.management.common.mbeans.ServerInformation; -import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription; -import org.apache.qpid.server.management.AMQManagedObject; -import org.apache.qpid.server.registry.ApplicationRegistry; - -import javax.management.JMException; -import java.io.IOException; - -/** MBean class for the ServerInformationMBean. */ -@MBeanDescription("Server Information Interface") -public class ServerInformationMBean extends AMQManagedObject implements ServerInformation -{ - private String buildVersion; - private String productVersion; - private ApplicationRegistry registry; - - public ServerInformationMBean(ApplicationRegistry applicationRegistry) throws JMException - { - super(ServerInformation.class, ServerInformation.TYPE); - - registry = applicationRegistry; - buildVersion = QpidProperties.getBuildVersion(); - productVersion = QpidProperties.getReleaseVersion(); - } - - public String getObjectInstanceName() - { - return ServerInformation.TYPE; - } - - public Integer getManagementApiMajorVersion() throws IOException - { - return QPID_JMX_API_MAJOR_VERSION; - } - - public Integer getManagementApiMinorVersion() throws IOException - { - return QPID_JMX_API_MINOR_VERSION; - } - - public String getBuildVersion() throws IOException - { - return buildVersion; - } - - public String getProductVersion() throws IOException - { - return productVersion; - } - - - public void resetStatistics() throws Exception - { - registry.resetStatistics(); - } - - public double getPeakMessageDeliveryRate() - { - return registry.getMessageDeliveryStatistics().getPeak(); - } - - public double getPeakDataDeliveryRate() - { - return registry.getDataDeliveryStatistics().getPeak(); - } - - public double getMessageDeliveryRate() - { - return registry.getMessageDeliveryStatistics().getRate(); - } - - public double getDataDeliveryRate() - { - return registry.getDataDeliveryStatistics().getRate(); - } - - public long getTotalMessagesDelivered() - { - return registry.getMessageDeliveryStatistics().getTotal(); - } - - public long getTotalDataDelivered() - { - return registry.getDataDeliveryStatistics().getTotal(); - } - - public double getPeakMessageReceiptRate() - { - return registry.getMessageReceiptStatistics().getPeak(); - } - - public double getPeakDataReceiptRate() - { - return registry.getDataReceiptStatistics().getPeak(); - } - - public double getMessageReceiptRate() - { - return registry.getMessageReceiptStatistics().getRate(); - } - - public double getDataReceiptRate() - { - return registry.getDataReceiptStatistics().getRate(); - } - - public long getTotalMessagesReceived() - { - return registry.getMessageReceiptStatistics().getTotal(); - } - - public long getTotalDataReceived() - { - return registry.getDataReceiptStatistics().getTotal(); - } - - public boolean isStatisticsEnabled() - { - return registry.isStatisticsEnabled(); - } - -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/LogRecorder.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/LogRecorder.java new file mode 100644 index 0000000000..a1065319d3 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/LogRecorder.java @@ -0,0 +1,210 @@ +/* + * 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.logging; + +import java.util.Iterator; +import org.apache.log4j.Appender; +import org.apache.log4j.Layout; +import org.apache.log4j.Logger; +import org.apache.log4j.spi.ErrorHandler; +import org.apache.log4j.spi.Filter; +import org.apache.log4j.spi.LoggingEvent; + +public class LogRecorder implements Appender, Iterable<LogRecorder.Record> +{ + private ErrorHandler _errorHandler; + private Filter _filter; + private String _name; + private long _recordId; + + private final int _bufferSize = 4096; + private final int _mask = _bufferSize - 1; + private Record[] _records = new Record[_bufferSize]; + + + public static class Record + { + private final long _id; + private final String _logger; + private final long _timestamp; + private final String _threadName; + private final String _level; + private final String _message; + + + public Record(long id, LoggingEvent event) + { + _id = id; + _logger = event.getLoggerName(); + _timestamp = event.timeStamp; + _threadName = event.getThreadName(); + _level = event.getLevel().toString(); + _message = event.getRenderedMessage(); + } + + public long getId() + { + return _id; + } + + public long getTimestamp() + { + return _timestamp; + } + + public String getThreadName() + { + return _threadName; + } + + public String getLevel() + { + return _level; + } + + public String getMessage() + { + return _message; + } + + public String getLogger() + { + return _logger; + } + } + + public LogRecorder() + { + + Logger.getRootLogger().addAppender(this); + } + + @Override + public void addFilter(Filter filter) + { + _filter = filter; + } + + @Override + public void clearFilters() + { + _filter = null; + } + + @Override + public void close() + { + //TODO - Implement + } + + @Override + public synchronized void doAppend(LoggingEvent loggingEvent) + { + _records[((int) (_recordId & _mask))] = new Record(_recordId, loggingEvent); + _recordId++; + } + + @Override + public ErrorHandler getErrorHandler() + { + return _errorHandler; + } + + @Override + public Filter getFilter() + { + return _filter; + } + + @Override + public Layout getLayout() + { + return null; + } + + @Override + public String getName() + { + return _name; + } + + @Override + public boolean requiresLayout() + { + return false; + } + + @Override + public void setErrorHandler(ErrorHandler errorHandler) + { + _errorHandler = errorHandler; + } + + @Override + public void setLayout(Layout layout) + { + + } + + @Override + public void setName(String name) + { + _name = name; + } + + @Override + public Iterator<Record> iterator() + { + return new RecordIterator(Math.max(_recordId-_bufferSize, 0l)); + } + + private class RecordIterator implements Iterator<Record> + { + private long _id; + + public RecordIterator(long currentRecordId) + { + _id = currentRecordId; + } + + @Override + public boolean hasNext() + { + return _id < _recordId; + } + + @Override + public Record next() + { + Record record = _records[((int) (_id & _mask))]; + while(_id < _recordId-_bufferSize) + { + _id = _recordId-_bufferSize; + record = _records[((int) (_id & _mask))]; + } + _id++; + return record; + } + + @Override + public void remove() + { + throw new UnsupportedOperationException(); + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/AbstractAMQManagedConnectionObject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/AbstractAMQManagedConnectionObject.java deleted file mode 100644 index 6cfc827046..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/AbstractAMQManagedConnectionObject.java +++ /dev/null @@ -1,90 +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.management; - -import org.apache.qpid.management.common.mbeans.ManagedConnection; - -import javax.management.JMException; -import javax.management.MBeanNotificationInfo; -import javax.management.NotCompliantMBeanException; -import javax.management.Notification; -import javax.management.ObjectName; -import javax.management.monitor.MonitorNotification; -import javax.management.openmbean.CompositeType; -import javax.management.openmbean.OpenType; -import javax.management.openmbean.SimpleType; -import javax.management.openmbean.TabularType; - -public abstract class AbstractAMQManagedConnectionObject extends AMQManagedObject implements ManagedConnection -{ - private final String _name; - - protected static final OpenType[] _channelAttributeTypes = { SimpleType.INTEGER, SimpleType.BOOLEAN, SimpleType.STRING, SimpleType.INTEGER, SimpleType.BOOLEAN }; - protected static final CompositeType _channelType; - protected static final TabularType _channelsType; - - protected static final String BROKER_MANAGEMENT_CONSOLE_HAS_CLOSED_THE_CONNECTION_STR = - "Broker Management Console has closed the connection."; - - static - { - try - { - _channelType = new CompositeType("Channel", "Channel Details", COMPOSITE_ITEM_NAMES_DESC.toArray(new String[COMPOSITE_ITEM_NAMES_DESC.size()]), - COMPOSITE_ITEM_NAMES_DESC.toArray(new String[COMPOSITE_ITEM_NAMES_DESC.size()]), _channelAttributeTypes); - _channelsType = new TabularType("Channels", "Channels", _channelType, (String[]) TABULAR_UNIQUE_INDEX.toArray(new String[TABULAR_UNIQUE_INDEX.size()])); - } - catch (JMException ex) - { - // This is not expected to ever occur. - throw new RuntimeException("Got JMException in static initializer.", ex); - } - } - - protected AbstractAMQManagedConnectionObject(final String remoteAddress) throws NotCompliantMBeanException - { - super(ManagedConnection.class, ManagedConnection.TYPE); - _name = "anonymous".equals(remoteAddress) ? (remoteAddress + hashCode()) : remoteAddress; - } - - public String getObjectInstanceName() - { - return ObjectName.quote(_name); - } - - public void notifyClients(String notificationMsg) - { - final Notification n = new Notification(MonitorNotification.THRESHOLD_VALUE_EXCEEDED, this, incrementAndGetSequenceNumber(), - System.currentTimeMillis(), notificationMsg); - getBroadcaster().sendNotification(n); - } - - @Override - public MBeanNotificationInfo[] getNotificationInfo() - { - String[] notificationTypes = new String[] { MonitorNotification.THRESHOLD_VALUE_EXCEEDED }; - String name = MonitorNotification.class.getName(); - String description = "Channel count has reached threshold value"; - MBeanNotificationInfo info1 = new MBeanNotificationInfo(notificationTypes, name, description); - - return new MBeanNotificationInfo[] { info1 }; - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/AMQMessageHeader.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/AMQMessageHeader.java index faac14f8a7..63bd1e45a0 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/AMQMessageHeader.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/AMQMessageHeader.java @@ -20,6 +20,7 @@ */ package org.apache.qpid.server.message; +import java.util.Collection; import java.util.Set; public interface AMQMessageHeader @@ -28,6 +29,10 @@ public interface AMQMessageHeader long getExpiration(); + String getUserId(); + + String getAppId(); + String getMessageId(); String getMimeType(); @@ -52,4 +57,5 @@ public interface AMQMessageHeader boolean containsHeader(String name); + Collection<String> getHeaderNames(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/ContentHeaderBodyAdapter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/ContentHeaderBodyAdapter.java index e87b67d242..01c1021070 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/ContentHeaderBodyAdapter.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/ContentHeaderBodyAdapter.java @@ -20,6 +20,7 @@ */ package org.apache.qpid.server.message; +import java.util.Collection; import org.apache.qpid.framing.BasicContentHeaderProperties; import org.apache.qpid.framing.ContentHeaderBody; import org.apache.qpid.framing.FieldTable; @@ -50,6 +51,16 @@ public class ContentHeaderBodyAdapter implements AMQMessageHeader return getProperties().getExpiration(); } + public String getUserId() + { + return getProperties().getUserIdAsString(); + } + + public String getAppId() + { + return getProperties().getAppIdAsString(); + } + public String getMessageId() { return getProperties().getMessageIdAsString(); @@ -117,6 +128,13 @@ public class ContentHeaderBodyAdapter implements AMQMessageHeader return true; } + @Override + public Collection<String> getHeaderNames() + { + FieldTable ft = getProperties().getHeaders(); + return ft.keys(); + } + public boolean containsHeader(String name) { FieldTable ft = getProperties().getHeaders(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData.java index 583f0c09a7..e890bf5ef8 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData.java @@ -20,6 +20,7 @@ */ package org.apache.qpid.server.message; +import java.util.Collection; import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.BasicContentHeaderProperties; @@ -242,6 +243,16 @@ public class MessageMetaData implements StorableMessageMetaData return (BasicContentHeaderProperties) getContentHeaderBody().getProperties(); } + public String getUserId() + { + return getProperties().getUserIdAsString(); + } + + public String getAppId() + { + return getProperties().getAppIdAsString(); + } + public String getCorrelationId() { return getProperties().getCorrelationIdAsString(); @@ -318,6 +329,12 @@ public class MessageMetaData implements StorableMessageMetaData return true; } + @Override + public Collection<String> getHeaderNames() + { + return getProperties().getHeaders().keys(); + } + public boolean containsHeader(String name) { FieldTable ft = getProperties().getHeaders(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData_1_0.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData_1_0.java index 7d030fe711..2cc1a92853 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData_1_0.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData_1_0.java @@ -21,11 +21,7 @@ package org.apache.qpid.server.message; import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; import org.apache.qpid.amqp_1_0.codec.ValueHandler; import org.apache.qpid.amqp_1_0.messaging.SectionDecoder; import org.apache.qpid.amqp_1_0.type.AmqpErrorException; @@ -486,6 +482,18 @@ public class MessageMetaData_1_0 implements StorableMessageMetaData return null; //TODO } + public String getAppId() + { + //TODO + return null; + } + + public String getUserId() + { + // TODO + return null; + } + public Object getHeader(final String name) { return _appProperties == null ? null : _appProperties.get(name); @@ -508,6 +516,16 @@ public class MessageMetaData_1_0 implements StorableMessageMetaData return true; } + @Override + public Collection<String> getHeaderNames() + { + if(_appProperties == null) + { + return Collections.emptySet(); + } + return Collections.unmodifiableCollection(_appProperties.keySet()); + } + public boolean containsHeader(final String name) { return _appProperties != null && _appProperties.containsKey(name); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferHeader.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferHeader.java index 126e7c28cb..91384f7c22 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferHeader.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferHeader.java @@ -20,14 +20,11 @@ */ package org.apache.qpid.server.message; +import java.util.*; import org.apache.qpid.transport.DeliveryProperties; import org.apache.qpid.transport.MessageDeliveryPriority; import org.apache.qpid.transport.MessageProperties; -import java.util.Map; -import java.util.Set; -import java.util.UUID; - class MessageTransferHeader implements AMQMessageHeader { @@ -60,10 +57,22 @@ class MessageTransferHeader implements AMQMessageHeader return _deliveryProps == null ? 0L : _deliveryProps.getExpiration(); } + public String getUserId() + { + byte[] userIdBytes = _messageProps == null ? null : _messageProps.getUserId(); + return userIdBytes == null ? null : new String(userIdBytes); + } + + public String getAppId() + { + byte[] appIdBytes = _messageProps == null ? null : _messageProps.getAppId(); + return appIdBytes == null ? null : new String(appIdBytes); + } + public String getMessageId() { UUID id = _messageProps == null ? null : _messageProps.getMessageId(); - + return id == null ? null : String.valueOf(id); } @@ -93,7 +102,7 @@ class MessageTransferHeader implements AMQMessageHeader public String getType() { Object type = getHeader(JMS_TYPE); - return type instanceof String ? (String) type : null; + return type instanceof String ? (String) type : null; } public String getReplyTo() @@ -145,6 +154,14 @@ class MessageTransferHeader implements AMQMessageHeader } + @Override + public Collection<String> getHeaderNames() + { + Map<String, Object> appHeaders = _messageProps == null ? null : _messageProps.getApplicationHeaders(); + return appHeaders != null ? Collections.unmodifiableCollection(appHeaders.keySet()) : Collections.EMPTY_SET ; + + } + public boolean containsHeader(String name) { Map<String, Object> appHeaders = _messageProps == null ? null : _messageProps.getApplicationHeaders(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Attribute.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Attribute.java new file mode 100644 index 0000000000..4fccf47e0e --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Attribute.java @@ -0,0 +1,199 @@ +/* + * + * 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.model; + +public abstract class Attribute<C extends ConfiguredObject, T> +{ + private final String _name; + public Attribute(String name) + { + _name = name; + } + + public String getName() + { + return _name; + } + + abstract public Class<T> getType(); + + public T getValue(C configuredObject) + { + Object o = configuredObject.getAttribute(_name); + if(getType().isInstance(o)) + { + return (T) o; + } + return null; + } + + public T setValue(T expected, T desired, C configuredObject) + { + return (T) configuredObject.setAttribute(_name, expected, desired); + } + + abstract public T setValue(String stringValue, C configuredObject); + + static class StringAttribute<C extends ConfiguredObject> extends Attribute<C, String> + { + + public StringAttribute(String name) + { + super(name); + } + + @Override + public Class<String> getType() + { + return String.class; + } + + @Override + public String setValue(String stringValue, C configuredObject) + { + return setValue(getValue(configuredObject), stringValue, configuredObject); + } + + } + + static class IntegerAttribute<C extends ConfiguredObject> extends Attribute<C, Integer> + { + + public IntegerAttribute(String name) + { + super(name); + } + + @Override + public Class<Integer> getType() + { + return Integer.class; + } + + @Override + public Integer setValue(String stringValue, C configuredObject) + { + try + { + Integer val = Integer.valueOf(stringValue); + return setValue(getValue(configuredObject), val, configuredObject); + } + catch (NumberFormatException e) + { + throw new IllegalArgumentException(e); + } + } + } + + + static class LongAttribute<C extends ConfiguredObject> extends Attribute<C, Long> + { + + public LongAttribute(String name) + { + super(name); + } + + @Override + public Class<Long> getType() + { + return Long.class; + } + + @Override + public Long setValue(String stringValue, C configuredObject) + { + try + { + Long val = Long.valueOf(stringValue); + return setValue(getValue(configuredObject), val, configuredObject); + } + catch (NumberFormatException e) + { + throw new IllegalArgumentException(e); + } + } + } + + + static class DoubleAttribute<C extends ConfiguredObject> extends Attribute<C, Double> + { + + public DoubleAttribute(String name) + { + super(name); + } + + @Override + public Class<Double> getType() + { + return Double.class; + } + + @Override + public Double setValue(String stringValue, C configuredObject) + { + try + { + Double val = Double.valueOf(stringValue); + return setValue(getValue(configuredObject), val, configuredObject); + } + catch (NumberFormatException e) + { + throw new IllegalArgumentException(e); + } + } + } + + + static class FloatAttribute<C extends ConfiguredObject> extends Attribute<C, Float> + { + + public FloatAttribute(String name) + { + super(name); + } + + @Override + public Class<Float> getType() + { + return Float.class; + } + + @Override + public Float setValue(String stringValue, C configuredObject) + { + try + { + Float val = Float.valueOf(stringValue); + return setValue(getValue(configuredObject), val, configuredObject); + } + catch (NumberFormatException e) + { + throw new IllegalArgumentException(e); + } + } + } + + + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/AuthenticationMethod.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/AuthenticationMethod.java new file mode 100644 index 0000000000..7a5927a365 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/AuthenticationMethod.java @@ -0,0 +1,33 @@ +/* + * + * 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.model; + +import java.util.Collection; + +public interface AuthenticationMethod extends ConfiguredObject +{ + // name is the SASL mech where this is a SASL authentication + + // parents + VirtualHostAlias getVirtualHostAlias(); + AuthenticationProvider getAuthenticationProvider(); + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/AuthenticationProvider.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/AuthenticationProvider.java new file mode 100644 index 0000000000..6000886956 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/AuthenticationProvider.java @@ -0,0 +1,55 @@ +/* + * + * 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.model; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; + +public interface AuthenticationProvider extends ConfiguredObject +{ + + public static final String ID = "id"; + public static final String DESCRIPTION = "description"; + public static final String NAME = "name"; + public static final String STATE = "state"; + public static final String DURABLE = "durable"; + public static final String LIFETIME_POLICY = "lifetimePolicy"; + public static final String TIME_TO_LIVE = "timeToLive"; + public static final String CREATED = "created"; + public static final String UPDATED = "updated"; + public static final String TYPE = "type"; + + public static final Collection<String> AVAILABLE_ATTRIBUTES = + Collections.unmodifiableList( + Arrays.asList(ID, + NAME, + DESCRIPTION, + STATE, + DURABLE, + LIFETIME_POLICY, + TIME_TO_LIVE, + CREATED, + UPDATED, + TYPE)); + //children + Collection<VirtualHostAlias> getVirtualHostPortBindings(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Broker.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Broker.java new file mode 100644 index 0000000000..ca1de0f189 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Broker.java @@ -0,0 +1,82 @@ +/* + * + * 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.model; + +import java.security.AccessControlException; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Map; + +public interface Broker extends ConfiguredObject +{ + + String BUILD_VERSION = "buildVersion"; + String BYTES_RETAINED = "bytesRetained"; + String OPERATING_SYSTEM = "operatingSystem"; + String PLATFORM = "platform"; + String PROCESS_PID = "processPid"; + String PRODUCT_VERSION = "productVersion"; + String STATISTICS_ENABLED = "statisticsEnabled"; + String SUPPORTED_STORE_TYPES = "supportedStoreTypes"; + String CREATED = "created"; + String DURABLE = "durable"; + String ID = "id"; + String LIFETIME_POLICY = "lifetimePolicy"; + String NAME = "name"; + String STATE = "state"; + String TIME_TO_LIVE = "timeToLive"; + String UPDATED = "updated"; + + // Attributes + public static final Collection<String> AVAILABLE_ATTRIBUTES = + Collections.unmodifiableList( + Arrays.asList(BUILD_VERSION, + BYTES_RETAINED, + OPERATING_SYSTEM, + PLATFORM, + PROCESS_PID, + PRODUCT_VERSION, + STATISTICS_ENABLED, + SUPPORTED_STORE_TYPES, + CREATED, + DURABLE, + ID, + LIFETIME_POLICY, + NAME, + STATE, + TIME_TO_LIVE, + UPDATED)); + + //children + Collection < VirtualHost > getVirtualHosts(); + + Collection<Port> getPorts(); + + Collection<AuthenticationProvider> getAuthenticationProviders(); + + VirtualHost createVirtualHost(String name, State initialState, boolean durable, + LifetimePolicy lifetime, long ttl, Map<String, Object> attributes) + throws AccessControlException, IllegalArgumentException; + + void deleteVirtualHost(VirtualHost virtualHost) + throws AccessControlException, IllegalStateException; +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/ConfigurationChangeListener.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/ConfigurationChangeListener.java index 6477633a9b..78b98faffe 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/ConfigurationChangeListener.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/ConfigurationChangeListener.java @@ -30,7 +30,8 @@ public interface ConfigurationChangeListener * @param newState the state after the change */ void stateChanged(ConfiguredObject object, State oldState, State newState); - + + void childAdded(ConfiguredObject object, ConfiguredObject child); void childRemoved(ConfiguredObject object, ConfiguredObject child); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/ConfiguredObject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/ConfiguredObject.java index fb47a54d0a..414b2d083a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/ConfiguredObject.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/ConfiguredObject.java @@ -22,6 +22,7 @@ package org.apache.qpid.server.model; import java.security.AccessControlException; import java.util.Collection; +import java.util.Map; import java.util.UUID; public interface ConfiguredObject @@ -81,7 +82,7 @@ public interface ConfiguredObject * @param desiredState the state the caller wishes the object to attain * @return the new current state * @throws IllegalStateTransitionException the requested state tranisition is invalid - * @throws AccessControlException the current context does not have sufficeint permissions to change the state + * @throws AccessControlException the current context does not have sufficient permissions to change the state */ State setDesiredState(State currentState, State desiredState) throws IllegalStateTransitionException, AccessControlException; @@ -89,7 +90,7 @@ public interface ConfiguredObject /** * Get the actual state of the object. * - * This state is derived fromt the desired state of the object itself and + * This state is derived from the desired state of the object itself and * the actual state of its parents. If an object "desires" to be ACTIVE, but one of its parents is STOPPED, then * the actual state of the object will be STOPPED * @@ -126,7 +127,7 @@ public interface ConfiguredObject /** * Returns whether the the object configuration is durably stored * - * @return the durablity + * @return the durability */ boolean isDurable(); @@ -188,7 +189,7 @@ public interface ConfiguredObject /** * Get the names of attributes that are set on this object * - * Not that the returned collection is correct at the time the method is called, but will not reflect future + * Note that the returned collection is correct at the time the method is called, but will not reflect future * additions or removals when they occur * * @return the collection of attribute names @@ -226,4 +227,20 @@ public interface ConfiguredObject * @return the Statistics holder for the ConfiguredObject (or null if none exists) */ Statistics getStatistics(); + + /** + * Return children of the ConfiguredObject of the given class + * + * @param clazz the class of the children to return + * @return the children + * + * @throws NullPointerException if the supplied class null + * + */ + <C extends ConfiguredObject> Collection<C> getChildren(Class<C> clazz); + + + <C extends ConfiguredObject> C createChild(Class<C> childClass, + Map<String, Object> attributes, + ConfiguredObject... otherParents); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/ConfiguredObjectFinder.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/ConfiguredObjectFinder.java new file mode 100644 index 0000000000..6a7d6f8f7b --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/ConfiguredObjectFinder.java @@ -0,0 +1,38 @@ +/* + * + * 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.model; + +import java.util.Collection; + +public class ConfiguredObjectFinder +{ + public static <C extends ConfiguredObject> C findConfiguredObjectByName(Collection<C> configuredObjects, String name) + { + for (C configuredObject : configuredObjects) + { + if (name.equals(configuredObject.getName())) + { + return configuredObject; + } + } + return null; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Connection.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Connection.java new file mode 100644 index 0000000000..aaf6007afd --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Connection.java @@ -0,0 +1,107 @@ +/* + * + * 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.model; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; + +public interface Connection extends ConfiguredObject +{ + + // Statistics + + String BYTES_IN = "bytesIn"; + String BYTES_OUT = "bytesOut"; + String LAST_IO_TIME = "lastIoTime"; + String LOCAL_TRANSACTION_BEGINS = "localTransactionBegins"; + String LOCAL_TRANSACTION_ROLLBACKS = "localTransactionRollbacks"; + String MESSAGES_IN = "messagesIn"; + String MESSAGES_OUT = "messagesOut"; + String SESSION_COUNT = "sessionCount"; + String STATE_CHANGED = "stateChanged"; + String XA_TRANSACTION_BRANCH_ENDS = "xaTransactionBranchEnds"; + String XA_TRANSACTION_BRANCH_STARTS = "xaTransactionBranchStarts"; + String XA_TRANSACTION_BRANCH_SUSPENDS = "xaTransactionBranchSuspends"; + + public static final Collection<String> AVAILABLE_STATISTICS = + Collections.unmodifiableCollection( + Arrays.asList(BYTES_IN, + BYTES_OUT, + LAST_IO_TIME, + LOCAL_TRANSACTION_BEGINS, + LOCAL_TRANSACTION_ROLLBACKS, + MESSAGES_IN, + MESSAGES_OUT, + SESSION_COUNT, + STATE_CHANGED, + XA_TRANSACTION_BRANCH_ENDS, + XA_TRANSACTION_BRANCH_STARTS, + XA_TRANSACTION_BRANCH_SUSPENDS)); + + // Attributes + + public static final String ID = "id"; + public static final String NAME = "name"; + public static final String STATE = "state"; + public static final String DURABLE = "durable"; + public static final String LIFETIME_POLICY = "lifetimePolicy"; + public static final String TIME_TO_LIVE = "timeToLive"; + public static final String CREATED = "created"; + public static final String UPDATED = "updated"; + + public static final String CLIENT_ID = "clientId"; + public static final String CLIENT_VERSION = "clientVersion"; + public static final String INCOMING = "incoming"; + public static final String LOCAL_ADDRESS = "localAddress"; + public static final String PRINCIPAL = "principal"; + public static final String PROPERTIES = "properties"; + public static final String REMOTE_ADDRESS = "remoteAddress"; + public static final String REMOTE_PROCESS_NAME = "remoteProcessName"; + public static final String REMOTE_PROCESS_PID = "remoteProcessPid"; + public static final String SESSION_COUNT_LIMIT = "sessionCountLimit"; + + public static final Collection<String> AVAILABLE_ATTRIBUTES = + Collections.unmodifiableCollection( + Arrays.asList( ID, + NAME, + STATE, + DURABLE, + LIFETIME_POLICY, + TIME_TO_LIVE, + CREATED, + UPDATED, + CLIENT_ID, + CLIENT_VERSION, + INCOMING, + LOCAL_ADDRESS, + PRINCIPAL, + PROPERTIES, + REMOTE_ADDRESS, + REMOTE_PROCESS_NAME, + REMOTE_PROCESS_PID, + SESSION_COUNT_LIMIT)); + + //children + Collection<Session> getSessions(); + + void delete(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Event.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Event.java new file mode 100644 index 0000000000..91b684f06e --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Event.java @@ -0,0 +1,27 @@ +/* + * + * 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.model; + +abstract public class Event<T extends EventType> +{ + abstract public T getEventType(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/EventType.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/EventType.java new file mode 100644 index 0000000000..edd5ce4250 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/EventType.java @@ -0,0 +1,60 @@ +/* + * + * 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.model; + +import java.util.HashMap; +import java.util.Map; + +/** + * A type of event generated by a ConfiguredObject. + */ +public abstract class EventType<T extends EventType<T>> +{ + private static final Map<Class<? extends EventType>, Integer> EVENT_TYPES = + new HashMap<Class<? extends EventType>, Integer>(); + + private final int _classId; + + protected EventType() + { + synchronized (EVENT_TYPES) + { + if(EVENT_TYPES.containsKey(getClass())) + { + throw new IllegalArgumentException("Cannot define more one instance of the same EventType " + + getClass().getName()); + } + else + { + _classId = EVENT_TYPES.size(); + EVENT_TYPES.put(getClass(), _classId); + } + } + } + + public final int getId() + { + return _classId; + } + + abstract public Event<T> newEvent(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Exchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Exchange.java index e872273d05..e63c71e955 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Exchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Exchange.java @@ -77,7 +77,7 @@ public interface Exchange extends ConfiguredObject //children Collection<Binding> getBindings(); Collection<Publisher> getPublishers(); - + //operations Binding createBinding(String bindingKey, Queue queue, diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Model.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Model.java new file mode 100644 index 0000000000..fd429321c8 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Model.java @@ -0,0 +1,97 @@ +/* + * + * 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.model; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +public class Model +{ + private static final Map<Class<? extends ConfiguredObject>, Collection<Class<? extends ConfiguredObject>>> + PARENTS = new HashMap<Class<? extends ConfiguredObject>, Collection<Class<? extends ConfiguredObject>>>(); + + + private static final Map<Class<? extends ConfiguredObject>, Collection<Class<? extends ConfiguredObject>>> + CHILDREN = new HashMap<Class<? extends ConfiguredObject>, Collection<Class<? extends ConfiguredObject>>>(); + + static void addRelationship(Class<? extends ConfiguredObject> parent, Class<? extends ConfiguredObject> child) + { + Collection<Class<? extends ConfiguredObject>> parents = PARENTS.get(child); + if(parents == null) + { + parents = new ArrayList<Class<? extends ConfiguredObject>>(); + PARENTS.put(child, parents); + } + parents.add(parent); + + Collection<Class<? extends ConfiguredObject>> children = CHILDREN.get(parent); + if(children == null) + { + children = new ArrayList<Class<? extends ConfiguredObject>>(); + CHILDREN.put(parent, children); + } + children.add(child); + } + + static + { + addRelationship(Broker.class, VirtualHost.class); + addRelationship(Broker.class, Port.class); + addRelationship(Broker.class, AuthenticationProvider.class); + + addRelationship(VirtualHost.class, Exchange.class); + addRelationship(VirtualHost.class, Queue.class); + addRelationship(VirtualHost.class, Connection.class); + addRelationship(VirtualHost.class, VirtualHostAlias.class); + + addRelationship(AuthenticationProvider.class, User.class); + + addRelationship(Connection.class, Session.class); + + addRelationship(Exchange.class, Binding.class); + addRelationship(Exchange.class, Publisher.class); + + addRelationship(Queue.class, Binding.class); + addRelationship(Queue.class, Consumer.class); + + addRelationship(Session.class, Consumer.class); + addRelationship(Session.class, Publisher.class); + + } + + public static Collection<Class<? extends ConfiguredObject>> getParentTypes(Class<? extends ConfiguredObject> child) + { + Collection<Class<? extends ConfiguredObject>> parentTypes = PARENTS.get(child); + return parentTypes == null ? Collections.EMPTY_LIST + : Collections.unmodifiableCollection(parentTypes); + } + + public static Collection<Class<? extends ConfiguredObject>> getChildTypes(Class<? extends ConfiguredObject> parent) + { + Collection<Class<? extends ConfiguredObject>> childTypes = CHILDREN.get(parent); + return childTypes == null ? Collections.EMPTY_LIST + : Collections.unmodifiableCollection(childTypes); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/PasswordCredentialManagingAuthenticationProvider.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/PasswordCredentialManagingAuthenticationProvider.java new file mode 100644 index 0000000000..1027e5ce8c --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/PasswordCredentialManagingAuthenticationProvider.java @@ -0,0 +1,46 @@ +/* + * + * 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.model; + +import java.io.IOException; +import java.util.Map; + +import javax.security.auth.login.AccountNotFoundException; + +public interface PasswordCredentialManagingAuthenticationProvider extends AuthenticationProvider +{ + boolean createUser(String username, String password, Map<String, String> attributes); + + void deleteUser(String user) throws AccountNotFoundException; + + void setPassword(String username, String password) throws AccountNotFoundException; + + Map<String, Map<String,String>> getUsers(); + + /** + * Refreshes the cache of user and password data from the underlying storage. + * + * If there is a failure whilst reloading the data, the implementation must + * throw an {@link IOException} and revert to using the previous cached username + * and password data. In this way, the broker will remain usable. + */ + void reload() throws IOException; +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Port.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Port.java new file mode 100644 index 0000000000..50c0ebcd14 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Port.java @@ -0,0 +1,91 @@ +/* + * + * 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.model; + +import java.security.AccessControlException; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; + +public interface Port extends ConfiguredObject +{ + String CREATED = "created"; + String DURABLE = "durable"; + String ID = "id"; + String LIFETIME_POLICY = "lifetimePolicy"; + String NAME = "name"; + String STATE = "state"; + String TIME_TO_LIVE = "timeToLive"; + String UPDATED = "updated"; + String BINDING_ADDRESS = "bindingAddress"; + String PORT = "port"; + String PROTOCOLS = "protocols"; + String TRANSPORTS = "transports"; + + // Attributes + public static final Collection<String> AVAILABLE_ATTRIBUTES = + Collections.unmodifiableList( + Arrays.asList( + ID, + NAME, + STATE, + DURABLE, + LIFETIME_POLICY, + TIME_TO_LIVE, + CREATED, + UPDATED, + BINDING_ADDRESS, + PORT, + PROTOCOLS, + TRANSPORTS + )); + + + String getBindingAddress(); + + int getPort(); + + Collection<Transport> getTransports(); + + void addTransport(Transport transport) throws IllegalStateException, + AccessControlException, + IllegalArgumentException; + + Transport removeTransport(Transport transport) throws IllegalStateException, + AccessControlException, + IllegalArgumentException; + + + Collection<Protocol> getProtocols(); + + void addProtocol(Protocol protocol) throws IllegalStateException, + AccessControlException, + IllegalArgumentException; + + Protocol removeProtocol(Protocol protocol) throws IllegalStateException, + AccessControlException, + IllegalArgumentException; + + + //children + Collection<VirtualHostAlias> getVirtualHostBindings(); + Collection<Connection> getConnections(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Protocol.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Protocol.java new file mode 100644 index 0000000000..fecbcec194 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Protocol.java @@ -0,0 +1,32 @@ +/* + * + * 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.model; + +public enum Protocol +{ + AMQP_0_8, + AMQP_0_9, + AMQP_0_9_1, + AMQP_0_10, + AMQP_1_0, + JMX, + HTTP +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Queue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Queue.java index 7c4f0de22b..5dda4d66cd 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Queue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Queue.java @@ -25,7 +25,6 @@ import java.util.Collection; import java.util.Collections; import org.apache.qpid.server.queue.QueueEntryVisitor; - public interface Queue extends ConfiguredObject { public static final String BINDING_COUNT = "bindingCount"; @@ -71,6 +70,7 @@ public interface Queue extends ConfiguredObject public static final String ID = "id"; + public static final String DESCRIPTION = "description"; public static final String NAME = "name"; public static final String STATE = "state"; public static final String DURABLE = "durable"; @@ -78,6 +78,7 @@ public interface Queue extends ConfiguredObject public static final String TIME_TO_LIVE = "timeToLive"; public static final String CREATED = "created"; public static final String UPDATED = "updated"; + public static final String ARGUMENTS = "arguments"; public static final String ALERT_REPEAT_GAP = "alertRepeatGap"; public static final String ALERT_THRESHOLD_MESSAGE_AGE = "alertThresholdMessageAge"; @@ -106,6 +107,7 @@ public interface Queue extends ConfiguredObject Collections.unmodifiableList( Arrays.asList(ID, NAME, + DESCRIPTION, STATE, DURABLE, LIFETIME_POLICY, @@ -143,4 +145,6 @@ public interface Queue extends ConfiguredObject void visit(QueueEntryVisitor visitor); void delete(); + + void setNotificationListener(QueueNotificationListener listener); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueNotificationListener.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/QueueNotificationListener.java index 959ca03c80..ab601f685c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueNotificationListener.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/QueueNotificationListener.java @@ -18,10 +18,11 @@ * under the License.
*
*/
-package org.apache.qpid.server.queue;
+package org.apache.qpid.server.model;
+import org.apache.qpid.server.queue.NotificationCheck;
public interface QueueNotificationListener
{
- void notifyClients(NotificationCheck notification, AMQQueue queue, String notificationMsg);
+ void notifyClients(NotificationCheck notification, Queue queue, String notificationMsg);
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Session.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Session.java new file mode 100644 index 0000000000..e813d0c129 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Session.java @@ -0,0 +1,82 @@ +/* + * + * 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.model; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; + +public interface Session extends ConfiguredObject +{ + // Statistics + + public static final String BYTES_IN = "bytesIn"; + public static final String BYTES_OUT = "bytesOut"; + public static final String CONSUMER_COUNT = "consumerCount"; + public static final String LOCAL_TRANSACTION_BEGINS = "localTransactionBegins"; + public static final String LOCAL_TRANSACTION_OPEN = "localTransactionOpen"; + public static final String LOCAL_TRANSACTION_ROLLBACKS = "localTransactionRollbacks"; + public static final String STATE_CHANGED = "stateChanged"; + public static final String UNACKNOWLEDGED_BYTES = "unacknowledgedBytes"; + public static final String UNACKNOWLEDGED_MESSAGES = "unacknowledgedMessages"; + public static final String XA_TRANSACTION_BRANCH_ENDS = "xaTransactionBranchEnds"; + public static final String XA_TRANSACTION_BRANCH_STARTS = "xaTransactionBranchStarts"; + public static final String XA_TRANSACTION_BRANCH_SUSPENDS = "xaTransactionBranchSuspends"; + + public static final Collection<String> AVAILABLE_STATISTICS = + Collections.unmodifiableCollection(Arrays.asList(BYTES_IN, BYTES_OUT, CONSUMER_COUNT, + LOCAL_TRANSACTION_BEGINS, + LOCAL_TRANSACTION_OPEN, + LOCAL_TRANSACTION_ROLLBACKS, STATE_CHANGED, + UNACKNOWLEDGED_BYTES, UNACKNOWLEDGED_MESSAGES, + XA_TRANSACTION_BRANCH_ENDS, XA_TRANSACTION_BRANCH_STARTS, + XA_TRANSACTION_BRANCH_SUSPENDS)); + + + public static final String ID = "id"; + public static final String NAME = "name"; + public static final String STATE = "state"; + public static final String DURABLE = "durable"; + public static final String LIFETIME_POLICY = "lifetimePolicy"; + public static final String TIME_TO_LIVE = "timeToLive"; + public static final String CREATED = "created"; + public static final String UPDATED = "updated"; + + public static final String CHANNEL_ID = "channelId"; + // PRODUCER_FLOW_BLOCKED is exposed as an interim step. We will expose attribute(s) that exposing + // available credit of both producer and consumer sides. + public static final String PRODUCER_FLOW_BLOCKED = "producerFlowBlocked"; + + public static final Collection<String> AVAILABLE_ATTRIBUTES = + Collections.unmodifiableCollection(Arrays.asList(ID, + NAME, + STATE, + DURABLE, + LIFETIME_POLICY, + TIME_TO_LIVE, + CREATED, + UPDATED, + CHANNEL_ID, + PRODUCER_FLOW_BLOCKED)); + + Collection<Consumer> getSubscriptions(); + Collection<Publisher> getPublishers(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Statistics.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Statistics.java index 2cb81eae82..92d6f47741 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Statistics.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Statistics.java @@ -1,8 +1,4 @@ -package org.apache.qpid.server.model; - -import java.util.Collection; - -/** +/* * 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. @@ -18,6 +14,11 @@ import java.util.Collection; * See the License for the specific language governing permissions and * limitations under the License. */ + +package org.apache.qpid.server.model; + +import java.util.Collection; + public interface Statistics { Collection<String> getStatisticNames(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Transport.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Transport.java new file mode 100644 index 0000000000..03cd46be01 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Transport.java @@ -0,0 +1,27 @@ +/* + * + * 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.model; + +public enum Transport +{ + TCP, + SSL +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/UUIDGenerator.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/UUIDGenerator.java index d8493c6df4..920088d61c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/UUIDGenerator.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/UUIDGenerator.java @@ -40,11 +40,11 @@ public class UUIDGenerator return UUID.nameUUIDFromBytes(sb.toString().getBytes()); } - public static UUID generateExchangeUUID(String echangeName, String virtualHostName) + public static UUID generateExchangeUUID(String exchangeName, String virtualHostName) { - if(ExchangeDefaults.DEFAULT_EXCHANGE_NAME.asString().equals(echangeName) || echangeName.startsWith("amq.") || echangeName.startsWith("qpid.")) + if(ExchangeDefaults.DEFAULT_EXCHANGE_NAME.asString().equals(exchangeName) || exchangeName.startsWith("amq.") || exchangeName.startsWith("qpid.")) { - return generateUUID(echangeName, virtualHostName); + return generateUUID(exchangeName, virtualHostName); } else { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/User.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/User.java new file mode 100644 index 0000000000..d97bf46d31 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/User.java @@ -0,0 +1,59 @@ +/* + * + * 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.model; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; + +public interface User extends ConfiguredObject +{ + String CREATED = "created"; + String DURABLE = "durable"; + String ID = "id"; + String LIFETIME_POLICY = "lifetimePolicy"; + String NAME = "name"; + String STATE = "state"; + String TIME_TO_LIVE = "timeToLive"; + String UPDATED = "updated"; + String PASSWORD = "password"; + + // Attributes + public static final Collection<String> AVAILABLE_ATTRIBUTES = + Collections.unmodifiableList( + Arrays.asList( + ID, + NAME, + STATE, + DURABLE, + LIFETIME_POLICY, + TIME_TO_LIVE, + CREATED, + UPDATED, + PASSWORD + )); + + public String getPassword(); + + public void setPassword(String password); + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/VirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/VirtualHost.java new file mode 100644 index 0000000000..53faefc954 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/VirtualHost.java @@ -0,0 +1,154 @@ +/* + * + * 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.model; + +import org.apache.qpid.server.queue.QueueEntry; +import java.security.AccessControlException; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Map; + +public interface VirtualHost extends ConfiguredObject +{ + // Statistics + + public static final String BYTES_IN = "bytesIn"; + public static final String BYTES_OUT = "bytesOut"; + public static final String BYTES_RETAINED = "bytesRetained"; + public static final String LOCAL_TRANSACTION_BEGINS = "localTransactionBegins"; + public static final String LOCAL_TRANSACTION_ROLLBACKS = "localTransactionRollbacks"; + public static final String MESSAGES_IN = "messagesIn"; + public static final String MESSAGES_OUT = "messagesOut"; + public static final String MESSAGES_RETAINED = "messagesRetained"; + public static final String STATE_CHANGED = "stateChanged"; + public static final String XA_TRANSACTION_BRANCH_ENDS = "xaTransactionBranchEnds"; + public static final String XA_TRANSACTION_BRANCH_STARTS = "xaTransactionBranchStarts"; + public static final String XA_TRANSACTION_BRANCH_SUSPENDS = "xaTransactionBranchSuspends"; + public static final String QUEUE_COUNT = "queueCount"; + public static final String EXCHANGE_COUNT = "exchangeCount"; + public static final String CONNECTION_COUNT = "connectionCount"; + + public static final Collection<String> AVAILABLE_STATISTICS = + Collections.unmodifiableList( + Arrays.asList(BYTES_IN, BYTES_OUT, BYTES_RETAINED, LOCAL_TRANSACTION_BEGINS, + LOCAL_TRANSACTION_ROLLBACKS, MESSAGES_IN, MESSAGES_OUT, MESSAGES_RETAINED, STATE_CHANGED, + XA_TRANSACTION_BRANCH_ENDS, XA_TRANSACTION_BRANCH_STARTS, XA_TRANSACTION_BRANCH_SUSPENDS, + QUEUE_COUNT, EXCHANGE_COUNT, CONNECTION_COUNT)); + + String ALERT_REPEAT_GAP = "alertRepeatGap"; + String ALERT_THRESHOLD_MESSAGE_AGE = "alertThresholdMessageAge"; + String ALERT_THRESHOLD_MESSAGE_SIZE = "alertThresholdMessageSize"; + String ALERT_THRESHOLD_QUEUE_DEPTH_BYTES = "alertThresholdQueueDepthBytes"; + String ALERT_THRESHOLD_QUEUE_DEPTH_MESSAGES = "alertThresholdQueueDepthMessages"; + String DEAD_LETTER_QUEUE_ENABLED = "deadLetterQueueEnabled"; + String FEDERATION_TAG = "federationTag"; + String HOUSEKEEPING_CHECK_PERIOD = "housekeepingCheckPeriod"; + String MAXIMUM_DELIVERY_ATTEMPTS = "maximumDeliveryAttempts"; + String QUEUE_FLOW_CONTROL_SIZE_BYTES = "queueFlowControlSizeBytes"; + String QUEUE_FLOW_RESUME_SIZE_BYTES = "queueFlowResumeSizeBytes"; + String STORE_CONFIGURATION = "storeConfiguration"; + String STORE_TRANSACTION_IDLE_TIMEOUT_CLOSE = "storeTransactionIdleTimeoutClose"; + String STORE_TRANSACTION_IDLE_TIMEOUT_WARN = "storeTransactionIdleTimeoutWarn"; + String STORE_TRANSACTION_OPEN_TIMEOUT_CLOSE = "storeTransactionOpenTimeoutClose"; + String STORE_TRANSACTION_OPEN_TIMEOUT_WARN = "storeTransactionOpenTimeoutWarn"; + String STORE_TYPE = "storeType"; + String SUPPORTED_EXCHANGE_TYPES = "supportedExchangeTypes"; + String SUPPORTED_QUEUE_TYPES = "supportedQueueTypes"; + String CREATED = "created"; + String DURABLE = "durable"; + String ID = "id"; + String LIFETIME_POLICY = "lifetimePolicy"; + String NAME = "name"; + String STATE = "state"; + String TIME_TO_LIVE = "timeToLive"; + String UPDATED = "updated"; + // Attributes + public static final Collection<String> AVAILABLE_ATTRIBUTES = + Collections.unmodifiableList( + Arrays.asList( + ID, + NAME, + STATE, + DURABLE, + LIFETIME_POLICY, + TIME_TO_LIVE, + CREATED, + UPDATED, + SUPPORTED_EXCHANGE_TYPES, + SUPPORTED_QUEUE_TYPES, + DEAD_LETTER_QUEUE_ENABLED, + FEDERATION_TAG, + HOUSEKEEPING_CHECK_PERIOD, + MAXIMUM_DELIVERY_ATTEMPTS, + QUEUE_FLOW_CONTROL_SIZE_BYTES, + QUEUE_FLOW_RESUME_SIZE_BYTES, + STORE_TYPE, + STORE_CONFIGURATION, + STORE_TRANSACTION_IDLE_TIMEOUT_CLOSE, + STORE_TRANSACTION_IDLE_TIMEOUT_WARN, + STORE_TRANSACTION_OPEN_TIMEOUT_CLOSE, + STORE_TRANSACTION_OPEN_TIMEOUT_WARN, + ALERT_REPEAT_GAP, + ALERT_THRESHOLD_MESSAGE_AGE, + ALERT_THRESHOLD_MESSAGE_SIZE, + ALERT_THRESHOLD_QUEUE_DEPTH_BYTES, + ALERT_THRESHOLD_QUEUE_DEPTH_MESSAGES)); + + + + String getReplicationGroupName(); + + //children + Collection<VirtualHostAlias> getAliases(); + Collection<Connection> getConnections(); + Collection<Queue> getQueues(); + Collection<Exchange> getExchanges(); + + Exchange createExchange(String name, State initialState, boolean durable, + LifetimePolicy lifetime, long ttl, String type, Map<String, Object> attributes) + throws AccessControlException, IllegalArgumentException; + + Queue createQueue(String name, State initialState, boolean durable, + boolean exclusive, LifetimePolicy lifetime, long ttl, Map<String, Object> attributes) + throws AccessControlException, IllegalArgumentException; + + void deleteQueue(Queue queue) throws AccessControlException, IllegalStateException; + + Collection<String> getExchangeTypes(); + + public static interface Transaction + { + void dequeue(QueueEntry entry); + + void copy(QueueEntry entry, Queue queue); + + void move(QueueEntry entry, Queue queue); + + } + + public static interface TransactionalOperation + { + void withinTransaction(Transaction txn); + } + + void executeTransaction(TransactionalOperation op); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/VirtualHostAlias.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/VirtualHostAlias.java new file mode 100644 index 0000000000..31403d78e5 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/VirtualHostAlias.java @@ -0,0 +1,37 @@ +/* + * + * 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.model; + +import java.security.AccessControlException; +import java.util.Collection; + +public interface VirtualHostAlias extends ConfiguredObject +{ + // parents + Port getPort(); + VirtualHost getVirtualHost(); + + // children + Collection<AuthenticationMethod> getAuthenticationMethods(); + + + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AbstractAdapter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AbstractAdapter.java new file mode 100644 index 0000000000..78880c232d --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AbstractAdapter.java @@ -0,0 +1,293 @@ +/* + * + * 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.model.adapter; + +import java.security.AccessControlException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import org.apache.qpid.server.model.ConfigurationChangeListener; +import org.apache.qpid.server.model.ConfiguredObject; +import org.apache.qpid.server.model.IllegalStateTransitionException; +import org.apache.qpid.server.model.State; + +abstract class AbstractAdapter implements ConfiguredObject +{ + private final Map<String,Object> _attributes = new HashMap<String, Object>(); + private final Map<Class<? extends ConfiguredObject>, ConfiguredObject> _parents = + new HashMap<Class<? extends ConfiguredObject>, ConfiguredObject>(); + private final Collection<ConfigurationChangeListener> _changeListeners = + new ArrayList<ConfigurationChangeListener>(); + + private final UUID _id; + + protected AbstractAdapter(String... names) + { + StringBuilder sb = new StringBuilder(); + for(String name : names) + { + sb.append('/').append(name); + } + _id = UUID.nameUUIDFromBytes(sb.toString().getBytes()); + } + + protected AbstractAdapter() + { + _id = UUID.randomUUID(); + } + + static String getStringAttribute(String name, Map<String,Object> attributes, String defaultVal) + { + final Object value = attributes.get(name); + return value == null ? defaultVal : String.valueOf(value); + } + + static Map getMapAttribute(String name, Map<String,Object> attributes, Map defaultVal) + { + final Object value = attributes.get(name); + if(value == null) + { + return defaultVal; + } + else if(value instanceof Map) + { + return (Map) value; + } + else + { + throw new IllegalArgumentException("Value for attribute " + name + " is not of required type Map"); + } + } + + + static <E extends Enum> E getEnumAttribute(Class<E> clazz, String name, Map<String,Object> attributes, E defaultVal) + { + Object obj = attributes.get(name); + if(obj == null) + { + return defaultVal; + } + else if(clazz.isInstance(obj)) + { + return (E) obj; + } + else if(obj instanceof String) + { + return (E) Enum.valueOf(clazz, (String)obj); + } + else + { + throw new IllegalArgumentException("Value for attribute " + name + " is not of required type " + clazz.getSimpleName()); + } + } + + static Boolean getBooleanAttribute(String name, Map<String,Object> attributes, Boolean defaultValue) + { + Object obj = attributes.get(name); + if(obj == null) + { + return defaultValue; + } + else if(obj instanceof Boolean) + { + return (Boolean) obj; + } + else if(obj instanceof String) + { + return Boolean.parseBoolean((String) obj); + } + else + { + throw new IllegalArgumentException("Value for attribute " + name + " is not of required type Boolean"); + } + } + + static Integer getIntegerAttribute(String name, Map<String,Object> attributes, Integer defaultValue) + { + Object obj = attributes.get(name); + if(obj == null) + { + return defaultValue; + } + else if(obj instanceof Number) + { + return ((Number) obj).intValue(); + } + else if(obj instanceof String) + { + return Integer.valueOf((String) obj); + } + else + { + throw new IllegalArgumentException("Value for attribute " + name + " is not of required type Integer"); + } + } + + static Long getLongAttribute(String name, Map<String,Object> attributes, Long defaultValue) + { + Object obj = attributes.get(name); + if(obj == null) + { + return defaultValue; + } + else if(obj instanceof Number) + { + return ((Number) obj).longValue(); + } + else if(obj instanceof String) + { + return Long.valueOf((String) obj); + } + else + { + throw new IllegalArgumentException("Value for attribute " + name + " is not of required type Long"); + } + } + + public final UUID getId() + { + return _id; + } + + public State getDesiredState() + { + return null; //TODO + } + + public State setDesiredState(final State currentState, final State desiredState) + throws IllegalStateTransitionException, AccessControlException + { + return null; //TODO + } + + public void addChangeListener(final ConfigurationChangeListener listener) + { + if(listener == null) + { + throw new NullPointerException("Cannot add a null listener"); + } + synchronized (this) + { + if(!_changeListeners.contains(listener)) + { + _changeListeners.add(listener); + } + } + } + + public boolean removeChangeListener(final ConfigurationChangeListener listener) + { + if(listener == null) + { + throw new NullPointerException("Cannot remove a null listener"); + } + synchronized (this) + { + return _changeListeners.remove(listener); + } + } + + + protected void childAdded(ConfiguredObject child) + { + synchronized (this) + { + for(ConfigurationChangeListener listener : _changeListeners) + { + listener.childAdded(this, child); + } + } + } + + + protected void childRemoved(ConfiguredObject child) + { + synchronized (this) + { + for(ConfigurationChangeListener listener : _changeListeners) + { + listener.childRemoved(this, child); + } + } + } + + public Object getAttribute(final String name) + { + synchronized (this) + { + return _attributes.get(name); + } + } + + public Object setAttribute(final String name, final Object expected, final Object desired) + throws IllegalStateException, AccessControlException, IllegalArgumentException + { + synchronized (this) + { + Object currentValue = _attributes.get(name); + if((currentValue == null && expected == null) + || (currentValue != null && currentValue.equals(expected))) + { + _attributes.put(name, desired); + return desired; + } + else + { + return currentValue; + } + } + } + + public <T extends ConfiguredObject> T getParent(final Class<T> clazz) + { + synchronized (this) + { + return (T) _parents.get(clazz); + } + } + + protected <T extends ConfiguredObject> void addParent(Class<T> clazz, T parent) + { + synchronized (this) + { + _parents.put(clazz, parent); + } + } + + protected <T extends ConfiguredObject> void removeParent(Class<T> clazz) + { + synchronized (this) + { + _parents.remove(clazz); + } + } + + public Collection<String> getAttributeNames() + { + synchronized(_attributes) + { + return new ArrayList<String>(_attributes.keySet()); + } + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AuthenticationProviderAdapter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AuthenticationProviderAdapter.java new file mode 100644 index 0000000000..8a75818f04 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AuthenticationProviderAdapter.java @@ -0,0 +1,487 @@ +/* + * + * 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.model.adapter; + +import java.io.IOException; +import java.security.AccessControlException; +import java.security.Principal; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.security.auth.login.AccountNotFoundException; + +import org.apache.log4j.Logger; +import org.apache.qpid.server.model.*; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.security.access.Operation; +import org.apache.qpid.server.security.auth.database.PrincipalDatabase; +import org.apache.qpid.server.security.auth.manager.AuthenticationManager; +import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager; +import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; + +public abstract class AuthenticationProviderAdapter<T extends AuthenticationManager> extends AbstractAdapter implements AuthenticationProvider +{ + private static final Logger LOGGER = Logger.getLogger(AuthenticationProviderAdapter.class); + + private final BrokerAdapter _broker; + private final T _authManager; + + private AuthenticationProviderAdapter(BrokerAdapter brokerAdapter, + final T authManager) + { + _broker = brokerAdapter; + _authManager = authManager; + } + + public static AuthenticationProviderAdapter createAuthenticationProviderAdapter(BrokerAdapter brokerAdapter, + final AuthenticationManager authManager) + { + return authManager instanceof PrincipalDatabaseAuthenticationManager + ? new PrincipalDatabaseAuthenticationManagerAdapter(brokerAdapter, (PrincipalDatabaseAuthenticationManager) authManager) + : new SimpleAuthenticationProviderAdapter(brokerAdapter, authManager); + } + + T getAuthManager() + { + return _authManager; + } + + @Override + public Collection<VirtualHostAlias> getVirtualHostPortBindings() + { + return Collections.emptyList(); + } + + @Override + public String getName() + { + return _authManager.getClass().getSimpleName(); + } + + @Override + public String setName(String currentName, String desiredName) throws IllegalStateException, AccessControlException + { + return null; + } + + @Override + public State getActualState() + { + return null; + } + + @Override + public boolean isDurable() + { + return true; + } + + @Override + public void setDurable(boolean durable) + throws IllegalStateException, AccessControlException, IllegalArgumentException + { + } + + @Override + public LifetimePolicy getLifetimePolicy() + { + return LifetimePolicy.PERMANENT; + } + + @Override + public LifetimePolicy setLifetimePolicy(LifetimePolicy expected, LifetimePolicy desired) + throws IllegalStateException, AccessControlException, IllegalArgumentException + { + return null; + } + + @Override + public long getTimeToLive() + { + return 0; + } + + @Override + public long setTimeToLive(long expected, long desired) + throws IllegalStateException, AccessControlException, IllegalArgumentException + { + return 0; + } + + @Override + public Statistics getStatistics() + { + return NoStatistics.getInstance(); + } + + @Override + public Collection<String> getAttributeNames() + { + return AuthenticationProvider.AVAILABLE_ATTRIBUTES; + } + + @Override + public Object getAttribute(String name) + { + if(TYPE.equals(name)) + { + return _authManager.getClass().getSimpleName(); + } + else if(CREATED.equals(name)) + { + // TODO + } + else if(DURABLE.equals(name)) + { + return true; + } + else if(ID.equals(name)) + { + return getId(); + } + else if(LIFETIME_POLICY.equals(name)) + { + return LifetimePolicy.PERMANENT; + } + else if(NAME.equals(name)) + { + return getName(); + } + else if(STATE.equals(name)) + { + return State.ACTIVE; // TODO + } + else if(TIME_TO_LIVE.equals(name)) + { + // TODO + } + else if(UPDATED.equals(name)) + { + // TODO + } + return super.getAttribute(name); + } + + @Override + public <C extends ConfiguredObject> Collection<C> getChildren(Class<C> clazz) + { + return null; + } + + @Override + public <C extends ConfiguredObject> C createChild(Class<C> childClass, + Map<String, Object> attributes, + ConfiguredObject... otherParents) + { + return null; + } + + private static class SimpleAuthenticationProviderAdapter extends AuthenticationProviderAdapter<AuthenticationManager> + { + public SimpleAuthenticationProviderAdapter( + BrokerAdapter brokerAdapter, AuthenticationManager authManager) + { + super(brokerAdapter,authManager); + } + } + + private static class PrincipalDatabaseAuthenticationManagerAdapter + extends AuthenticationProviderAdapter<PrincipalDatabaseAuthenticationManager> + implements PasswordCredentialManagingAuthenticationProvider + { + public PrincipalDatabaseAuthenticationManagerAdapter( + BrokerAdapter brokerAdapter, PrincipalDatabaseAuthenticationManager authManager) + { + super(brokerAdapter, authManager); + } + + @Override + public boolean createUser(String username, String password, Map<String, String> attributes) + { + return getPrincipalDatabase().createPrincipal(new UsernamePrincipal(username), password.toCharArray()); + } + + @Override + public void deleteUser(String username) throws AccountNotFoundException + { + if(getSecurityManager().authoriseMethod(Operation.DELETE, + "UserManagement", + "deleteUser")) + { + + getPrincipalDatabase().deletePrincipal(new UsernamePrincipal(username)); + } + else + { + throw new AccessControlException("Cannot delete user " + username); + } + } + + private org.apache.qpid.server.security.SecurityManager getSecurityManager() + { + return ApplicationRegistry.getInstance().getSecurityManager(); + } + + private PrincipalDatabase getPrincipalDatabase() + { + return getAuthManager().getPrincipalDatabase(); + } + + @Override + public void setPassword(String username, String password) throws AccountNotFoundException + { + getPrincipalDatabase().updatePassword(new UsernamePrincipal(username), password.toCharArray()); + } + + public void reload() throws IOException + { + if(getSecurityManager().authoriseMethod(Operation.UPDATE, "UserManagement", "reload")) + { + getPrincipalDatabase().reload(); + } + else + { + throw new AccessControlException("Do not have permission to reload principal database"); + } + } + + @Override + public Map<String, Map<String, String>> getUsers() + { + + Map<String, Map<String,String>> users = new HashMap<String, Map<String, String>>(); + for(Principal principal : getPrincipalDatabase().getUsers()) + { + users.put(principal.getName(), Collections.EMPTY_MAP); + } + return users; + } + + @Override + public <C extends ConfiguredObject> C createChild(Class<C> childClass, + Map<String, Object> attributes, + ConfiguredObject... otherParents) + { + if(childClass == User.class) + { + Principal p = new UsernamePrincipal((String) attributes.get("name")); + if(getSecurityManager().authoriseMethod(Operation.UPDATE, "UserManagement", "createUser")) + { + if(getPrincipalDatabase().createPrincipal(p, ((String)attributes.get("password")).toCharArray())) + { + return (C) new PrincipalAdapter(p); + } + } + else + { + throw new AccessControlException("Do not have permission to create a new user"); + } + + } + + return super.createChild(childClass, attributes, otherParents); + } + + @Override + public <C extends ConfiguredObject> Collection<C> getChildren(Class<C> clazz) + { + if(clazz == User.class) + { + List<Principal> users = getPrincipalDatabase().getUsers(); + Collection<User> principals = new ArrayList<User>(users.size()); + for(Principal user : users) + { + principals.add(new PrincipalAdapter(user)); + } + return (Collection<C>) Collections.unmodifiableCollection(principals); + } + else + { + return super.getChildren(clazz); + } + } + + private class PrincipalAdapter extends AbstractAdapter implements User + { + private final Principal _user; + + + public PrincipalAdapter(Principal user) + { + super(PrincipalDatabaseAuthenticationManagerAdapter.this.getName(), user.getName()); + _user = user; + + } + + @Override + public String getPassword() + { + return null; + } + + @Override + public void setPassword(String password) + { + try + { + PrincipalDatabaseAuthenticationManagerAdapter.this.setPassword(_user.getName(), password); + } + catch (AccountNotFoundException e) + { + throw new IllegalStateException(e); + } + } + + @Override + public String getName() + { + return _user.getName(); + } + + @Override + public String setName(String currentName, String desiredName) + throws IllegalStateException, AccessControlException + { + throw new IllegalStateException("Names cannot be updated"); + } + + @Override + public State getActualState() + { + return State.ACTIVE; + } + + @Override + public boolean isDurable() + { + return true; + } + + @Override + public void setDurable(boolean durable) + throws IllegalStateException, AccessControlException, IllegalArgumentException + { + throw new IllegalStateException("Durability cannot be updated"); + } + + @Override + public LifetimePolicy getLifetimePolicy() + { + return LifetimePolicy.PERMANENT; + } + + @Override + public LifetimePolicy setLifetimePolicy(LifetimePolicy expected, LifetimePolicy desired) + throws IllegalStateException, AccessControlException, IllegalArgumentException + { + throw new IllegalStateException("LifetimePolicy cannot be updated"); + } + + @Override + public long getTimeToLive() + { + return 0; + } + + @Override + public long setTimeToLive(long expected, long desired) + throws IllegalStateException, AccessControlException, IllegalArgumentException + { + throw new IllegalStateException("ttl cannot be updated"); + } + + @Override + public Statistics getStatistics() + { + return NoStatistics.getInstance(); + } + + @Override + public <C extends ConfiguredObject> Collection<C> getChildren(Class<C> clazz) + { + return null; + } + + @Override + public <C extends ConfiguredObject> C createChild(Class<C> childClass, + Map<String, Object> attributes, + ConfiguredObject... otherParents) + { + return null; + } + + @Override + public Collection<String> getAttributeNames() + { + return User.AVAILABLE_ATTRIBUTES; + } + + @Override + public Object getAttribute(String name) + { + if(ID.equals(name)) + { + return getId(); + } + else if(NAME.equals(name)) + { + return getName(); + } + return super.getAttribute(name); + } + + @Override + public Object setAttribute(String name, Object expected, Object desired) + throws IllegalStateException, AccessControlException, IllegalArgumentException + { + if(name.equals(PASSWORD)) + { + setPassword((String)desired); + } + return super.setAttribute(name, + expected, + desired); + } + + @Override + public State setDesiredState(State currentState, State desiredState) + throws IllegalStateTransitionException, AccessControlException + { + if(desiredState == State.DELETED) + { + try + { + deleteUser(_user.getName()); + } + catch (AccountNotFoundException e) + { + LOGGER.warn("Failed to delete user " + _user, e); + } + return State.DELETED; + } + return super.setDesiredState(currentState, desiredState); + } + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/BindingAdapter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/BindingAdapter.java new file mode 100644 index 0000000000..d3d04be70f --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/BindingAdapter.java @@ -0,0 +1,222 @@ +/* + * + * 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.model.adapter; + +import java.security.AccessControlException; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import org.apache.qpid.AMQInternalException; +import org.apache.qpid.AMQSecurityException; +import org.apache.qpid.server.model.Binding; +import org.apache.qpid.server.model.ConfiguredObject; +import org.apache.qpid.server.model.Exchange; +import org.apache.qpid.server.model.LifetimePolicy; +import org.apache.qpid.server.model.Queue; +import org.apache.qpid.server.model.State; +import org.apache.qpid.server.model.Statistics; + +final class BindingAdapter extends AbstractAdapter implements Binding +{ + private final org.apache.qpid.server.binding.Binding _binding; + private Statistics _statistics = NoStatistics.getInstance(); + private final ExchangeAdapter _exchange; + private QueueAdapter _queue; + + public BindingAdapter(final org.apache.qpid.server.binding.Binding binding, + ExchangeAdapter exchangeAdapter, + QueueAdapter queueAdapter) + { + super(exchangeAdapter.getExchange().getVirtualHost().getName(), + exchangeAdapter.getName(), + queueAdapter.getName(), + binding.getBindingKey()); + _binding = binding; + _exchange = exchangeAdapter; + _queue = queueAdapter; + addParent(Queue.class, queueAdapter); + addParent(Exchange.class, exchangeAdapter); + } + + + public ExchangeAdapter getExchange() + { + return _exchange; + } + + public QueueAdapter getQueue() + { + return _queue; + } + + public String getName() + { + return _binding.getBindingKey(); + } + + public String setName(final String currentName, final String desiredName) + throws IllegalStateException, AccessControlException + { + return null; //TODO + } + + public State getActualState() + { + return null; //TODO + } + + public boolean isDurable() + { + return _binding.getQueue().isDurable() && _binding.getExchange().isDurable(); + } + + public void setDurable(final boolean durable) + throws IllegalStateException, AccessControlException, IllegalArgumentException + { + //TODO + } + + public LifetimePolicy getLifetimePolicy() + { + return LifetimePolicy.PERMANENT; + } + + public LifetimePolicy setLifetimePolicy(final LifetimePolicy expected, final LifetimePolicy desired) + throws IllegalStateException, AccessControlException, IllegalArgumentException + { + return null; //TODO + } + + public long getTimeToLive() + { + return 0; //TODO + } + + public long setTimeToLive(final long expected, final long desired) + throws IllegalStateException, AccessControlException, IllegalArgumentException + { + return 0; //TODO + } + + public Statistics getStatistics() + { + return _statistics; + } + + @Override + public <C extends ConfiguredObject> Collection<C> getChildren(Class<C> clazz) + { + return Collections.emptySet(); + } + + @Override + public <C extends ConfiguredObject> C createChild(Class<C> childClass, Map<String, Object> attributes, ConfiguredObject... otherParents) + { + throw new IllegalArgumentException("Cannot add children to a binding"); + } + + public Map<String, Object> getArguments() + { + return new HashMap<String, Object> (_binding.getArguments()); + } + + public void delete() + { + try + { + _queue.getAMQQueue().getVirtualHost().getBindingFactory().removeBinding(_binding); + } + catch(AMQSecurityException e) + { + throw new AccessControlException(e.getMessage()); + } + catch(AMQInternalException e) + { + throw new IllegalStateException(e); + } + } + + @Override + public Object getAttribute(final String name) + { + if(ID.equals(name)) + { + return getId(); + } + else if(NAME.equals(name)) + { + return getName(); + } + else if(STATE.equals(name)) + { + + } + else if(DURABLE.equals(name)) + { + return _queue.isDurable() && _exchange.isDurable(); + } + else if(LIFETIME_POLICY.equals(name)) + { + return _queue.getLifetimePolicy() == LifetimePolicy.AUTO_DELETE || _exchange.getLifetimePolicy() == LifetimePolicy.AUTO_DELETE ? LifetimePolicy.AUTO_DELETE : LifetimePolicy.PERMANENT; + } + else if(TIME_TO_LIVE.equals(name)) + { + + } + else if(CREATED.equals(name)) + { + + } + else if(UPDATED.equals(name)) + { + + } + else if(EXCHANGE.equals(name)) + { + return _exchange.getName(); + } + else if(QUEUE.equals(name)) + { + return _queue.getName(); + } + else if(ARGUMENTS.equals(name)) + { + return getArguments(); + } + + return super.getAttribute(name); //TODO + } + + @Override + public Object setAttribute(final String name, final Object expected, final Object desired) + throws IllegalStateException, AccessControlException, IllegalArgumentException + { + return super.setAttribute(name, expected, desired); //TODO + } + + @Override + public Collection<String> getAttributeNames() + { + return Binding.AVAILABLE_ATTRIBUTES; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/BrokerAdapter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/BrokerAdapter.java new file mode 100644 index 0000000000..ad88dbc613 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/BrokerAdapter.java @@ -0,0 +1,484 @@ +/* + * + * 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.model.adapter; + +import java.net.InetSocketAddress; +import java.security.AccessControlException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import org.apache.qpid.common.QpidProperties; +import org.apache.qpid.server.model.AuthenticationProvider; +import org.apache.qpid.server.model.Broker; +import org.apache.qpid.server.model.ConfiguredObject; +import org.apache.qpid.server.model.LifetimePolicy; +import org.apache.qpid.server.model.Port; +import org.apache.qpid.server.model.State; +import org.apache.qpid.server.model.Statistics; +import org.apache.qpid.server.model.VirtualHost; +import org.apache.qpid.server.registry.IApplicationRegistry; +import org.apache.qpid.server.security.auth.manager.AuthenticationManager; +import org.apache.qpid.server.security.auth.manager.IAuthenticationManagerRegistry; +import org.apache.qpid.server.transport.QpidAcceptor; +import org.apache.qpid.server.virtualhost.VirtualHostRegistry; + +public class BrokerAdapter extends AbstractAdapter implements Broker, VirtualHostRegistry.RegistryChangeListener, + IApplicationRegistry.PortBindingListener, + IAuthenticationManagerRegistry.RegistryChangeListener +{ + + + private final IApplicationRegistry _applicationRegistry; + private String _name; + private final Map<org.apache.qpid.server.virtualhost.VirtualHost, VirtualHostAdapter> _vhostAdapters = + new HashMap<org.apache.qpid.server.virtualhost.VirtualHost, VirtualHostAdapter>(); + private final StatisticsAdapter _statistics; + private final Map<QpidAcceptor, PortAdapter> _portAdapters = new HashMap<QpidAcceptor, PortAdapter>(); + private HTTPPortAdapter _httpManagementPort; + private final Map<AuthenticationManager, AuthenticationProviderAdapter> _authManagerAdapters = + new HashMap<AuthenticationManager, AuthenticationProviderAdapter>(); + + + public BrokerAdapter(final IApplicationRegistry instance) + { + _applicationRegistry = instance; + _name = "Broker"; + _statistics = new StatisticsAdapter(instance); + + instance.getVirtualHostRegistry().addRegistryChangeListener(this); + populateVhosts(); + instance.addPortBindingListener(this); + populatePorts(); + instance.addRegistryChangeListener(this); + populateAuthenticationManagers(); + } + + private void populateVhosts() + { + synchronized(_vhostAdapters) + { + Collection<org.apache.qpid.server.virtualhost.VirtualHost> actualVhosts = + _applicationRegistry.getVirtualHostRegistry().getVirtualHosts(); + for(org.apache.qpid.server.virtualhost.VirtualHost vh : actualVhosts) + { + if(!_vhostAdapters.containsKey(vh)) + { + _vhostAdapters.put(vh, new VirtualHostAdapter(this, vh)); + } + } + + } + } + + + public Collection<VirtualHost> getVirtualHosts() + { + synchronized(_vhostAdapters) + { + return new ArrayList<VirtualHost>(_vhostAdapters.values()); + } + + } + private void populatePorts() + { + synchronized (_portAdapters) + { + Map<InetSocketAddress, QpidAcceptor> acceptors = _applicationRegistry.getAcceptors(); + + for(Map.Entry<InetSocketAddress, QpidAcceptor> entry : acceptors.entrySet()) + { + if(!_portAdapters.containsKey(entry.getValue())) + { + _portAdapters.put(entry.getValue(), new PortAdapter(this, entry.getValue(), entry.getKey())); + } + } + if(_applicationRegistry.useHTTPManagement()) + { + _httpManagementPort = new HTTPPortAdapter(this, _applicationRegistry.getHTTPManagementPort()); + } + + } + } + + public Collection<Port> getPorts() + { + synchronized (_portAdapters) + { + final ArrayList<Port> ports = new ArrayList<Port>(_portAdapters.values()); + if(_httpManagementPort != null) + { + ports.add(_httpManagementPort); + } + return ports; + } + } + + private void populateAuthenticationManagers() + { + synchronized (_authManagerAdapters) + { + IAuthenticationManagerRegistry authenticationManagerRegistry = + _applicationRegistry.getAuthenticationManagerRegistry(); + if(authenticationManagerRegistry != null) + { + Map<String, AuthenticationManager> authenticationManagers = + authenticationManagerRegistry.getAvailableAuthenticationManagers(); + + for(Map.Entry<String, AuthenticationManager> entry : authenticationManagers.entrySet()) + { + if(!_authManagerAdapters.containsKey(entry.getValue())) + { + _authManagerAdapters.put(entry.getValue(), + AuthenticationProviderAdapter.createAuthenticationProviderAdapter(this, + entry.getValue())); + } + } + } + } + } + + public Collection<AuthenticationProvider> getAuthenticationProviders() + { + synchronized (_authManagerAdapters) + { + final ArrayList<AuthenticationProvider> authManagers = + new ArrayList<AuthenticationProvider>(_authManagerAdapters.values()); + return authManagers; + } + + } + + public VirtualHost createVirtualHost(final String name, + final State initialState, + final boolean durable, + final LifetimePolicy lifetime, + final long ttl, + final Map<String, Object> attributes) + throws AccessControlException, IllegalArgumentException + { + return null; //TODO + } + + public VirtualHost createVirtualHost(final Map<String, Object> attributes) + throws AccessControlException, IllegalArgumentException + { + return null; //TODO + } + + public void deleteVirtualHost(final VirtualHost vhost) + throws AccessControlException, IllegalStateException + { + //TODO + throw new UnsupportedOperationException("Not yet implemented"); + } + + public String getName() + { + return _name; + } + + public String setName(final String currentName, final String desiredName) + throws IllegalStateException, AccessControlException + { + return null; //TODO + } + + + public State getActualState() + { + return null; //TODO + } + + + public boolean isDurable() + { + return true; + } + + public void setDurable(final boolean durable) + throws IllegalStateException, AccessControlException, IllegalArgumentException + { + throw new IllegalStateException(); + } + + public LifetimePolicy getLifetimePolicy() + { + return LifetimePolicy.PERMANENT; + } + + public LifetimePolicy setLifetimePolicy(final LifetimePolicy expected, final LifetimePolicy desired) + throws IllegalStateException, AccessControlException, IllegalArgumentException + { + throw new IllegalStateException(); + } + + public long getTimeToLive() + { + return 0; + } + + public long setTimeToLive(final long expected, final long desired) + throws IllegalStateException, AccessControlException, IllegalArgumentException + { + throw new IllegalStateException(); + } + + public Statistics getStatistics() + { + return _statistics; + } + + @Override + public <C extends ConfiguredObject> Collection<C> getChildren(Class<C> clazz) + { + if(clazz == VirtualHost.class) + { + return (Collection<C>) getVirtualHosts(); + } + else if(clazz == Port.class) + { + return (Collection<C>) getPorts(); + } + else if(clazz == AuthenticationProvider.class) + { + return (Collection<C>) getAuthenticationProviders(); + } + + return Collections.emptySet(); + } + + @Override + public <C extends ConfiguredObject> C createChild(Class<C> childClass, Map<String, Object> attributes, ConfiguredObject... otherParents) + { + if(childClass == VirtualHost.class) + { + return (C) createVirtualHost(attributes); + } + else if(childClass == Port.class) + { + return (C) createPort(attributes); + } + else if(childClass == AuthenticationProvider.class) + { + return (C) createAuthenticationProvider(attributes); + } + else + { + throw new IllegalArgumentException("Cannot create child of class " + childClass.getSimpleName()); + } + } + + private Port createPort(Map<String, Object> attributes) + { + // TODO + return null; + } + + private AuthenticationProvider createAuthenticationProvider(Map<String,Object> attributes) + { + // TODO + return null; + } + + + public void virtualHostRegistered(org.apache.qpid.server.virtualhost.VirtualHost virtualHost) + { + VirtualHostAdapter adapter = null; + synchronized (_vhostAdapters) + { + if(!_vhostAdapters.containsKey(virtualHost)) + { + adapter = new VirtualHostAdapter(this, virtualHost); + _vhostAdapters.put(virtualHost, adapter); + } + } + if(adapter != null) + { + childAdded(adapter); + } + } + + public void virtualHostUnregistered(org.apache.qpid.server.virtualhost.VirtualHost virtualHost) + { + VirtualHostAdapter adapter = null; + + synchronized (_vhostAdapters) + { + adapter = _vhostAdapters.remove(virtualHost); + } + if(adapter != null) + { + childRemoved(adapter); + } + } + + @Override + public void authenticationManagerRegistered(AuthenticationManager authenticationManager) + { + AuthenticationProviderAdapter adapter = null; + synchronized (_authManagerAdapters) + { + if(!_authManagerAdapters.containsKey(authenticationManager)) + { + adapter = + AuthenticationProviderAdapter.createAuthenticationProviderAdapter(this, authenticationManager); + _authManagerAdapters.put(authenticationManager, adapter); + } + } + if(adapter != null) + { + childAdded(adapter); + } + } + + @Override + public void authenticationManagerUnregistered(AuthenticationManager authenticationManager) + { + AuthenticationProviderAdapter adapter; + synchronized (_authManagerAdapters) + { + adapter = _authManagerAdapters.remove(authenticationManager); + } + if(adapter != null) + { + childRemoved(adapter); + } + } + + + @Override + public void bound(QpidAcceptor acceptor, InetSocketAddress bindAddress) + { + synchronized (_portAdapters) + { + if(!_portAdapters.containsKey(acceptor)) + { + PortAdapter adapter = new PortAdapter(this, acceptor, bindAddress); + _portAdapters.put(acceptor, adapter); + childAdded(adapter); + } + } + } + + @Override + public void unbound(QpidAcceptor acceptor) + { + PortAdapter adapter = null; + + synchronized (_portAdapters) + { + adapter = _portAdapters.remove(acceptor); + } + if(adapter != null) + { + childRemoved(adapter); + } + } + + @Override + public Collection<String> getAttributeNames() + { + return AVAILABLE_ATTRIBUTES; + } + + @Override + public Object getAttribute(String name) + { + if(ID.equals(name)) + { + return getId(); + } + else if(NAME.equals(name)) + { + return getName(); + } + else if(STATE.equals(name)) + { + return State.ACTIVE; + } + else if(DURABLE.equals(name)) + { + return isDurable(); + } + else if(LIFETIME_POLICY.equals(name)) + { + return LifetimePolicy.PERMANENT; + } + else if(TIME_TO_LIVE.equals(name)) + { + // TODO + } + else if(CREATED.equals(name)) + { + // TODO + } + else if(UPDATED.equals(name)) + { + // TODO + } + else if(BUILD_VERSION.equals(name)) + { + return QpidProperties.getBuildVersion(); + } + else if(BYTES_RETAINED.equals(name)) + { + // TODO + } + else if(OPERATING_SYSTEM.equals(name)) + { + return System.getProperty("os.name") + " " + + System.getProperty("os.version") + " " + + System.getProperty("os.arch"); + } + else if(PLATFORM.equals(name)) + { + return System.getProperty("java.vendor") + " " + + System.getProperty("java.runtime.version", System.getProperty("java.version")); + } + else if(PROCESS_PID.equals(name)) + { + // TODO + } + else if(PRODUCT_VERSION.equals(name)) + { + return QpidProperties.getReleaseVersion(); + } + else if(STATISTICS_ENABLED.equals(name)) + { + // TODO + } + else if(SUPPORTED_STORE_TYPES.equals(name)) + { + // TODO + } + + return super.getAttribute(name); //TODO - Implement. + } + + @Override + public Object setAttribute(String name, Object expected, Object desired) + throws IllegalStateException, AccessControlException, IllegalArgumentException + { + return super.setAttribute(name, expected, desired); //TODO - Implement. + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/ConnectionAdapter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/ConnectionAdapter.java new file mode 100644 index 0000000000..8114156e3a --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/ConnectionAdapter.java @@ -0,0 +1,315 @@ +/* + * + * 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.model.adapter; + +import java.security.AccessControlException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; + +import org.apache.qpid.AMQException; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.qpid.server.model.ConfiguredObject; +import org.apache.qpid.server.model.Connection; +import org.apache.qpid.server.model.LifetimePolicy; +import org.apache.qpid.server.model.Session; +import org.apache.qpid.server.model.State; +import org.apache.qpid.server.model.Statistics; +import org.apache.qpid.server.protocol.AMQConnectionModel; +import org.apache.qpid.server.protocol.AMQSessionModel; +import org.apache.qpid.server.stats.StatisticsGatherer; + +final class ConnectionAdapter extends AbstractAdapter implements Connection +{ + + + + + private AMQConnectionModel _connection; + + private final Map<AMQSessionModel, SessionAdapter> _sessionAdapters = + new HashMap<AMQSessionModel, SessionAdapter>(); + private final Statistics _statistics; + + public ConnectionAdapter(final AMQConnectionModel conn) + { + _connection = conn; + _statistics = new ConnectionStatisticsAdapter(conn); + } + + public Collection<Session> getSessions() + { + List<AMQSessionModel> actualSessions = _connection.getSessionModels(); + + synchronized (_sessionAdapters) + { + for(AMQSessionModel session : _sessionAdapters.keySet()) + { + if(!actualSessions.contains(session)) + { + _sessionAdapters.remove(session); + } + } + for(AMQSessionModel session : actualSessions) + { + if(!_sessionAdapters.containsKey(session)) + { + _sessionAdapters.put(session, new SessionAdapter(session)); + } + } + return new ArrayList<Session>(_sessionAdapters.values()); + } + } + + public void delete() + { + try + { + _connection.close(AMQConstant.CONNECTION_FORCED, "Connection closed by external action"); + } + catch(AMQException e) + { + throw new IllegalStateException(e); + } + } + + public String getName() + { + final String remoteAddressString = _connection.getRemoteAddressString(); + return remoteAddressString.replaceAll("/",""); + } + + public String setName(final String currentName, final String desiredName) + throws IllegalStateException, AccessControlException + { + return null; //TODO + } + + public State getActualState() + { + return null; //TODO + } + + public boolean isDurable() + { + return false; //TODO + } + + public void setDurable(final boolean durable) + throws IllegalStateException, AccessControlException, IllegalArgumentException + { + //TODO + } + + public LifetimePolicy getLifetimePolicy() + { + return null; //TODO + } + + public LifetimePolicy setLifetimePolicy(final LifetimePolicy expected, final LifetimePolicy desired) + throws IllegalStateException, AccessControlException, IllegalArgumentException + { + return null; //TODO + } + + public long getTimeToLive() + { + return 0; //TODO + } + + public long setTimeToLive(final long expected, final long desired) + throws IllegalStateException, AccessControlException, IllegalArgumentException + { + return 0; //TODO + } + + @Override + public Object getAttribute(String name) + { + + if(name.equals(ID)) + { + return getId(); + } + else if (name.equals(NAME)) + { + return getName(); + } + else if(name.equals(CLIENT_ID)) + { + return _connection.getClientId(); + } + else if(name.equals(CLIENT_VERSION)) + { + return _connection.getClientVersion(); + } + else if(name.equals(INCOMING)) + { + + } + else if(name.equals(LOCAL_ADDRESS)) + { + + } + else if(name.equals(PRINCIPAL)) + { + return _connection.getPrincipalAsString(); + } + else if(name.equals(PROPERTIES)) + { + + } + else if(name.equals(REMOTE_ADDRESS)) + { + return _connection.getRemoteAddressString(); + } + else if(name.equals(REMOTE_PROCESS_NAME)) + { + + } + else if(name.equals(REMOTE_PROCESS_PID)) + { + + } + else if(name.equals(SESSION_COUNT_LIMIT)) + { + return _connection.getSessionCountLimit(); + } + return super.getAttribute(name); + } + + @Override + public Object setAttribute(String name, Object expected, Object desired) throws IllegalStateException, AccessControlException, IllegalArgumentException + { + if(name.equals(CLIENT_ID)) + { + + } + else if(name.equals(CLIENT_VERSION)) + { + + } + else if(name.equals(INCOMING)) + { + + } + else if(name.equals(LOCAL_ADDRESS)) + { + + } + else if(name.equals(PRINCIPAL)) + { + + } + else if(name.equals(PROPERTIES)) + { + + } + else if(name.equals(REMOTE_ADDRESS)) + { + + } + else if(name.equals(REMOTE_PROCESS_NAME)) + { + + } + else if(name.equals(REMOTE_PROCESS_PID)) + { + + } + else if(name.equals(SESSION_COUNT_LIMIT)) + { + + } + return super.setAttribute(name, expected, desired); + } + + @Override + public Collection<String> getAttributeNames() + { + final HashSet<String> attrNames = new HashSet<String>(super.getAttributeNames()); + attrNames.addAll(Connection.AVAILABLE_ATTRIBUTES); + return Collections.unmodifiableCollection(attrNames); + } + + public Statistics getStatistics() + { + return _statistics; + } + + @Override + public <C extends ConfiguredObject> Collection<C> getChildren(Class<C> clazz) + { + if(clazz == Session.class) + { + return (Collection<C>) getSessions(); + } + else + { + return Collections.emptySet(); + } + } + + public <C extends ConfiguredObject> C createChild(Class<C> childClass, Map<String, Object> attributes, ConfiguredObject... otherParents) + { + if(childClass == Session.class) + { + throw new IllegalStateException(); + } + else + { + throw new IllegalArgumentException("Cannot create a child of class " + childClass.getSimpleName()); + } + + } + + private class ConnectionStatisticsAdapter extends StatisticsAdapter + { + public ConnectionStatisticsAdapter(StatisticsGatherer applicationRegistry) + { + super(applicationRegistry); + } + + @Override + public Collection<String> getStatisticNames() + { + return Connection.AVAILABLE_STATISTICS; + } + + @Override + public Object getStatistic(String name) + { + if(LAST_IO_TIME.equals(name)) + { + return _connection.getLastIoTime(); + } + else if(SESSION_COUNT.equals(name)) + { + return _connection.getSessionModels().size(); + } + return super.getStatistic(name); + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/ConsumerAdapter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/ConsumerAdapter.java new file mode 100644 index 0000000000..6fb6f4971d --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/ConsumerAdapter.java @@ -0,0 +1,225 @@ +/* + * + * 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.model.adapter; + +import java.util.Map; +import org.apache.qpid.server.model.ConfiguredObject; +import org.apache.qpid.server.model.Consumer; +import org.apache.qpid.server.model.LifetimePolicy; +import org.apache.qpid.server.model.State; +import org.apache.qpid.server.model.Statistics; +import org.apache.qpid.server.subscription.Subscription; + +import java.security.AccessControlException; +import java.util.Collection; +import java.util.Collections; + +public class ConsumerAdapter extends AbstractAdapter implements Consumer +{ + private final Subscription _subscription; + private final QueueAdapter _queue; + private final ConsumerStatistics _statistics; + + public ConsumerAdapter(final QueueAdapter queueAdapter, final Subscription subscription) + { + super(queueAdapter.getVirtualHost().getName(), + queueAdapter.getName(), + subscription.getSessionModel().getConnectionModel().getRemoteAddressString(), + String.valueOf(subscription.getSessionModel().getChannelId()), + subscription.getConsumerName() ); + + _subscription = subscription; + _queue = queueAdapter; + _statistics = new ConsumerStatistics(); + //TODO + } + + public String getName() + { + return _subscription.getConsumerName(); + } + + public String setName(final String currentName, final String desiredName) + throws IllegalStateException, AccessControlException + { + return null; //TODO + } + + public State getActualState() + { + return null; //TODO + } + + public boolean isDurable() + { + return false; //TODO + } + + public void setDurable(final boolean durable) + throws IllegalStateException, AccessControlException, IllegalArgumentException + { + //TODO + } + + public LifetimePolicy getLifetimePolicy() + { + return null; //TODO + } + + public LifetimePolicy setLifetimePolicy(final LifetimePolicy expected, final LifetimePolicy desired) + throws IllegalStateException, AccessControlException, IllegalArgumentException + { + return null; //TODO + } + + public long getTimeToLive() + { + return 0; //TODO + } + + public long setTimeToLive(final long expected, final long desired) + throws IllegalStateException, AccessControlException, IllegalArgumentException + { + return 0; //TODO + } + + @Override + public Collection<String> getAttributeNames() + { + return Consumer.AVAILABLE_ATTRIBUTES; + } + + @Override + public Object setAttribute(final String name, final Object expected, final Object desired) + throws IllegalStateException, AccessControlException, IllegalArgumentException + { + return super.setAttribute(name, expected, desired); //TODO + } + + @Override + public Object getAttribute(final String name) + { + if(ID.equals(name)) + { + return getId(); + } + else if(NAME.equals(name)) + { + return getName(); + } + else if(STATE.equals(name)) + { + + } + else if(DURABLE.equals(name)) + { + return false; + } + else if(LIFETIME_POLICY.equals(name)) + { + return LifetimePolicy.AUTO_DELETE; + } + else if(TIME_TO_LIVE.equals(name)) + { + + } + else if(CREATED.equals(name)) + { + + } + else if(UPDATED.equals(name)) + { + + } + else if(DISTRIBUTION_MODE.equals(name)) + { + return _subscription.acquires() ? "MOVE" : "COPY"; + } + else if(SETTLEMENT_MODE.equals(name)) + { + + } + else if(EXCLUSIVE.equals(name)) + { + + } + else if(NO_LOCAL.equals(name)) + { + + } + else if(SELECTOR.equals(name)) + { + + } + return super.getAttribute(name); //TODO + } + + public Statistics getStatistics() + { + return _statistics; + } + + @Override + public <C extends ConfiguredObject> Collection<C> getChildren(Class<C> clazz) + { + return Collections.emptySet(); + } + + @Override + public <C extends ConfiguredObject> C createChild(Class<C> childClass, Map<String, Object> attributes, ConfiguredObject... otherParents) + { + throw new IllegalArgumentException(); + } + + private class ConsumerStatistics implements Statistics + { + + public Collection<String> getStatisticNames() + { + return AVAILABLE_STATISTICS; + } + + public Object getStatistic(String name) + { + if(name.equals(BYTES_OUT)) + { + return _subscription.getBytesOut(); + } + else if(name.equals(MESSAGES_OUT)) + { + return _subscription.getMessagesOut(); + } + else if(name.equals(STATE_CHANGED)) + { + + } + else if(name.equals(UNACKNOWLEDGED_BYTES)) + { + return _subscription.getUnacknowledgedBytes(); + } + else if(name.equals(UNACKNOWLEDGED_MESSAGES)) + { + return _subscription.getUnacknowledgedMessages(); + } + return null; // TODO - Implement + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/ExchangeAdapter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/ExchangeAdapter.java new file mode 100644 index 0000000000..dd22804355 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/ExchangeAdapter.java @@ -0,0 +1,409 @@ +/* + * + * 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.model.adapter; + +import java.security.AccessControlException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import org.apache.qpid.AMQException; +import org.apache.qpid.AMQInternalException; +import org.apache.qpid.AMQSecurityException; +import org.apache.qpid.server.binding.Binding; +import org.apache.qpid.server.model.ConfiguredObject; +import org.apache.qpid.server.model.Exchange; +import org.apache.qpid.server.model.LifetimePolicy; +import org.apache.qpid.server.model.Publisher; +import org.apache.qpid.server.model.Queue; +import org.apache.qpid.server.model.State; +import org.apache.qpid.server.model.Statistics; +import org.apache.qpid.server.model.UUIDGenerator; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.virtualhost.VirtualHost; + +final class ExchangeAdapter extends AbstractAdapter implements Exchange, org.apache.qpid.server.exchange.Exchange.BindingListener +{ + + private final org.apache.qpid.server.exchange.Exchange _exchange; + private final Map<Binding, BindingAdapter> _bindingAdapters = + new HashMap<Binding, BindingAdapter>(); + private VirtualHostAdapter _vhost; + private final ExchangeStatistics _statistics; + + + public ExchangeAdapter(final VirtualHostAdapter virtualHostAdapter, + final org.apache.qpid.server.exchange.Exchange exchange) + { + super(virtualHostAdapter.getName(), exchange.getName()); + _statistics = new ExchangeStatistics(); + _vhost = virtualHostAdapter; + _exchange = exchange; + addParent(org.apache.qpid.server.model.VirtualHost.class, virtualHostAdapter); + + exchange.addBindingListener(this); + populateBindings(); + } + + private void populateBindings() + { + Collection<Binding> actualBindings = _exchange.getBindings(); + synchronized (_bindingAdapters) + { + for(Binding binding : actualBindings) + { + if(!_bindingAdapters.containsKey(binding)) + { + QueueAdapter queueAdapter = _vhost.getQueueAdapter(binding.getQueue()); + BindingAdapter adapter = new BindingAdapter(binding, this, queueAdapter); + _bindingAdapters.put(binding, adapter); + + queueAdapter.bindingRegistered(binding, adapter); + } + } + } + + } + + public String getExchangeType() + { + return _exchange.getType().getName().toString(); + } + + public Collection<org.apache.qpid.server.model.Binding> getBindings() + { + synchronized (_bindingAdapters) + { + return new ArrayList<org.apache.qpid.server.model.Binding>(_bindingAdapters.values()); + } + + } + + public Collection<Publisher> getPublishers() + { + // TODO + return Collections.emptyList(); + } + + + public org.apache.qpid.server.model.Binding createBinding(Queue queue, + Map<String, Object> attributes) + throws AccessControlException, IllegalStateException + { + attributes = new HashMap<String, Object>(attributes); + String bindingKey = getStringAttribute(org.apache.qpid.server.model.Binding.NAME, attributes, ""); + Map<String, Object> bindingArgs = getMapAttribute(org.apache.qpid.server.model.Binding.ARGUMENTS, attributes, Collections.EMPTY_MAP); + + attributes.remove(org.apache.qpid.server.model.Binding.NAME); + attributes.remove(org.apache.qpid.server.model.Binding.ARGUMENTS); + + return createBinding(bindingKey, queue, bindingArgs, attributes); + + } + + public org.apache.qpid.server.model.Binding createBinding(String bindingKey, Queue queue, + Map<String, Object> bindingArguments, + Map<String, Object> attributes) + throws AccessControlException, IllegalStateException + { + VirtualHost virtualHost = _vhost.getVirtualHost(); + + + AMQQueue amqQueue = ((QueueAdapter)queue).getAMQQueue(); + + try + { + if(!virtualHost.getBindingFactory().addBinding(bindingKey, amqQueue, _exchange, bindingArguments)) + { + Binding oldBinding = virtualHost.getBindingFactory().getBinding(bindingKey, amqQueue, _exchange, + bindingArguments); + + Map<String, Object> oldArgs = oldBinding.getArguments(); + if((oldArgs == null && !bindingArguments.isEmpty()) || (oldArgs != null && !oldArgs.equals(bindingArguments))) + { + //TODO: generate deterministic UUID + virtualHost.getBindingFactory().replaceBinding(UUIDGenerator.generateUUID(), bindingKey, amqQueue, _exchange, bindingArguments); + } + } + Binding binding = virtualHost.getBindingFactory().getBinding(bindingKey, amqQueue, _exchange, bindingArguments); + + synchronized (_bindingAdapters) + { + return binding == null ? null : _bindingAdapters.get(binding); + } + } + catch(AMQSecurityException e) + { + throw new AccessControlException(e.toString()); + } + catch(AMQInternalException e) + { + throw new IllegalStateException(e); + } + } + + public void delete() + { + try + { + _vhost.getVirtualHost().getExchangeRegistry().unregisterExchange(getName(), false); + } + catch(AMQException e) + { + throw new IllegalStateException(e); + } + } + + public String getName() + { + return _exchange.getName(); + } + + public String setName(final String currentName, final String desiredName) + throws IllegalStateException, AccessControlException + { + return null; //TODO + } + + public State getActualState() + { + return null; //TODO + } + + public boolean isDurable() + { + return _exchange.isDurable(); + } + + public void setDurable(final boolean durable) + throws IllegalStateException, AccessControlException, IllegalArgumentException + { + //TODO + } + + public LifetimePolicy getLifetimePolicy() + { + return _exchange.isAutoDelete() ? LifetimePolicy.AUTO_DELETE : LifetimePolicy.PERMANENT; + } + + public LifetimePolicy setLifetimePolicy(final LifetimePolicy expected, final LifetimePolicy desired) + throws IllegalStateException, AccessControlException, IllegalArgumentException + { + return null; //TODO + } + + public long getTimeToLive() + { + return 0; //TODO + } + + public long setTimeToLive(final long expected, final long desired) + throws IllegalStateException, AccessControlException, IllegalArgumentException + { + return 0; //TODO + } + + public Statistics getStatistics() + { + return _statistics; + } + + @Override + public <C extends ConfiguredObject> Collection<C> getChildren(Class<C> clazz) + { + if(clazz == org.apache.qpid.server.model.Binding.class) + { + return (Collection<C>) getBindings(); + } + else + { + return Collections.emptySet(); + } + } + + @Override + public <C extends ConfiguredObject> C createChild(Class<C> childClass, Map<String, Object> attributes, ConfiguredObject... otherParents) + { + if(childClass == org.apache.qpid.server.model.Binding.class) + { + if(otherParents != null && otherParents.length == 1 && otherParents[0] instanceof Queue) + { + Queue queue = (Queue) otherParents[0]; + if(queue.getParent(org.apache.qpid.server.model.VirtualHost.class) == getParent(org.apache.qpid.server.model.VirtualHost.class)) + { + return (C) createBinding(queue, attributes); + } + else + { + throw new IllegalArgumentException("Queue and Exchange parents of a binding must be on same virtual host"); + } + } + else + { + throw new IllegalArgumentException("Other parent must be a queue"); + } + } + else + { + throw new IllegalArgumentException(); + } + } + + public void bindingAdded(org.apache.qpid.server.exchange.Exchange exchange, Binding binding) + { + BindingAdapter adapter = null; + synchronized (_bindingAdapters) + { + if(!_bindingAdapters.containsKey(binding)) + { + QueueAdapter queueAdapter = _vhost.getQueueAdapter(binding.getQueue()); + adapter = new BindingAdapter(binding, this, queueAdapter); + _bindingAdapters.put(binding,adapter); + queueAdapter.bindingRegistered(binding,adapter); + } + } + if(adapter != null) + { + childAdded(adapter); + } + } + + public void bindingRemoved(org.apache.qpid.server.exchange.Exchange exchange, Binding binding) + { + BindingAdapter adapter = null; + synchronized (_bindingAdapters) + { + adapter = _bindingAdapters.remove(binding); + } + if(adapter != null) + { + _vhost.getQueueAdapter(binding.getQueue()).bindingUnregistered(binding); + childRemoved(adapter); + } + } + + org.apache.qpid.server.exchange.Exchange getExchange() + { + return _exchange; + } + + @Override + public Object getAttribute(String name) + { + if(ID.equals(name)) + { + return getId(); + } + else if(NAME.equals(name)) + { + return getName(); + } + else if(STATE.equals(name)) + { + return State.ACTIVE; + } + else if(DURABLE.equals(name)) + { + return isDurable(); + } + else if(LIFETIME_POLICY.equals(name)) + { + return _exchange.isAutoDelete() ? LifetimePolicy.AUTO_DELETE : LifetimePolicy.PERMANENT; + } + else if(TIME_TO_LIVE.equals(name)) + { + + } + else if(CREATED.equals(name)) + { + + } + else if(UPDATED.equals(name)) + { + + } + else if(ALTERNATE_EXCHANGE.equals(name)) + { + return _exchange.getAlternateExchange(); + } + else if(TYPE.equals(name)) + { + return _exchange.getType().getName().asString(); + } + return super.getAttribute(name); + } + + @Override + public Object setAttribute(String name, Object expected, Object desired) + throws IllegalStateException, AccessControlException, IllegalArgumentException + { + return super.setAttribute(name, expected, desired); //TODO - Implement + } + + @Override + public Collection<String> getAttributeNames() + { + return AVAILABLE_ATTRIBUTES; + } + + private class ExchangeStatistics implements Statistics + { + + public Collection<String> getStatisticNames() + { + return AVAILABLE_STATISTICS; + } + + public Object getStatistic(String name) + { + if(BINDING_COUNT.equals(name)) + { + return _exchange.getBindingCount(); + } + else if(BYTES_DROPPED.equals(name)) + { + return _exchange.getByteDrops(); + } + else if(BYTES_IN.equals(name)) + { + return _exchange.getByteReceives(); + } + else if(MESSAGES_DROPPED.equals(name)) + { + return _exchange.getMsgDrops(); + } + else if(MESSAGES_IN.equals(name)) + { + return _exchange.getMsgReceives(); + } + else if(PRODUCER_COUNT.equals(name)) + { + + } + else if(STATE_CHANGED.equals(name)) + { + + } + return null; // TODO - Implement + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/HTTPPortAdapter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/HTTPPortAdapter.java new file mode 100644 index 0000000000..fdcc5e0184 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/HTTPPortAdapter.java @@ -0,0 +1,262 @@ +/* + * + * 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.model.adapter; + +import java.security.AccessControlException; +import java.util.Collection; +import java.util.Collections; +import java.util.Map; +import org.apache.qpid.server.model.ConfiguredObject; +import org.apache.qpid.server.model.Connection; +import org.apache.qpid.server.model.LifetimePolicy; +import org.apache.qpid.server.model.Port; +import org.apache.qpid.server.model.Protocol; +import org.apache.qpid.server.model.State; +import org.apache.qpid.server.model.Statistics; +import org.apache.qpid.server.model.Transport; +import org.apache.qpid.server.model.VirtualHostAlias; + +public class HTTPPortAdapter extends AbstractAdapter implements Port +{ + private final BrokerAdapter _broker; + private int _port; + public HTTPPortAdapter(BrokerAdapter brokerAdapter, int port) + { + _broker = brokerAdapter; + _port = port; + + } + + @Override + public String getBindingAddress() + { + return "0.0.0.0"; + } + + @Override + public int getPort() + { + return _port; + } + + @Override + public Collection<Transport> getTransports() + { + return Collections.singleton(Transport.TCP); + } + + @Override + public void addTransport(Transport transport) + throws IllegalStateException, AccessControlException, IllegalArgumentException + { + throw new IllegalStateException(); // TODO - Implement + } + + @Override + public Transport removeTransport(Transport transport) + throws IllegalStateException, AccessControlException, IllegalArgumentException + { + throw new IllegalStateException(); // TODO - Implement + } + + @Override + public Collection<Protocol> getProtocols() + { + return Collections.singleton(Protocol.HTTP); + } + + @Override + public void addProtocol(Protocol protocol) + throws IllegalStateException, AccessControlException, IllegalArgumentException + { + throw new IllegalStateException(); // TODO - Implement + } + + @Override + public Protocol removeProtocol(Protocol protocol) + throws IllegalStateException, AccessControlException, IllegalArgumentException + { + throw new IllegalStateException(); // TODO - Implement + } + + @Override + public Collection<VirtualHostAlias> getVirtualHostBindings() + { + return Collections.emptySet(); + } + + @Override + public Collection<Connection> getConnections() + { + return Collections.emptySet(); // TODO - Implement + } + + @Override + public String getName() + { + return getBindingAddress() + ":" + getPort(); // TODO - Implement + } + + @Override + public String setName(String currentName, String desiredName) throws IllegalStateException, AccessControlException + { + throw new IllegalStateException(); // TODO - Implement + } + + @Override + public State getActualState() + { + return State.ACTIVE; + } + + @Override + public boolean isDurable() + { + return false; // TODO - Implement + } + + @Override + public void setDurable(boolean durable) + throws IllegalStateException, AccessControlException, IllegalArgumentException + { + throw new IllegalStateException(); + } + + @Override + public LifetimePolicy getLifetimePolicy() + { + return LifetimePolicy.PERMANENT; + } + + @Override + public LifetimePolicy setLifetimePolicy(LifetimePolicy expected, LifetimePolicy desired) + throws IllegalStateException, AccessControlException, IllegalArgumentException + { + throw new IllegalStateException(); // TODO - Implement + } + + @Override + public long getTimeToLive() + { + return 0; // TODO - Implement + } + + @Override + public long setTimeToLive(long expected, long desired) + throws IllegalStateException, AccessControlException, IllegalArgumentException + { + throw new IllegalStateException(); // TODO - Implement + } + + @Override + public Statistics getStatistics() + { + return NoStatistics.getInstance(); + } + + @Override + public <C extends ConfiguredObject> Collection<C> getChildren(Class<C> clazz) + { + if(clazz == Connection.class) + { + return (Collection<C>) getConnections(); + } + else + { + return Collections.emptySet(); + } + } + + @Override + public <C extends ConfiguredObject> C createChild(Class<C> childClass, Map<String, Object> attributes, ConfiguredObject... otherParents) + { + throw new UnsupportedOperationException(); + } + + @Override + public Object getAttribute(String name) + { + if(ID.equals(name)) + { + return getId(); + } + else if(NAME.equals(name)) + { + return getName(); + } + else if(STATE.equals(name)) + { + return getActualState(); + } + else if(DURABLE.equals(name)) + { + return isDurable(); + } + else if(LIFETIME_POLICY.equals(name)) + { + return getLifetimePolicy(); + } + else if(TIME_TO_LIVE.equals(name)) + { + return getTimeToLive(); + } + else if(CREATED.equals(name)) + { + + } + else if(UPDATED.equals(name)) + { + + } + else if(BINDING_ADDRESS.equals(name)) + { + return getBindingAddress(); + } + else if(PORT.equals(name)) + { + return getPort(); + } + else if(PROTOCOLS.equals(name)) + { + return getProtocols(); + } + else if(TRANSPORTS.equals(name)) + { + return getTransports(); + } + + return super.getAttribute(name); //TODO - Implement + } + + @Override + public Collection<String> getAttributeNames() + { + return AVAILABLE_ATTRIBUTES; + } + + @Override + public Object setAttribute(String name, Object expected, Object desired) + throws IllegalStateException, AccessControlException, IllegalArgumentException + { + return super.setAttribute(name, expected, desired); //TODO - Implement + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/NoStatistics.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/NoStatistics.java new file mode 100644 index 0000000000..b83887ffe5 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/NoStatistics.java @@ -0,0 +1,46 @@ +package org.apache.qpid.server.model.adapter; + +import org.apache.qpid.server.model.Statistics; + +import java.util.Collection; +import java.util.Collections; + +/** + * 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 + * <p/> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p/> + * 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. + */ +public class NoStatistics implements Statistics +{ + private static final NoStatistics INSTANCE = new NoStatistics(); + + private NoStatistics() + { + } + + public Collection<String> getStatisticNames() + { + return Collections.emptyList(); + } + + public Object getStatistic(String name) + { + return null; + } + + public static NoStatistics getInstance() + { + return INSTANCE; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/PortAdapter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/PortAdapter.java new file mode 100644 index 0000000000..0021431ee3 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/PortAdapter.java @@ -0,0 +1,318 @@ +/* + * + * 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.model.adapter; + +import java.util.Map; +import org.apache.qpid.server.model.ConfiguredObject; +import org.apache.qpid.server.model.Connection; +import org.apache.qpid.server.model.LifetimePolicy; +import org.apache.qpid.server.model.Port; +import org.apache.qpid.server.model.Protocol; +import org.apache.qpid.server.model.State; +import org.apache.qpid.server.model.Statistics; +import org.apache.qpid.server.model.Transport; +import org.apache.qpid.server.model.VirtualHost; +import org.apache.qpid.server.model.VirtualHostAlias; +import org.apache.qpid.server.protocol.AmqpProtocolVersion; +import org.apache.qpid.server.transport.QpidAcceptor; + +import java.net.InetSocketAddress; +import java.security.AccessControlException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +public class PortAdapter extends AbstractAdapter implements Port +{ + private final BrokerAdapter _broker; + private final QpidAcceptor _acceptor; + private final InetSocketAddress _address; + private final Collection<Protocol> _protocols; + + public PortAdapter(BrokerAdapter brokerAdapter, QpidAcceptor acceptor, InetSocketAddress address) + { + _broker = brokerAdapter; + _acceptor = acceptor; + _address = address; + + List<Protocol> protocols = new ArrayList<Protocol>(); + + for(AmqpProtocolVersion pv : _acceptor.getSupported()) + { + switch(pv) + { + case v0_8: + protocols.add(Protocol.AMQP_0_8); + break; + case v0_9: + protocols.add(Protocol.AMQP_0_9); + break; + case v0_9_1: + protocols.add(Protocol.AMQP_0_9_1); + break; + case v0_10: + protocols.add(Protocol.AMQP_0_10); + break; + case v1_0_0: + protocols.add(Protocol.AMQP_1_0); + break; + } + } + + _protocols = Collections.unmodifiableCollection(protocols); + + } + + @Override + public String getBindingAddress() + { + return _address.getHostName(); + } + + @Override + public int getPort() + { + return _address.getPort(); + } + + @Override + public Collection<Transport> getTransports() + { + switch (_acceptor.getTransport()) + { + case TCP: + return Collections.singleton(Transport.TCP); + case SSL: + return Collections.singleton(Transport.SSL); + } + + return null; // TODO - Implement + } + + @Override + public void addTransport(Transport transport) + throws IllegalStateException, AccessControlException, IllegalArgumentException + { + throw new IllegalStateException(); // TODO - Implement + } + + @Override + public Transport removeTransport(Transport transport) + throws IllegalStateException, AccessControlException, IllegalArgumentException + { + throw new IllegalStateException(); // TODO - Implement + } + + @Override + public Collection<Protocol> getProtocols() + { + return _protocols; + } + + @Override + public void addProtocol(Protocol protocol) + throws IllegalStateException, AccessControlException, IllegalArgumentException + { + throw new IllegalStateException(); // TODO - Implement + } + + @Override + public Protocol removeProtocol(Protocol protocol) + throws IllegalStateException, AccessControlException, IllegalArgumentException + { + throw new IllegalStateException(); // TODO - Implement + } + + @Override + public Collection<VirtualHostAlias> getVirtualHostBindings() + { + List<VirtualHostAlias> aliases = new ArrayList<VirtualHostAlias>(); + for(VirtualHost vh : _broker.getVirtualHosts()) + { + for(VirtualHostAlias alias : vh.getAliases()) + { + if(alias.getPort().equals(this)) + { + aliases.add(alias); + } + } + } + return Collections.unmodifiableCollection(aliases); + } + + @Override + public Collection<Connection> getConnections() + { + return null; // TODO - Implement + } + + @Override + public String getName() + { + return getBindingAddress() + ":" + getPort(); // TODO - Implement + } + + @Override + public String setName(String currentName, String desiredName) throws IllegalStateException, AccessControlException + { + throw new IllegalStateException(); // TODO - Implement + } + + @Override + public State getActualState() + { + return State.ACTIVE; + } + + @Override + public boolean isDurable() + { + return false; // TODO - Implement + } + + @Override + public void setDurable(boolean durable) + throws IllegalStateException, AccessControlException, IllegalArgumentException + { + throw new IllegalStateException(); + } + + @Override + public LifetimePolicy getLifetimePolicy() + { + return LifetimePolicy.PERMANENT; + } + + @Override + public LifetimePolicy setLifetimePolicy(LifetimePolicy expected, LifetimePolicy desired) + throws IllegalStateException, AccessControlException, IllegalArgumentException + { + throw new IllegalStateException(); // TODO - Implement + } + + @Override + public long getTimeToLive() + { + return 0; // TODO - Implement + } + + @Override + public long setTimeToLive(long expected, long desired) + throws IllegalStateException, AccessControlException, IllegalArgumentException + { + throw new IllegalStateException(); // TODO - Implement + } + + @Override + public Statistics getStatistics() + { + return NoStatistics.getInstance(); + } + + @Override + public <C extends ConfiguredObject> Collection<C> getChildren(Class<C> clazz) + { + if(clazz == Connection.class) + { + return (Collection<C>) getConnections(); + } + else + { + return Collections.emptySet(); + } + } + + @Override + public <C extends ConfiguredObject> C createChild(Class<C> childClass, Map<String, Object> attributes, ConfiguredObject... otherParents) + { + throw new UnsupportedOperationException(); + } + + @Override + public Object getAttribute(String name) + { + if(ID.equals(name)) + { + return getId(); + } + else if(NAME.equals(name)) + { + return getName(); + } + else if(STATE.equals(name)) + { + return getActualState(); + } + else if(DURABLE.equals(name)) + { + return isDurable(); + } + else if(LIFETIME_POLICY.equals(name)) + { + return getLifetimePolicy(); + } + else if(TIME_TO_LIVE.equals(name)) + { + return getTimeToLive(); + } + else if(CREATED.equals(name)) + { + + } + else if(UPDATED.equals(name)) + { + + } + else if(BINDING_ADDRESS.equals(name)) + { + return getBindingAddress(); + } + else if(PORT.equals(name)) + { + return getPort(); + } + else if(PROTOCOLS.equals(name)) + { + return getProtocols(); + } + else if(TRANSPORTS.equals(name)) + { + return getTransports(); + } + + return super.getAttribute(name); //TODO - Implement + } + + @Override + public Collection<String> getAttributeNames() + { + return AVAILABLE_ATTRIBUTES; + } + + @Override + public Object setAttribute(String name, Object expected, Object desired) + throws IllegalStateException, AccessControlException, IllegalArgumentException + { + return super.setAttribute(name, expected, desired); //TODO - Implement + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/QueueAdapter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/QueueAdapter.java new file mode 100644 index 0000000000..5c35fe5f7b --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/QueueAdapter.java @@ -0,0 +1,702 @@ +/* + * + * 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.model.adapter; + +import java.security.AccessControlException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import org.apache.qpid.AMQException; +import org.apache.qpid.AMQStoreException; +import org.apache.qpid.server.binding.Binding; +import org.apache.qpid.server.model.ConfiguredObject; +import org.apache.qpid.server.model.ConfiguredObjectFinder; +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.Queue; +import org.apache.qpid.server.model.QueueNotificationListener; +import org.apache.qpid.server.model.State; +import org.apache.qpid.server.model.Statistics; +import org.apache.qpid.server.queue.*; +import org.apache.qpid.server.subscription.Subscription; + +final class QueueAdapter extends AbstractAdapter implements Queue, AMQQueue.SubscriptionRegistrationListener, AMQQueue.NotificationListener +{ + + static final Map<String, String> ATTRIBUTE_MAPPINGS = new HashMap<String, String>(); + static + { + QueueAdapter.ATTRIBUTE_MAPPINGS.put(Queue.ALERT_REPEAT_GAP, "x-qpid-minimum-alert-repeat-gap"); + QueueAdapter.ATTRIBUTE_MAPPINGS.put(Queue.ALERT_THRESHOLD_MESSAGE_AGE, "x-qpid-maximum-message-size"); + QueueAdapter.ATTRIBUTE_MAPPINGS.put(Queue.ALERT_THRESHOLD_MESSAGE_SIZE, "x-qpid-maximum-message-age"); + QueueAdapter.ATTRIBUTE_MAPPINGS.put(Queue.ALERT_THRESHOLD_QUEUE_DEPTH_MESSAGES, "x-qpid-maximum-message-count"); + + QueueAdapter.ATTRIBUTE_MAPPINGS.put(Queue.MAXIMUM_DELIVERY_ATTEMPTS, "x-qpid-maximum-delivery-count"); + + QueueAdapter.ATTRIBUTE_MAPPINGS.put(Queue.QUEUE_FLOW_CONTROL_SIZE_BYTES, "x-qpid-capacity"); + QueueAdapter.ATTRIBUTE_MAPPINGS.put(Queue.QUEUE_FLOW_RESUME_SIZE_BYTES, "x-qpid-flow-resume-capacity"); + + QueueAdapter.ATTRIBUTE_MAPPINGS.put(Queue.SORT_KEY, "qpid.sort_key"); + QueueAdapter.ATTRIBUTE_MAPPINGS.put(Queue.LVQ_KEY, "qpid.last_value_queue_key"); + + } + + private final AMQQueue _queue; + private final Map<Binding, BindingAdapter> _bindingAdapters = + new HashMap<Binding, BindingAdapter>(); + private Map<org.apache.qpid.server.subscription.Subscription, ConsumerAdapter> _consumerAdapters = + new HashMap<org.apache.qpid.server.subscription.Subscription, ConsumerAdapter>(); + + + private final VirtualHostAdapter _vhost; + private QueueStatisticsAdapter _statistics; + private QueueNotificationListener _queueNotificationListener; + + public QueueAdapter(final VirtualHostAdapter virtualHostAdapter, final AMQQueue queue) + { + super(virtualHostAdapter.getName(), queue.getName()); + _vhost = virtualHostAdapter; + addParent(org.apache.qpid.server.model.VirtualHost.class, virtualHostAdapter); + + _queue = queue; + _queue.addSubscriptionRegistrationListener(this); + populateConsumers(); + _statistics = new QueueStatisticsAdapter(queue); + _queue.setNotificationListener(this); + } + + private void populateConsumers() + { + Collection<org.apache.qpid.server.subscription.Subscription> actualSubscriptions = _queue.getConsumers(); + + synchronized (_consumerAdapters) + { + Iterator<org.apache.qpid.server.subscription.Subscription> iter = _consumerAdapters.keySet().iterator(); + for(org.apache.qpid.server.subscription.Subscription subscription : actualSubscriptions) + { + if(!_consumerAdapters.containsKey(subscription)) + { + _consumerAdapters.put(subscription, new ConsumerAdapter(this, subscription)); + } + } + } + } + + public Collection<org.apache.qpid.server.model.Binding> getBindings() + { + synchronized (_bindingAdapters) + { + return new ArrayList<org.apache.qpid.server.model.Binding>(_bindingAdapters.values()); + } + } + + public Collection<Consumer> getConsumers() + { + synchronized (_consumerAdapters) + { + return new ArrayList<Consumer>(_consumerAdapters.values()); + } + + } + + public void visit(final QueueEntryVisitor visitor) + { + _queue.visit(visitor); + } + + public void delete() + { + try + { + _queue.delete(); + if (_queue.isDurable()) + { + + _queue.getVirtualHost().getMessageStore().removeQueue(_queue); + } + } + catch(AMQException e) + { + throw new IllegalStateException(e); + } + } + + public String getName() + { + return _queue.getName(); + } + + public String setName(final String currentName, final String desiredName) + throws IllegalStateException, AccessControlException + { + return null; //TODO + } + + public State getActualState() + { + return null; //TODO + } + + public boolean isDurable() + { + return _queue.isDurable(); + } + + public void setDurable(final boolean durable) + throws IllegalStateException, AccessControlException, IllegalArgumentException + { + //TODO + } + + public LifetimePolicy getLifetimePolicy() + { + return _queue.isAutoDelete() ? LifetimePolicy.AUTO_DELETE : LifetimePolicy.PERMANENT; + } + + public LifetimePolicy setLifetimePolicy(final LifetimePolicy expected, final LifetimePolicy desired) + throws IllegalStateException, AccessControlException, IllegalArgumentException + { + return null; //TODO + } + + public long getTimeToLive() + { + return 0; //TODO + } + + public long setTimeToLive(final long expected, final long desired) + throws IllegalStateException, AccessControlException, IllegalArgumentException + { + return 0; //TODO + } + + + @Override + public Collection<String> getAttributeNames() + { + return Queue.AVAILABLE_ATTRIBUTES; + } + + @Override + public Object setAttribute(String name, Object expected, Object desired) throws IllegalStateException, AccessControlException, IllegalArgumentException + { + try + { + if(ALERT_REPEAT_GAP.equals(name)) + { + _queue.setMinimumAlertRepeatGap((Long)desired); + return desired; + } + else if(ALERT_THRESHOLD_MESSAGE_AGE.equals(name)) + { + _queue.setMaximumMessageAge((Long)desired); + return desired; + } + else if(ALERT_THRESHOLD_MESSAGE_SIZE.equals(name)) + { + _queue.setMaximumMessageSize((Long)desired); + return desired; + } + else if(ALERT_THRESHOLD_QUEUE_DEPTH_BYTES.equals(name)) + { + _queue.setMaximumQueueDepth((Long)desired); + return desired; + } + else if(ALERT_THRESHOLD_QUEUE_DEPTH_MESSAGES.equals(name)) + { + _queue.setMaximumMessageCount((Long)desired); + return desired; + } + else if(ALTERNATE_EXCHANGE.equals(name)) + { + // In future we may want to accept a UUID as an alternative way to identifying the exchange + ExchangeAdapter alternateExchange = (ExchangeAdapter) desired; + _queue.setAlternateExchange(alternateExchange == null ? null : alternateExchange.getExchange()); + return desired; + } + else if(EXCLUSIVE.equals(name)) + { + Boolean exclusiveFlag = (Boolean) desired; + _queue.setExclusive(exclusiveFlag); + return desired; + } + else if(MESSAGE_GROUP_KEY.equals(name)) + { + // TODO + } + else if(MESSAGE_GROUP_DEFAULT_GROUP.equals(name)) + { + // TODO + } + else if(MESSAGE_GROUP_SHARED_GROUPS.equals(name)) + { + // TODO + } + else if(LVQ_KEY.equals(name)) + { + // TODO + } + else if(MAXIMUM_DELIVERY_ATTEMPTS.equals(name)) + { + _queue.setMaximumDeliveryCount((Integer)desired); + return desired; + } + else if(NO_LOCAL.equals(name)) + { + // TODO + } + else if(OWNER.equals(name)) + { + // TODO + } + else if(QUEUE_FLOW_CONTROL_SIZE_BYTES.equals(name)) + { + _queue.setCapacity((Long)desired); + return desired; + } + else if(QUEUE_FLOW_RESUME_SIZE_BYTES.equals(name)) + { + _queue.setFlowResumeCapacity((Long)desired); + return desired; + } + else if(QUEUE_FLOW_STOPPED.equals(name)) + { + // TODO + } + else if(SORT_KEY.equals(name)) + { + // TODO + } + else if(TYPE.equals(name)) + { + // TODO + } + else if (DESCRIPTION.equals(name)) + { + _queue.setDescription((String) desired); + return desired; + } + + return super.setAttribute(name, expected, desired); + } + finally + { + if (_queue.isDurable()) + { + try + { + _queue.getVirtualHost().getMessageStore().updateQueue(_queue); + } + catch (AMQStoreException e) + { + throw new IllegalStateException(e); + } + } + } + } + + @Override + public Object getAttribute(String name) + { + + if(ALERT_REPEAT_GAP.equals(name)) + { + return _queue.getMinimumAlertRepeatGap(); + } + else if(ALERT_THRESHOLD_MESSAGE_AGE.equals(name)) + { + return _queue.getMaximumMessageAge(); + } + else if(ALERT_THRESHOLD_MESSAGE_SIZE.equals(name)) + { + return _queue.getMaximumMessageSize(); + } + else if(ALERT_THRESHOLD_QUEUE_DEPTH_BYTES.equals(name)) + { + return _queue.getMaximumQueueDepth(); + } + else if(ALERT_THRESHOLD_QUEUE_DEPTH_MESSAGES.equals(name)) + { + return _queue.getMaximumMessageCount(); + } + else if(ALTERNATE_EXCHANGE.equals(name)) + { + org.apache.qpid.server.exchange.Exchange alternateExchange = _queue.getAlternateExchange(); + return alternateExchange == null ? null : + ConfiguredObjectFinder.findConfiguredObjectByName(_vhost.getExchanges(), + alternateExchange.getName()); + } + else if(EXCLUSIVE.equals(name)) + { + return _queue.isExclusive(); + } + else if(MESSAGE_GROUP_KEY.equals(name)) + { + // TODO + } + else if(MESSAGE_GROUP_DEFAULT_GROUP.equals(name)) + { + // TODO + } + else if(MESSAGE_GROUP_SHARED_GROUPS.equals(name)) + { + // TODO + } + else if(LVQ_KEY.equals(name)) + { + if(_queue instanceof ConflationQueue) + { + return ((ConflationQueue)_queue).getConflationKey(); + } + } + else if(MAXIMUM_DELIVERY_ATTEMPTS.equals(name)) + { + return _queue.getMaximumDeliveryCount(); + } + else if(NO_LOCAL.equals(name)) + { + // TODO + } + else if(OWNER.equals(name)) + { + return _queue.getOwner() == null ? null : _queue.getOwner().asString(); + } + else if(QUEUE_FLOW_CONTROL_SIZE_BYTES.equals(name)) + { + return _queue.getCapacity(); + } + else if(QUEUE_FLOW_RESUME_SIZE_BYTES.equals(name)) + { + return _queue.getFlowResumeCapacity(); + } + else if(QUEUE_FLOW_STOPPED.equals(name)) + { + return _queue.isOverfull(); + } + else if(SORT_KEY.equals(name)) + { + if(_queue instanceof SortedQueue) + { + return ((SortedQueue)_queue).getSortedPropertyName(); + } + } + else if(TYPE.equals(name)) + { + if(_queue instanceof SortedQueue) + { + return "sorted"; + } + if(_queue instanceof ConflationQueue) + { + return "lvq"; + } + if(_queue instanceof AMQPriorityQueue) + { + return "priority"; + } + return "standard"; + } + else if(CREATED.equals(name)) + { + // TODO + } + else if(DURABLE.equals(name)) + { + return _queue.isDurable(); + } + else if(ID.equals(name)) + { + return getId(); + } + else if(LIFETIME_POLICY.equals(name)) + { + return _queue.isAutoDelete() ? LifetimePolicy.AUTO_DELETE : LifetimePolicy.PERMANENT; + } + else if(NAME.equals(name)) + { + return _queue.getName(); + } + else if(STATE.equals(name)) + { + return State.ACTIVE; // TODO + } + else if(TIME_TO_LIVE.equals(name)) + { + // TODO + } + else if(UPDATED.equals(name)) + { + // TODO + } + else if (DESCRIPTION.equals(name)) + { + return _queue.getDescription(); + } + + return super.getAttribute(name); + } + + public Statistics getStatistics() + { + return _statistics; + } + + @Override + public <C extends ConfiguredObject> Collection<C> getChildren(Class<C> clazz) + { + if(clazz == Consumer.class) + { + return (Collection<C>) getConsumers(); + } + else if(clazz == org.apache.qpid.server.model.Binding.class) + { + return (Collection<C>) getBindings(); + } + else + { + return Collections.emptySet(); + } + } + + public org.apache.qpid.server.model.Binding createBinding(Exchange exchange, Map<String, Object> attributes) + throws AccessControlException, IllegalStateException + { + attributes = new HashMap<String, Object>(attributes); + String bindingKey = getStringAttribute(org.apache.qpid.server.model.Binding.NAME, attributes, ""); + Map<String, Object> bindingArgs = getMapAttribute(org.apache.qpid.server.model.Binding.ARGUMENTS, attributes, Collections.EMPTY_MAP); + + attributes.remove(org.apache.qpid.server.model.Binding.NAME); + attributes.remove(org.apache.qpid.server.model.Binding.ARGUMENTS); + + return exchange.createBinding(bindingKey, this, bindingArgs, attributes); + + } + + + + @Override + public <C extends ConfiguredObject> C createChild(Class<C> childClass, Map<String, Object> attributes, ConfiguredObject... otherParents) + { + if(childClass == org.apache.qpid.server.model.Binding.class) + { + if(otherParents != null && otherParents.length == 1 && otherParents[0] instanceof Exchange) + { + Exchange exchange = (Exchange) otherParents[0]; + if(exchange.getParent(org.apache.qpid.server.model.VirtualHost.class) == getParent(org.apache.qpid.server.model.VirtualHost.class)) + { + return (C) createBinding(exchange, attributes); + } + else + { + throw new IllegalArgumentException("Queue and Exchange parents of a binding must be on same virtual host"); + } + } + else + { + throw new IllegalArgumentException("Other parent must be an exchange"); + } + } + else + { + throw new IllegalArgumentException(); + } + } + + void bindingRegistered(Binding binding, BindingAdapter adapter) + { + synchronized (_bindingAdapters) + { + _bindingAdapters.put(binding, adapter); + } + childAdded(adapter); + } + + void bindingUnregistered(Binding binding) + { + BindingAdapter adapter = null; + synchronized (_bindingAdapters) + { + adapter = _bindingAdapters.remove(binding); + } + if(adapter != null) + { + childRemoved(adapter); + } + } + + AMQQueue getAMQQueue() + { + return _queue; + } + + public void subscriptionRegistered(final AMQQueue queue, final Subscription subscription) + { + ConsumerAdapter adapter = null; + synchronized (_consumerAdapters) + { + if(!_consumerAdapters.containsKey(subscription)) + { + adapter = new ConsumerAdapter(this, subscription); + _consumerAdapters.put(subscription,adapter); + // TODO - register with session + } + } + if(adapter != null) + { + childAdded(adapter); + } + } + + public void subscriptionUnregistered(final AMQQueue queue, final Subscription subscription) + { + ConsumerAdapter adapter = null; + + synchronized (_consumerAdapters) + { + adapter = _consumerAdapters.remove(subscription); + // TODO - register with session + } + if(adapter != null) + { + childRemoved(adapter); + } + } + + VirtualHostAdapter getVirtualHost() + { + return _vhost; + } + + + private static class QueueStatisticsAdapter implements Statistics + { + + private final AMQQueue _queue; + + public QueueStatisticsAdapter(AMQQueue queue) + { + _queue = queue; + } + + public Collection<String> getStatisticNames() + { + return Queue.AVAILABLE_STATISTICS; + } + + public Object getStatistic(String name) + { + if(BINDING_COUNT.equals(name)) + { + return _queue.getBindingCount(); + } + else if(CONSUMER_COUNT.equals(name)) + { + return _queue.getConsumerCount(); + } + else if(CONSUMER_COUNT_WITH_CREDIT.equals(name)) + { + return _queue.getActiveConsumerCount(); + } + else if(DISCARDS_TTL_BYTES.equals(name)) + { + return null; // TODO + } + else if(DISCARDS_TTL_MESSAGES.equals(name)) + { + return null; // TODO + } + else if(PERSISTENT_DEQUEUED_BYTES.equals(name)) + { + return _queue.getPersistentByteDequeues(); + } + else if(PERSISTENT_DEQUEUED_MESSAGES.equals(name)) + { + return _queue.getPersistentMsgDequeues(); + } + else if(PERSISTENT_ENQUEUED_BYTES.equals(name)) + { + return _queue.getPersistentByteEnqueues(); + } + else if(PERSISTENT_ENQUEUED_MESSAGES.equals(name)) + { + return _queue.getPersistentMsgEnqueues(); + } + else if(QUEUE_DEPTH_BYTES.equals(name)) + { + return _queue.getQueueDepth(); + } + else if(QUEUE_DEPTH_MESSAGES.equals(name)) + { + return _queue.getMessageCount(); + } + else if(STATE_CHANGED.equals(name)) + { + return null; // TODO + } + else if(TOTAL_DEQUEUED_BYTES.equals(name)) + { + return _queue.getTotalDequeueSize(); + } + else if(TOTAL_DEQUEUED_MESSAGES.equals(name)) + { + return _queue.getTotalDequeueCount(); + } + else if(TOTAL_ENQUEUED_BYTES.equals(name)) + { + return _queue.getTotalEnqueueSize(); + } + else if(TOTAL_ENQUEUED_MESSAGES.equals(name)) + { + return _queue.getTotalEnqueueCount(); + } + else if(UNACKNOWLEDGED_BYTES.equals(name)) + { + return _queue.getUnackedMessageBytes(); + } + else if(UNACKNOWLEDGED_MESSAGES.equals(name)) + { + return _queue.getUnackedMessageCount(); + } + + return null; + } + } + + @Override + public void setNotificationListener(QueueNotificationListener listener) + { + _queueNotificationListener = listener; + } + + @Override + public void notifyClients(NotificationCheck notification, AMQQueue queue, String notificationMsg) + { + QueueNotificationListener listener = _queueNotificationListener; + if(listener != null) + { + listener.notifyClients(notification, this, notificationMsg); + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/SessionAdapter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/SessionAdapter.java new file mode 100644 index 0000000000..25d9c6feb1 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/SessionAdapter.java @@ -0,0 +1,239 @@ +/* + * + * 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.model.adapter; + +import java.security.AccessControlException; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; + +import java.util.Map; +import org.apache.qpid.server.model.ConfiguredObject; +import org.apache.qpid.server.model.LifetimePolicy; +import org.apache.qpid.server.model.Publisher; +import org.apache.qpid.server.model.Session; +import org.apache.qpid.server.model.State; +import org.apache.qpid.server.model.Statistics; +import org.apache.qpid.server.model.Consumer; +import org.apache.qpid.server.protocol.AMQSessionModel; + +final class SessionAdapter extends AbstractAdapter implements Session +{ + // Attributes + + + private AMQSessionModel _session; + private SessionStatistics _statistics; + + public SessionAdapter(final AMQSessionModel session) + { + _session = session; + _statistics = new SessionStatistics(); + } + + public Collection<Consumer> getSubscriptions() + { + return null; //TODO + } + + public Collection<Publisher> getPublishers() + { + return null; //TODO + } + + public String getName() + { + return String.valueOf(_session.getChannelId()); + } + + public String setName(final String currentName, final String desiredName) + throws IllegalStateException, AccessControlException + { + return null; //TODO + } + + public State getActualState() + { + return null; //TODO + } + + public boolean isDurable() + { + return false; //TODO + } + + public void setDurable(final boolean durable) + throws IllegalStateException, AccessControlException, IllegalArgumentException + { + //TODO + } + + public LifetimePolicy getLifetimePolicy() + { + return null; //TODO + } + + public LifetimePolicy setLifetimePolicy(final LifetimePolicy expected, final LifetimePolicy desired) + throws IllegalStateException, AccessControlException, IllegalArgumentException + { + return null; //TODO + } + + public long getTimeToLive() + { + return 0; //TODO + } + + public long setTimeToLive(final long expected, final long desired) + throws IllegalStateException, AccessControlException, IllegalArgumentException + { + return 0; //TODO + } + + @Override + public Collection<String> getAttributeNames() + { + Collection<String> names = new HashSet<String>(super.getAttributeNames()); + names.addAll(AVAILABLE_ATTRIBUTES); + + return Collections.unmodifiableCollection(names); + } + + @Override + public Object getAttribute(String name) + { + if(name.equals(ID)) + { + return getId(); + } + else if (name.equals(NAME)) + { + return getName(); + } + else if(name.equals(CHANNEL_ID)) + { + return _session.getChannelId(); + } + else if(name.equals(PRODUCER_FLOW_BLOCKED)) + { + return _session.getBlocking(); + } + return super.getAttribute(name); //TODO - Implement + } + + @Override + public Object setAttribute(String name, Object expected, Object desired) + throws IllegalStateException, AccessControlException, IllegalArgumentException + { + return super.setAttribute(name, expected, desired); //TODO - Implement + } + + public Statistics getStatistics() + { + return _statistics; + } + + @Override + public <C extends ConfiguredObject> Collection<C> getChildren(Class<C> clazz) + { + if(clazz == Consumer.class) + { + return (Collection<C>) getSubscriptions(); + } + else if(clazz == Publisher.class) + { + return (Collection<C>) getPublishers(); + } + else + { + return Collections.emptySet(); + } + } + + @Override + public <C extends ConfiguredObject> C createChild(Class<C> childClass, Map<String, Object> attributes, ConfiguredObject... otherParents) + { + throw new UnsupportedOperationException(); + } + + private class SessionStatistics implements Statistics + { + + public SessionStatistics() + { + } + + public Collection<String> getStatisticNames() + { + return AVAILABLE_STATISTICS; + } + + public Object getStatistic(String name) + { + if(name.equals(BYTES_IN)) + { + } + else if(name.equals(BYTES_OUT)) + { + } + else if(name.equals(CONSUMER_COUNT)) + { + final Collection<Consumer> subscriptions = getSubscriptions(); + return subscriptions == null ? 0 : subscriptions.size(); + } + else if(name.equals(LOCAL_TRANSACTION_BEGINS)) + { + return _session.getTxnStart(); + } + else if(name.equals(LOCAL_TRANSACTION_OPEN)) + { + long open = _session.getTxnCount() - (_session.getTxnCommits() + _session.getTxnRejects()); + return (Boolean) (open > 0l); + } + else if(name.equals(LOCAL_TRANSACTION_ROLLBACKS)) + { + return _session.getTxnCommits(); + } + else if(name.equals(STATE_CHANGED)) + { + } + else if(name.equals(UNACKNOWLEDGED_BYTES)) + { + } + else if(name.equals(UNACKNOWLEDGED_MESSAGES)) + { + return _session.getUnacknowledgedMessageCount(); + } + else if(name.equals(XA_TRANSACTION_BRANCH_ENDS)) + { + } + else if(name.equals(XA_TRANSACTION_BRANCH_STARTS)) + { + } + else if(name.equals(XA_TRANSACTION_BRANCH_SUSPENDS)) + { + + } + + return null; // TODO - Implement + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/StatisticsAdapter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/StatisticsAdapter.java new file mode 100644 index 0000000000..f98e46c911 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/StatisticsAdapter.java @@ -0,0 +1,67 @@ +package org.apache.qpid.server.model.adapter; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import org.apache.qpid.server.model.Statistics; +import org.apache.qpid.server.stats.StatisticsCounter; +import org.apache.qpid.server.stats.StatisticsGatherer; + +/** +* 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 +* <p/> +* http://www.apache.org/licenses/LICENSE-2.0 +* <p/> +* 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. +*/ +class StatisticsAdapter implements Statistics +{ + + private final Map<String, StatisticsCounter> _statistics = + new HashMap<String, StatisticsCounter>(); + + + private static final String BYTES_IN = "bytesIn"; + private static final String BYTES_OUT = "bytesOut"; + private static final String MESSAGES_IN = "messagesIn"; + private static final String MESSAGES_OUT = "messagesOut"; + + private static final Collection<String> STATISTIC_NAMES = + Collections.unmodifiableCollection(Arrays.asList(BYTES_IN, BYTES_OUT, MESSAGES_IN, MESSAGES_OUT)); + + + + public StatisticsAdapter(StatisticsGatherer statGatherer) + { + _statistics.put(BYTES_OUT, statGatherer.getDataDeliveryStatistics()); + _statistics.put(BYTES_IN, statGatherer.getDataReceiptStatistics()); + _statistics.put(MESSAGES_OUT, statGatherer.getMessageDeliveryStatistics()); + _statistics.put(MESSAGES_IN, statGatherer.getMessageReceiptStatistics()); + } + + + public Collection<String> getStatisticNames() + { + return STATISTIC_NAMES; + } + + public Object getStatistic(String name) + { + StatisticsCounter counter = _statistics.get(name); + return counter == null ? null : counter.getTotal(); + + } + + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/VirtualHostAdapter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/VirtualHostAdapter.java new file mode 100644 index 0000000000..204054c8cb --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/VirtualHostAdapter.java @@ -0,0 +1,844 @@ +/* + * + * 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.model.adapter; + +import java.security.AccessControlException; +import java.security.Principal; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import org.apache.qpid.AMQException; +import org.apache.qpid.framing.FieldTable; +import org.apache.qpid.server.connection.IConnectionRegistry; +import org.apache.qpid.server.exchange.ExchangeRegistry; +import org.apache.qpid.server.exchange.ExchangeType; +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.model.ConfiguredObject; +import org.apache.qpid.server.model.Connection; +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.Queue; +import org.apache.qpid.server.model.State; +import org.apache.qpid.server.model.Statistics; +import org.apache.qpid.server.model.UUIDGenerator; +import org.apache.qpid.server.model.VirtualHost; +import org.apache.qpid.server.model.VirtualHostAlias; +import org.apache.qpid.server.protocol.AMQConnectionModel; +import org.apache.qpid.server.queue.AMQQueue; +import org.apache.qpid.server.queue.AMQQueueFactory; +import org.apache.qpid.server.queue.QueueEntry; +import org.apache.qpid.server.queue.QueueRegistry; +import org.apache.qpid.server.security.SecurityManager; +import org.apache.qpid.server.store.MessageStore; +import org.apache.qpid.server.txn.LocalTransaction; +import org.apache.qpid.server.txn.ServerTransaction; + +final class VirtualHostAdapter extends AbstractAdapter implements VirtualHost, ExchangeRegistry.RegistryChangeListener, + QueueRegistry.RegistryChangeListener, + IConnectionRegistry.RegistryChangeListener +{ + + private final org.apache.qpid.server.virtualhost.VirtualHost _virtualHost; + + private final Map<AMQConnectionModel, ConnectionAdapter> _connectionAdapters = + new HashMap<AMQConnectionModel, ConnectionAdapter>(); + + private final Map<AMQQueue, QueueAdapter> _queueAdapters = + new HashMap<AMQQueue, QueueAdapter>(); + + private final Map<org.apache.qpid.server.exchange.Exchange, ExchangeAdapter> _exchangeAdapters = + new HashMap<org.apache.qpid.server.exchange.Exchange, ExchangeAdapter>(); + + private final StatisticsAdapter _statistics; + + private final BrokerAdapter _broker; + + private final List<VirtualHostAlias> _aliases = new ArrayList<VirtualHostAlias>(); + + + VirtualHostAdapter(BrokerAdapter brokerAdapter, + final org.apache.qpid.server.virtualhost.VirtualHost virtualHost) + { + super(virtualHost.getName()); + _broker = brokerAdapter; + _virtualHost = virtualHost; + _statistics = new VirtualHostStatisticsAdapter(virtualHost); + virtualHost.getQueueRegistry().addRegistryChangeListener(this); + populateQueues(); + virtualHost.getExchangeRegistry().addRegistryChangeListener(this); + populateExchanges(); + virtualHost.getConnectionRegistry().addRegistryChangeListener(this); + populateConnections(); + + + + for(Port port :_broker.getPorts()) + { + _aliases.add(new VirtualHostAliasAdapter(this, port)); + } + } + + + private void populateExchanges() + { + Collection<org.apache.qpid.server.exchange.Exchange> actualExchanges = + _virtualHost.getExchangeRegistry().getExchanges(); + + synchronized (_exchangeAdapters) + { + for(org.apache.qpid.server.exchange.Exchange exchange : actualExchanges) + { + if(!_exchangeAdapters.containsKey(exchange)) + { + _exchangeAdapters.put(exchange, new ExchangeAdapter(this,exchange)); + } + } + } + } + + + private void populateQueues() + { + Collection<AMQQueue> actualQueues = _virtualHost.getQueueRegistry().getQueues(); + + synchronized(_queueAdapters) + { + for(AMQQueue queue : actualQueues) + { + if(!_queueAdapters.containsKey(queue)) + { + _queueAdapters.put(queue, new QueueAdapter(this,queue)); + } + } + } + } + + private void populateConnections() + { + + List<AMQConnectionModel> actualConnections = _virtualHost.getConnectionRegistry().getConnections(); + + synchronized(_connectionAdapters) + { + for(AMQConnectionModel conn : actualConnections) + { + if(!_connectionAdapters.containsKey(conn)) + { + _connectionAdapters.put(conn, new ConnectionAdapter(conn)); + } + } + } + + } + + public String getReplicationGroupName() + { + return null; //TODO + } + + public Collection<VirtualHostAlias> getAliases() + { + return Collections.unmodifiableCollection(_aliases); + } + + public Collection<Connection> getConnections() + { + synchronized(_connectionAdapters) + { + return new ArrayList<Connection>(_connectionAdapters.values()); + } + + } + + public Collection<Queue> getQueues() + { + synchronized(_queueAdapters) + { + return new ArrayList<Queue>(_queueAdapters.values()); + } + } + + public Collection<Exchange> getExchanges() + { + synchronized (_exchangeAdapters) + { + return new ArrayList<Exchange>(_exchangeAdapters.values()); + } + } + + + public Exchange createExchange(Map<String, Object> attributes) + throws AccessControlException, IllegalArgumentException + { + attributes = new HashMap<String, Object>(attributes); + + String name = getStringAttribute(Exchange.NAME, attributes, null); + State state = getEnumAttribute(State.class, Exchange.STATE, attributes, State.ACTIVE); + boolean durable = getBooleanAttribute(Exchange.DURABLE, attributes, false); + LifetimePolicy lifetime = getEnumAttribute(LifetimePolicy.class, Exchange.LIFETIME_POLICY, attributes, LifetimePolicy.PERMANENT); + String type = getStringAttribute(Exchange.TYPE, attributes, null); + long ttl = getLongAttribute(Exchange.TIME_TO_LIVE, attributes, 0l); + + attributes.remove(Exchange.NAME); + attributes.remove(Exchange.STATE); + attributes.remove(Exchange.DURABLE); + attributes.remove(Exchange.LIFETIME_POLICY); + attributes.remove(Exchange.TYPE); + attributes.remove(Exchange.TIME_TO_LIVE); + + return createExchange(name, state, durable, lifetime, ttl, type, attributes); + } + + + public Exchange createExchange(final String name, + final State initialState, + final boolean durable, + final LifetimePolicy lifetime, + final long ttl, + final String type, + final Map<String, Object> attributes) + throws AccessControlException, IllegalArgumentException + { + try + { + org.apache.qpid.server.exchange.Exchange exchange = + _virtualHost.getExchangeFactory().createExchange(name, type, durable, + lifetime == LifetimePolicy.AUTO_DELETE); + _virtualHost.getExchangeRegistry().registerExchange(exchange); + if(durable) + { + _virtualHost.getMessageStore().createExchange(exchange); + } + + synchronized (_exchangeAdapters) + { + return _exchangeAdapters.get(exchange); + } + } + catch(AMQException e) + { + throw new IllegalArgumentException(e); + } + } + + public Queue createQueue(Map<String, Object> attributes) + throws AccessControlException, IllegalArgumentException + { + attributes = new HashMap<String, Object>(attributes); + + String name = getStringAttribute(Queue.NAME, attributes, null); + State state = getEnumAttribute(State.class, Queue.STATE, attributes, State.ACTIVE); + boolean durable = getBooleanAttribute(Queue.DURABLE, attributes, false); + LifetimePolicy lifetime = getEnumAttribute(LifetimePolicy.class, Queue.LIFETIME_POLICY, attributes, LifetimePolicy.PERMANENT); + long ttl = getLongAttribute(Queue.TIME_TO_LIVE, attributes, 0l); + boolean exclusive= getBooleanAttribute(Queue.EXCLUSIVE, attributes, false); + + attributes.remove(Queue.NAME); + attributes.remove(Queue.STATE); + attributes.remove(Queue.DURABLE); + attributes.remove(Queue.LIFETIME_POLICY); + attributes.remove(Queue.TIME_TO_LIVE); + + List<String> attrNames = new ArrayList<String>(attributes.keySet()); + for(String attr : attrNames) + { + if(QueueAdapter.ATTRIBUTE_MAPPINGS.containsKey(attr)) + { + attributes.put(QueueAdapter.ATTRIBUTE_MAPPINGS.get(attr),attributes.remove(attr)); + } + } + + return createQueue(name, state, durable, exclusive, lifetime, ttl, attributes); + } + + public Queue createQueue(final String name, + final State initialState, + final boolean durable, + boolean exclusive, + final LifetimePolicy lifetime, + final long ttl, + final Map<String, Object> attributes) + throws AccessControlException, IllegalArgumentException + { + String owner = null; + if(exclusive) + { + Set<Principal> principals = + SecurityManager.getThreadSubject().getPrincipals(); + if(principals != null && !principals.isEmpty()) + { + owner = principals.iterator().next().getName(); + } + } + try + { + if(_virtualHost.getQueueRegistry().getQueue(name)!=null) + { + throw new IllegalArgumentException("Queue with name "+name+" already exists"); + } + AMQQueue queue = + AMQQueueFactory.createAMQQueueImpl(UUIDGenerator.generateUUID(name, _virtualHost.getName()), name, + durable, owner, lifetime == LifetimePolicy.AUTO_DELETE, + exclusive, _virtualHost, attributes); + _virtualHost.getBindingFactory().addBinding(name, queue, _virtualHost.getExchangeRegistry().getDefaultExchange(), null); + + if(durable) + { + _virtualHost.getMessageStore().createQueue(queue, FieldTable.convertToFieldTable(attributes)); + } + synchronized (_queueAdapters) + { + return _queueAdapters.get(queue); + } + + } + catch(AMQException e) + { + throw new IllegalArgumentException(e); + } + + } + + public String getName() + { + return _virtualHost.getName(); + } + + public String setName(final String currentName, final String desiredName) + throws IllegalStateException, AccessControlException + { + throw new IllegalStateException(); + } + + public State getActualState() + { + return getDesiredState(); + } + + public boolean isDurable() + { + return true; + } + + public void setDurable(final boolean durable) + throws IllegalStateException, AccessControlException, IllegalArgumentException + { + throw new IllegalStateException(); + } + + public LifetimePolicy getLifetimePolicy() + { + return LifetimePolicy.PERMANENT; + } + + public LifetimePolicy setLifetimePolicy(final LifetimePolicy expected, final LifetimePolicy desired) + throws IllegalStateException, AccessControlException, IllegalArgumentException + { + throw new IllegalStateException(); + } + + public long getTimeToLive() + { + return 0; + } + + public long setTimeToLive(final long expected, final long desired) + throws IllegalStateException, AccessControlException, IllegalArgumentException + { + throw new IllegalStateException(); + } + + public Statistics getStatistics() + { + return _statistics; + } + + @Override + public <C extends ConfiguredObject> Collection<C> getChildren(Class<C> clazz) + { + if(clazz == Exchange.class) + { + return (Collection<C>) getExchanges(); + } + else if(clazz == Queue.class) + { + return (Collection<C>) getQueues(); + } + else if(clazz == Connection.class) + { + return (Collection<C>) getConnections(); + } + else if(clazz == VirtualHostAlias.class) + { + return (Collection<C>) getAliases(); + } + else + { + return Collections.emptySet(); + } + } + + @Override + public <C extends ConfiguredObject> C createChild(Class<C> childClass, Map<String, Object> attributes, ConfiguredObject... otherParents) + { + if(childClass == Exchange.class) + { + return (C) createExchange(attributes); + } + else if(childClass == Queue.class) + { + return (C) createQueue(attributes); + } + else if(childClass == VirtualHostAlias.class) + { + throw new UnsupportedOperationException(); + } + else if(childClass == Connection.class) + { + throw new UnsupportedOperationException(); + } + throw new IllegalArgumentException("Cannot create a child of class " + childClass.getSimpleName()); + } + + public void exchangeRegistered(org.apache.qpid.server.exchange.Exchange exchange) + { + ExchangeAdapter adapter = null; + synchronized (_exchangeAdapters) + { + if(!_exchangeAdapters.containsKey(exchange)) + { + adapter = new ExchangeAdapter(this, exchange); + _exchangeAdapters.put(exchange, adapter); + + } + + } + if(adapter != null) + { + childAdded(adapter); + } + + } + + + public void exchangeUnregistered(org.apache.qpid.server.exchange.Exchange exchange) + { + ExchangeAdapter adapter; + synchronized (_exchangeAdapters) + { + adapter = _exchangeAdapters.remove(exchange); + + } + + if(adapter != null) + { + childRemoved(adapter); + } + } + + public void queueRegistered(AMQQueue queue) + { + QueueAdapter adapter = null; + synchronized (_queueAdapters) + { + if(!_queueAdapters.containsKey(queue)) + { + adapter = new QueueAdapter(this, queue); + _queueAdapters.put(queue, adapter); + + } + + } + if(adapter != null) + { + childAdded(adapter); + } + + } + + public void queueUnregistered(AMQQueue queue) + { + + QueueAdapter adapter; + synchronized (_queueAdapters) + { + adapter = _queueAdapters.remove(queue); + + } + + if(adapter != null) + { + childRemoved(adapter); + } + } + + public void connectionRegistered(AMQConnectionModel connection) + { + ConnectionAdapter adapter = null; + synchronized (_connectionAdapters) + { + if(!_connectionAdapters.containsKey(connection)) + { + adapter = new ConnectionAdapter(connection); + _connectionAdapters.put(connection, adapter); + + } + + } + if(adapter != null) + { + childAdded(adapter); + } + } + + public void connectionUnregistered(AMQConnectionModel connection) + { + + ConnectionAdapter adapter; + synchronized (_connectionAdapters) + { + adapter = _connectionAdapters.remove(connection); + + } + + if(adapter != null) + { + childRemoved(adapter); + } + } + + QueueAdapter getQueueAdapter(AMQQueue queue) + { + synchronized (_queueAdapters) + { + return _queueAdapters.get(queue); + } + } + + public void deleteQueue(Queue queue) + throws AccessControlException, IllegalStateException + { + // TODO + throw new UnsupportedOperationException("Not Yet Implemented"); + } + + public Collection<String> getExchangeTypes() + { + Collection<ExchangeType<? extends org.apache.qpid.server.exchange.Exchange>> types = + _virtualHost.getExchangeFactory().getRegisteredTypes(); + + Collection<String> exchangeTypes = new ArrayList<String>(); + + for(ExchangeType<? extends org.apache.qpid.server.exchange.Exchange> type : types) + { + exchangeTypes.add(type.getName().asString()); + } + return Collections.unmodifiableCollection(exchangeTypes); + } + + public void executeTransaction(TransactionalOperation op) + { + MessageStore store = _virtualHost.getMessageStore(); + final LocalTransaction txn = new LocalTransaction(store); + + op.withinTransaction(new Transaction() + { + public void dequeue(final QueueEntry entry) + { + if(entry.acquire()) + { + txn.dequeue(entry.getQueue(), entry.getMessage(), new ServerTransaction.Action() + { + public void postCommit() + { + entry.discard(); + } + + public void onRollback() + { + } + }); + } + } + + public void copy(QueueEntry entry, Queue queue) + { + final ServerMessage message = entry.getMessage(); + final AMQQueue toQueue = ((QueueAdapter)queue).getAMQQueue(); + + txn.enqueue(toQueue, message, new ServerTransaction.Action() + { + public void postCommit() + { + try + { + toQueue.enqueue(message); + } + catch(AMQException e) + { + throw new RuntimeException(e); + } + } + + public void onRollback() + { + } + }); + + } + + public void move(final QueueEntry entry, Queue queue) + { + final ServerMessage message = entry.getMessage(); + final AMQQueue toQueue = ((QueueAdapter)queue).getAMQQueue(); + if(entry.acquire()) + { + txn.enqueue(toQueue, message, + new ServerTransaction.Action() + { + + public void postCommit() + { + try + { + toQueue.enqueue(message); + } + catch (AMQException e) + { + throw new RuntimeException(e); + } + } + + public void onRollback() + { + entry.release(); + } + }); + txn.dequeue(entry.getQueue(), message, + new ServerTransaction.Action() + { + + public void postCommit() + { + entry.discard(); + } + + public void onRollback() + { + + } + }); + } + } + + }); + txn.commit(); + } + + org.apache.qpid.server.virtualhost.VirtualHost getVirtualHost() + { + return _virtualHost; + } + + @Override + public Object getAttribute(String name) + { + if(ID.equals(name)) + { + return getId(); + } + else if(NAME.equals(name)) + { + return getName(); + } + else if(STATE.equals(name)) + { + return State.ACTIVE; + } + else if(DURABLE.equals(name)) + { + return isDurable(); + } + else if(LIFETIME_POLICY.equals(name)) + { + return LifetimePolicy.PERMANENT; + } + else if(TIME_TO_LIVE.equals(name)) + { + // TODO + } + else if(CREATED.equals(name)) + { + // TODO + } + else if(UPDATED.equals(name)) + { + // TODO + } + else if(SUPPORTED_EXCHANGE_TYPES.equals(name)) + { + List<String> types = new ArrayList<String>(); + for(ExchangeType type : _virtualHost.getExchangeFactory().getRegisteredTypes()) + { + types.add(type.getName().asString()); + } + return Collections.unmodifiableCollection(types); + } + else if(SUPPORTED_QUEUE_TYPES.equals(name)) + { + // TODO + } + else if(DEAD_LETTER_QUEUE_ENABLED.equals(name)) + { + return _virtualHost.getConfiguration().isDeadLetterQueueEnabled(); + } + else if(FEDERATION_TAG.equals(name)) + { + return _virtualHost.getFederationTag(); + } + else if(HOUSEKEEPING_CHECK_PERIOD.equals(name)) + { + return _virtualHost.getConfiguration().getHousekeepingCheckPeriod(); + } + else if(MAXIMUM_DELIVERY_ATTEMPTS.equals(name)) + { + return _virtualHost.getConfiguration().getMaxDeliveryCount(); + } + else if(QUEUE_FLOW_CONTROL_SIZE_BYTES.equals(name)) + { + return _virtualHost.getConfiguration().getCapacity(); + } + else if(QUEUE_FLOW_RESUME_SIZE_BYTES.equals(name)) + { + return _virtualHost.getConfiguration().getFlowResumeCapacity(); + } + else if(STORE_TYPE.equals(name)) + { + return _virtualHost.getMessageStore().getStoreType(); + } + else if(STORE_CONFIGURATION.equals(name)) + { + // TODO + } + else if(STORE_TRANSACTION_IDLE_TIMEOUT_CLOSE.equals(name)) + { + return _virtualHost.getConfiguration().getTransactionTimeoutIdleClose(); + } + else if(STORE_TRANSACTION_IDLE_TIMEOUT_WARN.equals(name)) + { + return _virtualHost.getConfiguration().getTransactionTimeoutIdleWarn(); + } + else if(STORE_TRANSACTION_OPEN_TIMEOUT_CLOSE.equals(name)) + { + return _virtualHost.getConfiguration().getTransactionTimeoutOpenClose(); + } + else if(STORE_TRANSACTION_OPEN_TIMEOUT_WARN.equals(name)) + { + return _virtualHost.getConfiguration().getTransactionTimeoutOpenWarn(); + } + else if(ALERT_REPEAT_GAP.equals(name)) + { + return _virtualHost.getConfiguration().getMinimumAlertRepeatGap(); + } + else if(ALERT_THRESHOLD_MESSAGE_AGE.equals(name)) + { + return _virtualHost.getConfiguration().getMaximumMessageAge(); + } + else if(ALERT_THRESHOLD_MESSAGE_SIZE.equals(name)) + { + return _virtualHost.getConfiguration().getMaximumMessageSize(); + } + else if(ALERT_THRESHOLD_QUEUE_DEPTH_BYTES.equals(name)) + { + return _virtualHost.getConfiguration().getMaximumQueueDepth(); + } + else if(ALERT_THRESHOLD_QUEUE_DEPTH_MESSAGES.equals(name)) + { + return _virtualHost.getConfiguration().getMaximumMessageCount(); + } + return super.getAttribute(name); + } + + @Override + public Object setAttribute(String name, Object expected, Object desired) + throws IllegalStateException, AccessControlException, IllegalArgumentException + { + return super.setAttribute(name, expected, desired); //TODO - Implement + } + + @Override + public Collection<String> getAttributeNames() + { + return AVAILABLE_ATTRIBUTES; + } + + private static class VirtualHostStatisticsAdapter extends StatisticsAdapter + { + private final org.apache.qpid.server.virtualhost.VirtualHost _vhost; + + private static final Collection<String> VHOST_STATS = Arrays.asList( + VirtualHost.QUEUE_COUNT, + VirtualHost.EXCHANGE_COUNT, + VirtualHost.CONNECTION_COUNT); + + public VirtualHostStatisticsAdapter(org.apache.qpid.server.virtualhost.VirtualHost virtualHost) + { + super(virtualHost); + _vhost = virtualHost; + } + + @Override + public Collection<String> getStatisticNames() + { + Set<String> stats = new HashSet<String>(super.getStatisticNames()); + stats.addAll(VHOST_STATS); + return stats; + } + + @Override + public Object getStatistic(String name) + { + if(VirtualHost.QUEUE_COUNT.equals(name)) + { + return _vhost.getQueueRegistry().getQueues().size(); + } + else if(VirtualHost.EXCHANGE_COUNT.equals(name)) + { + return _vhost.getExchangeRegistry().getExchanges().size(); + } + else if(VirtualHost.CONNECTION_COUNT.equals(name)) + { + return _vhost.getConnectionRegistry().getConnections().size(); + } + else + { + return super.getStatistic(name); + } + } + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/VirtualHostAliasAdapter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/VirtualHostAliasAdapter.java new file mode 100644 index 0000000000..22ea2e612b --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/VirtualHostAliasAdapter.java @@ -0,0 +1,142 @@ +/* + * + * 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.model.adapter; + +import java.util.Map; +import org.apache.qpid.server.model.AuthenticationMethod; +import org.apache.qpid.server.model.ConfiguredObject; +import org.apache.qpid.server.model.LifetimePolicy; +import org.apache.qpid.server.model.Port; +import org.apache.qpid.server.model.State; +import org.apache.qpid.server.model.Statistics; +import org.apache.qpid.server.model.VirtualHost; +import org.apache.qpid.server.model.VirtualHostAlias; + +import java.security.AccessControlException; +import java.util.Collection; +import java.util.Collections; + +public class VirtualHostAliasAdapter extends AbstractAdapter implements VirtualHostAlias +{ + private VirtualHostAdapter _vhost; + private Port _port; + + public VirtualHostAliasAdapter(VirtualHostAdapter virtualHostAdapter, Port port) + { + super(virtualHostAdapter.getName(), port.getName()); + _vhost = virtualHostAdapter; + _port = port; + } + + @Override + public Port getPort() + { + return _port; + } + + @Override + public VirtualHost getVirtualHost() + { + return _vhost; + } + + @Override + public Collection<AuthenticationMethod> getAuthenticationMethods() + { + return Collections.emptySet(); // TODO - Implement + } + + @Override + public String getName() + { + return _vhost.getName(); + } + + @Override + public String setName(String currentName, String desiredName) throws IllegalStateException, AccessControlException + { + throw new IllegalStateException(); // TODO - Implement + } + + @Override + public State getActualState() + { + return State.ACTIVE; // TODO - Implement + } + + @Override + public boolean isDurable() + { + return true; // TODO - Implement + } + + @Override + public void setDurable(boolean durable) + throws IllegalStateException, AccessControlException, IllegalArgumentException + { + throw new IllegalStateException(); + } + + @Override + public LifetimePolicy getLifetimePolicy() + { + return LifetimePolicy.PERMANENT; // TODO - Implement + } + + @Override + public LifetimePolicy setLifetimePolicy(LifetimePolicy expected, LifetimePolicy desired) + throws IllegalStateException, AccessControlException, IllegalArgumentException + { + throw new IllegalStateException(); // TODO - Implement + } + + @Override + public long getTimeToLive() + { + return 0; // TODO - Implement + } + + @Override + public long setTimeToLive(long expected, long desired) + throws IllegalStateException, AccessControlException, IllegalArgumentException + { + throw new IllegalStateException(); // TODO - Implement + } + + @Override + public Statistics getStatistics() + { + return NoStatistics.getInstance(); + } + + @Override + public <C extends ConfiguredObject> Collection<C> getChildren(Class<C> clazz) + { + return Collections.emptySet(); + } + + @Override + public <C extends ConfiguredObject> C createChild(Class<C> childClass, Map<String, Object> attributes, ConfiguredObject... otherParents) + { + throw new UnsupportedOperationException(); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/impl/AbstractConfiguredObject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/impl/AbstractConfiguredObject.java new file mode 100644 index 0000000000..091887bb3d --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/impl/AbstractConfiguredObject.java @@ -0,0 +1,335 @@ +/* + * + * 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.model.impl; + +import org.apache.qpid.server.model.ConfigurationChangeListener; +import org.apache.qpid.server.model.ConfiguredObject; +import org.apache.qpid.server.model.IllegalStateTransitionException; +import org.apache.qpid.server.model.LifetimePolicy; +import org.apache.qpid.server.model.State; + +import java.security.AccessControlException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +abstract class AbstractConfiguredObject implements ConfiguredObject +{ + public static final Map<String, Object> EMPTY_ATTRIBUTE_MAP = + Collections.<String, Object>emptyMap(); + public static final Map<Class<? extends ConfiguredObject>, ConfiguredObject> EMPTY_PARENT_MAP = + Collections.<Class<? extends ConfiguredObject>, ConfiguredObject>emptyMap(); + + private UUID _id; + private String _name; + private State _state; + private boolean _isDurable; + private LifetimePolicy _lifetimePolicy; + private long _timeToLive; + + + private final Map<String,Object> _attributes = new HashMap<String, Object>(); + private final Map<Class<? extends ConfiguredObject>, ConfiguredObject> _parents = + new HashMap<Class<? extends ConfiguredObject>, ConfiguredObject>(); + private final Map<Class<? extends ConfiguredObject>, Collection<ConfiguredObject>> _children = + new HashMap<Class<? extends ConfiguredObject>, Collection<ConfiguredObject>>(); + + + private final Collection<ConfigurationChangeListener> _changeListeners = + new ArrayList<ConfigurationChangeListener>(); + + protected AbstractConfiguredObject(final UUID id, + final String name, + final State state, + final boolean durable, + final LifetimePolicy lifetimePolicy, + final long timeToLive, + final Map<String, Object> attributes, + final Map<Class<? extends ConfiguredObject>, ConfiguredObject> parents) + { + _id = id; + _name = name; + _state = state; + _isDurable = durable; + _lifetimePolicy = lifetimePolicy; + _timeToLive = timeToLive; + _attributes.putAll(attributes); + _parents.putAll(parents); + } + + public UUID getId() + { + return _id; + } + + public String getName() + { + return _name; + } + + public String setName(final String currentName, final String desiredName) + throws IllegalStateException, AccessControlException + { + if(desiredName == null) + { + throw new NullPointerException("The name may not be null"); + } + + synchronized (getLock()) + { + if(_name.equals(currentName)) + { + _name = desiredName; + } + return _name; + } + } + + public State getDesiredState() + { + return _state; + } + + public State setDesiredState(final State currentState, final State desiredState) + throws IllegalStateTransitionException, AccessControlException + { + synchronized (getLock()) + { + if(_state == currentState && currentState != desiredState) + { + _state = desiredState; + for(ConfigurationChangeListener listener : _changeListeners) + { + listener.stateChanged(this, currentState, desiredState); + } + } + return _state; + } + } + + public void addChangeListener(final ConfigurationChangeListener listener) + { + if(listener == null) + { + throw new NullPointerException("Cannot add a null listener"); + } + synchronized (getLock()) + { + if(!_changeListeners.contains(listener)) + { + _changeListeners.add(listener); + } + } + } + + public boolean removeChangeListener(final ConfigurationChangeListener listener) + { + if(listener == null) + { + throw new NullPointerException("Cannot remove a null listener"); + } + synchronized (getLock()) + { + return _changeListeners.remove(listener); + } + } + + public boolean isDurable() + { + return _isDurable; + } + + public void setDurable(final boolean durable) + throws IllegalStateException, AccessControlException, IllegalArgumentException + { + synchronized (getLock()) + { + _isDurable = durable; + } + } + + public LifetimePolicy getLifetimePolicy() + { + return _lifetimePolicy; + } + + public LifetimePolicy setLifetimePolicy(final LifetimePolicy expected, final LifetimePolicy desired) + throws IllegalStateException, AccessControlException, IllegalArgumentException + { + synchronized(getLock()) + { + if((_lifetimePolicy == null && expected == null) + || (_lifetimePolicy != null && _lifetimePolicy.equals(expected))) + { + _lifetimePolicy = desired; + } + + return _lifetimePolicy; + + } + } + + public long getTimeToLive() + { + return _timeToLive; + } + + public long setTimeToLive(final long expected, final long desired) + throws IllegalStateException, AccessControlException, IllegalArgumentException + { + synchronized(getLock()) + { + if(_timeToLive == expected) + { + _timeToLive = desired; + } + return _timeToLive; + } + } + + public Collection<String> getAttributeNames() + { + synchronized(_attributes) + { + return new ArrayList<String>(_attributes.keySet()); + } + } + + public Object getAttribute(final String name) + { + synchronized (getLock()) + { + return _attributes.get(name); + } + } + + public Object setAttribute(final String name, final Object expected, final Object desired) + throws IllegalStateException, AccessControlException, IllegalArgumentException + { + synchronized (getLock()) + { + Object currentValue = _attributes.get(name); + if ((currentValue == null && expected == null && desired != null) + || (currentValue != null && currentValue.equals(expected) && !currentValue.equals(desired))) + { + _attributes.put(name, desired); + return desired; + } + else + { + return currentValue; + } + } + } + + + public <T extends ConfiguredObject> T getParent(final Class<T> clazz) + { + synchronized (getLock()) + { + return (T) _parents.get(clazz); + } + } + + protected <T extends ConfiguredObject> void addParent(Class<T> clazz, T parent) + { + synchronized (getLock()) + { + _parents.put(clazz, parent); + } + } + + protected <T extends ConfiguredObject> void removeParent(Class<T> clazz) + { + synchronized (getLock()) + { + _parents.remove(clazz); + } + } + + protected <T extends ConfiguredObject> void childAdded(Class<T> clazz, T child) + { + synchronized (getLock()) + { + Collection<ConfiguredObject> children = _children.get(clazz); + if(children == null) + { + children = new ArrayList<ConfiguredObject>(); + _children.put(clazz, children); + } + children.add(child); + } + notifyChildAddedListener(child); + } + + + protected <T extends ConfiguredObject> void childRemoved(Class<T> clazz, T child) + { + synchronized (getLock()) + { + Collection<ConfiguredObject> children = _children.get(clazz); + if(children != null) + { + + children.remove(child); + } + } + notifyChildRemovedListener(child); + } + + protected void notifyChildAddedListener(ConfiguredObject child) + { + for (ConfigurationChangeListener listener : _changeListeners) + { + listener.childAdded(this, child); + } + } + + protected void notifyChildRemovedListener(ConfiguredObject child) + { + synchronized (getLock()) + { + for (ConfigurationChangeListener listener : _changeListeners) + { + listener.childRemoved(this, child); + } + } + } + + @Override + public <C extends ConfiguredObject> Collection<C> getChildren(Class<C> clazz) + { + synchronized (getLock()) + { + Collection<C> children = new ArrayList<C>(); + if(_children.containsKey(clazz)) + { + children.addAll((Collection<? extends C>) _children.get(clazz)); + } + return children; + } + } + + abstract protected Object getLock(); +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/impl/BrokerImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/impl/BrokerImpl.java new file mode 100644 index 0000000000..fe554e2e1c --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/impl/BrokerImpl.java @@ -0,0 +1,148 @@ +/* + * + * 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.model.impl; + +import java.security.AccessControlException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Map; +import java.util.UUID; +import org.apache.qpid.server.model.AuthenticationProvider; +import org.apache.qpid.server.model.Broker; +import org.apache.qpid.server.model.ConfiguredObject; +import org.apache.qpid.server.model.LifetimePolicy; +import org.apache.qpid.server.model.Port; +import org.apache.qpid.server.model.State; +import org.apache.qpid.server.model.Statistics; +import org.apache.qpid.server.model.VirtualHost; + +public class BrokerImpl extends AbstractConfiguredObject implements Broker +{ + private final Collection<VirtualHost> _virtualHosts = new ArrayList<VirtualHost>(); + private final Collection<Port> _ports = new ArrayList<Port>(); + private final Collection<AuthenticationProvider> _authenticationProviders = new ArrayList<AuthenticationProvider>(); + + public BrokerImpl(final UUID id, + final String name, + final State state, + final boolean durable, + final LifetimePolicy lifetimePolicy, + final long timeToLive, + final Map<String, Object> attributes) + { + super(id, name, state, durable, lifetimePolicy, timeToLive, attributes, Collections.EMPTY_MAP); + } + + @Override + protected Object getLock() + { + return this; + } + + public Collection<VirtualHost> getVirtualHosts() + { + synchronized (getLock()) + { + return new ArrayList<VirtualHost>(_virtualHosts); + } + } + + public Collection<Port> getPorts() + { + synchronized (getLock()) + { + return new ArrayList<Port>(_ports); + } + } + + public Collection<AuthenticationProvider> getAuthenticationProviders() + { + synchronized (getLock()) + { + return new ArrayList<AuthenticationProvider>(_authenticationProviders); + } + } + + public State getActualState() + { + return getDesiredState(); + } + + public Statistics getStatistics() + { + // TODO + return null; + } + + @Override + public <C extends ConfiguredObject> C createChild(Class<C> childClass, Map<String, Object> attributes, ConfiguredObject... otherParents) + { + throw new UnsupportedOperationException(); + } + + public VirtualHost createVirtualHost(String name, State initialState,boolean durable, + LifetimePolicy lifetime, long ttl, Map<String, Object> attributes) + throws AccessControlException, IllegalArgumentException + { + // TODO - check name is valid and not reserved + // TODO - check permissions + + synchronized (getLock()) + { + for(VirtualHost virtualHost : _virtualHosts) + { + if(virtualHost.getName().equals(name)) + { + throw new IllegalArgumentException("A virtual host with the name '"+name+"' already exists"); + } + } + VirtualHostImpl vhost = new VirtualHostImpl(UUID.randomUUID(), + name, + initialState, + durable, + lifetime, + ttl, + attributes, + this); + _virtualHosts.add(vhost); + + // TODO - create a mapping for each port with "default" authentication provider and alias of the vhost name? + + childAdded(VirtualHost.class, vhost); + return vhost; + } + } + + public void deleteVirtualHost(VirtualHost virtualHost) + { + synchronized (getLock()) + { + boolean found = _virtualHosts.remove(virtualHost); + if (!found) + { + throw new IllegalArgumentException("A virtual host with the name '" + virtualHost.getName() + "' does not exist"); + } + childRemoved(VirtualHost.class, virtualHost); + } + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/impl/ExchangeImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/impl/ExchangeImpl.java new file mode 100644 index 0000000000..91caf52f3a --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/impl/ExchangeImpl.java @@ -0,0 +1,115 @@ +/* + * + * 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.model.impl; + +import org.apache.qpid.server.model.Binding; +import org.apache.qpid.server.model.ConfiguredObject; +import org.apache.qpid.server.model.Exchange; +import org.apache.qpid.server.model.LifetimePolicy; +import org.apache.qpid.server.model.Publisher; +import org.apache.qpid.server.model.Queue; +import org.apache.qpid.server.model.State; +import org.apache.qpid.server.model.Statistics; +import org.apache.qpid.server.model.VirtualHost; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +class ExchangeImpl extends AbstractConfiguredObject implements Exchange +{ + + private final VirtualHostImpl _virtualHost; + + ExchangeImpl(final UUID id, + final String name, + final State state, + final boolean durable, + final LifetimePolicy lifetimePolicy, + final long timeToLive, + final String exchangeType, + final Map<String, Object> attributes, + final VirtualHostImpl parent) + { + super(id, name, state, durable, lifetimePolicy, timeToLive, fixAttributes(attributes, exchangeType), + (Map) Collections.singletonMap(VirtualHost.class, parent)); + _virtualHost = parent; + + } + + private static Map<String, Object> fixAttributes(final Map<String, Object> attributes, final String exchangeType) + { + Map<String,Object> fixedAttributes = new HashMap<String, Object>(attributes); + fixedAttributes.put(TYPE, exchangeType); + return fixedAttributes; + } + + @Override + protected Object getLock() + { + return _virtualHost.getLock(); + } + + public String getExchangeType() + { + return (String) getAttribute(TYPE); + } + + public Collection<Binding> getBindings() + { + return null; //TODO + } + + public Collection<Publisher> getPublishers() + { + return null; //TODO + } + + public Binding createBinding(String bindingKey, Queue queue, Map<String, Object> bindingArguments, + Map<String, Object> attributes) + { + return null; // TODO - Implement + } + + public void delete() + { + // TODO - Implement + } + + public State getActualState() + { + State vhostState = _virtualHost.getActualState(); + return vhostState == State.ACTIVE ? getDesiredState() : vhostState; + } + + public Statistics getStatistics() + { + return null; // TODO + } + + @Override + public <C extends ConfiguredObject> C createChild(Class<C> childClass, Map<String, Object> attributes, ConfiguredObject... otherParents) + { + throw new UnsupportedOperationException(); //TODO + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/impl/QueueImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/impl/QueueImpl.java new file mode 100644 index 0000000000..bdd7ac5b45 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/impl/QueueImpl.java @@ -0,0 +1,107 @@ +/* + * + * 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.model.impl; + +import java.util.Collection; +import java.util.Collections; +import java.util.Map; +import java.util.UUID; +import org.apache.qpid.server.model.Binding; +import org.apache.qpid.server.model.ConfiguredObject; +import org.apache.qpid.server.model.LifetimePolicy; +import org.apache.qpid.server.model.Queue; +import org.apache.qpid.server.model.QueueNotificationListener; +import org.apache.qpid.server.model.State; +import org.apache.qpid.server.model.Statistics; +import org.apache.qpid.server.model.Consumer; +import org.apache.qpid.server.model.VirtualHost; +import org.apache.qpid.server.queue.QueueEntryVisitor; + +class QueueImpl extends AbstractConfiguredObject implements Queue +{ + + private final VirtualHostImpl _virtualHost; + + QueueImpl(final UUID id, + final String name, + final State state, + final boolean durable, + final LifetimePolicy lifetimePolicy, + final long timeToLive, + final Map<String, Object> attributes, + final VirtualHostImpl parent) + { + super(id, name, state, durable, lifetimePolicy, timeToLive, attributes, + (Map) Collections.singletonMap(VirtualHost.class, parent)); + + _virtualHost = parent; + + } + + @Override + protected Object getLock() + { + return _virtualHost.getLock(); + } + + public Collection<Binding> getBindings() + { + return null; //TODO + } + + public Collection<Consumer> getConsumers() + { + return null; //TODO + } + + public void visit(QueueEntryVisitor visitor) + { + //TODO + } + + public void delete() + { + // TODO - Implement + } + + public State getActualState() + { + State vhostState = _virtualHost.getActualState(); + return vhostState == State.ACTIVE ? getDesiredState() : vhostState; + } + + public Statistics getStatistics() + { + return null; //TODO + } + + @Override + public <C extends ConfiguredObject> C createChild(Class<C> childClass, Map<String, Object> attributes, ConfiguredObject... otherParents) + { + throw new UnsupportedOperationException(); // TODO + } + + @Override + public void setNotificationListener(QueueNotificationListener listener) + { + // TODO - implement + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/impl/VirtualHostImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/impl/VirtualHostImpl.java new file mode 100644 index 0000000000..4a1b0b7127 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/impl/VirtualHostImpl.java @@ -0,0 +1,248 @@ +/* + * + * 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.model.impl; + +import org.apache.qpid.server.model.Broker; +import org.apache.qpid.server.model.ConfiguredObject; +import org.apache.qpid.server.model.Connection; +import org.apache.qpid.server.model.Exchange; +import org.apache.qpid.server.model.LifetimePolicy; +import org.apache.qpid.server.model.Queue; +import org.apache.qpid.server.model.State; +import org.apache.qpid.server.model.Statistics; +import org.apache.qpid.server.model.VirtualHost; +import org.apache.qpid.server.model.VirtualHostAlias; + +import java.security.AccessControlException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; + +class VirtualHostImpl extends AbstractConfiguredObject implements VirtualHost +{ + // attribute names + private static final String REPLICATION_GROUP_NAME = "replicationGroupName"; + + private final Collection<VirtualHostAlias> _aliases = new ArrayList<VirtualHostAlias>(); + private final Collection<Connection> _connections = new ArrayList<Connection>(); + private final Collection<Queue> _queues = new ArrayList<Queue>(); + private final Collection<Exchange> _exchanges = new ArrayList<Exchange>(); + + private final Map<String, Queue> _queueMap = new ConcurrentHashMap<String, Queue>(); + private final Map<String, Exchange> _exchangeMap= new ConcurrentHashMap<String, Exchange>(); + + private final BrokerImpl _broker; + + + VirtualHostImpl(final UUID id, + final String name, + final State state, + final boolean durable, + final LifetimePolicy lifetimePolicy, + final long timeToLive, + final Map<String, Object> attributes, + final BrokerImpl parent) + { + super(id, name, state, durable, lifetimePolicy, timeToLive, attributes, + (Map) Collections.singletonMap(Broker.class, parent)); + + _broker = parent; + } + + @Override + protected Object getLock() + { + return this; + } + + public String getReplicationGroupName() + { + return (String) getAttribute(REPLICATION_GROUP_NAME); + } + + @Override + public Object setAttribute(final String name, final Object expected, final Object desired) + throws IllegalStateException, AccessControlException, IllegalArgumentException + { + synchronized(getLock()) + { + if(REPLICATION_GROUP_NAME.equals(name)) + { + if(getActualState() != State.STOPPED) + { + throw new IllegalStateException("A virtual host must be stopped before you can change the replication group"); + } + if(!(desired instanceof String)) + { + throw new IllegalArgumentException("The desired replication group MUST be a String"); + } + } + return super.setAttribute(name, expected, desired); + } + } + + public Statistics getStatistics() + { + return null; //TODO + } + + @Override + public <C extends ConfiguredObject> C createChild(Class<C> childClass, Map<String, Object> attributes, ConfiguredObject... otherParents) + { + throw new UnsupportedOperationException(); // TODO + } + + public Collection<VirtualHostAlias> getAliases() + { + synchronized(getLock()) + { + return new ArrayList<VirtualHostAlias>(_aliases); + } + } + + public Collection<Connection> getConnections() + { + synchronized (getLock()) + { + return new ArrayList<Connection>(_connections); + } + } + + public Collection<Queue> getQueues() + { + synchronized (getLock()) + { + return new ArrayList<Queue>(_queues); + } + } + + public Collection<Exchange> getExchanges() + { + synchronized (getLock()) + { + return new ArrayList<Exchange>(_exchanges); + } + } + + public State getActualState() + { + final State brokerActualState = _broker.getActualState(); + return brokerActualState == State.ACTIVE ? getDesiredState() : brokerActualState; + } + + + public Exchange createExchange(String name, State initialState,boolean durable, + LifetimePolicy lifetime, long ttl, String type, Map<String, Object> attributes) + throws AccessControlException, IllegalArgumentException + { + // TODO - check name is valid and not reserved + // TODO - check type + // TODO - check permissions + + synchronized (getLock()) + { + for(Exchange exchange : _exchanges) + { + if(exchange.getName().equals(name)) + { + throw new IllegalArgumentException("A exchange with the name '"+name+"' already exists"); + } + } + ExchangeImpl exchange = new ExchangeImpl(UUID.randomUUID(), + name, + initialState, + durable, + lifetime, + ttl, + type, + attributes, + this); + _exchanges.add(exchange); + _exchangeMap.put(name, exchange); + + notifyChildAddedListener(exchange); + return exchange; + } + } + + + public Queue createQueue(String name, State initialState,boolean durable, + boolean exclusive, LifetimePolicy lifetime, long ttl, Map<String, Object> attributes) + throws AccessControlException, IllegalArgumentException + { + // TODO - check name is valid and not reserved + // TODO - check permissions + + synchronized (getLock()) + { + for(Queue queue : _queues) + { + if(queue.getName().equals(name)) + { + throw new IllegalArgumentException("A queue with the name '"+name+"' already exists"); + } + } + QueueImpl queue = new QueueImpl(UUID.randomUUID(), + name, + initialState, + durable, + lifetime, + ttl, + attributes, + this); + + _queues.add(queue); + _queueMap.put(name, queue); + + notifyChildAddedListener(queue); + // TODO - add binding to default exchange?, or make the default exchange work directly off the map held here + + return queue; + } + } + + public void deleteQueue(Queue queue) + { + synchronized (getLock()) + { + boolean found = _queues.remove(queue); + if (!found) + { + throw new IllegalArgumentException("A queue with the name '" + queue.getName()+ "' does not exist"); + } + _queueMap.remove(queue.getName()); + notifyChildRemovedListener(queue); + } + } + + public Collection<String> getExchangeTypes() + { + return null; // TODO - Implement + } + + public void executeTransaction(TransactionalOperation op) + { + // TODO - Implement + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/OsgiSystemPackages.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/OsgiSystemPackages.properties index badeffca05..4677d4b9e6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/OsgiSystemPackages.properties +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/OsgiSystemPackages.properties @@ -31,12 +31,24 @@ javax.management.openmbean=1.0.0 javax.management=1.0.0 +javax.management.remote.rmi=1.0.0 +javax.management.remote=1.0.0 +javax.management.monitor=1.0.0 + +javax.crypto=1 +javax.crypto.spec=1 + +javax.servlet=2 +javax.servlet.http=2 javax.security.auth=1.0.0 javax.security.auth.callback=1.0.0 +javax.security.auth.login=1.0.0 javax.security.sasl=1.0.0 javax.security=1.0.0 +javax.rmi.ssl=1.0.0 + org.xml.sax=1.0.0 org.xml.sax.helpers=1.0.0 @@ -46,37 +58,57 @@ org.osgi.service.startlevel=1.0.0 org.osgi.service.url=1.0.0 org.osgi.util.tracker=1.0.0 +org.apache.commons.codec=1.3.0 +org.apache.commons.codec.binary=1.3.0 + org.apache.commons.configuration=1.0.0 org.apache.commons.lang=1.0.0 org.apache.commons.lang.builder=1.0.0 +org.apache.commons.lang.time=1.0.0 org.apache.commons.logging=1.0.0 -org.apache.log4j=1.2.12 +org.apache.log4j=1.2.16 org.slf4j=1.6.1 +org.eclipse.jetty=7.6.3 +org.eclipse.jetty.http=7.6.3 +org.eclipse.jetty.io=7.6.3 +org.eclipse.jetty.io.nio=7.6.3 +org.eclipse.jetty.security=7.6.3 +org.eclipse.jetty.server=7.6.3 +org.eclipse.jetty.server.session=7.6.3 +org.eclipse.jetty.servlet=7.6.3 + +org.codehaus.jackson=1.9.0 +org.codehaus.jackson.map=1.9.0 + # For Qpid packages (org.apache.qpid), the version number is automatically overridden by QpidPropertis#getReleaseVersion() -org.apache.qpid.junit.extensions.util=0.0.0 org.apache.qpid=0.0.0 org.apache.qpid.common=0.0.0 org.apache.qpid.exchange=0.0.0 org.apache.qpid.framing=0.0.0 org.apache.qpid.management.common.mbeans.annotations=0.0.0 +org.apache.qpid.management.common.mbeans=0.0.0 org.apache.qpid.protocol=0.0.0 org.apache.qpid.transport=0.0.0 org.apache.qpid.transport.codec=0.0.0 org.apache.qpid.server.binding=0.0.0 +org.apache.qpid.server.model=0.0.0 +org.apache.qpid.server.model.adapter=0.0.0 +org.apache.qpid.server.model.impl=0.0.0 org.apache.qpid.server.configuration=0.0.0 org.apache.qpid.server.configuration.plugins=0.0.0 org.apache.qpid.server.configuration.management=0.0.0 +org.apache.qpid.server.connection=0.0.0 org.apache.qpid.server.exchange=0.0.0 org.apache.qpid.server.logging=0.0.0 org.apache.qpid.server.logging.actors=0.0.0 +org.apache.qpid.server.logging.messages=0.0.0 org.apache.qpid.server.logging.subjects=0.0.0 org.apache.qpid.server.message=0.0.0 -org.apache.qpid.server.management=0.0.0 org.apache.qpid.server.persistent=0.0.0 org.apache.qpid.server.plugins=0.0.0 org.apache.qpid.server.protocol=0.0.0 @@ -88,7 +120,10 @@ org.apache.qpid.server.security.access.plugins=0.0.0 org.apache.qpid.server.security.auth=0.0.0 org.apache.qpid.server.security.auth.sasl=0.0.0 org.apache.qpid.server.security.auth.manager=0.0.0 +org.apache.qpid.server.security.auth.rmi=0.0.0 +org.apache.qpid.server.stats=0.0.0 org.apache.qpid.server.virtualhost=0.0.0 org.apache.qpid.server.virtualhost.plugins=0.0.0 org.apache.qpid.util=0.0.0 +org.apache.qpid.server.store.berkeleydb=0.0.0 diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQConnectionModel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQConnectionModel.java index b7fd2387a5..69ba7279bc 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQConnectionModel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQConnectionModel.java @@ -77,4 +77,16 @@ public interface AMQConnectionModel extends StatisticsGatherer public String getUserName(); public boolean isSessionNameUnique(byte[] name); + + String getRemoteAddressString(); + + String getClientId(); + + String getClientVersion(); + + String getPrincipalAsString(); + + long getSessionCountLimit(); + + long getLastIoTime(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java index 5db336649f..850e293c3b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java @@ -34,7 +34,6 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.atomic.AtomicBoolean; -import javax.management.JMException; import javax.security.auth.Subject; import javax.security.sasl.SaslServer; import org.apache.log4j.Logger; @@ -62,8 +61,6 @@ import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.logging.actors.ManagementActor; import org.apache.qpid.server.logging.messages.ConnectionMessages; import org.apache.qpid.server.logging.subjects.ConnectionLogSubject; -import org.apache.qpid.server.management.Managable; -import org.apache.qpid.server.management.ManagedObject; import org.apache.qpid.server.output.ProtocolOutputConverter; import org.apache.qpid.server.output.ProtocolOutputConverterRegistry; import org.apache.qpid.server.queue.QueueEntry; @@ -81,7 +78,7 @@ import org.apache.qpid.transport.TransportException; import org.apache.qpid.transport.network.NetworkConnection; import org.apache.qpid.util.BytesDataOutput; -public class AMQProtocolEngine implements ServerProtocolEngine, Managable, AMQProtocolSession, ConnectionConfig +public class AMQProtocolEngine implements ServerProtocolEngine, AMQProtocolSession, ConnectionConfig { private static final Logger _logger = Logger.getLogger(AMQProtocolEngine.class); @@ -106,8 +103,6 @@ public class AMQProtocolEngine implements ServerProtocolEngine, Managable, AMQPr private AMQCodecFactory _codecFactory; - private AMQProtocolSessionMBean _managedObject; - private SaslServer _saslServer; private Object _lastReceived; @@ -148,8 +143,6 @@ public class AMQProtocolEngine implements ServerProtocolEngine, Managable, AMQPr private final ConfigStore _configStore; private long _createTime = System.currentTimeMillis(); - private ApplicationRegistry _registry; - private boolean _statisticsEnabled = false; private StatisticsCounter _messagesDelivered, _dataDelivered, _messagesReceived, _dataReceived; private NetworkConnection _network; @@ -159,11 +152,6 @@ public class AMQProtocolEngine implements ServerProtocolEngine, Managable, AMQPr private long _lastReceivedTime; private boolean _blocking; - public ManagedObject getManagedObject() - { - return _managedObject; - } - public AMQProtocolEngine(VirtualHostRegistry virtualHostRegistry, NetworkConnection network, final long connectionId) { _stateManager = new AMQStateManager(virtualHostRegistry, this); @@ -181,8 +169,8 @@ public class AMQProtocolEngine implements ServerProtocolEngine, Managable, AMQPr _actor.message(ConnectionMessages.OPEN(null, null, null, false, false, false)); - _registry = virtualHostRegistry.getApplicationRegistry(); initialiseStatistics(); + } public void setNetworkConnection(NetworkConnection network) @@ -196,11 +184,6 @@ public class AMQProtocolEngine implements ServerProtocolEngine, Managable, AMQPr _sender = sender; } - private AMQProtocolSessionMBean createMBean() throws JMException - { - return new AMQProtocolSessionMBean(this); - } - public long getSessionID() { return _connectionID; @@ -649,17 +632,6 @@ public class AMQProtocolEngine implements ServerProtocolEngine, Managable, AMQPr { _cachedChannels[channelId] = channel; } - - checkForNotification(); - } - - private void checkForNotification() - { - int channelsCount = _channelMap.size(); - if (_managedObject != null && channelsCount >= _maxNoOfChannels) - { - _managedObject.notifyClients("Channel count (" + channelsCount + ") has reached the threshold value"); - } } public Long getMaximumNumberOfChannels() @@ -811,13 +783,6 @@ public class AMQProtocolEngine implements ServerProtocolEngine, Managable, AMQPr getConfigStore().removeConfiguredObject(this); - if (_managedObject != null) - { - _managedObject.unregister(); - // Ensure we only do this once. - _managedObject = null; - } - for (Task task : _taskList) { task.doTask(this); @@ -1004,16 +969,6 @@ public class AMQProtocolEngine implements ServerProtocolEngine, Managable, AMQPr _virtualHost.getConnectionRegistry().registerConnection(this); _configStore.addConfiguredObject(this); - - try - { - _managedObject = createMBean(); - _managedObject.register(); - } - catch (JMException e) - { - _logger.error(e); - } } public void addSessionCloseTask(Task task) @@ -1170,6 +1125,16 @@ public class AMQProtocolEngine implements ServerProtocolEngine, Managable, AMQPr return _clientVersion; } + public String getPrincipalAsString() + { + return getAuthId(); + } + + public long getSessionCountLimit() + { + return getMaximumNumberOfChannels(); + } + public Boolean isIncoming() { return true; @@ -1400,12 +1365,7 @@ public class AMQProtocolEngine implements ServerProtocolEngine, Managable, AMQPr public List<AMQSessionModel> getSessionModels() { - List<AMQSessionModel> sessions = new ArrayList<AMQSessionModel>(); - for (AMQChannel channel : getChannels()) - { - sessions.add((AMQSessionModel) channel); - } - return sessions; + return new ArrayList<AMQSessionModel>(getChannels()); } public LogSubject getLogSubject() @@ -1415,21 +1375,15 @@ public class AMQProtocolEngine implements ServerProtocolEngine, Managable, AMQPr public void registerMessageDelivered(long messageSize) { - if (isStatisticsEnabled()) - { - _messagesDelivered.registerEvent(1L); - _dataDelivered.registerEvent(messageSize); - } + _messagesDelivered.registerEvent(1L); + _dataDelivered.registerEvent(messageSize); _virtualHost.registerMessageDelivered(messageSize); } public void registerMessageReceived(long messageSize, long timestamp) { - if (isStatisticsEnabled()) - { - _messagesReceived.registerEvent(1L, timestamp); - _dataReceived.registerEvent(messageSize, timestamp); - } + _messagesReceived.registerEvent(1L, timestamp); + _dataReceived.registerEvent(messageSize, timestamp); _virtualHost.registerMessageReceived(messageSize, timestamp); } @@ -1463,29 +1417,26 @@ public class AMQProtocolEngine implements ServerProtocolEngine, Managable, AMQPr public void initialiseStatistics() { - setStatisticsEnabled(!StatisticsCounter.DISABLE_STATISTICS && - _registry.getConfiguration().isStatisticsGenerationConnectionsEnabled()); - _messagesDelivered = new StatisticsCounter("messages-delivered-" + getSessionID()); _dataDelivered = new StatisticsCounter("data-delivered-" + getSessionID()); _messagesReceived = new StatisticsCounter("messages-received-" + getSessionID()); _dataReceived = new StatisticsCounter("data-received-" + getSessionID()); } - public boolean isStatisticsEnabled() + public boolean isSessionNameUnique(byte[] name) { - return _statisticsEnabled; + // 0-8/0-9/0-9-1 sessions don't have names + return true; } - public void setStatisticsEnabled(boolean enabled) + public String getRemoteAddressString() { - _statisticsEnabled = enabled; + return String.valueOf(getRemoteAddress()); } - public boolean isSessionNameUnique(byte[] name) + public String getClientId() { - // 0-8/0-9/0-9-1 sessions don't have names - return true; + return String.valueOf(getContextKey()); } public void setDeferFlush(boolean deferFlush) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java deleted file mode 100644 index e70720600e..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java +++ /dev/null @@ -1,344 +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. - * - */ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License") - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.qpid.server.protocol; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.ConnectionCloseBody; -import org.apache.qpid.framing.MethodRegistry; -import org.apache.qpid.management.common.mbeans.annotations.MBeanConstructor; -import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription; -import org.apache.qpid.protocol.AMQConstant; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.logging.actors.CurrentActor; -import org.apache.qpid.server.logging.actors.ManagementActor; -import org.apache.qpid.server.management.AbstractAMQManagedConnectionObject; -import org.apache.qpid.server.management.ManagedObject; - -import javax.management.JMException; -import javax.management.MBeanException; -import javax.management.NotCompliantMBeanException; -import javax.management.openmbean.CompositeData; -import javax.management.openmbean.CompositeDataSupport; -import javax.management.openmbean.OpenDataException; -import javax.management.openmbean.TabularData; -import javax.management.openmbean.TabularDataSupport; -import java.util.Date; -import java.util.List; - -/** - * This MBean class implements the management interface. In order to make more attributes, operations and notifications - * available over JMX simply augment the ManagedConnection interface and add the appropriate implementation here. - */ -@MBeanDescription("Management Bean for an AMQ Broker 0-9-1/0-9/0-8 Connections") -public class AMQProtocolSessionMBean extends AbstractAMQManagedConnectionObject -{ - private AMQProtocolSession _protocolSession = null; - - private static final AMQShortString BROKER_MANAGEMENT_CONSOLE_HAS_CLOSED_THE_CONNECTION = - new AMQShortString(BROKER_MANAGEMENT_CONSOLE_HAS_CLOSED_THE_CONNECTION_STR); - - @MBeanConstructor("Creates an MBean exposing an AMQ Broker 0-9-1/0-9/0-8 Connection") - public AMQProtocolSessionMBean(AMQProtocolSession amqProtocolSession) throws NotCompliantMBeanException, OpenDataException - { - super(amqProtocolSession.getRemoteAddress().toString()); - _protocolSession = amqProtocolSession; - } - - public String getClientId() - { - return String.valueOf(_protocolSession.getContextKey()); - } - - public String getAuthorizedId() - { - return (_protocolSession.getAuthorizedPrincipal() != null ) ? _protocolSession.getAuthorizedPrincipal().getName() : null; - } - - public String getVersion() - { - return _protocolSession.getClientVersion(); - } - - public Date getLastIoTime() - { - return new Date(_protocolSession.getLastIoTime()); - } - - public String getRemoteAddress() - { - return _protocolSession.getRemoteAddress().toString(); - } - - public ManagedObject getParentObject() - { - return _protocolSession.getVirtualHost().getManagedObject(); - } - - public Long getWrittenBytes() - { - return _protocolSession.getWrittenBytes(); - } - - public Long getReadBytes() - { - return _protocolSession.getWrittenBytes(); - } - - public Long getMaximumNumberOfChannels() - { - return _protocolSession.getMaximumNumberOfChannels(); - } - - /** - * commits transactions for a transactional channel - * - * @param channelId - * @throws JMException if channel with given id doesn't exist or if commit fails - */ - public void commitTransactions(int channelId) throws JMException - { - CurrentActor.set(new ManagementActor(getLogActor().getRootMessageLogger())); - try - { - AMQChannel channel = _protocolSession.getChannel(channelId); - if (channel == null) - { - throw new JMException("The channel (channel Id = " + channelId + ") does not exist"); - } - - _protocolSession.commitTransactions(channel); - } - catch (AMQException ex) - { - throw new MBeanException(ex, ex.toString()); - } - finally - { - CurrentActor.remove(); - } - } - - /** - * rollsback the transactions for a transactional channel - * - * @param channelId - * @throws JMException if channel with given id doesn't exist or if rollback fails - */ - public void rollbackTransactions(int channelId) throws JMException - { - CurrentActor.set(new ManagementActor(getLogActor().getRootMessageLogger())); - try - { - AMQChannel channel = _protocolSession.getChannel(channelId); - if (channel == null) - { - throw new JMException("The channel (channel Id = " + channelId + ") does not exist"); - } - - _protocolSession.rollbackTransactions(channel); - } - catch (AMQException ex) - { - throw new MBeanException(ex, ex.toString()); - } - finally - { - CurrentActor.remove(); - } - } - - /** - * Creates the list of channels in tabular form from the _channelMap. - * - * @return list of channels in tabular form. - * @throws OpenDataException - */ - public TabularData channels() throws OpenDataException - { - TabularDataSupport channelsList = new TabularDataSupport(_channelsType); - List<AMQChannel> list = _protocolSession.getChannels(); - - for (AMQChannel channel : list) - { - Object[] itemValues = - { - channel.getChannelId(), channel.isTransactional(), - (channel.getDefaultQueue() != null) ? channel.getDefaultQueue().getNameShortString().asString() : null, - channel.getUnacknowledgedMessageMap().size(), channel.getBlocking() - }; - - CompositeData channelData = new CompositeDataSupport(_channelType, - COMPOSITE_ITEM_NAMES_DESC.toArray(new String[COMPOSITE_ITEM_NAMES_DESC.size()]), itemValues); - channelsList.put(channelData); - } - - return channelsList; - } - - /** - * closes the connection. The administrator can use this management operation to close connection to free up - * resources. - * @throws JMException - */ - public void closeConnection() throws JMException - { - - MethodRegistry methodRegistry = _protocolSession.getMethodRegistry(); - ConnectionCloseBody responseBody = - methodRegistry.createConnectionCloseBody(AMQConstant.REPLY_SUCCESS.getCode(), - // replyCode - BROKER_MANAGEMENT_CONSOLE_HAS_CLOSED_THE_CONNECTION, - // replyText, - 0, - 0); - - // This seems ugly but because we use closeConnection in both normal - // broker operation and as part of the management interface it cannot - // be avoided. The Current Actor will be null when this method is - // called via the Management interface. This is because we allow the - // Local API connection with JConsole. If we did not allow that option - // then the CurrentActor could be set in our JMX Proxy object. - // As it is we need to set the CurrentActor on all MBean methods - // Ideally we would not have a single method that can be called from - // two contexts. - boolean removeActor = false; - if (CurrentActor.get() == null) - { - removeActor = true; - CurrentActor.set(new ManagementActor(getLogActor().getRootMessageLogger())); - } - - try - { - _protocolSession.writeFrame(responseBody.generateFrame(0)); - - try - { - - _protocolSession.closeSession(); - } - catch (AMQException ex) - { - throw new MBeanException(ex, ex.toString()); - } - } - finally - { - if (removeActor) - { - CurrentActor.remove(); - } - } - } - - public void resetStatistics() throws Exception - { - _protocolSession.resetStatistics(); - } - - public double getPeakMessageDeliveryRate() - { - return _protocolSession.getMessageDeliveryStatistics().getPeak(); - } - - public double getPeakDataDeliveryRate() - { - return _protocolSession.getDataDeliveryStatistics().getPeak(); - } - - public double getMessageDeliveryRate() - { - return _protocolSession.getMessageDeliveryStatistics().getRate(); - } - - public double getDataDeliveryRate() - { - return _protocolSession.getDataDeliveryStatistics().getRate(); - } - - public long getTotalMessagesDelivered() - { - return _protocolSession.getMessageDeliveryStatistics().getTotal(); - } - - public long getTotalDataDelivered() - { - return _protocolSession.getDataDeliveryStatistics().getTotal(); - } - - public double getPeakMessageReceiptRate() - { - return _protocolSession.getMessageReceiptStatistics().getPeak(); - } - - public double getPeakDataReceiptRate() - { - return _protocolSession.getDataReceiptStatistics().getPeak(); - } - - public double getMessageReceiptRate() - { - return _protocolSession.getMessageReceiptStatistics().getRate(); - } - - public double getDataReceiptRate() - { - return _protocolSession.getDataReceiptStatistics().getRate(); - } - - public long getTotalMessagesReceived() - { - return _protocolSession.getMessageReceiptStatistics().getTotal(); - } - - public long getTotalDataReceived() - { - return _protocolSession.getDataReceiptStatistics().getTotal(); - } - - public boolean isStatisticsEnabled() - { - return _protocolSession.isStatisticsEnabled(); - } - - public void setStatisticsEnabled(boolean enabled) - { - _protocolSession.setStatisticsEnabled(enabled); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQSessionModel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQSessionModel.java index 0896499cda..efc64d9d91 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQSessionModel.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQSessionModel.java @@ -55,7 +55,7 @@ public interface AMQSessionModel extends Comparable<AMQSessionModel> * is logged or the connection is closed, depending on the configuration. An open * transaction is one that has recent activity. The transaction age is counted * from the time the transaction was started. An idle transaction is one that - * has had no activity, such as publishing or acknowledgeing messages. + * has had no activity, such as publishing or acknowledging messages. * * @param openWarn time in milliseconds before alerting on open transaction * @param openClose time in milliseconds before closing connection with open transaction @@ -72,6 +72,16 @@ public interface AMQSessionModel extends Comparable<AMQSessionModel> void unblock(); + boolean getBlocking(); boolean onSameConnection(InboundMessage inbound); + + int getUnacknowledgedMessageCount(); + + Long getTxnCount(); + Long getTxnStart(); + Long getTxnCommits(); + Long getTxnRejects(); + + int getChannelId(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/Subscription_1_0.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/Subscription_1_0.java index 08926d000d..b4195d7e5a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/Subscription_1_0.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/Subscription_1_0.java @@ -49,6 +49,7 @@ import org.apache.qpid.amqp_1_0.type.transport.Transfer; import org.apache.qpid.server.filter.FilterManager; import org.apache.qpid.server.logging.LogActor; import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.protocol.AMQSessionModel; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.QueueEntry; import org.apache.qpid.server.subscription.Subscription; @@ -631,4 +632,46 @@ class Subscription_1_0 implements Subscription { _filters = filters; } + + @Override + public AMQSessionModel getSessionModel() + { + // TODO + return null; + } + + @Override + public long getBytesOut() + { + // TODO + return 0; + } + + @Override + public long getMessagesOut() + { + // TODO + return 0; + } + + @Override + public long getUnacknowledgedBytes() + { + // TODO + return 0; + } + + @Override + public long getUnacknowledgedMessages() + { + // TODO + return 0; + } + + @Override + public String getConsumerName() + { + //TODO + return "TODO"; + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java index e643338c3d..38847972d5 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java @@ -28,21 +28,25 @@ import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.exchange.ExchangeReferrer; import org.apache.qpid.server.logging.LogSubject; -import org.apache.qpid.server.management.Managable; -import org.apache.qpid.server.management.ManagedObject; import org.apache.qpid.server.protocol.AMQSessionModel; import org.apache.qpid.server.security.AuthorizationHolder; import org.apache.qpid.server.store.TransactionLogResource; import org.apache.qpid.server.subscription.Subscription; import org.apache.qpid.server.virtualhost.VirtualHost; +import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Set; -public interface AMQQueue extends Managable, Comparable<AMQQueue>, ExchangeReferrer, TransactionLogResource, BaseQueue, +public interface AMQQueue extends Comparable<AMQQueue>, ExchangeReferrer, TransactionLogResource, BaseQueue, QueueConfig { + public interface NotificationListener + { + void notifyClients(NotificationCheck notification, AMQQueue queue, String notificationMsg); + } + boolean getDeleteOnNoConsumers(); void setDeleteOnNoConsumers(boolean b); @@ -57,6 +61,12 @@ public interface AMQQueue extends Managable, Comparable<AMQQueue>, ExchangeRefer LogSubject getLogSubject(); + long getUnackedMessageBytes(); + + long getTotalDequeueCount(); + + long getTotalEnqueueCount(); + public interface Context { QueueEntry getLastSeenEntry(); @@ -79,6 +89,17 @@ public interface AMQQueue extends Managable, Comparable<AMQQueue>, ExchangeRefer void unregisterSubscription(final Subscription subscription) throws AMQException; + Collection<Subscription> getConsumers(); + + interface SubscriptionRegistrationListener + { + void subscriptionRegistered(AMQQueue queue, Subscription subscription); + void subscriptionUnregistered(AMQQueue queue, Subscription subscription); + } + + void addSubscriptionRegistrationListener(SubscriptionRegistrationListener listener); + void removeSubscriptionRegistrationListener(SubscriptionRegistrationListener listener); + int getConsumerCount(); @@ -109,7 +130,7 @@ public interface AMQQueue extends Managable, Comparable<AMQQueue>, ExchangeRefer void dequeue(QueueEntry entry, Subscription sub); - void decrementUnackedMsgCount(); + void decrementUnackedMsgCount(QueueEntry queueEntry); boolean resend(final QueueEntry entry, final Subscription subscription) throws AMQException; @@ -146,13 +167,8 @@ public interface AMQQueue extends Managable, Comparable<AMQQueue>, ExchangeRefer void removeMessagesFromQueue(long fromMessageId, long toMessageId); - static interface Visitor - { - boolean visit(QueueEntry entry); - } - - void visit(Visitor visitor); - + void visit(QueueEntryVisitor visitor); + long getMaximumMessageSize(); @@ -216,8 +232,6 @@ public interface AMQQueue extends Managable, Comparable<AMQQueue>, ExchangeRefer void setAlternateExchange(Exchange exchange); - void setAlternateExchange(String exchangeName); - Map<String, Object> getArguments(); void checkCapacity(AMQSessionModel channel); @@ -245,12 +259,12 @@ public interface AMQQueue extends Managable, Comparable<AMQQueue>, ExchangeRefer } /** - * ExistingSubscriptionPreventsExclusive signals a failure to create an exclusize subscription, as a subscription + * ExistingSubscriptionPreventsExclusive signals a failure to create an exclusive subscription, as a subscription * already exists. * * <p/><table id="crc"><caption>CRC Card</caption> * <tr><th> Responsibilities <th> Collaborations - * <tr><td> Represent failure to create an exclusize subscription, as a subscription already exists. + * <tr><td> Represent failure to create an exclusive subscription, as a subscription already exists. * </table> * * @todo Not an AMQP exception as no status code. @@ -274,9 +288,7 @@ public interface AMQQueue extends Managable, Comparable<AMQQueue>, ExchangeRefer ConfigurationPlugin getConfiguration(); - ManagedObject getManagedObject(); - - void setExclusive(boolean exclusive) throws AMQException; + void setExclusive(boolean exclusive); /** * Gets the maximum delivery count. If a message on this queue @@ -295,4 +307,19 @@ public interface AMQQueue extends Managable, Comparable<AMQQueue>, ExchangeRefer */ public void setMaximumDeliveryCount(final int maximumDeliveryCount); + void setNotificationListener(NotificationListener listener); + + /** + * Sets the free text description of this queue. + * + * @param description + * + */ + void setDescription(String description); + + /** + * Gets the free text description of this queue. + */ + String getDescription(); + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java index f2b7d7c56b..d93af2fc25 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueFactory.java @@ -20,6 +20,7 @@ */ package org.apache.qpid.server.queue; +import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.UUID; @@ -41,6 +42,7 @@ import org.apache.qpid.server.virtualhost.VirtualHost; public class AMQQueueFactory { public static final String X_QPID_PRIORITIES = "x-qpid-priorities"; + public static final String X_QPID_DESCRIPTION = "x-qpid-description"; public static final String QPID_LVQ_KEY = "qpid.LVQ_key"; public static final String QPID_LAST_VALUE_QUEUE = "qpid.last_value_queue"; public static final String QPID_LAST_VALUE_QUEUE_KEY = "qpid.last_value_queue_key"; @@ -350,32 +352,7 @@ public class AMQQueueFactory boolean autodelete = config.getAutoDelete(); boolean exclusive = config.getExclusive(); String owner = config.getOwner(); - Map<String,Object> arguments = null; - - if(config.isLVQ() || config.getLVQKey() != null) - { - arguments = new HashMap<String,Object>(); - arguments.put(QPID_LAST_VALUE_QUEUE, 1); - arguments.put(QPID_LAST_VALUE_QUEUE_KEY, config.getLVQKey() == null ? QPID_LVQ_KEY : config.getLVQKey()); - } - else if (config.getPriority() || config.getPriorities() > 0) - { - arguments = new HashMap<String,Object>(); - arguments.put(X_QPID_PRIORITIES, config.getPriorities() < 0 ? 10 : config.getPriorities()); - } - else if (config.getQueueSortKey() != null && !"".equals(config.getQueueSortKey())) - { - arguments = new HashMap<String,Object>(); - arguments.put(QPID_QUEUE_SORT_KEY, config.getQueueSortKey()); - } - if (!config.getAutoDelete() && config.isDeadLetterQueueEnabled()) - { - if (arguments == null) - { - arguments = new HashMap<String,Object>(); - } - arguments.put(X_QPID_DLQ_ENABLED, true); - } + Map<String, Object> arguments = createQueueArgumentsFromConfig(config); // we need queues that are defined in config to have deterministic ids. UUID id = UUIDGenerator.generateUUID(queueName, host.getName()); @@ -385,7 +362,6 @@ public class AMQQueueFactory return q; } - /** * Validates DLQ and DLE names * <p> @@ -475,4 +451,43 @@ public class AMQQueueFactory String dlExchangeName = name + serverConfig.getDeadLetterExchangeSuffix(); return dlExchangeName; } + + private static Map<String, Object> createQueueArgumentsFromConfig(QueueConfiguration config) + { + Map<String,Object> arguments = new HashMap<String,Object>(); + + if(config.isLVQ() || config.getLVQKey() != null) + { + arguments.put(QPID_LAST_VALUE_QUEUE, 1); + arguments.put(QPID_LAST_VALUE_QUEUE_KEY, config.getLVQKey() == null ? QPID_LVQ_KEY : config.getLVQKey()); + } + else if (config.getPriority() || config.getPriorities() > 0) + { + arguments.put(X_QPID_PRIORITIES, config.getPriorities() < 0 ? 10 : config.getPriorities()); + } + else if (config.getQueueSortKey() != null && !"".equals(config.getQueueSortKey())) + { + arguments.put(QPID_QUEUE_SORT_KEY, config.getQueueSortKey()); + } + + if (!config.getAutoDelete() && config.isDeadLetterQueueEnabled()) + { + arguments.put(X_QPID_DLQ_ENABLED, true); + } + + if (config.getDescription() != null && !"".equals(config.getDescription())) + { + arguments.put(X_QPID_DESCRIPTION, config.getDescription()); + } + + if (arguments.isEmpty()) + { + return Collections.emptyMap(); + } + else + { + return arguments; + } + } + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java deleted file mode 100644 index b0d4cb3486..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java +++ /dev/null @@ -1,664 +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.queue; - -import org.apache.commons.lang.time.FastDateFormat; -import org.apache.log4j.Logger; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.BasicContentHeaderProperties; -import org.apache.qpid.framing.ContentHeaderBody; -import org.apache.qpid.management.common.mbeans.ManagedQueue; -import org.apache.qpid.management.common.mbeans.annotations.MBeanConstructor; -import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.management.AMQManagedObject; -import org.apache.qpid.server.management.ManagedObject; -import org.apache.qpid.server.message.AMQMessage; -import org.apache.qpid.server.message.AMQMessageHeader; -import org.apache.qpid.server.message.MessageTransferMessage; -import org.apache.qpid.server.message.ServerMessage; -import org.apache.qpid.transport.MessageProperties; - -import javax.management.JMException; -import javax.management.MBeanException; -import javax.management.MBeanNotificationInfo; -import javax.management.Notification; -import javax.management.ObjectName; -import javax.management.OperationsException; -import javax.management.monitor.MonitorNotification; -import javax.management.openmbean.ArrayType; -import javax.management.openmbean.CompositeData; -import javax.management.openmbean.CompositeDataSupport; -import javax.management.openmbean.CompositeType; -import javax.management.openmbean.OpenDataException; -import javax.management.openmbean.OpenType; -import javax.management.openmbean.SimpleType; -import javax.management.openmbean.TabularData; -import javax.management.openmbean.TabularDataSupport; -import javax.management.openmbean.TabularType; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; - - -/** - * AMQQueueMBean is the management bean for an {@link AMQQueue}. - * - * <p/><table id="crc"><caption>CRC Caption</caption> - * <tr><th> Responsibilities <th> Collaborations - * </table> - */ -@MBeanDescription("Management Interface for AMQQueue") -public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, QueueNotificationListener -{ - - /** Used for debugging purposes. */ - private static final Logger LOGGER = Logger.getLogger(AMQQueueMBean.class); - - /** Date/time format used for message expiration and message timestamp formatting */ - public static final String JMSTIMESTAMP_DATETIME_FORMAT = "MM-dd-yy HH:mm:ss.SSS z"; - - private static final FastDateFormat FAST_DATE_FORMAT = FastDateFormat.getInstance(JMSTIMESTAMP_DATETIME_FORMAT); - - private final AMQQueue _queue; - private final String _queueName; - // OpenMBean data types for viewMessages method - - private static OpenType[] _msgAttributeTypes = new OpenType[6]; // AMQ message attribute types. - private static CompositeType _messageDataType = null; // Composite type for representing AMQ Message data. - private static TabularType _messagelistDataType = null; // Datatype for representing AMQ messages list. - - // OpenMBean data types for viewMessageContent method - private static CompositeType _msgContentType = null; - private static OpenType[] _msgContentAttributeTypes = new OpenType[4]; - - private final long[] _lastNotificationTimes = new long[NotificationCheck.values().length]; - private Notification _lastNotification = null; - - - - - @MBeanConstructor("Creates an MBean exposing an AMQQueue") - public AMQQueueMBean(AMQQueue queue) throws JMException - { - super(ManagedQueue.class, ManagedQueue.TYPE); - _queue = queue; - _queueName = queue.getName(); - } - - public ManagedObject getParentObject() - { - return _queue.getVirtualHost().getManagedObject(); - } - - static - { - try - { - init(); - } - catch (JMException ex) - { - // This is not expected to ever occur. - throw new RuntimeException("Got JMException in static initializer.", ex); - } - } - - /** - * initialises the openmbean data types - */ - private static void init() throws OpenDataException - { - _msgContentAttributeTypes[0] = SimpleType.LONG; // For message id - _msgContentAttributeTypes[1] = SimpleType.STRING; // For MimeType - _msgContentAttributeTypes[2] = SimpleType.STRING; // For Encoding - _msgContentAttributeTypes[3] = new ArrayType(1, SimpleType.BYTE); // For message content - _msgContentType = new CompositeType("Message Content", "AMQ Message Content", - VIEW_MSG_CONTENT_COMPOSITE_ITEM_NAMES_DESC.toArray(new String[VIEW_MSG_CONTENT_COMPOSITE_ITEM_NAMES_DESC.size()]), - VIEW_MSG_CONTENT_COMPOSITE_ITEM_NAMES_DESC.toArray(new String[VIEW_MSG_CONTENT_COMPOSITE_ITEM_NAMES_DESC.size()]), - _msgContentAttributeTypes); - - _msgAttributeTypes[0] = SimpleType.LONG; // For message id - _msgAttributeTypes[1] = new ArrayType(1, SimpleType.STRING); // For header attributes - _msgAttributeTypes[2] = SimpleType.LONG; // For size - _msgAttributeTypes[3] = SimpleType.BOOLEAN; // For redelivered - _msgAttributeTypes[4] = SimpleType.LONG; // For queue position - _msgAttributeTypes[5] = SimpleType.INTEGER; // For delivery count - - _messageDataType = new CompositeType("Message", "AMQ Message", - VIEW_MSGS_COMPOSITE_ITEM_NAMES_DESC.toArray(new String[VIEW_MSGS_COMPOSITE_ITEM_NAMES_DESC.size()]), - VIEW_MSGS_COMPOSITE_ITEM_NAMES_DESC.toArray(new String[VIEW_MSGS_COMPOSITE_ITEM_NAMES_DESC.size()]), _msgAttributeTypes); - _messagelistDataType = new TabularType("Messages", "List of messages", _messageDataType, - VIEW_MSGS_TABULAR_UNIQUE_INDEX.toArray(new String[VIEW_MSGS_TABULAR_UNIQUE_INDEX.size()])); - } - - public String getObjectInstanceName() - { - return ObjectName.quote(_queueName); - } - - public String getName() - { - return _queueName; - } - - public boolean isDurable() - { - return _queue.isDurable(); - } - - public String getOwner() - { - return String.valueOf(_queue.getOwner()); - } - - public boolean isAutoDelete() - { - return _queue.isAutoDelete(); - } - - public Integer getMessageCount() - { - return _queue.getMessageCount(); - } - - public Integer getMaximumDeliveryCount() - { - return _queue.getMaximumDeliveryCount(); - } - - public Long getMaximumMessageSize() - { - return _queue.getMaximumMessageSize(); - } - - public Long getMaximumMessageAge() - { - return _queue.getMaximumMessageAge(); - } - - public void setMaximumMessageAge(Long maximumMessageAge) - { - _queue.setMaximumMessageAge(maximumMessageAge); - } - - public void setMaximumMessageSize(Long value) - { - _queue.setMaximumMessageSize(value); - } - - public Integer getConsumerCount() - { - return _queue.getConsumerCount(); - } - - public Integer getActiveConsumerCount() - { - return _queue.getActiveConsumerCount(); - } - - public Long getReceivedMessageCount() - { - return _queue.getReceivedMessageCount(); - } - - public Long getMaximumMessageCount() - { - return _queue.getMaximumMessageCount(); - } - - public void setMaximumMessageCount(Long value) - { - _queue.setMaximumMessageCount(value); - } - - /** - * returns the maximum total size of messages(bytes) in the queue. - */ - public Long getMaximumQueueDepth() - { - return _queue.getMaximumQueueDepth(); - } - - public void setMaximumQueueDepth(Long value) - { - _queue.setMaximumQueueDepth(value); - } - - /** - * returns the total size of messages(bytes) in the queue. - */ - public Long getQueueDepth() throws JMException - { - return _queue.getQueueDepth(); - } - - public Long getCapacity() - { - return _queue.getCapacity(); - } - - public void setCapacity(Long capacity) throws IllegalArgumentException - { - if( _queue.getFlowResumeCapacity() > capacity ) - { - throw new IllegalArgumentException("Capacity must not be less than FlowResumeCapacity"); - } - - _queue.setCapacity(capacity); - } - - public Long getFlowResumeCapacity() - { - return _queue.getFlowResumeCapacity(); - } - - public void setFlowResumeCapacity(Long flowResumeCapacity) throws IllegalArgumentException - { - if( _queue.getCapacity() < flowResumeCapacity ) - { - throw new IllegalArgumentException("FlowResumeCapacity must not exceed Capacity"); - } - - _queue.setFlowResumeCapacity(flowResumeCapacity); - } - - public boolean isFlowOverfull() - { - return _queue.isOverfull(); - } - - public boolean isExclusive() - { - return _queue.isExclusive(); - } - - public void setExclusive(boolean exclusive) throws JMException - { - try - { - _queue.setExclusive(exclusive); - } - catch (AMQException e) - { - throw new JMException(e.toString()); - } - } - - public void setAlternateExchange(String exchangeName) - { - _queue.setAlternateExchange(exchangeName); - } - - public String getAlternateExchange() - { - Exchange exchange = _queue.getAlternateExchange(); - String name = exchange == null ? null : exchange.getName(); - return name == null ? null : name; - } - - /** - * Checks if there is any notification to be send to the listeners - */ - public void checkForNotification(ServerMessage msg) throws AMQException - { - - final Set<NotificationCheck> notificationChecks = _queue.getNotificationChecks(); - - if(!notificationChecks.isEmpty()) - { - final long currentTime = System.currentTimeMillis(); - final long thresholdTime = currentTime - _queue.getMinimumAlertRepeatGap(); - - for (NotificationCheck check : notificationChecks) - { - if (check.isMessageSpecific() || (_lastNotificationTimes[check.ordinal()] < thresholdTime)) - { - if (check.notifyIfNecessary(msg, _queue, this)) - { - _lastNotificationTimes[check.ordinal()] = currentTime; - } - } - } - } - - } - - /** - * Sends the notification to the listeners - */ - public void notifyClients(NotificationCheck notification, AMQQueue queue, String notificationMsg) - { - // important : add log to the log file - monitoring tools may be looking for this - LOGGER.info(notification.name() + " On Queue " + queue.getNameShortString() + " - " + notificationMsg); - notificationMsg = notification.name() + " " + notificationMsg; - - _lastNotification = - new Notification(MonitorNotification.THRESHOLD_VALUE_EXCEEDED, this, incrementAndGetSequenceNumber(), - System.currentTimeMillis(), notificationMsg); - - getBroadcaster().sendNotification(_lastNotification); - } - - public Notification getLastNotification() - { - return _lastNotification; - } - - /** - * @see AMQQueue#deleteMessageFromTop - */ - public void deleteMessageFromTop() throws JMException - { - _queue.deleteMessageFromTop(); - } - - /** - * Clears the queue of non-acquired messages - * - * @return the number of messages deleted - * @see AMQQueue#clearQueue - */ - public Long clearQueue() throws JMException - { - try - { - return _queue.clearQueue(); - } - catch (AMQException ex) - { - throw new MBeanException(ex, "Error clearing queue " + _queueName); - } - } - - /** - * returns message content as byte array and related attributes for the given message id. - */ - public CompositeData viewMessageContent(long msgId) throws JMException - { - QueueEntry entry = _queue.getMessageOnTheQueue(msgId); - - if (entry == null) - { - throw new OperationsException("AMQMessage with message id = " + msgId + " is not in the " + _queueName); - } - - ServerMessage serverMsg = entry.getMessage(); - final int bodySize = (int) serverMsg.getSize(); - - - List<Byte> msgContent = new ArrayList<Byte>(); - - java.nio.ByteBuffer buf = java.nio.ByteBuffer.allocate(bodySize); - int position = 0; - - while(position < bodySize) - { - position += serverMsg.getContent(buf, position); - buf.flip(); - for(int i = 0; i < buf.limit(); i++) - { - msgContent.add(buf.get(i)); - } - buf.clear(); - } - - AMQMessageHeader header = serverMsg.getMessageHeader(); - - String mimeType = null, encoding = null; - if (header != null) - { - mimeType = header.getMimeType(); - - encoding = header.getEncoding(); - } - - - Object[] itemValues = { msgId, mimeType, encoding, msgContent.toArray(new Byte[0]) }; - - return new CompositeDataSupport(_msgContentType, - VIEW_MSG_CONTENT_COMPOSITE_ITEM_NAMES_DESC.toArray( - new String[VIEW_MSG_CONTENT_COMPOSITE_ITEM_NAMES_DESC.size()]), itemValues); - - } - - /** - * Returns the header contents of the messages stored in this queue in tabular form. - * Deprecated as of Qpid JMX API 1.3 - */ - @Deprecated - public TabularData viewMessages(int beginIndex, int endIndex) throws JMException - { - return viewMessages((long)beginIndex,(long)endIndex); - } - - - /** - * Returns the header contents of the messages stored in this queue in tabular form. - * @param startPosition The queue position of the first message to be viewed - * @param endPosition The queue position of the last message to be viewed - */ - public TabularData viewMessages(long startPosition, long endPosition) throws JMException - { - if ((startPosition > endPosition) || (startPosition < 1)) - { - throw new OperationsException("From Index = " + startPosition + ", To Index = " + endPosition - + "\n\"From Index\" should be greater than 0 and less than \"To Index\""); - } - - if ((endPosition - startPosition) > Integer.MAX_VALUE) - { - throw new OperationsException("Specified MessageID interval is too large. Intervals must be less than 2^31 in size"); - } - - List<QueueEntry> list = _queue.getMessagesRangeOnTheQueue(startPosition,endPosition); - TabularDataSupport _messageList = new TabularDataSupport(_messagelistDataType); - - try - { - // Create the tabular list of message header contents - int size = list.size(); - - for (int i = 0; i < size ; i++) - { - long position = startPosition + i; - final QueueEntry queueEntry = list.get(i); - ServerMessage serverMsg = queueEntry.getMessage(); - - String[] headerAttributes = null; - Object[] itemValues = null; - - if(serverMsg instanceof AMQMessage) - { - AMQMessage msg = (AMQMessage) serverMsg; - ContentHeaderBody headerBody = msg.getContentHeaderBody(); - // Create header attributes list - headerAttributes = getMessageHeaderProperties(headerBody); - itemValues = new Object[]{msg.getMessageId(), headerAttributes, headerBody.getBodySize(), queueEntry.isRedelivered(), position, queueEntry.getDeliveryCount()}; - } - else if(serverMsg instanceof MessageTransferMessage) - { - // We have a 0-10 message - MessageTransferMessage msg = (MessageTransferMessage) serverMsg; - - // Create header attributes list - headerAttributes = getMessageTransferMessageHeaderProps(msg); - itemValues = new Object[]{msg.getMessageNumber(), headerAttributes, msg.getSize(), queueEntry.isRedelivered(), position, queueEntry.getDeliveryCount()}; - } - else - { - //unknown message - headerAttributes = new String[]{"N/A"}; - itemValues = new Object[]{serverMsg.getMessageNumber(), headerAttributes, serverMsg.getSize(), queueEntry.isRedelivered(), position, queueEntry.getDeliveryCount()}; - } - - CompositeData messageData = new CompositeDataSupport(_messageDataType, - VIEW_MSGS_COMPOSITE_ITEM_NAMES_DESC.toArray(new String[VIEW_MSGS_COMPOSITE_ITEM_NAMES_DESC.size()]), itemValues); - _messageList.put(messageData); - } - } - catch (AMQException e) - { - JMException jme = new JMException("Error creating message contents: " + e); - jme.initCause(e); - throw jme; - } - - return _messageList; - } - - private String[] getMessageHeaderProperties(ContentHeaderBody headerBody) - { - List<String> list = new ArrayList<String>(); - BasicContentHeaderProperties headerProperties = (BasicContentHeaderProperties) headerBody.getProperties(); - list.add("reply-to = " + headerProperties.getReplyToAsString()); - list.add("propertyFlags = " + headerProperties.getPropertyFlags()); - list.add("ApplicationID = " + headerProperties.getAppIdAsString()); - list.add("ClusterID = " + headerProperties.getClusterIdAsString()); - list.add("UserId = " + headerProperties.getUserIdAsString()); - list.add("JMSMessageID = " + headerProperties.getMessageIdAsString()); - list.add("JMSCorrelationID = " + headerProperties.getCorrelationIdAsString()); - - int delMode = headerProperties.getDeliveryMode(); - list.add("JMSDeliveryMode = " + - ((delMode == BasicContentHeaderProperties.PERSISTENT) ? "Persistent" : "Non_Persistent")); - - list.add("JMSPriority = " + headerProperties.getPriority()); - list.add("JMSType = " + headerProperties.getType()); - - final long expirationDate = headerProperties.getExpiration(); - final long timestampDate = headerProperties.getTimestamp(); - - addStringifiedJMSTimestamoAndJMSExpiration(list, expirationDate, - timestampDate); - - return list.toArray(new String[list.size()]); - } - - private String[] getMessageTransferMessageHeaderProps(MessageTransferMessage msg) - { - List<String> list = new ArrayList<String>(); - - AMQMessageHeader header = msg.getMessageHeader(); - MessageProperties msgProps = msg.getHeader().getMessageProperties(); - - String appID = null; - String userID = null; - - if(msgProps != null) - { - appID = msgProps.getAppId() == null ? "null" : new String(msgProps.getAppId()); - userID = msgProps.getUserId() == null ? "null" : new String(msgProps.getUserId()); - } - - list.add("reply-to = " + header.getReplyTo()); - list.add("propertyFlags = "); //TODO - list.add("ApplicationID = " + appID); - list.add("ClusterID = "); //TODO - list.add("UserId = " + userID); - list.add("JMSMessageID = " + header.getMessageId()); - list.add("JMSCorrelationID = " + header.getCorrelationId()); - list.add("JMSDeliveryMode = " + (msg.isPersistent() ? "Persistent" : "Non_Persistent")); - list.add("JMSPriority = " + header.getPriority()); - list.add("JMSType = " + header.getType()); - - final long expirationDate = header.getExpiration(); - final long timestampDate = header.getTimestamp(); - addStringifiedJMSTimestamoAndJMSExpiration(list, expirationDate, timestampDate); - - return list.toArray(new String[list.size()]); - } - - private void addStringifiedJMSTimestamoAndJMSExpiration(final List<String> list, - final long expirationDate, final long timestampDate) - { - final String formattedExpirationDate = (expirationDate != 0) ? FAST_DATE_FORMAT.format(expirationDate) : null; - final String formattedTimestampDate = (timestampDate != 0) ? FAST_DATE_FORMAT.format(timestampDate) : null; - list.add("JMSExpiration = " + formattedExpirationDate); - list.add("JMSTimestamp = " + formattedTimestampDate); - } - - /** - * @see ManagedQueue#moveMessages - * @param fromMessageId - * @param toMessageId - * @param toQueueName - * @throws JMException - */ - public void moveMessages(long fromMessageId, long toMessageId, String toQueueName) throws JMException - { - if ((fromMessageId > toMessageId) || (fromMessageId < 1)) - { - throw new OperationsException("\"From MessageId\" should be greater than 0 and less than \"To MessageId\""); - } - - _queue.moveMessagesToAnotherQueue(fromMessageId, toMessageId, toQueueName); - } - - /** - * @see ManagedQueue#deleteMessages - * @param fromMessageId - * @param toMessageId - * @throws JMException - */ - public void deleteMessages(long fromMessageId, long toMessageId) throws JMException - { - if ((fromMessageId > toMessageId) || (fromMessageId < 1)) - { - throw new OperationsException("\"From MessageId\" should be greater than 0 and less than \"To MessageId\""); - } - - _queue.removeMessagesFromQueue(fromMessageId, toMessageId); - } - - /** - * @see ManagedQueue#copyMessages - * @param fromMessageId - * @param toMessageId - * @param toQueueName - * @throws JMException - */ - public void copyMessages(long fromMessageId, long toMessageId, String toQueueName) throws JMException - { - if ((fromMessageId > toMessageId) || (fromMessageId < 1)) - { - throw new OperationsException("\"From MessageId\" should be greater than 0 and less than \"To MessageId\""); - } - - _queue.copyMessagesToAnotherQueue(fromMessageId, toMessageId, toQueueName); - } - - /** - * returns Notifications sent by this MBean. - */ - @Override - public MBeanNotificationInfo[] getNotificationInfo() - { - String[] notificationTypes = new String[] { MonitorNotification.THRESHOLD_VALUE_EXCEEDED }; - String name = MonitorNotification.class.getName(); - String description = "Either Message count or Queue depth or Message size has reached threshold high value"; - MBeanNotificationInfo info1 = new MBeanNotificationInfo(notificationTypes, name, description); - - return new MBeanNotificationInfo[] { info1 }; - } - -} // End of AMQQueueMBean class diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DefaultQueueRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DefaultQueueRegistry.java index 2493974d45..27a9e13617 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DefaultQueueRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/DefaultQueueRegistry.java @@ -20,12 +20,10 @@ */ package org.apache.qpid.server.queue; -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.exchange.DefaultExchangeRegistry; import org.apache.qpid.server.virtualhost.VirtualHost; +import java.util.ArrayList; import java.util.Collection; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; @@ -33,11 +31,11 @@ import java.util.concurrent.ConcurrentMap; public class DefaultQueueRegistry implements QueueRegistry { - private static final Logger LOGGER = Logger.getLogger(DefaultExchangeRegistry.class); - private ConcurrentMap<AMQShortString, AMQQueue> _queueMap = new ConcurrentHashMap<AMQShortString, AMQQueue>(); private final VirtualHost _virtualHost; + private final Collection<RegistryChangeListener> _listeners = + new ArrayList<RegistryChangeListener>(); public DefaultQueueRegistry(VirtualHost virtualHost) { @@ -52,11 +50,28 @@ public class DefaultQueueRegistry implements QueueRegistry public void registerQueue(AMQQueue queue) { _queueMap.put(queue.getNameShortString(), queue); + synchronized (_listeners) + { + for(RegistryChangeListener listener : _listeners) + { + listener.queueRegistered(queue); + } + } } public void unregisterQueue(AMQShortString name) { - _queueMap.remove(name); + AMQQueue q = _queueMap.remove(name); + if(q != null) + { + synchronized (_listeners) + { + for(RegistryChangeListener listener : _listeners) + { + listener.queueUnregistered(q); + } + } + } } public AMQQueue getQueue(AMQShortString name) @@ -79,19 +94,30 @@ public class DefaultQueueRegistry implements QueueRegistry return getQueue(new AMQShortString(queue)); } + public void addRegistryChangeListener(RegistryChangeListener listener) + { + synchronized(_listeners) + { + _listeners.add(listener); + } + } + @Override public void stopAllAndUnregisterMBeans() { for (final AMQQueue queue : getQueues()) { queue.stop(); - try - { - queue.getManagedObject().unregister(); - } - catch (AMQException e) + + //TODO: this is a bit of a hack, what if the listeners aren't aware + //that we are just unregistering the MBean because of HA, and aren't + //actually removing the queue as such. + synchronized (_listeners) { - LOGGER.warn("Failed to unregister mbean", e); + for(RegistryChangeListener listener : _listeners) + { + listener.queueUnregistered(queue); + } } } _queueMap.clear(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java index c1ebbe412f..3efef9ab98 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/NotificationCheck.java @@ -20,6 +20,7 @@ */
package org.apache.qpid.server.queue;
+import org.apache.log4j.Logger;
import org.apache.qpid.server.message.ServerMessage;
public enum NotificationCheck
@@ -27,13 +28,16 @@ public enum NotificationCheck MESSAGE_COUNT_ALERT
{
- boolean notifyIfNecessary(ServerMessage msg, AMQQueue queue, QueueNotificationListener listener)
+ public boolean notifyIfNecessary(ServerMessage<?> msg, AMQQueue queue, AMQQueue.NotificationListener listener) {
int msgCount;
final long maximumMessageCount = queue.getMaximumMessageCount();
if (maximumMessageCount!= 0 && (msgCount = queue.getMessageCount()) >= maximumMessageCount)
{
- listener.notifyClients(this, queue, msgCount + ": Maximum count on queue threshold ("+ maximumMessageCount +") breached.");
+ String notificationMsg = msgCount + ": Maximum count on queue threshold ("+ maximumMessageCount +") breached.";
+
+ logNotification(this, queue, notificationMsg);
+ listener.notifyClients(this, queue, notificationMsg);
return true;
}
return false;
@@ -41,7 +45,7 @@ public enum NotificationCheck },
MESSAGE_SIZE_ALERT(true)
{
- boolean notifyIfNecessary(ServerMessage msg, AMQQueue queue, QueueNotificationListener listener)
+ public boolean notifyIfNecessary(ServerMessage<?> msg, AMQQueue queue, AMQQueue.NotificationListener listener) {
final long maximumMessageSize = queue.getMaximumMessageSize();
if(maximumMessageSize != 0)
@@ -50,10 +54,12 @@ public enum NotificationCheck long messageSize;
messageSize = (msg == null) ? 0 : msg.getSize();
-
if (messageSize >= maximumMessageSize)
{
- listener.notifyClients(this, queue, messageSize + "b : Maximum message size threshold ("+ maximumMessageSize +") breached. [Message ID=" + msg.getMessageNumber() + "]");
+ String notificationMsg = messageSize + "b : Maximum message size threshold ("+ maximumMessageSize +") breached. [Message ID=" + msg.getMessageNumber() + "]";
+
+ logNotification(this, queue, notificationMsg);
+ listener.notifyClients(this, queue, notificationMsg);
return true;
}
}
@@ -63,7 +69,7 @@ public enum NotificationCheck },
QUEUE_DEPTH_ALERT
{
- boolean notifyIfNecessary(ServerMessage msg, AMQQueue queue, QueueNotificationListener listener)
+ public boolean notifyIfNecessary(ServerMessage<?> msg, AMQQueue queue, AMQQueue.NotificationListener listener) {
// Check for threshold queue depth in bytes
final long maximumQueueDepth = queue.getMaximumQueueDepth();
@@ -74,7 +80,10 @@ public enum NotificationCheck if (queueDepth >= maximumQueueDepth)
{
- listener.notifyClients(this, queue, (queueDepth>>10) + "Kb : Maximum queue depth threshold ("+(maximumQueueDepth>>10)+"Kb) breached.");
+ String notificationMsg = (queueDepth>>10) + "Kb : Maximum queue depth threshold ("+(maximumQueueDepth>>10)+"Kb) breached.";
+
+ logNotification(this, queue, notificationMsg);
+ listener.notifyClients(this, queue, notificationMsg);
return true;
}
}
@@ -84,7 +93,7 @@ public enum NotificationCheck },
MESSAGE_AGE_ALERT
{
- boolean notifyIfNecessary(ServerMessage msg, AMQQueue queue, QueueNotificationListener listener)
+ public boolean notifyIfNecessary(ServerMessage<?> msg, AMQQueue queue, AMQQueue.NotificationListener listener) {
final long maxMessageAge = queue.getMaximumMessageAge();
@@ -97,7 +106,10 @@ public enum NotificationCheck if(firstArrivalTime < thresholdTime)
{
long oldestAge = currentTime - firstArrivalTime;
- listener.notifyClients(this, queue, (oldestAge/1000) + "s : Maximum age on queue threshold ("+(maxMessageAge /1000)+"s) breached.");
+ String notificationMsg = (oldestAge/1000) + "s : Maximum age on queue threshold ("+(maxMessageAge /1000)+"s) breached.";
+
+ logNotification(this, queue, notificationMsg);
+ listener.notifyClients(this, queue, notificationMsg);
return true;
}
@@ -109,6 +121,8 @@ public enum NotificationCheck }
;
+ private static final Logger LOGGER = Logger.getLogger(NotificationCheck.class);
+
private final boolean _messageSpecific;
NotificationCheck()
@@ -126,6 +140,11 @@ public enum NotificationCheck return _messageSpecific;
}
- abstract boolean notifyIfNecessary(ServerMessage msg, AMQQueue queue, QueueNotificationListener listener);
+ public abstract boolean notifyIfNecessary(ServerMessage<?> msg, AMQQueue queue, AMQQueue.NotificationListener listener); + //A bit of a hack, only for use until we do the logging listener
+ private static void logNotification(NotificationCheck notification, AMQQueue queue, String notificationMsg)
+ {
+ LOGGER.info(notification.name() + " On Queue " + queue.getNameShortString() + " - " + notificationMsg);
+ }
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java index 209553e8fa..25e771a9cf 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java @@ -233,7 +233,7 @@ public abstract class QueueEntryImpl implements QueueEntry if(state instanceof SubscriptionAcquiredState) { - getQueue().decrementUnackedMsgCount(); + getQueue().decrementUnackedMsgCount(this); Subscription subscription = ((SubscriptionAcquiredState)state).getSubscription(); if (subscription != null) { @@ -369,7 +369,7 @@ public abstract class QueueEntryImpl implements QueueEntry Subscription s = null; if (state instanceof SubscriptionAcquiredState) { - getQueue().decrementUnackedMsgCount(); + getQueue().decrementUnackedMsgCount(this); s = ((SubscriptionAcquiredState) state).getSubscription(); s.onDequeue(this); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRegistry.java index 72a54c9889..e8c34128e9 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRegistry.java @@ -42,7 +42,15 @@ public interface QueueRegistry AMQQueue getQueue(String queue); + void addRegistryChangeListener(RegistryChangeListener listener); + void stopAllAndUnregisterMBeans(); AMQQueue getQueue(UUID queueId); + + interface RegistryChangeListener + { + void queueRegistered(AMQQueue queue); + void queueUnregistered(AMQQueue queue); + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java index d7eb304c92..4e609af254 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java @@ -19,8 +19,10 @@ package org.apache.qpid.server.queue; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.EnumSet; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; @@ -32,8 +34,6 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; -import javax.management.JMException; - import org.apache.log4j.Logger; import org.apache.qpid.AMQException; import org.apache.qpid.AMQSecurityException; @@ -52,7 +52,6 @@ import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.logging.actors.QueueActor; import org.apache.qpid.server.logging.messages.QueueMessages; import org.apache.qpid.server.logging.subjects.QueueLogSubject; -import org.apache.qpid.server.management.ManagedObject; import org.apache.qpid.server.message.ServerMessage; import org.apache.qpid.server.protocol.AMQSessionModel; import org.apache.qpid.server.registry.ApplicationRegistry; @@ -70,6 +69,7 @@ import org.apache.qpid.server.virtualhost.VirtualHost; public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener, MessageGroupManager.SubscriptionResetHelper { private static final Logger _logger = Logger.getLogger(SimpleAMQQueue.class); + private static final String QPID_GROUP_HEADER_KEY = "qpid.group_header_key"; private static final String QPID_SHARED_MSG_GROUP = "qpid.shared_msg_group"; private static final String QPID_DEFAULT_MESSAGE_GROUP = "qpid.default-message-group"; @@ -77,11 +77,9 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener, Mes // TODO - should make this configurable at the vhost / broker level private static final int DEFAULT_MAX_GROUPS = 255; - private final VirtualHost _virtualHost; private final AMQShortString _name; - private final String _resourceName; /** null means shared */ private final AMQShortString _owner; @@ -118,6 +116,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener, Mes private final AtomicLong _dequeueCount = new AtomicLong(); private final AtomicLong _dequeueSize = new AtomicLong(); + private final AtomicLong _enqueueCount = new AtomicLong(); private final AtomicLong _enqueueSize = new AtomicLong(); private final AtomicLong _persistentMessageEnqueueSize = new AtomicLong(); private final AtomicLong _persistentMessageDequeueSize = new AtomicLong(); @@ -130,6 +129,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener, Mes private final AtomicLong _byteTxnDequeues = new AtomicLong(0); private final AtomicLong _unackedMsgCount = new AtomicLong(0); private final AtomicLong _unackedMsgCountHigh = new AtomicLong(0); + private final AtomicLong _unackedMsgBytes = new AtomicLong(); private final AtomicInteger _bindingCountHigh = new AtomicInteger(); @@ -173,7 +173,6 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener, Mes private LogSubject _logSubject; private LogActor _logActor; - private AMQQueueMBean _managedObject; private static final String SUB_FLUSH_RUNNER = "SUB_FLUSH_RUNNER"; private boolean _nolocal; @@ -191,6 +190,12 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener, Mes private int _maximumDeliveryCount = ApplicationRegistry.getInstance().getConfiguration().getMaxDeliveryCount(); private final MessageGroupManager _messageGroupManager; + private final Collection<SubscriptionRegistrationListener> _subscriptionListeners = + new ArrayList<SubscriptionRegistrationListener>(); + + private AMQQueue.NotificationListener _notificationListener; + private final long[] _lastNotificationTimes = new long[NotificationCheck.values().length]; + protected SimpleAMQQueue(UUID id, AMQShortString name, boolean durable, AMQShortString owner, boolean autoDelete, boolean exclusive, VirtualHost virtualHost, Map<String,Object> arguments) { this(id, name, durable, owner, autoDelete, exclusive,virtualHost, new SimpleQueueEntryList.Factory(), arguments); @@ -227,14 +232,13 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener, Mes } _name = name; - _resourceName = String.valueOf(name); _durable = durable; _owner = owner; _autoDelete = autoDelete; _exclusive = exclusive; _virtualHost = virtualHost; _entries = entryListFactory.createQueueEntryList(this); - _arguments = arguments; + _arguments = arguments == null ? new HashMap<String, Object>() : new HashMap<String, Object>(arguments); _id = id; @@ -255,16 +259,6 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener, Mes getConfigStore().addConfiguredObject(this); - try - { - _managedObject = new AMQQueueMBean(this); - _managedObject.register(); - } - catch (JMException e) - { - _logger.error("AMQQueue MBean creation has failed ", e); - } - if(arguments != null && arguments.containsKey(QPID_GROUP_HEADER_KEY)) { if(arguments.containsKey(QPID_SHARED_MSG_GROUP) && String.valueOf(arguments.get(QPID_SHARED_MSG_GROUP)).equals("1")) @@ -339,15 +333,10 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener, Mes { return _exclusive; } - - public void setExclusive(boolean exclusive) throws AMQException + + public void setExclusive(boolean exclusive) { _exclusive = exclusive; - - if(isDurable()) - { - getVirtualHost().getMessageStore().updateQueue(this); - } } public Exchange getAlternateExchange() @@ -368,22 +357,10 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener, Mes _alternateExchange = exchange; } - public void setAlternateExchange(String exchangeName) - { - if(exchangeName == null || exchangeName.equals("")) - { - _alternateExchange = null; - return; - } - - Exchange exchange = getVirtualHost().getExchangeRegistry().getExchange(new AMQShortString(exchangeName)); - if (exchange == null) - { - throw new RuntimeException("Exchange '" + exchangeName + "' is not registered with the VirtualHost."); - } - setAlternateExchange(exchange); - } - + /** + * Arguments used to create this queue. The caller is assured + * that null will never be returned. + */ public Map<String, Object> getArguments() { return _arguments; @@ -430,8 +407,8 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener, Mes { throw new AMQSecurityException("Permission denied"); } - - + + if (hasExclusiveSubscriber()) { throw new ExistingExclusiveSubscription(); @@ -463,15 +440,24 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener, Mes { subscription.setNoLocal(_nolocal); } + + synchronized (_subscriptionListeners) + { + for(SubscriptionRegistrationListener listener : _subscriptionListeners) + { + listener.subscriptionRegistered(this, subscription); + } + } + _subscriptionList.add(subscription); - + //Increment consumerCountHigh if necessary. (un)registerSubscription are both //synchronized methods so we don't need additional synchronization here if(_counsumerCountHigh.get() < getConsumerCount()) { _counsumerCountHigh.incrementAndGet(); } - + if (isDeleted()) { subscription.queueDeleted(this); @@ -507,6 +493,14 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener, Mes resetSubPointersForGroups(subscription, true); } + synchronized (_subscriptionListeners) + { + for(SubscriptionRegistrationListener listener : _subscriptionListeners) + { + listener.subscriptionUnregistered(this, subscription); + } + } + // auto-delete queues must be deleted if there are no remaining subscribers if (_autoDelete && getDeleteOnNoConsumers() && !subscription.isTransient() && getConsumerCount() == 0 ) @@ -526,6 +520,34 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener, Mes } + public Collection<Subscription> getConsumers() + { + List<Subscription> consumers = new ArrayList<Subscription>(); + SubscriptionList.SubscriptionNodeIterator iter = _subscriptionList.iterator(); + while(iter.advance()) + { + consumers.add(iter.getNode().getSubscription()); + } + return consumers; + + } + + public void addSubscriptionRegistrationListener(final SubscriptionRegistrationListener listener) + { + synchronized (_subscriptionListeners) + { + _subscriptionListeners.add(listener); + } + } + + public void removeSubscriptionRegistrationListener(final SubscriptionRegistrationListener listener) + { + synchronized (_subscriptionListeners) + { + _subscriptionListeners.remove(listener); + } + } + public void resetSubPointersForGroups(Subscription subscription, boolean clearAssignments) { QueueEntry entry = _messageGroupManager.findEarliestAssignedAvailableEntry(subscription); @@ -576,10 +598,10 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener, Mes break; } } - + reconfigure(); } - + private void reconfigure() { //Reconfigure the queue for to reflect this new binding. @@ -604,7 +626,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener, Mes public void removeBinding(final Binding binding) { _bindings.remove(binding); - + reconfigure(); } @@ -718,10 +740,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener, Mes } } - if(_managedObject != null) - { - _managedObject.checkForNotification(entry.getMessage()); - } + checkForNotification(entry.getMessage()); if(action != null) { @@ -738,8 +757,8 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener, Mes { try { - if (!sub.isSuspended() - && subscriptionReadyAndHasInterest(sub, entry) + if (!sub.isSuspended() + && subscriptionReadyAndHasInterest(sub, entry) && mightAssign(sub, entry) && !sub.wouldSuspend(entry)) { @@ -788,6 +807,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener, Mes { long size = message.getSize(); getAtomicQueueSize().addAndGet(size); + _enqueueCount.incrementAndGet(); _enqueueSize.addAndGet(size); if(message.isPersistent() && isDurable()) { @@ -796,19 +816,29 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener, Mes } } + public long getTotalDequeueCount() + { + return _dequeueCount.get(); + } + + public long getTotalEnqueueCount() + { + return _enqueueCount.get(); + } + private void incrementQueueCount() { getAtomicQueueCount().incrementAndGet(); } - + private void incrementTxnEnqueueStats(final ServerMessage message) { _msgTxnEnqueues.incrementAndGet(); _byteTxnEnqueues.addAndGet(message.getSize()); } - + private void incrementTxnDequeueStats(QueueEntry entry) - { + { _msgTxnDequeues.incrementAndGet(); _byteTxnDequeues.addAndGet(entry.getSize()); } @@ -819,7 +849,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener, Mes setLastSeenEntry(sub, entry); _deliveredMessages.incrementAndGet(); - incrementUnackedMsgCount(); + incrementUnackedMsgCount(entry); sub.send(entry, batch); } @@ -887,7 +917,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener, Mes { _deliveredMessages.decrementAndGet(); } - + if(sub != null && sub.isSessionTransactional()) { incrementTxnDequeueStats(entry); @@ -940,11 +970,13 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener, Mes } } + + public int getConsumerCount() { return _subscriptionList.size(); } - + public int getConsumerCountHigh() { return _counsumerCountHigh.get(); @@ -1148,7 +1180,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener, Mes } - public void visit(final Visitor visitor) + public void visit(final QueueEntryVisitor visitor) { QueueEntryIterator queueListIterator = _entries.iterator(); @@ -1411,7 +1443,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener, Mes } public long clearQueue() throws AMQException - { + { return clear(0l); } @@ -1422,7 +1454,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener, Mes { throw new AMQSecurityException("Permission denied: queue " + getName()); } - + QueueEntryIterator queueListIterator = _entries.iterator(); long count = 0; @@ -1489,7 +1521,7 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener, Mes { throw new AMQSecurityException("Permission denied: " + getName()); } - + if (!_deleted.getAndSet(true)) { @@ -1617,12 +1649,6 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener, Mes txn.commit(); - - if(_managedObject!=null) - { - _managedObject.unregister(); - } - for (Task task : _deleteTaskList) { task.doTask(this); @@ -2101,16 +2127,13 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener, Mes } else { - if (_managedObject != null) + // There is a chance that the node could be deleted by + // the time the check actually occurs. So verify we + // can actually get the message to perform the check. + ServerMessage msg = node.getMessage(); + if (msg != null) { - // There is a chance that the node could be deleted by - // the time the check actually occurs. So verify we - // can actually get the message to perform the check. - ServerMessage msg = node.getMessage(); - if (msg != null) - { - _managedObject.checkForNotification(msg); - } + checkForNotification(msg); } } } @@ -2235,11 +2258,6 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener, Mes return _notificationChecks; } - public ManagedObject getManagedObject() - { - return _managedObject; - } - private final class QueueEntryListener implements QueueEntry.StateChangeListener { @@ -2330,12 +2348,6 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener, Mes return _queueConfiguration; } - public String getResourceName() - { - return _resourceName; - } - - public ConfigStore getConfigStore() { return getVirtualHost().getConfigStore(); @@ -2355,22 +2367,22 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener, Mes { return _dequeueSize.get(); } - + public long getByteTxnEnqueues() { return _byteTxnEnqueues.get(); } - + public long getByteTxnDequeues() { return _byteTxnDequeues.get(); } - + public long getMsgTxnEnqueues() { return _msgTxnEnqueues.get(); } - + public long getMsgTxnDequeues() { return _msgTxnDequeues.get(); @@ -2407,21 +2419,28 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener, Mes { return _unackedMsgCountHigh.get(); } - + public long getUnackedMessageCount() { return _unackedMsgCount.get(); } - - public void decrementUnackedMsgCount() + + public long getUnackedMessageBytes() + { + return _unackedMsgBytes.get(); + } + + public void decrementUnackedMsgCount(QueueEntry queueEntry) { _unackedMsgCount.decrementAndGet(); + _unackedMsgBytes.addAndGet(-queueEntry.getSize()); } - - private void incrementUnackedMsgCount() + + private void incrementUnackedMsgCount(QueueEntry entry) { long unackedMsgCount = _unackedMsgCount.incrementAndGet(); - + _unackedMsgBytes.addAndGet(entry.getSize()); + long unackedMsgCountHigh; while(unackedMsgCount > (unackedMsgCountHigh = _unackedMsgCountHigh.get())) { @@ -2447,4 +2466,54 @@ public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener, Mes _maximumDeliveryCount = maximumDeliveryCount; } + /** + * Checks if there is any notification to send to the listeners + */ + private void checkForNotification(ServerMessage<?> msg) throws AMQException + { + final Set<NotificationCheck> notificationChecks = getNotificationChecks(); + final AMQQueue.NotificationListener listener = _notificationListener; + + if(listener != null && !notificationChecks.isEmpty()) + { + final long currentTime = System.currentTimeMillis(); + final long thresholdTime = currentTime - getMinimumAlertRepeatGap(); + + for (NotificationCheck check : notificationChecks) + { + if (check.isMessageSpecific() || (_lastNotificationTimes[check.ordinal()] < thresholdTime)) + { + if (check.notifyIfNecessary(msg, this, listener)) + { + _lastNotificationTimes[check.ordinal()] = currentTime; + } + } + } + } + } + + public void setNotificationListener(AMQQueue.NotificationListener listener) + { + _notificationListener = listener; + } + + @Override + public void setDescription(String description) + { + if (description == null) + { + _arguments.remove(AMQQueueFactory.X_QPID_DESCRIPTION); + } + else + { + _arguments.put(AMQQueueFactory.X_QPID_DESCRIPTION, description); + } + } + + @Override + public String getDescription() + { + return (String) _arguments.get(AMQQueueFactory.X_QPID_DESCRIPTION); + } + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java index 80a91be262..10c69b7f97 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java @@ -22,9 +22,9 @@ package org.apache.qpid.server.registry; import org.apache.commons.configuration.ConfigurationException; import org.apache.log4j.Logger; +import org.apache.qpid.server.logging.*; import org.osgi.framework.BundleContext; -import org.apache.qpid.AMQException; import org.apache.qpid.common.Closeable; import org.apache.qpid.common.QpidProperties; import org.apache.qpid.qmf.QMFService; @@ -35,18 +35,13 @@ import org.apache.qpid.server.configuration.ServerConfiguration; import org.apache.qpid.server.configuration.SystemConfig; import org.apache.qpid.server.configuration.SystemConfigImpl; import org.apache.qpid.server.configuration.VirtualHostConfiguration; -import org.apache.qpid.server.logging.CompositeStartupMessageLogger; -import org.apache.qpid.server.logging.Log4jMessageLogger; -import org.apache.qpid.server.logging.LogActor; -import org.apache.qpid.server.logging.RootMessageLogger; -import org.apache.qpid.server.logging.SystemOutMessageLogger; import org.apache.qpid.server.logging.actors.AbstractActor; import org.apache.qpid.server.logging.actors.BrokerActor; import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.logging.messages.BrokerMessages; import org.apache.qpid.server.logging.messages.VirtualHostMessages; -import org.apache.qpid.server.management.ManagedObjectRegistry; -import org.apache.qpid.server.management.NoopManagedObjectRegistry; +import org.apache.qpid.server.model.Broker; +import org.apache.qpid.server.model.adapter.BrokerAdapter; import org.apache.qpid.server.plugins.PluginManager; import org.apache.qpid.server.security.SecurityManager; import org.apache.qpid.server.security.auth.manager.AuthenticationManager; @@ -72,6 +67,7 @@ import java.util.concurrent.atomic.AtomicReference; */ public abstract class ApplicationRegistry implements IApplicationRegistry { + private static final Logger _logger = Logger.getLogger(ApplicationRegistry.class); private static AtomicReference<IApplicationRegistry> _instance = new AtomicReference<IApplicationRegistry>(null); @@ -81,11 +77,9 @@ public abstract class ApplicationRegistry implements IApplicationRegistry private final Map<InetSocketAddress, QpidAcceptor> _acceptors = Collections.synchronizedMap(new HashMap<InetSocketAddress, QpidAcceptor>()); - private ManagedObjectRegistry _managedObjectRegistry; - private IAuthenticationManagerRegistry _authenticationManagerRegistry; - private VirtualHostRegistry _virtualHostRegistry; + private final VirtualHostRegistry _virtualHostRegistry = new VirtualHostRegistry(this); private SecurityManager _securityManager; @@ -101,30 +95,32 @@ public abstract class ApplicationRegistry implements IApplicationRegistry private QMFService _qmfService; - private BrokerConfig _broker; + private BrokerConfig _brokerConfig; + + private Broker _broker; private ConfigStore _configStore; - + private Timer _reportingTimer; - private boolean _statisticsEnabled = false; private StatisticsCounter _messagesDelivered, _dataDelivered, _messagesReceived, _dataReceived; private BundleContext _bundleContext; + private final List<PortBindingListener> _portBindingListeners = new ArrayList<PortBindingListener>(); - protected Map<InetSocketAddress, QpidAcceptor> getAcceptors() - { - return _acceptors; - } + private int _httpManagementPort = -1; - protected void setManagedObjectRegistry(ManagedObjectRegistry managedObjectRegistry) - { - _managedObjectRegistry = managedObjectRegistry; - } + private LogRecorder _logRecorder; + + private List<IAuthenticationManagerRegistry.RegistryChangeListener> _authManagerChangeListeners = + new ArrayList<IAuthenticationManagerRegistry.RegistryChangeListener>(); - protected void setVirtualHostRegistry(VirtualHostRegistry virtualHostRegistry) + public Map<InetSocketAddress, QpidAcceptor> getAcceptors() { - _virtualHostRegistry = virtualHostRegistry; + synchronized (_acceptors) + { + return new HashMap<InetSocketAddress, QpidAcceptor>(_acceptors); + } } protected void setSecurityManager(SecurityManager securityManager) @@ -191,11 +187,11 @@ public abstract class ApplicationRegistry implements IApplicationRegistry store.setRoot(new SystemConfigImpl(store)); instance.setConfigStore(store); - BrokerConfig broker = new BrokerConfigAdapter(instance); + final BrokerConfig brokerConfig = new BrokerConfigAdapter(instance); - SystemConfig system = store.getRoot(); - system.addBroker(broker); - instance.setBroker(broker); + final SystemConfig system = store.getRoot(); + system.addBroker(brokerConfig); + instance.setBrokerConfig(brokerConfig); try { @@ -208,7 +204,7 @@ public abstract class ApplicationRegistry implements IApplicationRegistry //remove the Broker instance, then re-throw try { - system.removeBroker(broker); + system.removeBroker(brokerConfig); } catch(Throwable t) { @@ -283,18 +279,28 @@ public abstract class ApplicationRegistry implements IApplicationRegistry public void initialise() throws Exception { + _logRecorder = new LogRecorder(); //Create the RootLogger to be used during broker operation _rootMessageLogger = new Log4jMessageLogger(_configuration); //Create the composite (log4j+SystemOut MessageLogger to be used during startup RootMessageLogger[] messageLoggers = {new SystemOutMessageLogger(), _rootMessageLogger}; _startupMessageLogger = new CompositeStartupMessageLogger(messageLoggers); - - CurrentActor.set(new BrokerActor(_startupMessageLogger)); + + BrokerActor actor = new BrokerActor(_startupMessageLogger); + CurrentActor.setDefault(actor); + CurrentActor.set(actor); try { - initialiseManagedObjectRegistry(); + initialiseStatistics(); + + if(_configuration.getHTTPManagementEnabled()) + { + _httpManagementPort = _configuration.getHTTPManagementPort(); + } + + _broker = new BrokerAdapter(this); configure(); @@ -302,13 +308,23 @@ public abstract class ApplicationRegistry implements IApplicationRegistry logStartupMessages(CurrentActor.get()); - _virtualHostRegistry = new VirtualHostRegistry(this); - _securityManager = new SecurityManager(_configuration, _pluginManager); _authenticationManagerRegistry = createAuthenticationManagerRegistry(_configuration, _pluginManager); - _managedObjectRegistry.start(); + if(!_authManagerChangeListeners.isEmpty()) + { + for(IAuthenticationManagerRegistry.RegistryChangeListener listener : _authManagerChangeListeners) + { + + _authenticationManagerRegistry.addRegistryChangeListener(listener); + for(AuthenticationManager authMgr : _authenticationManagerRegistry.getAvailableAuthenticationManagers().values()) + { + listener.authenticationManagerRegistered(authMgr); + } + } + _authManagerChangeListeners.clear(); + } } finally { @@ -319,7 +335,6 @@ public abstract class ApplicationRegistry implements IApplicationRegistry try { initialiseVirtualHosts(); - initialiseStatistics(); initialiseStatisticsReporting(); } finally @@ -344,23 +359,18 @@ public abstract class ApplicationRegistry implements IApplicationRegistry getVirtualHostRegistry().setDefaultVirtualHostName(_configuration.getDefaultVirtualHost()); } - protected void initialiseManagedObjectRegistry() throws AMQException - { - _managedObjectRegistry = new NoopManagedObjectRegistry(); - } - public void initialiseStatisticsReporting() { long report = _configuration.getStatisticsReportingPeriod() * 1000; // convert to ms final boolean broker = _configuration.isStatisticsGenerationBrokerEnabled(); final boolean virtualhost = _configuration.isStatisticsGenerationVirtualhostsEnabled(); final boolean reset = _configuration.isStatisticsReportResetEnabled(); - + /* add a timer task to report statistics if generation is enabled for broker or virtualhosts */ if (report > 0L && (broker || virtualhost)) { _reportingTimer = new Timer("Statistics-Reporting", true); - + _reportingTimer.scheduleAtFixedRate(new StatisticsReportingTask(broker, virtualhost, reset), @@ -495,9 +505,7 @@ public abstract class ApplicationRegistry implements IApplicationRegistry close(_pluginManager); - close(_managedObjectRegistry); - - BrokerConfig broker = getBroker(); + BrokerConfig broker = getBrokerConfig(); if(broker != null) { broker.getSystem().removeBroker(broker); @@ -513,12 +521,14 @@ public abstract class ApplicationRegistry implements IApplicationRegistry private void unbind() { + List<QpidAcceptor> removedAcceptors = new ArrayList<QpidAcceptor>(); synchronized (_acceptors) { for (InetSocketAddress bindAddress : _acceptors.keySet()) { QpidAcceptor acceptor = _acceptors.get(bindAddress); + removedAcceptors.add(acceptor); try { acceptor.getNetworkTransport().close(); @@ -531,6 +541,16 @@ public abstract class ApplicationRegistry implements IApplicationRegistry CurrentActor.get().message(BrokerMessages.SHUTTING_DOWN(acceptor.toString(), bindAddress.getPort())); } } + synchronized (_portBindingListeners) + { + for(QpidAcceptor acceptor : removedAcceptors) + { + for(PortBindingListener listener : _portBindingListeners) + { + listener.unbound(acceptor); + } + } + } } public ServerConfiguration getConfiguration() @@ -544,6 +564,13 @@ public abstract class ApplicationRegistry implements IApplicationRegistry { _acceptors.put(bindAddress, acceptor); } + synchronized (_portBindingListeners) + { + for(PortBindingListener listener : _portBindingListeners) + { + listener.bound(acceptor, bindAddress); + } + } } public VirtualHostRegistry getVirtualHostRegistry() @@ -556,15 +583,16 @@ public abstract class ApplicationRegistry implements IApplicationRegistry return _securityManager; } - public ManagedObjectRegistry getManagedObjectRegistry() + @Override + public AuthenticationManager getAuthenticationManager(SocketAddress address) { - return _managedObjectRegistry; + return _authenticationManagerRegistry.getAuthenticationManager(address); } @Override - public AuthenticationManager getAuthenticationManager(SocketAddress address) + public IAuthenticationManagerRegistry getAuthenticationManagerRegistry() { - return _authenticationManagerRegistry.getAuthenticationManager(address); + return _authenticationManagerRegistry; } public PluginManager getPluginManager() @@ -581,7 +609,7 @@ public abstract class ApplicationRegistry implements IApplicationRegistry { return _rootMessageLogger; } - + public RootMessageLogger getCompositeStartupMessageLogger() { return _startupMessageLogger; @@ -597,69 +625,63 @@ public abstract class ApplicationRegistry implements IApplicationRegistry return _qmfService; } - public BrokerConfig getBroker() + public BrokerConfig getBrokerConfig() { - return _broker; + return _brokerConfig; } - public void setBroker(final BrokerConfig broker) + public void setBrokerConfig(final BrokerConfig broker) { - _broker = broker; + _brokerConfig = broker; } public VirtualHost createVirtualHost(final VirtualHostConfiguration vhostConfig) throws Exception { VirtualHostImpl virtualHost = new VirtualHostImpl(this, vhostConfig); _virtualHostRegistry.registerVirtualHost(virtualHost); - getBroker().addVirtualHost(virtualHost); + getBrokerConfig().addVirtualHost(virtualHost); return virtualHost; } - + public void registerMessageDelivered(long messageSize) { - if (isStatisticsEnabled()) - { - _messagesDelivered.registerEvent(1L); - _dataDelivered.registerEvent(messageSize); - } + _messagesDelivered.registerEvent(1L); + _dataDelivered.registerEvent(messageSize); } - + public void registerMessageReceived(long messageSize, long timestamp) { - if (isStatisticsEnabled()) - { - _messagesReceived.registerEvent(1L, timestamp); - _dataReceived.registerEvent(messageSize, timestamp); - } + _messagesReceived.registerEvent(1L, timestamp); + _dataReceived.registerEvent(messageSize, timestamp); } - + public StatisticsCounter getMessageReceiptStatistics() { return _messagesReceived; } - + public StatisticsCounter getDataReceiptStatistics() { return _dataReceived; } - + public StatisticsCounter getMessageDeliveryStatistics() { return _messagesDelivered; } - + public StatisticsCounter getDataDeliveryStatistics() { return _dataDelivered; } - + public void resetStatistics() { _messagesDelivered.reset(); _dataDelivered.reset(); _messagesReceived.reset(); _dataReceived.reset(); - + for (VirtualHost vhost : _virtualHostRegistry.getVirtualHosts()) { vhost.resetStatistics(); @@ -668,25 +690,12 @@ public abstract class ApplicationRegistry implements IApplicationRegistry public void initialiseStatistics() { - setStatisticsEnabled(!StatisticsCounter.DISABLE_STATISTICS && - getConfiguration().isStatisticsGenerationBrokerEnabled()); - _messagesDelivered = new StatisticsCounter("messages-delivered"); _dataDelivered = new StatisticsCounter("bytes-delivered"); _messagesReceived = new StatisticsCounter("messages-received"); _dataReceived = new StatisticsCounter("bytes-received"); } - public boolean isStatisticsEnabled() - { - return _statisticsEnabled; - } - - public void setStatisticsEnabled(boolean enabled) - { - _statisticsEnabled = enabled; - } - private void logStartupMessages(LogActor logActor) { logActor.message(BrokerMessages.STARTUP(QpidProperties.getReleaseVersion(), QpidProperties.getBuildVersion())); @@ -700,4 +709,48 @@ public abstract class ApplicationRegistry implements IApplicationRegistry logActor.message(BrokerMessages.MAX_MEMORY(Runtime.getRuntime().maxMemory())); } + public Broker getBroker() + { + return _broker; + } + + @Override + public void addPortBindingListener(PortBindingListener listener) + { + synchronized (_portBindingListeners) + { + _portBindingListeners.add(listener); + } + } + + + @Override + public boolean useHTTPManagement() + { + return _httpManagementPort != -1; + } + + @Override + public int getHTTPManagementPort() + { + return _httpManagementPort; + } + + public LogRecorder getLogRecorder() + { + return _logRecorder; + } + + @Override + public void addRegistryChangeListener(IAuthenticationManagerRegistry.RegistryChangeListener registryChangeListener) + { + if(_authenticationManagerRegistry == null) + { + _authManagerChangeListeners.add(registryChangeListener); + } + else + { + _authenticationManagerRegistry.addRegistryChangeListener(registryChangeListener); + } + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java index b28e3d6c89..774d0338ef 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ConfigurationFileApplicationRegistry.java @@ -25,8 +25,6 @@ import org.osgi.framework.BundleContext; import org.apache.qpid.AMQException; import org.apache.qpid.server.configuration.ServerConfiguration; -import org.apache.qpid.server.management.JMXManagedObjectRegistry; -import org.apache.qpid.server.management.NoopManagedObjectRegistry; import java.io.File; @@ -41,18 +39,4 @@ public class ConfigurationFileApplicationRegistry extends ApplicationRegistry { super(new ServerConfiguration(configurationURL), bundleContext); } - - @Override - protected void initialiseManagedObjectRegistry() throws AMQException - { - if (getConfiguration().getManagementEnabled()) - { - setManagedObjectRegistry(new JMXManagedObjectRegistry()); - } - else - { - setManagedObjectRegistry(new NoopManagedObjectRegistry()); - } - } - } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java index 35e7fe3f61..2baf7ed5ee 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java @@ -27,10 +27,11 @@ import org.apache.qpid.server.configuration.ConfigurationManager; import org.apache.qpid.server.configuration.ServerConfiguration; import org.apache.qpid.server.configuration.VirtualHostConfiguration; import org.apache.qpid.server.logging.RootMessageLogger; -import org.apache.qpid.server.management.ManagedObjectRegistry; +import org.apache.qpid.server.model.Broker; import org.apache.qpid.server.plugins.PluginManager; import org.apache.qpid.server.security.SecurityManager; import org.apache.qpid.server.security.auth.manager.AuthenticationManager; +import org.apache.qpid.server.security.auth.manager.IAuthenticationManagerRegistry; import org.apache.qpid.server.stats.StatisticsGatherer; import org.apache.qpid.server.transport.QpidAcceptor; import org.apache.qpid.server.virtualhost.VirtualHost; @@ -38,6 +39,7 @@ import org.apache.qpid.server.virtualhost.VirtualHostRegistry; import java.net.InetSocketAddress; import java.net.SocketAddress; +import java.util.Map; import java.util.UUID; public interface IApplicationRegistry extends StatisticsGatherer @@ -61,8 +63,6 @@ public interface IApplicationRegistry extends StatisticsGatherer */ ServerConfiguration getConfiguration(); - ManagedObjectRegistry getManagedObjectRegistry(); - /** * Get the AuthenticationManager for the given socket address * @@ -74,6 +74,8 @@ public interface IApplicationRegistry extends StatisticsGatherer */ AuthenticationManager getAuthenticationManager(SocketAddress address); + IAuthenticationManagerRegistry getAuthenticationManagerRegistry(); + VirtualHostRegistry getVirtualHostRegistry(); SecurityManager getSecurityManager(); @@ -95,15 +97,35 @@ public interface IApplicationRegistry extends StatisticsGatherer QMFService getQMFService(); - void setBroker(BrokerConfig broker); + void setBrokerConfig(BrokerConfig broker); + + BrokerConfig getBrokerConfig(); - BrokerConfig getBroker(); + Broker getBroker(); VirtualHost createVirtualHost(VirtualHostConfiguration vhostConfig) throws Exception; ConfigStore getConfigStore(); void setConfigStore(ConfigStore store); - + void initialiseStatisticsReporting(); + + Map<InetSocketAddress, QpidAcceptor> getAcceptors(); + + void addPortBindingListener(PortBindingListener listener); + + boolean useHTTPManagement(); + + int getHTTPManagementPort(); + + void addRegistryChangeListener(IAuthenticationManagerRegistry.RegistryChangeListener registryChangeListener); + + public interface PortBindingListener + { + public void bound(QpidAcceptor acceptor, InetSocketAddress bindAddress); + public void unbound(QpidAcceptor acceptor); + + } + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/AbstractPasswordFilePrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/AbstractPasswordFilePrincipalDatabase.java index 7088fae50c..cac60a5283 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/AbstractPasswordFilePrincipalDatabase.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/AbstractPasswordFilePrincipalDatabase.java @@ -198,7 +198,7 @@ public abstract class AbstractPasswordFilePrincipalDatabase<U extends PasswordPr try { _userUpdate.lock(); - _userMap.clear(); + final Map<String, U> newUserMap = new HashMap<String, U>(); BufferedReader reader = null; try @@ -216,7 +216,7 @@ public abstract class AbstractPasswordFilePrincipalDatabase<U extends PasswordPr U user = createUserFromFileData(result); getLogger().info("Created user:" + user); - _userMap.put(user.getName(), user); + newUserMap.put(user.getName(), user); } } finally @@ -226,6 +226,9 @@ public abstract class AbstractPasswordFilePrincipalDatabase<U extends PasswordPr reader.close(); } } + + _userMap.clear(); + _userMap.putAll(newUserMap); } finally { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AnonymousAuthenticationManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AnonymousAuthenticationManager.java index 0eb3963865..5676c43754 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AnonymousAuthenticationManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AnonymousAuthenticationManager.java @@ -47,7 +47,7 @@ public class AnonymousAuthenticationManager implements AuthenticationManager private static final Principal ANONYMOUS_PRINCIPAL = new UsernamePrincipal("ANONYMOUS"); - private static final Subject ANONYMOUS_SUBJECT = new Subject(); + public static final Subject ANONYMOUS_SUBJECT = new Subject(); static { ANONYMOUS_SUBJECT.getPrincipals().add(ANONYMOUS_PRINCIPAL); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManagerRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManagerRegistry.java index 3a1ca4f19d..89a4d8ae66 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManagerRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManagerRegistry.java @@ -21,9 +21,12 @@ package org.apache.qpid.server.security.auth.manager; import java.net.InetSocketAddress; import java.net.SocketAddress; +import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.Iterator; +import java.util.List; import java.util.Map; import org.apache.commons.configuration.ConfigurationException; @@ -49,6 +52,8 @@ public class AuthenticationManagerRegistry implements Closeable, IAuthentication private final Map<String,AuthenticationManager> _classToAuthManagerMap = new HashMap<String,AuthenticationManager>(); private final AuthenticationManager _defaultAuthenticationManager; private final Map<Integer,AuthenticationManager> _portToAuthenticationManagerMap; + private final List<RegistryChangeListener> _listeners = + Collections.synchronizedList(new ArrayList<RegistryChangeListener>()); public AuthenticationManagerRegistry(ServerConfiguration serverConfiguration, PluginManager _pluginManager) throws ConfigurationException @@ -114,9 +119,8 @@ public class AuthenticationManagerRegistry implements Closeable, IAuthentication final SecurityConfiguration securityConfiguration) throws ConfigurationException { - for (final Iterator<AuthenticationManagerPluginFactory<? extends Plugin>> iterator = factories.iterator(); iterator.hasNext();) + for(AuthenticationManagerPluginFactory<? extends Plugin> factory : factories) { - final AuthenticationManagerPluginFactory<? extends Plugin> factory = (AuthenticationManagerPluginFactory<? extends Plugin>) iterator.next(); final AuthenticationManager tmp = factory.newInstance(securityConfiguration); if (tmp != null) { @@ -127,6 +131,11 @@ public class AuthenticationManagerRegistry implements Closeable, IAuthentication + " Remove configuration for one of the authentication managers."); } _classToAuthManagerMap.put(tmp.getClass().getSimpleName(),tmp); + + for(RegistryChangeListener listener : _listeners) + { + listener.authenticationManagerRegistered(tmp); + } } } } @@ -179,5 +188,16 @@ public class AuthenticationManagerRegistry implements Closeable, IAuthentication return portToAuthenticationManagerMap; } + @Override + public Map<String, AuthenticationManager> getAvailableAuthenticationManagers() + { + return Collections.unmodifiableMap(new HashMap<String, AuthenticationManager>(_classToAuthManagerMap)); + } + + @Override + public void addRegistryChangeListener(RegistryChangeListener listener) + { + _listeners.add(listener); + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/IAuthenticationManagerRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/IAuthenticationManagerRegistry.java index bfb49b8ed6..485ca2e1e9 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/IAuthenticationManagerRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/IAuthenticationManagerRegistry.java @@ -21,7 +21,9 @@ package org.apache.qpid.server.security.auth.manager; import java.net.SocketAddress; +import java.util.Map; import org.apache.qpid.common.Closeable; +import org.apache.qpid.server.virtualhost.VirtualHost; /** * Registry for {@link AuthenticationManager} instances. @@ -43,4 +45,15 @@ public interface IAuthenticationManagerRegistry extends Closeable * @return authentication manager. */ public AuthenticationManager getAuthenticationManager(SocketAddress address); + + Map<String, AuthenticationManager> getAvailableAuthenticationManagers(); + + public static interface RegistryChangeListener + { + void authenticationManagerRegistered(AuthenticationManager authenticationManager); + void authenticationManagerUnregistered(AuthenticationManager authenticationManager); + } + + public void addRegistryChangeListener(RegistryChangeListener listener); + }
\ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java index 24b365d34c..e6498919a1 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java @@ -32,7 +32,6 @@ import org.apache.qpid.server.configuration.plugins.ConfigurationPluginFactory; import org.apache.qpid.server.security.auth.AuthenticationResult; import org.apache.qpid.server.security.auth.AuthenticationResult.AuthenticationStatus; import org.apache.qpid.server.security.auth.database.PrincipalDatabase; -import org.apache.qpid.server.security.auth.management.AMQUserManagementMBean; import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser; import org.apache.qpid.server.security.auth.sasl.JCAProvider; import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; @@ -98,8 +97,6 @@ public class PrincipalDatabaseAuthenticationManager implements AuthenticationMan private PrincipalDatabase _principalDatabase = null; - private AMQUserManagementMBean _mbean = null; - public static final AuthenticationManagerPluginFactory<PrincipalDatabaseAuthenticationManager> FACTORY = new AuthenticationManagerPluginFactory<PrincipalDatabaseAuthenticationManager>() { public PrincipalDatabaseAuthenticationManager newInstance(final ConfigurationPlugin config) throws ConfigurationException @@ -211,8 +208,6 @@ public class PrincipalDatabaseAuthenticationManager implements AuthenticationMan { _logger.warn("No additional SASL providers registered."); } - - registerManagement(); } private void initialiseAuthenticationMechanisms(Map<String, Class<? extends SaslServerFactory>> providerMap, PrincipalDatabase database) @@ -332,8 +327,6 @@ public class PrincipalDatabaseAuthenticationManager implements AuthenticationMan { _mechanisms = null; Security.removeProvider(PROVIDER_NAME); - - unregisterManagement(); } private PrincipalDatabase createPrincipalDatabaseImpl(final String pdClazz) throws ConfigurationException @@ -407,6 +400,11 @@ public class PrincipalDatabaseAuthenticationManager implements AuthenticationMan } } + public PrincipalDatabase getPrincipalDatabase() + { + return _principalDatabase; + } + private String generateSetterName(String argName) throws ConfigurationException { if ((argName == null) || (argName.length() == 0)) @@ -427,41 +425,4 @@ public class PrincipalDatabaseAuthenticationManager implements AuthenticationMan { _principalDatabase = principalDatabase; } - - protected void registerManagement() - { - try - { - _logger.info("Registering UserManagementMBean"); - - _mbean = new AMQUserManagementMBean(); - _mbean.setPrincipalDatabase(_principalDatabase); - _mbean.register(); - } - catch (Exception e) - { - _logger.warn("User management disabled as unable to create MBean:", e); - _mbean = null; - } - } - - protected void unregisterManagement() - { - try - { - if (_mbean != null) - { - _logger.info("Unregistering UserManagementMBean"); - _mbean.unregister(); - } - } - catch (Exception e) - { - _logger.warn("Failed to unregister User management MBean:", e); - } - finally - { - _mbean = null; - } - } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticator.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticator.java index e27fd99f90..2e21cfbb07 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticator.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticator.java @@ -20,6 +20,9 @@ */ package org.apache.qpid.server.security.auth.rmi; +import java.net.SocketAddress; + +import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.security.auth.AuthenticationResult; import org.apache.qpid.server.security.auth.AuthenticationResult.AuthenticationStatus; import org.apache.qpid.server.security.auth.manager.AuthenticationManager; @@ -37,11 +40,13 @@ public class RMIPasswordAuthenticator implements JMXAuthenticator static final String INVALID_CREDENTIALS = "Invalid user details supplied"; static final String CREDENTIALS_REQUIRED = "User details are required. " + "Please ensure you are using an up to date management console to connect."; - + private AuthenticationManager _authenticationManager = null; + private SocketAddress _socketAddress; - public RMIPasswordAuthenticator() + public RMIPasswordAuthenticator(SocketAddress socketAddress) { + _socketAddress = socketAddress; } public void setAuthenticationManager(final AuthenticationManager authenticationManager) @@ -79,11 +84,25 @@ public class RMIPasswordAuthenticator implements JMXAuthenticator { throw new SecurityException(SHOULD_BE_NON_NULL); } - + // Verify that an AuthenticationManager has been set. if (_authenticationManager == null) { - throw new SecurityException(UNABLE_TO_LOOKUP); + try + { + if(ApplicationRegistry.getInstance().getAuthenticationManager(_socketAddress) != null) + { + _authenticationManager = ApplicationRegistry.getInstance().getAuthenticationManager(_socketAddress); + } + else + { + throw new SecurityException(UNABLE_TO_LOOKUP); + } + } + catch(IllegalStateException e) + { + throw new SecurityException(UNABLE_TO_LOOKUP); + } } final AuthenticationResult result = _authenticationManager.authenticate(username, password); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/stats/StatisticsCounter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/stats/StatisticsCounter.java index 2bd17cfa2f..f382f90010 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/stats/StatisticsCounter.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/stats/StatisticsCounter.java @@ -33,8 +33,7 @@ public class StatisticsCounter private static final Logger _log = LoggerFactory.getLogger(StatisticsCounter.class); public static final long DEFAULT_SAMPLE_PERIOD = Long.getLong("qpid.statistics.samplePeriod", 2000L); // 2s - public static final boolean DISABLE_STATISTICS = Boolean.getBoolean("qpid.statistics.disable"); - + private static final String COUNTER = "counter"; private static final AtomicLong _counterIds = new AtomicLong(0L); @@ -78,11 +77,6 @@ public class StatisticsCounter public void registerEvent(long value, long timestamp) { - if (DISABLE_STATISTICS) - { - return; - } - long thisSample = (timestamp / _period); synchronized (this) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/stats/StatisticsGatherer.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/stats/StatisticsGatherer.java index 36fec4025a..37d87bb628 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/stats/StatisticsGatherer.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/stats/StatisticsGatherer.java @@ -103,16 +103,4 @@ public interface StatisticsGatherer * Reset the counters for this, and any child {@link StatisticsGatherer}s. */ void resetStatistics(); - - /** - * Check if this object has statistics generation enabled. - * - * @return true if statistics generation is enabled - */ - boolean isStatisticsEnabled(); - - /** - * Enable or disable statistics generation for this object. - */ - void setStatisticsEnabled(boolean enabled); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/ConfigurationRecoveryHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/ConfigurationRecoveryHandler.java index 1307b1dbd4..f1053f60ad 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/ConfigurationRecoveryHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/ConfigurationRecoveryHandler.java @@ -32,7 +32,7 @@ public interface ConfigurationRecoveryHandler public static interface QueueRecoveryHandler { - void queue(UUID id, String queueName, String owner, boolean exclusive, FieldTable arguments); + void queue(UUID id, String queueName, String owner, boolean exclusive, FieldTable arguments, UUID alternateExchangeId); ExchangeRecoveryHandler completeQueueRecovery(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/ConfiguredObjectHelper.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/ConfiguredObjectHelper.java index 1a67fdf540..7356e1ae83 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/ConfiguredObjectHelper.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/ConfiguredObjectHelper.java @@ -40,12 +40,7 @@ import org.apache.qpid.server.util.MapJsonSerializer; public class ConfiguredObjectHelper { - /** - * Name of queue attribute to store queue creation arguments. - * <p> - * This attribute is not defined yet on Queue configured object interface. - */ - private static final String QUEUE_ARGUMENTS = "ARGUMENTS"; + private MapJsonSerializer _serializer = new MapJsonSerializer(); @@ -57,14 +52,15 @@ public class ConfiguredObjectHelper String queueName = (String) attributeMap.get(Queue.NAME); String owner = (String) attributeMap.get(Queue.OWNER); boolean exclusive = (Boolean) attributeMap.get(Queue.EXCLUSIVE); + UUID alternateExchangeId = attributeMap.get(Queue.ALTERNATE_EXCHANGE) == null ? null : UUID.fromString((String)attributeMap.get(Queue.ALTERNATE_EXCHANGE)); @SuppressWarnings("unchecked") - Map<String, Object> queueArgumentsMap = (Map<String, Object>) attributeMap.get(QUEUE_ARGUMENTS); + Map<String, Object> queueArgumentsMap = (Map<String, Object>) attributeMap.get(Queue.ARGUMENTS); FieldTable arguments = null; if (queueArgumentsMap != null) { arguments = FieldTable.convertToFieldTable(queueArgumentsMap); } - qrh.queue(configuredObject.getId(), queueName, owner, exclusive, arguments); + qrh.queue(configuredObject.getId(), queueName, owner, exclusive, arguments, alternateExchangeId); } } @@ -73,6 +69,24 @@ public class ConfiguredObjectHelper Map<String, Object> attributesMap = _serializer.deserialize(queueRecord.getAttributes()); attributesMap.put(Queue.NAME, queue.getName()); attributesMap.put(Queue.EXCLUSIVE, queue.isExclusive()); + if (queue.getAlternateExchange() != null) + { + attributesMap.put(Queue.ALTERNATE_EXCHANGE, queue.getAlternateExchange().getId()); + } + else + { + attributesMap.remove(Queue.ALTERNATE_EXCHANGE); + } + if (attributesMap.containsKey(Queue.ARGUMENTS)) + { + // We wouldn't need this if createQueueConfiguredObject took only AMQQueue + Map<String, Object> currentArgs = (Map<String, Object>) attributesMap.get(Queue.ARGUMENTS); + currentArgs.putAll(queue.getArguments()); + } + else + { + attributesMap.put(Queue.ARGUMENTS, queue.getArguments()); + } String newJson = _serializer.serialize(attributesMap); ConfiguredObjectRecord newQueueRecord = new ConfiguredObjectRecord(queue.getId(), queueRecord.getType(), newJson); return newQueueRecord; @@ -84,9 +98,15 @@ public class ConfiguredObjectHelper attributesMap.put(Queue.NAME, queue.getName()); attributesMap.put(Queue.OWNER, AMQShortString.toString(queue.getOwner())); attributesMap.put(Queue.EXCLUSIVE, queue.isExclusive()); + if (queue.getAlternateExchange() != null) + { + attributesMap.put(Queue.ALTERNATE_EXCHANGE, queue.getAlternateExchange().getId()); + } + // TODO KW i think the arguments could come from the queue itself removing the need for the parameter arguments. + // It would also do away with the need for the if/then/else within updateQueueConfiguredObject if (arguments != null) { - attributesMap.put(QUEUE_ARGUMENTS, FieldTable.convertToMap(arguments)); + attributesMap.put(Queue.ARGUMENTS, FieldTable.convertToMap(arguments)); } String json = _serializer.serialize(attributesMap); ConfiguredObjectRecord configuredObject = new ConfiguredObjectRecord(queue.getId(), Queue.class.getName(), json); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java index 7b98b30860..262d7d0213 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java @@ -134,4 +134,10 @@ public class MemoryMessageStore extends NullMessageStore { _eventManager.addEventListener(eventListener, events); } + + @Override + public String getStoreType() + { + return "Memory"; + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java index cf08ee00ff..0acaf164d9 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java @@ -67,4 +67,6 @@ public interface MessageStore extends DurableConfigurationStore void addEventListener(EventListener eventListener, Event... events); String getStoreLocation(); + + String getStoreType(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/NullMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/NullMessageStore.java index 34c7d2d933..be08e309e6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/NullMessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/NullMessageStore.java @@ -28,7 +28,7 @@ import org.apache.qpid.server.federation.Bridge; import org.apache.qpid.server.federation.BrokerLink; import org.apache.qpid.server.queue.AMQQueue; -public class NullMessageStore implements MessageStore +public abstract class NullMessageStore implements MessageStore { @Override public void configureConfigStore(String name, diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/derby/DerbyMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/derby/DerbyMessageStore.java index c065eb263b..ab374b4917 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/derby/DerbyMessageStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/derby/DerbyMessageStore.java @@ -232,6 +232,8 @@ public class DerbyMessageStore implements MessageStore private static final String DERBY_SINGLE_DB_SHUTDOWN_CODE = "08006"; + private static final String DERBY_STORE_TYPE = "DERBY"; + private final StateManager _stateManager; private final EventManager _eventManager = new EventManager(); @@ -2651,4 +2653,11 @@ public class DerbyMessageStore implements MessageStore { return _persistentSizeHighThreshold; } + + @Override + public String getStoreType() + { + return DERBY_STORE_TYPE; + } + }
\ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/AssignedSubscriptionMessageGroupManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/AssignedSubscriptionMessageGroupManager.java index 6b2dff7165..efedad1181 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/AssignedSubscriptionMessageGroupManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/AssignedSubscriptionMessageGroupManager.java @@ -20,10 +20,10 @@ */ package org.apache.qpid.server.subscription; +import org.apache.qpid.server.queue.QueueEntryVisitor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.QueueEntry; import java.util.Iterator; @@ -102,7 +102,7 @@ public class AssignedSubscriptionMessageGroupManager implements MessageGroupMana return visitor.getEntry(); } - private class EntryFinder implements AMQQueue.Visitor + private class EntryFinder implements QueueEntryVisitor { private QueueEntry _entry; private Subscription _sub; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/DefinedGroupMessageGroupManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/DefinedGroupMessageGroupManager.java index 62e94f6f2e..f38e23b342 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/DefinedGroupMessageGroupManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/DefinedGroupMessageGroupManager.java @@ -20,12 +20,12 @@ */ package org.apache.qpid.server.subscription; +import org.apache.qpid.server.queue.QueueEntryVisitor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.apache.qpid.server.message.AMQMessageHeader; import org.apache.qpid.server.message.ServerMessage; -import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.QueueEntry; import java.util.HashMap; @@ -176,7 +176,7 @@ public class DefinedGroupMessageGroupManager implements MessageGroupManager return visitor.getEntry(); } - private class EntryFinder implements AMQQueue.Visitor + private class EntryFinder implements QueueEntryVisitor { private QueueEntry _entry; private Subscription _sub; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/ExplicitAcceptDispositionChangeListener.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/ExplicitAcceptDispositionChangeListener.java index cf2754862d..8f3822be6c 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/ExplicitAcceptDispositionChangeListener.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/ExplicitAcceptDispositionChangeListener.java @@ -45,7 +45,7 @@ class ExplicitAcceptDispositionChangeListener implements ServerSession.MessageDi final Subscription_0_10 subscription = getSubscription(); if(subscription != null && _entry.isAcquiredBy(_sub)) { - subscription.getSession().acknowledge(subscription, _entry); + subscription.getSessionModel().acknowledge(subscription, _entry); } else { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/ImplicitAcceptDispositionChangeListener.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/ImplicitAcceptDispositionChangeListener.java index 1e37675c98..826082cc65 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/ImplicitAcceptDispositionChangeListener.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/ImplicitAcceptDispositionChangeListener.java @@ -72,6 +72,10 @@ class ImplicitAcceptDispositionChangeListener implements ServerSession.MessageDi public boolean acquire() { boolean acquired = _entry.acquire(getSubscription()); + if(acquired) + { + getSubscription().recordUnacknowledged(_entry); + } return acquired; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription.java index 66825caa24..8911754a66 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription.java @@ -23,6 +23,7 @@ package org.apache.qpid.server.subscription; import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.logging.LogActor; +import org.apache.qpid.server.protocol.AMQSessionModel; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.QueueEntry; @@ -32,6 +33,14 @@ public interface Subscription boolean isTransient(); + long getBytesOut(); + + long getMessagesOut(); + + long getUnacknowledgedBytes(); + + long getUnacknowledgedMessages(); + public static enum State { ACTIVE, @@ -45,6 +54,7 @@ public interface Subscription } AMQQueue getQueue(); + AMQSessionModel getSessionModel(); QueueEntry.SubscriptionAcquiredState getOwningState(); QueueEntry.SubscriptionAssignedState getAssignedState(); @@ -108,4 +118,6 @@ public interface Subscription boolean isSessionTransactional(); void queueEmpty() throws AMQException; + + String getConsumerName(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java index 1f25c215cc..baf5d09c95 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/SubscriptionImpl.java @@ -44,6 +44,7 @@ import org.apache.qpid.server.logging.subjects.SubscriptionLogSubject; import org.apache.qpid.server.message.AMQMessage; import org.apache.qpid.server.output.ProtocolOutputConverter; import org.apache.qpid.server.protocol.AMQProtocolSession; +import org.apache.qpid.server.protocol.AMQSessionModel; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.QueueEntry; @@ -92,8 +93,13 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage private LogActor _logActor; private UUID _id; private final AtomicLong _deliveredCount = new AtomicLong(0); - private long _createTime = System.currentTimeMillis(); + private final AtomicLong _deliveredBytes = new AtomicLong(0); + + private final AtomicLong _unacknowledgedCount = new AtomicLong(0); + private final AtomicLong _unacknowledgedBytes = new AtomicLong(0); + private long _createTime = System.currentTimeMillis(); + static final class BrowserSubscription extends SubscriptionImpl { @@ -276,22 +282,13 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage public void send(QueueEntry entry, boolean batch) throws AMQException { - // if we do not need to wait for client acknowledgements - // we can decrement the reference count immediately. - - // By doing this _before_ the send we ensure that it - // doesn't get sent if it can't be dequeued, preventing - // duplicate delivery on recovery. - - // The send may of course still fail, in which case, as - // the message is unacked, it will be lost. - + synchronized (getChannel()) { getChannel().getProtocolSession().setDeferFlush(batch); long deliveryTag = getChannel().getNextDeliveryTag(); - + addUnacknowledgedMessage(entry); recordMessageDelivery(entry, deliveryTag); sendToClient(entry, deliveryTag); @@ -371,6 +368,11 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage } + public AMQSessionModel getSessionModel() + { + return _channel; + } + public ConfigStore getConfigStore() { return getQueue().getConfigStore(); @@ -599,6 +601,11 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage return _consumerTag; } + public String getConsumerName() + { + return _consumerTag == null ? null : _consumerTag.asString(); + } + public long getSubscriptionID() { return _subscriptionID; @@ -687,6 +694,7 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage { _deliveryMethod.deliverToClient(this,entry,deliveryTag); _deliveredCount.incrementAndGet(); + _deliveredBytes.addAndGet(entry.getSize()); } @@ -832,4 +840,44 @@ public abstract class SubscriptionImpl implements Subscription, FlowCreditManage _channel.getProtocolSession().flushBatched(); } + + public long getBytesOut() + { + return _deliveredBytes.longValue(); + } + + public long getMessagesOut() + { + return _deliveredCount.longValue(); + } + + + protected void addUnacknowledgedMessage(QueueEntry entry) + { + final long size = entry.getSize(); + _unacknowledgedBytes.addAndGet(size); + _unacknowledgedCount.incrementAndGet(); + entry.addStateChangeListener(new QueueEntry.StateChangeListener() + { + public void stateChanged(QueueEntry entry, QueueEntry.State oldState, QueueEntry.State newState) + { + if(oldState.equals(QueueEntry.State.ACQUIRED) && !newState.equals(QueueEntry.State.ACQUIRED)) + { + _unacknowledgedBytes.addAndGet(-size); + _unacknowledgedCount.decrementAndGet(); + entry.removeStateChangeListener(this); + } + } + }); + } + + public long getUnacknowledgedBytes() + { + return _unacknowledgedBytes.longValue(); + } + + public long getUnacknowledgedMessages() + { + return _unacknowledgedCount.longValue(); + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java index 76d975a789..db378f2bf3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java @@ -130,6 +130,10 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr private String _trace; private final long _createTime = System.currentTimeMillis(); private final AtomicLong _deliveredCount = new AtomicLong(0); + private final AtomicLong _deliveredBytes = new AtomicLong(0); + private final AtomicLong _unacknowledgedCount = new AtomicLong(0); + private final AtomicLong _unacknowledgedBytes = new AtomicLong(0); + private final Map<String, Object> _arguments; private int _deferredMessageCredit; private long _deferredSizeCredit; @@ -185,7 +189,7 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr } _queue = queue; - Map<String, Object> arguments = queue.getArguments() == null ? Collections.EMPTY_MAP : queue.getArguments(); + Map<String, Object> arguments = queue.getArguments(); _traceExclude = (String) arguments.get("qpid.trace.exclude"); _trace = (String) arguments.get("qpid.trace.id"); _id = getConfigStore().createId(); @@ -199,9 +203,13 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr CurrentActor.get().message(this, SubscriptionMessages.CREATE(filterLogString, queue.isDurable() && exclusive, filterLogString.length() > 0)); } - } + public String getConsumerName() + { + return _destination; + } + public boolean isSuspended() { return !isActive() || _deleted.get() || _session.isClosing(); // TODO check for Session suspension @@ -620,10 +628,15 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr _session.sendMessage(xfr, _postIdSettingAction); entry.incrementDeliveryCount(); _deliveredCount.incrementAndGet(); + _deliveredBytes.addAndGet(entry.getSize()); if(_acceptMode == MessageAcceptMode.NONE && _acquireMode == MessageAcquireMode.PRE_ACQUIRED) { forceDequeue(entry, false); } + else if(_acquireMode == MessageAcquireMode.PRE_ACQUIRED) + { + recordUnacknowledged(entry); + } } else { @@ -632,6 +645,12 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr } } + void recordUnacknowledged(QueueEntry entry) + { + _unacknowledgedCount.incrementAndGet(); + _unacknowledgedBytes.addAndGet(entry.getSize()); + } + private void deferredAddCredit(final int deferredMessageCredit, final long deferredSizeCredit) { _deferredMessageCredit += deferredMessageCredit; @@ -653,7 +672,7 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr private void forceDequeue(final QueueEntry entry, final boolean restoreCredit) { - AutoCommitTransaction dequeueTxn = new AutoCommitTransaction(getQueue().getVirtualHost().getMessageStore()); + AutoCommitTransaction dequeueTxn = new AutoCommitTransaction(getQueue().getVirtualHost().getMessageStore()); dequeueTxn.dequeue(entry.getQueue(), entry.getMessage(), new ServerTransaction.Action() { @@ -690,7 +709,7 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr entry.setRedelivered(); } - if (getSession().isClosing() || !setRedelivered) + if (getSessionModel().isClosing() || !setRedelivered) { entry.decrementDeliveryCount(); } @@ -918,6 +937,8 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr // TODO Fix Store Context / cleanup if(entry.isAcquiredBy(this)) { + _unacknowledgedBytes.addAndGet(-entry.getSize()); + _unacknowledgedCount.decrementAndGet(); entry.discard(); } } @@ -944,7 +965,7 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr return false; } - ServerSession getSession() + public ServerSession getSessionModel() { return _session; } @@ -952,7 +973,7 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr public SessionConfig getSessionConfig() { - return getSession(); + return getSessionModel(); } public boolean isBrowsing() @@ -1073,4 +1094,24 @@ public class Subscription_0_10 implements Subscription, FlowCreditManager.FlowCr { _session.getConnection().flush(); } + + public long getBytesOut() + { + return _deliveredBytes.longValue(); + } + + public long getMessagesOut() + { + return _deliveredCount.longValue(); + } + + public long getUnacknowledgedBytes() + { + return _unacknowledgedBytes.longValue(); + } + + public long getUnacknowledgedMessages() + { + return _unacknowledgedCount.longValue(); + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/QpidAcceptor.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/QpidAcceptor.java index 637ea7dffc..7c4188bfcd 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/QpidAcceptor.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/QpidAcceptor.java @@ -20,25 +20,62 @@ */ package org.apache.qpid.server.transport; +import org.apache.qpid.server.protocol.AmqpProtocolVersion; import org.apache.qpid.transport.network.NetworkTransport; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + public class QpidAcceptor { - private NetworkTransport _transport; - private String _protocol; - public QpidAcceptor(NetworkTransport transport, String protocol) + public enum Transport { - _transport = transport; - _protocol = protocol; + TCP("TCP"), + SSL("TCP/SSL"); + + private final String _asString; + + Transport(String asString) + { + _asString = asString; + } + + public String toString() + { + return _asString; + } + } + + private NetworkTransport _networkTransport; + private Transport _transport; + private Set<AmqpProtocolVersion> _supported; + + + public QpidAcceptor(NetworkTransport transport, Transport protocol, Set<AmqpProtocolVersion> supported) + { + _networkTransport = transport; + _transport = protocol; + _supported = Collections.unmodifiableSet(new HashSet<AmqpProtocolVersion>(supported)); } public NetworkTransport getNetworkTransport() { + return _networkTransport; + } + + public Transport getTransport() + { return _transport; } + public Set<AmqpProtocolVersion> getSupported() + { + return _supported; + } + public String toString() { - return _protocol; + return _transport.toString(); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java index c9482b9712..2d0e61ec2e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java @@ -37,8 +37,6 @@ import org.apache.qpid.server.logging.LogSubject; import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.logging.actors.GenericActor; import org.apache.qpid.server.logging.messages.ConnectionMessages; -import org.apache.qpid.server.management.Managable; -import org.apache.qpid.server.management.ManagedObject; import org.apache.qpid.server.protocol.AMQConnectionModel; import org.apache.qpid.server.protocol.AMQSessionModel; import org.apache.qpid.server.security.AuthorizationHolder; @@ -56,7 +54,7 @@ import static org.apache.qpid.server.logging.subjects.LogSubjectFormat.CONNECTIO import static org.apache.qpid.server.logging.subjects.LogSubjectFormat.SOCKET_FORMAT; import static org.apache.qpid.server.logging.subjects.LogSubjectFormat.USER_FORMAT; -public class ServerConnection extends Connection implements Managable, AMQConnectionModel, LogSubject, AuthorizationHolder +public class ServerConnection extends Connection implements AMQConnectionModel, LogSubject, AuthorizationHolder { private ConnectionConfig _config; private Runnable _onOpenTask; @@ -65,11 +63,9 @@ public class ServerConnection extends Connection implements Managable, AMQConnec private Subject _authorizedSubject = null; private Principal _authorizedPrincipal = null; - private boolean _statisticsEnabled = false; private StatisticsCounter _messagesDelivered, _dataDelivered, _messagesReceived, _dataReceived; private final long _connectionId; private final Object _reference = new Object(); - private ServerConnectionMBean _mBean; private VirtualHost _virtualHost; private AtomicLong _lastIoTime = new AtomicLong(); private boolean _blocking; @@ -118,7 +114,6 @@ public class ServerConnection extends Connection implements Managable, AMQConnec { _virtualHost.getConnectionRegistry().deregisterConnection(this); } - unregisterConnectionMbean(); } if (state == State.CLOSED) @@ -156,8 +151,6 @@ public class ServerConnection extends Connection implements Managable, AMQConnec _virtualHost = virtualHost; initialiseStatistics(); - - registerConnectionMbean(); } public void setConnectionConfig(final ConnectionConfig config) @@ -273,7 +266,6 @@ public class ServerConnection extends Connection implements Managable, AMQConnec public void close(AMQConstant cause, String message) throws AMQException { closeSubscriptions(); - unregisterConnectionMbean(); ConnectionCloseCode replyCode = ConnectionCloseCode.NORMAL; try { @@ -338,21 +330,15 @@ public class ServerConnection extends Connection implements Managable, AMQConnec public void registerMessageDelivered(long messageSize) { - if (isStatisticsEnabled()) - { - _messagesDelivered.registerEvent(1L); - _dataDelivered.registerEvent(messageSize); - } + _messagesDelivered.registerEvent(1L); + _dataDelivered.registerEvent(messageSize); _virtualHost.registerMessageDelivered(messageSize); } public void registerMessageReceived(long messageSize, long timestamp) { - if (isStatisticsEnabled()) - { - _messagesReceived.registerEvent(1L, timestamp); - _dataReceived.registerEvent(messageSize, timestamp); - } + _messagesReceived.registerEvent(1L, timestamp); + _dataReceived.registerEvent(messageSize, timestamp); _virtualHost.registerMessageReceived(messageSize, timestamp); } @@ -386,25 +372,12 @@ public class ServerConnection extends Connection implements Managable, AMQConnec public void initialiseStatistics() { - setStatisticsEnabled(!StatisticsCounter.DISABLE_STATISTICS && - _virtualHost.getApplicationRegistry().getConfiguration().isStatisticsGenerationConnectionsEnabled()); - _messagesDelivered = new StatisticsCounter("messages-delivered-" + getConnectionId()); _dataDelivered = new StatisticsCounter("data-delivered-" + getConnectionId()); _messagesReceived = new StatisticsCounter("messages-received-" + getConnectionId()); _dataReceived = new StatisticsCounter("data-received-" + getConnectionId()); } - public boolean isStatisticsEnabled() - { - return _statisticsEnabled; - } - - public void setStatisticsEnabled(boolean enabled) - { - _statisticsEnabled = enabled; - } - /** * @return authorizedSubject */ @@ -448,6 +421,11 @@ public class ServerConnection extends Connection implements Managable, AMQConnec return !super.hasSessionWithName(name); } + public String getRemoteAddressString() + { + return getConfig().getAddress(); + } + public String getUserName() { return _authorizedPrincipal.getName(); @@ -476,12 +454,6 @@ public class ServerConnection extends Connection implements Managable, AMQConnec } } - - public ManagedObject getManagedObject() - { - return _mBean; - } - @Override public void send(ProtocolEvent event) { @@ -489,54 +461,29 @@ public class ServerConnection extends Connection implements Managable, AMQConnec super.send(event); } - public AtomicLong getLastIoTime() + public long getLastIoTime() { - return _lastIoTime; + return _lastIoTime.longValue(); } - void checkForNotification() - { - int channelsCount = getSessionModels().size(); - if (_mBean != null && channelsCount >= getConnectionDelegate().getChannelMax()) - { - _mBean.notifyClients("Channel count (" + channelsCount + ") has reached the threshold value"); - } - } - - private void registerConnectionMbean() + public String getClientId() { - try - { - _mBean = new ServerConnectionMBean(this); - _mBean.register(); - } - catch (JMException jme) - { - log.error("Unable to register mBean for ServerConnection", jme); - } + return getConnectionDelegate().getClientId(); } - private void unregisterConnectionMbean() + public String getClientVersion() { - if (_mBean != null) - { - if (log.isDebugEnabled()) - { - log.debug("Unregistering mBean for ServerConnection" + _mBean); - } - _mBean.unregister(); - _mBean = null; - } + return getConnectionDelegate().getClientVersion(); } - public String getClientId() + public String getPrincipalAsString() { - return getConnectionDelegate().getClientId(); + return getAuthorizedPrincipal().getName(); } - public String getClientVersion() + public long getSessionCountLimit() { - return getConnectionDelegate().getClientVersion(); + return getChannelMax(); } public Principal getPeerPrincipal() diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java index ad59c56878..c13f63b44d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java @@ -61,7 +61,7 @@ public class ServerConnectionDelegate extends ServerDelegate public ServerConnectionDelegate(IApplicationRegistry appRegistry, String localFQDN, AuthenticationManager authManager) { - this(createConnectionProperties(appRegistry.getBroker()), Collections.singletonList((Object)"en_US"), appRegistry, localFQDN, authManager); + this(createConnectionProperties(appRegistry.getBrokerConfig()), Collections.singletonList((Object)"en_US"), appRegistry, localFQDN, authManager); } private ServerConnectionDelegate(Map<String, Object> properties, @@ -226,7 +226,7 @@ public class ServerConnectionDelegate extends ServerDelegate } @Override - protected int getChannelMax() + public int getChannelMax() { return _maxNoOfChannels; } @@ -266,9 +266,6 @@ public class ServerConnectionDelegate extends ServerDelegate if(isSessionNameUnique(atc.getName(), conn)) { super.sessionAttach(conn, atc); - final ServerConnection serverConnection = (ServerConnection) conn; - - serverConnection.checkForNotification(); } else { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionMBean.java deleted file mode 100644 index bb545164fb..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionMBean.java +++ /dev/null @@ -1,263 +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.transport; - -import org.apache.qpid.management.common.mbeans.annotations.MBeanConstructor; -import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription; -import org.apache.qpid.server.logging.actors.CurrentActor; -import org.apache.qpid.server.logging.actors.ManagementActor; -import org.apache.qpid.server.management.AbstractAMQManagedConnectionObject; -import org.apache.qpid.server.management.ManagedObject; -import org.apache.qpid.server.protocol.AMQSessionModel; - -import javax.management.JMException; -import javax.management.NotCompliantMBeanException; -import javax.management.openmbean.CompositeData; -import javax.management.openmbean.CompositeDataSupport; -import javax.management.openmbean.TabularData; -import javax.management.openmbean.TabularDataSupport; -import java.io.IOException; -import java.util.Date; -import java.util.List; - -/** - * This MBean class implements the management interface. In order to make more attributes, operations and notifications - * available over JMX simply augment the ManagedConnection interface and add the appropriate implementation here. - */ -@MBeanDescription("Management Bean for an AMQ Broker 0-10 Connection") -public class ServerConnectionMBean extends AbstractAMQManagedConnectionObject -{ - private final ServerConnection _serverConnection; - - @MBeanConstructor("Creates an MBean exposing an AMQ Broker 0-10 Connection") - protected ServerConnectionMBean(final ServerConnection serverConnection) throws NotCompliantMBeanException - { - super(serverConnection.getConfig().getAddress()); - _serverConnection = serverConnection; - } - - @Override - public ManagedObject getParentObject() - { - return _serverConnection.getVirtualHost().getManagedObject(); - } - - @Override - public String getClientId() - { - return _serverConnection.getClientId(); - } - - @Override - public String getAuthorizedId() - { - return _serverConnection.getAuthorizedPrincipal().getName(); - } - - @Override - public String getVersion() - { - return String.valueOf(_serverConnection.getClientVersion()); - } - - @Override - public String getRemoteAddress() - { - return _serverConnection.getConfig().getAddress(); - } - - @Override - public Date getLastIoTime() - { - return new Date(_serverConnection.getLastIoTime().longValue()); - } - - @Override - public Long getMaximumNumberOfChannels() - { - return (long) _serverConnection.getConnectionDelegate().getChannelMax(); - } - - @Override - public TabularData channels() throws IOException, JMException - { - final TabularDataSupport channelsList = new TabularDataSupport(_channelsType); - final List<AMQSessionModel> list = _serverConnection.getSessionModels(); - - for (final AMQSessionModel channel : list) - { - final ServerSession session = (ServerSession)channel; - Object[] itemValues = - { - session.getChannel(), - session.isTransactional(), - null, - session.getUnacknowledgedMessageCount(), - session.getBlocking() - }; - - final CompositeData channelData = new CompositeDataSupport(_channelType, - COMPOSITE_ITEM_NAMES_DESC.toArray(new String[COMPOSITE_ITEM_NAMES_DESC.size()]), itemValues); - channelsList.put(channelData); - } - return channelsList; - } - - @Override - public void commitTransactions(int channelId) throws JMException - { - final ServerSession session = (ServerSession)_serverConnection.getSession(channelId); - if (session == null) - { - throw new JMException("The channel (channel Id = " + channelId + ") does not exist"); - } - else if (session.isTransactional()) - { - CurrentActor.set(new ManagementActor(getLogActor().getRootMessageLogger())); - try - { - session.commit(); - } - finally - { - CurrentActor.remove(); - } - } - } - - @Override - public void rollbackTransactions(int channelId) throws JMException - { - final ServerSession session = (ServerSession)_serverConnection.getSession(channelId); - if (session == null) - { - throw new JMException("The channel (channel Id = " + channelId + ") does not exist"); - } - else if (session.isTransactional()) - { - CurrentActor.set(new ManagementActor(getLogActor().getRootMessageLogger())); - try - { - session.rollback(); - } - finally - { - CurrentActor.remove(); - } - } - } - - @Override - public void closeConnection() throws Exception - { - _serverConnection.mgmtClose(); - } - - @Override - public void resetStatistics() throws Exception - { - _serverConnection.resetStatistics(); - } - - @Override - public double getPeakMessageDeliveryRate() - { - return _serverConnection.getMessageDeliveryStatistics().getPeak(); - } - - @Override - public double getPeakDataDeliveryRate() - { - return _serverConnection.getDataDeliveryStatistics().getPeak(); - } - - @Override - public double getMessageDeliveryRate() - { - return _serverConnection.getMessageDeliveryStatistics().getRate(); - } - - @Override - public double getDataDeliveryRate() - { - return _serverConnection.getDataDeliveryStatistics().getRate(); - } - - @Override - public long getTotalMessagesDelivered() - { - return _serverConnection.getMessageDeliveryStatistics().getTotal(); - } - - @Override - public long getTotalDataDelivered() - { - return _serverConnection.getDataDeliveryStatistics().getTotal(); - } - - @Override - public double getPeakMessageReceiptRate() - { - return _serverConnection.getMessageReceiptStatistics().getPeak(); - } - - @Override - public double getPeakDataReceiptRate() - { - return _serverConnection.getDataReceiptStatistics().getPeak(); - } - - @Override - public double getMessageReceiptRate() - { - return _serverConnection.getMessageReceiptStatistics().getRate(); - } - - @Override - public double getDataReceiptRate() - { - return _serverConnection.getDataReceiptStatistics().getRate(); - } - - @Override - public long getTotalMessagesReceived() - { - return _serverConnection.getMessageReceiptStatistics().getTotal(); - } - - @Override - public long getTotalDataReceived() - { - return _serverConnection.getDataReceiptStatistics().getTotal(); - } - - @Override - public boolean isStatisticsEnabled() - { - return _serverConnection.isStatisticsEnabled(); - } - - @Override - public void setStatisticsEnabled(boolean enabled) - { - _serverConnection.setStatisticsEnabled(enabled); - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java index 0cb60fafd3..9914485638 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java @@ -630,11 +630,21 @@ public class ServerSession extends Session return _txnRejects.get(); } + public int getChannelId() + { + return getChannel(); + } + public Long getTxnCount() { return _txnCount.get(); } + public Long getTxnStart() + { + return _txnStarts.get(); + } + public Principal getAuthorizedPrincipal() { return getConnection().getAuthorizedPrincipal(); @@ -1059,5 +1069,4 @@ public class ServerSession extends Session { return getId().compareTo(session.getId()); } - } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java index 85ea97c107..3dbc835c45 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java @@ -1226,11 +1226,7 @@ public class ServerSessionDelegate extends SessionDelegate try { queue = createQueue(queueName, method, virtualHost, (ServerSession)session); - if(method.getExclusive()) - { - queue.setExclusive(true); - } - else if(method.getAutoDelete()) + if(!method.getExclusive() && method.getAutoDelete()) { queue.setDeleteOnNoConsumers(true); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java index c59016173a..dcc5acb820 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java @@ -32,7 +32,6 @@ import org.apache.qpid.server.connection.IConnectionRegistry; import org.apache.qpid.server.exchange.ExchangeFactory; import org.apache.qpid.server.exchange.ExchangeRegistry; import org.apache.qpid.server.federation.BrokerLink; -import org.apache.qpid.server.management.ManagedObject; import org.apache.qpid.server.protocol.v1_0.LinkRegistry; import org.apache.qpid.server.queue.QueueRegistry; import org.apache.qpid.server.registry.IApplicationRegistry; @@ -62,8 +61,6 @@ public interface VirtualHost extends DurableConfigurationStore.Source, VirtualHo void close(); - ManagedObject getManagedObject(); - UUID getBrokerId(); void scheduleHouseKeepingTask(long period, HouseKeepingTask task); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java index e956806823..acd6101ff8 100755 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java @@ -100,7 +100,7 @@ public class VirtualHostConfigRecoveryHandler implements ConfigurationRecoveryHa return this; } - public void queue(UUID id, String queueName, String owner, boolean exclusive, FieldTable arguments) + public void queue(UUID id, String queueName, String owner, boolean exclusive, FieldTable arguments, UUID alternateExchangeId) { try { @@ -111,6 +111,17 @@ public class VirtualHostConfigRecoveryHandler implements ConfigurationRecoveryHa q = AMQQueueFactory.createAMQQueueImpl(id, queueName, true, owner, false, exclusive, _virtualHost, FieldTable.convertToMap(arguments)); _virtualHost.getQueueRegistry().registerQueue(q); + + if (alternateExchangeId != null) + { + Exchange altExchange = _virtualHost.getExchangeRegistry().getExchange(alternateExchangeId); + if (altExchange == null) + { + _logger.error("Unknown exchange id " + alternateExchangeId + ", cannot set alternate exchange on queue with id " + id); + return; + } + q.setAlternateExchange(altExchange); + } } CurrentActor.get().message(_logSubject, TransactionLogMessages.RECOVERY_START(queueName, true)); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java index 5a56fe1765..8945431e99 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java @@ -20,12 +20,20 @@ */ package org.apache.qpid.server.virtualhost; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.TimeUnit; import org.apache.commons.configuration.ConfigurationException; import org.apache.log4j.Logger; import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.AMQBrokerManagerMBean; import org.apache.qpid.server.binding.BindingFactory; import org.apache.qpid.server.configuration.BrokerConfig; import org.apache.qpid.server.configuration.ConfigStore; @@ -45,11 +53,9 @@ import org.apache.qpid.server.federation.BrokerLink; import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.logging.messages.VirtualHostMessages; import org.apache.qpid.server.logging.subjects.MessageStoreLogSubject; -import org.apache.qpid.server.management.AMQManagedObject; -import org.apache.qpid.server.management.ManagedObject; -import org.apache.qpid.server.protocol.v1_0.LinkRegistry; import org.apache.qpid.server.protocol.AMQConnectionModel; import org.apache.qpid.server.protocol.AMQSessionModel; +import org.apache.qpid.server.protocol.v1_0.LinkRegistry; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.AMQQueueFactory; import org.apache.qpid.server.queue.DefaultQueueRegistry; @@ -66,20 +72,6 @@ import org.apache.qpid.server.txn.DtxRegistry; import org.apache.qpid.server.virtualhost.plugins.VirtualHostPlugin; import org.apache.qpid.server.virtualhost.plugins.VirtualHostPluginFactory; -import javax.management.JMException; -import javax.management.NotCompliantMBeanException; -import javax.management.ObjectName; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.UUID; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.ScheduledThreadPoolExecutor; -import java.util.concurrent.TimeUnit; - - public class VirtualHostImpl implements VirtualHost, IConnectionRegistry.RegistryChangeListener, EventListener { private static final Logger _logger = Logger.getLogger(VirtualHostImpl.class); @@ -104,10 +96,6 @@ public class VirtualHostImpl implements VirtualHost, IConnectionRegistry.Registr private final VirtualHostConfiguration _vhostConfig; - private final VirtualHostMBean _virtualHostMBean; - - private final AMQBrokerManagerMBean _brokerMBean; - private final QueueRegistry _queueRegistry; private final ExchangeRegistry _exchangeRegistry; @@ -124,8 +112,6 @@ public class VirtualHostImpl implements VirtualHost, IConnectionRegistry.Registr private volatile State _state = State.INITIALISING; - private boolean _statisticsEnabled = false; - private StatisticsCounter _messagesDelivered, _dataDelivered, _messagesReceived, _dataReceived; private final Map<String, LinkRegistry> _linkRegistry = new HashMap<String, LinkRegistry>(); @@ -144,7 +130,7 @@ public class VirtualHostImpl implements VirtualHost, IConnectionRegistry.Registr } _appRegistry = appRegistry; - _brokerConfig = _appRegistry.getBroker(); + _brokerConfig = _appRegistry.getBrokerConfig(); _vhostConfig = hostConfig; _name = _vhostConfig.getName(); _dtxRegistry = new DtxRegistry(); @@ -153,7 +139,6 @@ public class VirtualHostImpl implements VirtualHost, IConnectionRegistry.Registr CurrentActor.get().message(VirtualHostMessages.CREATED(_name)); - _virtualHostMBean = new VirtualHostMBean(); _securityManager = new SecurityManager(_appRegistry.getSecurityManager()); _securityManager.configureHostPlugins(_vhostConfig); @@ -171,8 +156,6 @@ public class VirtualHostImpl implements VirtualHost, IConnectionRegistry.Registr _bindingFactory = new BindingFactory(this); - _brokerMBean = new AMQBrokerManagerMBean(_virtualHostMBean); - _messageStore = initialiseMessageStore(hostConfig.getMessageStoreClass()); configureMessageStore(hostConfig); @@ -541,16 +524,6 @@ public class VirtualHostImpl implements VirtualHost, IConnectionRegistry.Registr CurrentActor.get().message(VirtualHostMessages.CLOSED()); } - public ManagedObject getBrokerMBean() - { - return _brokerMBean; - } - - public ManagedObject getManagedObject() - { - return _virtualHostMBean; - } - public UUID getBrokerId() { return _appRegistry.getBrokerId(); @@ -568,21 +541,15 @@ public class VirtualHostImpl implements VirtualHost, IConnectionRegistry.Registr public void registerMessageDelivered(long messageSize) { - if (isStatisticsEnabled()) - { - _messagesDelivered.registerEvent(1L); - _dataDelivered.registerEvent(messageSize); - } + _messagesDelivered.registerEvent(1L); + _dataDelivered.registerEvent(messageSize); _appRegistry.registerMessageDelivered(messageSize); } public void registerMessageReceived(long messageSize, long timestamp) { - if (isStatisticsEnabled()) - { - _messagesReceived.registerEvent(1L, timestamp); - _dataReceived.registerEvent(messageSize, timestamp); - } + _messagesReceived.registerEvent(1L, timestamp); + _dataReceived.registerEvent(messageSize, timestamp); _appRegistry.registerMessageReceived(messageSize, timestamp); } @@ -621,25 +588,12 @@ public class VirtualHostImpl implements VirtualHost, IConnectionRegistry.Registr public void initialiseStatistics() { - setStatisticsEnabled(!StatisticsCounter.DISABLE_STATISTICS && - _appRegistry.getConfiguration().isStatisticsGenerationVirtualhostsEnabled()); - _messagesDelivered = new StatisticsCounter("messages-delivered-" + getName()); _dataDelivered = new StatisticsCounter("bytes-delivered-" + getName()); _messagesReceived = new StatisticsCounter("messages-received-" + getName()); _dataReceived = new StatisticsCounter("bytes-received-" + getName()); } - public boolean isStatisticsEnabled() - { - return _statisticsEnabled; - } - - public void setStatisticsEnabled(boolean enabled) - { - _statisticsEnabled = enabled; - } - public BrokerLink createBrokerConnection(UUID id, long createTime, Map<String,String> arguments) { BrokerLink blink = new BrokerLink(this, id, createTime, arguments); @@ -772,36 +726,6 @@ public class VirtualHostImpl implements VirtualHost, IConnectionRegistry.Registr } } - - /** - * Virtual host JMX MBean class. - * - * This has some of the methods implemented from management interface for exchanges. Any - * Implementation of an Exchange MBean should extend this class. - */ - public class VirtualHostMBean extends AMQManagedObject implements ManagedVirtualHost - { - public VirtualHostMBean() throws NotCompliantMBeanException - { - super(ManagedVirtualHost.class, ManagedVirtualHost.TYPE); - } - - public String getObjectInstanceName() - { - return ObjectName.quote(_name); - } - - public String getName() - { - return _name; - } - - public VirtualHostImpl getVirtualHost() - { - return VirtualHostImpl.this; - } - } - private final class BeforeActivationListener implements EventListener { @Override @@ -825,17 +749,19 @@ public class VirtualHostImpl implements VirtualHost, IConnectionRegistry.Registr public void event(Event event) { State finalState = State.ERRORED; + try { initialiseHouseKeeping(_vhostConfig.getHousekeepingCheckPeriod()); - try - { - _brokerMBean.register(); - } - catch (JMException e) - { - throw new RuntimeException("Failed to register virtual host mbean for virtual host " + getName(), e); - } +//TODO: implement state changing for the VirtualHost MBean instead of registering and unregistering +// try +// { +// _brokerMBean.register(); +// } +// catch (JMException e) +// { +// throw new RuntimeException("Failed to register virtual host mbean for virtual host " + getName(), e); +// } finalState = State.ACTIVE; } finally @@ -861,7 +787,8 @@ public class VirtualHostImpl implements VirtualHost, IConnectionRegistry.Registr */ _connectionRegistry.close(IConnectionRegistry.VHOST_PASSIVATE_REPLY_TEXT); - _brokerMBean.unregister(); +//TODO: implement state changing for the VirtualHost MBean instead of registering and unregistering +// _brokerMBean.unregister(); removeHouseKeepingTasks(); _queueRegistry.stopAllAndUnregisterMBeans(); @@ -884,7 +811,6 @@ public class VirtualHostImpl implements VirtualHost, IConnectionRegistry.Registr @Override public void event(Event event) { - _brokerMBean.unregister(); shutdownHouseKeeping(); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java index ef621a166a..1be472844a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostRegistry.java @@ -22,10 +22,12 @@ package org.apache.qpid.server.virtualhost; import org.apache.qpid.common.Closeable;
import org.apache.qpid.server.configuration.ConfigStore;
+import org.apache.qpid.server.exchange.ExchangeRegistry; import org.apache.qpid.server.registry.ApplicationRegistry;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@@ -37,6 +39,8 @@ public class VirtualHostRegistry implements Closeable private String _defaultVirtualHostName;
private ApplicationRegistry _applicationRegistry;
+ private final Collection<RegistryChangeListener> _listeners = + Collections.synchronizedCollection(new ArrayList<RegistryChangeListener>()); public VirtualHostRegistry(ApplicationRegistry applicationRegistry)
{
@@ -50,11 +54,25 @@ public class VirtualHostRegistry implements Closeable throw new Exception("Virtual Host with name " + host.getName() + " already registered.");
}
_registry.put(host.getName(),host);
+ synchronized (_listeners) + { + for(RegistryChangeListener listener : _listeners) + { + listener.virtualHostRegistered(host); + } + } }
public synchronized void unregisterVirtualHost(VirtualHost host)
{
_registry.remove(host.getName());
+ synchronized (_listeners) + { + for(RegistryChangeListener listener : _listeners) + { + listener.virtualHostUnregistered(host); + } + } }
public VirtualHost getVirtualHost(String name)
@@ -106,4 +124,17 @@ public class VirtualHostRegistry implements Closeable }
}
+ + public static interface RegistryChangeListener + { + void virtualHostRegistered(VirtualHost virtualHost); + void virtualHostUnregistered(VirtualHost virtualHost); + + } + + public void addRegistryChangeListener(RegistryChangeListener listener) + { + _listeners.add(listener); + } + }
diff --git a/qpid/java/broker/src/test/java/org/apache/log4j/xml/QpidLog4JConfiguratorTest.java b/qpid/java/broker/src/test/java/org/apache/log4j/xml/QpidLog4JConfiguratorTest.java deleted file mode 100644 index c06ce5e31a..0000000000 --- a/qpid/java/broker/src/test/java/org/apache/log4j/xml/QpidLog4JConfiguratorTest.java +++ /dev/null @@ -1,395 +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.log4j.xml; - - -import junit.framework.TestCase; -import org.apache.log4j.xml.QpidLog4JConfigurator.IllegalLoggerLevelException; - -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; - -public class QpidLog4JConfiguratorTest extends TestCase -{ - private static final String NEWLINE = System.getProperty("line.separator"); - - private File _testConfigFile; - - private File createTempTestLog4JConfig(String loggerLevel,String rootLoggerLevel, boolean missingTagClose, boolean incorrectAttribute) - { - File tmpFile = null; - try - { - tmpFile = File.createTempFile("QpidLog4JConfiguratorTestLog4jConfig", ".tmp"); - tmpFile.deleteOnExit(); - - FileWriter fstream = new FileWriter(tmpFile); - BufferedWriter writer = new BufferedWriter(fstream); - - writer.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"+NEWLINE); - writer.write("<!DOCTYPE log4j:configuration SYSTEM \"log4j.dtd\">"+NEWLINE); - - writer.write("<log4j:configuration xmlns:log4j=\"http://jakarta.apache.org/log4j/\" debug=\"null\" " + - "threshold=\"null\">"+NEWLINE); - - writer.write(" <appender class=\"org.apache.log4j.ConsoleAppender\" name=\"STDOUT\">"+NEWLINE); - writer.write(" <layout class=\"org.apache.log4j.PatternLayout\">"+NEWLINE); - writer.write(" <param name=\"ConversionPattern\" value=\"%d %-5p [%t] %C{2} (%F:%L) - %m%n\"/>"+NEWLINE); - writer.write(" </layout>"+NEWLINE); - writer.write(" </appender>"+NEWLINE); - - String closeTag="/"; - if(missingTagClose) - { - closeTag=""; - } - - //Example of a 'category' with a 'priority' - writer.write(" <category additivity=\"true\" name=\"logger1\">"+NEWLINE); - writer.write(" <priority value=\"" + loggerLevel+ "\"" + closeTag + ">"+NEWLINE); - writer.write(" <appender-ref ref=\"STDOUT\"/>"+NEWLINE); - writer.write(" </category>"+NEWLINE); - - String attributeName="value"; - if(incorrectAttribute) - { - attributeName="values"; - } - - //Example of a 'category' with a 'level' - writer.write(" <category additivity=\"true\" name=\"logger2\">"+NEWLINE); - writer.write(" <level " + attributeName + "=\"" + loggerLevel+ "\"/>"+NEWLINE); - writer.write(" <appender-ref ref=\"STDOUT\"/>"+NEWLINE); - writer.write(" </category>"+NEWLINE); - - //Example of a 'logger' with a 'level' - writer.write(" <logger additivity=\"true\" name=\"logger3\">"+NEWLINE); - writer.write(" <level value=\"" + loggerLevel+ "\"/>"+NEWLINE); - writer.write(" <appender-ref ref=\"STDOUT\"/>"+NEWLINE); - writer.write(" </logger>"+NEWLINE); - - //'root' logger - writer.write(" <root>"+NEWLINE); - writer.write(" <priority value=\"" + rootLoggerLevel+ "\"/>"+NEWLINE); - writer.write(" <appender-ref ref=\"STDOUT\"/>"+NEWLINE); - writer.write(" </root>"+NEWLINE); - - writer.write("</log4j:configuration>"+NEWLINE); - - writer.flush(); - writer.close(); - } - catch (IOException e) - { - fail("Unable to create temporary test log4j configuration"); - } - - return tmpFile; - } - - - - //******* Test Methods ******* // - - public void testCheckLevelsAndStrictParser() - { - //try the valid logger levels - _testConfigFile = createTempTestLog4JConfig("all", "info", false, false); - try - { - QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); - } - catch (Exception e) - { - fail("No exception expected, valid levels and xml were used"); - } - - _testConfigFile = createTempTestLog4JConfig("trace", "info", false, false); - try - { - QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); - } - catch (Exception e) - { - fail("No exception expected, valid levels and xml were used"); - } - - _testConfigFile = createTempTestLog4JConfig("debug", "info", false, false); - try - { - QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); - } - catch (Exception e) - { - fail("No exception expected, valid levels and xml were used"); - } - - _testConfigFile = createTempTestLog4JConfig("info", "info", false, false); - try - { - QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); - } - catch (Exception e) - { - fail("No exception expected, valid levels and xml were used"); - } - - _testConfigFile = createTempTestLog4JConfig("warn", "info", false, false); - try - { - QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); - } - catch (Exception e) - { - fail("No exception expected, valid levels and xml were used"); - } - - _testConfigFile = createTempTestLog4JConfig("error", "info", false, false); - try - { - QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); - } - catch (Exception e) - { - fail("No exception expected, valid levels and xml were used"); - } - - _testConfigFile = createTempTestLog4JConfig("fatal", "info", false, false); - try - { - QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); - } - catch (Exception e) - { - fail("No exception expected, valid levels and xml were used"); - } - - _testConfigFile = createTempTestLog4JConfig("off", "info", false, false); - try - { - QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); - } - catch (Exception e) - { - fail("No exception expected, valid levels and xml were used"); - } - - _testConfigFile = createTempTestLog4JConfig("null", "info", false, false); - try - { - QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); - } - catch (Exception e) - { - fail("No exception expected, valid levels and xml were used"); - } - - _testConfigFile = createTempTestLog4JConfig("inherited", "info", false, false); - try - { - QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); - } - catch (Exception e) - { - fail("No exception expected, valid levels and xml were used"); - } - - //now try an invalid logger level - _testConfigFile = createTempTestLog4JConfig("madeup", "info", false, false); - try - { - QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); - fail("IllegalLoggerLevelException expected, invalid levels used"); - } - catch (IllegalLoggerLevelException e) - { - //expected, ignore - } - catch (IOException e) - { - fail("Incorrect Exception, expected an IllegalLoggerLevelException"); - } - - - - //now try the valid rootLogger levels - _testConfigFile = createTempTestLog4JConfig("info", "all", false, false); - try - { - QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); - } - catch (Exception e) - { - fail("No exception expected, valid levels and xml were used"); - } - - _testConfigFile = createTempTestLog4JConfig("info", "trace", false, false); - try - { - QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); - } - catch (Exception e) - { - fail("No exception expected, valid levels and xml were used"); - } - - _testConfigFile = createTempTestLog4JConfig("info", "debug", false, false); - try - { - QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); - } - catch (Exception e) - { - fail("No exception expected, valid levels and xml were used"); - } - - _testConfigFile = createTempTestLog4JConfig("info", "info", false, false); - try - { - QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); - } - catch (Exception e) - { - fail("No exception expected, valid levels and xml were used"); - } - - _testConfigFile = createTempTestLog4JConfig("info", "warn", false, false); - try - { - QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); - } - catch (Exception e) - { - fail("No exception expected, valid levels and xml were used"); - } - - _testConfigFile = createTempTestLog4JConfig("info", "error", false, false); - try - { - QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); - } - catch (Exception e) - { - fail("No exception expected, valid levels and xml were used"); - } - - _testConfigFile = createTempTestLog4JConfig("info", "fatal", false, false); - try - { - QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); - } - catch (Exception e) - { - fail("No exception expected, valid levels and xml were used"); - } - - _testConfigFile = createTempTestLog4JConfig("info", "off", false, false); - try - { - QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); - } - catch (Exception e) - { - fail("No exception expected, valid levels and xml were used"); - } - - _testConfigFile = createTempTestLog4JConfig("info", "null", false, false); - try - { - QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); - } - catch (Exception e) - { - fail("No exception expected, valid levels and xml were used"); - } - - _testConfigFile = createTempTestLog4JConfig("info", "inherited", false, false); - try - { - QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); - } - catch (Exception e) - { - fail("No exception expected, valid levels and xml were used"); - } - - _testConfigFile = createTempTestLog4JConfig("info", "debug", false, false); - try - { - QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); - } - catch (Exception e) - { - fail("No exception expected, valid levels and xml were used"); - } - - //now try an invalid logger level - _testConfigFile = createTempTestLog4JConfig("info", "madeup", false, false); - try - { - QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); - fail("IllegalLoggerLevelException expected, invalid levels used"); - } - catch (IllegalLoggerLevelException e) - { - //expected, ignore - } - catch (IOException e) - { - fail("Incorrect Exception, expected an IllegalLoggerLevelException"); - } - - - - //now try invalid xml - _testConfigFile = createTempTestLog4JConfig("info", "info", true, false); - try - { - QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); - fail("IOException expected, malformed XML used"); - } - catch (IllegalLoggerLevelException e) - { - fail("Incorrect Exception, expected an IOException"); - } - catch (IOException e) - { - //expected, ignore - } - - _testConfigFile = createTempTestLog4JConfig("info", "info", false, true); - try - { - QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); - fail("IOException expected, malformed XML used"); - } - catch (IllegalLoggerLevelException e) - { - //expected, ignore - } - catch (IOException e) - { - fail("Incorrect Exception, expected an IllegalLoggerLevelException"); - } - } -} diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/AMQBrokerManagerMBeanTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/AMQBrokerManagerMBeanTest.java deleted file mode 100644 index d34d1bbef3..0000000000 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/AMQBrokerManagerMBeanTest.java +++ /dev/null @@ -1,194 +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; - -import org.apache.commons.configuration.XMLConfiguration; - -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.management.common.mbeans.ManagedBroker; -import org.apache.qpid.server.configuration.ServerConfiguration; -import org.apache.qpid.server.exchange.Exchange; -import org.apache.qpid.server.exchange.ExchangeRegistry; -import org.apache.qpid.server.logging.SystemOutMessageLogger; -import org.apache.qpid.server.logging.actors.CurrentActor; -import org.apache.qpid.server.logging.actors.TestLogActor; -import org.apache.qpid.server.queue.AMQPriorityQueue; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.queue.AMQQueueFactory; -import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.registry.IApplicationRegistry; -import org.apache.qpid.server.store.TestableMemoryMessageStore; -import org.apache.qpid.server.util.TestApplicationRegistry; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.virtualhost.VirtualHostImpl; -import org.apache.qpid.test.utils.QpidTestCase; - -import java.util.HashMap; -import java.util.Map; - -public class AMQBrokerManagerMBeanTest extends QpidTestCase -{ - private QueueRegistry _queueRegistry; - private ExchangeRegistry _exchangeRegistry; - private VirtualHost _vHost; - - public void testExchangeOperations() throws Exception - { - String exchange1 = "testExchange1_" + System.currentTimeMillis(); - String exchange2 = "testExchange2_" + System.currentTimeMillis(); - String exchange3 = "testExchange3_" + System.currentTimeMillis(); - - assertTrue(_exchangeRegistry.getExchange(new AMQShortString(exchange1)) == null); - assertTrue(_exchangeRegistry.getExchange(new AMQShortString(exchange2)) == null); - assertTrue(_exchangeRegistry.getExchange(new AMQShortString(exchange3)) == null); - - - ManagedBroker mbean = new AMQBrokerManagerMBean((VirtualHostImpl.VirtualHostMBean) _vHost.getManagedObject()); - mbean.createNewExchange(exchange1, "direct", false); - mbean.createNewExchange(exchange2, "topic", false); - mbean.createNewExchange(exchange3, "headers", false); - - assertTrue(_exchangeRegistry.getExchange(new AMQShortString(exchange1)) != null); - assertTrue(_exchangeRegistry.getExchange(new AMQShortString(exchange2)) != null); - assertTrue(_exchangeRegistry.getExchange(new AMQShortString(exchange3)) != null); - - mbean.unregisterExchange(exchange1); - mbean.unregisterExchange(exchange2); - mbean.unregisterExchange(exchange3); - - assertTrue(_exchangeRegistry.getExchange(new AMQShortString(exchange1)) == null); - assertTrue(_exchangeRegistry.getExchange(new AMQShortString(exchange2)) == null); - assertTrue(_exchangeRegistry.getExchange(new AMQShortString(exchange3)) == null); - } - - public void testQueueOperations() throws Exception - { - String queueName = "testQueue_" + System.currentTimeMillis(); - - ManagedBroker mbean = new AMQBrokerManagerMBean((VirtualHostImpl.VirtualHostMBean) _vHost.getManagedObject()); - - assertTrue(_queueRegistry.getQueue(new AMQShortString(queueName)) == null); - - mbean.createNewQueue(queueName, "test", false); - assertTrue(_queueRegistry.getQueue(new AMQShortString(queueName)) != null); - - mbean.deleteQueue(queueName); - assertTrue(_queueRegistry.getQueue(new AMQShortString(queueName)) == null); - } - - public void testCreateNewQueueBindsToDefaultExchange() throws Exception - { - String queueName = "testQueue_" + System.currentTimeMillis(); - - ManagedBroker mbean = new AMQBrokerManagerMBean((VirtualHostImpl.VirtualHostMBean) _vHost.getManagedObject()); - ExchangeRegistry exReg = _vHost.getExchangeRegistry(); - Exchange defaultExchange = exReg.getDefaultExchange(); - - mbean.createNewQueue(queueName, "test", false); - assertTrue(_queueRegistry.getQueue(new AMQShortString(queueName)) != null); - - assertTrue("New queue should be bound to default exchange", defaultExchange.isBound(new AMQShortString(queueName))); - } - - /** - * Tests that setting the {@link AMQQueueFactory#X_QPID_MAXIMUM_DELIVERY_COUNT} argument does cause the - * maximum delivery count to be set on the Queue. - */ - public void testCreateNewQueueWithMaximumDeliveryCount() throws Exception - { - final Map<String,Object> args = new HashMap<String, Object>(); - args.put(AMQQueueFactory.X_QPID_MAXIMUM_DELIVERY_COUNT, 5); - - final AMQShortString queueName = new AMQShortString("testCreateNewQueueWithMaximumDeliveryCount"); - - final QueueRegistry qReg = _vHost.getQueueRegistry(); - - assertNull("The queue should not yet exist", qReg.getQueue(queueName)); - - final ManagedBroker mbean = new AMQBrokerManagerMBean((VirtualHostImpl.VirtualHostMBean) _vHost.getManagedObject()); - mbean.createNewQueue(queueName.asString(), "test", false, args); - - final AMQQueue createdQueue = qReg.getQueue(queueName); - assertNotNull("The queue was not registered as expected", createdQueue); - assertEquals("Unexpected maximum delivery count", 5, createdQueue.getMaximumDeliveryCount()); - } - - /** - * Tests that setting the {@link AMQQueueFactory#X_QPID_PRIORITIES} argument prompts creation of - * a Priority Queue. - */ - public void testCreatePriorityQueue() throws Exception - { - int numPriorities = 7; - Map<String,Object> args = new HashMap<String, Object>(); - args.put(AMQQueueFactory.X_QPID_PRIORITIES, numPriorities); - - AMQShortString queueName = new AMQShortString("testCreatePriorityQueue"); - - QueueRegistry qReg = _vHost.getQueueRegistry(); - - assertNull("The queue should not yet exist", qReg.getQueue(queueName)); - - ManagedBroker mbean = new AMQBrokerManagerMBean((VirtualHostImpl.VirtualHostMBean) _vHost.getManagedObject()); - mbean.createNewQueue(queueName.asString(), "test", false, args); - - AMQQueue queue = qReg.getQueue(queueName); - assertEquals("Queue is not a priorty queue", AMQPriorityQueue.class, queue.getClass()); - assertEquals("Number of priorities supported was not as expected", numPriorities, ((AMQPriorityQueue)queue).getPriorities()); - } - - @Override - public void setUp() throws Exception - { - super.setUp(); - - CurrentActor.set(new TestLogActor(new SystemOutMessageLogger())); - - XMLConfiguration configXml = new XMLConfiguration(); - configXml.addProperty("virtualhosts.virtualhost(-1).name", "test"); - configXml.addProperty("virtualhosts.virtualhost(-1).test.store.class", TestableMemoryMessageStore.class.getName()); - - ServerConfiguration configuration = new ServerConfiguration(configXml); - - ApplicationRegistry registry = new TestApplicationRegistry(configuration); - ApplicationRegistry.initialise(registry); - registry.getVirtualHostRegistry().setDefaultVirtualHostName("test"); - - IApplicationRegistry appRegistry = ApplicationRegistry.getInstance(); - _vHost = appRegistry.getVirtualHostRegistry().getVirtualHost("test"); - _queueRegistry = _vHost.getQueueRegistry(); - _exchangeRegistry = _vHost.getExchangeRegistry(); - } - - @Override - public void tearDown() throws Exception - { - try - { - super.tearDown(); - } - finally - { - ApplicationRegistry.remove(); - } - } -} diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/QueueConfigurationTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/QueueConfigurationTest.java index 36f131a30f..9225f7810a 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/QueueConfigurationTest.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/QueueConfigurationTest.java @@ -204,6 +204,18 @@ public class QueueConfigurationTest extends TestCase assertEquals("test-sort-key", qConf.getQueueSortKey()); } + public void testQueueDescription() throws ConfigurationException + { + //Check default value + QueueConfiguration qConf = new QueueConfiguration("test", _emptyConf); + assertNull(qConf.getDescription()); + + // Check explicit value + final VirtualHostConfiguration vhostConfig = overrideConfiguration("description", "mydescription"); + qConf = new QueueConfiguration("test", vhostConfig); + assertEquals("mydescription", qConf.getDescription()); + } + private VirtualHostConfiguration overrideConfiguration(String property, Object value) throws ConfigurationException { diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/ServerConfigurationTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/ServerConfigurationTest.java index c2d2eb37c1..2ee02430c8 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/ServerConfigurationTest.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/ServerConfigurationTest.java @@ -252,13 +252,13 @@ public class ServerConfigurationTest extends QpidTestCase { // Check default _serverConfig.initialise(); - assertEquals(true, _serverConfig.getManagementSSLEnabled()); + assertEquals(false, _serverConfig.getManagementSSLEnabled()); // Check value we set - _config.setProperty("management.ssl.enabled", false); + _config.setProperty("management.ssl.enabled", true); _serverConfig = new ServerConfiguration(_config); _serverConfig.initialise(); - assertEquals(false, _serverConfig.getManagementSSLEnabled()); + assertEquals(true, _serverConfig.getManagementSSLEnabled()); } public void testGetManagementKeystorePassword() throws ConfigurationException @@ -287,25 +287,17 @@ public class ServerConfigurationTest extends QpidTestCase assertEquals(false, _serverConfig.getQueueAutoRegister()); } - public void testGetManagementEnabled() throws ConfigurationException + public void testGetJMXManagementEnabled() throws ConfigurationException { // Check default _serverConfig.initialise(); - assertEquals(true, _serverConfig.getManagementEnabled()); + assertEquals(true, _serverConfig.getJMXManagementEnabled()); // Check value we set _config.setProperty("management.enabled", false); _serverConfig = new ServerConfiguration(_config); _serverConfig.initialise(); - assertEquals(false, _serverConfig.getManagementEnabled()); - } - - public void testSetManagementEnabled() throws ConfigurationException - { - // Check value we set - _serverConfig.initialise(); - _serverConfig.setManagementEnabled(false); - assertEquals(false, _serverConfig.getManagementEnabled()); + assertEquals(false, _serverConfig.getJMXManagementEnabled()); } public void testGetManagementRightsInferAllAccess() throws Exception diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/ExchangeMBeanTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/ExchangeMBeanTest.java deleted file mode 100644 index 9034bf9c3a..0000000000 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/ExchangeMBeanTest.java +++ /dev/null @@ -1,235 +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.exchange; - -import org.apache.commons.lang.ArrayUtils; - -import org.apache.qpid.exchange.ExchangeDefaults; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.management.common.mbeans.ManagedExchange; -import org.apache.qpid.server.management.ManagedObject; -import org.apache.qpid.server.model.UUIDGenerator; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.queue.AMQQueueFactory; -import org.apache.qpid.server.queue.QueueRegistry; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.registry.IApplicationRegistry; -import org.apache.qpid.server.util.InternalBrokerBaseCase; -import org.apache.qpid.server.virtualhost.VirtualHost; - -import javax.management.JMException; -import javax.management.openmbean.CompositeDataSupport; -import javax.management.openmbean.TabularData; -import java.util.ArrayList; -import java.util.Iterator; - -/** - * Unit test class for testing different Exchange MBean operations - */ -public class ExchangeMBeanTest extends InternalBrokerBaseCase -{ - private AMQQueue _queue; - private QueueRegistry _queueRegistry; - private VirtualHost _virtualHost; - - public void testGeneralProperties() throws Exception - { - DirectExchange exchange = new DirectExchange(); - exchange.initialise(UUIDGenerator.generateUUID(), _virtualHost, ExchangeDefaults.DIRECT_EXCHANGE_NAME, false, 0, true); - ManagedObject managedObj = exchange.getManagedObject(); - ManagedExchange mbean = (ManagedExchange)managedObj; - - // test general exchange properties - assertEquals("Unexpected exchange name", "amq.direct", mbean.getName()); - assertEquals("Unexpected exchange type", "direct", mbean.getExchangeType()); - assertEquals("Unexpected ticket number", Integer.valueOf(0), mbean.getTicketNo()); - assertFalse("Unexpected durable flag", mbean.isDurable()); - assertTrue("Unexpected auto delete flag", mbean.isAutoDelete()); - } - - public void testDirectExchangeMBean() throws Exception - { - DirectExchange exchange = new DirectExchange(); - exchange.initialise(UUIDGenerator.generateUUID(), _virtualHost, ExchangeDefaults.DIRECT_EXCHANGE_NAME, false, 0, true); - ManagedObject managedObj = exchange.getManagedObject(); - ManagedExchange mbean = (ManagedExchange)managedObj; - - mbean.createNewBinding(_queue.getNameShortString().toString(), "binding1"); - mbean.createNewBinding(_queue.getNameShortString().toString(), "binding2"); - - TabularData data = mbean.bindings(); - ArrayList<Object> list = new ArrayList<Object>(data.values()); - assertTrue(list.size() == 2); - } - - public void testTopicExchangeMBean() throws Exception - { - TopicExchange exchange = new TopicExchange(); - exchange.initialise(UUIDGenerator.generateUUID(), _virtualHost,ExchangeDefaults.TOPIC_EXCHANGE_NAME, false, 0, true); - ManagedObject managedObj = exchange.getManagedObject(); - ManagedExchange mbean = (ManagedExchange)managedObj; - - mbean.createNewBinding(_queue.getNameShortString().toString(), "binding1"); - mbean.createNewBinding(_queue.getNameShortString().toString(), "binding2"); - - TabularData data = mbean.bindings(); - ArrayList<Object> list = new ArrayList<Object>(data.values()); - assertTrue(list.size() == 2); - } - - public void testHeadersExchangeMBean() throws Exception - { - HeadersExchange exchange = new HeadersExchange(); - exchange.initialise(UUIDGenerator.generateUUID(), _virtualHost,ExchangeDefaults.HEADERS_EXCHANGE_NAME, false, 0, true); - ManagedObject managedObj = exchange.getManagedObject(); - ManagedExchange mbean = (ManagedExchange)managedObj; - - mbean.createNewBinding(_queue.getNameShortString().toString(), "x-match=any,key1=binding1,key2=binding2"); - - TabularData data = mbean.bindings(); - ArrayList<Object> list = new ArrayList<Object>(data.values()); - assertEquals("Unexpected number of bindings", 1, list.size()); - - final Iterator<CompositeDataSupport> rowItr = (Iterator<CompositeDataSupport>) data.values().iterator(); - CompositeDataSupport row = rowItr.next(); - assertBinding(1, _queue.getName(), new String[]{"x-match=any","key1=binding1","key2=binding2"}, row); - } - - /** - * Included to ensure 0-10 Specification compliance: - * 2.3.1.4 "the field in the bind arguments has no value and a field of the same name is present in the message headers - */ - public void testHeadersExchangeMBeanMatchPropertyNoValue() throws Exception - { - HeadersExchange exchange = new HeadersExchange(); - exchange.initialise(UUIDGenerator.generateUUID(), _virtualHost,ExchangeDefaults.HEADERS_EXCHANGE_NAME, false, 0, true); - ManagedObject managedObj = exchange.getManagedObject(); - ManagedExchange mbean = (ManagedExchange)managedObj; - - mbean.createNewBinding(_queue.getNameShortString().toString(), "x-match=any,key4,key5="); - - TabularData data = mbean.bindings(); - ArrayList<Object> list = new ArrayList<Object>(data.values()); - assertEquals("Unexpected number of bindings", 1, list.size()); - - final Iterator<CompositeDataSupport> rowItr = (Iterator<CompositeDataSupport>) data.values().iterator(); - CompositeDataSupport row = rowItr.next(); - assertBinding(1, _queue.getName(), new String[]{"x-match=any","key4=","key5="}, row); - } - - public void testInvalidHeaderBindingMalformed() throws Exception - { - HeadersExchange exchange = new HeadersExchange(); - exchange.initialise(UUIDGenerator.generateUUID(), _virtualHost,ExchangeDefaults.HEADERS_EXCHANGE_NAME, false, 0, true); - ManagedObject managedObj = exchange.getManagedObject(); - ManagedExchange mbean = (ManagedExchange)managedObj; - - try - { - mbean.createNewBinding(_queue.getNameShortString().toString(), "x-match=any,=value4"); - fail("Exception not thrown"); - } - catch (JMException jme) - { - //pass - } - } - - private void assertBinding(final int expectedBindingNo, final String expectedQueueName, final String[] expectedBindingArray, - final CompositeDataSupport row) - { - final Number bindingNumber = (Number) row.get(ManagedExchange.HDR_BINDING_NUMBER); - final String queueName = (String) row.get(ManagedExchange.HDR_QUEUE_NAME); - final String[] bindings = (String[]) row.get(ManagedExchange.HDR_QUEUE_BINDINGS); - assertEquals("Unexpected binding number", expectedBindingNo, bindingNumber); - assertEquals("Unexpected queue name", expectedQueueName, queueName); - assertEquals("Unexpected no of bindings", expectedBindingArray.length, bindings.length); - for(String binding : bindings) - { - assertTrue("Expected binding not found: " + binding, ArrayUtils.contains(expectedBindingArray, binding)); - } - } - - /** - * Test adding bindings and removing them from the default exchange via JMX. - * <p> - * QPID-2700 - */ - public void testDefaultBindings() throws Exception - { - int bindings = _queue.getBindingCount(); - - Exchange exchange = _queue.getVirtualHost().getExchangeRegistry().getDefaultExchange(); - ManagedExchange mbean = (ManagedExchange) ((AbstractExchange) exchange).getManagedObject(); - - mbean.createNewBinding(_queue.getName(), "robot"); - mbean.createNewBinding(_queue.getName(), "kitten"); - - assertEquals("Should have added two bindings", bindings + 2, _queue.getBindingCount()); - - mbean.removeBinding(_queue.getName(), "robot"); - - assertEquals("Should have one extra binding", bindings + 1, _queue.getBindingCount()); - - mbean.removeBinding(_queue.getName(), "kitten"); - - assertEquals("Should have original number of binding", bindings, _queue.getBindingCount()); - } - - /** - * Test adding bindings and removing them from the topic exchange via JMX. - * <p> - * QPID-2700 - */ - public void testTopicBindings() throws Exception - { - int bindings = _queue.getBindingCount(); - - Exchange exchange = _queue.getVirtualHost().getExchangeRegistry().getExchange(new AMQShortString("amq.topic")); - ManagedExchange mbean = (ManagedExchange) ((AbstractExchange) exchange).getManagedObject(); - - mbean.createNewBinding(_queue.getName(), "robot.#"); - mbean.createNewBinding(_queue.getName(), "#.kitten"); - - assertEquals("Should have added two bindings", bindings + 2, _queue.getBindingCount()); - - mbean.removeBinding(_queue.getName(), "robot.#"); - - assertEquals("Should have one extra binding", bindings + 1, _queue.getBindingCount()); - - mbean.removeBinding(_queue.getName(), "#.kitten"); - - assertEquals("Should have original number of binding", bindings, _queue.getBindingCount()); - } - - @Override - public void setUp() throws Exception - { - super.setUp(); - - IApplicationRegistry applicationRegistry = ApplicationRegistry.getInstance(); - _virtualHost = applicationRegistry.getVirtualHostRegistry().getVirtualHost("test"); - _queueRegistry = _virtualHost.getQueueRegistry(); - _queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("testQueue"), false, new AMQShortString("ExchangeMBeanTest"), false, false, - _virtualHost, null); - _queueRegistry.registerQueue(_queue); - } -} diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/HeadersBindingTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/HeadersBindingTest.java index 4305cdadc6..833df34fd8 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/HeadersBindingTest.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/HeadersBindingTest.java @@ -7,9 +7,9 @@ * 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 @@ -20,6 +20,7 @@ */ package org.apache.qpid.server.exchange; +import java.util.Collection; import junit.framework.TestCase; import org.apache.qpid.server.binding.Binding; @@ -50,6 +51,16 @@ public class HeadersBindingTest extends TestCase return 0; } + public String getUserId() + { + return null; + } + + public String getAppId() + { + return null; + } + public String getMessageId() { return null; @@ -57,7 +68,7 @@ public class HeadersBindingTest extends TestCase public String getMimeType() { - return null; //To change body of implemented methods use File | Settings | File Templates. + return null; } public String getEncoding() @@ -105,6 +116,12 @@ public class HeadersBindingTest extends TestCase return _headers.keySet().containsAll(names); } + @Override + public Collection<String> getHeaderNames() + { + return _headers.keySet(); + } + public boolean containsHeader(String name) { return _headers.containsKey(name); @@ -125,13 +142,13 @@ public class HeadersBindingTest extends TestCase private MockHeader matchHeaders = new MockHeader(); private int _count = 0; private MockAMQQueue _queue; - + protected void setUp() { _count++; _queue = new MockAMQQueue(getQueueName()); } - + protected String getQueueName() { return "Queue" + _count; diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/management/AMQUserManagementMBeanTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/management/AMQUserManagementMBeanTest.java deleted file mode 100644 index f7d85c11a8..0000000000 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/management/AMQUserManagementMBeanTest.java +++ /dev/null @@ -1,153 +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.management; - -import org.apache.qpid.management.common.mbeans.UserManagement; -import org.apache.qpid.server.security.auth.database.PlainPasswordFilePrincipalDatabase; -import org.apache.qpid.server.security.auth.management.AMQUserManagementMBean; -import org.apache.qpid.server.util.InternalBrokerBaseCase; - -import javax.management.openmbean.CompositeData; -import javax.management.openmbean.TabularData; -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; - -/** - * - * Tests the AMQUserManagementMBean and its interaction with the PrincipalDatabase. - * - */ -public class AMQUserManagementMBeanTest extends InternalBrokerBaseCase -{ - private PlainPasswordFilePrincipalDatabase _database; - private AMQUserManagementMBean _amqumMBean; - - private File _passwordFile; - - private static final String TEST_USERNAME = "testuser"; - private static final String TEST_PASSWORD = "password"; - - @Override - public void setUp() throws Exception - { - super.setUp(); - - _database = new PlainPasswordFilePrincipalDatabase(); - _amqumMBean = new AMQUserManagementMBean(); - loadFreshTestPasswordFile(); - } - - @Override - public void tearDown() throws Exception - { - //clean up test password/access files - File _oldPasswordFile = new File(_passwordFile.getAbsolutePath() + ".old"); - _oldPasswordFile.delete(); - _passwordFile.delete(); - - super.tearDown(); - } - - public void testDeleteUser() - { - assertEquals("Unexpected number of users before test", 1,_amqumMBean.viewUsers().size()); - assertTrue("Delete should return true to flag successful delete", _amqumMBean.deleteUser(TEST_USERNAME)); - assertEquals("Unexpected number of users after test", 0,_amqumMBean.viewUsers().size()); - } - - public void testDeleteUserWhereUserDoesNotExist() - { - assertEquals("Unexpected number of users before test", 1,_amqumMBean.viewUsers().size()); - assertFalse("Delete should return false to flag unsuccessful delete", _amqumMBean.deleteUser("made.up.username")); - assertEquals("Unexpected number of users after test", 1,_amqumMBean.viewUsers().size()); - - } - - public void testCreateUser() - { - assertEquals("Unexpected number of users before test", 1,_amqumMBean.viewUsers().size()); - assertTrue("Create should return true to flag successful create", _amqumMBean.createUser("newuser", "mypass")); - assertEquals("Unexpected number of users before test", 2,_amqumMBean.viewUsers().size()); - } - - public void testCreateUserWhereUserAlreadyExists() - { - assertEquals("Unexpected number of users before test", 1,_amqumMBean.viewUsers().size()); - assertFalse("Create should return false to flag unsuccessful create", _amqumMBean.createUser(TEST_USERNAME, "mypass")); - assertEquals("Unexpected number of users before test", 1,_amqumMBean.viewUsers().size()); - } - - public void testSetPassword() - { - assertTrue("Set password should return true to flag successful change", _amqumMBean.setPassword(TEST_USERNAME, "newpassword")); - } - - public void testSetPasswordWhereUserDoesNotExist() - { - assertFalse("Set password should return false to flag successful change", _amqumMBean.setPassword("made.up.username", "newpassword")); - } - - public void testViewUsers() - { - TabularData userList = _amqumMBean.viewUsers(); - - assertNotNull(userList); - assertEquals("Unexpected number of users in user list", 1, userList.size()); - assertTrue(userList.containsKey(new Object[]{TEST_USERNAME})); - - // Check the deprecated read, write and admin items continue to exist but return false. - CompositeData userRec = userList.get(new Object[]{TEST_USERNAME}); - assertTrue(userRec.containsKey(UserManagement.RIGHTS_READ_ONLY)); - assertEquals(false, userRec.get(UserManagement.RIGHTS_READ_ONLY)); - assertEquals(false, userRec.get(UserManagement.RIGHTS_READ_WRITE)); - assertTrue(userRec.containsKey(UserManagement.RIGHTS_READ_WRITE)); - assertTrue(userRec.containsKey(UserManagement.RIGHTS_ADMIN)); - assertEquals(false, userRec.get(UserManagement.RIGHTS_ADMIN)); - } - - // ============================ Utility methods ========================= - - private void loadFreshTestPasswordFile() - { - try - { - if(_passwordFile == null) - { - _passwordFile = File.createTempFile(this.getClass().getName(),".password"); - } - - BufferedWriter passwordWriter = new BufferedWriter(new FileWriter(_passwordFile, false)); - passwordWriter.write(TEST_USERNAME + ":" + TEST_PASSWORD); - passwordWriter.newLine(); - passwordWriter.flush(); - passwordWriter.close(); - _database.setPasswordFile(_passwordFile.toString()); - _amqumMBean.setPrincipalDatabase(_database); - } - catch (IOException e) - { - fail("Unable to create test password file: " + e.getMessage()); - } - } -} diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/model/impl/AbstractConfiguredObjectImplTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/model/impl/AbstractConfiguredObjectImplTest.java new file mode 100644 index 0000000000..62c8225049 --- /dev/null +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/model/impl/AbstractConfiguredObjectImplTest.java @@ -0,0 +1,188 @@ +/* + * + * 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.model.impl; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import junit.framework.TestCase; + +import org.apache.qpid.server.model.ConfigurationChangeListener; +import org.apache.qpid.server.model.ConfiguredObject; +import org.apache.qpid.server.model.LifetimePolicy; +import org.apache.qpid.server.model.State; +import org.apache.qpid.server.model.Statistics; + +public class AbstractConfiguredObjectImplTest extends TestCase +{ + + private ConfiguredObject _concreteObject; + private UUID _uuid = UUID.randomUUID(); + private ConfigurationChangeListener _configurationStateChangeListener = mock(ConfigurationChangeListener.class); + + @Override + protected void setUp() throws Exception + { + super.setUp(); + _concreteObject = createParentConfiguredObject(); + } + + public void testInitialState() + { + assertEquals(State.INITIALISING, _concreteObject.getDesiredState()); + } + + public void testStateNotifications() + { + _concreteObject.addChangeListener(_configurationStateChangeListener); + + _concreteObject.setDesiredState(State.INITIALISING, State.ACTIVE); + + verify(_configurationStateChangeListener, times(1)).stateChanged(_concreteObject, State.INITIALISING, State.ACTIVE); + + _concreteObject.setDesiredState(State.ACTIVE, State.ACTIVE); + + verify(_configurationStateChangeListener, times(0)).stateChanged(_concreteObject, State.ACTIVE, State.ACTIVE); + + verifyNoMoreInteractions(_configurationStateChangeListener); + } + + public void testSetGetAttribute() + { + assertNull(_concreteObject.getAttribute("test-attribute")); + + assertEquals(Integer.valueOf(1), _concreteObject.setAttribute("test-attribute", null, Integer.valueOf(1))); + assertEquals(Integer.valueOf(1), _concreteObject.getAttribute("test-attribute")); + + assertNull(_concreteObject.setAttribute("test-attribute", Integer.valueOf(1), null)); + assertNull(_concreteObject.getAttribute("test-attribute")); + } + + public void testSetAttributeWhenCurrentNotMatched() + { + assertEquals(Integer.valueOf(1), _concreteObject.setAttribute("test-attribute", null, Integer.valueOf(1))); + assertEquals(Integer.valueOf(1), _concreteObject.getAttribute("test-attribute")); + + assertEquals(Integer.valueOf(1), _concreteObject.setAttribute("test-attribute", Integer.valueOf(2), Integer.valueOf(3))); + assertEquals("Expected no change", Integer.valueOf(1), _concreteObject.getAttribute("test-attribute")); + } + + public void testParentage() + { + TestParentCO parentCO = createParentConfiguredObject(); + assertNull("Parent should have no parent", parentCO.getParent(TestParentCO.class)); + + Map<Class<? extends ConfiguredObject>, ConfiguredObject> parent = new HashMap<Class<? extends ConfiguredObject>, ConfiguredObject>(); + parent.put(TestParentCO.class, parentCO); + TestChildCO childCO = createChildConfiguredObject(parent); + + assertEquals("Child should have its parent", parentCO, childCO.getParent(TestParentCO.class)); + + TestParentCO stranger = createParentConfiguredObject(); + assertNotSame("Child should not have stranger as its parent", stranger, childCO.getParent(TestParentCO.class)); + + } + + private TestParentCO createParentConfiguredObject() + { + return new TestParentCO(_uuid, "parent1", State.INITIALISING, true, LifetimePolicy.PERMANENT, 0l, AbstractConfiguredObject.EMPTY_ATTRIBUTE_MAP); + } + + private TestChildCO createChildConfiguredObject(Map<Class<? extends ConfiguredObject>, ConfiguredObject> parents) + { + return new TestChildCO(_uuid, "parent1", State.INITIALISING, true, LifetimePolicy.PERMANENT, 0l, AbstractConfiguredObject.EMPTY_ATTRIBUTE_MAP, parents); + } + + private final class TestParentCO extends AbstractConfiguredObject + { + private TestParentCO(UUID id, String name, State state, boolean durable, LifetimePolicy lifetimePolicy, + long timeToLive, Map<String, Object> attributes) + { + super(id, name, state, durable, lifetimePolicy, timeToLive, attributes, EMPTY_PARENT_MAP); + } + + @Override + public State getActualState() + { + throw new UnsupportedOperationException(); + } + + @Override + protected Object getLock() + { + return this; + } + + @Override + public Statistics getStatistics() + { + return null; + } + + @Override + public <C extends ConfiguredObject> C createChild(Class<C> childClass, Map<String, Object> attributes, ConfiguredObject... otherParents) + { + return null; + } + } + + private final class TestChildCO extends AbstractConfiguredObject + { + private TestChildCO(UUID id, String name, State state, boolean durable, LifetimePolicy lifetimePolicy, + long timeToLive, Map<String, Object> attributes, + Map<Class<? extends ConfiguredObject>, ConfiguredObject> parents) + { + super(id, name, state, durable, lifetimePolicy, timeToLive, attributes, parents); + } + + @Override + public State getActualState() + { + throw new UnsupportedOperationException(); + } + + @Override + protected Object getLock() + { + return this; + } + + @Override + public Statistics getStatistics() + { + return null; + } + + @Override + public <C extends ConfiguredObject> C createChild(Class<C> childClass, Map<String, Object> attributes, ConfiguredObject... otherParents) + { + return null; + } + } + +} diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/model/impl/BrokerImplTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/model/impl/BrokerImplTest.java new file mode 100644 index 0000000000..0ffb6627ff --- /dev/null +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/model/impl/BrokerImplTest.java @@ -0,0 +1,106 @@ +/* + * + * 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.model.impl; + +import static org.apache.qpid.server.model.impl.AbstractConfiguredObject.EMPTY_ATTRIBUTE_MAP; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; + +import java.util.UUID; + +import junit.framework.TestCase; + +import org.apache.qpid.server.model.Broker; +import org.apache.qpid.server.model.ConfigurationChangeListener; +import org.apache.qpid.server.model.LifetimePolicy; +import org.apache.qpid.server.model.State; +import org.apache.qpid.server.model.VirtualHost; + +public class BrokerImplTest extends TestCase +{ + private Broker _broker; + private UUID _brokerUuid = UUID.randomUUID(); + private ConfigurationChangeListener _childAddedRemovedListener = mock(ConfigurationChangeListener.class); + + @Override + protected void setUp() throws Exception + { + super.setUp(); + createBroker(); + } + + public void testVirtualHostChildAddedAndDeletedNotifications() + { + _broker.addChangeListener(_childAddedRemovedListener); + + VirtualHost createdVirtualHost = _broker.createVirtualHost("vhost", State.INITIALISING, true, LifetimePolicy.PERMANENT, 0, EMPTY_ATTRIBUTE_MAP); + + verify(_childAddedRemovedListener).childAdded(_broker, createdVirtualHost); + verifyNoMoreInteractions(_childAddedRemovedListener); + + _broker.deleteVirtualHost(createdVirtualHost); + verify(_childAddedRemovedListener).childRemoved(_broker, createdVirtualHost); + + verifyNoMoreInteractions(_childAddedRemovedListener); + } + + public void testVirtualHostDeleteUnknownDisallowed() + { + try + { + _broker.deleteVirtualHost(mock(VirtualHost.class)); + fail("Exception not thrown"); + } + catch (IllegalArgumentException iae) + { + // PASS + } + } + + public void testVirtualHostDeletedTwiceDisallowed() + { + VirtualHost createdVirtualHost = _broker.createVirtualHost("vhost", State.INITIALISING, true, LifetimePolicy.PERMANENT, 0, EMPTY_ATTRIBUTE_MAP); + _broker.deleteVirtualHost(createdVirtualHost); + + try + { + _broker.deleteVirtualHost(createdVirtualHost); + fail("Exception not thrown"); + } + catch (IllegalArgumentException iae) + { + // PASS + } + } + + private void createBroker() + { + _broker = new BrokerImpl(_brokerUuid, + "broker1", + State.INITIALISING, + true, + LifetimePolicy.PERMANENT, + 0l, + EMPTY_ATTRIBUTE_MAP); + } +} diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/model/impl/VirtualHostImplTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/model/impl/VirtualHostImplTest.java new file mode 100644 index 0000000000..0cf70859e2 --- /dev/null +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/model/impl/VirtualHostImplTest.java @@ -0,0 +1,108 @@ +/* + * + * 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.model.impl; + +import static org.apache.qpid.server.model.impl.AbstractConfiguredObject.EMPTY_ATTRIBUTE_MAP; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; + +import java.util.UUID; + +import junit.framework.TestCase; + +import org.apache.qpid.server.model.Broker; +import org.apache.qpid.server.model.ConfigurationChangeListener; +import org.apache.qpid.server.model.Exchange; +import org.apache.qpid.server.model.LifetimePolicy; +import org.apache.qpid.server.model.Queue; +import org.apache.qpid.server.model.State; +import org.apache.qpid.server.model.VirtualHost; + +public class VirtualHostImplTest extends TestCase +{ + private VirtualHost _virtualHost; + private UUID _brokerUuid = UUID.randomUUID(); + private ConfigurationChangeListener _childAddedRemovedListener = mock(ConfigurationChangeListener.class); + + @Override + protected void setUp() throws Exception + { + super.setUp(); + createVirtualHost(); + } + + public void testQueueChildAddedAndDeletedNotifications() + { + _virtualHost.addChangeListener(_childAddedRemovedListener); + + Queue queue = _virtualHost.createQueue("queue", State.INITIALISING, true, false, LifetimePolicy.PERMANENT, 0, EMPTY_ATTRIBUTE_MAP); + + verify(_childAddedRemovedListener).childAdded(_virtualHost, queue); + verifyNoMoreInteractions(_childAddedRemovedListener); + + _virtualHost.deleteQueue(queue); + + verify(_childAddedRemovedListener).childRemoved(_virtualHost, queue); + verifyNoMoreInteractions(_childAddedRemovedListener); + } + + public void testExchangeChildAddedNotifications() + { + _virtualHost.addChangeListener(_childAddedRemovedListener); + + Exchange exchange = _virtualHost.createExchange("exchange", State.INITIALISING, true, LifetimePolicy.PERMANENT, 0L, "direct", EMPTY_ATTRIBUTE_MAP); + + verify(_childAddedRemovedListener).childAdded(_virtualHost, exchange); + verifyNoMoreInteractions(_childAddedRemovedListener); + } + + public void testQueueDeletedTwiceDisallowed() + { + Queue queue = _virtualHost.createQueue("queue", State.INITIALISING, true, false, LifetimePolicy.PERMANENT, 0, EMPTY_ATTRIBUTE_MAP); + + _virtualHost.deleteQueue(queue); + + try + { + _virtualHost.deleteQueue(queue); + fail("Exception not thrown"); + } + catch (IllegalArgumentException iae) + { + // PASS + } + } + + private void createVirtualHost() + { + Broker broker = new BrokerImpl(_brokerUuid, + "broker1", + State.INITIALISING, + true, + LifetimePolicy.PERMANENT, + 0l, + EMPTY_ATTRIBUTE_MAP); + + _virtualHost = broker.createVirtualHost("vhost1", State.INITIALISING, true, LifetimePolicy.PERMANENT, 0, EMPTY_ATTRIBUTE_MAP); + } +} diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBeanTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBeanTest.java deleted file mode 100644 index fe9bcc57a6..0000000000 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBeanTest.java +++ /dev/null @@ -1,146 +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.protocol; - -import org.apache.log4j.Logger; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.management.common.mbeans.ManagedConnection; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.queue.AMQQueueFactory; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.store.MessageStore; -import org.apache.qpid.server.store.TestableMemoryMessageStore; -import org.apache.qpid.server.util.InternalBrokerBaseCase; -import org.apache.qpid.server.virtualhost.VirtualHost; - -import javax.management.JMException; -import javax.management.openmbean.CompositeData; -import javax.management.openmbean.TabularData; - - -/** Test class to test MBean operations for AMQMinaProtocolSession. */ -public class AMQProtocolSessionMBeanTest extends InternalBrokerBaseCase -{ - /** Used for debugging. */ - private static final Logger log = Logger.getLogger(AMQProtocolSessionMBeanTest.class); - - private MessageStore _messageStore = new TestableMemoryMessageStore(); - private AMQProtocolEngine _protocolSession; - private AMQChannel _channel; - private AMQProtocolSessionMBean _mbean; - - public void testChannels() throws Exception - { - // check the channel count is correct - int channelCount = _mbean.channels().size(); - assertTrue(channelCount == 1); - AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("testQueue_" + System.currentTimeMillis()), - false, - new AMQShortString("test"), - true, - false, _protocolSession.getVirtualHost(), null); - AMQChannel channel = new AMQChannel(_protocolSession, 2, _messageStore); - channel.setDefaultQueue(queue); - _protocolSession.addChannel(channel); - channelCount = _mbean.channels().size(); - assertTrue(channelCount == 2); - - // general properties test - _protocolSession.setMaximumNumberOfChannels(1000L); - assertTrue(_mbean.getMaximumNumberOfChannels() == 1000L); - - // check APIs - AMQChannel channel3 = new AMQChannel(_protocolSession, 3, _messageStore); - channel3.setLocalTransactional(); - _protocolSession.addChannel(channel3); - _mbean.rollbackTransactions(2); - _mbean.rollbackTransactions(3); - _mbean.commitTransactions(2); - _mbean.commitTransactions(3); - - // This should throw exception, because the channel does't exist - try - { - _mbean.commitTransactions(4); - fail(); - } - catch (JMException ex) - { - log.debug("expected exception is thrown :" + ex.getMessage()); - } - - // check channels() return type conveys flow control blocking status correctly - AMQChannel channel4 = new AMQChannel(_protocolSession, 4, _messageStore); - _protocolSession.addChannel(channel4); - channel4.setDefaultQueue(queue); - - final String blocking = ManagedConnection.FLOW_BLOCKED; - TabularData channels = _mbean.channels(); - CompositeData chan4result = channels.get(new Integer[]{4}); - assertNotNull(chan4result); - assertEquals("Flow should not have been blocked", false, chan4result.get(blocking)); - - channel4.block(queue); - channels = _mbean.channels(); - chan4result = channels.get(new Integer[]{4}); - assertNotNull(chan4result); - assertEquals("Flow should have been blocked", true, chan4result.get(blocking)); - - channel4.unblock(queue); - channels = _mbean.channels(); - chan4result = channels.get(new Integer[]{4}); - assertNotNull(chan4result); - assertEquals("Flow should have been unblocked", false, chan4result.get(blocking)); - - // check if closing of session works - _protocolSession.addChannel(new AMQChannel(_protocolSession, 5, _messageStore)); - _mbean.closeConnection(); - try - { - channelCount = _mbean.channels().size(); - assertTrue(channelCount == 0); - // session is now closed so adding another channel should throw an exception - _protocolSession.addChannel(new AMQChannel(_protocolSession, 6, _messageStore)); - fail(); - } - catch (AMQException ex) - { - log.debug("expected exception is thrown :" + ex.getMessage()); - } - } - - @Override - public void setUp() throws Exception - { - super.setUp(); - - VirtualHost vhost = ApplicationRegistry.getInstance().getVirtualHostRegistry().getVirtualHost("test"); - _protocolSession = new InternalTestProtocolSession(vhost); - - _channel = new AMQChannel(_protocolSession, 1, _messageStore); - _protocolSession.addChannel(_channel); - _mbean = (AMQProtocolSessionMBean) _protocolSession.getManagedObject(); - } - -} diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueAlertTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueAlertTest.java deleted file mode 100644 index 25d35aab16..0000000000 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueAlertTest.java +++ /dev/null @@ -1,348 +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.queue; - -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.BasicContentHeaderProperties; -import org.apache.qpid.framing.ContentHeaderBody; -import org.apache.qpid.framing.abstraction.ContentChunk; -import org.apache.qpid.framing.abstraction.MessagePublishInfo; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.message.AMQMessage; -import org.apache.qpid.server.message.MessageMetaData; -import org.apache.qpid.server.protocol.InternalTestProtocolSession; -import org.apache.qpid.server.subscription.Subscription; -import org.apache.qpid.server.subscription.SubscriptionFactoryImpl; -import org.apache.qpid.server.util.InternalBrokerBaseCase; - -import javax.management.Notification; - -import java.nio.ByteBuffer; -import java.util.ArrayList; - -/** This class tests all the alerts an AMQQueue can throw based on threshold values of different parameters */ -public class AMQQueueAlertTest extends InternalBrokerBaseCase -{ - private final static long MAX_MESSAGE_COUNT = 50; - private final static long MAX_MESSAGE_AGE = 250; // 0.25 sec - private final static long MAX_MESSAGE_SIZE = 2000; // 2 KB - private final static long MAX_QUEUE_DEPTH = 10000; // 10 KB - private AMQQueueMBean _queueMBean; - private static final SubscriptionFactoryImpl SUBSCRIPTION_FACTORY = SubscriptionFactoryImpl.INSTANCE; - - /** - * Tests if the alert gets thrown when message count increases the threshold limit - * - * @throws Exception - */ - public void testMessageCountAlert() throws Exception - { - setSession(new InternalTestProtocolSession(getVirtualHost())); - AMQChannel channel = new AMQChannel(getSession(), 2, getMessageStore()); - getSession().addChannel(channel); - - setQueue(AMQQueueFactory.createAMQQueueImpl(new AMQShortString("testQueue1"), false, new AMQShortString("AMQueueAlertTest"), - false, false, - getVirtualHost(), null)); - _queueMBean = (AMQQueueMBean) getQueue().getManagedObject(); - - _queueMBean.setMaximumMessageCount(MAX_MESSAGE_COUNT); - - sendMessages(channel, MAX_MESSAGE_COUNT, 256l); - assertTrue(_queueMBean.getMessageCount() == MAX_MESSAGE_COUNT); - - Notification lastNotification = _queueMBean.getLastNotification(); - assertNotNull(lastNotification); - - String notificationMsg = lastNotification.getMessage(); - assertTrue(notificationMsg.startsWith(NotificationCheck.MESSAGE_COUNT_ALERT.name())); - } - - /** - * Tests if the Message Size alert gets thrown when message of higher than threshold limit is sent - * - * @throws Exception - */ - public void testMessageSizeAlert() throws Exception - { - setSession(new InternalTestProtocolSession(getVirtualHost())); - AMQChannel channel = new AMQChannel(getSession(), 2, getMessageStore()); - getSession().addChannel(channel); - - setQueue(AMQQueueFactory.createAMQQueueImpl(new AMQShortString("testQueue2"), false, new AMQShortString("AMQueueAlertTest"), - false, false, - getVirtualHost(), null)); - _queueMBean = (AMQQueueMBean) getQueue().getManagedObject(); - _queueMBean.setMaximumMessageCount(MAX_MESSAGE_COUNT); - _queueMBean.setMaximumMessageSize(MAX_MESSAGE_SIZE); - - sendMessages(channel, 1, MAX_MESSAGE_SIZE * 2); - assertTrue(_queueMBean.getMessageCount() == 1); - - Notification lastNotification = _queueMBean.getLastNotification(); - assertNotNull(lastNotification); - - String notificationMsg = lastNotification.getMessage(); - assertTrue(notificationMsg.startsWith(NotificationCheck.MESSAGE_SIZE_ALERT.name())); - } - - /** - * Tests if Queue Depth alert is thrown when queue depth reaches the threshold value - * - * Based on FT-402 subbmitted by client - * - * @throws Exception - */ - public void testQueueDepthAlertNoSubscriber() throws Exception - { - setSession(new InternalTestProtocolSession(getVirtualHost())); - AMQChannel channel = new AMQChannel(getSession(), 2, getMessageStore()); - getSession().addChannel(channel); - - setQueue(AMQQueueFactory.createAMQQueueImpl(new AMQShortString("testQueue3"), false, new AMQShortString("AMQueueAlertTest"), - false, false, - getVirtualHost(), null)); - _queueMBean = (AMQQueueMBean) getQueue().getManagedObject(); - _queueMBean.setMaximumMessageCount(MAX_MESSAGE_COUNT); - _queueMBean.setMaximumQueueDepth(MAX_QUEUE_DEPTH); - - while (getQueue().getQueueDepth() < MAX_QUEUE_DEPTH) - { - sendMessages(channel, 1, MAX_MESSAGE_SIZE); - } - - Notification lastNotification = _queueMBean.getLastNotification(); - assertNotNull(lastNotification); - - String notificationMsg = lastNotification.getMessage(); - assertTrue(notificationMsg.startsWith(NotificationCheck.QUEUE_DEPTH_ALERT.name())); - } - - /** - * Tests if MESSAGE AGE alert is thrown, when a message is in the queue for time higher than threshold value of - * message age - * - * Alternative test to FT-401 provided by client - * - * @throws Exception - */ - public void testMessageAgeAlert() throws Exception - { - setSession(new InternalTestProtocolSession(getVirtualHost())); - AMQChannel channel = new AMQChannel(getSession(), 2, getMessageStore()); - getSession().addChannel(channel); - - setQueue(AMQQueueFactory.createAMQQueueImpl(new AMQShortString("testQueue4"), false, new AMQShortString("AMQueueAlertTest"), - false, false, - getVirtualHost(), null)); - _queueMBean = (AMQQueueMBean) getQueue().getManagedObject(); - _queueMBean.setMaximumMessageCount(MAX_MESSAGE_COUNT); - _queueMBean.setMaximumMessageAge(MAX_MESSAGE_AGE); - - sendMessages(channel, 1, MAX_MESSAGE_SIZE); - - // Ensure message sits on queue long enough to age. - Thread.sleep(MAX_MESSAGE_AGE * 2); - - Notification lastNotification = _queueMBean.getLastNotification(); - assertNotNull("Last notification was null", lastNotification); - - String notificationMsg = lastNotification.getMessage(); - assertTrue(notificationMsg.startsWith(NotificationCheck.MESSAGE_AGE_ALERT.name())); - } - - /* - This test sends some messages to the queue with subscribers needing message to be acknowledged. - The messages will not be acknowledged and will be required twice. Why we are checking this is because - the bug reported said that the queueDepth keeps increasing when messages are requeued. - // TODO - queue depth now includes unacknowledged messages so does not go down when messages are delivered - - The QueueDepth should decrease when messages are delivered from the queue (QPID-408) - */ - public void testQueueDepthAlertWithSubscribers() throws Exception - { - AMQChannel channel = new AMQChannel(getSession(), 2, getMessageStore()); - getSession().addChannel(channel); - - // Create queue - setQueue(getNewQueue()); - Subscription subscription = - SUBSCRIPTION_FACTORY.createSubscription(channel.getChannelId(), getSession(), new AMQShortString("consumer_tag"), true, null, false, channel.getCreditManager()); - - getQueue().registerSubscription( - subscription, false); - - _queueMBean = (AMQQueueMBean) getQueue().getManagedObject(); - _queueMBean.setMaximumMessageCount(9999l); // Set a high value, because this is not being tested - _queueMBean.setMaximumQueueDepth(MAX_QUEUE_DEPTH); - - // Send messages(no of message to be little more than what can cause a Queue_Depth alert) - int messageCount = Math.round(MAX_QUEUE_DEPTH / MAX_MESSAGE_SIZE) + 10; - long totalSize = (messageCount * MAX_MESSAGE_SIZE); - sendMessages(channel, messageCount, MAX_MESSAGE_SIZE); - - // Check queueDepth. There should be no messages on the queue and as the subscriber is listening - // so there should be no Queue_Deoth alert raised - assertEquals(new Long(totalSize), new Long(_queueMBean.getQueueDepth())); - Notification lastNotification = _queueMBean.getLastNotification(); -// assertNull(lastNotification); - - // Kill the subscriber and check for the queue depth values. - // Messages are unacknowledged, so those should get requeued. All messages should be on the Queue - getQueue().unregisterSubscription(subscription); - channel.requeue(); - - assertEquals(new Long(totalSize), new Long(_queueMBean.getQueueDepth())); - - lastNotification = _queueMBean.getLastNotification(); - assertNotNull(lastNotification); - String notificationMsg = lastNotification.getMessage(); - assertTrue(notificationMsg.startsWith(NotificationCheck.QUEUE_DEPTH_ALERT.name())); - - // Connect a consumer again and check QueueDepth values. The queue should get emptied. - // Messages will get delivered but still are unacknowledged. - Subscription subscription2 = - SUBSCRIPTION_FACTORY.createSubscription(channel.getChannelId(), getSession(), new AMQShortString("consumer_tag"), true, null, false, channel.getCreditManager()); - - getQueue().registerSubscription( - subscription2, false); - - while (getQueue().getUndeliveredMessageCount()!= 0) - { - Thread.sleep(100); - } -// assertEquals(new Long(0), new Long(_queueMBean.getQueueDepth())); - - // Kill the subscriber again. Now those messages should get requeued again. Check if the queue depth - // value is correct. - getQueue().unregisterSubscription(subscription2); - channel.requeue(); - - assertEquals(new Long(totalSize), new Long(_queueMBean.getQueueDepth())); - getSession().closeSession(); - - // Check the clear queue - _queueMBean.clearQueue(); - assertEquals(new Long(0), new Long(_queueMBean.getQueueDepth())); - } - - protected IncomingMessage message(final boolean immediate, long size) throws AMQException - { - MessagePublishInfo publish = new MessagePublishInfo() - { - - public AMQShortString getExchange() - { - return null; - } - - public void setExchange(AMQShortString exchange) - { - //To change body of implemented methods use File | Settings | File Templates. - } - - public boolean isImmediate() - { - return immediate; - } - - public boolean isMandatory() - { - return false; - } - - public AMQShortString getRoutingKey() - { - return null; - } - }; - - ContentHeaderBody contentHeaderBody = new ContentHeaderBody(); - BasicContentHeaderProperties props = new BasicContentHeaderProperties(); - contentHeaderBody.setProperties(props); - contentHeaderBody.setBodySize(size); // in bytes - IncomingMessage message = new IncomingMessage(publish); - message.setContentHeaderBody(contentHeaderBody); - - return message; - } - - @Override - protected void configure() - { - // Increase Alert Check period - getConfiguration().setHousekeepingCheckPeriod(200); - } - - private void sendMessages(AMQChannel channel, long messageCount, final long size) throws AMQException - { - IncomingMessage[] messages = new IncomingMessage[(int) messageCount]; - MessageMetaData[] metaData = new MessageMetaData[(int) messageCount]; - for (int i = 0; i < messages.length; i++) - { - messages[i] = message(false, size); - ArrayList<AMQQueue> qs = new ArrayList<AMQQueue>(); - qs.add(getQueue()); - metaData[i] = messages[i].headersReceived(System.currentTimeMillis()); - messages[i].setStoredMessage(getMessageStore().addMessage(metaData[i])); - - messages[i].enqueue(qs); - - } - - for (int i = 0; i < messageCount; i++) - { - ContentChunk contentChunk = new ContentChunk() - { - private byte[] _data = new byte[(int)size]; - - public int getSize() - { - return (int) size; - } - - public byte[] getData() - { - return _data; - } - - public void reduceToFit() - { - } - }; - - messages[i].addContentBodyFrame(contentChunk); - messages[i].getStoredMessage().addContent(0, ByteBuffer.wrap(contentChunk.getData())); - - getQueue().enqueue(new AMQMessage(messages[i].getStoredMessage())); - } - } - - private AMQQueue getNewQueue() throws AMQException - { - return AMQQueueFactory.createAMQQueueImpl(new AMQShortString("testQueue" + Math.random()), - false, - new AMQShortString("AMQueueAlertTest"), - false, - false, getVirtualHost(), null); - } -} diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueMBeanTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueMBeanTest.java deleted file mode 100644 index 89c14c40a0..0000000000 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/AMQQueueMBeanTest.java +++ /dev/null @@ -1,546 +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.queue; - -import java.io.IOException; -import java.nio.ByteBuffer; -import java.text.SimpleDateFormat; -import java.util.*; -import javax.management.JMException; -import javax.management.openmbean.CompositeData; -import javax.management.openmbean.CompositeDataSupport; -import javax.management.openmbean.TabularData; -import org.apache.qpid.AMQException; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.framing.BasicContentHeaderProperties; -import org.apache.qpid.framing.ContentBody; -import org.apache.qpid.framing.ContentHeaderBody; -import org.apache.qpid.framing.abstraction.ContentChunk; -import org.apache.qpid.framing.abstraction.MessagePublishInfo; -import org.apache.qpid.management.common.mbeans.ManagedQueue; -import org.apache.qpid.server.AMQChannel; -import org.apache.qpid.server.message.AMQMessage; -import org.apache.qpid.server.message.MessageMetaData; -import org.apache.qpid.server.protocol.InternalTestProtocolSession; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.store.TestableMemoryMessageStore; -import org.apache.qpid.server.subscription.Subscription; -import org.apache.qpid.server.subscription.SubscriptionFactory; -import org.apache.qpid.server.subscription.SubscriptionFactoryImpl; -import org.apache.qpid.server.util.InternalBrokerBaseCase; - -/** - * Test class to test AMQQueueMBean attributes and operations - */ -public class AMQQueueMBeanTest extends InternalBrokerBaseCase -{ - private static long MESSAGE_SIZE = 1000; - private AMQQueueMBean _queueMBean; - private static final SubscriptionFactoryImpl SUBSCRIPTION_FACTORY = SubscriptionFactoryImpl.INSTANCE; - - public void testMessageCountTransient() throws Exception - { - int messageCount = 10; - sendMessages(messageCount, false); - assertTrue(_queueMBean.getMessageCount() == messageCount); - assertTrue(_queueMBean.getReceivedMessageCount() == messageCount); - long queueDepth = (messageCount * MESSAGE_SIZE); - assertTrue(_queueMBean.getQueueDepth() == queueDepth); - - _queueMBean.deleteMessageFromTop(); - assertTrue(_queueMBean.getMessageCount() == (messageCount - 1)); - assertTrue(_queueMBean.getReceivedMessageCount() == messageCount); - - _queueMBean.clearQueue(); - assertEquals(0,(int)_queueMBean.getMessageCount()); - assertTrue(_queueMBean.getReceivedMessageCount() == messageCount); - - //Ensure that the data has been removed from the Store - verifyBrokerState(); - } - - public void testMessageCountPersistent() throws Exception - { - int messageCount = 10; - sendMessages(messageCount, true); - assertEquals("", messageCount, _queueMBean.getMessageCount().intValue()); - assertTrue(_queueMBean.getReceivedMessageCount() == messageCount); - long queueDepth = (messageCount * MESSAGE_SIZE); - assertTrue(_queueMBean.getQueueDepth() == queueDepth); - - _queueMBean.deleteMessageFromTop(); - assertTrue(_queueMBean.getMessageCount() == (messageCount - 1)); - assertTrue(_queueMBean.getReceivedMessageCount() == messageCount); - - _queueMBean.clearQueue(); - assertTrue(_queueMBean.getMessageCount() == 0); - assertTrue(_queueMBean.getReceivedMessageCount() == messageCount); - - //Ensure that the data has been removed from the Store - verifyBrokerState(); - } - - public void testDeleteMessages() throws Exception - { - int messageCount = 10; - sendMessages(messageCount, true); - assertEquals("", messageCount, _queueMBean.getMessageCount().intValue()); - assertTrue(_queueMBean.getReceivedMessageCount() == messageCount); - long queueDepth = (messageCount * MESSAGE_SIZE); - assertTrue(_queueMBean.getQueueDepth() == queueDepth); - - //delete first message - _queueMBean.deleteMessages(1L,1L); - assertTrue(_queueMBean.getMessageCount() == (messageCount - 1)); - assertTrue(_queueMBean.getReceivedMessageCount() == messageCount); - try - { - _queueMBean.viewMessageContent(1L); - fail("Message should no longer be on the queue"); - } - catch(Exception e) - { - - } - - //delete last message, leaving 2nd to 9th - _queueMBean.deleteMessages(10L,10L); - assertTrue(_queueMBean.getMessageCount() == (messageCount - 2)); - assertTrue(_queueMBean.getReceivedMessageCount() == messageCount); - try - { - _queueMBean.viewMessageContent(10L); - fail("Message should no longer be on the queue"); - } - catch(Exception e) - { - - } - - //delete remaining messages, leaving none - _queueMBean.deleteMessages(2L,9L); - assertTrue(_queueMBean.getMessageCount() == (0)); - assertTrue(_queueMBean.getReceivedMessageCount() == messageCount); - - //Ensure that the data has been removed from the Store - verifyBrokerState(); - } - - - // todo: collect to a general testing class -duplicated from Systest/MessageReturntest - private void verifyBrokerState() - { - - TestableMemoryMessageStore store = (TestableMemoryMessageStore) getVirtualHost().getMessageStore(); - - // Unlike MessageReturnTest there is no need for a delay as there this thread does the clean up. - - assertEquals("Store should have no messages:" + store.getMessageCount(), 0, store.getMessageCount()); - } - - public void testConsumerCount() throws AMQException - { - - assertTrue(getQueue().getActiveConsumerCount() == 0); - assertTrue(_queueMBean.getActiveConsumerCount() == 0); - - - InternalTestProtocolSession protocolSession = new InternalTestProtocolSession(getVirtualHost()); - - AMQChannel channel = new AMQChannel(protocolSession, 1, getMessageStore()); - protocolSession.addChannel(channel); - - Subscription subscription = - SUBSCRIPTION_FACTORY.createSubscription(channel.getChannelId(), protocolSession, new AMQShortString("test"), false, null, false, channel.getCreditManager()); - - getQueue().registerSubscription(subscription, false); - assertEquals(1,(int)_queueMBean.getActiveConsumerCount()); - - - SubscriptionFactory subscriptionFactory = SUBSCRIPTION_FACTORY; - Subscription s1 = subscriptionFactory.createSubscription(channel.getChannelId(), - protocolSession, - new AMQShortString("S1"), - false, - null, - true, - channel.getCreditManager()); - - Subscription s2 = subscriptionFactory.createSubscription(channel.getChannelId(), - protocolSession, - new AMQShortString("S2"), - false, - null, - true, - channel.getCreditManager()); - getQueue().registerSubscription(s1,false); - getQueue().registerSubscription(s2,false); - assertTrue(_queueMBean.getActiveConsumerCount() == 3); - assertTrue(_queueMBean.getConsumerCount() == 3); - - s1.close(); - assertEquals(2, (int) _queueMBean.getActiveConsumerCount()); - assertTrue(_queueMBean.getConsumerCount() == 3); - } - - public void testGeneralProperties() throws Exception - { - long maxQueueDepth = 1000; // in bytes - _queueMBean.setMaximumMessageCount(50000l); - _queueMBean.setMaximumMessageSize(2000l); - _queueMBean.setMaximumQueueDepth(maxQueueDepth); - - assertEquals("Max MessageCount not set",50000,_queueMBean.getMaximumMessageCount().longValue()); - assertEquals("Max MessageSize not set",2000, _queueMBean.getMaximumMessageSize().longValue()); - assertEquals("Max QueueDepth not set",maxQueueDepth, _queueMBean.getMaximumQueueDepth().longValue()); - - assertEquals("Queue Name does not match", new AMQShortString(getName()), _queueMBean.getName()); - assertFalse("AutoDelete should not be set.",_queueMBean.isAutoDelete()); - assertFalse("Queue should not be durable.",_queueMBean.isDurable()); - - //set+get exclusivity using the mbean, and also verify it is actually updated in the queue - _queueMBean.setExclusive(true); - assertTrue("Exclusive property should be true.",_queueMBean.isExclusive()); - assertTrue("Exclusive property should be true.", getQueue().isExclusive()); - _queueMBean.setExclusive(false); - assertFalse("Exclusive property should be false.",_queueMBean.isExclusive()); - assertFalse("Exclusive property should be false.", getQueue().isExclusive()); - } - - /** - * Tests view messages with two test messages. The first message is non-persistent, the second persistent - * and has timestamp/expiration. - * - */ - public void testViewMessages() throws Exception - { - sendMessages(1, false); - final Date msg2Timestamp = new Date(); - final Date msg2Expiration = new Date(msg2Timestamp.getTime() + 1000); - sendMessages(1, true, msg2Timestamp.getTime(), msg2Expiration.getTime()); - - final TabularData tab = _queueMBean.viewMessages(1l, 2l); - assertEquals("Unexpected number of rows in table", 2, tab.size()); - final Iterator<CompositeDataSupport> rowItr = (Iterator<CompositeDataSupport>) tab.values().iterator(); - - // Check row1 - final CompositeDataSupport row1 = rowItr.next(); - assertEquals("Message should have AMQ message id", 1l, row1.get(ManagedQueue.MSG_AMQ_ID)); - assertNotNull("Expected message header array", row1.get(ManagedQueue.MSG_HEADER)); - final Map<String, String> row1Headers = headerArrayToMap((String[])row1.get(ManagedQueue.MSG_HEADER)); - assertEquals("Unexpected JMSPriority within header", "Non_Persistent", row1Headers.get("JMSDeliveryMode")); - assertEquals("Unexpected JMSTimestamp within header", "null", row1Headers.get("JMSTimestamp")); - assertEquals("Unexpected JMSExpiration within header", "null", row1Headers.get("JMSExpiration")); - - final CompositeDataSupport row2 = rowItr.next(); - assertEquals("Message should have AMQ message id", 2l, row2.get(ManagedQueue.MSG_AMQ_ID)); - assertNotNull("Expected message header array", row2.get(ManagedQueue.MSG_HEADER)); - final Map<String, String> row2Headers = headerArrayToMap((String[])row2.get(ManagedQueue.MSG_HEADER)); - assertEquals("Unexpected JMSPriority within header", "Persistent", row2Headers.get("JMSDeliveryMode")); - final SimpleDateFormat simpleDateFormat = new SimpleDateFormat(AMQQueueMBean.JMSTIMESTAMP_DATETIME_FORMAT); - assertEquals("Unexpected JMSTimestamp within header", msg2Timestamp, - simpleDateFormat.parse(row2Headers.get("JMSTimestamp"))); - assertEquals("Unexpected JMSExpiration within header", msg2Expiration, - simpleDateFormat.parse(row2Headers.get("JMSExpiration"))); - } - - public void testViewMessageWithIllegalStartEndRanges() throws Exception - { - try - { - _queueMBean.viewMessages(0L, 3L); - fail(); - } - catch (JMException ex) - { - // PASS - } - - try - { - _queueMBean.viewMessages(2L, 1L); - fail(); - } - catch (JMException ex) - { - // PASS - } - - try - { - _queueMBean.viewMessages(-1L, 1L); - fail(); - } - catch (JMException ex) - { - // PASS - } - - try - { - long end = Integer.MAX_VALUE; - end+=2; - _queueMBean.viewMessages(1L, end); - fail("Expected Exception due to oversized(> 2^31) message range"); - } - catch (JMException ex) - { - // PASS - } - } - - public void testViewMessageContent() throws Exception - { - final List<AMQMessage> sentMessages = sendMessages(1, true); - final Long id = sentMessages.get(0).getMessageId(); - - final CompositeData messageData = _queueMBean.viewMessageContent(id); - assertNotNull(messageData); - } - - public void testViewMessageContentWithUnknownMessageId() throws Exception - { - final List<AMQMessage> sentMessages = sendMessages(1, true); - final Long id = sentMessages.get(0).getMessageId(); - - try - { - _queueMBean.viewMessageContent(id + 1); - fail(); - } - catch (JMException ex) - { - // PASS - } - } - - public void testFlowControlProperties() throws Exception - { - assertTrue(_queueMBean.getCapacity() == 0); - assertTrue(_queueMBean.getFlowResumeCapacity() == 0); - assertFalse(_queueMBean.isFlowOverfull()); - - //capacity currently 0, try setting FlowResumeCapacity above this - try - { - _queueMBean.setFlowResumeCapacity(1L); - fail("Should have failed to allow setting FlowResumeCapacity above Capacity"); - } - catch (IllegalArgumentException ex) - { - //expected exception - assertTrue(_queueMBean.getFlowResumeCapacity() == 0); - } - - //add a message to the queue - sendMessages(1, true); - - //(FlowResume)Capacity currently 0, set both to 2 - _queueMBean.setCapacity(2L); - assertTrue(_queueMBean.getCapacity() == 2L); - _queueMBean.setFlowResumeCapacity(2L); - assertTrue(_queueMBean.getFlowResumeCapacity() == 2L); - - //Try setting Capacity below FlowResumeCapacity - try - { - _queueMBean.setCapacity(1L); - fail("Should have failed to allow setting Capacity below FlowResumeCapacity"); - } - catch (IllegalArgumentException ex) - { - //expected exception - assertTrue(_queueMBean.getCapacity() == 2); - } - - //create a channel and use it to exercise the capacity check mechanism - AMQChannel channel = new AMQChannel(getSession(), 1, getMessageStore()); - getQueue().checkCapacity(channel); - - assertTrue(_queueMBean.isFlowOverfull()); - assertTrue(channel.getBlocking()); - - //set FlowResumeCapacity to MESSAGE_SIZE and check queue is now underfull and channel unblocked - _queueMBean.setCapacity(MESSAGE_SIZE);//must increase capacity too - _queueMBean.setFlowResumeCapacity(MESSAGE_SIZE); - - assertFalse(_queueMBean.isFlowOverfull()); - assertFalse(channel.getBlocking()); - } - - public void testMaximumDeliveryCount() throws IOException - { - assertEquals("Unexpected default maximum delivery count", Integer.valueOf(0), _queueMBean.getMaximumDeliveryCount()); - } - - public void testViewAllMessages() throws Exception - { - final int messageCount = 5; - sendPersistentMessages(messageCount); - - - final TabularData messageTable = _queueMBean.viewMessages(1L, 5L); - assertNotNull("Message table should not be null", messageTable); - assertEquals("Unexpected number of rows", messageCount, messageTable.size()); - - - final Iterator rowIterator = messageTable.values().iterator(); - // Get its message ID - final CompositeDataSupport row1 = (CompositeDataSupport) rowIterator.next(); - final Long msgId = (Long) row1.get("AMQ MessageId"); - final Long queuePosition = (Long) row1.get("Queue Position"); - final Integer deliveryCount = (Integer) row1.get("Delivery Count"); - - assertNotNull("Row should have value for queue position", queuePosition); - assertNotNull("Row should have value for msgid", msgId); - assertNotNull("Row should have value for deliveryCount", deliveryCount); - } - - - @Override - public void setUp() throws Exception - { - super.setUp(); - - _queueMBean = new AMQQueueMBean(getQueue()); - } - - public void tearDown() - { - ApplicationRegistry.remove(); - } - - private void sendPersistentMessages(int messageCount) throws AMQException - { - sendMessages(messageCount, true); - assertEquals("Expected " + messageCount + " messages in the queue", messageCount, _queueMBean - .getMessageCount().intValue()); - } - - private List<AMQMessage> sendMessages(int messageCount, boolean persistent) throws AMQException - { - return sendMessages(messageCount, persistent, 0l, 0l); - } - - private List<AMQMessage> sendMessages(int messageCount, boolean persistent, long timestamp, long expiration) throws AMQException - { - final List<AMQMessage> sentMessages = new ArrayList<AMQMessage>(); - - for (int i = 0; i < messageCount; i++) - { - IncomingMessage currentMessage = createIncomingMessage(false, persistent, timestamp, expiration); - ArrayList<AMQQueue> qs = new ArrayList<AMQQueue>(); - qs.add(getQueue()); - currentMessage.enqueue(qs); - - // route header - MessageMetaData mmd = currentMessage.headersReceived(System.currentTimeMillis()); - - // Add the message to the store so we have something to test later - currentMessage.setStoredMessage(getMessageStore().addMessage(mmd)); - ContentChunk chunk = getSession().getMethodRegistry() - .getProtocolVersionMethodConverter() - .convertToContentChunk( - new ContentBody(new byte[(int) MESSAGE_SIZE])); - currentMessage.addContentBodyFrame(chunk); - currentMessage.getStoredMessage().addContent(0, ByteBuffer.wrap(chunk.getData())); - - AMQMessage m = new AMQMessage(currentMessage.getStoredMessage()); - for(BaseQueue q : currentMessage.getDestinationQueues()) - { - q.enqueue(m); - } - - sentMessages.add(m); - } - - return sentMessages; - } - - private IncomingMessage createIncomingMessage(final boolean immediate, boolean persistent, long timestamp, long expiration) throws AMQException - { - MessagePublishInfo publish = new MessagePublishInfo() - { - - public AMQShortString getExchange() - { - return null; - } - - public void setExchange(AMQShortString exchange) - { - } - - public boolean isImmediate() - { - return immediate; - } - - public boolean isMandatory() - { - return false; - } - - public AMQShortString getRoutingKey() - { - return null; - } - }; - - ContentHeaderBody contentHeaderBody = new ContentHeaderBody(); - contentHeaderBody.setBodySize(MESSAGE_SIZE); // in bytes - final BasicContentHeaderProperties props = new BasicContentHeaderProperties(); - contentHeaderBody.setProperties(props); - props.setDeliveryMode((byte) (persistent ? 2 : 1)); - if (timestamp > 0) - { - props.setTimestamp(timestamp); - } - if (expiration > 0) - { - props.setExpiration(expiration); - } - IncomingMessage msg = new IncomingMessage(publish); - msg.setContentHeaderBody(contentHeaderBody); - return msg; - } - - /** - * - * Utility method to convert array of Strings in the form x = y into a - * map with key/value x => y. - * - */ - private Map<String,String> headerArrayToMap(final String[] headerArray) - { - final Map<String, String> headerMap = new HashMap<String, String>(); - final List<String> headerList = Arrays.asList(headerArray); - for (Iterator<String> iterator = headerList.iterator(); iterator.hasNext();) - { - final String nameValuePair = iterator.next(); - final String[] nameValue = nameValuePair.split(" *= *", 2); - headerMap.put(nameValue[0], nameValue[1]); - } - return headerMap; - } - - -} diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockAMQQueue.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockAMQQueue.java index afaa417415..c1c200c43e 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockAMQQueue.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockAMQQueue.java @@ -29,13 +29,14 @@ import org.apache.qpid.server.configuration.QueueConfigType; import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.logging.LogSubject; -import org.apache.qpid.server.management.ManagedObject; import org.apache.qpid.server.message.ServerMessage; import org.apache.qpid.server.protocol.AMQSessionModel; import org.apache.qpid.server.security.AuthorizationHolder; import org.apache.qpid.server.subscription.Subscription; import org.apache.qpid.server.virtualhost.VirtualHost; +import java.util.Collection; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; @@ -51,7 +52,6 @@ public class MockAMQQueue implements AMQQueue private AuthorizationHolder _authorizationHolder; private AMQSessionModel _exclusiveOwner; - private AMQShortString _owner; private List<Binding> _bindings = new CopyOnWriteArrayList<Binding>(); private boolean _autoDelete; @@ -98,7 +98,12 @@ public class MockAMQQueue implements AMQQueue return "[MockAMQQueue]"; } - }; + }; + } + + public long getUnackedMessageBytes() + { + return 0; } public ConfigStore getConfigStore() @@ -121,6 +126,16 @@ public class MockAMQQueue implements AMQQueue return 0; } + public long getTotalDequeueCount() + { + return 0; + } + + public long getTotalEnqueueCount() + { + return 0; + } + public int getBindingCountHigh() { return 0; @@ -219,12 +234,27 @@ public class MockAMQQueue implements AMQQueue public void registerSubscription(Subscription subscription, boolean exclusive) throws AMQException { - + } public void unregisterSubscription(Subscription subscription) throws AMQException { - + + } + + public Collection<Subscription> getConsumers() + { + return Collections.emptyList(); + } + + public void addSubscriptionRegistrationListener(final SubscriptionRegistrationListener listener) + { + + } + + public void removeSubscriptionRegistrationListener(final SubscriptionRegistrationListener listener) + { + } public int getConsumerCount() @@ -283,7 +313,7 @@ public class MockAMQQueue implements AMQQueue } public int delete() throws AMQException - { + { _deleted = true; return getMessageCount(); } @@ -358,17 +388,17 @@ public class MockAMQQueue implements AMQQueue public void moveMessagesToAnotherQueue(long fromMessageId, long toMessageId, String queueName) { - + } public void copyMessagesToAnotherQueue(long fromMessageId, long toMessageId, String queueName) { - + } public void removeMessagesFromQueue(long fromMessageId, long toMessageId) { - + } public long getMaximumMessageSize() @@ -378,7 +408,7 @@ public class MockAMQQueue implements AMQQueue public void setMaximumMessageSize(long value) { - + } public long getMaximumMessageCount() @@ -388,7 +418,7 @@ public class MockAMQQueue implements AMQQueue public void setMaximumMessageCount(long value) { - + } public long getMaximumQueueDepth() @@ -398,7 +428,7 @@ public class MockAMQQueue implements AMQQueue public void setMaximumQueueDepth(long value) { - + } public long getMaximumMessageAge() @@ -408,7 +438,7 @@ public class MockAMQQueue implements AMQQueue public void setMaximumMessageAge(long maximumMessageAge) { - + } public long getMinimumAlertRepeatGap() @@ -418,7 +448,7 @@ public class MockAMQQueue implements AMQQueue public void deleteMessageFromTop() { - + } public long clearQueue() @@ -429,7 +459,7 @@ public class MockAMQQueue implements AMQQueue public void checkMessageStatus() throws AMQException { - + } public Set<NotificationCheck> getNotificationChecks() @@ -439,22 +469,22 @@ public class MockAMQQueue implements AMQQueue public void flushSubscription(Subscription sub) throws AMQException { - + } public void deliverAsync(Subscription sub) { - + } public void deliverAsync() { - + } public void stop() { - + } public boolean isExclusive() @@ -469,7 +499,7 @@ public class MockAMQQueue implements AMQQueue public void setAlternateExchange(Exchange exchange) { - + } public Map<String, Object> getArguments() @@ -481,11 +511,6 @@ public class MockAMQQueue implements AMQQueue { } - public ManagedObject getManagedObject() - { - return null; - } - public int compareTo(AMQQueue o) { return 0; @@ -503,7 +528,7 @@ public class MockAMQQueue implements AMQQueue public void setCapacity(long capacity) { - + } public long getFlowResumeCapacity() @@ -513,7 +538,7 @@ public class MockAMQQueue implements AMQQueue public void setFlowResumeCapacity(long flowResumeCapacity) { - + } public void configure(ConfigurationPlugin config) @@ -546,12 +571,6 @@ public class MockAMQQueue implements AMQQueue _exclusiveOwner = exclusiveOwner; } - - public String getResourceName() - { - return _name.toString(); - } - public boolean isOverfull() { return false; @@ -582,7 +601,7 @@ public class MockAMQQueue implements AMQQueue return 0; } - public void decrementUnackedMsgCount() + public void decrementUnackedMsgCount(QueueEntry queueEntry) { } @@ -599,7 +618,6 @@ public class MockAMQQueue implements AMQQueue public void setExclusive(boolean exclusive) { - } public int getMaximumDeliveryCount() @@ -611,11 +629,23 @@ public class MockAMQQueue implements AMQQueue { } - public void setAlternateExchange(String exchangeName) + public void visit(final QueueEntryVisitor visitor) { } - public void visit(final Visitor visitor) + @Override + public void setNotificationListener(NotificationListener listener) { } + + @Override + public void setDescription(String description) + { + } + + @Override + public String getDescription() + { + return null; + } } diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/NotificationCheckTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/NotificationCheckTest.java new file mode 100644 index 0000000000..df2de7f0e0 --- /dev/null +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/NotificationCheckTest.java @@ -0,0 +1,106 @@ +/* + * + * 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.queue; + +import static org.mockito.Matchers.contains; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyZeroInteractions; +import static org.mockito.Mockito.when; + +import static org.apache.qpid.server.queue.NotificationCheck.MESSAGE_AGE_ALERT; +import static org.apache.qpid.server.queue.NotificationCheck.MESSAGE_COUNT_ALERT; +import static org.apache.qpid.server.queue.NotificationCheck.MESSAGE_SIZE_ALERT; +import static org.apache.qpid.server.queue.NotificationCheck.QUEUE_DEPTH_ALERT; + + +import junit.framework.TestCase; + +import org.apache.qpid.server.message.ServerMessage; +import org.apache.qpid.server.queue.AMQQueue.NotificationListener; + +public class NotificationCheckTest extends TestCase +{ + + private ServerMessage<?> _message = mock(ServerMessage.class); + private AMQQueue _queue = mock(AMQQueue.class); + private NotificationListener _listener = mock(NotificationListener.class); + + public void testMessageCountAlertFires() throws Exception + { + when(_queue.getMaximumMessageCount()).thenReturn(1000l); + when(_queue.getMessageCount()).thenReturn(999, 1000, 1001); + + MESSAGE_COUNT_ALERT.notifyIfNecessary(_message, _queue, _listener); + verifyZeroInteractions(_listener); + + MESSAGE_COUNT_ALERT.notifyIfNecessary(_message, _queue, _listener); + verify(_listener).notifyClients(eq(MESSAGE_COUNT_ALERT), eq(_queue), eq("1000: Maximum count on queue threshold (1000) breached.")); + + MESSAGE_COUNT_ALERT.notifyIfNecessary(_message, _queue, _listener); + verify(_listener).notifyClients(eq(MESSAGE_COUNT_ALERT), eq(_queue), eq("1001: Maximum count on queue threshold (1000) breached.")); + } + + public void testMessageSizeAlertFires() throws Exception + { + when(_queue.getMaximumMessageSize()).thenReturn(1024l); + when(_message.getSize()).thenReturn(1023l, 1024l, 1025l); + + MESSAGE_SIZE_ALERT.notifyIfNecessary(_message, _queue, _listener); + verifyZeroInteractions(_listener); + + MESSAGE_SIZE_ALERT.notifyIfNecessary(_message, _queue, _listener); + verify(_listener).notifyClients(eq(MESSAGE_SIZE_ALERT), eq(_queue), contains("1024b : Maximum message size threshold (1024) breached.")); + + MESSAGE_SIZE_ALERT.notifyIfNecessary(_message, _queue, _listener); + verify(_listener).notifyClients(eq(MESSAGE_SIZE_ALERT), eq(_queue), contains("1025b : Maximum message size threshold (1024) breached.")); + } + + public void testMessageAgeAlertFires() throws Exception + { + long now = System.currentTimeMillis(); + when(_queue.getMaximumMessageAge()).thenReturn(1000l); + when(_queue.getOldestMessageArrivalTime()).thenReturn(now, now - 15000); + + MESSAGE_AGE_ALERT.notifyIfNecessary(_message, _queue, _listener); + verifyZeroInteractions(_listener); + + MESSAGE_AGE_ALERT.notifyIfNecessary(_message, _queue, _listener); + // Uses contains as first part of message is nondeterministic + verify(_listener).notifyClients(eq(MESSAGE_AGE_ALERT), eq(_queue), contains("s : Maximum age on queue threshold (1s) breached.")); + } + + public void testQueueDepthAlertFires() throws Exception + { + when(_queue.getMaximumQueueDepth()).thenReturn(1024l); + when(_queue.getQueueDepth()).thenReturn(1023l, 1024l, 2048l); + + QUEUE_DEPTH_ALERT.notifyIfNecessary(_message, _queue, _listener); + verifyZeroInteractions(_listener); + + QUEUE_DEPTH_ALERT.notifyIfNecessary(_message, _queue, _listener); + verify(_listener).notifyClients(eq(QUEUE_DEPTH_ALERT), eq(_queue), eq("1Kb : Maximum queue depth threshold (1Kb) breached.")); + + QUEUE_DEPTH_ALERT.notifyIfNecessary(_message, _queue, _listener); + verify(_listener).notifyClients(eq(QUEUE_DEPTH_ALERT), eq(_queue), eq("2Kb : Maximum queue depth threshold (1Kb) breached.")); + } +} diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SimpleAMQQueueTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SimpleAMQQueueTest.java index a8fad96063..3048ca3803 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SimpleAMQQueueTest.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SimpleAMQQueueTest.java @@ -21,6 +21,13 @@ package org.apache.qpid.server.queue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyZeroInteractions; +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Matchers.contains; +import static org.mockito.Matchers.eq; + import org.apache.commons.configuration.PropertiesConfiguration; import org.apache.qpid.AMQException; @@ -79,7 +86,6 @@ public class SimpleAMQQueueTest extends InternalBrokerBaseCase public void setExchange(AMQShortString exchange) { - //To change body of implemented methods use File | Settings | File Templates. } public boolean isImmediate() @@ -1096,7 +1102,7 @@ public class SimpleAMQQueueTest extends InternalBrokerBaseCase /** * Tests that entry in dequeued state are not enqueued and not delivered to subscription */ - public void testEqueueDequeuedEntry() + public void testEnqueueDequeuedEntry() { // create a queue where each even entry is considered a dequeued SimpleAMQQueue queue = new SimpleAMQQueue(UUIDGenerator.generateUUID(), new AMQShortString("test"), false, @@ -1231,6 +1237,39 @@ public class SimpleAMQQueueTest extends InternalBrokerBaseCase assertEquals("Unexpected active consumer count", 1, queue.getActiveConsumerCount()); } + public void testNotificationFiredOnEnqueue() throws Exception + { + AMQQueue.NotificationListener listener = mock(AMQQueue.NotificationListener.class); + + _queue.setNotificationListener(listener); + _queue.setMaximumMessageCount(2); + + _queue.enqueue(createMessage(new Long(24))); + verifyZeroInteractions(listener); + + _queue.enqueue(createMessage(new Long(25))); + + verify(listener, atLeastOnce()).notifyClients(eq(NotificationCheck.MESSAGE_COUNT_ALERT), eq(_queue), contains("Maximum count on queue threshold")); + } + + public void testNotificationFiredAsync() throws Exception + { + AMQQueue.NotificationListener listener = mock(AMQQueue.NotificationListener.class); + + _queue.enqueue(createMessage(new Long(24))); + _queue.enqueue(createMessage(new Long(25))); + _queue.enqueue(createMessage(new Long(26))); + + _queue.setNotificationListener(listener); + _queue.setMaximumMessageCount(2); + + verifyZeroInteractions(listener); + + _queue.checkMessageStatus(); + + verify(listener, atLeastOnce()).notifyClients(eq(NotificationCheck.MESSAGE_COUNT_ALERT), eq(_queue), contains("Maximum count on queue threshold")); + } + /** * A helper method to create a queue with given name * diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticatorTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticatorTest.java index f6675e917e..c0c55de92a 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticatorTest.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticatorTest.java @@ -32,6 +32,7 @@ import javax.management.remote.JMXPrincipal; import javax.security.auth.Subject; import javax.security.sasl.SaslException; import javax.security.sasl.SaslServer; +import java.net.InetSocketAddress; import java.util.Collections; /** @@ -47,7 +48,7 @@ public class RMIPasswordAuthenticatorTest extends TestCase protected void setUp() throws Exception { - _rmipa = new RMIPasswordAuthenticator(); + _rmipa = new RMIPasswordAuthenticator(new InetSocketAddress(5672)); _credentials = new String[] {USERNAME, PASSWORD}; } diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/store/DurableConfigurationStoreTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/store/DurableConfigurationStoreTest.java index 48e631a0f4..8ab32d9710 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/store/DurableConfigurationStoreTest.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/store/DurableConfigurationStoreTest.java @@ -1,3 +1,23 @@ +/* + * + * 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.store; import static org.mockito.Matchers.any; @@ -78,7 +98,7 @@ public class DurableConfigurationStoreTest extends QpidTestCase _exchangeId = UUIDGenerator.generateUUID(); _storeName = getName(); - _storePath = TMP_FOLDER + "/" + _storeName; + _storePath = TMP_FOLDER + File.separator + _storeName; FileUtils.delete(new File(_storePath), true); setTestSystemProperty("QPID_WORK", TMP_FOLDER); _configuration = mock(Configuration.class); @@ -172,7 +192,7 @@ public class DurableConfigurationStoreTest extends QpidTestCase _store.createQueue(queue); reopenStore(); - verify(_queueRecoveryHandler).queue(_queueId, getName(), getName() + "Owner", true, null); + verify(_queueRecoveryHandler).queue(_queueId, getName(), getName() + "Owner", true, null, null); } public void testCreateQueueAMQQueueFieldTable() throws Exception @@ -186,10 +206,29 @@ public class DurableConfigurationStoreTest extends QpidTestCase _store.createQueue(queue, arguments); reopenStore(); - verify(_queueRecoveryHandler).queue(_queueId, getName(), getName() + "Owner", true, arguments); + verify(_queueRecoveryHandler).queue(_queueId, getName(), getName() + "Owner", true, arguments, null); } - public void testUpdateQueue() throws Exception + public void testCreateQueueAMQQueueWithAlternateExchange() throws Exception + { + Exchange alternateExchange = createTestAlternateExchange(); + + AMQQueue queue = createTestQueue(getName(), getName() + "Owner", true, alternateExchange); + _store.createQueue(queue); + + reopenStore(); + verify(_queueRecoveryHandler).queue(_queueId, getName(), getName() + "Owner", true, null, alternateExchange.getId()); + } + + private Exchange createTestAlternateExchange() + { + UUID exchUuid = UUID.randomUUID(); + Exchange alternateExchange = mock(Exchange.class); + when(alternateExchange.getId()).thenReturn(exchUuid); + return alternateExchange; + } + + public void testUpdateQueueExclusivity() throws Exception { // create queue AMQQueue queue = createTestQueue(getName(), getName() + "Owner", true); @@ -204,7 +243,26 @@ public class DurableConfigurationStoreTest extends QpidTestCase _store.updateQueue(queue); reopenStore(); - verify(_queueRecoveryHandler).queue(_queueId, getName(), getName() + "Owner", false, arguments); + verify(_queueRecoveryHandler).queue(_queueId, getName(), getName() + "Owner", false, arguments, null); + } + + public void testUpdateQueueAlternateExchange() throws Exception + { + // create queue + AMQQueue queue = createTestQueue(getName(), getName() + "Owner", true); + Map<String, Object> attributes = new HashMap<String, Object>(); + attributes.put("x-qpid-dlq-enabled", Boolean.TRUE); + attributes.put("x-qpid-maximum-delivery-count", new Integer(10)); + FieldTable arguments = FieldTable.convertToFieldTable(attributes); + _store.createQueue(queue, arguments); + + // update the queue to have exclusive=false + Exchange alternateExchange = createTestAlternateExchange(); + queue = createTestQueue(getName(), getName() + "Owner", false, alternateExchange); + _store.updateQueue(queue); + + reopenStore(); + verify(_queueRecoveryHandler).queue(_queueId, getName(), getName() + "Owner", false, arguments, alternateExchange.getId()); } public void testRemoveQueue() throws Exception @@ -221,17 +279,23 @@ public class DurableConfigurationStoreTest extends QpidTestCase _store.removeQueue(queue); reopenStore(); verify(_queueRecoveryHandler, never()).queue(any(UUID.class), anyString(), anyString(), anyBoolean(), - any(FieldTable.class)); + any(FieldTable.class), any(UUID.class)); } private AMQQueue createTestQueue(String queueName, String queueOwner, boolean exclusive) throws AMQStoreException { + return createTestQueue(queueName, queueOwner, exclusive, null); + } + + private AMQQueue createTestQueue(String queueName, String queueOwner, boolean exclusive, Exchange alternateExchange) throws AMQStoreException + { AMQQueue queue = mock(AMQQueue.class); when(queue.getName()).thenReturn(queueName); when(queue.getNameShortString()).thenReturn(AMQShortString.valueOf(queueName)); when(queue.getOwner()).thenReturn(AMQShortString.valueOf(queueOwner)); when(queue.isExclusive()).thenReturn(exclusive); when(queue.getId()).thenReturn(_queueId); + when(queue.getAlternateExchange()).thenReturn(alternateExchange); return queue; } diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/store/MessageStoreTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/store/MessageStoreTest.java index 64048d294b..93f3701c85 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/store/MessageStoreTest.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/store/MessageStoreTest.java @@ -99,7 +99,7 @@ public class MessageStoreTest extends InternalBrokerBaseCase { super.setUp(); - String storePath = System.getProperty("QPID_WORK") + "/" + getName(); + String storePath = System.getProperty("QPID_WORK") + File.separator + getName(); _config = new PropertiesConfiguration(); _config.addProperty("store.class", getTestProfileMessageStoreClassName()); @@ -267,15 +267,9 @@ public class MessageStoreTest extends InternalBrokerBaseCase //Validate normally expected properties of Queues/Topics validateDurableQueueProperties(); - //Update the durable exclusive queue's exclusivity and verify it is persisted and recovered correctly + //Update the durable exclusive queue's exclusivity setQueueExclusivity(false); validateQueueExclusivityProperty(false); - - //Reload the Virtualhost to recover the queues again - reloadVirtualHost(); - - //verify the change was persisted and recovered correctly - validateQueueExclusivityProperty(false); } /** diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/store/OperationalLoggingListenerTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/store/OperationalLoggingListenerTest.java index c6ef35d255..24e8b591e0 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/store/OperationalLoggingListenerTest.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/store/OperationalLoggingListenerTest.java @@ -147,6 +147,12 @@ public class OperationalLoggingListenerTest extends TestCase { _eventManager.addEventListener(eventListener, events); } + + @Override + public String getStoreType() + { + return "TEST"; + } } private static class TestActor implements LogActor diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/subscription/MockSubscription.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/subscription/MockSubscription.java index 5ba9c0c015..0aa0569b07 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/subscription/MockSubscription.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/subscription/MockSubscription.java @@ -1,5 +1,3 @@ -package org.apache.qpid.server.subscription; - /* * * Licensed to the Apache Software Foundation (ASF) under one @@ -21,16 +19,24 @@ package org.apache.qpid.server.subscription; * */ +package org.apache.qpid.server.subscription; + import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.AMQChannel; +import org.apache.qpid.protocol.AMQConstant; import org.apache.qpid.server.logging.LogActor; +import org.apache.qpid.server.logging.LogSubject; +import org.apache.qpid.server.message.InboundMessage; +import org.apache.qpid.server.protocol.AMQConnectionModel; +import org.apache.qpid.server.protocol.AMQSessionModel; import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.QueueEntry; import org.apache.qpid.server.queue.QueueEntry.SubscriptionAcquiredState; +import org.apache.qpid.server.stats.StatisticsCounter; import java.util.ArrayList; import java.util.List; +import java.util.UUID; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; @@ -76,19 +82,9 @@ public class MockSubscription implements Subscription _state = State.CLOSED; } - public boolean filtersMessages() - { - return false; - } - - public AMQChannel getChannel() - { - return null; - } - - public AMQShortString getConsumerTag() + public String getConsumerName() { - return tag; + return tag == null ? null : tag.asString(); } public long getSubscriptionID() @@ -121,11 +117,36 @@ public class MockSubscription implements Subscription return false; } + public long getBytesOut() + { + return 0; // TODO - Implement + } + + public long getMessagesOut() + { + return 0; // TODO - Implement + } + + public long getUnacknowledgedBytes() + { + return 0; // TODO - Implement + } + + public long getUnacknowledgedMessages() + { + return 0; // TODO - Implement + } + public AMQQueue getQueue() { return queue; } + public AMQSessionModel getSessionModel() + { + return new MockSessionModel(); + } + public boolean trySendLock() { return _stateChangeLock.tryLock(); @@ -154,11 +175,6 @@ public class MockSubscription implements Subscription return _isActive ; } - public void confirmAutoClose() - { - - } - public void set(String key, Object value) { } @@ -173,11 +189,6 @@ public class MockSubscription implements Subscription return false; } - public boolean isBrowser() - { - return false; - } - public boolean isClosed() { return _closed; @@ -207,10 +218,6 @@ public class MockSubscription implements Subscription _stateChangeLock.unlock(); } - public void resend(QueueEntry entry) throws AMQException - { - } - public void onDequeue(QueueEntry queueEntry) { } @@ -232,7 +239,6 @@ public class MockSubscription implements Subscription messages.add(entry); } - @Override public void flushBatched() { @@ -249,7 +255,7 @@ public class MockSubscription implements Subscription } public void setNoLocal(boolean noLocal) - { + { } public void setStateListener(StateListener listener) @@ -285,4 +291,259 @@ public class MockSubscription implements Subscription { _isActive = isActive; } + + private static class MockSessionModel implements AMQSessionModel + { + + @Override + public int compareTo(AMQSessionModel o) + { + return 0; + } + + @Override + public UUID getId() + { + return null; + } + + @Override + public AMQConnectionModel getConnectionModel() + { + return new MockConnectionModel(); + } + + @Override + public String getClientID() + { + return null; + } + + @Override + public void close() throws AMQException + { + } + + @Override + public LogSubject getLogSubject() + { + return null; + } + + @Override + public void checkTransactionStatus(long openWarn, long openClose, + long idleWarn, long idleClose) throws AMQException + { + } + + @Override + public void block(AMQQueue queue) + { + } + + @Override + public void unblock(AMQQueue queue) + { + } + + @Override + public void block() + { + } + + @Override + public void unblock() + { + } + + @Override + public boolean getBlocking() + { + return false; + } + + @Override + public boolean onSameConnection(InboundMessage inbound) + { + return false; + } + + @Override + public int getUnacknowledgedMessageCount() + { + return 0; + } + + @Override + public Long getTxnCount() + { + return null; + } + + @Override + public Long getTxnStart() + { + return null; + } + + @Override + public Long getTxnCommits() + { + return null; + } + + @Override + public Long getTxnRejects() + { + return null; + } + + @Override + public int getChannelId() + { + return 0; + } + } + + private static class MockConnectionModel implements AMQConnectionModel + { + @Override + public void initialiseStatistics() + { + } + + @Override + public void registerMessageReceived(long messageSize, long timestamp) + { + } + + @Override + public void registerMessageDelivered(long messageSize) + { + } + + @Override + public StatisticsCounter getMessageDeliveryStatistics() + { + return null; + } + + @Override + public StatisticsCounter getMessageReceiptStatistics() + { + return null; + } + + @Override + public StatisticsCounter getDataDeliveryStatistics() + { + return null; + } + + @Override + public StatisticsCounter getDataReceiptStatistics() + { + return null; + } + + @Override + public void resetStatistics() + { + + } + + @Override + public UUID getId() + { + return null; + } + + @Override + public void close(AMQConstant cause, String message) + throws AMQException + { + } + + @Override + public void closeSession(AMQSessionModel session, AMQConstant cause, + String message) throws AMQException + { + } + + @Override + public long getConnectionId() + { + return 0; + } + + @Override + public List<AMQSessionModel> getSessionModels() + { + return null; + } + + @Override + public void block() + { + } + + @Override + public void unblock() + { + } + + @Override + public LogSubject getLogSubject() + { + return null; + } + + @Override + public String getUserName() + { + return null; + } + + @Override + public boolean isSessionNameUnique(byte[] name) + { + return false; + } + + @Override + public String getRemoteAddressString() + { + return "remoteAddress:1234"; + } + + @Override + public String getClientId() + { + return null; + } + + @Override + public String getClientVersion() + { + return null; + } + + @Override + public String getPrincipalAsString() + { + return null; + } + + @Override + public long getSessionCountLimit() + { + return 0; + } + + @Override + public long getLastIoTime() + { + return 0; + } + } } diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/transport/ServerConnectionMBeanTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/transport/ServerConnectionMBeanTest.java deleted file mode 100644 index b0b81355ac..0000000000 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/transport/ServerConnectionMBeanTest.java +++ /dev/null @@ -1,231 +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.transport; - -import org.apache.qpid.management.common.mbeans.ManagedConnection; -import org.apache.qpid.server.configuration.MockConnectionConfig; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.util.InternalBrokerBaseCase; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.transport.Binary; -import org.apache.qpid.transport.Connection; -import org.apache.qpid.transport.Session; - -import javax.management.JMException; -import javax.management.openmbean.CompositeData; -import javax.management.openmbean.TabularData; -import java.net.InetSocketAddress; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Date; -import java.util.List; -import java.util.UUID; -import java.util.concurrent.atomic.AtomicLong; - -public class ServerConnectionMBeanTest extends InternalBrokerBaseCase -{ - private ServerConnection _serverConnection; - private ServerSessionMock _serverSession; - private ServerConnectionMBean _mbean; - private List<Session> _sessions = new ArrayList<Session>(); - - @Override - public void setUp() throws Exception - { - super.setUp(); - - final VirtualHost vhost = ApplicationRegistry.getInstance().getVirtualHostRegistry().getVirtualHost("test"); - _serverConnection = new ServerConnection(1) - { - protected Collection<Session> getChannels() - { - return _sessions; - } - public Session getSession(int channelId) - { - for(Session session : _sessions) - { - if (session.getChannel() == channelId) - { - return session; - } - } - return null; - } - @Override - public AtomicLong getLastIoTime() - { - return new AtomicLong(1); - } - }; - final MockConnectionConfig config = new MockConnectionConfig(UUID.randomUUID(), null, null, - false, 1, vhost, "address", Boolean.TRUE, Boolean.TRUE, Boolean.TRUE, - "authid", "remoteProcessName", new Integer(1967), new Integer(1970), vhost.getConfigStore(), Boolean.FALSE); - _serverConnection.setConnectionConfig(config); - _serverConnection.setVirtualHost(vhost); - _serverConnection.setConnectionDelegate(new ServerConnectionDelegate(getRegistry(), "", getRegistry().getAuthenticationManager(new InetSocketAddress(5672)))); - _serverSession = new ServerSessionMock(_serverConnection, 1); - _mbean = (ServerConnectionMBean) _serverConnection.getManagedObject(); - } - - public void testChannels() throws Exception - { - // check the channel count is correct - TabularData tabularData = _mbean.channels(); - - int channelCount = tabularData.size(); - assertEquals("Unexpected number of channels",1,channelCount); - _sessions.add(new ServerSession(_serverConnection, new ServerSessionDelegate(), - new Binary(getName().getBytes()), 2 , _serverConnection.getConfig())); - - channelCount = _mbean.channels().size(); - assertEquals("Unexpected number of channels",2,channelCount); - - final CompositeData chanresult = tabularData.get(new Integer[]{1}); - assertNotNull(chanresult); - assertEquals("Unexpected channel id", new Integer(1),(Integer)chanresult.get(ManagedConnection.CHAN_ID)); - assertNull("Unexpected default queue", chanresult.get(ManagedConnection.DEFAULT_QUEUE)); - assertFalse("Unexpected transactional flag", (Boolean)chanresult.get(ManagedConnection.TRANSACTIONAL)); - assertFalse("Flow should have been blocked", (Boolean)chanresult.get(ManagedConnection.FLOW_BLOCKED)); - assertEquals("Unexpected unack'd count", new Integer(1967), (Integer)chanresult.get(ManagedConnection.UNACKED_COUNT)); - } - - public void testMaxChannels() throws Exception - { - _serverConnection.getConnectionDelegate().setChannelMax(10001); - assertEquals("Max channels not got correctly", new Long(10001), _mbean.getMaximumNumberOfChannels()); - } - - public void testRollback() throws Exception - { - _mbean.rollbackTransactions(1); - assertFalse("Rollback performed despite not being transacted", _serverSession.isRolledback()); - - _serverSession.setTransactional(true); - _mbean.rollbackTransactions(1); - assertTrue("Rollback not performed", _serverSession.isRolledback()); - - try - { - _mbean.rollbackTransactions(2); - fail("Exception expected"); - } - catch (JMException jme) - { - //pass - } - } - - public void testCommit() throws Exception - { - _mbean.commitTransactions(1); - assertFalse("Commit performed despite not being transacted", _serverSession.isCommitted()); - - _serverSession.setTransactional(true); - _mbean.commitTransactions(1); - assertTrue("Commit not performed", _serverSession.isCommitted()); - - try - { - _mbean.commitTransactions(2); - fail("Exception expected"); - } - catch (JMException jme) - { - //pass - } - } - - public void testGetName() - { - assertEquals("Unexpected Object Instance Name", "\"address\"", _mbean.getObjectInstanceName()); - } - - public void testEnableStatistics() - { - assertFalse("Unexpected statistics enable flag", _mbean.isStatisticsEnabled()); - _mbean.setStatisticsEnabled(true); - assertTrue("Unexpected statistics enable flag", _mbean.isStatisticsEnabled()); - } - - public void testLastIOTime() - { - assertEquals("Unexpected last IO time", new Date(1), _mbean.getLastIoTime()); - } - - private class ServerSessionMock extends ServerSession - { - private int _channelId = 0; - private boolean _committed = false; - private boolean _rolledback = false; - private boolean _transacted = false; - - ServerSessionMock(Connection connection, int channelId) - { - super(connection, new ServerSessionDelegate(), new Binary(String.valueOf(channelId).getBytes()), 1 , _serverConnection.getConfig()); - _channelId = channelId; - _sessions.add(this); - } - - public int getChannel() - { - return _channelId; - } - - @Override - public void commit() - { - _committed = true; - } - - @Override - public void rollback() - { - _rolledback = true; - } - - public boolean isCommitted() - { - return _committed; - } - - public boolean isRolledback() - { - return _rolledback; - } - - @Override - public int getUnacknowledgedMessageCount() - { - return 1967; - } - - public boolean isTransactional() - { - return _transacted; - } - - public void setTransactional(boolean transacted) - { - _transacted = transacted; - } - } -} diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/txn/MockStoreTransaction.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/txn/MockStoreTransaction.java index af49238998..0221f3d509 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/txn/MockStoreTransaction.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/txn/MockStoreTransaction.java @@ -124,6 +124,12 @@ class MockStoreTransaction implements Transaction storeTransaction.setState(TransactionState.STARTED); return storeTransaction; } + + @Override + public String getStoreType() + { + return "TEST"; + } }; } }
\ No newline at end of file diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/util/TestApplicationRegistry.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/util/TestApplicationRegistry.java index 9bd69e3889..a64ab620ab 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/util/TestApplicationRegistry.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/util/TestApplicationRegistry.java @@ -21,6 +21,8 @@ package org.apache.qpid.server.util; import java.net.SocketAddress; +import java.util.Collections; +import java.util.Map; import org.apache.commons.configuration.ConfigurationException; import org.apache.qpid.server.configuration.ServerConfiguration; @@ -101,6 +103,17 @@ public class TestApplicationRegistry extends ApplicationRegistry { return pdam; } + + @Override + public Map<String, AuthenticationManager> getAvailableAuthenticationManagers() + { + return Collections.singletonMap(pdam.getClass().getName(), pdam); + } + + @Override + public void addRegistryChangeListener(RegistryChangeListener listener) + { + } }; } } diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/virtualhost/MockVirtualHost.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/virtualhost/MockVirtualHost.java index 58c7625ad6..df31845798 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/virtualhost/MockVirtualHost.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/virtualhost/MockVirtualHost.java @@ -32,7 +32,6 @@ import org.apache.qpid.server.connection.IConnectionRegistry; import org.apache.qpid.server.exchange.ExchangeFactory; import org.apache.qpid.server.exchange.ExchangeRegistry; import org.apache.qpid.server.federation.BrokerLink; -import org.apache.qpid.server.management.ManagedObject; import org.apache.qpid.server.protocol.v1_0.LinkRegistry; import org.apache.qpid.server.queue.QueueRegistry; import org.apache.qpid.server.registry.IApplicationRegistry; @@ -141,11 +140,6 @@ public class MockVirtualHost implements VirtualHost return 0; } - public ManagedObject getManagedObject() - { - return null; - } - public MessageStore getMessageStore() { return null; @@ -257,11 +251,6 @@ public class MockVirtualHost implements VirtualHost } - public boolean isStatisticsEnabled() - { - return false; - } - public void registerMessageDelivered(long messageSize) { @@ -277,11 +266,6 @@ public class MockVirtualHost implements VirtualHost } - public void setStatisticsEnabled(boolean enabled) - { - - } - public State getState() { return State.ACTIVE; diff --git a/qpid/java/build.deps b/qpid/java/build.deps index 5b0d23f8cc..45e1f80ef8 100644 --- a/qpid/java/build.deps +++ b/qpid/java/build.deps @@ -34,6 +34,7 @@ geronimo-jta=lib/required/geronimo-jta_1.1_spec-1.1.1.jar geronimo-kernel=lib/required/geronimo-kernel-2.2.1.jar geronimo-openejb=lib/required/geronimo-ejb_3.0_spec-1.0.1.jar geronimo-servlet=lib/required/geronimo-servlet_2.5_spec-1.2.jar +#servlet-api=lib/required/geronimo-servlet_3.0_spec-1.0.jar junit=lib/required/junit-3.8.1.jar mockito-all=lib/required/mockito-all-1.9.0.jar @@ -47,6 +48,18 @@ slf4j-log4j=lib/required/slf4j-log4j12-1.6.4.jar xalan=lib/required/xalan-2.7.0.jar +jetty=lib/required/jetty-server-7.6.3.v20120416.jar +jetty-continuation=lib/required/jetty-continuation-7.6.3.v20120416.jar +jetty-security=lib/required/jetty-security-7.6.3.v20120416.jar +jetty-util=lib/required/jetty-util-7.6.3.v20120416.jar +jetty-io=lib/required/jetty-io-7.6.3.v20120416.jar +jetty-http=lib/required/jetty-http-7.6.3.v20120416.jar +jetty-servlet=lib/required/jetty-servlet-7.6.3.v20120416.jar +jetty-websocket=lib/required/jetty-websocket-7.6.3.v20120416.jar +servlet-api=${geronimo-servlet} + +dojo=lib/required/dojo-war-1.7.2.war + felix-main=lib/required/org.apache.felix.main-2.0.5.jar felix.libs=${felix-main} @@ -65,8 +78,9 @@ amqp-1-0-client-jms.libs=${geronimo-jms} tools.libs=${commons-configuration.libs} ${log4j} broker.libs=${commons-cli} ${commons-logging} ${log4j} ${slf4j-log4j} \ ${xalan} ${felix.libs} ${derby-db} ${commons-configuration.libs} \ - ${jackson-core} ${jackson-mapper} + ${jackson-core} ${jackson-mapper} ${jetty} ${jetty-continuation} ${jetty-security} ${jetty-http} ${jetty-io} ${jetty-servlet} ${jetty-util} ${servlet-api} ${jetty-websocket} +broker-plugins-management.libs=${jetty} ${jetty-continuation} ${jetty-security} ${jetty-http} ${jetty-io} ${jetty-servlet} ${jetty-util} ${servlet-api} ${jackson-core} ${jackson-mapper} broker-plugins.libs=${felix.libs} ${log4j} ${commons-configuration.libs} test.libs=${slf4j-log4j} ${log4j} ${junit} ${slf4j-api} ${mockito-all} @@ -154,6 +168,9 @@ bdb-je=lib/bdbstore/je-5.0.55.jar bdbstore.libs=${bdb-je} bdbstore.test.libs=${test.libs} +bdbstore-jmx.libs=${bdb-je} +bdbstore-jmx.test.libs=${test.libs} + # optional perftests-visualisation-jfc module deps jfreechart.jar=lib/jfree/jfreechart-1.0.13.jar jcommon.jar=lib/jfree/jcommon-1.0.16.jar @@ -161,6 +178,9 @@ csvjdbc.jar=lib/csvjdbc/csvjdbc-1.0.8.jar perftests-visualisation-jfc.libs=${jfreechart.jar} ${jcommon.jar} ${csvjdbc.jar} perftests-visualisation-jfc.test.libs=${test.libs} +#optional qpid-web module deps +broker-web.libs=${servlet-api} + # Libraries used only within the build bnd=lib/required/bnd-0.0.384.jar jython=lib/required/jython-standalone-2.5.2.jar diff --git a/qpid/java/build.xml b/qpid/java/build.xml index 5ac4b03a03..789d61d3fb 100644 --- a/qpid/java/build.xml +++ b/qpid/java/build.xml @@ -27,7 +27,7 @@ <findSubProjects name="management" dir="management" excludes="common,example"/> <property name="optional" value="false"/> - <property name="modules.opt.default" value="bdbstore perftests/visualisation-jfc"/> + <property name="modules.opt.default" value="bdbstore bdbstore/jmx perftests/visualisation-jfc broker-web"/> <condition property="modules.opt" value="" else="${modules.opt.default}"> <isfalse value="${optional}"/> </condition> diff --git a/qpid/java/common.xml b/qpid/java/common.xml index ab71642053..b5ae5679d0 100644 --- a/qpid/java/common.xml +++ b/qpid/java/common.xml @@ -277,8 +277,8 @@ <!-- targets for downloading ivy and retrieving dependencies --> <target name="retrieve-dependencies" depends="load-ivy, configure-ivy, retrieve-optional-dependencies" unless="${ivy.dont.retrieve}"> <echo message="Resolving and retrieving dependencies..."/> - <ivy:resolve type="jar,bundle" file="${project.root}/ivy.retrieve.xml" conf="required"/> - <ivy:retrieve type="jar,bundle" conf="required" sync="true" + <ivy:resolve type="jar,bundle,war" file="${project.root}/ivy.retrieve.xml" conf="required"/> + <ivy:retrieve type="jar,bundle,war" conf="required" sync="true" pattern="${project.root}/lib/required/[artifact]-[revision].[ext]" /> </target> diff --git a/qpid/java/ivy.retrieve.xml b/qpid/java/ivy.retrieve.xml index 8e2806a509..161c134c38 100644 --- a/qpid/java/ivy.retrieve.xml +++ b/qpid/java/ivy.retrieve.xml @@ -48,6 +48,7 @@ <dependency org="org.apache.geronimo.specs" name="geronimo-jms_1.1_spec" rev="1.0" transitive="false"/> <dependency org="org.apache.geronimo.specs" name="geronimo-jta_1.1_spec" rev="1.1.1" transitive="false"/> <dependency org="org.apache.geronimo.specs" name="geronimo-servlet_2.5_spec" rev="1.2" transitive="false"/> + <dependency org="org.apache.geronimo.specs" name="geronimo-servlet_3.0_spec" rev="1.0" transitive="false"/> <dependency org="com.google.code.gson" name="gson" rev="2.0" transitive="false"/> <dependency org="org.codehaus.jackson" name="jackson-core-asl" rev="1.9.0" transitive="false"/> <dependency org="org.codehaus.jackson" name="jackson-mapper-asl" rev="1.9.0" transitive="false"/> @@ -60,6 +61,15 @@ <dependency org="org.apache.felix" name="org.apache.felix.main" rev="2.0.5" transitive="false"/> <dependency org="org.slf4j" name="slf4j-api" rev="1.6.4" transitive="false"/> <dependency org="org.slf4j" name="slf4j-log4j12" rev="1.6.4" transitive="false"/> + <dependency org="org.eclipse.jetty" name="jetty-server" rev="7.6.3.v20120416" transitive="false"/> + <dependency org="org.eclipse.jetty" name="jetty-websocket" rev="7.6.3.v20120416" transitive="false"/> + <dependency org="org.eclipse.jetty" name="jetty-continuation" rev="7.6.3.v20120416" transitive="false"/> + <dependency org="org.eclipse.jetty" name="jetty-io" rev="7.6.3.v20120416" transitive="false"/> + <dependency org="org.eclipse.jetty" name="jetty-http" rev="7.6.3.v20120416" transitive="false"/> + <dependency org="org.eclipse.jetty" name="jetty-security" rev="7.6.3.v20120416" transitive="false"/> + <dependency org="org.eclipse.jetty" name="jetty-servlet" rev="7.6.3.v20120416" transitive="false"/> + <dependency org="org.eclipse.jetty" name="jetty-util" rev="7.6.3.v20120416" transitive="false"/> + <dependency org="org.dojotoolkit" name="dojo-war" rev="1.7.2" transitive="false"/> <dependency org="xalan" name="xalan" rev="2.7.0" transitive="false"/> <!-- The following are optional dependencies, for modules providing optional functionlity or diff --git a/qpid/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ManagedQueue.java b/qpid/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ManagedQueue.java index 254ec01519..b00b28b2a9 100644 --- a/qpid/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ManagedQueue.java +++ b/qpid/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ManagedQueue.java @@ -63,9 +63,14 @@ public interface ManagedQueue String ENCODING = "Encoding"; String CONTENT = "Content"; List<String> VIEW_MSG_CONTENT_COMPOSITE_ITEM_NAMES_DESC = Collections.unmodifiableList(Arrays.asList(MSG_AMQ_ID, MIME, ENCODING, CONTENT)); - + + /** Date/time format used for message expiration and message timestamp formatting */ + String JMSTIMESTAMP_DATETIME_FORMAT = "MM-dd-yy HH:mm:ss.SSS z"; + //Individual attribute name constants static final String ATTR_NAME = "Name"; + static final String ATTR_DESCRIPTION = "Description"; + static final String ATTR_QUEUE_TYPE = "QueueType"; static final String ATTR_OWNER = "Owner"; static final String ATTR_MAX_MSG_AGE = "MaximumMessageAge"; static final String ATTR_MAX_MSG_COUNT = "MaximumMessageCount"; @@ -92,6 +97,8 @@ public interface ManagedQueue new HashSet<String>( Arrays.asList( ATTR_NAME, + ATTR_QUEUE_TYPE, + ATTR_DESCRIPTION, ATTR_OWNER, ATTR_MAX_MSG_AGE, ATTR_MAX_MSG_COUNT, @@ -235,7 +242,7 @@ public interface ManagedQueue * Tells the maximum number of messages that can be stored in the queue. * This is useful in setting the notifications or taking required * action is the number of message increase this limit. - * @return maximum muber of message allowed to be stored in the queue. + * @return maximum nuumber of message allowed to be stored in the queue. * @throws IOException */ Long getMaximumMessageCount() throws IOException; @@ -287,13 +294,33 @@ public interface ManagedQueue */ @MBeanAttribute(name="Capacity", description="The flow control Capacity (Bytes) of the queue") void setCapacity(Long value) throws IOException, IllegalArgumentException; + + /** + * Gets the free text queue description. + * @since Qpid JMX API 2.5 + */ + String getDescription(); + + /** + * Sets the free text queue description. + * @since Qpid JMX API 2.5 + */ + @MBeanAttribute(name="Description", description="Free text description of the queue") + void setDescription(String string); + + /** + * Gets the queue type + * @since Qpid JMX API 2.5 + */ + @MBeanAttribute(name="QueueType", description="Type of the queue e.g. standard, priority, etc") + String getQueueType(); /** * Returns the current flow control FlowResumeCapacity of the queue in bytes. * * @since Qpid JMX API 1.6 * @return Capacity below which flow resumes in bytes - * @throws IOException + * @throws IOExceptionm */ Long getFlowResumeCapacity() throws IOException; @@ -332,7 +359,7 @@ public interface ManagedQueue * @since Qpid JMX API 2.0 * @param exclusive the capacity in bytes * @throws IOException - * @throws JMException + * @throws JMException */ @MBeanAttribute(name="Exclusive", description="Whether the queue is Exclusive or not") void setExclusive(boolean exclusive) throws IOException, JMException; @@ -341,10 +368,13 @@ public interface ManagedQueue * Sets the Alternate Exchange for the queue, for use in dead letter queue functionality. * * @since Qpid JMX API 2.4 - * @param the name of the exchange to use. Specifying null or the empty string will clear the alternate exchange. + * @param exchangeName the name of the exchange to use. Specifying null or the empty string will clear the + * alternate exchange. * @throws IOException + * @throws JMException */ - void setAlternateExchange(String exchangeName) throws IOException; + @MBeanAttribute(name="AlternateExchange", description="Alternate exchange for the queue") + void setAlternateExchange(String exchangeName) throws IOException, JMException; /** * Returns the name of the Alternate Exchange for the queue, or null if there isn't one. @@ -353,7 +383,6 @@ public interface ManagedQueue * @return the name of the Alternate Exchange for the queue, or null if there isn't one * @throws IOException */ - @MBeanAttribute(name="AlternateExchange", description="Alternate exchange for the queue") String getAlternateExchange() throws IOException; //********** Operations *****************// @@ -473,4 +502,5 @@ public interface ManagedQueue @MBeanOperationParameter(name="to MessageId", description="to MessageId")long toMessageId, @MBeanOperationParameter(name= ManagedQueue.TYPE, description="to Queue Name")String toQueue) throws IOException, JMException; + } diff --git a/qpid/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ServerInformation.java b/qpid/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ServerInformation.java index 38b89b58c5..1a4715224f 100644 --- a/qpid/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ServerInformation.java +++ b/qpid/java/management/common/src/main/java/org/apache/qpid/management/common/mbeans/ServerInformation.java @@ -46,7 +46,7 @@ public interface ServerInformation * Qpid JMX API 1.1 can be assumed. */ int QPID_JMX_API_MAJOR_VERSION = 2; - int QPID_JMX_API_MINOR_VERSION = 4; + int QPID_JMX_API_MINOR_VERSION = 5; /** diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ApplicationRegistry.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ApplicationRegistry.java index 963a821864..64a9068357 100644 --- a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ApplicationRegistry.java +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ApplicationRegistry.java @@ -47,7 +47,7 @@ public abstract class ApplicationRegistry //max supported broker management interface supported by this release of the management console public static final int SUPPORTED_QPID_JMX_API_MAJOR_VERSION = 2; - public static final int SUPPORTED_QPID_JMX_API_MINOR_VERSION = 4; + public static final int SUPPORTED_QPID_JMX_API_MINOR_VERSION = 5; public static final String DATA_DIR = System.getProperty("user.home") + File.separator + ".qpidmc"; diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/ViewUtility.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/ViewUtility.java index ba4e091b73..737895958f 100644 --- a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/ViewUtility.java +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/ViewUtility.java @@ -404,13 +404,8 @@ public class ViewUtility private static void convertByteArray(FormToolkit toolkit, Composite compositeHolder, CompositeData data, String itemName, String encoding) { - Byte[] arrayItems = (Byte[])data.get(itemName); - byte[] byteArray = new byte[arrayItems.length]; + byte[] byteArray = getByteArray(data, itemName); - for (int i = 0; i < arrayItems.length; i++) - { - byteArray[i] = arrayItems[i]; - } try { String textMessage = new String(byteArray, encoding); @@ -427,6 +422,27 @@ public class ViewUtility } } + private static byte[] getByteArray(CompositeData data, String itemName) + { + byte[] byteArray; + Object binaryData = data.get(itemName); + + if(binaryData instanceof byte[]) + { + byteArray = (byte[]) binaryData; + } + else + { + Byte[] objectArray = (Byte[]) binaryData; + byteArray = new byte[objectArray.length]; + for(int i = 0; i < objectArray.length; i++) + { + byteArray[i] = objectArray[i]; + } + } + return byteArray; + } + private static Shell getShell() { Shell shell = Display.getCurrent().getActiveShell(); @@ -462,13 +478,8 @@ public class ViewUtility private static void handleBinaryMessageContent(FormToolkit toolkit, Composite compositeHolder, CompositeData data, String itemName, String encoding) { final String thisEncoding = encoding; - final Byte[] arrayItems = (Byte[]) data.get(itemName); - final byte[] byteArray = new byte[arrayItems.length]; - for (int i = 0; i < arrayItems.length; i++) - { - byteArray[i] = arrayItems[i]; - } + final byte[] byteArray = getByteArray(data, itemName); try { diff --git a/qpid/java/management/eclipse-plugin/src/test/java/org/apache/qpid/management/ui/ManagementConsoleTest.java b/qpid/java/management/eclipse-plugin/src/test/java/org/apache/qpid/management/ui/ManagementConsoleTest.java deleted file mode 100644 index eef6356642..0000000000 --- a/qpid/java/management/eclipse-plugin/src/test/java/org/apache/qpid/management/ui/ManagementConsoleTest.java +++ /dev/null @@ -1,123 +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.management.ui; - -import org.apache.qpid.exchange.ExchangeDefaults; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.server.exchange.DirectExchange; -import org.apache.qpid.server.management.AMQManagedObject; -import org.apache.qpid.server.model.UUIDGenerator; -import org.apache.qpid.server.queue.AMQQueue; -import org.apache.qpid.server.queue.AMQQueueFactory; -import org.apache.qpid.server.queue.AMQQueueMBean; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.registry.IApplicationRegistry; -import org.apache.qpid.server.util.InternalBrokerBaseCase; -import org.apache.qpid.server.virtualhost.VirtualHost; - -import javax.management.MBeanFeatureInfo; -import javax.management.MBeanInfo; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; - - -/** - * Test class to test if any change in the broker JMX code is affesting the management console - * There are some hardcoding of management feature names and parameter names to create a customized - * look in the console. - */ -public class ManagementConsoleTest extends InternalBrokerBaseCase -{ - private VirtualHost _virtualHost; - - @Override - public void setUp() throws Exception - { - super.setUp(); - IApplicationRegistry applicationRegistry = ApplicationRegistry.getInstance(); - _virtualHost = applicationRegistry.getVirtualHostRegistry().getVirtualHost("test"); - } - - - /** - * Test for AMQQueueMBean attribute and operation names, which are used in the management console - * @throws Exception - */ - public void testAMQQueueMBeanInfo() throws Exception - { - // If this test fails due to changes in the broker code, - // then the constants in the Constants.java shoule be updated accordingly - AMQQueue queue = AMQQueueFactory.createAMQQueueImpl(new AMQShortString("testQueueForManagement"), false, null, false, false, - _virtualHost, null); - AMQManagedObject mbean = new AMQQueueMBean(queue); - MBeanInfo mbeanInfo = mbean.getMBeanInfo(); - - List<String> operationNames = getNamesList(mbeanInfo.getOperations()); - assertTrue(operationNames.contains(Constants.OPERATION_MOVE_MESSAGES)); - - List<String> attributesList = getNamesList(mbeanInfo.getAttributes()); - assertTrue(attributesList.contains(Constants.ATTRIBUTE_QUEUE_CONSUMERCOUNT)); - assertTrue(attributesList.contains(Constants.ATTRIBUTE_QUEUE_DEPTH)); - } - - /** - * Test for Exchange MBean attribute and operation names, which are used in the management console - * @throws Exception - */ - public void testExchangeMBeanInfo() throws Exception - { - // If this test fails due to changes in the broker code, - // then the constants in the Constants.java shoule be updated accordingly - DirectExchange exchange = new DirectExchange(); - exchange.initialise(UUIDGenerator.generateUUID(), _virtualHost, ExchangeDefaults.DIRECT_EXCHANGE_NAME, false, 0, true); - AMQManagedObject mbean = (AMQManagedObject)exchange.getManagedObject(); - MBeanInfo mbeanInfo = mbean.getMBeanInfo(); - - // Check for the Exchange Type property in the ObjectName - assertNotNull(mbean.getObjectName().getKeyProperty(Constants.EXCHANGE_TYPE)); - - // Check for operation names - List<String> operationNames = getNamesList(mbeanInfo.getOperations()); - assertTrue(operationNames.contains(Constants.OPERATION_CREATE_BINDING)); - } - - /** - * Test for VirtualHostManagerMBean features used in Management console for customizing the GUI - * @throws Exception - */ - public void testVirtualHostManagerMBeanInfo() throws Exception - { - AMQManagedObject mbean = (AMQManagedObject)_virtualHost.getManagedObject(); - assertTrue(mbean.getType().equals(Constants.VIRTUAL_HOST)); - } - - private List<String> getNamesList(MBeanFeatureInfo[] features) - { - List<String> names = new ArrayList<String>(); - for (MBeanFeatureInfo feature : features) - { - names.add(feature.getName()); - } - - return names; - } -} diff --git a/qpid/java/module.xml b/qpid/java/module.xml index 8c6d815fee..87df541275 100644 --- a/qpid/java/module.xml +++ b/qpid/java/module.xml @@ -52,6 +52,7 @@ <property name="module.results" location="${build.results}/${module}"/> <property name="module.failed" location="${module.results}/FAILED"/> <property name="module.src" location="src/main/java"/> + <property name="module.src.resources" location="src/main/resources"/> <property name="module.test.src" location="src/test/java"/> <property name="module.bin" location="bin"/> <property name="module.etc" location="etc"/> @@ -443,12 +444,17 @@ <target name="build" depends="jar,jar-tests,jar-sources,libs,copy-bin,copy-etc,postbuild" description="compile and copy resources into build tree"/> <target name="jar.manifest" depends="compile" if="module.manifest"> - <jar destfile="${module.jar}" basedir="${module.classes}" manifest="${module.manifest}"/> + <jar destfile="${module.jar}" basedir="${module.classes}" manifest="${module.manifest}"> + <metainf dir="${project.root}/resources/" /> + <metainf dir="${module.src.resources}" erroronmissingdir="false"/> + </jar> </target> <target name="jar.nomanifest" depends="compile" unless="module.manifest"> + <jar destfile="${module.jar}" basedir="${module.classes}"> <metainf dir="${project.root}/resources/" /> + <metainf dir="${module.src.resources}" erroronmissingdir="false"/> </jar> </target> diff --git a/qpid/java/systests/build.xml b/qpid/java/systests/build.xml index 57337bdc55..d8ca018ca0 100644 --- a/qpid/java/systests/build.xml +++ b/qpid/java/systests/build.xml @@ -32,7 +32,7 @@ nn - or more contributor license agreements. See the NOTICE file </or> </condition> - <property name="module.depends" value="client management/common broker broker/test common amqp-1-0-common common/test jca ${systests.optional.depends}"/> + <property name="module.depends" value="client management/common broker broker/test common amqp-1-0-common common/test jca broker-plugins/management ${systests.optional.depends}"/> <property name="module.test.src" location="src/main/java"/> <property name="module.test.excludes" value="**/DropInTest.java,**/TestClientControlledTest.java"/> diff --git a/qpid/java/systests/etc/config-systests-settings.xml b/qpid/java/systests/etc/config-systests-settings.xml index 8fad3b8a68..0b65ad83c3 100644 --- a/qpid/java/systests/etc/config-systests-settings.xml +++ b/qpid/java/systests/etc/config-systests-settings.xml @@ -56,6 +56,9 @@ <keyStorePath>${QPID_HOME}/../test-profiles/test_resources/ssl/java_broker_keystore.jks</keyStorePath> <keyStorePassword>password</keyStorePassword> </ssl> + <http> + <enabled>false</enabled> + </http> </management> <advanced> <framesize>65535</framesize> diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/ManagedConnectionMBeanTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/ManagedConnectionMBeanTest.java deleted file mode 100644 index 3fc370dc68..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/ManagedConnectionMBeanTest.java +++ /dev/null @@ -1,278 +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.management.jmx; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.common.QpidProperties; -import org.apache.qpid.management.common.mbeans.ManagedConnection; -import org.apache.qpid.test.utils.JMXTestUtils; -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -import javax.jms.Connection; -import javax.jms.Destination; -import javax.jms.Message; -import javax.jms.MessageConsumer; -import javax.jms.MessageProducer; -import javax.jms.Session; -import javax.jms.TextMessage; -import javax.management.JMException; -import javax.management.openmbean.CompositeDataSupport; -import javax.management.openmbean.TabularData; -import java.io.IOException; -import java.util.Date; -import java.util.Iterator; -import java.util.List; - -public class ManagedConnectionMBeanTest extends QpidBrokerTestCase -{ - private static final Logger LOGGER = LoggerFactory.getLogger(ManagedConnectionMBeanTest.class); - - /** - * JMX helper. - */ - private JMXTestUtils _jmxUtils; - private Connection _connection; - - public void setUp() throws Exception - { - _jmxUtils = new JMXTestUtils(this); - _jmxUtils.setUp(); - super.setUp(); - _jmxUtils.open(); - _connection = getConnection(); - } - - public void tearDown() throws Exception - { - if (_jmxUtils != null) - { - _jmxUtils.close(); - } - super.tearDown(); - } - - public void testChannels() throws Exception - { - final String queueName = getTestQueueName(); - - final Session session = _connection.createSession(true, Session.SESSION_TRANSACTED); - final Destination destination = session.createQueue(queueName); - final MessageConsumer consumer = session.createConsumer(destination); - - final int numberOfMessages = 2; - sendMessage(session, destination, numberOfMessages); - _connection.start(); - - for (int i = 0; i < numberOfMessages; i++) - { - final Message m = consumer.receive(1000l); - assertNotNull("Message " + i + " is not received", m); - } - - List<ManagedConnection> connections = _jmxUtils.getManagedConnections("test"); - assertNotNull("Connection MBean is not found", connections); - assertEquals("Unexpected number of connection mbeans", 1, connections.size()); - final ManagedConnection mBean = connections.get(0); - assertNotNull("Connection MBean is null", mBean); - - TabularData channelsData = mBean.channels(); - assertNotNull("Channels data are null", channelsData); - assertEquals("Unexpected number of rows in channel table", 1, channelsData.size()); - - final Iterator<CompositeDataSupport> rowItr = (Iterator<CompositeDataSupport>) channelsData.values().iterator(); - final CompositeDataSupport row = rowItr.next(); - Number unackCount = (Number) row.get(ManagedConnection.UNACKED_COUNT); - final Boolean transactional = (Boolean) row.get(ManagedConnection.TRANSACTIONAL); - final Boolean flowBlocked = (Boolean) row.get(ManagedConnection.FLOW_BLOCKED); - assertNotNull("Channel should have unacknowledged messages", unackCount); - assertEquals("Unexpected number of unacknowledged messages", 2, unackCount.intValue()); - assertNotNull("Channel should have transaction flag", transactional); - assertTrue("Unexpected transaction flag", transactional); - assertNotNull("Channel should have flow blocked flag", flowBlocked); - assertFalse("Unexpected value of flow blocked flag", flowBlocked); - - final Date initialLastIOTime = mBean.getLastIoTime(); - session.commit(); - assertTrue("Last IO time should have been updated", mBean.getLastIoTime().after(initialLastIOTime)); - - channelsData = mBean.channels(); - assertNotNull("Channels data are null", channelsData); - assertEquals("Unexpected number of rows in channel table", 1, channelsData.size()); - - final Iterator<CompositeDataSupport> rowItr2 = (Iterator<CompositeDataSupport>) channelsData.values().iterator(); - final CompositeDataSupport row2 = rowItr2.next(); - unackCount = (Number) row2.get(ManagedConnection.UNACKED_COUNT); - assertNotNull("Channel should have unacknowledged messages", unackCount); - assertEquals("Unexpected number of anacknowledged messages", 0, unackCount.intValue()); - - _connection.close(); - - LOGGER.debug("Querying JMX for number of open connections"); - connections = _jmxUtils.getManagedConnections("test"); - assertNotNull("Connection MBean is not found", connections); - assertEquals("Unexpected number of connection mbeans after connection closed", 0, connections.size()); - } - - public void testCommit() throws Exception - { - final String queueName = getTestQueueName(); - - final Session consumerSession = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - final Session producerSession = _connection.createSession(true, Session.SESSION_TRANSACTED); - final Destination destination = producerSession.createQueue(queueName); - final MessageConsumer consumer = consumerSession.createConsumer(destination); - final MessageProducer producer = producerSession.createProducer(destination); - - _connection.start(); - - List<ManagedConnection> connections = _jmxUtils.getManagedConnections("test"); - assertNotNull("Connection MBean is not found", connections); - assertEquals("Unexpected number of connection mbeans", 1, connections.size()); - final ManagedConnection mBean = connections.get(0); - assertNotNull("Connection MBean is null", mBean); - - final int numberOfMessages = 2; - for (int i = 0; i < numberOfMessages; i++) - { - producer.send(producerSession.createTextMessage("Test " + i)); - } - - // sync to make sure that messages are received on the broker - // before we commit via JMX - ((AMQSession<?, ?>) producerSession).sync(); - - Message m = consumer.receive(500l); - assertNull("Unexpected message received", m); - - Number channelId = getFirstTransactedChannelId(mBean, 2); - mBean.commitTransactions(channelId.intValue()); - - for (int i = 0; i < numberOfMessages; i++) - { - m = consumer.receive(1000l); - assertNotNull("Message " + i + " is not received", m); - assertEquals("Unexpected message received at " + i, "Test " + i, ((TextMessage) m).getText()); - } - producerSession.commit(); - m = consumer.receive(500l); - assertNull("Unexpected message received", m); - } - - protected Number getFirstTransactedChannelId(final ManagedConnection mBean, int channelNumber) throws IOException, JMException - { - TabularData channelsData = mBean.channels(); - assertNotNull("Channels data are null", channelsData); - assertEquals("Unexpected number of rows in channel table", channelNumber, channelsData.size()); - final Iterator<CompositeDataSupport> rowItr = (Iterator<CompositeDataSupport>) channelsData.values().iterator(); - while (rowItr.hasNext()) - { - final CompositeDataSupport row = rowItr.next(); - Boolean transacted = (Boolean) row.get(ManagedConnection.TRANSACTIONAL); - if (transacted.booleanValue()) - { - return (Number) row.get(ManagedConnection.CHAN_ID); - } - } - return null; - } - - public void testRollback() throws Exception - { - final String queueName = getTestQueueName(); - - final Session consumerSession = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); - final Session producerSession = _connection.createSession(true, Session.SESSION_TRANSACTED); - final Destination destination = producerSession.createQueue(queueName); - final MessageConsumer consumer = consumerSession.createConsumer(destination); - final MessageProducer producer = producerSession.createProducer(destination); - - List<ManagedConnection> connections = _jmxUtils.getManagedConnections("test"); - assertNotNull("Connection MBean is not found", connections); - assertEquals("Unexpected number of connection mbeans", 1, connections.size()); - final ManagedConnection mBean = connections.get(0); - assertNotNull("Connection MBean is null", mBean); - - final int numberOfMessages = 2; - for (int i = 0; i < numberOfMessages; i++) - { - producer.send(producerSession.createTextMessage("Test " + i)); - } - - // sync to make sure that messages are received on the broker - // before we rollback via JMX - ((AMQSession<?, ?>) producerSession).sync(); - - Number channelId = getFirstTransactedChannelId(mBean, 2); - mBean.rollbackTransactions(channelId.intValue()); - - Message m = consumer.receive(1000l); - assertNull("Unexpected message received: " + String.valueOf(m), m); - - producerSession.commit(); - - _connection.start(); - m = consumer.receive(1000l); - assertNull("Unexpected message received after commit " + String.valueOf(m), m); - } - - public void testAuthorisedId() throws Exception - { - List<ManagedConnection> connections = _jmxUtils.getManagedConnections("test"); - assertNotNull("Connection MBean is not found", connections); - assertEquals("Unexpected number of connection mbeans", 1, connections.size()); - final ManagedConnection mBean = connections.get(0); - assertNotNull("Connection MBean is null", mBean); - assertEquals("Unexpected authorized id", "guest", mBean.getAuthorizedId()); - } - - public void testClientVersion() throws Exception - { - List<ManagedConnection> connections = _jmxUtils.getManagedConnections("test"); - assertNotNull("Connection MBean is not found", connections); - assertEquals("Unexpected number of connection mbeans", 1, connections.size()); - final ManagedConnection mBean = connections.get(0); - assertNotNull("Connection MBean is null", mBean); - - String expectedVersion = QpidProperties.getReleaseVersion(); - assertNotNull("version should not be null", expectedVersion); - assertFalse("version should not be the empty string", expectedVersion.equals("")); - assertFalse("version should not be the string 'null'", expectedVersion.equals("null")); - - assertEquals("Unexpected version", expectedVersion, mBean.getVersion()); - } - - public void testClientId() throws Exception - { - List<ManagedConnection> connections = _jmxUtils.getManagedConnections("test"); - assertNotNull("Connection MBean is not found", connections); - assertEquals("Unexpected number of connection mbeans", 1, connections.size()); - final ManagedConnection mBean = connections.get(0); - assertNotNull("Connection MBean is null", mBean); - - String expectedClientId = _connection.getClientID(); - assertNotNull("ClientId should not be null", expectedClientId); - assertFalse("ClientId should not be the empty string", expectedClientId.equals("")); - assertFalse("ClientId should not be the string 'null'", expectedClientId.equals("null")); - - assertEquals("Unexpected ClientId", expectedClientId, mBean.getClientId()); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/MessageConnectionStatisticsTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/MessageConnectionStatisticsTest.java deleted file mode 100644 index 9465749226..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/MessageConnectionStatisticsTest.java +++ /dev/null @@ -1,101 +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.management.jmx; - -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.management.common.mbeans.ManagedBroker; -import org.apache.qpid.management.common.mbeans.ManagedConnection; - -import javax.jms.Connection; -import java.util.ArrayList; -import java.util.List; - -/** - * Test enabling generation of message statistics on a per-connection basis. - */ -public class MessageConnectionStatisticsTest extends MessageStatisticsTestCase -{ - public void configureStatistics() throws Exception - { - // no statistics generation configured - } - - /** - * Test statistics on a single connection - */ - public void testEnablingStatisticsPerConnection() throws Exception - { - ManagedBroker vhost = _jmxUtils.getManagedBroker("test"); - - sendUsing(_test, 5, 200); - Thread.sleep(1000); - - List<String> addresses = new ArrayList<String>(); - for (ManagedConnection mc : _jmxUtils.getManagedConnections("test")) - { - assertEquals("Incorrect connection total", 0, mc.getTotalMessagesReceived()); - assertEquals("Incorrect connection data", 0, mc.getTotalDataReceived()); - assertFalse("Connection statistics should not be enabled", mc.isStatisticsEnabled()); - - addresses.add(mc.getRemoteAddress()); - } - assertEquals("Incorrect vhost total", 0, vhost.getTotalMessagesReceived()); - assertEquals("Incorrect vhost data", 0, vhost.getTotalDataReceived()); - - Connection test = new AMQConnection(_brokerUrl, USER, USER, "clientid", "test"); - test.start(); - for (ManagedConnection mc : _jmxUtils.getManagedConnections("test")) - { - if (addresses.contains(mc.getRemoteAddress())) - { - continue; - } - mc.setStatisticsEnabled(true); - assertEquals("Incorrect connection total", 0, mc.getTotalMessagesReceived()); - assertEquals("Incorrect connection data", 0, mc.getTotalDataReceived()); - } - - sendUsing(test, 5, 200); - sendUsing(_test, 5, 200); - Thread.sleep(1000); - - for (ManagedConnection mc : _jmxUtils.getManagedConnections("test")) - { - if (addresses.contains(mc.getRemoteAddress())) - { - assertEquals("Incorrect connection total", 0, mc.getTotalMessagesReceived()); - assertEquals("Incorrect connection data", 0, mc.getTotalDataReceived()); - assertFalse("Connection statistics should not be enabled", mc.isStatisticsEnabled()); - } - else - { - assertEquals("Incorrect connection total", 5, mc.getTotalMessagesReceived()); - assertEquals("Incorrect connection data", 1000, mc.getTotalDataReceived()); - assertTrue("Connection statistics should be enabled", mc.isStatisticsEnabled()); - } - } - assertEquals("Incorrect vhost total", 0, vhost.getTotalMessagesReceived()); - assertEquals("Incorrect vhost data", 0, vhost.getTotalDataReceived()); - assertFalse("Vhost statistics should not be enabled", vhost.isStatisticsEnabled()); - - test.close(); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/MessageStatisticsConfigurationTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/MessageStatisticsConfigurationTest.java deleted file mode 100644 index 383c4c00a8..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/MessageStatisticsConfigurationTest.java +++ /dev/null @@ -1,162 +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.management.jmx; - -import org.apache.qpid.management.common.mbeans.ManagedBroker; -import org.apache.qpid.management.common.mbeans.ManagedConnection; - -/** - * Test enabling generation of message statistics on a per-connection basis. - */ -public class MessageStatisticsConfigurationTest extends MessageStatisticsTestCase -{ - public void configureStatistics() throws Exception - { - setConfigurationProperty("statistics.generation.broker", Boolean.toString(getName().contains("Broker"))); - setConfigurationProperty("statistics.generation.virtualhosts", Boolean.toString(getName().contains("Virtualhost"))); - setConfigurationProperty("statistics.generation.connections", Boolean.toString(getName().contains("Connection"))); - } - - /** - * Just broker statistics. - */ - public void testGenerateBrokerStatistics() throws Exception - { - sendUsing(_test, 5, 200); - Thread.sleep(1000); - - for (ManagedConnection mc : _jmxUtils.getManagedConnections("test")) - { - assertEquals("Incorrect connection total", 0, mc.getTotalMessagesReceived()); - assertEquals("Incorrect connection data", 0, mc.getTotalDataReceived()); - assertFalse("Connection statistics should not be enabled", mc.isStatisticsEnabled()); - } - - ManagedBroker vhost = _jmxUtils.getManagedBroker("test"); - assertEquals("Incorrect vhost data", 0, vhost.getTotalMessagesReceived()); - assertEquals("Incorrect vhost data", 0, vhost.getTotalDataReceived()); - assertFalse("Vhost statistics should not be enabled", vhost.isStatisticsEnabled()); - - assertEquals("Incorrect server total messages", 5, _jmxUtils.getServerInformation().getTotalMessagesReceived()); - assertEquals("Incorrect server total data", 1000, _jmxUtils.getServerInformation().getTotalDataReceived()); - assertTrue("Server statistics should be enabled", _jmxUtils.getServerInformation().isStatisticsEnabled()); - } - - /** - * Just virtualhost statistics. - */ - public void testGenerateVirtualhostStatistics() throws Exception - { - sendUsing(_test, 5, 200); - Thread.sleep(1000); - - for (ManagedConnection mc : _jmxUtils.getManagedConnections("test")) - { - assertEquals("Incorrect connection total", 0, mc.getTotalMessagesReceived()); - assertEquals("Incorrect connection data", 0, mc.getTotalDataReceived()); - assertFalse("Connection statistics should not be enabled", mc.isStatisticsEnabled()); - } - - ManagedBroker vhost = _jmxUtils.getManagedBroker("test"); - assertEquals("Incorrect vhost data", 5, vhost.getTotalMessagesReceived()); - assertEquals("Incorrect vhost data", 1000, vhost.getTotalDataReceived()); - assertTrue("Vhost statistics should be enabled", vhost.isStatisticsEnabled()); - - assertEquals("Incorrect server total messages", 0, _jmxUtils.getServerInformation().getTotalMessagesReceived()); - assertEquals("Incorrect server total data", 0, _jmxUtils.getServerInformation().getTotalDataReceived()); - assertFalse("Server statistics should not be enabled", _jmxUtils.getServerInformation().isStatisticsEnabled()); - } - - /** - * Just connection statistics. - */ - public void testGenerateConnectionStatistics() throws Exception - { - sendUsing(_test, 5, 200); - Thread.sleep(1000); - - for (ManagedConnection mc : _jmxUtils.getManagedConnections("test")) - { - assertEquals("Incorrect connection total", 5, mc.getTotalMessagesReceived()); - assertEquals("Incorrect connection data", 1000, mc.getTotalDataReceived()); - assertTrue("Connection statistics should be enabled", mc.isStatisticsEnabled()); - } - - ManagedBroker vhost = _jmxUtils.getManagedBroker("test"); - assertEquals("Incorrect vhost data", 0, vhost.getTotalMessagesReceived()); - assertEquals("Incorrect vhost data", 0, vhost.getTotalDataReceived()); - assertFalse("Vhost statistics should not be enabled", vhost.isStatisticsEnabled()); - - assertEquals("Incorrect server total messages", 0, _jmxUtils.getServerInformation().getTotalMessagesReceived()); - assertEquals("Incorrect server total data", 0, _jmxUtils.getServerInformation().getTotalDataReceived()); - assertFalse("Server statistics should not be enabled", _jmxUtils.getServerInformation().isStatisticsEnabled()); - } - - /** - * Both broker and virtualhost statistics. - */ - public void testGenerateBrokerAndVirtualhostStatistics() throws Exception - { - sendUsing(_test, 5, 200); - Thread.sleep(1000); - - for (ManagedConnection mc : _jmxUtils.getManagedConnections("test")) - { - assertEquals("Incorrect connection total", 0, mc.getTotalMessagesReceived()); - assertEquals("Incorrect connection data", 0, mc.getTotalDataReceived()); - assertFalse("Connection statistics should not be enabled", mc.isStatisticsEnabled()); - } - - ManagedBroker vhost = _jmxUtils.getManagedBroker("test"); - assertEquals("Incorrect vhost data", 5, vhost.getTotalMessagesReceived()); - assertEquals("Incorrect vhost data", 1000, vhost.getTotalDataReceived()); - assertTrue("Vhost statistics should be enabled", vhost.isStatisticsEnabled()); - - assertEquals("Incorrect server total messages", 5, _jmxUtils.getServerInformation().getTotalMessagesReceived()); - assertEquals("Incorrect server total data", 1000, _jmxUtils.getServerInformation().getTotalDataReceived()); - assertTrue("Server statistics should be enabled", _jmxUtils.getServerInformation().isStatisticsEnabled()); - } - - /** - * Broker, virtualhost and connection statistics. - */ - public void testGenerateBrokerVirtualhostAndConnectionStatistics() throws Exception - { - sendUsing(_test, 5, 200); - Thread.sleep(1000); - - for (ManagedConnection mc : _jmxUtils.getManagedConnections("test")) - { - assertEquals("Incorrect connection total", 5, mc.getTotalMessagesReceived()); - assertEquals("Incorrect connection data", 1000, mc.getTotalDataReceived()); - assertTrue("Connection statistics should be enabled", mc.isStatisticsEnabled()); - } - - ManagedBroker vhost = _jmxUtils.getManagedBroker("test"); - assertEquals("Incorrect vhost data", 5, vhost.getTotalMessagesReceived()); - assertEquals("Incorrect vhost data", 1000, vhost.getTotalDataReceived()); - assertTrue("Vhost statistics should be enabled", vhost.isStatisticsEnabled()); - - assertEquals("Incorrect server total messages", 5, _jmxUtils.getServerInformation().getTotalMessagesReceived()); - assertEquals("Incorrect server total data", 1000, _jmxUtils.getServerInformation().getTotalDataReceived()); - assertTrue("Server statistics should be enabled", _jmxUtils.getServerInformation().isStatisticsEnabled()); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/MessageStatisticsDeliveryTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/MessageStatisticsDeliveryTest.java deleted file mode 100644 index bdfd1e2c14..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/MessageStatisticsDeliveryTest.java +++ /dev/null @@ -1,109 +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.management.jmx; - -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.management.common.mbeans.ManagedBroker; -import org.apache.qpid.management.common.mbeans.ManagedConnection; - -import javax.jms.Connection; -import javax.jms.Message; -import javax.jms.MessageConsumer; -import javax.jms.Session; -import java.util.ArrayList; -import java.util.List; - -/** - * Test statistics for delivery and receipt. - */ -public class MessageStatisticsDeliveryTest extends MessageStatisticsTestCase -{ - public void configureStatistics() throws Exception - { - setConfigurationProperty("statistics.generation.broker", "true"); - setConfigurationProperty("statistics.generation.virtualhosts", "true"); - setConfigurationProperty("statistics.generation.connections", "true"); - } - - public void testDeliveryAndReceiptStatistics() throws Exception - { - ManagedBroker vhost = _jmxUtils.getManagedBroker("test"); - - sendUsing(_test, 5, 200); - Thread.sleep(1000); - - List<String> addresses = new ArrayList<String>(); - for (ManagedConnection mc : _jmxUtils.getManagedConnections("test")) - { - assertEquals("Incorrect connection delivery total", 0, mc.getTotalMessagesDelivered()); - assertEquals("Incorrect connection delivery data", 0, mc.getTotalDataDelivered()); - assertEquals("Incorrect connection receipt total", 5, mc.getTotalMessagesReceived()); - assertEquals("Incorrect connection receipt data", 1000, mc.getTotalDataReceived()); - - addresses.add(mc.getRemoteAddress()); - } - - assertEquals("Incorrect vhost delivery total", 0, vhost.getTotalMessagesDelivered()); - assertEquals("Incorrect vhost delivery data", 0, vhost.getTotalDataDelivered()); - assertEquals("Incorrect vhost receipt total", 5, vhost.getTotalMessagesReceived()); - assertEquals("Incorrect vhost receipt data", 1000, vhost.getTotalDataReceived()); - - Connection test = new AMQConnection(_brokerUrl, USER, USER, "clientid", "test"); - test.start(); - receiveUsing(test, 5); - - for (ManagedConnection mc : _jmxUtils.getManagedConnections("test")) - { - if (addresses.contains(mc.getRemoteAddress())) - { - assertEquals("Incorrect connection delivery total", 0, mc.getTotalMessagesDelivered()); - assertEquals("Incorrect connection delivery data", 0, mc.getTotalDataDelivered()); - assertEquals("Incorrect connection receipt total", 5, mc.getTotalMessagesReceived()); - assertEquals("Incorrect connection receipt data", 1000, mc.getTotalDataReceived()); - } - else - { - assertEquals("Incorrect connection delivery total", 5, mc.getTotalMessagesDelivered()); - assertEquals("Incorrect connection delivery data", 1000, mc.getTotalDataDelivered()); - assertEquals("Incorrect connection receipt total", 0, mc.getTotalMessagesReceived()); - assertEquals("Incorrect connection receipt data", 0, mc.getTotalDataReceived()); - } - } - assertEquals("Incorrect vhost delivery total", 5, vhost.getTotalMessagesDelivered()); - assertEquals("Incorrect vhost delivery data", 1000, vhost.getTotalDataDelivered()); - assertEquals("Incorrect vhost receipt total", 5, vhost.getTotalMessagesReceived()); - assertEquals("Incorrect vhost receipt data", 1000, vhost.getTotalDataReceived()); - - test.close(); - } - - protected void receiveUsing(Connection con, int number) throws Exception - { - Session session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); - createQueue(session); - MessageConsumer consumer = session.createConsumer(_queue); - for (int i = 0; i < number; i++) - { - Message msg = consumer.receive(1000); - assertNotNull("Message " + i + " was not received", msg); - } - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/MessageStatisticsTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/MessageStatisticsTest.java deleted file mode 100644 index de4567624d..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/MessageStatisticsTest.java +++ /dev/null @@ -1,196 +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.management.jmx; - -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.management.common.mbeans.ManagedBroker; -import org.apache.qpid.management.common.mbeans.ManagedConnection; - -import javax.jms.Connection; - -/** - * Test generation of message statistics. - */ -public class MessageStatisticsTest extends MessageStatisticsTestCase -{ - public void configureStatistics() throws Exception - { - setConfigurationProperty("statistics.generation.broker", "true"); - setConfigurationProperty("statistics.generation.virtualhosts", "true"); - setConfigurationProperty("statistics.generation.connections", "true"); - } - - /** - * Test message totals. - */ - public void testMessageTotals() throws Exception - { - sendUsing(_test, 10, 100); - sendUsing(_dev, 20, 100); - sendUsing(_local, 5, 100); - sendUsing(_local, 5, 100); - sendUsing(_local, 5, 100); - Thread.sleep(2000); - - ManagedBroker test = _jmxUtils.getManagedBroker("test"); - ManagedBroker dev = _jmxUtils.getManagedBroker("development"); - ManagedBroker local = _jmxUtils.getManagedBroker("localhost"); - - if (!isBroker010()) - { - long total = 0; - long data = 0; - for (ManagedConnection mc : _jmxUtils.getAllManagedConnections()) - { - total += mc.getTotalMessagesReceived(); - data += mc.getTotalDataReceived(); - } - assertEquals("Incorrect connection total", 45, total); - assertEquals("Incorrect connection data", 4500, data); - } - assertEquals("Incorrect server total", 45, _jmxUtils.getServerInformation().getTotalMessagesReceived()); - assertEquals("Incorrect server data", 4500, _jmxUtils.getServerInformation().getTotalDataReceived()); - - if (!isBroker010()) - { - long testTotal = 0; - long testData = 0; - for (ManagedConnection mc : _jmxUtils.getManagedConnections("test")) - { - testTotal += mc.getTotalMessagesReceived(); - testData += mc.getTotalDataReceived(); - } - assertEquals("Incorrect test connection total", 10, testTotal); - assertEquals("Incorrect test connection data", 1000, testData); - } - assertEquals("Incorrect test vhost total", 10, test.getTotalMessagesReceived()); - assertEquals("Incorrect test vhost data", 1000, test.getTotalDataReceived()); - - if (!isBroker010()) - { - long devTotal = 0; - long devData = 0; - for (ManagedConnection mc : _jmxUtils.getManagedConnections("development")) - { - devTotal += mc.getTotalMessagesReceived(); - devData += mc.getTotalDataReceived(); - } - assertEquals("Incorrect test connection total", 20, devTotal); - assertEquals("Incorrect test connection data", 2000, devData); - } - assertEquals("Incorrect development total", 20, dev.getTotalMessagesReceived()); - assertEquals("Incorrect development data", 2000, dev.getTotalDataReceived()); - - if (!isBroker010()) - { - long localTotal = 0; - long localData = 0; - for (ManagedConnection mc : _jmxUtils.getManagedConnections("localhost")) - { - localTotal += mc.getTotalMessagesReceived(); - localData += mc.getTotalDataReceived(); - } - assertEquals("Incorrect test connection total", 15, localTotal); - assertEquals("Incorrect test connection data", 1500, localData); - } - assertEquals("Incorrect localhost total", 15, local.getTotalMessagesReceived()); - assertEquals("Incorrect localhost data", 1500, local.getTotalDataReceived()); - } - - /** - * Test message totals when a connection is closed. - */ - public void testMessageTotalsWithClosedConnections() throws Exception - { - Connection temp = new AMQConnection(_brokerUrl, USER, USER, "clientid", "test"); - temp.start(); - - sendUsing(_test, 10, 100); - sendUsing(temp, 10, 100); - sendUsing(_test, 10, 100); - Thread.sleep(2000); - - temp.close(); - - ManagedBroker test = _jmxUtils.getManagedBroker("test"); - - if (!isBroker010()) - { - long total = 0; - long data = 0; - for (ManagedConnection mc : _jmxUtils.getAllManagedConnections()) - { - total += mc.getTotalMessagesReceived(); - data += mc.getTotalDataReceived(); - } - assertEquals("Incorrect active connection total", 20, total); - assertEquals("Incorrect active connection data", 2000, data); - } - assertEquals("Incorrect server total", 30, _jmxUtils.getServerInformation().getTotalMessagesReceived()); - assertEquals("Incorrect server data", 3000, _jmxUtils.getServerInformation().getTotalDataReceived()); - - if (!isBroker010()) - { - long testTotal = 0; - long testData = 0; - for (ManagedConnection mc : _jmxUtils.getManagedConnections("test")) - { - testTotal += mc.getTotalMessagesReceived(); - testData += mc.getTotalDataReceived(); - } - assertEquals("Incorrect test active connection total", 20, testTotal); - assertEquals("Incorrect test active connection data", 20 * 100, testData); - } - assertEquals("Incorrect test vhost total", 30, test.getTotalMessagesReceived()); - assertEquals("Incorrect test vhost data", 30 * 100, test.getTotalDataReceived()); - } - - /** - * Test message totals when a vhost has its statistics reset - */ - public void testMessageTotalVhostReset() throws Exception - { - sendUsing(_test, 10, 10); - sendUsing(_dev, 10, 10); - Thread.sleep(2000); - - ManagedBroker test = _jmxUtils.getManagedBroker("test"); - ManagedBroker dev = _jmxUtils.getManagedBroker("development"); - - assertEquals("Incorrect test vhost total messages", 10, test.getTotalMessagesReceived()); - assertEquals("Incorrect test vhost total data", 100, test.getTotalDataReceived()); - assertEquals("Incorrect dev vhost total messages", 10, dev.getTotalMessagesReceived()); - assertEquals("Incorrect dev vhost total data", 100, dev.getTotalDataReceived()); - - assertEquals("Incorrect server total messages", 20, _jmxUtils.getServerInformation().getTotalMessagesReceived()); - assertEquals("Incorrect server total data", 200, _jmxUtils.getServerInformation().getTotalDataReceived()); - - test.resetStatistics(); - - assertEquals("Incorrect test vhost total messages", 0, test.getTotalMessagesReceived()); - assertEquals("Incorrect test vhost total data", 0, test.getTotalDataReceived()); - assertEquals("Incorrect dev vhost total messages", 10, dev.getTotalMessagesReceived()); - assertEquals("Incorrect dev vhost total data", 100, dev.getTotalDataReceived()); - - assertEquals("Incorrect server total messages", 20, _jmxUtils.getServerInformation().getTotalMessagesReceived()); - assertEquals("Incorrect server total data", 200, _jmxUtils.getServerInformation().getTotalDataReceived()); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/MessageStatisticsTestCase.java b/qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/MessageStatisticsTestCase.java deleted file mode 100644 index 45200ba476..0000000000 --- a/qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/MessageStatisticsTestCase.java +++ /dev/null @@ -1,128 +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.management.jmx; - -import org.apache.qpid.AMQException; -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.AMQDestination; -import org.apache.qpid.client.AMQQueue; -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.exchange.ExchangeDefaults; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.test.utils.JMXTestUtils; -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -import javax.jms.Connection; -import javax.jms.Destination; -import javax.jms.JMSException; -import javax.jms.MessageProducer; -import javax.jms.Session; -import javax.jms.TextMessage; - -/** - * Test generation of message statistics. - */ -public abstract class MessageStatisticsTestCase extends QpidBrokerTestCase -{ - protected static final String USER = "admin"; - - protected JMXTestUtils _jmxUtils; - protected Connection _test, _dev, _local; - protected String _queueName = "statistics"; - protected Destination _queue; - protected String _brokerUrl; - - @Override - public void setUp() throws Exception - { - _jmxUtils = new JMXTestUtils(this, USER, USER); - _jmxUtils.setUp(); - - configureStatistics(); - - super.setUp(); - - _brokerUrl = getBroker().toString(); - _test = new AMQConnection(_brokerUrl, USER, USER, "clientid", "test"); - _dev = new AMQConnection(_brokerUrl, USER, USER, "clientid", "development"); - _local = new AMQConnection(_brokerUrl, USER, USER, "clientid", "localhost"); - - _test.start(); - _dev.start(); - _local.start(); - - _jmxUtils.open(); - } - - protected void createQueue(Session session) throws AMQException, JMSException - { - _queue = new AMQQueue(ExchangeDefaults.DIRECT_EXCHANGE_NAME, _queueName); - if (!((AMQSession<?,?>) session).isQueueBound((AMQDestination) _queue)) - { - ((AMQSession<?,?>) session).createQueue(new AMQShortString(_queueName), false, true, false, null); - ((AMQSession<?,?>) session).declareAndBind((AMQDestination) new AMQQueue(ExchangeDefaults.DIRECT_EXCHANGE_NAME, _queueName)); - } - } - - - @Override - public void tearDown() throws Exception - { - _jmxUtils.close(); - - _test.close(); - _dev.close(); - _local.close(); - - super.tearDown(); - } - - /** - * Configure statistics generation properties on the broker. - */ - public abstract void configureStatistics() throws Exception; - - protected void sendUsing(Connection con, int number, int size) throws Exception - { - Session session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); - createQueue(session); - MessageProducer producer = session.createProducer(_queue); - String content = new String(new byte[size]); - TextMessage msg = session.createTextMessage(content); - for (int i = 0; i < number; i++) - { - producer.send(msg); - } - } - - /** - * Asserts that the actual value is within the expected value plus or - * minus the given error. - */ - public void assertApprox(String message, double error, double expected, double actual) - { - double min = expected * (1.0d - error); - double max = expected * (1.0d + error); - String assertion = String.format("%s: expected %f +/- %d%%, actual %f", - message, expected, (int) (error * 100.0d), actual); - assertTrue(assertion, actual > min && actual < max); - } -} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/ModelTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/ModelTest.java index ab0d88c737..782709b24f 100644 --- a/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/ModelTest.java +++ b/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/ModelTest.java @@ -333,7 +333,7 @@ public class ModelTest extends QpidBrokerTestCase queueName)); assertEquals(queueName, managedQueue.getName()); - assertEquals(String.valueOf(owner), managedQueue.getOwner()); + assertEquals(owner, managedQueue.getOwner()); assertEquals(durable, managedQueue.isDurable()); assertEquals(autoDelete, managedQueue.isAutoDelete()); } diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/ExternalACLJMXTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/ExternalACLJMXTest.java index 6e4f12b9f3..ceff2b998a 100644 --- a/qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/ExternalACLJMXTest.java +++ b/qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/ExternalACLJMXTest.java @@ -19,7 +19,6 @@ package org.apache.qpid.server.security.acl; import org.apache.qpid.management.common.mbeans.ServerInformation; -import org.apache.qpid.server.management.ManagedObject; import org.apache.qpid.server.security.access.ObjectType; import org.apache.qpid.test.utils.JMXTestUtils; @@ -30,7 +29,7 @@ import java.lang.management.RuntimeMXBean; * Tests that access to the JMX interface is governed only by {@link ObjectType#METHOD}/{@link ObjectType#ALL} * rules and AMQP rights have no effect. * - * Ensures that objects outside the Qpid domain ({@link ManagedObject#DOMAIN}) are not governed by the ACL model. + * Ensures that objects outside the Qpid domain are not governed by the ACL model. */ public class ExternalACLJMXTest extends AbstractACLTestCase { diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/MessageStatisticsReportingTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/stats/StatisticsReportingTest.java index 786ef11956..c38fcd9199 100644 --- a/qpid/java/systests/src/main/java/org/apache/qpid/management/jmx/MessageStatisticsReportingTest.java +++ b/qpid/java/systests/src/main/java/org/apache/qpid/server/stats/StatisticsReportingTest.java @@ -18,30 +18,75 @@ * under the License. * */ -package org.apache.qpid.management.jmx; +package org.apache.qpid.server.stats; +import org.apache.qpid.AMQException; +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQDestination; +import org.apache.qpid.client.AMQQueue; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.exchange.ExchangeDefaults; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.test.utils.QpidBrokerTestCase; import org.apache.qpid.util.LogMonitor; import java.util.List; +import javax.jms.Connection; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; + /** - * Test generation of message statistics reporting. + * Test generation of message/data statistics reporting and the ability + * to control from the configuration file. */ -public class MessageStatisticsReportingTest extends MessageStatisticsTestCase +public class StatisticsReportingTest extends QpidBrokerTestCase { protected LogMonitor _monitor; - - public void configureStatistics() throws Exception + protected static final String USER = "admin"; + + protected Connection _test, _dev, _local; + protected String _queueName = "statistics"; + protected Destination _queue; + protected String _brokerUrl; + + @Override + public void setUp() throws Exception { setConfigurationProperty("statistics.generation.broker", "true"); setConfigurationProperty("statistics.generation.virtualhosts", "true"); - + if (getName().equals("testEnabledStatisticsReporting")) { setConfigurationProperty("statistics.reporting.period", "10"); } - + _monitor = new LogMonitor(_outputFile); + + super.setUp(); + + _brokerUrl = getBroker().toString(); + _test = new AMQConnection(_brokerUrl, USER, USER, "clientid", "test"); + _dev = new AMQConnection(_brokerUrl, USER, USER, "clientid", "development"); + _local = new AMQConnection(_brokerUrl, USER, USER, "clientid", "localhost"); + + _test.start(); + _dev.start(); + _local.start(); + + } + + @Override + public void tearDown() throws Exception + { + _test.close(); + _dev.close(); + _local.close(); + + super.tearDown(); } /** @@ -52,14 +97,14 @@ public class MessageStatisticsReportingTest extends MessageStatisticsTestCase sendUsing(_test, 10, 100); sendUsing(_dev, 20, 100); sendUsing(_local, 15, 100); - + Thread.sleep(10 * 1000); // 15s - + List<String> brokerStatsData = _monitor.findMatches("BRK-1008"); List<String> brokerStatsMessages = _monitor.findMatches("BRK-1009"); List<String> vhostStatsData = _monitor.findMatches("VHT-1003"); List<String> vhostStatsMessages = _monitor.findMatches("VHT-1004"); - + assertEquals("Incorrect number of broker data stats log messages", 2, brokerStatsData.size()); assertEquals("Incorrect number of broker message stats log messages", 2, brokerStatsMessages.size()); assertEquals("Incorrect number of virtualhost data stats log messages", 6, vhostStatsData.size()); @@ -74,17 +119,40 @@ public class MessageStatisticsReportingTest extends MessageStatisticsTestCase sendUsing(_test, 10, 100); sendUsing(_dev, 20, 100); sendUsing(_local, 15, 100); - + Thread.sleep(10 * 1000); // 15s - + List<String> brokerStatsData = _monitor.findMatches("BRK-1008"); List<String> brokerStatsMessages = _monitor.findMatches("BRK-1009"); List<String> vhostStatsData = _monitor.findMatches("VHT-1003"); List<String> vhostStatsMessages = _monitor.findMatches("VHT-1004"); - + assertEquals("Incorrect number of broker data stats log messages", 0, brokerStatsData.size()); assertEquals("Incorrect number of broker message stats log messages", 0, brokerStatsMessages.size()); assertEquals("Incorrect number of virtualhost data stats log messages", 0, vhostStatsData.size()); assertEquals("Incorrect number of virtualhost message stats log messages", 0, vhostStatsMessages.size()); } + + private void sendUsing(Connection con, int number, int size) throws Exception + { + Session session = con.createSession(false, Session.AUTO_ACKNOWLEDGE); + createQueue(session); + MessageProducer producer = session.createProducer(_queue); + String content = new String(new byte[size]); + TextMessage msg = session.createTextMessage(content); + for (int i = 0; i < number; i++) + { + producer.send(msg); + } + } + + private void createQueue(Session session) throws AMQException, JMSException + { + _queue = new AMQQueue(ExchangeDefaults.DIRECT_EXCHANGE_NAME, _queueName); + if (!((AMQSession<?,?>) session).isQueueBound((AMQDestination) _queue)) + { + ((AMQSession<?,?>) session).createQueue(new AMQShortString(_queueName), false, true, false, null); + ((AMQSession<?,?>) session).declareAndBind((AMQDestination) new AMQQueue(ExchangeDefaults.DIRECT_EXCHANGE_NAME, _queueName)); + } + } } diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/store/QuotaMessageStore.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/store/QuotaMessageStore.java index 2c029b4bf3..07965cfa95 100644 --- a/qpid/java/systests/src/main/java/org/apache/qpid/server/store/QuotaMessageStore.java +++ b/qpid/java/systests/src/main/java/org/apache/qpid/server/store/QuotaMessageStore.java @@ -171,4 +171,10 @@ public class QuotaMessageStore extends NullMessageStore } } } + + @Override + public String getStoreType() + { + return "QUOTA"; + } } diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/store/SlowMessageStore.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/store/SlowMessageStore.java index f2d4a513be..9db04b64b3 100644 --- a/qpid/java/systests/src/main/java/org/apache/qpid/server/store/SlowMessageStore.java +++ b/qpid/java/systests/src/main/java/org/apache/qpid/server/store/SlowMessageStore.java @@ -24,7 +24,6 @@ import org.apache.commons.configuration.Configuration; import org.apache.log4j.Logger; import org.apache.qpid.AMQStoreException; -import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.FieldTable; import org.apache.qpid.server.binding.Binding; import org.apache.qpid.server.exchange.Exchange; @@ -370,4 +369,10 @@ public class SlowMessageStore implements MessageStore return _realStore.getStoreLocation(); } + @Override + public String getStoreType() + { + return "SLOW"; + } + } diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/BrokerClosesClientConnectionTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/BrokerClosesClientConnectionTest.java index 5b3bca7033..2cd7520ae4 100644 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/BrokerClosesClientConnectionTest.java +++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/BrokerClosesClientConnectionTest.java @@ -26,7 +26,6 @@ import java.util.concurrent.TimeUnit; import org.apache.qpid.AMQConnectionClosedException; import org.apache.qpid.AMQDisconnectedException; import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.management.jmx.ManagedConnectionMBeanTest; import org.apache.qpid.test.utils.QpidBrokerTestCase; import org.apache.qpid.transport.ConnectionException; diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/JMXTestUtils.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/JMXTestUtils.java index 1ef6164db6..43b80b45fb 100644 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/JMXTestUtils.java +++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/JMXTestUtils.java @@ -33,11 +33,15 @@ import org.apache.qpid.management.common.mbeans.ManagedQueue; import org.apache.qpid.management.common.mbeans.ServerInformation; import org.apache.qpid.management.common.mbeans.UserManagement; +import javax.management.InstanceNotFoundException; import javax.management.JMException; +import javax.management.ListenerNotFoundException; import javax.management.MBeanException; import javax.management.MBeanServerConnection; import javax.management.MBeanServerInvocationHandler; import javax.management.MalformedObjectNameException; +import javax.management.NotificationFilter; +import javax.management.NotificationListener; import javax.management.ObjectName; import javax.management.remote.JMXConnector; import java.io.IOException; @@ -50,8 +54,8 @@ import java.util.Set; */ public class JMXTestUtils { - private static final String DEFAULT_PASSWORD = "admin"; - private static final String DEFAULT_USERID = "admin"; + public static final String DEFAULT_PASSWORD = "admin"; + public static final String DEFAULT_USERID = "admin"; private MBeanServerConnection _mbsc; private JMXConnector _jmxc; @@ -101,6 +105,18 @@ public class JMXTestUtils } } + public void addNotificationListener(ObjectName name, NotificationListener listener, NotificationFilter filter, Object handback) + throws InstanceNotFoundException, IOException + { + _mbsc.addNotificationListener(name, listener, filter, handback); + } + + public void removeNotificationListener(ObjectName name, NotificationListener listener) + throws InstanceNotFoundException, IOException, ListenerNotFoundException + { + _mbsc.removeNotificationListener(name, listener); + } + /** * Create a non-durable exchange with the requested name * @@ -144,7 +160,6 @@ public class JMXTestUtils throws IOException, JMException, MBeanException { ManagedBroker managedBroker = getManagedBroker(virtualHostName); - managedBroker.unregisterExchange(exchange); } @@ -160,87 +175,81 @@ public class JMXTestUtils throws IOException, JMException, MBeanException { ManagedBroker managedBroker = getManagedBroker(virtualHostName); - managedBroker.deleteQueue(queueName); } - + /** - * Sets the logging level. + * Sets the logging level. * * @throws JMException * @throws IOException if there is a problem with the JMX Connection * @throws MBeanException */ public void setRuntimeLoggerLevel(String logger, String level) - throws IOException, JMException, MBeanException + throws IOException, JMException, MBeanException { LoggingManagement loggingManagement = getLoggingManagement(); - loggingManagement.setRuntimeLoggerLevel(logger, level); } - + /** - * Reload logging config file. + * Reload logging config file. * * @throws JMException * @throws IOException if there is a problem with the JMX Connection * @throws MBeanException */ public void reloadConfigFile() - throws IOException, JMException, MBeanException + throws IOException, JMException, MBeanException { LoggingManagement loggingManagement = getLoggingManagement(); - loggingManagement.reloadConfigFile(); } /** - * Get list of available logger levels. + * Get list of available logger levels. * * @throws JMException * @throws IOException if there is a problem with the JMX Connection * @throws MBeanException */ public String[] getAvailableLoggerLevels() - throws IOException, JMException, MBeanException + throws IOException, JMException, MBeanException { LoggingManagement loggingManagement = getLoggingManagement(); - return loggingManagement.getAvailableLoggerLevels(); } - + /** - * Set root logger level. + * Set root logger level. * * @throws JMException * @throws IOException if there is a problem with the JMX Connection * @throws MBeanException */ public void setRuntimeRootLoggerLevel(String level) - throws IOException, JMException, MBeanException + throws IOException, JMException, MBeanException { LoggingManagement loggingManagement = getLoggingManagement(); - loggingManagement.setRuntimeRootLoggerLevel(level); } - + /** - * Get root logger level. + * Get root logger level. * * @throws JMException * @throws IOException if there is a problem with the JMX Connection * @throws MBeanException */ public String getRuntimeRootLoggerLevel() - throws IOException, JMException, MBeanException + throws IOException, JMException, MBeanException { LoggingManagement loggingManagement = getLoggingManagement(); - return loggingManagement.getRuntimeRootLoggerLevel(); } /** - * Retrive the ObjectName for a Virtualhost. + * Retrieve the ObjectName for a Virtualhost. * * This is then used to create a proxy to the ManagedBroker MBean. * @@ -261,12 +270,12 @@ public class JMXTestUtils // We have verified we have only one value in objectNames so return it ObjectName objectName = objectNames.iterator().next(); - _test.getLogger().info("Loading: " + objectName); + _test.getLogger().info("Loading: " + objectName); return objectName; } /** - * Retrive the ObjectName for the given Queue on a Virtualhost. + * Retrieve the ObjectName for the given Queue on a Virtualhost. * * This is then used to create a proxy to the ManagedQueue MBean. * @@ -289,7 +298,7 @@ public class JMXTestUtils // We have verified we have only one value in objectNames so return it ObjectName objectName = objectNames.iterator().next(); - _test.getLogger().info("Loading: " + objectName); + _test.getLogger().info("Loading: " + objectName); return objectName; } @@ -317,7 +326,7 @@ public class JMXTestUtils // We have verified we have only one value in objectNames so return it ObjectName objectName = objectNames.iterator().next(); - _test.getLogger().info("Loading: " + objectName); + _test.getLogger().info("Loading: " + objectName); return objectName; } @@ -330,7 +339,7 @@ public class JMXTestUtils _test.assertEquals("Unexpected number of objects matching " + managedClass + " returned", 1, objectNames.size()); ObjectName objectName = objectNames.iterator().next(); - _test.getLogger().info("Loading: " + objectName); + _test.getLogger().info("Loading: " + objectName); return getManagedObject(managedClass, objectName); } @@ -363,34 +372,34 @@ public class JMXTestUtils { return getManagedObject(ManagedBroker.class, getVirtualHostManagerObjectName(virtualHost)); } - + public ManagedExchange getManagedExchange(String exchangeName) { - ObjectName objectName = getExchangeObjectName("test", exchangeName); + ObjectName objectName = getExchangeObjectName("test", exchangeName); return MBeanServerInvocationHandler.newProxyInstance(_mbsc, objectName, ManagedExchange.class, false); } - + public ManagedQueue getManagedQueue(String queueName) { ObjectName objectName = getQueueObjectName("test", queueName); return getManagedObject(ManagedQueue.class, objectName); } - public LoggingManagement getLoggingManagement() throws MalformedObjectNameException + public LoggingManagement getLoggingManagement() throws MalformedObjectNameException { - ObjectName objectName = new ObjectName("org.apache.qpid:type=LoggingManagement,name=LoggingManagement"); + ObjectName objectName = new ObjectName("org.apache.qpid:type=LoggingManagement,name=LoggingManagement"); return getManagedObject(LoggingManagement.class, objectName); } - - public ConfigurationManagement getConfigurationManagement() throws MalformedObjectNameException + + public ConfigurationManagement getConfigurationManagement() throws MalformedObjectNameException { - ObjectName objectName = new ObjectName("org.apache.qpid:type=ConfigurationManagement,name=ConfigurationManagement"); + ObjectName objectName = new ObjectName("org.apache.qpid:type=ConfigurationManagement,name=ConfigurationManagement"); return getManagedObject(ConfigurationManagement.class, objectName); } - - public UserManagement getUserManagement() throws MalformedObjectNameException + + public UserManagement getUserManagement() throws MalformedObjectNameException { - ObjectName objectName = new ObjectName("org.apache.qpid:type=UserManagement,name=UserManagement"); + ObjectName objectName = new ObjectName("org.apache.qpid:type=UserManagement,name=UserManagement"); return getManagedObject(UserManagement.class, objectName); } diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/QpidBrokerTestCase.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/QpidBrokerTestCase.java index c5077ccb64..056356cad7 100644 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/QpidBrokerTestCase.java +++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/QpidBrokerTestCase.java @@ -83,6 +83,10 @@ public class QpidBrokerTestCase extends QpidTestCase INTERNAL /** Test case starts an embedded broker within this JVM */, SPAWNED /** Test case spawns a new broker as a separate process */ } + + public static final String GUEST_USERNAME = "guest"; + public static final String GUEST_PASSWORD = "guest"; + protected final static String QpidHome = System.getProperty("QPID_HOME"); protected File _configFile = new File(System.getProperty("broker.config")); @@ -1095,7 +1099,7 @@ public class QpidBrokerTestCase extends QpidTestCase public Connection getConnection() throws JMSException, NamingException { - return getConnection("guest", "guest"); + return getConnection(GUEST_USERNAME, GUEST_PASSWORD); } public Connection getConnection(ConnectionURL url) throws JMSException diff --git a/qpid/java/test-profiles/CPPExcludes b/qpid/java/test-profiles/CPPExcludes index 23722ae5cd..7c653c73f1 100755 --- a/qpid/java/test-profiles/CPPExcludes +++ b/qpid/java/test-profiles/CPPExcludes @@ -101,11 +101,8 @@ org.apache.qpid.server.logging.subjects.* org.apache.qpid.server.logging.actors.* // CPP Broker does not have a JMX interface to test -org.apache.qpid.management.jmx.* -org.apache.qpid.server.queue.AMQQueueMBeanTest#* -org.apache.qpid.server.exchange.ExchangeMBeanTest#* -org.apache.qpid.server.AMQBrokerManagerMBeanTest#* -org.apache.qpid.server.protocol.AMQProtocolSessionMBeanTest#* +org.apache.qpid.server.jmx.mbeans.* +org.apache.qpid.systest.management.jmx.* // JMX is used in this test for validation org.apache.qpid.server.queue.ModelTest#* @@ -159,8 +156,6 @@ org.apache.qpid.test.unit.transacted.TransactionTimeoutConfigurationTest#* org.apache.qpid.test.unit.transacted.TransactionTimeoutTest#* // Java broker only -org.apache.qpid.server.logging.management.LoggingManagementMBeanTest#* -org.apache.qpid.server.management.AMQUserManagementMBeanTest#* org.apache.qpid.server.SupportedProtocolVersionsTest#* diff --git a/qpid/java/test-profiles/Excludes b/qpid/java/test-profiles/Excludes index c0532e0b97..bff362b07e 100644 --- a/qpid/java/test-profiles/Excludes +++ b/qpid/java/test-profiles/Excludes @@ -31,3 +31,10 @@ org.apache.qpid.server.logging.DerbyMessageStoreLoggingTest#* org.apache.qpid.client.ssl.SSLTest#testVerifyLocalHostLocalDomain +// QPID-3936: disable the systests temporarily +org.apache.qpid.systest.disttest.* +org.apache.qpid.systest.disttest.clientonly.* +org.apache.qpid.systest.disttest.controlleronly.* +org.apache.qpid.systest.disttest.controllerandclient.* +org.apache.qpid.systest.disttest.endtoend.* + diff --git a/qpid/java/test-profiles/Java010Excludes b/qpid/java/test-profiles/Java010Excludes index e34cd6b694..f9ba753a5f 100755 --- a/qpid/java/test-profiles/Java010Excludes +++ b/qpid/java/test-profiles/Java010Excludes @@ -65,3 +65,8 @@ org.apache.qpid.client.failover.AddressBasedFailoverBehaviourTest#testFlowContro // QPID-3604: Immediate Prefetch no longer supported by 0-10 org.apache.qpid.client.AsynchMessageListenerTest#testImmediatePrefetchWithMessageListener +// QPID-4090: Can't connect from Java Client to Java Broker when Broker uses Base64MD5PasswordFilePrincipalDatabase principal database (0-10 protocol only) +org.apache.qpid.systest.management.jmx.UserManagementWithBase64MD5PasswordsTest#testJmsLoginForNewUser +org.apache.qpid.systest.management.jmx.UserManagementWithBase64MD5PasswordsTest#testJmsLoginNotPossibleForDeletedUser +org.apache.qpid.systest.management.jmx.UserManagementWithBase64MD5PasswordsTest#testJmsLoginForPasswordChangedUser +org.apache.qpid.systest.management.jmx.UserManagementWithBase64MD5PasswordsTest#testReload diff --git a/qpid/java/test-profiles/JavaPre010Excludes b/qpid/java/test-profiles/JavaPre010Excludes index 3f29dee203..422764bad0 100644 --- a/qpid/java/test-profiles/JavaPre010Excludes +++ b/qpid/java/test-profiles/JavaPre010Excludes @@ -70,3 +70,8 @@ org.apache.qpid.test.unit.ct.DurableSubscriberTest#testResubscribeWithChangedSel org.apache.qpid.ra.QpidRAConnectionTest#* org.apache.qpid.ra.QpidRAXAResourceTest#* +// These tests rely on new address syntax +org.apache.qpid.systest.management.jmx.QueueManagementTest#testGetSetAlternateExchange +org.apache.qpid.systest.management.jmx.QueueManagementTest#testRemoveAlternateExchange +org.apache.qpid.systest.management.jmx.QueueManagementTest#testAlternateExchangeSurvivesRestart + diff --git a/qpid/java/test-profiles/JavaTransientExcludes b/qpid/java/test-profiles/JavaTransientExcludes index 3469e35d02..3e42b79d99 100644 --- a/qpid/java/test-profiles/JavaTransientExcludes +++ b/qpid/java/test-profiles/JavaTransientExcludes @@ -42,3 +42,6 @@ org.apache.qpid.server.store.MessageStoreTest#testDurableExchangeRemoval org.apache.qpid.server.store.berkeleydb.* org.apache.qpid.server.store.DurableConfigurationStoreTest#* + +org.apache.qpid.systest.management.jmx.QueueManagementTest#testAlternateExchangeSurvivesRestart +org.apache.qpid.systest.management.jmx.QueueManagementTest#testQueueDescriptionSurvivesRestart |