diff options
185 files changed, 8355 insertions, 1981 deletions
diff --git a/qpid/java/broker/bin/passwd b/qpid/java/broker/bin/passwd new file mode 100644 index 0000000000..c1bb05c082 --- /dev/null +++ b/qpid/java/broker/bin/passwd @@ -0,0 +1,21 @@ +#!/bin/bash
+#
+# 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.
+#
+
+. qpid-run org.apache.qpid.server.security.Passwd "$@"
diff --git a/qpid/java/broker/bin/qpid-server b/qpid/java/broker/bin/qpid-server index 0080209479..a2b416b12b 100644 --- a/qpid/java/broker/bin/qpid-server +++ b/qpid/java/broker/bin/qpid-server @@ -18,4 +18,13 @@ # under the License. # +# Set classpath to include Qpid jar with all required jars in manifest +QPID_LIBS=$QPID_HOME/lib/qpid-incubating.jar:$QPID_HOME/lib/bdbstore-launch.jar + +# Set other variables used by the qpid-run script before calling +export JAVA=java \ + JAVA_VM=-server \ + JAVA_MEM=-Xmx1024m \ + QPID_CLASSPATH=$QPID_LIBS + . qpid-run org.apache.qpid.server.Main "$@" diff --git a/qpid/java/broker/bin/qpid.stop b/qpid/java/broker/bin/qpid.stop index 1bffc8cdb8..9193d3c4e1 100644 --- a/qpid/java/broker/bin/qpid.stop +++ b/qpid/java/broker/bin/qpid.stop @@ -5,9 +5,9 @@ # Script checks for a given pid running PROGRAM and attempts to quit it # -MAX_ATTEMPTS=5 -SLEEP_DELAY=2 -PROGRAM="org.apache.qpid.server.Main" +MAX_ATTEMPTS=1 +SLEEP_DELAY=1 +PROGRAM="DQPID" # @@ -15,7 +15,8 @@ PROGRAM="org.apache.qpid.server.Main" # printActions() { -ps=`ps o command p $1|grep $PROGRAM` +#ps=`ps o command p $1|grep $PROGRAM` +ps=`ps -o args -p $1|grep $PROGRAM` echo "Attempting to kill: $ps" } @@ -36,25 +37,25 @@ quit() kill $1 } +# +# Grep the ps log for the PID ($1) to ensure that it has quit +# +lookup() +{ +result=`ps -o args -p $1 |grep -v grep |grep $PROGRAM |wc -l` +} # # Sleep and then check then lookup the PID($1) to ensure it has quit # check() { +echo "Waiting $SLEEP_DELAY second for $1 to exit" sleep $SLEEP_DELAY lookup $1 } -# -# Grep the ps log for the PID ($1) to ensure that it has quit -# -lookup() -{ -result=`ps p $1 |grep -v grep |grep $PROGRAM |wc -l` -} - # # Verify the PID($1) is available @@ -62,7 +63,7 @@ result=`ps p $1 |grep -v grep |grep $PROGRAM |wc -l` verifyPid() { lookup $1 -if [[ $result == 1 ]] ; then +if [[ $[$result] == 1 ]] ; then brokerspid=$1 else echo "Unable to locate Qpid Process with PID $1" @@ -70,8 +71,6 @@ else fi } - - # # Main Run # @@ -89,22 +88,21 @@ printActions $brokerspid # Attempt to quit the process MAX_ATTEMPTS Times attempt=0 -while [[ $result > 0 && $attempt < $MAX_ATTEMPTS ]] ; do +while [[ $[$result] > 0 && $[$attempt] < $[$MAX_ATTEMPTS] ]] ; do quit $brokerspid check $brokerspid attempt=$[$attempt + 1] done - # Check that it has quit -if [[ $results == 0 ]] ; then +if [[ $[$result] == 0 ]] ; then echo "Process quit" exit 0 else # Now attempt to force quit the process attempt=0 - while [[ $result > 0 && $attempt < $MAX_ATTEMPTS ]] ; do + while [[ $[$result] > 0 && $[$attempt] < $[$MAX_ATTEMPTS] ]] ; do forceQuit $brokerspid check $brokerspid attempt=$[$attempt + 1] @@ -112,7 +110,7 @@ else # Output final status - if [[ $attempt == $MAX_ATTEMPTS ]] ; then + if [[ $[$result] > 0 && $[$attempt] == $[$MAX_ATTEMPTS] ]] ; then echo "Stopped trying to kill process: $brokerspid" echo "Attempted to stop $attempt times" else diff --git a/qpid/java/broker/bin/qpid.stopall b/qpid/java/broker/bin/qpid.stopall index f6862842c9..2e762bdd50 100644 --- a/qpid/java/broker/bin/qpid.stopall +++ b/qpid/java/broker/bin/qpid.stopall @@ -6,17 +6,16 @@ # Utilises qpid.stop to perform the actual stopping # -MAX_ATTEMPTS=5 -SLEEP_DELAY=2 -PROGRAM="org.apache.qpid.server.Main" +PROGRAM="DQPID" # # grep ps for instances of $PROGRAM and collect PIDs # lookup() { -pids=`ps o pid,command |grep -v grep | grep $PROGRAM | cut -d ' ' -f 1` -result=`echo -n $pids | wc -l` +#pids=`ps o pid,command | grep $PROGRAM | grep -v grep | cut -d ' ' -f 1` +pids=`ps -ef |grep $USER | grep $PROGRAM | grep -v grep | awk '{print $2}'` +result=`echo -n $pids | wc -w` } @@ -25,7 +24,7 @@ result=`echo -n $pids | wc -l` # showPids() { -ps p $pids +ps -o user,pid,args -p $pids } @@ -35,7 +34,7 @@ ps p $pids lookup -if [[ $result == 0 ]] ; then +if [[ $[$result] == 0 ]] ; then echo "No Qpid Brokers found running under user '$USER'" exit 0 fi @@ -49,7 +48,7 @@ done # Check we have quit all lookup -if [[ $result == 0 ]] ; then +if [[ $[$result] == 0 ]] ; then echo "All Qpid brokers successfully quit" else echo "Some brokers were not quit" diff --git a/qpid/java/broker/distribution/src/main/assembly/broker-bin.xml b/qpid/java/broker/distribution/src/main/assembly/broker-bin.xml index 4a7343660d..4b32630771 100644 --- a/qpid/java/broker/distribution/src/main/assembly/broker-bin.xml +++ b/qpid/java/broker/distribution/src/main/assembly/broker-bin.xml @@ -78,6 +78,12 @@ <fileMode>420</fileMode> </file> <file> + <source>../etc/jmxremote.access</source> + <outputDirectory>qpid-${qpid.version}/etc</outputDirectory> + <destName>jmxremote.access</destName> + <fileMode>420</fileMode> + </file> + <file> <source>../etc/log4j.xml</source> <outputDirectory>qpid-${qpid.version}/etc</outputDirectory> <destName>log4j.xml</destName> @@ -108,6 +114,12 @@ <fileMode>473</fileMode> </file> <file> + <source>../bin/passwd</source> + <outputDirectory>qpid-${qpid.version}/bin</outputDirectory> + <destName>passwd</destName> + <fileMode>473</fileMode> + </file> + <file> <source>../bin/qpid-server</source> <outputDirectory>qpid-${qpid.version}/bin</outputDirectory> <destName>qpid-server</destName> diff --git a/qpid/java/broker/etc/access b/qpid/java/broker/etc/access new file mode 100644 index 0000000000..a781ed8aa9 --- /dev/null +++ b/qpid/java/broker/etc/access @@ -0,0 +1 @@ +guest:localhost(rw),test(rw)
\ No newline at end of file diff --git a/qpid/java/broker/etc/config.xml b/qpid/java/broker/etc/config.xml index 3789e6fcb6..c66c2f632e 100644 --- a/qpid/java/broker/etc/config.xml +++ b/qpid/java/broker/etc/config.xml @@ -41,6 +41,8 @@ </connector> <management> <enabled>true</enabled> + <jmxport>8999</jmxport> + <security-enabled>true</security-enabled> </management> <advanced> <filterchain enableExecutorPool="true"/> @@ -63,13 +65,14 @@ </attributes> </principal-database> - <!--principal-database> - <name>md5passwordfile</name> - <class>org.apache.qpid.server.security.auth.database.MD5PasswordFilePrincipalDatabase</class> + <!-- Example use of Base64 encoded MD5 hashes for authentication via CRAM-MD5-Hashed + <principal-database> + <name>passwordfile</name> + <class>org.apache.qpid.server.security.auth.database.Base64MD5PasswordFilePrincipalDatabase</class> <attributes> <attribute> <name>passwordFile</name> - <value>${conf}/md5passwd</value> + <value>${conf}/qpid.passwd</value> </attribute> </attributes> </principal-database--> @@ -78,6 +81,10 @@ <access> <class>org.apache.qpid.server.security.access.AllowAll</class> </access> + <jmx> + <access>${conf}/jmxremote.access</access> + <principal-database>passwordfile</principal-database> + </jmx> </security> <virtualhosts> @@ -85,9 +92,10 @@ <name>localhost</name> <localhost> <store> - <!-- <class>org.apache.qpid.server.store.berkeleydb.BDBMessageStore</class> --> + <!-- <class>org.apache.qpid.server.store.berkeleydb.BDBMessageStore</class> + <environment-path>${work}/localhost-store</environment-path> --> + <class>org.apache.qpid.server.store.MemoryMessageStore</class> - <environment-path>localhost-store</environment-path> </store> <security> diff --git a/qpid/java/broker/etc/jmxremote.access b/qpid/java/broker/etc/jmxremote.access new file mode 100644 index 0000000000..d1172fc197 --- /dev/null +++ b/qpid/java/broker/etc/jmxremote.access @@ -0,0 +1,3 @@ +admin=admin +guest=readonly +user=readwrite diff --git a/qpid/java/broker/etc/log4j.xml b/qpid/java/broker/etc/log4j.xml index 74b80c0e80..b442227607 100644 --- a/qpid/java/broker/etc/log4j.xml +++ b/qpid/java/broker/etc/log4j.xml @@ -44,20 +44,16 @@ <param name="backupFilesToPath" value="${QPID_WORK}/backup/log"/> <layout class="org.apache.log4j.PatternLayout"> - <param name="ConversionPattern" value="%d %-5p [%t] %C{2} (%F:%L) - %m%n"/> - <!--param name="ConversionPattern" value="%t %-5p %c{2} - %m%n"/--> + <param name="ConversionPattern" value="%d %-5p [%t] %C{2} (%F:%L) - %m%n"/> </layout> </appender> - <appender name="FileAppender" class="org.apache.log4j.FileAppender"> - <param name="staticLogFileName" value="false"/> - + <appender name="FileAppender" class="org.apache.log4j.FileAppender"> <param name="File" value="${QPID_WORK}/log/${logprefix}qpid${logsuffix}.log"/> <param name="Append" value="false"/> <layout class="org.apache.log4j.PatternLayout"> - <param name="ConversionPattern" value="%t %-5p %c{2} - %m%n"/> - + <param name="ConversionPattern" value="%d %-5p [%t] %C{2} (%F:%L) - %m%n"/> </layout> </appender> diff --git a/qpid/java/broker/etc/persistent_config.xml b/qpid/java/broker/etc/persistent_config.xml new file mode 100644 index 0000000000..178a73515c --- /dev/null +++ b/qpid/java/broker/etc/persistent_config.xml @@ -0,0 +1,132 @@ +<?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. + - + + This is an example config using the BDBMessageStore available from + the Red Hat Messaging project at etp.108.redhat.com and distributed under GPL. + --> + +<broker> + <prefix>${QPID_HOME}</prefix> + <work>${QPID_WORK}</work> + <conf>${prefix}/etc</conf> + <connector> + <qpidnio>true</qpidnio> + <transport>nio</transport> + <port>5672</port> + <sslport>8672</sslport> + <socketReceiveBuffer>32768</socketReceiveBuffer> + <socketSendBuffer>32768</socketSendBuffer> + </connector> + <management> + <enabled>true</enabled> + <jmxport>8999</jmxport> + </management> + <advanced> + <filterchain enableExecutorPool="true"/> + <enablePooledAllocator>false</enablePooledAllocator> + <enableDirectBuffers>false</enableDirectBuffers> + <framesize>65535</framesize> + <compressBufferOnQueue>false</compressBufferOnQueue> + </advanced> + + <security> + <principal-databases> + <principal-database> + <name>passwordfile</name> + <class>org.apache.qpid.server.security.auth.database.PlainPasswordVhostFilePrincipalDatabase</class> + <attributes> + <attribute> + <name>passwordFile</name> + <value>${conf}/passwdVhost</value> + </attribute> + </attributes> + </principal-database> + </principal-databases> + + <access> + <class>org.apache.qpid.server.security.access.AllowAll</class> + </access> + <jmx> + <access>${conf}/jmxremote.access</access> + <principal-database>passwordfile</principal-database> + </jmx> + </security> + + <virtualhosts> + <virtualhost> + <name>localhost</name> + <localhost> + <store> + <class>org.apache.qpid.server.store.berkeleydb.BDBMessageStore</class> + <environment-path>${work}/bdbstore/localhost-store</environment-path> + </store> + + <security> + <access> + <class>org.apache.qpid.server.security.access.PrincipalDatabaseAccessManager</class> + <attributes> + <attribute> + <name>principalDatabase</name> + <value>passwordfile</value> + </attribute> + <attribute> + <name>defaultAccessManager</name> + <value>DenyAll</value> + </attribute> + </attributes> + </access> + </security> + </localhost> + </virtualhost> + + <virtualhost> + <name>development</name> + <development> + <store> + <class>org.apache.qpid.server.store.berkeleydb.BDBMessageStore</class> + <environment-path>${work}/bdbstore/development-store</environment-path> + </store> + </development> + </virtualhost> + + <virtualhost> + <name>test</name> + <test> + <store> + <class>org.apache.qpid.server.store.berkeleydb.BDBMessageStore</class> + <environment-path>${work}/bdbstore/test-store</environment-path> + </store> + </test> + </virtualhost> + + </virtualhosts> + <heartbeat> + <delay>0</delay> + <timeoutFactor>2.0</timeoutFactor> + </heartbeat> + <queue> + <auto_register>true</auto_register> + </queue> + + <virtualhosts>${conf}/virtualhosts.xml</virtualhosts> +</broker> + + diff --git a/qpid/java/broker/etc/transient_config.xml b/qpid/java/broker/etc/transient_config.xml new file mode 100644 index 0000000000..164d66cd1b --- /dev/null +++ b/qpid/java/broker/etc/transient_config.xml @@ -0,0 +1,128 @@ +<?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. + - + + This is an example config file that uses the MemoryMessageStore. + As a result it is aimed at brokers sending transient messages. + + --> +<broker> + <prefix>${QPID_HOME}</prefix> + <work>${QPID_WORK}</work> + <conf>${prefix}/etc</conf> + <connector> + <qpidnio>true</qpidnio> + <transport>nio</transport> + <port>5672</port> + <sslport>8672</sslport> + <socketReceiveBuffer>32768</socketReceiveBuffer> + <socketSendBuffer>32768</socketSendBuffer> + </connector> + <management> + <enabled>true</enabled> + <jmxport>8999</jmxport> + </management> + <advanced> + <filterchain enableExecutorPool="true"/> + <enablePooledAllocator>false</enablePooledAllocator> + <enableDirectBuffers>false</enableDirectBuffers> + <framesize>65535</framesize> + <compressBufferOnQueue>false</compressBufferOnQueue> + </advanced> + + <security> + <principal-databases> + <principal-database> + <name>passwordfile</name> + <class>org.apache.qpid.server.security.auth.database.PlainPasswordVhostFilePrincipalDatabase</class> + <attributes> + <attribute> + <name>passwordFile</name> + <value>${conf}/passwdVhost</value> + </attribute> + </attributes> + </principal-database> + </principal-databases> + <access> + <class>org.apache.qpid.server.security.access.AllowAll</class> + </access> + <jmx> + <access>${conf}/jmxremote.access</access> + <principal-database>passwordfile</principal-database> + </jmx> + </security> + + <virtualhosts> + <virtualhost> + <name>localhost</name> + <localhost> + <store> + <class>org.apache.qpid.server.store.MemoryMessageStore</class> + </store> + + <security> + <access> + <class>org.apache.qpid.server.security.access.PrincipalDatabaseAccessManager</class> + <attributes> + <attribute> + <name>principalDatabase</name> + <value>passwordfile</value> + </attribute> + <attribute> + <name>defaultAccessManager</name> + <value>DenyAll</value> + </attribute> + </attributes> + </access> + </security> + </localhost> + </virtualhost> + + <virtualhost> + <name>development</name> + <development> + <store> + <class>org.apache.qpid.server.store.MemoryMessageStore</class> + </store> + </development> + </virtualhost> + + <virtualhost> + <name>test</name> + <test> + <store> + <class>org.apache.qpid.server.store.MemoryMessageStore</class> + </store> + </test> + </virtualhost> + + </virtualhosts> + <heartbeat> + <delay>0</delay> + <timeoutFactor>2.0</timeoutFactor> + </heartbeat> + <queue> + <auto_register>true</auto_register> + </queue> + + <virtualhosts>${conf}/virtualhosts.xml</virtualhosts> +</broker> + + 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 index 23c32aceab..d31359b019 100644 --- 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 @@ -1,5 +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. + * + */ +/* + * * Copyright (c) 2006 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -22,8 +42,12 @@ import javax.management.MBeanException; import javax.management.MalformedObjectNameException; import javax.management.ObjectName; +import org.apache.commons.configuration.Configuration; + import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.server.configuration.Configurator; +import org.apache.qpid.server.configuration.VirtualHostConfiguration; import org.apache.qpid.server.exchange.Exchange; import org.apache.qpid.server.exchange.ExchangeFactory; import org.apache.qpid.server.exchange.ExchangeRegistry; @@ -36,9 +60,6 @@ import org.apache.qpid.server.queue.AMQQueue; import org.apache.qpid.server.queue.QueueRegistry; import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.configuration.Configurator; -import org.apache.qpid.server.configuration.VirtualHostConfiguration; -import org.apache.commons.configuration.Configuration; /** * This MBean implements the broker management interface and exposes the @@ -82,8 +103,7 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr * @param autoDelete * @throws JMException */ - public void createNewExchange(String exchangeName, String type, boolean durable, boolean autoDelete) - throws JMException + public void createNewExchange(String exchangeName, String type, boolean durable) throws JMException { try { @@ -92,7 +112,8 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr Exchange exchange = _exchangeRegistry.getExchange(new AMQShortString(exchangeName)); if (exchange == null) { - exchange = _exchangeFactory.createExchange(new AMQShortString(exchangeName), new AMQShortString(type), durable, autoDelete, 0); + exchange = _exchangeFactory.createExchange(new AMQShortString(exchangeName), new AMQShortString(type), + durable, false, 0); _exchangeRegistry.registerExchange(exchange); } else @@ -140,8 +161,7 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr * @param autoDelete * @throws JMException */ - public void createNewQueue(String queueName, String owner, boolean durable,boolean autoDelete) - throws JMException + public void createNewQueue(String queueName, String owner, boolean durable) throws JMException { AMQQueue queue = _queueRegistry.getQueue(new AMQShortString(queueName)); if (queue != null) @@ -156,22 +176,27 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr { ownerShortString = new AMQShortString(owner); } - queue = new AMQQueue(new AMQShortString(queueName), durable, ownerShortString, autoDelete, getVirtualHost()); + + queue = new AMQQueue(new AMQShortString(queueName), durable, ownerShortString, false, getVirtualHost()); if (queue.isDurable() && !queue.isAutoDelete()) { _messageStore.createQueue(queue); } - Configuration virtualHostDefaultQueueConfiguration = VirtualHostConfiguration.getDefaultQueueConfiguration(queue); + Configuration virtualHostDefaultQueueConfiguration = + VirtualHostConfiguration.getDefaultQueueConfiguration(queue); if (virtualHostDefaultQueueConfiguration != null) { Configurator.configure(queue, virtualHostDefaultQueueConfiguration); } + _queueRegistry.registerQueue(queue); } catch (AMQException ex) { - throw new MBeanException(new JMException(ex.getMessage()),"Error in creating queue " + queueName); + JMException jme = new JMException(ex.getMessage()); + jme.initCause(ex); + throw new MBeanException(jme, "Error in creating queue " + queueName); } } @@ -202,7 +227,9 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr } catch (AMQException ex) { - throw new MBeanException(new JMException(ex.getMessage()), "Error in deleting queue " + queueName); + JMException jme = new JMException(ex.getMessage()); + jme.initCause(ex); + throw new MBeanException(jme, "Error in deleting queue " + queueName); } } @@ -213,7 +240,7 @@ public class AMQBrokerManagerMBean extends AMQManagedObject implements ManagedBr // This will have a single instance for a virtual host, so not having the name property in the ObjectName public ObjectName getObjectName() throws MalformedObjectNameException - { + { return getObjectNameForSingleInstanceMBean(); } } // End of MBean class 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 1ebe5fa0a2..2e1653e69d 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 @@ -472,7 +472,7 @@ public class AMQChannel if (unacked.queue != null) { // Ensure message is released for redelivery - unacked.message.release(); + unacked.message.release(unacked.queue); // Mark message redelivered unacked.message.setRedelivered(true); @@ -503,7 +503,10 @@ public class AMQChannel { // Ensure message is released for redelivery - unacked.message.release(); + if (unacked.queue != null) + { + unacked.message.release(unacked.queue); + } // Mark message redelivered unacked.message.setRedelivered(true); @@ -672,14 +675,14 @@ public class AMQChannel // else // { //release to allow it to be delivered - msg.release(); + msg.release(message.queue); // Without any details from the client about what has been processed we have to mark // all messages in the unacked map as redelivered. msg.setRedelivered(true); - Subscription sub = msg.getDeliveredSubscription(); + Subscription sub = msg.getDeliveredSubscription(message.queue); if (sub != null) { @@ -753,7 +756,7 @@ public class AMQChannel // Process Messages to Requeue at the front of the queue for (UnacknowledgedMessage message : msgToRequeue) { - message.message.release(); + message.message.release(message.queue); message.message.setRedelivered(true); deliveryContext.deliver(message.message, message.queue, true); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java index 38a505c6c7..146d0566ce 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.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 @@ -36,14 +36,17 @@ import org.apache.commons.cli.Options; import org.apache.commons.cli.ParseException; import org.apache.commons.cli.PosixParser; import org.apache.commons.configuration.ConfigurationException; + import org.apache.log4j.BasicConfigurator; import org.apache.log4j.Logger; import org.apache.log4j.xml.DOMConfigurator; + import org.apache.mina.common.ByteBuffer; import org.apache.mina.common.IoAcceptor; import org.apache.mina.common.SimpleByteBufferAllocator; import org.apache.mina.transport.socket.nio.SocketAcceptorConfig; import org.apache.mina.transport.socket.nio.SocketSessionConfig; + import org.apache.qpid.AMQException; import org.apache.qpid.framing.ProtocolVersion; import org.apache.qpid.pool.ReadWriteThreadModel; @@ -59,7 +62,7 @@ import org.apache.qpid.url.URLSyntaxException; * Main entry point for AMQPD. * */ -@SuppressWarnings({"AccessStaticViaInstance"}) +@SuppressWarnings({ "AccessStaticViaInstance" }) public class Main { private static final Logger _logger = Logger.getLogger(Main.class); @@ -74,9 +77,9 @@ public class Main protected static class InitException extends Exception { - InitException(String msg) + InitException(String msg, Throwable cause) { - super(msg); + super(msg, cause); } } @@ -97,6 +100,7 @@ public class Main try { commandLine = new PosixParser().parse(options, args); + return true; } catch (ParseException e) @@ -104,6 +108,7 @@ public class Main System.err.println("Error: " + e.getMessage()); HelpFormatter formatter = new HelpFormatter(); formatter.printHelp("Qpid", options, true); + return false; } } @@ -112,17 +117,26 @@ public class Main { Option help = new Option("h", "help", false, "print this message"); Option version = new Option("v", "version", false, "print the version information and exit"); - Option configFile = OptionBuilder.withArgName("file").hasArg().withDescription("use given configuration file"). - withLongOpt("config").create("c"); - Option port = OptionBuilder.withArgName("port").hasArg().withDescription("listen on the specified port. Overrides any value in the config file"). - withLongOpt("port").create("p"); - Option bind = OptionBuilder.withArgName("bind").hasArg().withDescription("bind to the specified address. Overrides any value in the config file"). - withLongOpt("bind").create("b"); - Option logconfig = OptionBuilder.withArgName("logconfig").hasArg().withDescription("use the specified log4j xml configuration file. By " + - "default looks for a file named " + DEFAULT_LOG_CONFIG_FILENAME + " in the same directory as the configuration file"). - withLongOpt("logconfig").create("l"); - Option logwatchconfig = OptionBuilder.withArgName("logwatch").hasArg().withDescription("monitor the log file configuration file for changes. Units are seconds. " + - "Zero means do not check for changes.").withLongOpt("logwatch").create("w"); + Option configFile = + OptionBuilder.withArgName("file").hasArg().withDescription("use given configuration file").withLongOpt("config") + .create("c"); + Option port = + OptionBuilder.withArgName("port").hasArg() + .withDescription("listen on the specified port. Overrides any value in the config file") + .withLongOpt("port").create("p"); + Option bind = + OptionBuilder.withArgName("bind").hasArg() + .withDescription("bind to the specified address. Overrides any value in the config file") + .withLongOpt("bind").create("b"); + Option logconfig = + OptionBuilder.withArgName("logconfig").hasArg() + .withDescription("use the specified log4j xml configuration file. By " + + "default looks for a file named " + DEFAULT_LOG_CONFIG_FILENAME + + " in the same directory as the configuration file").withLongOpt("logconfig").create("l"); + Option logwatchconfig = + OptionBuilder.withArgName("logwatch").hasArg() + .withDescription("monitor the log file configuration file for changes. Units are seconds. " + + "Zero means do not check for changes.").withLongOpt("logwatch").create("w"); options.addOption(help); options.addOption(version); @@ -150,7 +164,7 @@ public class Main boolean first = true; for (ProtocolVersion pv : ProtocolVersion.getSupportedProtocolVersions()) { - if(first) + if (first) { first = false; } @@ -158,9 +172,11 @@ public class Main { protocol.append(", "); } + protocol.append(pv.getMajorVersion()).append('-').append(pv.getMinorVersion()); } + System.out.println(ver + " (" + protocol + ")"); } else @@ -186,7 +202,6 @@ public class Main } } - protected void startup() throws InitException, ConfigurationException, Exception { final String QpidHome = System.getProperty("QPID_HOME"); @@ -201,7 +216,7 @@ public class Main error = error + "\nNote: Qpid_HOME is not set."; } - throw new InitException(error); + throw new InitException(error, null); } else { @@ -226,8 +241,8 @@ public class Main _logger.info("Starting Qpid.AMQP broker"); - ConnectorConfiguration connectorConfig = ApplicationRegistry.getInstance(). - getConfiguredObject(ConnectorConfiguration.class); + ConnectorConfiguration connectorConfig = + ApplicationRegistry.getInstance().getConfiguredObject(ConnectorConfiguration.class); ByteBuffer.setUseDirectBuffers(connectorConfig.enableDirectBuffers); @@ -249,7 +264,7 @@ public class Main } catch (NumberFormatException e) { - throw new InitException("Invalid port: " + portStr); + throw new InitException("Invalid port: " + portStr, e); } } @@ -264,19 +279,21 @@ public class Main int totalVHosts = ((Collection) virtualHosts).size(); for (int vhost = 0; vhost < totalVHosts; vhost++) { - setupVirtualHosts(configFile.getParent() , (String)((List)virtualHosts).get(vhost)); + setupVirtualHosts(configFile.getParent(), (String) ((List) virtualHosts).get(vhost)); } } else { - setupVirtualHosts(configFile.getParent() , (String)virtualHosts); + setupVirtualHosts(configFile.getParent(), (String) virtualHosts); } } + bind(port, connectorConfig); } - protected void setupVirtualHosts(String configFileParent, String configFilePath) throws ConfigurationException, AMQException, URLSyntaxException + protected void setupVirtualHosts(String configFileParent, String configFilePath) + throws ConfigurationException, AMQException, URLSyntaxException { String configVar = "${conf}"; @@ -285,7 +302,7 @@ public class Main configFilePath = configFileParent + configFilePath.substring(configVar.length()); } - if (configFilePath.indexOf(".xml") != -1 ) + if (configFilePath.indexOf(".xml") != -1) { VirtualHostConfiguration vHostConfig = new VirtualHostConfiguration(configFilePath); vHostConfig.performBindings(); @@ -298,11 +315,12 @@ public class Main String[] fileNames = virtualHostDir.list(); - for (int each=0; each < fileNames.length; each++) + for (int each = 0; each < fileNames.length; each++) { if (fileNames[each].endsWith(".xml")) { - VirtualHostConfiguration vHostConfig = new VirtualHostConfiguration(configFilePath+"/"+fileNames[each]); + VirtualHostConfiguration vHostConfig = + new VirtualHostConfiguration(configFilePath + "/" + fileNames[each]); vHostConfig.performBindings(); } } @@ -319,7 +337,7 @@ public class Main try { - //IoAcceptor acceptor = new SocketAcceptor(connectorConfig.processors); + // IoAcceptor acceptor = new SocketAcceptor(connectorConfig.processors); IoAcceptor acceptor = connectorConfig.createAcceptor(); SocketAcceptorConfig sconfig = (SocketAcceptorConfig) acceptor.getDefaultConfig(); SocketSessionConfig sc = (SocketSessionConfig) sconfig.getSessionConfig(); @@ -334,7 +352,7 @@ public class Main { sconfig.setThreadModel(ReadWriteThreadModel.getInstance()); } - + if (!connectorConfig.enableSSL || !connectorConfig.sslOnly) { AMQPFastProtocolHandler handler = new AMQPProtocolProvider().getHandler(); @@ -347,6 +365,7 @@ public class Main { bindAddress = new InetSocketAddress(InetAddress.getByAddress(parseIP(bindAddr)), port); } + acceptor.bind(bindAddress, handler, sconfig); _logger.info("Qpid.AMQP listening on non-SSL address " + bindAddress); } @@ -356,8 +375,7 @@ public class Main AMQPFastProtocolHandler handler = new AMQPProtocolProvider().getHandler(); try { - acceptor.bind(new InetSocketAddress(connectorConfig.sslPort), - handler, sconfig); + acceptor.bind(new InetSocketAddress(connectorConfig.sslPort), handler, sconfig); _logger.info("Qpid.AMQP listening on SSL port " + connectorConfig.sslPort); } catch (IOException e) @@ -415,16 +433,17 @@ public class Main } catch (NumberFormatException e) { - System.err.println("Log watch configuration value of " + logWatchConfig + " is invalid. Must be " + - "a non-negative integer. Using default of zero (no watching configured"); + System.err.println("Log watch configuration value of " + logWatchConfig + " is invalid. Must be " + + "a non-negative integer. Using default of zero (no watching configured"); } + if (logConfigFile.exists() && logConfigFile.canRead()) { System.out.println("Configuring logger using configuration file " + logConfigFile.getAbsolutePath()); if (logWatchTime > 0) { - System.out.println("log file " + logConfigFile.getAbsolutePath() + " will be checked for changes every " + - logWatchTime + " seconds"); + System.out.println("log file " + logConfigFile.getAbsolutePath() + " will be checked for changes every " + + logWatchTime + " seconds"); // log4j expects the watch interval in milliseconds DOMConfigurator.configureAndWatch(logConfigFile.getAbsolutePath(), logWatchTime * 1000); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java index 4d66e37628..de3905268e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DestNameExchange.java @@ -196,6 +196,7 @@ public class DestNameExchange extends AbstractExchange } else { + _logger.error("MESSAGE LOSS: Message should be sent on a Dead Letter Queue"); _logger.warn(msg); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRejectMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRejectMethodHandler.java index 14687c40ae..9052b2e81f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRejectMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicRejectMethodHandler.java @@ -98,7 +98,7 @@ public class BasicRejectMethodHandler implements StateAwareMethodListener<BasicR // If we haven't requested message to be resent to this consumer then reject it from ever getting it. // if (!evt.getMethod().resend) { - message.message.reject(message.message.getDeliveredSubscription()); + message.message.reject(message.message.getDeliveredSubscription(message.queue)); } if (evt.getMethod().requeue) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java index 2ecb39254f..30a40c5a75 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionOpenMethodHandler.java @@ -33,6 +33,7 @@ import org.apache.qpid.server.state.AMQStateManager; import org.apache.qpid.server.state.StateAwareMethodListener; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.security.access.AccessResult; +import org.apache.qpid.server.security.access.AccessRights; import org.apache.log4j.Logger; public class ConnectionOpenMethodHandler implements StateAwareMethodListener<ConnectionOpenBody> @@ -75,23 +76,26 @@ public class ConnectionOpenMethodHandler implements StateAwareMethodListener<Con if (virtualHost == null) { - throw body.getConnectionException(AMQConstant.NOT_FOUND, "Unknown virtual host: " + virtualHostName); + throw body.getConnectionException(AMQConstant.NOT_FOUND, "Unknown virtual host: '" + virtualHostName + "'"); } else { session.setVirtualHost(virtualHost); - AccessResult result = virtualHost.getAccessManager().isAuthorized(virtualHost, session.getAuthorizedID()); + AccessResult result = virtualHost.getAccessManager().isAuthorized(virtualHost, session.getAuthorizedID(), AccessRights.Rights.ANY); switch (result.getStatus()) { default: case REFUSED: - throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, - "Access denied to vHost '" + virtualHostName + "' by " - + result.getAuthorizer()); + String error = "Any access denied to vHost '" + virtualHostName + "' by " + + result.getAuthorizer(); + + _logger.warn(error); + + throw body.getConnectionException(AMQConstant.ACCESS_REFUSED, error); case GRANTED: - _logger.info("Granted access to vHost '" + virtualHostName + "' for " + session.getAuthorizedID() + _logger.info("Granted any access to vHost '" + virtualHostName + "' for " + session.getAuthorizedID() + " by '" + result.getAuthorizer() + "'"); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java index 6029a023e5..fef00942a0 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java @@ -37,6 +37,7 @@ import org.apache.qpid.server.protocol.HeartbeatConfig; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.security.auth.manager.AuthenticationManager; import org.apache.qpid.server.security.auth.AuthenticationResult; +import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; import org.apache.qpid.server.state.AMQState; import org.apache.qpid.server.state.AMQStateManager; import org.apache.qpid.server.state.StateAwareMethodListener; @@ -106,7 +107,7 @@ public class ConnectionSecureOkMethodHandler implements StateAwareMethodListener ConnectionStartOkMethodHandler.getConfiguredFrameSize(), // frameMax HeartbeatConfig.getInstance().getDelay()); // heartbeat session.writeFrame(tune); - session.setAuthorizedID(ss.getAuthorizationID()); + session.setAuthorizedID(new UsernamePrincipal(ss.getAuthorizationID())); disposeSaslServer(session); break; case CONTINUE: diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java index 6c14aae7ed..4734143497 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java @@ -37,6 +37,7 @@ import org.apache.qpid.server.protocol.HeartbeatConfig; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.security.auth.manager.AuthenticationManager; import org.apache.qpid.server.security.auth.AuthenticationResult; +import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; import org.apache.qpid.server.state.AMQState; import org.apache.qpid.server.state.AMQStateManager; import org.apache.qpid.server.state.StateAwareMethodListener; @@ -95,7 +96,7 @@ public class ConnectionStartOkMethodHandler implements StateAwareMethodListener< throw new AMQException("Authentication failed"); case SUCCESS: _logger.info("Connected as: " + ss.getAuthorizationID()); - session.setAuthorizedID(ss.getAuthorizationID()); + session.setAuthorizedID(new UsernamePrincipal(ss.getAuthorizationID())); stateManager.changeState(AMQState.CONNECTION_NOT_TUNED); // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java index 9e0a1019f2..2e697d4564 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java @@ -64,7 +64,6 @@ public class QueueDeclareHandler implements StateAwareMethodListener<QueueDeclar private final AtomicInteger _counter = new AtomicInteger(); - protected QueueDeclareHandler() { Configurator.configure(this); @@ -92,12 +91,12 @@ public class QueueDeclareHandler implements StateAwareMethodListener<QueueDeclar synchronized (queueRegistry) { - if (((queue = queueRegistry.getQueue(body.queue)) == null) ) + if (((queue = queueRegistry.getQueue(body.queue)) == null)) { - if(body.passive) + if (body.passive) { - String msg = "Queue: " + body.queue + " not found."; - throw body.getChannelException(AMQConstant.NOT_FOUND,msg ); + String msg = "Queue: " + body.queue + " not found on VirtualHost(" + virtualHost + ")."; + throw body.getChannelException(AMQConstant.NOT_FOUND, msg); } else { @@ -112,13 +111,16 @@ public class QueueDeclareHandler implements StateAwareMethodListener<QueueDeclar Exchange defaultExchange = exchangeRegistry.getDefaultExchange(); queue.bind(body.queue, null, defaultExchange); - _log.info("Queue " + body.queue + " bound to default exchange"); + _log.info("Queue " + body.queue + " bound to default exchange(" + defaultExchange.getName() + ")"); } } } - else if(queue.getOwner() != null && !session.getContextKey().equals(queue.getOwner())) + else if (queue.getOwner() != null && !session.getContextKey().equals(queue.getOwner())) { - throw body.getChannelException(AMQConstant.ALREADY_EXISTS, "Cannot declare queue, as exclusive queue with same name declared on another connection"); + throw body.getChannelException(AMQConstant.ALREADY_EXISTS, "Cannot declare queue('" + body.queue + "')," + + " as exclusive queue with same name " + + "declared on another client ID('" + + queue.getOwner() + "')"); } AMQChannel channel = session.getChannel(evt.getChannelId()); @@ -138,10 +140,10 @@ public class QueueDeclareHandler implements StateAwareMethodListener<QueueDeclar // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. // Be aware of possible changes to parameter order as versions change. AMQFrame response = QueueDeclareOkBody.createAMQFrame(evt.getChannelId(), - (byte)8, (byte)0, // AMQP version (major, minor) - queue.getConsumerCount(), // consumerCount - queue.getMessageCount(), // messageCount - body.queue); // queue + (byte) 8, (byte) 0, // AMQP version (major, minor) + queue.getConsumerCount(), // consumerCount + queue.getMessageCount(), // messageCount + body.queue); // queue _log.info("Queue " + body.queue + " declared successfully"); session.writeFrame(response); } @@ -162,24 +164,22 @@ public class QueueDeclareHandler implements StateAwareMethodListener<QueueDeclar { final QueueRegistry registry = virtualHost.getQueueRegistry(); AMQShortString owner = body.exclusive ? session.getContextKey() : null; - final AMQQueue queue = new AMQQueue(body.queue, body.durable, owner, body.autoDelete, virtualHost); + final AMQQueue queue = new AMQQueue(body.queue, body.durable, owner, body.autoDelete, virtualHost); final AMQShortString queueName = queue.getName(); - if(body.exclusive && !body.durable) + if (body.exclusive && !body.durable) { final AMQProtocolSession.Task deleteQueueTask = - new AMQProtocolSession.Task() - { - - public void doTask(AMQProtocolSession session) throws AMQException + new AMQProtocolSession.Task() { - if(registry.getQueue(queueName) == queue) + public void doTask(AMQProtocolSession session) throws AMQException { - queue.delete(); + if (registry.getQueue(queueName) == queue) + { + queue.delete(); + } } - - } - }; + }; session.addSessionCloseTask(deleteQueueTask); @@ -190,16 +190,14 @@ public class QueueDeclareHandler implements StateAwareMethodListener<QueueDeclar session.removeSessionCloseTask(deleteQueueTask); } }); - - - } + }// if exclusive and not durable Configuration virtualHostDefaultQueueConfiguration = VirtualHostConfiguration.getDefaultQueueConfiguration(queue); if (virtualHostDefaultQueueConfiguration != null) { Configurator.configure(queue, virtualHostDefaultQueueConfiguration); } - + return queue; } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java index c89529f2a3..38c9e4950a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.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,29 +20,174 @@ */ package org.apache.qpid.server.management; +import java.io.IOException; import java.lang.management.ManagementFactory; +import java.rmi.RemoteException; +import java.rmi.registry.LocateRegistry; +import java.rmi.registry.Registry; +import java.rmi.server.UnicastRemoteObject; +import java.util.HashMap; +import java.util.Map; import javax.management.JMException; import javax.management.MBeanServer; +import javax.management.MBeanServerFactory; +import javax.management.remote.JMXConnectorServer; +import javax.management.remote.JMXConnectorServerFactory; +import javax.management.remote.JMXServiceURL; +import javax.management.remote.MBeanServerForwarder; +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.UnsupportedCallbackException; +import javax.security.auth.login.AccountNotFoundException; +import javax.security.sasl.AuthorizeCallback; import org.apache.log4j.Logger; +import org.apache.qpid.AMQException; +import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.registry.IApplicationRegistry; +import org.apache.qpid.server.security.auth.database.PrincipalDatabase; +import org.apache.qpid.server.security.auth.database.Base64MD5PasswordFilePrincipalDatabase; +import org.apache.qpid.server.security.auth.database.PlainPasswordFilePrincipalDatabase; +import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; +import org.apache.qpid.server.security.auth.sasl.crammd5.CRAMMD5HashedInitialiser; + +/** + * This class starts up an MBeanserver. If out of the box agent is being used then there are no security features + * implemented. To use the security features like user authentication, turn off the jmx options in the "QPID_OPTS" env + * variable and use JMXMP connector server. If JMXMP connector is not available, then the standard JMXConnector will be + * used, which again doesn't have user authentication. + */ public class JMXManagedObjectRegistry implements ManagedObjectRegistry { private static final Logger _log = Logger.getLogger(JMXManagedObjectRegistry.class); private final MBeanServer _mbeanServer; + private Registry _rmiRegistry; + private JMXServiceURL _jmxURL; - public JMXManagedObjectRegistry() + public JMXManagedObjectRegistry() throws AMQException { _log.info("Initialising managed object registry using platform MBean server"); - // we use the platform MBean server currently but this must be changed or at least be configuurable - _mbeanServer = ManagementFactory.getPlatformMBeanServer(); + IApplicationRegistry appRegistry = ApplicationRegistry.getInstance(); + + // Retrieve the config parameters + boolean platformServer = appRegistry.getConfiguration().getBoolean("management.platform-mbeanserver", true); + + _mbeanServer = + platformServer ? ManagementFactory.getPlatformMBeanServer() + : MBeanServerFactory.createMBeanServer(ManagedObject.DOMAIN); + } + + + public void start() + { + // Check if the "QPID_OPTS" is set to use Out of the Box JMXAgent + if (areOutOfTheBoxJMXOptionsSet()) + { + _log.info("JMX: Using the out of the box JMX Agent"); + return; + } + + IApplicationRegistry appRegistry = ApplicationRegistry.getInstance(); + + boolean security = appRegistry.getConfiguration().getBoolean("management.security-enabled", true); + int port = appRegistry.getConfiguration().getInt("management.jmxport", 8999); + + try + { + if (security) + { + // For SASL using JMXMP + _jmxURL = new JMXServiceURL("jmxmp", null, port); + + Map env = new HashMap(); + Map<String, PrincipalDatabase> map = appRegistry.getDatabaseManager().getDatabases(); + PrincipalDatabase db = null; + + for (Map.Entry<String, PrincipalDatabase> entry : map.entrySet()) + { + if (entry.getValue() instanceof Base64MD5PasswordFilePrincipalDatabase) + { + db = entry.getValue(); + break; + } + else if (entry.getValue() instanceof PlainPasswordFilePrincipalDatabase) + { + db = entry.getValue(); + } + } + + if (db instanceof Base64MD5PasswordFilePrincipalDatabase) + { + env.put("jmx.remote.profiles", "SASL/CRAM-MD5"); + CRAMMD5HashedInitialiser initialiser = new CRAMMD5HashedInitialiser(); + initialiser.initialise(db); + env.put("jmx.remote.sasl.callback.handler", initialiser.getCallbackHandler()); + } + else if (db instanceof PlainPasswordFilePrincipalDatabase) + { + env.put("jmx.remote.profiles", "SASL/PLAIN"); + env.put("jmx.remote.sasl.callback.handler", new UserCallbackHandler(db)); + } + + // Enable the SSL security and server authentication + /* + SslRMIClientSocketFactory csf = new SslRMIClientSocketFactory(); + SslRMIServerSocketFactory ssf = new SslRMIServerSocketFactory(); + env.put(RMIConnectorServer.RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE, csf); + env.put(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE, ssf); + */ + + try + { + JMXConnectorServer cs = JMXConnectorServerFactory.newJMXConnectorServer(_jmxURL, env, _mbeanServer); + MBeanServerForwarder mbsf = MBeanInvocationHandlerImpl.newProxyInstance(); + cs.setMBeanServerForwarder(mbsf); + cs.start(); + _log.info("JMX: Starting JMXConnector server with SASL"); + } + catch (java.net.MalformedURLException urlException) + { + // When JMXMPConnector is not available + // java.net.MalformedURLException: Unsupported protocol: jmxmp + _log.info("JMX: Starting JMXConnector server"); + startJMXConnectorServer(port); + } + } + else + { + startJMXConnectorServer(port); + } + } + catch (Exception ex) + { + _log.error("Error in initialising Managed Object Registry." + ex.getMessage()); + ex.printStackTrace(); + } + } + + /** + * Starts up an RMIRegistry at configured port and attaches a JMXConnectorServer to it. + * + * @param port + * + * @throws IOException + */ + private void startJMXConnectorServer(int port) throws IOException + { + startRMIRegistry(port); + _jmxURL = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:" + port + "/jmxrmi"); + JMXConnectorServer cs = JMXConnectorServerFactory.newJMXConnectorServer(_jmxURL, null, _mbeanServer); + cs.start(); } public void registerObject(ManagedObject managedObject) throws JMException { - _mbeanServer.registerMBean(managedObject, managedObject.getObjectName()); + _mbeanServer.registerMBean(managedObject, managedObject.getObjectName()); } public void unregisterObject(ManagedObject managedObject) throws JMException @@ -50,4 +195,105 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry _mbeanServer.unregisterMBean(managedObject.getObjectName()); } + /** + * Checks is the "QPID_OPTS" env variable is set to use the out of the box JMXAgent. + * + * @return + */ + private boolean areOutOfTheBoxJMXOptionsSet() + { + if (System.getProperty("com.sun.management.jmxremote") != null) + { + return true; + } + + if (System.getProperty("com.sun.management.jmxremote.port") != null) + { + return true; + } + + return false; + } + + /** + * Starts the rmi registry at given port + * + * @param port + * + * @throws RemoteException + */ + private void startRMIRegistry(int port) throws RemoteException + { + System.setProperty("java.rmi.server.randomIDs", "true"); + _rmiRegistry = LocateRegistry.createRegistry(port); + } + + // stops the RMIRegistry, if it was running and bound to a port + public void close() throws RemoteException + { + if (_rmiRegistry != null) + { + // Stopping the RMI registry + UnicastRemoteObject.unexportObject(_rmiRegistry, true); + } + } + + /** This class is used for SASL enabled JMXConnector for performing user authentication. */ + private class UserCallbackHandler implements CallbackHandler + { + private final PrincipalDatabase _principalDatabase; + + protected UserCallbackHandler(PrincipalDatabase database) + { + _principalDatabase = database; + } + + public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException + { + // Retrieve callbacks + NameCallback ncb = null; + PasswordCallback pcb = null; + for (int i = 0; i < callbacks.length; i++) + { + if (callbacks[i] instanceof NameCallback) + { + ncb = (NameCallback) callbacks[i]; + } + else if (callbacks[i] instanceof PasswordCallback) + { + pcb = (PasswordCallback) callbacks[i]; + } + else if (callbacks[i] instanceof AuthorizeCallback) + { + ((AuthorizeCallback) callbacks[i]).setAuthorized(true); + } + else + { + throw new UnsupportedCallbackException(callbacks[i]); + } + } + + boolean authorized = false; + // Process retrieval of password; can get password if username is available in NameCallback + if ((ncb != null) && (pcb != null)) + { + String username = ncb.getDefaultName(); + try + { + authorized = _principalDatabase.verifyPassword(username, new String(pcb.getPassword())); + } + catch (AccountNotFoundException e) + { + IOException ioe = new IOException("User not authorized. " + e); + ioe.initCause(e); + throw ioe; + } + } + + if (!authorized) + { + throw new IOException("User not authorized."); + } + } + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java new file mode 100644 index 0000000000..a79d993afc --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/MBeanInvocationHandlerImpl.java @@ -0,0 +1,217 @@ +/* + * + * 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.management; + +import org.apache.qpid.AMQException; +import org.apache.log4j.Logger; + +import javax.management.remote.MBeanServerForwarder; +import javax.management.remote.JMXPrincipal; +import javax.management.MBeanServer; +import javax.management.ObjectName; +import javax.management.MBeanInfo; +import javax.management.MBeanOperationInfo; +import javax.management.JMException; +import javax.security.auth.Subject; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Proxy; +import java.lang.reflect.Method; +import java.security.AccessController; +import java.security.Principal; +import java.security.AccessControlContext; +import java.util.Set; +import java.util.Properties; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.ConcurrentHashMap; +import java.io.File; +import java.io.InputStream; +import java.io.IOException; +import java.io.FileInputStream; + +/** + * This class can be used by the JMXConnectorServer as an InvocationHandler for the mbean operations. This implements + * the logic for allowing the users to invoke MBean operations and implements the restrictions for readOnly, readWrite + * and admin users. + */ +public class MBeanInvocationHandlerImpl implements InvocationHandler +{ + private static final Logger _logger = Logger.getLogger(MBeanInvocationHandlerImpl.class); + + public final static String ADMIN = "admin"; + public final static String READWRITE = "readwrite"; + public final static String READONLY = "readonly"; + private final static String DELEGATE = "JMImplementation:type=MBeanServerDelegate"; + private MBeanServer mbs; + private static Properties _userRoles = new Properties(); + + public static MBeanServerForwarder newProxyInstance() + { + final InvocationHandler handler = new MBeanInvocationHandlerImpl(); + final Class[] interfaces = new Class[]{MBeanServerForwarder.class}; + + Object proxy = Proxy.newProxyInstance(MBeanServerForwarder.class.getClassLoader(), interfaces, handler); + return MBeanServerForwarder.class.cast(proxy); + } + + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable + { + final String methodName = method.getName(); + + if (methodName.equals("getMBeanServer")) + { + return mbs; + } + + if (methodName.equals("setMBeanServer")) + { + if (args[0] == null) + { + throw new IllegalArgumentException("Null MBeanServer"); + } + if (mbs != null) + { + throw new IllegalArgumentException("MBeanServer object already initialized"); + } + mbs = (MBeanServer) args[0]; + return null; + } + + // Retrieve Subject from current AccessControlContext + AccessControlContext acc = AccessController.getContext(); + Subject subject = Subject.getSubject(acc); + + // Allow operations performed locally on behalf of the connector server itself + if (subject == null) + { + return method.invoke(mbs, args); + } + + if (args == null || DELEGATE.equals(args[0])) + { + return method.invoke(mbs, args); + } + + // Restrict access to "createMBean" and "unregisterMBean" to any user + if (methodName.equals("createMBean") || methodName.equals("unregisterMBean")) + { + throw new SecurityException("Access denied"); + } + + // Retrieve JMXPrincipal from Subject + Set<JMXPrincipal> principals = subject.getPrincipals(JMXPrincipal.class); + if (principals == null || principals.isEmpty()) + { + throw new SecurityException("Access denied"); + } + + Principal principal = principals.iterator().next(); + String identity = principal.getName(); + + // Following users can perform any operation other than "createMBean" and "unregisterMBean" + if (isAdmin(identity) || isAllowedToModify(identity)) + { + return method.invoke(mbs, args); + } + + // These users can only call "getAttribute" on the MBeanServerDelegate MBean + // Here we can add other fine grained permissions like specific method for a particular mbean + if (isReadOnlyUser(identity) && isReadOnlyMethod(method, args)) + { + return method.invoke(mbs, args); + } + + throw new SecurityException("Access denied"); + } + + // Initialises the user roles + public static void setAccessRights(Properties accessRights) + { + _userRoles = accessRights; + } + + private boolean isAdmin(String userName) + { + if (ADMIN.equals(_userRoles.getProperty(userName))) + { + return true; + } + return false; + } + + private boolean isAllowedToModify(String userName) + { + if (READWRITE.equals(_userRoles.getProperty(userName))) + { + return true; + } + return false; + } + + private boolean isReadOnlyUser(String userName) + { + if (READONLY.equals(_userRoles.getProperty(userName))) + { + return true; + } + return false; + } + + private boolean isReadOnlyMethod(Method method, Object[] args) + { + String methodName = method.getName(); + if (methodName.equals("queryMBeans") || + methodName.equals("getDefaultDomain") || + methodName.equals("getMBeanInfo") || + methodName.equals("getAttribute") || + methodName.equals("getAttributes")) + { + return true; + } + + if (args[0] instanceof ObjectName) + { + String mbeanMethod = (args.length > 1) ? (String) args[1] : null; + if (mbeanMethod == null) + { + return false; + } + + try + { + MBeanInfo mbeanInfo = mbs.getMBeanInfo((ObjectName) args[0]); + if (mbeanInfo != null) + { + MBeanOperationInfo[] opInfos = mbeanInfo.getOperations(); + for (MBeanOperationInfo opInfo : opInfos) + { + if (opInfo.getName().equals(mbeanMethod) && (opInfo.getImpact() == MBeanOperationInfo.INFO)) + { + return true; + } + } + } + } + catch (JMException ex) + { + ex.printStackTrace(); + } + } + + return false; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedBroker.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedBroker.java index b2f79b6410..45e2e91ed7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedBroker.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedBroker.java @@ -52,8 +52,7 @@ public interface ManagedBroker @MBeanOperation(name="createNewExchange", description="Creates a new Exchange", impact= MBeanOperationInfo.ACTION) void createNewExchange(@MBeanOperationParameter(name="name", description="Name of the new exchange")String name, @MBeanOperationParameter(name="ExchangeType", description="Type of the exchange")String type, - @MBeanOperationParameter(name="durable", description="true if the Exchang should be durable")boolean durable, - @MBeanOperationParameter(name="passive", description="true of the Exchange should be passive")boolean passive) + @MBeanOperationParameter(name="durable", description="true if the Exchang should be durable")boolean durable) throws IOException, JMException; /** @@ -81,8 +80,7 @@ public interface ManagedBroker @MBeanOperation(name="createNewQueue", description="Create a new Queue on the Broker server", impact= MBeanOperationInfo.ACTION) void createNewQueue(@MBeanOperationParameter(name="queue name", description="Name of the new queue")String queueName, @MBeanOperationParameter(name="owner", description="Owner name")String owner, - @MBeanOperationParameter(name="durable", description="true if the queue should be durable")boolean durable, - @MBeanOperationParameter(name="autoDelete", description="true if the queue should be auto delete") boolean autoDelete) + @MBeanOperationParameter(name="durable", description="true if the queue should be durable")boolean durable) throws IOException, JMException; /** diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObjectRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObjectRegistry.java index 32298f05e3..5f9bc9ddad 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObjectRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/ManagedObjectRegistry.java @@ -21,6 +21,7 @@ package org.apache.qpid.server.management; import javax.management.JMException; +import java.rmi.RemoteException; /** * Handles the registration (and unregistration and so on) of managed objects. @@ -36,7 +37,11 @@ import javax.management.JMException; */ public interface ManagedObjectRegistry { + void start(); + void registerObject(ManagedObject managedObject) throws JMException; void unregisterObject(ManagedObject managedObject) throws JMException; + + void close() throws RemoteException; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/NoopManagedObjectRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/NoopManagedObjectRegistry.java index 5b86543ea6..b4fbed6948 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/management/NoopManagedObjectRegistry.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/management/NoopManagedObjectRegistry.java @@ -24,6 +24,8 @@ import javax.management.JMException; import org.apache.log4j.Logger; +import java.rmi.RemoteException; + /** * 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. @@ -38,6 +40,11 @@ public class NoopManagedObjectRegistry implements ManagedObjectRegistry _log.info("Management is disabled"); } + public void start() + { + //no-op + } + public void registerObject(ManagedObject managedObject) throws JMException { } @@ -45,4 +52,9 @@ public class NoopManagedObjectRegistry implements ManagedObjectRegistry public void unregisterObject(ManagedObject managedObject) throws JMException { } + + public void close() throws RemoteException + { + + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java index fd8fb2d5cb..2e62c2f1e4 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQMinaProtocolSession.java @@ -28,6 +28,7 @@ import java.util.List; import java.util.Map; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArraySet; +import java.security.Principal; import javax.management.JMException; import javax.security.sasl.SaslServer; @@ -108,7 +109,7 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, private VersionSpecificRegistry _registry = MainRegistry.getVersionSpecificRegistry(_protocolVersion); private List<Integer> _closingChannelsList = new ArrayList<Integer>(); private ProtocolOutputConverter _protocolOutputConverter; - private String _authorizedID; + private Principal _authorizedID; public ManagedObject getManagedObject() @@ -745,12 +746,12 @@ public class AMQMinaProtocolSession implements AMQProtocolSession, return _protocolOutputConverter; } - public void setAuthorizedID(String authorizedID) + public void setAuthorizedID(Principal authorizedID) { _authorizedID = authorizedID; } - public String getAuthorizedID() + public Principal getAuthorizedID() { return _authorizedID; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java index 79421dd497..390117acf6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSession.java @@ -31,6 +31,8 @@ import org.apache.qpid.server.AMQChannel; import org.apache.qpid.server.output.ProtocolOutputConverter; import org.apache.qpid.server.virtualhost.VirtualHost; +import java.security.Principal; + public interface AMQProtocolSession extends AMQVersionAwareProtocolSession { @@ -165,9 +167,9 @@ public interface AMQProtocolSession extends AMQVersionAwareProtocolSession public ProtocolOutputConverter getProtocolOutputConverter(); - void setAuthorizedID(String authorizedID); + void setAuthorizedID(Principal authorizedID); - /** @return a username string that was used to authorized this session */ - String getAuthorizedID(); + /** @return a Principal that was used to authorized this session */ + Principal getAuthorizedID(); } 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 index 5eebd4c524..66f928a70e 100644 --- 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 @@ -1,5 +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. + * + */ +/* + * * Copyright (c) 2006 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -17,14 +37,15 @@ */ package org.apache.qpid.server.protocol; +import java.security.Principal; import java.util.Date; import java.util.List; import javax.management.JMException; import javax.management.MBeanException; import javax.management.MBeanNotificationInfo; -import javax.management.Notification; import javax.management.NotCompliantMBeanException; +import javax.management.Notification; import javax.management.monitor.MonitorNotification; import javax.management.openmbean.CompositeData; import javax.management.openmbean.CompositeDataSupport; @@ -56,15 +77,17 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed { private AMQMinaProtocolSession _session = null; private String _name = null; - - //openmbean data types for representing the channel attributes - private final static String[] _channelAtttibuteNames = {"Channel Id", "Transactional", "Default Queue", "Unacknowledged Message Count"}; - private final static String[] _indexNames = {_channelAtttibuteNames[0]}; - private final static OpenType[] _channelAttributeTypes = {SimpleType.INTEGER, SimpleType.BOOLEAN, SimpleType.STRING, SimpleType.INTEGER}; - private static CompositeType _channelType = null; // represents the data type for channel data - private static TabularType _channelsType = null; // Data type for list of channels type + + // openmbean data types for representing the channel attributes + private static final String[] _channelAtttibuteNames = + { "Channel Id", "Transactional", "Default Queue", "Unacknowledged Message Count" }; + private static final String[] _indexNames = { _channelAtttibuteNames[0] }; + private static final OpenType[] _channelAttributeTypes = + { SimpleType.INTEGER, SimpleType.BOOLEAN, SimpleType.STRING, SimpleType.INTEGER }; + private static CompositeType _channelType = null; // represents the data type for channel data + private static TabularType _channelsType = null; // Data type for list of channels type private static final AMQShortString BROKER_MANAGEMENT_CONSOLE_HAS_CLOSED_THE_CONNECTION = - new AMQShortString("Broker Management Console has closed the connection."); + new AMQShortString("Broker Management Console has closed the connection."); @MBeanConstructor("Creates an MBean exposing an AMQ Broker Connection") public AMQProtocolSessionMBean(AMQMinaProtocolSession session) throws NotCompliantMBeanException, OpenDataException @@ -72,22 +95,21 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed super(ManagedConnection.class, ManagedConnection.TYPE); _session = session; String remote = getRemoteAddress(); - remote = "anonymous".equals(remote) ? remote + hashCode() : remote; + remote = "anonymous".equals(remote) ? (remote + hashCode()) : remote; _name = jmxEncode(new StringBuffer(remote), 0).toString(); init(); } - static { try { init(); } - catch(JMException ex) + catch (JMException ex) { - // It should never occur - System.out.println(ex.getMessage()); + // This is not expected to ever occur. + throw new RuntimeException("Got JMException in static initializer.", ex); } } @@ -96,26 +118,27 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed */ private static void init() throws OpenDataException { - _channelType = new CompositeType("Channel", "Channel Details", _channelAtttibuteNames, - _channelAtttibuteNames, _channelAttributeTypes); + _channelType = + new CompositeType("Channel", "Channel Details", _channelAtttibuteNames, _channelAtttibuteNames, + _channelAttributeTypes); _channelsType = new TabularType("Channels", "Channels", _channelType, _indexNames); } public String getClientId() { - return _session.getContextKey() == null ? null : _session.getContextKey().toString(); + return (_session.getContextKey() == null) ? null : _session.getContextKey().toString(); } public String getAuthorizedId() { - return _session.getAuthorizedID(); + return (_session.getAuthorizedID() != null ) ? _session.getAuthorizedID().getName() : null; } public String getVersion() { - return _session.getClientVersion() == null ? null : _session.getClientVersion().toString(); + return (_session.getClientVersion() == null) ? null : _session.getClientVersion().toString(); } - + public Date getLastIoTime() { return new Date(_session.getIOSession().getLastIoTime()); @@ -171,6 +194,7 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed { throw new JMException("The channel (channel Id = " + channelId + ") does not exist"); } + _session.commitTransactions(channel); } catch (AMQException ex) @@ -194,6 +218,7 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed { throw new JMException("The channel (channel Id = " + channelId + ") does not exist"); } + _session.rollbackTransactions(channel); } catch (AMQException ex) @@ -215,9 +240,12 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed for (AMQChannel channel : list) { - Object[] itemValues = {channel.getChannelId(), channel.isTransactional(), + Object[] itemValues = + { + channel.getChannelId(), channel.isTransactional(), (channel.getDefaultQueue() != null) ? channel.getDefaultQueue().getName().asString() : null, - channel.getUnacknowledgedMessageMap().size()}; + channel.getUnacknowledgedMessageMap().size() + }; CompositeData channelData = new CompositeDataSupport(_channelType, _channelAtttibuteNames, itemValues); channelsList.put(channelData); @@ -232,17 +260,16 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed * @throws JMException */ public void closeConnection() throws JMException - { + { // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. // Be aware of possible changes to parameter order as versions change. - final AMQFrame response = ConnectionCloseBody.createAMQFrame(0, - _session.getProtocolMajorVersion(), - _session.getProtocolMinorVersion(), // AMQP version (major, minor) - 0, // classId - 0, // methodId - AMQConstant.REPLY_SUCCESS.getCode(), // replyCode - BROKER_MANAGEMENT_CONSOLE_HAS_CLOSED_THE_CONNECTION // replyText + final AMQFrame response = + ConnectionCloseBody.createAMQFrame(0, _session.getProtocolMajorVersion(), _session.getProtocolMinorVersion(), // AMQP version (major, minor) + 0, // classId + 0, // methodId + AMQConstant.REPLY_SUCCESS.getCode(), // replyCode + BROKER_MANAGEMENT_CONSOLE_HAS_CLOSED_THE_CONNECTION // replyText ); _session.writeFrame(response); @@ -259,18 +286,19 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed @Override public MBeanNotificationInfo[] getNotificationInfo() { - String[] notificationTypes = new String[]{MonitorNotification.THRESHOLD_VALUE_EXCEEDED}; + 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}; + return new MBeanNotificationInfo[] { info1 }; } public void notifyClients(String notificationMsg) { - Notification n = new Notification(MonitorNotification.THRESHOLD_VALUE_EXCEEDED, this, - ++_notificationSequenceNumber, System.currentTimeMillis(), notificationMsg); + Notification n = + new Notification(MonitorNotification.THRESHOLD_VALUE_EXCEEDED, this, ++_notificationSequenceNumber, + System.currentTimeMillis(), notificationMsg); _broadcaster.sendNotification(n); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ManagedConnection.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ManagedConnection.java index 990c4c0794..e6e713ac6d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ManagedConnection.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ManagedConnection.java @@ -23,6 +23,7 @@ package org.apache.qpid.server.protocol; import java.io.IOException; import java.util.Date; +import java.security.Principal; import javax.management.JMException; import javax.management.MBeanOperationInfo; @@ -67,16 +68,17 @@ public interface ManagedConnection /** * Tells the total number of bytes written till now. * @return number of bytes written. - */ + * @MBeanAttribute(name="WrittenBytes", description="The total number of bytes written till now") Long getWrittenBytes(); - + */ /** * Tells the total number of bytes read till now. * @return number of bytes read. - */ + * @MBeanAttribute(name="ReadBytes", description="The total number of bytes read till now") Long getReadBytes(); + */ /** * Threshold high value for no of channels. This is useful in setting notifications or diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java index d6962d28cd..b2046efee3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQMessage.java @@ -25,6 +25,7 @@ import org.apache.qpid.framing.AMQBody; import org.apache.qpid.framing.AMQDataBlock; import org.apache.qpid.framing.AMQFrame; import org.apache.qpid.framing.ContentHeaderBody; +import org.apache.qpid.framing.FieldTable; import org.apache.qpid.framing.abstraction.ContentChunk; import org.apache.qpid.framing.abstraction.MessagePublishInfo; import org.apache.qpid.framing.abstraction.ProtocolVersionMethodConverter; @@ -42,6 +43,8 @@ import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; +import java.util.HashMap; +import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; @@ -78,19 +81,20 @@ public class AMQMessage private boolean _immediate; private AtomicBoolean _taken = new AtomicBoolean(false); - private TransientMessageData _transientMessageData = new TransientMessageData(); private Subscription _takenBySubcription; - private Set<Subscription> _rejectedBy = null; + private Map<AMQQueue, AtomicBoolean> _takenMap = new HashMap<AMQQueue, AtomicBoolean>(); + private Map<AMQQueue, Subscription> _takenBySubcriptionMap = new HashMap<AMQQueue, Subscription>(); - public boolean isTaken() + public boolean isTaken(AMQQueue queue) { return _taken.get(); } private final int hashcode = System.identityHashCode(this); + public String debugIdentity() { return "(HC:" + hashcode + " ID:" + _messageId + " Ref:" + _referenceCount.get() + ")"; @@ -203,9 +207,10 @@ public class AMQMessage _transientMessageData.setMessagePublishInfo(info); _taken = new AtomicBoolean(false); + if (_log.isDebugEnabled()) { - _log.debug("Message(" + System.identityHashCode(this) + ") created (" + debugIdentity()+")"); + _log.debug("Message(" + System.identityHashCode(this) + ") created (" + debugIdentity() + ")"); } } @@ -318,8 +323,10 @@ public class AMQMessage // enqueuing the messages ensure that if required the destinations are recorded to a // persistent store + for (AMQQueue q : _transientMessageData.getDestinationQueues()) { + _takenMap.put(q, new AtomicBoolean(false)); _messageHandle.enqueue(storeContext, _messageId, q); } @@ -356,12 +363,13 @@ public class AMQMessage } /** - * Creates a long-lived reference to this message, and increments the count of such references, as an atomic operation. + * Creates a long-lived reference to this message, and increments the count of such references, as an atomic + * operation. */ public AMQMessage takeReference() { _referenceCount.incrementAndGet(); - return this; + return this; } /** Threadsafe. Increment the reference count on the message. */ @@ -378,9 +386,10 @@ public class AMQMessage * Threadsafe. This will decrement the reference count and when it reaches zero will remove the message from the * message store. * + * @param storeContext + * * @throws MessageCleanupException when an attempt was made to remove the message from the message store and that * failed - * @param storeContext */ public void decrementReference(StoreContext storeContext) throws MessageCleanupException { @@ -451,7 +460,7 @@ public class AMQMessage } - public boolean taken(Subscription sub) + public boolean taken(AMQQueue queue, Subscription sub) { if (_taken.getAndSet(true)) { @@ -464,7 +473,7 @@ public class AMQMessage } } - public void release() + public void release(AMQQueue queue) { if (_log.isTraceEnabled()) { @@ -600,7 +609,7 @@ public class AMQMessage for (AMQQueue q : destinationQueues) { //Increment the references to this message for each queue delivery. - incrementReference(); + incrementReference(); //normal deliver so add this message at the end. _txnContext.deliver(this, q, false); } @@ -824,11 +833,14 @@ public class AMQMessage public String toString() { - return "Message[" + debugIdentity() + "]: " + _messageId + "; ref count: " + _referenceCount + "; taken: " + - _taken + " by:" + _takenBySubcription; + return "Message[" + debugIdentity() + "]: " + _messageId + "; ref count: " + _referenceCount + "; taken : " + + _taken + " by :" + _takenBySubcription; + +// return "Message[" + debugIdentity() + "]: " + _messageId + "; ref count: " + _referenceCount + "; taken for queues: " + +// _takenMap.toString() + " by Subs:" + _takenBySubcriptionMap.toString(); } - public Subscription getDeliveredSubscription() + public Subscription getDeliveredSubscription(AMQQueue queue) { return _takenBySubcription; } 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 index 7a32848c44..bbaa7379f6 100644 --- 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 @@ -1,5 +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. + * + */ +/* + * * Copyright (c) 2006 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -17,11 +37,11 @@ */ package org.apache.qpid.server.queue; +import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Date; import java.util.Iterator; import java.util.List; -import java.util.Date; -import java.text.SimpleDateFormat; import javax.management.JMException; import javax.management.MBeanException; @@ -41,12 +61,14 @@ import javax.management.openmbean.TabularDataSupport; import javax.management.openmbean.TabularType; import org.apache.log4j.Logger; + import org.apache.mina.common.ByteBuffer; + import org.apache.qpid.AMQException; -import org.apache.qpid.framing.CommonContentHeaderProperties; -import org.apache.qpid.framing.ContentHeaderBody; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.BasicContentHeaderProperties; +import org.apache.qpid.framing.CommonContentHeaderProperties; +import org.apache.qpid.framing.ContentHeaderBody; import org.apache.qpid.framing.abstraction.ContentChunk; import org.apache.qpid.server.management.AMQManagedObject; import org.apache.qpid.server.management.MBeanConstructor; @@ -73,15 +95,15 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que private AMQQueue _queue = null; private String _queueName = null; // OpenMBean data types for viewMessages method - private final static String[] _msgAttributeNames = {"AMQ MessageId", "Header", "Size(bytes)", "Redelivered"}; - private static String[] _msgAttributeIndex = {_msgAttributeNames[0]}; + private static final String[] _msgAttributeNames = { "AMQ MessageId", "Header", "Size(bytes)", "Redelivered" }; + private static String[] _msgAttributeIndex = { _msgAttributeNames[0] }; private static OpenType[] _msgAttributeTypes = new OpenType[4]; // 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. + 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 final static String[] _msgContentAttributes = {"AMQ MessageId", "MimeType", "Encoding", "Content"}; + private static final String[] _msgContentAttributes = { "AMQ MessageId", "MimeType", "Encoding", "Content" }; private static OpenType[] _msgContentAttributeTypes = new OpenType[4]; private final long[] _lastNotificationTimes = new long[NotificationCheck.values().length]; @@ -95,7 +117,6 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que _queueName = jmxEncode(new StringBuffer(queue.getName()), 0).toString(); } - public ManagedObject getParentObject() { return _queue.getVirtualHost().getManagedObject(); @@ -107,10 +128,10 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que { init(); } - catch(JMException ex) + catch (JMException ex) { - // It should never occur - System.out.println(ex.getMessage()); + // This is not expected to ever occur. + throw new RuntimeException("Got JMException in static initializer.", ex); } } @@ -119,19 +140,21 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que */ 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", _msgContentAttributes, - _msgContentAttributes, _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 - - _messageDataType = new CompositeType("Message", "AMQ Message", _msgAttributeNames, _msgAttributeNames, _msgAttributeTypes); + _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", _msgContentAttributes, _msgContentAttributes, + _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 + + _messageDataType = + new CompositeType("Message", "AMQ Message", _msgAttributeNames, _msgAttributeNames, _msgAttributeTypes); _messagelistDataType = new TabularType("Messages", "List of messages", _messageDataType, _msgAttributeIndex); } @@ -213,7 +236,8 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que public Long getMaximumQueueDepth() { long queueDepthInBytes = _queue.getMaximumQueueDepth(); - return queueDepthInBytes >> 10 ; + + return queueDepthInBytes >> 10; } public void setMaximumQueueDepth(Long value) @@ -227,7 +251,8 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que public Long getQueueDepth() throws JMException { long queueBytesSize = _queue.getQueueDepth(); - return queueBytesSize >> 10 ; + + return queueBytesSize >> 10; } /** @@ -237,13 +262,13 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que { final long currentTime = System.currentTimeMillis(); - final long thresholdTime = currentTime - _queue.getMinimumAlertRepeatGap(); + final long thresholdTime = currentTime - _queue.getMinimumAlertRepeatGap(); - for(NotificationCheck check : NotificationCheck.values()) + for (NotificationCheck check : NotificationCheck.values()) { - if(check.isMessageSpecific() || _lastNotificationTimes[check.ordinal()]<thresholdTime) + if (check.isMessageSpecific() || (_lastNotificationTimes[check.ordinal()] < thresholdTime)) { - if(check.notifyIfNecessary(msg, _queue, this)) + if (check.notifyIfNecessary(msg, _queue, this)) { _lastNotificationTimes[check.ordinal()] = currentTime; } @@ -260,9 +285,10 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que // important : add log to the log file - monitoring tools may be looking for this _logger.info(notification.name() + " On Queue " + queue.getName() + " - " + notificationMsg); notificationMsg = notification.name() + " " + notificationMsg; - - _lastNotification = new Notification(MonitorNotification.THRESHOLD_VALUE_EXCEEDED, this, - ++_notificationSequenceNumber, System.currentTimeMillis(), notificationMsg); + + _lastNotification = + new Notification(MonitorNotification.THRESHOLD_VALUE_EXCEEDED, this, ++_notificationSequenceNumber, + System.currentTimeMillis(), notificationMsg); _broadcaster.sendNotification(_lastNotification); } @@ -334,20 +360,25 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que try { // Create header attributes list - CommonContentHeaderProperties headerProperties = (CommonContentHeaderProperties) msg.getContentHeaderBody().properties; + CommonContentHeaderProperties headerProperties = + (CommonContentHeaderProperties) msg.getContentHeaderBody().properties; String mimeType = null, encoding = null; if (headerProperties != null) { AMQShortString mimeTypeShortSting = headerProperties.getContentType(); - mimeType = mimeTypeShortSting == null ? null : mimeTypeShortSting.toString(); - encoding = headerProperties.getEncoding() == null ? "" : headerProperties.getEncoding().toString(); + mimeType = (mimeTypeShortSting == null) ? null : mimeTypeShortSting.toString(); + encoding = (headerProperties.getEncoding() == null) ? "" : headerProperties.getEncoding().toString(); } - Object[] itemValues = {msgId, mimeType, encoding, msgContent.toArray(new Byte[0])}; + + Object[] itemValues = { msgId, mimeType, encoding, msgContent.toArray(new Byte[0]) }; + return new CompositeDataSupport(_msgContentType, _msgContentAttributes, itemValues); } catch (AMQException e) { - throw new JMException("Error creating header attributes list: " + e); + JMException jme = new JMException("Error creating header attributes list: " + e); + jme.initCause(e); + throw jme; } } @@ -358,8 +389,8 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que { if ((beginIndex > endIndex) || (beginIndex < 1)) { - throw new OperationsException("From Index = " + beginIndex + ", To Index = " + endIndex + - "\n\"From Index\" should be greater than 0 and less than \"To Index\""); + throw new OperationsException("From Index = " + beginIndex + ", To Index = " + endIndex + + "\n\"From Index\" should be greater than 0 and less than \"To Index\""); } List<AMQMessage> list = _queue.getMessagesOnTheQueue(); @@ -368,20 +399,22 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que try { // Create the tabular list of message header contents - for (int i = beginIndex; i <= endIndex && i <= list.size(); i++) + for (int i = beginIndex; (i <= endIndex) && (i <= list.size()); i++) { AMQMessage msg = list.get(i - 1); ContentHeaderBody headerBody = msg.getContentHeaderBody(); // Create header attributes list String[] headerAttributes = getMessageHeaderProperties(headerBody); - Object[] itemValues = {msg.getMessageId(), headerAttributes, headerBody.bodySize, msg.isRedelivered()}; + Object[] itemValues = { msg.getMessageId(), headerAttributes, headerBody.bodySize, msg.isRedelivered() }; CompositeData messageData = new CompositeDataSupport(_messageDataType, _msgAttributeNames, itemValues); _messageList.put(messageData); } } catch (AMQException e) { - throw new JMException("Error creating message contents: " + e); + JMException jme = new JMException("Error creating message contents: " + e); + jme.initCause(e); + throw jme; } return _messageList; @@ -400,11 +433,11 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que list.add("JMSCorrelationID = " + headerProperties.getCorrelationIdAsString()); int delMode = headerProperties.getDeliveryMode(); - list.add("JMSDeliveryMode = " + (delMode == 1 ? "Persistent" : "Non_Persistent")); + list.add("JMSDeliveryMode = " + ((delMode == 1) ? "Persistent" : "Non_Persistent")); list.add("JMSPriority = " + headerProperties.getPriority()); list.add("JMSType = " + headerProperties.getType()); - + long longDate = headerProperties.getExpiration(); String strDate = (longDate != 0) ? _dateFormat.format(new Date(longDate)) : null; list.add("JMSExpiration = " + strDate); @@ -425,27 +458,26 @@ public class AMQQueueMBean extends AMQManagedObject implements ManagedQueue, Que */ public void moveMessages(long fromMessageId, long toMessageId, String toQueueName) throws JMException { - if (fromMessageId > toMessageId || (fromMessageId < 1)) + if ((fromMessageId > toMessageId) || (fromMessageId < 1)) { - throw new OperationsException("\"From MessageId\" should be greater then 0 and less then \"To MessageId\""); + throw new OperationsException("\"From MessageId\" should be greater then 0 and less then \"To MessageId\""); } _queue.moveMessagesToAnotherQueue(fromMessageId, toMessageId, toQueueName, _storeContext); } - /** * returns Notifications sent by this MBean. */ @Override public MBeanNotificationInfo[] getNotificationInfo() { - String[] notificationTypes = new String[]{MonitorNotification.THRESHOLD_VALUE_EXCEEDED}; + 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}; + return new MBeanNotificationInfo[] { info1 }; } } // End of AMQQueueMBean class diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java index cfa13c87fd..979f692361 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConcurrentSelectorDeliveryManager.java @@ -210,6 +210,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager /** * Returns all the messages in the Queue + * * @return List of messages */ public List<AMQMessage> getMessages() @@ -222,14 +223,16 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager list.add(message); } _lock.unlock(); - + return list; } /** * Returns messages within the range of given messageIds + * * @param fromMessageId * @param toMessageId + * * @return */ public List<AMQMessage> getMessages(long fromMessageId, long toMessageId) @@ -242,7 +245,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager long maxMessageCount = toMessageId - fromMessageId + 1; _lock.lock(); - + List<AMQMessage> foundMessagesList = new ArrayList<AMQMessage>(); for (AMQMessage message : _messages) @@ -399,7 +402,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager public void removeAMessageFromTop(StoreContext storeContext) throws AMQException { _lock.lock(); - + AMQMessage message = _messages.poll(); if (message != null) { @@ -432,9 +435,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager return count; } - /** - This can only be used to clear the _messages queue. Any subscriber resend queue will not be purged. - */ + /** This can only be used to clear the _messages queue. Any subscriber resend queue will not be purged. */ private AMQMessage getNextMessage() throws AMQException { return getNextMessage(_messages, null); @@ -444,8 +445,12 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager { AMQMessage message = messages.peek(); - //while (we have a message) && (The subscriber is not a browser or we are clearing) && (Check message is taken.) - while (message != null && (sub != null && !sub.isBrowser() || sub == null) && message.taken(sub)) + //while (we have a message) && ((The subscriber is not a browser or message is taken ) or we are clearing) && (Check message is taken.) + while (message != null + && ( + ((sub != null && !sub.isBrowser()) || message.isTaken(_queue)) + || sub == null) + && message.taken(_queue, sub)) { //remove the already taken message AMQMessage removed = messages.poll(); @@ -506,7 +511,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager } if (_log.isDebugEnabled()) { - _log.debug(debugIdentity() + "Async Delivery Message " + message.getMessageId() + "(" + System.identityHashCode(message) + + _log.debug(debugIdentity() + "Async Delivery Message :" + message + "(" + System.identityHashCode(message) + ") by :" + System.identityHashCode(this) + ") to :" + System.identityHashCode(sub)); } @@ -526,7 +531,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager if (_log.isDebugEnabled()) { - _log.debug(debugIdentity() + "Async Delivered Message r:" + removed.debugIdentity() + "d:" + message.debugIdentity() + + _log.debug(debugIdentity() + "Async Delivered Message r:" + removed.debugIdentity() + "d:" + message + ") by :" + System.identityHashCode(this) + ") to :" + System.identityHashCode(sub)); } @@ -562,7 +567,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager } catch (AMQException e) { - message.release(); + message.release(_queue); _log.error(debugIdentity() + "Unable to deliver message as dequeue failed: " + e, e); } } @@ -723,7 +728,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager _log.trace(debugIdentity() + "Delivering Message:" + msg.debugIdentity() + " to(" + System.identityHashCode(s) + ") :" + s); } - msg.taken(s); + msg.taken(_queue, s); //Deliver the message s.send(msg, _queue); } @@ -737,7 +742,7 @@ public class ConcurrentSelectorDeliveryManager implements DeliveryManager } } - if (!msg.isTaken()) + if (!msg.isTaken(_queue)) { if (_log.isInfoEnabled()) { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java index d3578d39e8..e3944954f3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubscriptionImpl.java @@ -558,7 +558,7 @@ public class SubscriptionImpl implements Subscription _logger.trace("Removed for resending:" + resent.debugIdentity()); } - resent.release(); + resent.release(_queue); _queue.subscriberHasPendingResend(false, this, resent); try 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 14a8063aee..89f0b7b39d 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 @@ -153,7 +153,7 @@ public abstract class ApplicationRegistry implements IApplicationRegistry { _logger.error("Error configuring application: " + e, e); //throw new AMQBrokerCreationException(instanceID, "Unable to create Application Registry instance " + instanceID); - throw new RuntimeException("Unable to create Application Registry"); + throw new RuntimeException("Unable to create Application Registry", e); } } else @@ -168,6 +168,12 @@ public abstract class ApplicationRegistry implements IApplicationRegistry { virtualHost.close(); } + + // close the rmi registry(if any) started for management + if (getInstance().getManagedObjectRegistry() != null) + { + getInstance().getManagedObjectRegistry().close(); + } } public Configuration getConfiguration() @@ -187,7 +193,7 @@ public abstract class ApplicationRegistry implements IApplicationRegistry catch (Exception e) { _logger.error("Unable to instantiate configuration class " + instanceType + " - ensure it has a public default constructor"); - throw new IllegalArgumentException("Unable to instantiate configuration class " + instanceType + " - ensure it has a public default constructor"); + throw new IllegalArgumentException("Unable to instantiate configuration class " + instanceType + " - ensure it has a public default constructor", e); } Configurator.configure(instance); _configuredObjects.put(instanceType, instance); 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 739ed9db42..1cca259a8d 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 @@ -42,6 +42,7 @@ import org.apache.qpid.server.security.access.AccessManager; import org.apache.qpid.server.security.access.AccessManagerImpl; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.qpid.server.virtualhost.VirtualHostRegistry; +import org.apache.qpid.AMQException; public class ConfigurationFileApplicationRegistry extends ApplicationRegistry { @@ -103,6 +104,7 @@ public class ConfigurationFileApplicationRegistry extends ApplicationRegistry public void initialise() throws Exception { initialiseManagedObjectRegistry(); + _virtualHostRegistry = new VirtualHostRegistry(); _accessManager = new AccessManagerImpl("default", _configuration); @@ -111,7 +113,12 @@ public class ConfigurationFileApplicationRegistry extends ApplicationRegistry _authenticationManager = new PrincipalDatabaseAuthenticationManager(null, null); + _databaseManager.initialiseManagement(_configuration); + + _managedObjectRegistry.start(); + initialiseVirtualHosts(); + } private void initialiseVirtualHosts() throws Exception @@ -123,7 +130,7 @@ public class ConfigurationFileApplicationRegistry extends ApplicationRegistry } } - private void initialiseManagedObjectRegistry() + private void initialiseManagedObjectRegistry() throws AMQException { ManagementConfiguration config = getConfiguredObject(ManagementConfiguration.class); if (config.enabled) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/Passwd.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/Passwd.java new file mode 100644 index 0000000000..f9e093dba7 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/Passwd.java @@ -0,0 +1,81 @@ +/* + * 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.security; + +import org.apache.commons.codec.binary.Base64; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.DigestException; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintStream; + +public class Passwd +{ + public static void main(String args[]) throws NoSuchAlgorithmException, DigestException, IOException + { + if (args.length != 2) + { + System.out.println("Passwd <username> <password>"); + System.exit(0); + } + + byte[] data = args[1].getBytes("utf-8"); + + MessageDigest md = MessageDigest.getInstance("MD5"); + + for (byte b : data) + { + md.update(b); + } + + byte[] digest = md.digest(); + + Base64 b64 = new Base64(); + + byte[] encoded = b64.encode(digest); + + output(args[0], encoded); + } + + private static void output(String user, byte[] encoded) throws IOException + { + +// File passwdFile = new File("qpid.passwd"); + + PrintStream ps = new PrintStream(System.out); + + user += ":"; + ps.write(user.getBytes("utf-8")); + + for (byte b : encoded) + { + ps.write(b); + } + + ps.println(); + + ps.flush(); + ps.close(); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AMQUserManagementMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AMQUserManagementMBean.java new file mode 100644 index 0000000000..a43474559d --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AMQUserManagementMBean.java @@ -0,0 +1,457 @@ +/* + * 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.security.access; + +import org.apache.qpid.server.management.MBeanDescription; +import org.apache.qpid.server.management.AMQManagedObject; +import org.apache.qpid.server.management.MBeanOperationParameter; +import org.apache.qpid.server.management.MBeanOperation; +import org.apache.qpid.server.management.MBeanInvocationHandlerImpl; +import org.apache.qpid.server.security.auth.database.PrincipalDatabase; +import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; +import org.apache.log4j.Logger; +import org.apache.commons.configuration.ConfigurationException; + +import javax.management.JMException; +import javax.management.openmbean.TabularData; +import javax.management.openmbean.TabularDataSupport; +import javax.management.openmbean.TabularType; +import javax.management.openmbean.SimpleType; +import javax.management.openmbean.CompositeType; +import javax.management.openmbean.OpenType; +import javax.management.openmbean.OpenDataException; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.CompositeDataSupport; +import javax.security.auth.login.AccountNotFoundException; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.FileOutputStream; +import java.util.Properties; +import java.util.List; +import java.util.Enumeration; +import java.util.concurrent.locks.ReentrantLock; +import java.security.Principal; + +/** 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 +{ + + private static final Logger _logger = Logger.getLogger(AMQUserManagementMBean.class); + + private PrincipalDatabase _principalDatabase; + private String _accessFileName; + private Properties _accessRights; + // private File _accessFile; + private ReentrantLock _accessRightsUpdate = new ReentrantLock(); + + // Setup for the TabularType + static TabularType _userlistDataType; // Datatype for representing User Lists + + static CompositeType _userDataType; // Composite type for representing User + static String[] _userItemNames = {"Username", "Read", "Write", "Admin"}; + + static + { + String[] userItemDesc = {"Broker Login username", "Management Console Read Permission", + "Management Console Write Permission", "Management Console Admin Permission"}; + + OpenType[] userItemTypes = new OpenType[4]; // User item types. + userItemTypes[0] = SimpleType.STRING; // For Username + userItemTypes[1] = SimpleType.BOOLEAN; // For Rights - Read + userItemTypes[2] = SimpleType.BOOLEAN; // For Rights - Write + userItemTypes[3] = SimpleType.BOOLEAN; // For Rights - Admin + String[] userDataIndex = {_userItemNames[0]}; + + try + { + _userDataType = + new CompositeType("User", "User Data", _userItemNames, userItemDesc, userItemTypes); + + _userlistDataType = new TabularType("Users", "List of users", _userDataType, userDataIndex); + } + catch (OpenDataException e) + { + _logger.error("Tabular data setup for viewing users incorrect."); + _userlistDataType = null; + } + } + + + public AMQUserManagementMBean() throws JMException + { + super(UserManagement.class, UserManagement.TYPE); + } + + public String getObjectInstanceName() + { + return UserManagement.TYPE; + } + + public boolean setPassword(@MBeanOperationParameter(name = "username", description = "Username")String username, + @MBeanOperationParameter(name = "password", description = "Password")String password) + { + try + { + //delegate password changes to the Principal Database + return _principalDatabase.updatePassword(new UsernamePrincipal(username), password); + } + catch (AccountNotFoundException e) + { + _logger.warn("Attempt to set password of non-existant user'" + username + "'"); + return false; + } + } + + public boolean setRights(@MBeanOperationParameter(name = "username", description = "Username")String username, + @MBeanOperationParameter(name = "read", description = "Administration read")boolean read, + @MBeanOperationParameter(name = "write", description = "Administration write")boolean write, + @MBeanOperationParameter(name = "admin", description = "Administration rights")boolean admin) + { + + if (_accessRights.get(username) == null) + { + // If the user doesn't exist in the user rights file check that they at least have an account. + if (_principalDatabase.getUser(username) == null) + { + return false; + } + } + + try + { + + _accessRightsUpdate.lock(); + + // Update the access rights + if (admin) + { + _accessRights.put(username, MBeanInvocationHandlerImpl.ADMIN); + } + else + { + if (read | write) + { + if (read) + { + _accessRights.put(username, MBeanInvocationHandlerImpl.READONLY); + } + if (write) + { + _accessRights.put(username, MBeanInvocationHandlerImpl.READWRITE); + } + } + else + { + _accessRights.remove(username); + } + } + + saveAccessFile(); + } + finally + { + if (_accessRightsUpdate.isHeldByCurrentThread()) + { + _accessRightsUpdate.unlock(); + } + } + + return true; + } + + public boolean createUser(@MBeanOperationParameter(name = "username", description = "Username")String username, + @MBeanOperationParameter(name = "password", description = "Password")String password, + @MBeanOperationParameter(name = "read", description = "Administration read")boolean read, + @MBeanOperationParameter(name = "write", description = "Administration write")boolean write, + @MBeanOperationParameter(name = "admin", description = "Administration rights")boolean admin) + { + if (_principalDatabase.createPrincipal(new UsernamePrincipal(username), password)) + { + _accessRights.put(username, ""); + + return setRights(username, read, write, admin); + } + + return false; + } + + public boolean deleteUser(@MBeanOperationParameter(name = "username", description = "Username")String username) + { + + try + { + if (_principalDatabase.deletePrincipal(new UsernamePrincipal(username))) + { + try + { + _accessRightsUpdate.lock(); + + _accessRights.remove(username); + saveAccessFile(); + } + finally + { + if (_accessRightsUpdate.isHeldByCurrentThread()) + { + _accessRightsUpdate.unlock(); + } + } + return true; + } + } + catch (AccountNotFoundException e) + { + _logger.warn("Attempt to delete user (" + username + ") that doesn't exist"); + } + + return false; + } + + public boolean reloadData() + { + try + { + try + { + loadAccessFile(); + } + catch (ConfigurationException e) + { + _logger.info("Reload failed due to:" + e); + return false; + } + + // Reload successful + return true; + } + catch (IOException e) + { + _logger.info("Reload failed due to:" + e); + // Reload unsuccessful + return false; + } + } + + + @MBeanOperation(name = "viewUsers", description = "All users with access rights to the system.") + public TabularData viewUsers() + { + // Table of users + // Username(string), Access rights Read,Write,Admin(bool,bool,bool) + + reloadData(); + + if (_userlistDataType == null) + { + _logger.warn("TabluarData not setup correctly"); + return null; + } + + List<Principal> users = _principalDatabase.getUsers(); + + TabularDataSupport userList = new TabularDataSupport(_userlistDataType); + + try + { + // Create the tabular list of message header contents + for (Principal user : users) + { + // Create header attributes list + + String rights = (String) _accessRights.get(user.getName()); + + Boolean read = false; + Boolean write = false; + Boolean admin = false; + + if (rights != null) + { + read = rights.equals(MBeanInvocationHandlerImpl.READONLY) + || rights.equals(MBeanInvocationHandlerImpl.READWRITE); + write = rights.equals(MBeanInvocationHandlerImpl.READWRITE); + admin = rights.equals(MBeanInvocationHandlerImpl.ADMIN); + } + + Object[] itemData = {user.getName(), read, write, admin}; + CompositeData messageData = new CompositeDataSupport(_userDataType, _userItemNames, itemData); + userList.put(messageData); + } + } + catch (OpenDataException e) + { + _logger.warn("Unable to create user list due to :" + e); + return null; + } + + return userList; + } + + /*** Broker Methods **/ + + /** + * setPrincipalDatabase + * + * @param database set The Database to use for user lookup + */ + public void setPrincipalDatabase(PrincipalDatabase database) + { + _principalDatabase = database; + } + + /** + * setAccessFile + * + * @param accessFile the file to use for updating. + * + * @throws java.io.IOException If the file cannot be accessed + * @throws org.apache.commons.configuration.ConfigurationException + * if checks on the file fail. + */ + public void setAccessFile(String accessFile) throws IOException, ConfigurationException + { + _accessFileName = accessFile; + + if (_accessFileName != null) + { + loadAccessFile(); + } + else + { + _logger.warn("Access rights file specified is null. Access rights not changed."); + } + } + + private void loadAccessFile() throws IOException, ConfigurationException + { + try + { + _accessRightsUpdate.lock(); + + Properties accessRights = new Properties(); + + File accessFile = new File(_accessFileName); + + if (!accessFile.exists()) + { + throw new ConfigurationException("'" + _accessFileName + "' does not exist"); + } + + if (!accessFile.canRead()) + { + throw new ConfigurationException("Cannot read '" + _accessFileName + "'."); + } + + if (!accessFile.canWrite()) + { + _logger.warn("Unable to write to access file '" + _accessFileName + "' changes will not be preserved."); + } + + accessRights.load(new FileInputStream(accessFile)); + checkAccessRights(accessRights); + setAccessRights(accessRights); + } + finally + { + if (_accessRightsUpdate.isHeldByCurrentThread()) + { + _accessRightsUpdate.unlock(); + } + } + } + + private void checkAccessRights(Properties accessRights) + { + Enumeration values = accessRights.propertyNames(); + + while (values.hasMoreElements()) + { + String user = (String) values.nextElement(); + + if (_principalDatabase.getUser(user) == null) + { + _logger.warn("Access rights contains user '" + user + "' but there is no authentication data for that user"); + } + } + } + + private void saveAccessFile() + { + try + { + _accessRightsUpdate.lock(); + try + { + // remove old temporary file + File tmp = new File(_accessFileName + ".tmp"); + if (tmp.exists()) + { + tmp.delete(); + } + + //remove old backup + File old = new File(_accessFileName + ".old"); + if (old.exists()) + { + old.delete(); + } + + // Rename current file + File rights = new File(_accessFileName); + rights.renameTo(old); + + FileOutputStream output = new FileOutputStream(tmp); + _accessRights.store(output, ""); + output.close(); + + // Rename new file to main file + tmp.renameTo(rights); + + // delete tmp + tmp.delete(); + } + catch (IOException e) + { + _logger.warn("Problem occured saving '" + _accessFileName + "' changes may not be preserved. :" + e); + } + } + finally + { + if (_accessRightsUpdate.isHeldByCurrentThread()) + { + _accessRightsUpdate.unlock(); + } + } + } + + /** + * user=read user=write user=readwrite user=admin + * + * @param accessRights The properties list of access rights to process + */ + private void setAccessRights(Properties accessRights) + { + _logger.debug("Setting Access Rights:" + accessRights); + _accessRights = accessRights; + MBeanInvocationHandlerImpl.setAccessRights(_accessRights); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessManager.java index 0c0de88182..d70a6dc8f4 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessManager.java @@ -20,8 +20,13 @@ */ package org.apache.qpid.server.security.access; +import java.security.Principal; + public interface AccessManager { + AccessResult isAuthorized(Accessable accessObject, Principal username, AccessRights.Rights rights); + + @Deprecated AccessResult isAuthorized(Accessable accessObject, String username); String getName(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessManagerImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessManagerImpl.java index 0feb2791da..35d036d20f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessManagerImpl.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessManagerImpl.java @@ -23,13 +23,13 @@ package org.apache.qpid.server.security.access; import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.ConfigurationException; import org.apache.qpid.server.registry.ApplicationRegistry; +import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; import org.apache.qpid.configuration.PropertyUtils; -import org.apache.qpid.configuration.PropertyException; import org.apache.log4j.Logger; import java.util.List; import java.lang.reflect.Method; -import java.lang.reflect.InvocationTargetException; +import java.security.Principal; public class AccessManagerImpl implements AccessManager { @@ -39,8 +39,13 @@ public class AccessManagerImpl implements AccessManager public AccessManagerImpl(String name, Configuration hostConfig) throws ConfigurationException { - String accessClass = hostConfig.getString("security.access.class"); + if (hostConfig == null) + { + _logger.warn("No Configuration specified. Using default access controls for VirtualHost:'" + name + "'"); + return; + } + String accessClass = hostConfig.getString("security.access.class"); if (accessClass == null) { _logger.warn("No access control specified. Using default access controls for VirtualHost:'" + name + "'"); @@ -111,21 +116,35 @@ public class AccessManagerImpl implements AccessManager } catch (Exception e) { - throw new ConfigurationException(e.getCause()); + ConfigurationException ce = new ConfigurationException(e.getMessage(), e.getCause()); + ce.initCause(e); + throw ce; } } } - public AccessResult isAuthorized(Accessable accessObject, String username) { + return isAuthorized(accessObject, new UsernamePrincipal(username), AccessRights.Rights.READ); + } + + public AccessResult isAuthorized(Accessable accessObject, Principal user, AccessRights.Rights rights) + { if (_accessManager == null) { - return ApplicationRegistry.getInstance().getAccessManager().isAuthorized(accessObject, username); + if (ApplicationRegistry.getInstance().getAccessManager() == this) + { + _logger.warn("No Default access manager specified DENYING ALL ACCESS"); + return new AccessResult(this, AccessResult.AccessStatus.REFUSED); + } + else + { + return ApplicationRegistry.getInstance().getAccessManager().isAuthorized(accessObject, user, rights); + } } else { - return _accessManager.isAuthorized(accessObject, username); + return _accessManager.isAuthorized(accessObject, user, rights); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessRights.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessRights.java new file mode 100644 index 0000000000..1b79a5a0e0 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AccessRights.java @@ -0,0 +1,63 @@ +/* + * 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.security.access; + +public class AccessRights +{ + public enum Rights + { + ANY, + READ, + WRITE, + READWRITE + } + + Rights _right; + + public AccessRights(Rights right) + { + _right = right; + } + + public boolean allows(Rights rights) + { + switch (_right) + { + case ANY: + return (rights.equals(Rights.WRITE) + || rights.equals(Rights.READ) + || rights.equals(Rights.READWRITE) + || rights.equals(Rights.ANY)); + case READ: + return rights.equals(Rights.READ) || rights.equals(Rights.ANY); + case WRITE: + return rights.equals(Rights.WRITE) || rights.equals(Rights.ANY); + case READWRITE: + return true; + } + return false; + } + + public Rights getRights() + { + return _right; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AllowAll.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AllowAll.java index b2e4094edd..1ddca3a64e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AllowAll.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/AllowAll.java @@ -20,9 +20,16 @@ */ package org.apache.qpid.server.security.access; +import java.security.Principal; + public class AllowAll implements AccessManager { + public AccessResult isAuthorized(Accessable accessObject, Principal username, AccessRights.Rights rights) + { + return new AccessResult(this, AccessResult.AccessStatus.GRANTED); + } + public AccessResult isAuthorized(Accessable accessObject, String username) { return new AccessResult(this, AccessResult.AccessStatus.GRANTED); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/DenyAll.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/DenyAll.java index 0e62d2657f..bf40eeba4e 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/DenyAll.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/DenyAll.java @@ -20,8 +20,15 @@ */ package org.apache.qpid.server.security.access; +import java.security.Principal; + public class DenyAll implements AccessManager { + public AccessResult isAuthorized(Accessable accessObject, Principal username, AccessRights.Rights rights) + { + return new AccessResult(this, AccessResult.AccessStatus.REFUSED); + } + public AccessResult isAuthorized(Accessable accessObject, String username) { return new AccessResult(this, AccessResult.AccessStatus.REFUSED); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/FileAccessManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/FileAccessManager.java new file mode 100644 index 0000000000..291bc714ed --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/FileAccessManager.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.security.access; + +import org.apache.qpid.server.virtualhost.VirtualHost; +import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; +import org.apache.log4j.Logger; + +import java.io.IOException; +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.FileNotFoundException; +import java.io.File; +import java.util.regex.Pattern; +import java.security.Principal; + +/** + * Represents a user database where the account information is stored in a simple flat file. + * + * The file is expected to be in the form: username:password username1:password1 ... usernamen:passwordn + * + * where a carriage return separates each username/password pair. Passwords are assumed to be in plain text. + */ +public class FileAccessManager implements AccessManager +{ + private static final Logger _logger = Logger.getLogger(FileAccessManager.class); + + protected File _accessFile; + + protected Pattern _regexp = Pattern.compile(":"); + + private static final short USER_INDEX = 0; + private static final short VIRTUALHOST_INDEX = 1; + + public void setAccessFile(String accessFile) throws FileNotFoundException + { + File f = new File(accessFile); + _logger.info("FileAccessManager using file " + f.getAbsolutePath()); + _accessFile = f; + if (!f.exists()) + { + throw new FileNotFoundException("Cannot find access file " + f); + } + if (!f.canRead()) + { + throw new FileNotFoundException("Cannot read access file " + f + + ". Check permissions."); + } + } + + /** + * Looks up the virtual hosts for a specified user in the access file. + * + * @param user The user to lookup + * + * @return a list of virtualhosts + */ + private VirtualHostAccess[] lookupVirtualHost(String user) + { + String[] results = lookup(user, VIRTUALHOST_INDEX); + VirtualHostAccess vhosts[] = new VirtualHostAccess[results.length]; + + for (int index = 0; index < results.length; index++) + { + vhosts[index] = new VirtualHostAccess(results[index]); + } + + return vhosts; + } + + + private String[] lookup(String user, int index) + { + try + { + BufferedReader reader = null; + try + { + reader = new BufferedReader(new FileReader(_accessFile)); + String line; + + while ((line = reader.readLine()) != null) + { + String[] result = _regexp.split(line); + if (result == null || result.length < (index + 1)) + { + continue; + } + + if (user.equals(result[USER_INDEX])) + { + return result[index].split(","); + } + } + return null; + } + finally + { + if (reader != null) + { + reader.close(); + } + } + } + catch (IOException ioe) + { + //ignore + } + return null; + } + + public AccessResult isAuthorized(Accessable accessObject, String username) + { + return isAuthorized(accessObject, new UsernamePrincipal(username), AccessRights.Rights.READ); + } + + public AccessResult isAuthorized(Accessable accessObject, Principal user, AccessRights.Rights rights) + { + if (accessObject instanceof VirtualHost) + { + VirtualHostAccess[] hosts = lookupVirtualHost(user.getName()); + + if (hosts != null) + { + for (VirtualHostAccess host : hosts) + { + if (accessObject.getAccessableName().equals(host.getVirtualHost())) + { + if (host.getAccessRights().allows(rights)) + { + return new AccessResult(this, AccessResult.AccessStatus.GRANTED); + } + else + { + return new AccessResult(this, AccessResult.AccessStatus.REFUSED); + } + } + } + } + } +// else if (accessObject instanceof AMQQueue) +// { +// String[] queues = lookupQueue(username, ((AMQQueue) accessObject).getVirtualHost()); +// +// if (queues != null) +// { +// for (String queue : queues) +// { +// if (accessObject.getAccessableName().equals(queue)) +// { +// return new AccessResult(this, AccessResult.AccessStatus.GRANTED); +// } +// } +// } +// } + + return new AccessResult(this, AccessResult.AccessStatus.REFUSED); + } + + public String getName() + { + return "FileAccessManager"; + } + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalDatabaseAccessManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalDatabaseAccessManager.java index 0e447b5744..6ccadb2e7d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalDatabaseAccessManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/PrincipalDatabaseAccessManager.java @@ -22,8 +22,11 @@ package org.apache.qpid.server.security.access; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.security.auth.database.PrincipalDatabase; +import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; import org.apache.log4j.Logger; +import java.security.Principal; + public class PrincipalDatabaseAccessManager implements AccessManager { private static final Logger _logger = Logger.getLogger(PrincipalDatabaseAccessManager.class); @@ -58,15 +61,21 @@ public class PrincipalDatabaseAccessManager implements AccessManager } } + public AccessResult isAuthorized(Accessable accessObject, String username) { + return isAuthorized(accessObject, new UsernamePrincipal(username), AccessRights.Rights.READ); + } + + public AccessResult isAuthorized(Accessable accessObject, Principal username, AccessRights.Rights rights) + { AccessResult result; if (_database == null) { if (_default != null) { - result = _default.isAuthorized(accessObject, username); + result = _default.isAuthorized(accessObject, username, rights); } else { @@ -75,7 +84,15 @@ public class PrincipalDatabaseAccessManager implements AccessManager } else { - result = ((AccessManager) _database).isAuthorized(accessObject, username); + if (!(_database instanceof AccessManager)) + { + _logger.warn("Specified PrincipalDatabase is not an AccessManager so using default AccessManager"); + result = _default.isAuthorized(accessObject, username, rights); + } + else + { + result = ((AccessManager) _database).isAuthorized(accessObject, username, rights); + } } result.addAuthorizer(this); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/UserManagement.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/UserManagement.java new file mode 100644 index 0000000000..6381213398 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/UserManagement.java @@ -0,0 +1,111 @@ +/* + * 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.security.access; + +import org.apache.qpid.server.management.MBeanOperation; +import org.apache.qpid.server.management.MBeanOperationParameter; +import org.apache.qpid.server.management.MBeanAttribute; +import org.apache.qpid.AMQException; + +import javax.management.openmbean.TabularData; +import javax.management.openmbean.CompositeData; +import javax.management.JMException; +import java.io.IOException; + +public interface UserManagement +{ + String TYPE = "UserManagement"; + + //********** Operations *****************// + /** + * set password for user + * + * @param username The username to create + * @param password The password for the user + * + * @return The result of the operation + */ + @MBeanOperation(name = "setPassword", description = "Set password for user.") + boolean setPassword(@MBeanOperationParameter(name = "username", description = "Username")String username, + @MBeanOperationParameter(name = "password", description = "Password")String password); + + /** + * set rights for users with given details + * + * @param username The username to create + * @param read The set of permission to give the new user + * @param write The set of permission to give the new user + * @param admin The set of permission to give the new user + * + * @return The result of the operation + */ + @MBeanOperation(name = "setRights", description = "Set access rights for user.") + boolean setRights(@MBeanOperationParameter(name = "username", description = "Username")String username, + @MBeanOperationParameter(name = "read", description = "Administration read")boolean read, + @MBeanOperationParameter(name = "write", description = "Administration write")boolean write, + @MBeanOperationParameter(name = "admin", description = "Administration rights")boolean admin); + + /** + * Create users with given details + * + * @param username The username to create + * @param password The password for the user + * @param read The set of permission to give the new user + * @param write The set of permission to give the new user + * @param admin The set of permission to give the new user + * + * @return The result of the operation + */ + @MBeanOperation(name = "createUser", description = "Create new user from system.") + boolean createUser(@MBeanOperationParameter(name = "username", description = "Username")String username, + @MBeanOperationParameter(name = "password", description = "Password")String password, + @MBeanOperationParameter(name = "read", description = "Administration read")boolean read, + @MBeanOperationParameter(name = "write", description = "Administration write")boolean write, + @MBeanOperationParameter(name = "admin", description = "Administration rights")boolean admin); + + /** + * View users returns all the users that are currently available to the system. + * + * @param username The user to delete + * + * @return The result of the operation + */ + @MBeanOperation(name = "deleteUser", description = "Delete user from system.") + boolean deleteUser(@MBeanOperationParameter(name = "username", description = "Username")String username); + + + /** + * Reload the date from disk + * + * @return The result of the operation + */ +// @MBeanOperation(name = "reloadData", description = "Reload the authentication file from disk.") +// boolean reloadData(); + + /** + * View users returns all the users that are currently available to the system. + * + * @return a table of users data (Username, read, write, admin) + */ + @MBeanOperation(name = "viewUsers", description = "All users with access rights to the system.") + TabularData viewUsers(); + +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/VirtualHostAccess.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/VirtualHostAccess.java new file mode 100644 index 0000000000..13151a66b8 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/VirtualHostAccess.java @@ -0,0 +1,68 @@ +/* + * 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.security.access; + +public class VirtualHostAccess +{ + private String _vhost; + private AccessRights _rights; + + public VirtualHostAccess(String vhostaccess) + { + //format <vhost>(<rights>) + int hostend = vhostaccess.indexOf('('); + + if (hostend == -1) + { + throw new IllegalArgumentException("VirtualHostAccess format string contains no access _rights"); + } + + _vhost = vhostaccess.substring(0, hostend); + + String rights = vhostaccess.substring(hostend); + + if (rights.indexOf('r') != -1) + { + if (rights.indexOf('w') != -1) + { + _rights = new AccessRights(AccessRights.Rights.READWRITE); + } + else + { + _rights = new AccessRights(AccessRights.Rights.READ); + } + } + else if (rights.indexOf('w') != -1) + { + _rights = new AccessRights(AccessRights.Rights.WRITE); + } + } + + public AccessRights getAccessRights() + { + return _rights; + } + + public String getVirtualHost() + { + return _vhost; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java new file mode 100644 index 0000000000..956db64d90 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java @@ -0,0 +1,626 @@ +/* + * 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.security.auth.database; + +import org.apache.log4j.Logger; +import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser; +import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; +import org.apache.qpid.server.security.auth.sasl.crammd5.CRAMMD5HashedInitialiser; +import org.apache.qpid.server.security.access.AMQUserManagementMBean; +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.codec.EncoderException; + +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.login.AccountNotFoundException; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.UnsupportedEncodingException; +import java.io.PrintStream; +import java.util.regex.Pattern; +import java.util.Map; +import java.util.HashMap; +import java.util.List; +import java.util.LinkedList; +import java.util.concurrent.locks.ReentrantLock; +import java.security.Principal; +import java.security.NoSuchAlgorithmException; +import java.security.MessageDigest; + +/** + * Represents a user database where the account information is stored in a simple flat file. + * + * The file is expected to be in the form: username:password username1:password1 ... usernamen:passwordn + * + * where a carriage return separates each username/password pair. Passwords are assumed to be in plain text. + */ +public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase +{ + private static final Logger _logger = Logger.getLogger(Base64MD5PasswordFilePrincipalDatabase.class); + + private File _passwordFile; + + private Pattern _regexp = Pattern.compile(":"); + + private Map<String, AuthenticationProviderInitialiser> _saslServers; + + AMQUserManagementMBean _mbean; + private static final String DEFAULT_ENCODING = "utf-8"; + private Map<String, User> _users = new HashMap<String, User>(); + private ReentrantLock _userUpdate = new ReentrantLock(); + + public Base64MD5PasswordFilePrincipalDatabase() + { + _saslServers = new HashMap<String, AuthenticationProviderInitialiser>(); + + /** + * Create Authenticators for MD5 Password file. + */ + + // Accept Plain incomming and hash it for comparison to the file. + CRAMMD5HashedInitialiser cram = new CRAMMD5HashedInitialiser(); + cram.initialise(this); + _saslServers.put(cram.getMechanismName(), cram); + + //fixme The PDs should setup a PD Mangement MBean +// try +// { +// _mbean = new AMQUserManagementMBean(); +// _mbean.setPrincipalDatabase(this); +// } +// catch (JMException e) +// { +// _logger.warn("User management disabled as unable to create MBean:" + e); +// } + } + + public void setPasswordFile(String passwordFile) throws IOException + { + File f = new File(passwordFile); + _logger.info("PasswordFilePrincipalDatabase using file " + f.getAbsolutePath()); + _passwordFile = f; + if (!f.exists()) + { + throw new FileNotFoundException("Cannot find password file " + f); + } + if (!f.canRead()) + { + throw new FileNotFoundException("Cannot read password file " + f + + ". Check permissions."); + } + + loadPasswordFile(); + } + + /** + * SASL Callback Mechanism - sets the Password in the PasswordCallback based on the value in the PasswordFile + * + * @param principal The Principal to set the password for + * @param callback The PasswordCallback to call setPassword on + * + * @throws AccountNotFoundException If the Principal cannont be found in this Database + */ + public void setPassword(Principal principal, PasswordCallback callback) throws AccountNotFoundException + { + if (_passwordFile == null) + { + throw new AccountNotFoundException("Unable to locate principal since no password file was specified during initialisation"); + } + if (principal == null) + { + throw new IllegalArgumentException("principal must not be null"); + } + + char[] pwd = lookupPassword(principal.getName()); + + if (pwd != null) + { + callback.setPassword(pwd); + } + else + { + throw new AccountNotFoundException("No account found for principal " + principal); + } + } + + /** + * Used to verify that the presented Password is correct. Currently only used by Management Console + * + * @param principal The principal to authenticate + * @param password The password to check + * + * @return true if password is correct + * + * @throws AccountNotFoundException if the principal cannot be found + */ + public boolean verifyPassword(String principal, String password) throws AccountNotFoundException + { + try + { + char[] pwd = lookupPassword(principal); + byte[] passwordBytes = password.getBytes(DEFAULT_ENCODING); + + int index = 0; + boolean verified = true; + + while (verified & index < passwordBytes.length) + { + verified = (pwd[index] == (char) passwordBytes[index]); + index++; + } + return verified; + } + catch (UnsupportedEncodingException e) + { + return false; + } + } + + public boolean updatePassword(Principal principal, String password) throws AccountNotFoundException + { + User user = _users.get(principal.getName()); + + if (user == null) + { + throw new AccountNotFoundException(principal.getName()); + } + + try + { + + char[] passwd = convertPassword(password); + + try + { + _userUpdate.lock(); + user.setPassword(passwd); + + try + { + savePasswordFile(); + } + catch (IOException e) + { + _logger.error("Unable to save password file, password change for user'" + + principal + "' will revert at restart"); + return false; + } + return true; + } + finally + { + if (_userUpdate.isHeldByCurrentThread()) + { + _userUpdate.unlock(); + } + } + } + catch (UnsupportedEncodingException e) + { + return false; + } + } + + private char[] convertPassword(String password) throws UnsupportedEncodingException + { + byte[] passwdBytes = password.getBytes(DEFAULT_ENCODING); + + char[] passwd = new char[passwdBytes.length]; + + int index = 0; + + for (byte b : passwdBytes) + { + passwd[index++] = (char) b; + } + + return passwd; + } + + public boolean createPrincipal(Principal principal, String password) + { + if (_users.get(principal.getName()) != null) + { + return false; + } + + User user; + try + { + user = new User(principal.getName(), convertPassword(password)); + } + catch (UnsupportedEncodingException e) + { + _logger.warn("Unable to encode password:" + e); + return false; + } + + try + { + _userUpdate.lock(); + _users.put(user.getName(), user); + + try + { + savePasswordFile(); + return true; + } + catch (IOException e) + { + return false; + } + + } + finally + { + if (_userUpdate.isHeldByCurrentThread()) + { + _userUpdate.unlock(); + } + } + } + + public boolean deletePrincipal(Principal principal) throws AccountNotFoundException + { + User user = _users.get(principal.getName()); + + if (user == null) + { + throw new AccountNotFoundException(principal.getName()); + } + + try + { + _userUpdate.lock(); + user.delete(); + + try + { + savePasswordFile(); + } + catch (IOException e) + { + _logger.warn("Unable to remove user '" + user.getName() + "' from password file."); + return false; + } + + _users.remove(user.getName()); + } + finally + { + if (_userUpdate.isHeldByCurrentThread()) + { + _userUpdate.unlock(); + } + } + + return true; + } + + + public Map<String, AuthenticationProviderInitialiser> getMechanisms() + { + return _saslServers; + } + + public List<Principal> getUsers() + { + return new LinkedList<Principal>(_users.values()); + } + + public Principal getUser(String username) + { + if (_users.containsKey(username)) + { + return new UsernamePrincipal(username); + } + return null; + } + + /** + * Looks up the password for a specified user in the password file. Note this code is <b>not</b> secure since it + * creates strings of passwords. It should be modified to create only char arrays which get nulled out. + * + * @param name The principal name to lookup + * + * @return a char[] for use in SASL. + */ + private char[] lookupPassword(String name) + { + User user = _users.get(name); + if (user == null) + { + return null; + } + else + { + return user.getPassword(); + } + } + + + private void loadPasswordFile() throws IOException + { + try + { + _userUpdate.lock(); + _users.clear(); + + BufferedReader reader = null; + try + { + reader = new BufferedReader(new FileReader(_passwordFile)); + String line; + + while ((line = reader.readLine()) != null) + { + String[] result = _regexp.split(line); + if (result == null || result.length < 2 || result[0].startsWith("#")) + { + continue; + } + + User user = new User(result); + _logger.info("Created user:" + user); + _users.put(user.getName(), user); + } + } + finally + { + if (reader != null) + { + reader.close(); + } + } + } + finally + { + if (_userUpdate.isHeldByCurrentThread()) + { + _userUpdate.unlock(); + } + } + } + + private void savePasswordFile() throws IOException + { + try + { + _userUpdate.lock(); + + BufferedReader reader = null; + PrintStream writer = null; + File tmp = new File(_passwordFile.getAbsolutePath() + ".tmp"); + if (tmp.exists()) + { + tmp.delete(); + } + try + { + writer = new PrintStream(tmp); + reader = new BufferedReader(new FileReader(_passwordFile)); + String line; + + while ((line = reader.readLine()) != null) + { + String[] result = _regexp.split(line); + if (result == null || result.length < 2 || result[0].startsWith("#")) + { + writer.write(line.getBytes(DEFAULT_ENCODING)); + continue; + } + + User user = _users.get(result[0]); + + if (user == null) + { + writer.write(line.getBytes(DEFAULT_ENCODING)); + writer.println(); + } + else if (!user.isDeleted()) + { + if (!user.isModified()) + { + writer.write(line.getBytes(DEFAULT_ENCODING)); + writer.println(); + } + else + { + try + { + byte[] encodedPassword = user.getEncodePassword(); + + writer.write((user.getName() + ":").getBytes(DEFAULT_ENCODING)); + writer.write(encodedPassword); + writer.println(); + + user.saved(); + } + catch (Exception e) + { + _logger.warn("Unable to encode new password reverting to old password."); + writer.write(line.getBytes(DEFAULT_ENCODING)); + writer.println(); + } + } + } + } + + for (User user : _users.values()) + { + if (user.isModified()) + { + byte[] encodedPassword; + try + { + encodedPassword = user.getEncodePassword(); + writer.write((user.getName() + ":").getBytes(DEFAULT_ENCODING)); + writer.write(encodedPassword); + writer.println(); + user.saved(); + } + catch (Exception e) + { + _logger.warn("Unable to get Encoded password for user'" + user.getName() + "' password not saved"); + } + } + } + } + finally + { + if (reader != null) + { + reader.close(); + } + + if (writer != null) + { + writer.close(); + } + + // Swap temp file to main password file. + File old = new File(_passwordFile.getAbsoluteFile() + ".old"); + if (old.exists()) + { + old.delete(); + } + _passwordFile.renameTo(old); + tmp.renameTo(_passwordFile); + tmp.delete(); + } + } + finally + { + if (_userUpdate.isHeldByCurrentThread()) + { + _userUpdate.unlock(); + } + } + } + + private class User implements Principal + { + String _name; + char[] _password; + byte[] _encodedPassword = null; + private boolean _modified = false; + private boolean _deleted = false; + + User(String[] data) throws UnsupportedEncodingException + { + if (data.length != 2) + { + throw new IllegalArgumentException("User Data should be lenght 2, username, password"); + } + + _name = data[0]; + + byte[] encoded_password = data[1].getBytes(DEFAULT_ENCODING); + + Base64 b64 = new Base64(); + byte[] decoded = b64.decode(encoded_password); + + _encodedPassword = encoded_password; + + _password = new char[decoded.length]; + + int index = 0; + for (byte c : decoded) + { + _password[index++] = (char) c; + } + } + + public User(String name, char[] password) + { + _name = name; + setPassword(password); + } + + public String getName() + { + return _name; + } + + public String toString() + { + if (_logger.isDebugEnabled()) + { + return getName() + ((_encodedPassword == null) ? "" : ":" + new String(_encodedPassword)); + } + else + { + return _name; + } + } + + char[] getPassword() + { + return _password; + } + + void setPassword(char[] password) + { + _password = password; + _modified = true; + _encodedPassword = null; + } + + + byte[] getEncodePassword() throws EncoderException, UnsupportedEncodingException, NoSuchAlgorithmException + { + if (_encodedPassword == null) + { + encodePassword(); + } + return _encodedPassword; + } + + private void encodePassword() throws EncoderException, UnsupportedEncodingException, NoSuchAlgorithmException + { + Base64 b64 = new Base64(); + _encodedPassword = b64.encode(new String(_password).getBytes(DEFAULT_ENCODING)); + } + + public boolean isModified() + { + return _modified; + } + + public boolean isDeleted() + { + return _deleted; + } + + public void delete() + { + _deleted = true; + } + + public void saved() + { + _modified = false; + } + + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java index 0c35206dd3..2d3f5e5131 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/ConfigurationFilePrincipalDatabaseManager.java @@ -1,38 +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 + * 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 * - * 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. + * 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.security.auth.database; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.ConfigurationException; + +import org.apache.log4j.Logger; + +import org.apache.qpid.configuration.PropertyUtils; +import org.apache.qpid.configuration.PropertyException; import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.security.auth.database.PrincipalDatabaseManager; import org.apache.qpid.server.security.auth.database.PrincipalDatabase; -import org.apache.qpid.configuration.PropertyUtils; -import org.apache.log4j.Logger; +import org.apache.qpid.server.security.auth.database.PrincipalDatabaseManager; +import org.apache.qpid.server.security.access.AMQUserManagementMBean; +import org.apache.qpid.AMQException; -import java.util.Map; -import java.util.List; -import java.util.HashMap; -import java.lang.reflect.Method; -import java.io.FileNotFoundException; +import javax.management.JMException; public class ConfigurationFilePrincipalDatabaseManager implements PrincipalDatabaseManager { @@ -80,18 +88,21 @@ public class ConfigurationFilePrincipalDatabaseManager implements PrincipalDatab initialisePrincipalDatabase((PrincipalDatabase) o, config, i); String name = databaseNames.get(i); - if (name == null || name.length() == 0) + if ((name == null) || (name.length() == 0)) { throw new Exception("Principal database names must have length greater than or equal to one character"); } + PrincipalDatabase pd = databases.get(name); if (pd != null) { throw new Exception("Duplicate principal database name not provided"); } + _logger.info("Initialised principal database '" + name + "' successfully"); databases.put(name, (PrincipalDatabase) o); } + return databases; } @@ -104,14 +115,16 @@ public class ConfigurationFilePrincipalDatabaseManager implements PrincipalDatab for (int i = 0; i < argumentNames.size(); i++) { String argName = argumentNames.get(i); - if (argName == null || argName.length() == 0) + if ((argName == null) || (argName.length() == 0)) { throw new ConfigurationException("Argument names must have length >= 1 character"); } + if (Character.isLowerCase(argName.charAt(0))) { argName = Character.toUpperCase(argName.charAt(0)) + argName.substring(1); } + String methodName = "set" + argName; Method method = null; try @@ -125,9 +138,10 @@ public class ConfigurationFilePrincipalDatabaseManager implements PrincipalDatab if (method == null) { - throw new ConfigurationException("No method " + methodName + " found in class " + principalDatabase.getClass() + - " hence unable to configure principal database. The method must be public and " + - "have a single String argument with a void return type"); + throw new ConfigurationException("No method " + methodName + " found in class " + + principalDatabase.getClass() + + " hence unable to configure principal database. The method must be public and " + + "have a single String argument with a void return type"); } try @@ -136,7 +150,14 @@ public class ConfigurationFilePrincipalDatabaseManager implements PrincipalDatab } catch (Exception ite) { - throw new ConfigurationException(ite.getCause()); + if (ite instanceof ConfigurationException) + { + throw(ConfigurationException) ite; + } + else + { + throw new ConfigurationException(ite.getMessage(), ite); + } } } } @@ -145,4 +166,71 @@ public class ConfigurationFilePrincipalDatabaseManager implements PrincipalDatab { return _databases; } + + public void initialiseManagement(Configuration config) throws ConfigurationException + { + try + { + AMQUserManagementMBean _mbean = new AMQUserManagementMBean(); + + String baseSecurity = "security.jmx"; + List<String> principalDBs = config.getList(baseSecurity + ".principal-database"); + + if (principalDBs.size() == 0) + { + throw new ConfigurationException("No principal-database specified for jmx security(" + baseSecurity + ".principal-database)"); + } + + String databaseName = principalDBs.get(0); + + PrincipalDatabase database = getDatabases().get(databaseName); + + if (database == null) + { + throw new ConfigurationException("Principal-database '" + databaseName + "' not found"); + } + + _mbean.setPrincipalDatabase(database); + + List<String> jmxaccesslist = config.getList(baseSecurity + ".access"); + + if (jmxaccesslist.size() == 0) + { + throw new ConfigurationException("No access control files specified for jmx security(" + baseSecurity + ".access)"); + } + + String jmxaccesssFile = null; + + try + { + jmxaccesssFile = PropertyUtils.replaceProperties(jmxaccesslist.get(0)); + } + catch (PropertyException e) + { + throw new ConfigurationException("Unable to parse access control filename '" + jmxaccesssFile + "'"); + } + + try + { + _mbean.setAccessFile(jmxaccesssFile); + } + catch (IOException e) + { + _logger.warn("Unable to load access file:" + jmxaccesssFile); + } + + try + { + _mbean.register(); + } + catch (AMQException e) + { + _logger.warn("Unable to register user management MBean"); + } + } + catch (JMException e) + { + _logger.warn("User management disabled as unable to create MBean:" + e); + } + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/MD5PasswordFilePrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/MD5PasswordFilePrincipalDatabase.java deleted file mode 100644 index c24a5f21e9..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/MD5PasswordFilePrincipalDatabase.java +++ /dev/null @@ -1,160 +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.security.auth.database; - -import org.apache.log4j.Logger; -import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser; -import org.apache.qpid.server.security.auth.sasl.crammd5.CRAMMD5Initialiser; -import org.apache.qpid.server.security.auth.sasl.plain.PlainInitialiser; - -import javax.security.auth.callback.PasswordCallback; -import javax.security.auth.login.AccountNotFoundException; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.BufferedReader; -import java.io.FileReader; -import java.util.regex.Pattern; -import java.util.Map; -import java.util.HashMap; -import java.security.Principal; - -/** - * Represents a user database where the account information is stored in a simple flat file. - * - * The file is expected to be in the form: username:password username1:password1 ... usernamen:passwordn - * - * where a carriage return separates each username/password pair. Passwords are assumed to be in plain text. - */ -public class MD5PasswordFilePrincipalDatabase implements PrincipalDatabase -{ - private static final Logger _logger = Logger.getLogger(MD5PasswordFilePrincipalDatabase.class); - - private File _passwordFile; - - private Pattern _regexp = Pattern.compile(":"); - - private Map<String, AuthenticationProviderInitialiser> _saslServers; - - public MD5PasswordFilePrincipalDatabase() - { - _saslServers = new HashMap<String, AuthenticationProviderInitialiser>(); - - /** - * Create Authenticators for MD5 Password file. - */ - - // Accept MD5 incomming and use plain comparison with the file - PlainInitialiser cram = new PlainInitialiser(); - cram.initialise(this); - // Accept Plain incomming and hash it for comparison to the file. - CRAMMD5Initialiser plain = new CRAMMD5Initialiser(); - plain.initialise(this,CRAMMD5Initialiser.HashDirection.INCOMMING); - - _saslServers.put(plain.getMechanismName(), cram); - _saslServers.put(cram.getMechanismName(), plain); - } - - public void setPasswordFile(String passwordFile) throws FileNotFoundException - { - File f = new File(passwordFile); - _logger.info("PasswordFilePrincipalDatabase using file " + f.getAbsolutePath()); - _passwordFile = f; - if (!f.exists()) - { - throw new FileNotFoundException("Cannot find password file " + f); - } - if (!f.canRead()) - { - throw new FileNotFoundException("Cannot read password file " + f + - ". Check permissions."); - } - } - - public void setPassword(Principal principal, PasswordCallback callback) throws IOException, - AccountNotFoundException - { - if (_passwordFile == null) - { - throw new AccountNotFoundException("Unable to locate principal since no password file was specified during initialisation"); - } - if (principal == null) - { - throw new IllegalArgumentException("principal must not be null"); - } - char[] pwd = lookupPassword(principal.getName()); - if (pwd != null) - { - callback.setPassword(pwd); - } - else - { - throw new AccountNotFoundException("No account found for principal " + principal); - } - } - - public Map<String, AuthenticationProviderInitialiser> getMechanisms() - { - return _saslServers; - } - - /** - * Looks up the password for a specified user in the password file. Note this code is <b>not</b> secure since it - * creates strings of passwords. It should be modified to create only char arrays which get nulled out. - * - * @param name - * - * @return - * - * @throws java.io.IOException - */ - private char[] lookupPassword(String name) throws IOException - { - BufferedReader reader = null; - try - { - reader = new BufferedReader(new FileReader(_passwordFile)); - String line; - - while ((line = reader.readLine()) != null) - { - String[] result = _regexp.split(line); - if (result == null || result.length < 2) - { - continue; - } - - if (name.equals(result[0])) - { - return result[1].toCharArray(); - } - } - return null; - } - finally - { - if (reader != null) - { - reader.close(); - } - } - } -} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java index 3abdd9a7ff..3f6794aaaf 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java @@ -21,8 +21,8 @@ package org.apache.qpid.server.security.auth.database; import org.apache.log4j.Logger; -import org.apache.qpid.server.security.auth.database.PrincipalDatabase; import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser; +import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; import org.apache.qpid.server.security.auth.sasl.amqplain.AmqPlainInitialiser; import org.apache.qpid.server.security.auth.sasl.crammd5.CRAMMD5Initialiser; import org.apache.qpid.server.security.auth.sasl.plain.PlainInitialiser; @@ -34,9 +34,11 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.io.BufferedReader; import java.io.FileReader; +import java.io.UnsupportedEncodingException; import java.util.regex.Pattern; import java.util.Map; import java.util.HashMap; +import java.util.List; import java.security.Principal; /** @@ -119,21 +121,103 @@ public class PlainPasswordFilePrincipalDatabase implements PrincipalDatabase } } + public boolean verifyPassword(String principal, String password) throws AccountNotFoundException + { + try + { + char[] pwd = lookupPassword(principal); + + return compareCharArray(pwd, convertPassword(password)); + } + catch (IOException e) + { + return false; + } + } + + private char[] convertPassword(String password) throws UnsupportedEncodingException + { + byte[] passwdBytes = password.getBytes("utf-8"); + + char[] passwd = new char[passwdBytes.length]; + + int index = 0; + + for (byte b : passwdBytes) + { + passwd[index++] = (char) b; + } + + return passwd; + } + + public boolean updatePassword(Principal principal, String password) throws AccountNotFoundException + { + return false; // updates denied + } + + public boolean createPrincipal(Principal principal, String password) + { + return false; // updates denied + } + + public boolean deletePrincipal(Principal principal) throws AccountNotFoundException + { + return false; // updates denied + } + public Map<String, AuthenticationProviderInitialiser> getMechanisms() { return _saslServers; } + public List<Principal> getUsers() + { + return null; //todo + } + + public Principal getUser(String username) + { + try + { + if (lookupPassword(username) != null) + { + return new UsernamePrincipal(username); + } + } + catch (IOException e) + { + //fall through to null return + } + return null; + } + + private boolean compareCharArray(char[] a, char[] b) + { + boolean equal = false; + if (a.length == b.length) + { + equal = true; + int index = 0; + while (equal && index < a.length) + { + equal = a[index] == b[index]; + index++; + } + } + return equal; + } + /** * Looks up the password for a specified user in the password file. Note this code is <b>not</b> secure since it * creates strings of passwords. It should be modified to create only char arrays which get nulled out. * - * @param name + * @param name the name of the principal to lookup * - * @return + * @return char[] of the password * - * @throws java.io.IOException + * @throws java.io.IOException whilst accessing the file */ private char[] lookupPassword(String name) throws IOException { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordVhostFilePrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordVhostFilePrincipalDatabase.java index c8318d6e64..598f8f8b4c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordVhostFilePrincipalDatabase.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordVhostFilePrincipalDatabase.java @@ -20,26 +20,17 @@ */ package org.apache.qpid.server.security.auth.database; -import org.apache.qpid.server.security.auth.database.PrincipalDatabase; -import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser; -import org.apache.qpid.server.security.auth.sasl.crammd5.CRAMMD5Initialiser; -import org.apache.qpid.server.security.auth.sasl.plain.PlainInitialiser; import org.apache.qpid.server.security.access.AccessManager; import org.apache.qpid.server.security.access.AccessResult; import org.apache.qpid.server.security.access.Accessable; +import org.apache.qpid.server.security.access.AccessRights; +import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; import org.apache.qpid.server.virtualhost.VirtualHost; import org.apache.log4j.Logger; -import javax.security.auth.callback.PasswordCallback; -import javax.security.auth.login.AccountNotFoundException; -import java.io.File; -import java.io.FileNotFoundException; import java.io.IOException; import java.io.BufferedReader; import java.io.FileReader; -import java.util.regex.Pattern; -import java.util.Map; -import java.util.HashMap; import java.security.Principal; /** @@ -103,9 +94,15 @@ public class PlainPasswordVhostFilePrincipalDatabase extends PlainPasswordFilePr public AccessResult isAuthorized(Accessable accessObject, String username) { + return isAuthorized(accessObject, new UsernamePrincipal(username), AccessRights.Rights.READ); + } + + public AccessResult isAuthorized(Accessable accessObject, Principal user, AccessRights.Rights rights) + { + if (accessObject instanceof VirtualHost) { - String[] hosts = lookupVirtualHost(username); + String[] hosts = lookupVirtualHost(user.getName()); if (hosts != null) { @@ -126,4 +123,5 @@ public class PlainPasswordVhostFilePrincipalDatabase extends PlainPasswordFilePr { return "PlainPasswordVhostFile"; } + } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabase.java index 6c5a2a44ee..8073fcc3c6 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabase.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabase.java @@ -23,8 +23,10 @@ package org.apache.qpid.server.security.auth.database; import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser; import java.io.IOException; +import java.io.UnsupportedEncodingException; import java.security.Principal; import java.util.Map; +import java.util.List; import javax.security.auth.callback.PasswordCallback; import javax.security.auth.login.AccountNotFoundException; @@ -46,5 +48,53 @@ public interface PrincipalDatabase void setPassword(Principal principal, PasswordCallback callback) throws IOException, AccountNotFoundException; + /** + * Used to verify that the presented Password is correct. Currently only used by Management Console + * @param principal The principal to authenticate + * @param password The password to check + * @return true if password is correct + * @throws AccountNotFoundException if the principal cannot be found + */ + boolean verifyPassword(String principal, String password) + throws AccountNotFoundException; + + /** + * Update(Change) the password for the given principal + * @param principal Who's password is to be changed + * @param password The new password to use + * @return True if change was successful + * @throws AccountNotFoundException If the given principal doesn't exist in the Database + */ + boolean updatePassword(Principal principal, String password) + throws AccountNotFoundException; + + /** + * Create a new principal in the database + * @param principal The principal to create + * @param password The password to set for the principal + * @return True on a successful creation + */ + boolean createPrincipal(Principal principal, String password); + + /** + * Delete a principal + * @param principal The principal to delete + * @return True on a successful creation + * @throws AccountNotFoundException If the given principal doesn't exist in the Database + */ + boolean deletePrincipal(Principal principal) + throws AccountNotFoundException; + + /** + * Get the principal from the database with the given username + * @param username of the principal to lookup + * @return The Principal object for the given username or null if not found. + */ + Principal getUser(String username); + + public Map<String, AuthenticationProviderInitialiser> getMechanisms(); + + + List<Principal> getUsers(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabaseManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabaseManager.java index 83f1201bd8..2c553ae76a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabaseManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabaseManager.java @@ -21,10 +21,14 @@ package org.apache.qpid.server.security.auth.database; import org.apache.qpid.server.security.auth.database.PrincipalDatabase; +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationException; import java.util.Map; public interface PrincipalDatabaseManager { public Map<String, PrincipalDatabase> getDatabases(); + + public void initialiseManagement(Configuration config) throws ConfigurationException; } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java index 9a58acd98c..b1ac0e1f00 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java @@ -21,6 +21,7 @@ package org.apache.qpid.server.security.auth.database; import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser; +import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; import org.apache.qpid.server.security.auth.sasl.crammd5.CRAMMD5Initialiser; import org.apache.qpid.server.security.auth.sasl.plain.PlainInitialiser; @@ -29,8 +30,10 @@ import javax.security.auth.login.AccountNotFoundException; import java.util.Properties; import java.util.Map; import java.util.HashMap; +import java.util.List; import java.security.Principal; import java.io.IOException; +import java.io.UnsupportedEncodingException; public class PropertiesPrincipalDatabase implements PrincipalDatabase { @@ -76,8 +79,87 @@ public class PropertiesPrincipalDatabase implements PrincipalDatabase } } + public boolean verifyPassword(String principal, String password) throws AccountNotFoundException + { + char[] pwd = _users.getProperty(principal).toCharArray(); + + try + { + return compareCharArray(pwd, convertPassword(password)); + } + catch (UnsupportedEncodingException e) + { + return false; + } + } + + public boolean updatePassword(Principal principal, String password) throws AccountNotFoundException + { + return false; // updates denied + } + + public boolean createPrincipal(Principal principal, String password) + { + return false; // updates denied + } + + public boolean deletePrincipal(Principal principal) throws AccountNotFoundException + { + return false; // updates denied + } + + private boolean compareCharArray(char[] a, char[] b) + { + boolean equal = false; + if (a.length == b.length) + { + equal = true; + int index = 0; + while (equal && index < a.length) + { + equal = a[index] == b[index]; + index++; + } + } + return equal; + } + + private char[] convertPassword(String password) throws UnsupportedEncodingException + { + byte[] passwdBytes = password.getBytes("utf-8"); + + char[] passwd = new char[passwdBytes.length]; + + int index = 0; + + for (byte b : passwdBytes) + { + passwd[index++] = (char) b; + } + + return passwd; + } + + public Map<String, AuthenticationProviderInitialiser> getMechanisms() { return _saslServers; } + + public List<Principal> getUsers() + { + return null; //todo + } + + public Principal getUser(String username) + { + if (_users.getProperty(username) != null) + { + return new UsernamePrincipal(username); + } + else + { + return null; + } + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabaseManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabaseManager.java index 89c84e8130..6b86a46bd2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabaseManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabaseManager.java @@ -20,6 +20,8 @@ */ package org.apache.qpid.server.security.auth.database; +import org.apache.commons.configuration.Configuration; + import java.util.Map; import java.util.Properties; import java.util.HashMap; @@ -38,4 +40,9 @@ public class PropertiesPrincipalDatabaseManager implements PrincipalDatabaseMana { return _databases; } + + public void initialiseManagement(Configuration config) + { + //todo + } } 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 0546bbb81e..ce5e0cd748 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 @@ -71,7 +71,7 @@ public class PrincipalDatabaseAuthenticationManager implements AuthenticationMan Map<String, Class<? extends SaslServerFactory>> providerMap = new TreeMap<String, Class<? extends SaslServerFactory>>(); - if (name == null) + if (name == null || hostConfig == null) { initialiseAuthenticationMechanisms(providerMap, ApplicationRegistry.getInstance().getDatabaseManager().getDatabases()); } @@ -108,11 +108,15 @@ public class PrincipalDatabaseAuthenticationManager implements AuthenticationMan if (providerMap.size() > 0) { - Security.addProvider(new JCAProvider(providerMap)); + // Ensure we are used before the defaults + if (Security.insertProviderAt(new JCAProvider(providerMap), 1) == -1) + { + _logger.warn("Unable to set order of providers."); + } } else { - _logger.warn("No SASL providers availble."); + _logger.warn("No additional SASL providers registered."); } } @@ -148,21 +152,20 @@ public class PrincipalDatabaseAuthenticationManager implements AuthenticationMan { if (database == null || database.getMechanisms().size() == 0) { - _logger.warn(""); + _logger.warn("No Database or no mechanisms to initialise authentication"); return; } - for (AuthenticationProviderInitialiser mechanism : database.getMechanisms().values()) + for (Map.Entry<String, AuthenticationProviderInitialiser> mechanism : database.getMechanisms().entrySet()) { - initialiseAuthenticationMechanism(mechanism, providerMap); + initialiseAuthenticationMechanism(mechanism.getKey(), mechanism.getValue(), providerMap); } } - private void initialiseAuthenticationMechanism(AuthenticationProviderInitialiser initialiser, + private void initialiseAuthenticationMechanism(String mechanism, AuthenticationProviderInitialiser initialiser, Map<String, Class<? extends SaslServerFactory>> providerMap) throws Exception { - String mechanism = initialiser.getMechanismName(); if (_mechanisms == null) { _mechanisms = mechanism; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/JCAProvider.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/JCAProvider.java index 8ffcdc4e36..fd4ad86055 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/JCAProvider.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/JCAProvider.java @@ -33,7 +33,7 @@ public final class JCAProvider extends Provider super("AMQSASLProvider", 1.0, "A JCA provider that registers all " + "AMQ SASL providers that want to be registered"); register(providerMap); - Security.addProvider(this); + //Security.addProvider(this); } private void register(Map<String, Class<? extends SaslServerFactory>> providerMap) diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePasswordInitialiser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePasswordInitialiser.java index 68095de3a0..dd0bd096c3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePasswordInitialiser.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePasswordInitialiser.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 @@ -33,14 +33,16 @@ import javax.security.auth.login.AccountNotFoundException; import javax.security.sasl.AuthorizeCallback; import org.apache.commons.configuration.Configuration; + import org.apache.log4j.Logger; + import org.apache.qpid.server.security.auth.database.PrincipalDatabase; import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser; import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; public abstract class UsernamePasswordInitialiser implements AuthenticationProviderInitialiser { - protected static final Logger _logger = Logger.getLogger(UsernamePasswordInitialiser.class); + protected static final Logger _logger = Logger.getLogger(UsernamePasswordInitialiser.class); private ServerCallbackHandler _callbackHandler; @@ -72,7 +74,9 @@ public abstract class UsernamePasswordInitialiser implements AuthenticationProvi { // very annoyingly the callback handler does not throw anything more appropriate than // IOException - throw new IOException("Error looking up user " + e); + IOException ioe = new IOException("Error looking up user " + e); + ioe.initCause(e); + throw ioe; } } else if (callback instanceof AuthorizeCallback) @@ -88,7 +92,7 @@ public abstract class UsernamePasswordInitialiser implements AuthenticationProvi } public void initialise(String baseConfigPath, Configuration configuration, - Map<String, PrincipalDatabase> principalDatabases) throws Exception + Map<String, PrincipalDatabase> principalDatabases) throws Exception { String principalDatabaseName = configuration.getString(baseConfigPath + ".principal-database"); PrincipalDatabase db = principalDatabases.get(principalDatabaseName); @@ -102,6 +106,7 @@ public abstract class UsernamePasswordInitialiser implements AuthenticationProvi { throw new NullPointerException("Cannot initialise with a null Principal database."); } + _callbackHandler = new ServerCallbackHandler(db); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePrincipal.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePrincipal.java index f9aaabd15a..d7c8383690 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePrincipal.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePrincipal.java @@ -22,10 +22,7 @@ package org.apache.qpid.server.security.auth.sasl; import java.security.Principal; -/** - * A principal that is just a wrapper for a simple username. - * - */ +/** A principal that is just a wrapper for a simple username. */ public class UsernamePrincipal implements Principal { private String _name; @@ -39,4 +36,9 @@ public class UsernamePrincipal implements Principal { return _name; } + + public String toString() + { + return _name; + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedInitialiser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedInitialiser.java new file mode 100644 index 0000000000..97f9a4e91a --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedInitialiser.java @@ -0,0 +1,50 @@ +/* + * + * 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.security.auth.sasl.crammd5; + +import org.apache.qpid.server.security.auth.sasl.UsernamePasswordInitialiser; +import org.apache.qpid.server.security.auth.database.PrincipalDatabase; + +import javax.security.sasl.SaslServerFactory; +import java.util.Map; + +public class CRAMMD5HashedInitialiser extends UsernamePasswordInitialiser +{ + public String getMechanismName() + { + return CRAMMD5HashedSaslServer.MECHANISM; + } + + public Class<? extends SaslServerFactory> getServerFactoryClassForJCARegistration() + { + return CRAMMD5HashedServerFactory.class; + } + + public void initialise(PrincipalDatabase passwordFile) + { + super.initialise(passwordFile); + } + + public Map<String, ?> getProperties() + { + return null; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedSaslServer.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedSaslServer.java new file mode 100644 index 0000000000..f6cab084ea --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedSaslServer.java @@ -0,0 +1,105 @@ +/* + * 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.security.auth.sasl.crammd5; + +import javax.security.sasl.SaslServer; +import javax.security.sasl.SaslException; +import javax.security.sasl.Sasl; +import javax.security.sasl.SaslServerFactory; +import javax.security.auth.callback.CallbackHandler; +import java.util.Enumeration; +import java.util.Map; + +public class CRAMMD5HashedSaslServer implements SaslServer +{ + public static final String MECHANISM = "CRAM-MD5-HASHED"; + + private SaslServer _realServer; + + public CRAMMD5HashedSaslServer(String mechanism, String protocol, String serverName, Map<String, ?> props, + CallbackHandler cbh) throws SaslException + { + Enumeration factories = Sasl.getSaslServerFactories(); + + while (factories.hasMoreElements()) + { + SaslServerFactory factory = (SaslServerFactory) factories.nextElement(); + + if (factory instanceof CRAMMD5HashedServerFactory) + { + continue; + } + + String[] mechs = factory.getMechanismNames(props); + + for (String mech : mechs) + { + if (mech.equals("CRAM-MD5")) + { + _realServer = factory.createSaslServer("CRAM-MD5", protocol, serverName, props, cbh); + return; + } + } + } + + throw new RuntimeException("No default SaslServer found for mechanism:" + "CRAM-MD5"); + } + + public String getMechanismName() + { + return MECHANISM; + } + + public byte[] evaluateResponse(byte[] response) throws SaslException + { + return _realServer.evaluateResponse(response); + } + + public boolean isComplete() + { + return _realServer.isComplete(); + } + + public String getAuthorizationID() + { + return _realServer.getAuthorizationID(); + } + + public byte[] unwrap(byte[] incoming, int offset, int len) throws SaslException + { + return _realServer.unwrap(incoming, offset, len); + } + + public byte[] wrap(byte[] outgoing, int offset, int len) throws SaslException + { + return _realServer.wrap(outgoing, offset, len); + } + + public Object getNegotiatedProperty(String propName) + { + return _realServer.getNegotiatedProperty(propName); + } + + public void dispose() throws SaslException + { + _realServer.dispose(); + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedServerFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedServerFactory.java new file mode 100644 index 0000000000..5298b5cc63 --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/crammd5/CRAMMD5HashedServerFactory.java @@ -0,0 +1,61 @@ +/* + * + * 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.security.auth.sasl.crammd5; + +import java.util.Map; + +import javax.security.auth.callback.CallbackHandler; +import javax.security.sasl.Sasl; +import javax.security.sasl.SaslException; +import javax.security.sasl.SaslServer; +import javax.security.sasl.SaslServerFactory; + +public class CRAMMD5HashedServerFactory implements SaslServerFactory +{ + public SaslServer createSaslServer(String mechanism, String protocol, String serverName, Map<String, ?> props, + CallbackHandler cbh) throws SaslException + { + if (mechanism.equals(CRAMMD5HashedSaslServer.MECHANISM)) + { + return new CRAMMD5HashedSaslServer(mechanism, protocol, serverName, props, cbh); + } + else + { + return null; + } + } + + public String[] getMechanismNames(Map props) + { + if (props != null) + { + if (props.containsKey(Sasl.POLICY_NOPLAINTEXT) || + props.containsKey(Sasl.POLICY_NODICTIONARY) || + props.containsKey(Sasl.POLICY_NOACTIVE)) + { + // returned array must be non null according to interface documentation + return new String[0]; + } + } + + return new String[]{CRAMMD5HashedSaslServer.MECHANISM}; + } +} diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServerFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServerFactory.java index ff3e87e3a0..f0dd9eeb6d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServerFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/plain/PlainSaslServerFactory.java @@ -29,7 +29,7 @@ import javax.security.sasl.SaslServer; import javax.security.sasl.SaslServerFactory; public class PlainSaslServerFactory implements SaslServerFactory -{ +{ public SaslServer createSaslServer(String mechanism, String protocol, String serverName, Map props, CallbackHandler cbh) throws SaslException { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/CleanupMessageOperation.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/CleanupMessageOperation.java index 05d1cd5291..609a85c22f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/CleanupMessageOperation.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/CleanupMessageOperation.java @@ -56,18 +56,7 @@ public class CleanupMessageOperation implements TxnOp public void commit(StoreContext context) { - //The routers reference can now be released. This is done - //here to ensure that it happens after the queues that - //enqueue it have incremented their counts (which as a - //memory only operation is done in the commit phase). - try - { - _msg.decrementReference(context); - } - catch (AMQException e) - { - _log.error("On commiting transaction, failed to cleanup unused message: " + e, e); - } + try { _msg.checkDeliveredToConsumer(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java index cf0da55f2a..6d776eec0f 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransactionalContext.java @@ -89,6 +89,12 @@ public class LocalTransactionalContext implements TransactionalContext public void rollback() throws AMQException { _txnBuffer.rollback(_storeContext); + // Hack to deal with uncommitted non-transactional writes + if(_messageStore.inTran(_storeContext)) + { + _messageStore.abortTran(_storeContext); + _inTran = false; + } _postCommitDeliveryList.clear(); } @@ -103,6 +109,7 @@ public class LocalTransactionalContext implements TransactionalContext // message.incrementReference(); _postCommitDeliveryList.add(new DeliveryDetails(message, queue, deliverFirst)); _messageDelivered = true; + _txnBuffer.enlist(new CleanupMessageOperation(message, _returnMessages)); /*_txnBuffer.enlist(new DeliverMessageOperation(message, queue)); if (_log.isDebugEnabled()) { @@ -111,7 +118,7 @@ public class LocalTransactionalContext implements TransactionalContext } message.incrementReference(); _messageDelivered = true; - _txnBuffer.enlist(new CleanupMessageOperation(message, _returnMessages)); + */ } @@ -195,6 +202,7 @@ public class LocalTransactionalContext implements TransactionalContext { _txnBuffer.enlist(new StoreMessageOperation(_messageStore)); } + //fixme fail commit here ... QPID-440 try { _txnBuffer.commit(_storeContext); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TxnBuffer.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TxnBuffer.java index 339ca8ae1a..405c233552 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TxnBuffer.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/TxnBuffer.java @@ -41,7 +41,7 @@ public class TxnBuffer { if (_log.isDebugEnabled()) { - _log.debug("Committing " + _ops.size() + " ops to commit.:" + _ops.toArray()); + _log.debug("Committing " + _ops.size() + " ops to commit.:" + _ops); } if (prepare(context)) 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 c24d1aa23a..b5c59dbbb7 100644 --- 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 @@ -181,7 +181,7 @@ public class VirtualHost implements Accessable catch (Exception e)
{
_logger.error("Unable to instantiate configuration class " + instanceType + " - ensure it has a public default constructor");
- throw new IllegalArgumentException("Unable to instantiate configuration class " + instanceType + " - ensure it has a public default constructor");
+ throw new IllegalArgumentException("Unable to instantiate configuration class " + instanceType + " - ensure it has a public default constructor", e);
}
Configurator.configure(instance);
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 index 236291968f..0c1da5c278 100644 --- 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 @@ -106,6 +106,8 @@ public class AMQQueueAlertTest extends TestCase /** * Tests if Queue Depth alert is thrown when queue depth reaches the threshold value * + * Based on FT402 subbmitted by client + * * @throws Exception */ public void testQueueDepthAlertNoSubscriber() throws Exception diff --git a/qpid/java/client/example/src/main/java/org/apache/qpid/example/publisher/FileMessageDispatcher.java b/qpid/java/client/example/src/main/java/org/apache/qpid/example/publisher/FileMessageDispatcher.java index b199d41432..6a7626c51d 100644 --- a/qpid/java/client/example/src/main/java/org/apache/qpid/example/publisher/FileMessageDispatcher.java +++ b/qpid/java/client/example/src/main/java/org/apache/qpid/example/publisher/FileMessageDispatcher.java @@ -1,4 +1,5 @@ /* + * * 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 @@ -6,33 +7,35 @@ * 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.example.publisher; -import org.apache.log4j.Logger; - import java.io.File; +import javax.jms.JMSException; + +import org.apache.log4j.Logger; + import org.apache.qpid.example.shared.FileUtils; import org.apache.qpid.example.shared.Statics; -import javax.jms.JMSException; - /** * Class that sends message files to the Publisher to distribute * using files as input * Must set properties for host in properties file or uses in vm broker */ -public class FileMessageDispatcher { +public class FileMessageDispatcher +{ protected static final Logger _logger = Logger.getLogger(FileMessageDispatcher.class); @@ -48,30 +51,30 @@ public class FileMessageDispatcher { public static void main(String[] args) { - //Check command line args ok - must provide a path or file for us to dispatch + // Check command line args ok - must provide a path or file for us to dispatch if (args.length == 0) { - System.err.println("Usage: FileMessageDispatcher <filesToDispatch>" + ""); + System.out.println("Usage: FileMessageDispatcher <filesToDispatch>" + ""); } else { try { - //publish message(s) from file(s) to configured queue + // publish message(s) from file(s) to configured queue publish(args[0]); - //Move payload file(s) to archive location as no error + // Move payload file(s) to archive location as no error FileUtils.moveFileToNewDir(args[0], System.getProperties().getProperty(Statics.ARCHIVE_PATH)); } - catch(Exception e) + catch (Exception e) { - //log error and exit + // log error and exit _logger.error("Error trying to dispatch message: " + e); System.exit(1); } finally { - //clean up before exiting + // clean up before exiting if (getPublisher() != null) { getPublisher().cleanup(); @@ -98,10 +101,10 @@ public class FileMessageDispatcher { File tempFile = new File(path); if (tempFile.isDirectory()) { - //while more files in dir publish them + // while more files in dir publish them File[] files = tempFile.listFiles(); - if (files == null || files.length == 0) + if ((files == null) || (files.length == 0)) { _logger.info("FileMessageDispatcher - No files to publish in input directory: " + tempFile); } @@ -109,10 +112,10 @@ public class FileMessageDispatcher { { for (File file : files) { - //Create message factory passing in payload path + // Create message factory passing in payload path FileMessageFactory factory = new FileMessageFactory(getPublisher().getSession(), file.toString()); - //Send the message generated from the payload using the _publisher + // Send the message generated from the payload using the _publisher getPublisher().sendMessage(factory.createEventMessage()); } @@ -120,11 +123,11 @@ public class FileMessageDispatcher { } else { - //handle a single file - //Create message factory passing in payload path - FileMessageFactory factory = new FileMessageFactory(getPublisher().getSession(),tempFile.toString()); + // handle a single file + // Create message factory passing in payload path + FileMessageFactory factory = new FileMessageFactory(getPublisher().getSession(), tempFile.toString()); - //Send the message generated from the payload using the _publisher + // Send the message generated from the payload using the _publisher getPublisher().sendMessage(factory.createEventMessage()); } } @@ -145,15 +148,15 @@ public class FileMessageDispatcher { */ private static Publisher getPublisher() { - if (_publisher != null) - { - return _publisher; - } + if (_publisher != null) + { + return _publisher; + } - //Create a _publisher - _publisher = new Publisher(); + // Create a _publisher + _publisher = new Publisher(); - return _publisher; + return _publisher; } } diff --git a/qpid/java/client/example/src/main/java/org/apache/qpid/example/publisher/FileMessageFactory.java b/qpid/java/client/example/src/main/java/org/apache/qpid/example/publisher/FileMessageFactory.java index 88bcbbbccb..f3b21e3c64 100644 --- a/qpid/java/client/example/src/main/java/org/apache/qpid/example/publisher/FileMessageFactory.java +++ b/qpid/java/client/example/src/main/java/org/apache/qpid/example/publisher/FileMessageFactory.java @@ -47,7 +47,9 @@ public class FileMessageFactory } catch (IOException e) { - throw new MessageFactoryException(e.toString()); + MessageFactoryException mfe = new MessageFactoryException(e.toString()); + mfe.initCause(e); + throw mfe; } } diff --git a/qpid/java/client/example/src/main/java/org/apache/qpid/example/shared/InitialContextHelper.java b/qpid/java/client/example/src/main/java/org/apache/qpid/example/shared/InitialContextHelper.java index 8505d1d457..98a2c0d497 100644 --- a/qpid/java/client/example/src/main/java/org/apache/qpid/example/shared/InitialContextHelper.java +++ b/qpid/java/client/example/src/main/java/org/apache/qpid/example/shared/InitialContextHelper.java @@ -59,11 +59,11 @@ public class InitialContextHelper } catch (IOException e) { - throw new ContextException(e.toString()); + throw new ContextException(e.toString(), e); } catch (NamingException n) { - throw new ContextException(n.toString()); + throw new ContextException(n.toString(), n); } } diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnection.java b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnection.java index 413524b6d8..0e3d99eeba 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnection.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnection.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,29 @@ */ package org.apache.qpid.client; +import java.io.IOException; +import java.net.ConnectException; +import java.nio.channels.UnresolvedAddressException; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.Map; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +import javax.jms.*; +import javax.jms.IllegalStateException; +import javax.naming.NamingException; +import javax.naming.Reference; +import javax.naming.Referenceable; +import javax.naming.StringRefAddr; + +import org.apache.log4j.Logger; + import org.apache.qpid.AMQConnectionFailureException; import org.apache.qpid.AMQException; import org.apache.qpid.AMQUndeliveredException; @@ -44,28 +67,6 @@ import org.apache.qpid.jms.ConnectionURL; import org.apache.qpid.jms.FailoverPolicy; import org.apache.qpid.url.URLSyntaxException; -import org.apache.log4j.Logger; - -import javax.jms.*; -import javax.jms.IllegalStateException; -import javax.naming.NamingException; -import javax.naming.Reference; -import javax.naming.Referenceable; -import javax.naming.StringRefAddr; -import java.io.IOException; -import java.net.ConnectException; -import java.nio.channels.UnresolvedAddressException; -import java.text.MessageFormat; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.LinkedList; -import java.util.Map; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.Executors; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.TimeUnit; - public class AMQConnection extends Closeable implements Connection, QueueConnection, TopicConnection, Referenceable { private static final Logger _logger = Logger.getLogger(AMQConnection.class); @@ -95,7 +96,7 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect private AMQProtocolHandler _protocolHandler; /** Maps from session id (Integer) to AMQSession instance */ - private final Map _sessions = new LinkedHashMap(); //fixme this is map is replicated in amqprotocolsession as _channelId2SessionMap + private final Map _sessions = new LinkedHashMap(); // fixme this is map is replicated in amqprotocolsession as _channelId2SessionMap private String _clientName; @@ -125,15 +126,14 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect /* * _Connected should be refactored with a suitable wait object. - */ + */ private boolean _connected; /* * The last error code that occured on the connection. Used to return the correct exception to the client - */ + */ private AMQException _lastAMQException = null; - /* * The connection meta data */ @@ -149,6 +149,7 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect /** Thread Pool for executing connection level processes. Such as returning bounced messages. */ private final ExecutorService _taskPool = Executors.newCachedThreadPool(); + private static final long DEFAULT_TIMEOUT = 1000 * 30; /** * @param broker brokerdetails @@ -160,13 +161,13 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect * @throws AMQException * @throws URLSyntaxException */ - public AMQConnection(String broker, String username, String password, - String clientName, String virtualHost) throws AMQException, URLSyntaxException + public AMQConnection(String broker, String username, String password, String clientName, String virtualHost) + throws AMQException, URLSyntaxException { - this(new AMQConnectionURL(ConnectionURL.AMQ_PROTOCOL + "://" + - username + ":" + password + "@" + - (clientName == null ? "" : clientName) + "/" + - virtualHost + "?brokerlist='" + AMQBrokerDetails.checkTransport(broker) + "'"), null); + this(new AMQConnectionURL( + ConnectionURL.AMQ_PROTOCOL + "://" + username + ":" + password + "@" + + ((clientName == null) ? "" : clientName) + "/" + virtualHost + "?brokerlist='" + + AMQBrokerDetails.checkTransport(broker) + "'"), null); } /** @@ -179,44 +180,38 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect * @throws AMQException * @throws URLSyntaxException */ - public AMQConnection(String broker, String username, String password, - String clientName, String virtualHost, SSLConfiguration sslConfig) throws AMQException, URLSyntaxException + public AMQConnection(String broker, String username, String password, String clientName, String virtualHost, + SSLConfiguration sslConfig) throws AMQException, URLSyntaxException { - this(new AMQConnectionURL(ConnectionURL.AMQ_PROTOCOL + "://" + - username + ":" + password + "@" + - (clientName == null ? "" : clientName) + "/" + - virtualHost + "?brokerlist='" + AMQBrokerDetails.checkTransport(broker) + "'"), sslConfig); + this(new AMQConnectionURL( + ConnectionURL.AMQ_PROTOCOL + "://" + username + ":" + password + "@" + + ((clientName == null) ? "" : clientName) + "/" + virtualHost + "?brokerlist='" + + AMQBrokerDetails.checkTransport(broker) + "'"), sslConfig); } - - public AMQConnection(String host, int port, String username, String password, - String clientName, String virtualHost) throws AMQException, URLSyntaxException + public AMQConnection(String host, int port, String username, String password, String clientName, String virtualHost) + throws AMQException, URLSyntaxException { this(host, port, false, username, password, clientName, virtualHost, null); } - public AMQConnection(String host, int port, String username, String password, - String clientName, String virtualHost, SSLConfiguration sslConfig) throws AMQException, URLSyntaxException + public AMQConnection(String host, int port, String username, String password, String clientName, String virtualHost, + SSLConfiguration sslConfig) throws AMQException, URLSyntaxException { this(host, port, false, username, password, clientName, virtualHost, sslConfig); } - - public AMQConnection(String host, int port, boolean useSSL, String username, String password, - String clientName, String virtualHost, SSLConfiguration sslConfig) throws AMQException, URLSyntaxException + public AMQConnection(String host, int port, boolean useSSL, String username, String password, String clientName, + String virtualHost, SSLConfiguration sslConfig) throws AMQException, URLSyntaxException { - this(new AMQConnectionURL(useSSL ? - ConnectionURL.AMQ_PROTOCOL + "://" + - username + ":" + password + "@" + - (clientName == null ? "" : clientName) + - virtualHost + "?brokerlist='tcp://" + host + ":" + port + "'" - + "," + ConnectionURL.OPTIONS_SSL + "='true'" : - ConnectionURL.AMQ_PROTOCOL + "://" + - username + ":" + password + "@" + - (clientName == null ? "" : clientName) + - virtualHost + "?brokerlist='tcp://" + host + ":" + port + "'" - + "," + ConnectionURL.OPTIONS_SSL + "='false'" - ), sslConfig); + this(new AMQConnectionURL( + useSSL + ? (ConnectionURL.AMQ_PROTOCOL + "://" + username + ":" + password + "@" + + ((clientName == null) ? "" : clientName) + virtualHost + "?brokerlist='tcp://" + host + ":" + port + + "'" + "," + ConnectionURL.OPTIONS_SSL + "='true'") + : (ConnectionURL.AMQ_PROTOCOL + "://" + username + ":" + password + "@" + + ((clientName == null) ? "" : clientName) + virtualHost + "?brokerlist='tcp://" + host + ":" + port + + "'" + "," + ConnectionURL.OPTIONS_SSL + "='false'")), sslConfig); } public AMQConnection(String connection) throws AMQException, URLSyntaxException @@ -229,13 +224,13 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect this(new AMQConnectionURL(connection), sslConfig); } - public AMQConnection(ConnectionURL connectionURL, SSLConfiguration sslConfig) throws AMQException { if (_logger.isInfoEnabled()) { _logger.info("Connection:" + connectionURL); } + _sslConfiguration = sslConfig; if (connectionURL == null) { @@ -249,7 +244,6 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect _password = connectionURL.getPassword(); setVirtualHost(connectionURL.getVirtualHost()); - if (connectionURL.getDefaultQueueExchangeName() != null) { _defaultQueueExchangeName = connectionURL.getDefaultQueueExchangeName(); @@ -270,7 +264,6 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect _temporaryTopicExchangeName = connectionURL.getTemporaryTopicExchangeName(); } - _failoverPolicy = new FailoverPolicy(connectionURL); _protocolHandler = new AMQProtocolHandler(this); @@ -278,7 +271,6 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect // We are not currently connected _connected = false; - Exception lastException = new Exception(); lastException.initCause(new ConnectException()); @@ -296,7 +288,8 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect if (_logger.isInfoEnabled()) { - _logger.info("Unable to connect to broker at " + _failoverPolicy.getCurrentBrokerDetails(), e.getCause()); + _logger.info("Unable to connect to broker at " + _failoverPolicy.getCurrentBrokerDetails(), + e.getCause()); } } } @@ -322,7 +315,7 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect } } - if (message == null || message.equals("")) + if ((message == null) || message.equals("")) { message = "Unable to Connect"; } @@ -335,11 +328,13 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect { e = new AMQUnresolvedAddressException(message, _failoverPolicy.getCurrentBrokerDetails().toString()); } + e.initCause(lastException); } throw e; } + _connectionMetaData = new QpidConnectionMetaData(this); } @@ -369,6 +364,7 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect { virtualHost = virtualHost.substring(1); } + _virtualHost = virtualHost; } @@ -382,7 +378,7 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect _protocolHandler.attainState(AMQState.CONNECTION_OPEN); _failoverPolicy.attainedConnection(); - //Again this should be changed to a suitable notify + // Again this should be changed to a suitable notify _connected = true; } catch (AMQException e) @@ -401,6 +397,7 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect try { makeBrokerConnection(bd); + return true; } catch (Exception e) @@ -409,8 +406,10 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect { _logger.info("Unable to connect to broker at " + bd); } + attemptReconnection(); } + return false; } @@ -421,6 +420,7 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect try { makeBrokerConnection(_failoverPolicy.getNextBrokerDetails()); + return true; } catch (Exception e) @@ -436,13 +436,14 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect { if (_logger.isInfoEnabled()) { - _logger.info(e.getMessage() + ":Unable to connect to broker at " + _failoverPolicy.getCurrentBrokerDetails()); + _logger.info(e.getMessage() + ":Unable to connect to broker at " + + _failoverPolicy.getCurrentBrokerDetails()); } } } } - //connection unsuccessful + // connection unsuccessful return false; } @@ -474,14 +475,14 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect return createSession(transacted, acknowledgeMode, AMQSession.DEFAULT_PREFETCH_HIGH_MARK); } - public org.apache.qpid.jms.Session createSession(final boolean transacted, final int acknowledgeMode, - final int prefetch) throws JMSException + public org.apache.qpid.jms.Session createSession(final boolean transacted, final int acknowledgeMode, final int prefetch) + throws JMSException { return createSession(transacted, acknowledgeMode, prefetch, prefetch); } public org.apache.qpid.jms.Session createSession(final boolean transacted, final int acknowledgeMode, - final int prefetchHigh, final int prefetchLow) throws JMSException + final int prefetchHigh, final int prefetchLow) throws JMSException { checkNotClosed(); if (channelLimitReached()) @@ -491,85 +492,81 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect else { return (org.apache.qpid.jms.Session) new FailoverSupport() - { - public Object operation() throws JMSException - { - int channelId = _idFactory.incrementAndGet(); - - if (_logger.isDebugEnabled()) - { - _logger.debug("Write channel open frame for channel id " + channelId); - } - - // We must create the session and register it before actually sending the frame to the server to - // open it, so that there is no window where we could receive data on the channel and not be set - // up to handle it appropriately. - AMQSession session = new AMQSession(AMQConnection.this, channelId, transacted, acknowledgeMode, - prefetchHigh, prefetchLow); - _protocolHandler.addSessionByChannel(channelId, session); - registerSession(channelId, session); - - boolean success = false; - try - { - createChannelOverWire(channelId, prefetchHigh, prefetchLow, transacted); - success = true; - } - catch (AMQException e) - { - JMSException jmse = new JMSException("Error creating session: " + e); - jmse.setLinkedException(e); - throw jmse; - } - finally - { - if (!success) - { - _protocolHandler.removeSessionByChannel(channelId); - deregisterSession(channelId); - } - } - - if (_started) { - try - { - session.start(); - } - catch (AMQException e) + public Object operation() throws JMSException { - throw new JMSAMQException(e); + int channelId = _idFactory.incrementAndGet(); + + if (_logger.isDebugEnabled()) + { + _logger.debug("Write channel open frame for channel id " + channelId); + } + + // We must create the session and register it before actually sending the frame to the server to + // open it, so that there is no window where we could receive data on the channel and not be set + // up to handle it appropriately. + AMQSession session = + new AMQSession(AMQConnection.this, channelId, transacted, acknowledgeMode, prefetchHigh, + prefetchLow); + _protocolHandler.addSessionByChannel(channelId, session); + registerSession(channelId, session); + + boolean success = false; + try + { + createChannelOverWire(channelId, prefetchHigh, prefetchLow, transacted); + success = true; + } + catch (AMQException e) + { + JMSException jmse = new JMSException("Error creating session: " + e); + jmse.setLinkedException(e); + throw jmse; + } + finally + { + if (!success) + { + _protocolHandler.removeSessionByChannel(channelId); + deregisterSession(channelId); + } + } + + if (_started) + { + try + { + session.start(); + } + catch (AMQException e) + { + throw new JMSAMQException(e); + } + } + + return session; } - } - return session; - } - }.execute(this); + }.execute(this); } } private void createChannelOverWire(int channelId, int prefetchHigh, int prefetchLow, boolean transacted) - throws AMQException + throws AMQException { // TODO: Be aware of possible changes to parameter order as versions change. - _protocolHandler.syncWrite( - ChannelOpenBody.createAMQFrame(channelId, - _protocolHandler.getProtocolMajorVersion(), - _protocolHandler.getProtocolMinorVersion(), - null), // outOfBand - ChannelOpenOkBody.class); - - //todo send low water mark when protocol allows. - //todo Be aware of possible changes to parameter order as versions change. - _protocolHandler.syncWrite( - BasicQosBody.createAMQFrame(channelId, - _protocolHandler.getProtocolMajorVersion(), - _protocolHandler.getProtocolMinorVersion(), - false, // global - prefetchHigh, // prefetchCount - 0), // prefetchSize - BasicQosOkBody.class); + _protocolHandler.syncWrite(ChannelOpenBody.createAMQFrame(channelId, _protocolHandler.getProtocolMajorVersion(), + _protocolHandler.getProtocolMinorVersion(), null), // outOfBand + ChannelOpenOkBody.class); + + // todo send low water mark when protocol allows. + // todo Be aware of possible changes to parameter order as versions change. + _protocolHandler.syncWrite(BasicQosBody.createAMQFrame(channelId, _protocolHandler.getProtocolMajorVersion(), + _protocolHandler.getProtocolMinorVersion(), false, // global + prefetchHigh, // prefetchCount + 0), // prefetchSize + BasicQosOkBody.class); if (transacted) { @@ -579,10 +576,8 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect } // TODO: Be aware of possible changes to parameter order as versions change. - _protocolHandler.syncWrite(TxSelectBody.createAMQFrame(channelId, - _protocolHandler.getProtocolMajorVersion(), - _protocolHandler.getProtocolMinorVersion()), - TxSelectOkBody.class); + _protocolHandler.syncWrite(TxSelectBody.createAMQFrame(channelId, _protocolHandler.getProtocolMajorVersion(), + _protocolHandler.getProtocolMinorVersion()), TxSelectOkBody.class); } } @@ -596,11 +591,10 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect { _protocolHandler.removeSessionByChannel(channelId); deregisterSession(channelId); - throw new AMQException("Error reopening channel " + channelId + " after failover: " + e); + throw new AMQException("Error reopening channel " + channelId + " after failover: " + e, e); } } - public void setFailoverPolicy(FailoverPolicy policy) { _failoverPolicy = policy; @@ -645,12 +639,13 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect private boolean channelLimitReached() { - return _maximumChannelCount != 0 && _sessions.size() == _maximumChannelCount; + return (_maximumChannelCount != 0) && (_sessions.size() == _maximumChannelCount); } public String getClientID() throws JMSException { checkNotClosed(); + return _clientName; } @@ -666,6 +661,7 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect public ConnectionMetaData getMetaData() throws JMSException { checkNotClosed(); + return _connectionMetaData; } @@ -673,6 +669,7 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect public ExceptionListener getExceptionListener() throws JMSException { checkNotClosed(); + return _exceptionListener; } @@ -706,6 +703,7 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect throw new JMSAMQException(e); } } + _started = true; } } @@ -726,13 +724,14 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect throw new JMSAMQException(e); } } + _started = false; } } public void close() throws JMSException { - close(-1); + close(DEFAULT_TIMEOUT); } public void close(long timeout) throws JMSException @@ -752,7 +751,7 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect { try { - //adjust timeout + // adjust timeout long taskPoolTimeout = adjustTimeout(timeout, startCloseTime); _taskPool.awaitTermination(taskPoolTimeout, TimeUnit.MILLISECONDS); @@ -763,7 +762,7 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect } } - //adjust timeout + // adjust timeout timeout = adjustTimeout(timeout, startCloseTime); _protocolHandler.closeConnection(timeout); @@ -771,7 +770,9 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect } catch (AMQException e) { - throw new JMSException("Error closing connection: " + e); + JMSException jmse = new JMSException("Error closing connection: " + e); + jmse.setLinkedException(e); + throw jmse; } } } @@ -785,6 +786,7 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect { timeout = 0; } + return timeout; } @@ -803,6 +805,7 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect session.markClosed(); } + _sessions.clear(); } @@ -842,6 +845,7 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect } } } + _sessions.clear(); if (sessionException != null) { @@ -850,42 +854,42 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect } public ConnectionConsumer createConnectionConsumer(Destination destination, String messageSelector, - ServerSessionPool sessionPool, - int maxMessages) throws JMSException + ServerSessionPool sessionPool, int maxMessages) throws JMSException { checkNotClosed(); + return null; } - public ConnectionConsumer createConnectionConsumer(Queue queue, String messageSelector, - ServerSessionPool sessionPool, - int maxMessages) throws JMSException + public ConnectionConsumer createConnectionConsumer(Queue queue, String messageSelector, ServerSessionPool sessionPool, + int maxMessages) throws JMSException { checkNotClosed(); + return null; } - public ConnectionConsumer createConnectionConsumer(Topic topic, String messageSelector, - ServerSessionPool sessionPool, - int maxMessages) throws JMSException + public ConnectionConsumer createConnectionConsumer(Topic topic, String messageSelector, ServerSessionPool sessionPool, + int maxMessages) throws JMSException { checkNotClosed(); + return null; } - public ConnectionConsumer createDurableConnectionConsumer(Topic topic, String subscriptionName, - String messageSelector, ServerSessionPool sessionPool, - int maxMessages) - throws JMSException + public ConnectionConsumer createDurableConnectionConsumer(Topic topic, String subscriptionName, String messageSelector, + ServerSessionPool sessionPool, int maxMessages) throws JMSException { // TODO Auto-generated method stub checkNotClosed(); + return null; } public long getMaximumChannelCount() throws JMSException { checkNotClosed(); + return _maximumChannelCount; } @@ -974,6 +978,7 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect { proceed = _connectionListener.preFailover(redirect); } + return proceed; } @@ -994,6 +999,7 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect { markAllSessionsClosed(); } + return resubscribe; } else @@ -1057,12 +1063,15 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect { if (cause instanceof AMQException) { - je = new JMSException(Integer.toString(((AMQException) cause).getErrorCode().getCode()), "Exception thrown against " + toString() + ": " + cause); + je = + new JMSException(Integer.toString(((AMQException) cause).getErrorCode().getCode()), + "Exception thrown against " + toString() + ": " + cause); } else { je = new JMSException("Exception thrown against " + toString() + ": " + cause); } + if (cause instanceof Exception) { je.setLinkedException((Exception) cause); @@ -1090,6 +1099,7 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect { _logger.info("Closing AMQConnection due to :" + cause.getMessage()); } + _closed.set(true); closeAllSessions(cause, -1, -1); // FIXME: when doing this end up with RejectedExecutionException from executor. } @@ -1145,9 +1155,11 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect buf.append("Host: ").append(String.valueOf(bd.getHost())); buf.append("\nPort: ").append(String.valueOf(bd.getPort())); } + buf.append("\nVirtual Host: ").append(String.valueOf(_virtualHost)); buf.append("\nClient ID: ").append(String.valueOf(_clientName)); - buf.append("\nActive session count: ").append(_sessions == null ? 0 : _sessions.size()); + buf.append("\nActive session count: ").append((_sessions == null) ? 0 : _sessions.size()); + return buf.toString(); } @@ -1158,11 +1170,8 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect public Reference getReference() throws NamingException { - return new Reference( - AMQConnection.class.getName(), - new StringRefAddr(AMQConnection.class.getName(), toURL()), - AMQConnectionFactory.class.getName(), - null); // factory location + return new Reference(AMQConnection.class.getName(), new StringRefAddr(AMQConnection.class.getName(), toURL()), + AMQConnectionFactory.class.getName(), null); // factory location } public SSLConfiguration getSSLConfiguration() @@ -1175,19 +1184,16 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect return _defaultTopicExchangeName; } - public void setDefaultTopicExchangeName(AMQShortString defaultTopicExchangeName) { _defaultTopicExchangeName = defaultTopicExchangeName; } - public AMQShortString getDefaultQueueExchangeName() { return _defaultQueueExchangeName; } - public void setDefaultQueueExchangeName(AMQShortString defaultQueueExchangeName) { _defaultQueueExchangeName = defaultQueueExchangeName; @@ -1200,10 +1206,9 @@ public class AMQConnection extends Closeable implements Connection, QueueConnect public AMQShortString getTemporaryQueueExchangeName() { - return _temporaryQueueExchangeName; //To change body of created methods use File | Settings | File Templates. + return _temporaryQueueExchangeName; // To change body of created methods use File | Settings | File Templates. } - public void setTemporaryTopicExchangeName(AMQShortString temporaryTopicExchangeName) { _temporaryTopicExchangeName = temporaryTopicExchangeName; diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionURL.java b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionURL.java index 0dcc544ea8..b3fbd1f510 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionURL.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionURL.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,12 +20,6 @@ */ package org.apache.qpid.client; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.jms.BrokerDetails; -import org.apache.qpid.jms.ConnectionURL; -import org.apache.qpid.url.URLHelper; -import org.apache.qpid.url.URLSyntaxException; - import java.net.URI; import java.net.URISyntaxException; import java.util.HashMap; @@ -33,6 +27,12 @@ import java.util.LinkedList; import java.util.List; import java.util.StringTokenizer; +import org.apache.qpid.framing.AMQShortString; +import org.apache.qpid.jms.BrokerDetails; +import org.apache.qpid.jms.ConnectionURL; +import org.apache.qpid.url.URLHelper; +import org.apache.qpid.url.URLSyntaxException; + public class AMQConnectionURL implements ConnectionURL { private String _url; @@ -49,7 +49,6 @@ public class AMQConnectionURL implements ConnectionURL private AMQShortString _temporaryTopicExchangeName; private AMQShortString _temporaryQueueExchangeName; - public AMQConnectionURL(String fullURL) throws URLSyntaxException { _url = fullURL; @@ -58,18 +57,18 @@ public class AMQConnectionURL implements ConnectionURL _failoverOptions = new HashMap<String, String>(); // Connection URL format - //amqp://[user:pass@][clientid]/virtualhost?brokerlist='tcp://host:port?option=\'value\',option=\'value\';vm://:3/virtualpath?option=\'value\'',failover='method?option=\'value\',option='value''" + // amqp://[user:pass@][clientid]/virtualhost?brokerlist='tcp://host:port?option=\'value\',option=\'value\';vm://:3/virtualpath?option=\'value\'',failover='method?option=\'value\',option='value''" // Options are of course optional except for requiring a single broker in the broker list. try { URI connection = new URI(fullURL); - if (connection.getScheme() == null || !(connection.getScheme().equalsIgnoreCase(AMQ_PROTOCOL))) + if ((connection.getScheme() == null) || !(connection.getScheme().equalsIgnoreCase(AMQ_PROTOCOL))) { throw new URISyntaxException(fullURL, "Not an AMQP URL"); } - if (connection.getHost() == null || connection.getHost().equals("")) + if ((connection.getHost() == null) || connection.getHost().equals("")) { String uid = AMQConnectionFactory.getUniqueClientID(); if (uid == null) @@ -91,7 +90,7 @@ public class AMQConnectionURL implements ConnectionURL if (userInfo == null) { - //Fix for Java 1.5 which doesn't parse UserInfo for non http URIs + // Fix for Java 1.5 which doesn't parse UserInfo for non http URIs userInfo = connection.getAuthority(); if (userInfo != null) @@ -112,16 +111,16 @@ public class AMQConnectionURL implements ConnectionURL if (userInfo == null) { - throw URLHelper.parseError(AMQ_PROTOCOL.length() + 3, - "User information not found on url", fullURL); + throw URLHelper.parseError(AMQ_PROTOCOL.length() + 3, "User information not found on url", fullURL); } else { parseUserInfo(userInfo); } + String virtualHost = connection.getPath(); - if (virtualHost != null && (!virtualHost.equals(""))) + if ((virtualHost != null) && (!virtualHost.equals(""))) { setVirtualHost(virtualHost); } @@ -130,7 +129,7 @@ public class AMQConnectionURL implements ConnectionURL int authLength = connection.getAuthority().length(); int start = AMQ_PROTOCOL.length() + 3; int testIndex = start + authLength; - if (testIndex < fullURL.length() && fullURL.charAt(testIndex) == '?') + if ((testIndex < fullURL.length()) && (fullURL.charAt(testIndex) == '?')) { throw URLHelper.parseError(start, testIndex - start, "Virtual host found", fullURL); } @@ -141,14 +140,9 @@ public class AMQConnectionURL implements ConnectionURL } - URLHelper.parseOptions(_options, connection.getQuery()); processOptions(); - - //Fragment is #string (not used) - //System.out.println(connection.getFragment()); - } catch (URISyntaxException uris) { @@ -165,11 +159,10 @@ public class AMQConnectionURL implements ConnectionURL } else { - if (slash != 0 && fullURL.charAt(slash - 1) == ':') + if ((slash != 0) && (fullURL.charAt(slash - 1) == ':')) { throw URLHelper.parseError(slash - 2, fullURL.indexOf('?') - slash + 2, - "Virtual host looks like a windows path, forward slash not allowed in URL", - fullURL); + "Virtual host looks like a windows path, forward slash not allowed in URL", fullURL); } else { @@ -182,14 +175,14 @@ public class AMQConnectionURL implements ConnectionURL private void parseUserInfo(String userinfo) throws URLSyntaxException { - //user info = user:pass + // user info = user:pass int colonIndex = userinfo.indexOf(':'); if (colonIndex == -1) { throw URLHelper.parseError(AMQ_PROTOCOL.length() + 3, userinfo.length(), - "Null password in user information not allowed.", _url); + "Null password in user information not allowed.", _url); } else { @@ -205,7 +198,7 @@ public class AMQConnectionURL implements ConnectionURL { String brokerlist = _options.get(OPTIONS_BROKERLIST); - //brokerlist tcp://host:port?option='value',option='value';vm://:3/virtualpath?option='value' + // brokerlist tcp://host:port?option='value',option='value';vm://:3/virtualpath?option='value' StringTokenizer st = new StringTokenizer(brokerlist, "" + URLHelper.BROKER_SEPARATOR); while (st.hasMoreTokens()) @@ -244,19 +237,16 @@ public class AMQConnectionURL implements ConnectionURL _defaultTopicExchangeName = new AMQShortString(_options.get(OPTIONS_DEFAULT_TOPIC_EXCHANGE)); } - if (_options.containsKey(OPTIONS_DEFAULT_QUEUE_EXCHANGE)) { _defaultQueueExchangeName = new AMQShortString(_options.get(OPTIONS_DEFAULT_QUEUE_EXCHANGE)); } - if (_options.containsKey(OPTIONS_TEMPORARY_QUEUE_EXCHANGE)) { _temporaryQueueExchangeName = new AMQShortString(_options.get(OPTIONS_TEMPORARY_QUEUE_EXCHANGE)); } - if (_options.containsKey(OPTIONS_TEMPORARY_TOPIC_EXCHANGE)) { _temporaryTopicExchangeName = new AMQShortString(_options.get(OPTIONS_TEMPORARY_TOPIC_EXCHANGE)); @@ -439,12 +429,11 @@ public class AMQConnectionURL implements ConnectionURL return sb.toString(); } - public static void main(String[] args) throws URLSyntaxException { - - String url2 = "amqp://ritchiem:bob@temp?brokerlist='tcp://localhost:5672;jcp://fancyserver:3000/',failover='roundrobin'"; - //"amqp://user:pass@clientid/virtualhost?brokerlist='tcp://host:1?option1=\'value\',option2=\'value\';vm://:3?option1=\'value\'',failover='method?option1=\'value\',option2='value''"; + String url2 = + "amqp://ritchiem:bob@temp?brokerlist='tcp://localhost:5672;jcp://fancyserver:3000/',failover='roundrobin'"; + // "amqp://user:pass@clientid/virtualhost?brokerlist='tcp://host:1?option1=\'value\',option2=\'value\';vm://:3?option1=\'value\'',failover='method?option1=\'value\',option2='value''"; ConnectionURL connectionurl2 = new AMQConnectionURL(url2); @@ -452,5 +441,4 @@ public class AMQConnectionURL implements ConnectionURL System.out.println(connectionurl2); } - } diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQDestination.java b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQDestination.java index 661372845a..585991d905 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQDestination.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQDestination.java @@ -53,6 +53,8 @@ public abstract class AMQDestination implements Destination, Referenceable private String _url; private AMQShortString _urlAsShortString; + private boolean _validated; + private byte[] _byteEncoding; private static final int IS_DURABLE_MASK = 0x1; private static final int IS_EXCLUSIVE_MASK = 0x2; @@ -198,12 +200,16 @@ public abstract class AMQDestination implements Destination, Referenceable { return toURL(); - /* - return "Destination: " + _destinationName + ", " + - "Queue Name: " + _queueName + ", Exchange: " + _exchangeName + - ", Exchange class: " + _exchangeClass + ", Exclusive: " + _isExclusive + - ", AutoDelete: " + _isAutoDelete + ", Routing Key: " + getRoutingKey(); - */ + } + + public boolean isValidated() + { + return _validated; + } + + public void setValidated(boolean validated) + { + _validated = validated; } public String toURL() @@ -348,15 +354,7 @@ public abstract class AMQDestination implements Destination, Referenceable { return false; } - /* if (_isExclusive != that._isExclusive) - { - return false; - } - if (_isAutoDelete != that._isAutoDelete) - { - return false; - } - */ + return true; } @@ -370,8 +368,7 @@ public abstract class AMQDestination implements Destination, Referenceable { result = 29 * result + _queueName.hashCode(); } -// result = result * (_isExclusive ? 13 : 7); -// result = result * (_isAutoDelete ? 13 : 7); + return result; } diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession.java b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession.java index 82f9a036d2..8bb5b622f7 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession.java @@ -202,6 +202,7 @@ public class AMQSession extends Closeable implements Session, QueueSession, Topi /** Responsible for decoding a message fragment and passing it to the appropriate message consumer. */ private static final Logger _dispatcherLogger = Logger.getLogger(Dispatcher.class); + private AtomicBoolean _firstDispatcher = new AtomicBoolean(true); private class Dispatcher extends Thread { @@ -327,8 +328,11 @@ public class AMQSession extends Closeable implements Session, QueueSession, Topi ") is closed rejecting(requeue)..."); } } - - rejectMessage(message, true); + // Don't reject if we're already closing + if (!_closed.get()) + { + rejectMessage(message, true); + } } else { @@ -995,42 +999,42 @@ public class AMQSession extends Closeable implements Session, QueueSession, Topi throw new java.lang.UnsupportedOperationException(); } - public MessageProducer createProducer(Destination destination, boolean mandatory, - boolean immediate, boolean waitUntilSent) + public BasicMessageProducer createProducer(Destination destination, boolean mandatory, + boolean immediate, boolean waitUntilSent) throws JMSException { return createProducerImpl(destination, mandatory, immediate, waitUntilSent); } - public MessageProducer createProducer(Destination destination, boolean mandatory, boolean immediate) + public BasicMessageProducer createProducer(Destination destination, boolean mandatory, boolean immediate) throws JMSException { return createProducerImpl(destination, mandatory, immediate); } - public MessageProducer createProducer(Destination destination, boolean immediate) + public BasicMessageProducer createProducer(Destination destination, boolean immediate) throws JMSException { return createProducerImpl(destination, DEFAULT_MANDATORY, immediate); } - public MessageProducer createProducer(Destination destination) throws JMSException + public BasicMessageProducer createProducer(Destination destination) throws JMSException { return createProducerImpl(destination, DEFAULT_MANDATORY, DEFAULT_IMMEDIATE); } - private org.apache.qpid.jms.MessageProducer createProducerImpl(Destination destination, boolean mandatory, - boolean immediate) + private BasicMessageProducer createProducerImpl(Destination destination, boolean mandatory, + boolean immediate) throws JMSException { return createProducerImpl(destination, mandatory, immediate, false); } - private org.apache.qpid.jms.MessageProducer createProducerImpl(final Destination destination, final boolean mandatory, - final boolean immediate, final boolean waitUntilSent) + private BasicMessageProducer createProducerImpl(final Destination destination, final boolean mandatory, + final boolean immediate, final boolean waitUntilSent) throws JMSException { - return (org.apache.qpid.jms.MessageProducer) new FailoverSupport() + return (BasicMessageProducer) new FailoverSupport() { public Object operation() throws JMSException { @@ -1248,8 +1252,10 @@ public class AMQSession extends Closeable implements Session, QueueSession, Topi { JMSException ex = new JMSException("Error registering consumer: " + e); - //todo remove - e.printStackTrace(); + if (_logger.isDebugEnabled()) + { + e.printStackTrace(); + } ex.setLinkedException(e); throw ex; } @@ -1926,6 +1932,24 @@ public class AMQSession extends Closeable implements Session, QueueSession, Topi synchronized void startDistpatcherIfNecessary() { + if (Boolean.parseBoolean(System.getProperties().getProperty("REGISTER_CONSUMERS_FLOWED", "false"))) + { +// if (!connectionStopped) + { + if (isSuspended() && _firstDispatcher.getAndSet(false)) + { + try + { + suspendChannel(false); + } + catch (AMQException e) + { + _logger.info("Suspending channel threw an exception:" + e); + } + } + } + } + startDistpatcherIfNecessary(false); } @@ -1974,6 +1998,27 @@ public class AMQSession extends Closeable implements Session, QueueSession, Topi bindQueue(amqd, queueName, protocolHandler, consumer.getRawSelectorFieldTable()); + // The dispatcher will be null if we have just created this session + // so suspend the channel before we register our consumer so that we don't + // start prefetching until a receive/mListener is set. + if (Boolean.parseBoolean(System.getProperties().getProperty("REGISTER_CONSUMERS_FLOWED", "false"))) + { + if (_dispatcher == null) + { + if (!isSuspended()) + { + try + { + suspendChannel(true); + } + catch (AMQException e) + { + _logger.info("Suspending channel threw an exception:" + e); + } + } + } + } + try { consumeFromQueue(consumer, queueName, protocolHandler, nowait, consumer.getMessageSelector()); @@ -2089,7 +2134,7 @@ public class AMQSession extends Closeable implements Session, QueueSession, Topi // Remove the consumer from the map BasicMessageConsumer consumer = (BasicMessageConsumer) _consumers.get(consumerTag); if (consumer != null) - { + { // fixme this isn't right.. needs to check if _queue contains data for this consumer if (consumer.isAutoClose())// && _queue.isEmpty()) { diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer.java b/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer.java index 73010ce517..1c3cdbcb65 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer.java @@ -20,9 +20,9 @@ */ package org.apache.qpid.client; +import java.util.Arrays; import java.util.Iterator; import java.util.List; -import java.util.Arrays; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.TimeUnit; @@ -34,6 +34,7 @@ import javax.jms.Message; import javax.jms.MessageListener; import org.apache.log4j.Logger; + import org.apache.qpid.AMQException; import org.apache.qpid.client.message.AbstractJMSMessage; import org.apache.qpid.client.message.MessageFactoryRegistry; @@ -138,10 +139,10 @@ public class BasicMessageConsumer extends Closeable implements MessageConsumer private boolean _noConsume; private List<StackTraceElement> _closedStack = null; - protected BasicMessageConsumer(int channelId, AMQConnection connection, AMQDestination destination, String messageSelector, - boolean noLocal, MessageFactoryRegistry messageFactory, AMQSession session, - AMQProtocolHandler protocolHandler, FieldTable rawSelectorFieldTable, - int prefetchHigh, int prefetchLow, boolean exclusive, int acknowledgeMode, boolean noConsume, boolean autoClose) + protected BasicMessageConsumer(int channelId, AMQConnection connection, AMQDestination destination, + String messageSelector, boolean noLocal, MessageFactoryRegistry messageFactory, AMQSession session, + AMQProtocolHandler protocolHandler, FieldTable rawSelectorFieldTable, int prefetchHigh, int prefetchLow, + boolean exclusive, int acknowledgeMode, boolean noConsume, boolean autoClose) { _channelId = channelId; _connection = connection; @@ -160,7 +161,7 @@ public class BasicMessageConsumer extends Closeable implements MessageConsumer _autoClose = autoClose; _noConsume = noConsume; - //Force queue browsers not to use acknowledge modes. + // Force queue browsers not to use acknowledge modes. if (_noConsume) { _acknowledgeMode = Session.NO_ACKNOWLEDGE; @@ -175,12 +176,14 @@ public class BasicMessageConsumer extends Closeable implements MessageConsumer public String getMessageSelector() throws JMSException { checkPreConditions(); + return _messageSelector; } public MessageListener getMessageListener() throws JMSException { checkPreConditions(); + return _messageListener.get(); } @@ -198,14 +201,14 @@ public class BasicMessageConsumer extends Closeable implements MessageConsumer { checkPreConditions(); - //if the current listener is non-null and the session is not stopped, then - //it is an error to call this method. + // if the current listener is non-null and the session is not stopped, then + // it is an error to call this method. - //i.e. it is only valid to call this method if + // i.e. it is only valid to call this method if // - // (a) the connection is stopped, in which case the dispatcher is not running - // OR - // (b) the listener is null AND we are not receiving synchronously at present + // (a) the connection is stopped, in which case the dispatcher is not running + // OR + // (b) the listener is null AND we are not receiving synchronously at present // if (!_session.getAMQConnection().started()) @@ -215,7 +218,8 @@ public class BasicMessageConsumer extends Closeable implements MessageConsumer if (_logger.isDebugEnabled()) { - _logger.debug("Session stopped : Message listener(" + messageListener + ") set for destination " + _destination); + _logger.debug("Session stopped : Message listener(" + messageListener + ") set for destination " + + _destination); } } else @@ -224,6 +228,7 @@ public class BasicMessageConsumer extends Closeable implements MessageConsumer { throw new javax.jms.IllegalStateException("Another thread is already receiving synchronously."); } + if (!_messageListener.compareAndSet(null, messageListener)) { throw new javax.jms.IllegalStateException("Attempt to alter listener while session is started."); @@ -233,7 +238,7 @@ public class BasicMessageConsumer extends Closeable implements MessageConsumer if (messageListener != null) { - //handle case where connection has already been started, and the dispatcher has alreaded started + // handle case where connection has already been started, and the dispatcher has alreaded started // putting values on the _synchronousQueue synchronized (_session) @@ -263,10 +268,12 @@ public class BasicMessageConsumer extends Closeable implements MessageConsumer { throw new javax.jms.IllegalStateException("Another thread is already receiving."); } + if (isMessageListenerSet()) { throw new javax.jms.IllegalStateException("A listener has already been set."); } + _receivingThread = Thread.currentThread(); } @@ -331,6 +338,7 @@ public class BasicMessageConsumer extends Closeable implements MessageConsumer { return null; } + Object o = null; if (l > 0) { @@ -340,6 +348,7 @@ public class BasicMessageConsumer extends Closeable implements MessageConsumer { o = _synchronousQueue.take(); } + final AbstractJMSMessage m = returnMessageOrThrow(o); if (m != null) { @@ -352,6 +361,7 @@ public class BasicMessageConsumer extends Closeable implements MessageConsumer catch (InterruptedException e) { _logger.warn("Interrupted: " + e); + return null; } finally @@ -365,6 +375,7 @@ public class BasicMessageConsumer extends Closeable implements MessageConsumer if (isAutoClose() && _closeWhenNoMessages && _synchronousQueue.isEmpty()) { close(false); + return true; } else @@ -387,6 +398,7 @@ public class BasicMessageConsumer extends Closeable implements MessageConsumer { return null; } + Object o = _synchronousQueue.poll(); final AbstractJMSMessage m = returnMessageOrThrow(o); if (m != null) @@ -414,8 +426,7 @@ public class BasicMessageConsumer extends Closeable implements MessageConsumer * @throws JMSException if the argument is a throwable. If it is a JMSException it is rethrown as is, but if not a * JMSException is created with the linked exception set appropriately */ - private AbstractJMSMessage returnMessageOrThrow(Object o) - throws JMSException + private AbstractJMSMessage returnMessageOrThrow(Object o) throws JMSException { // errors are passed via the queue too since there is no way of interrupting the poll() via the API. if (o instanceof Throwable) @@ -425,6 +436,7 @@ public class BasicMessageConsumer extends Closeable implements MessageConsumer { e.setLinkedException((Exception) o); } + throw e; } else @@ -433,7 +445,6 @@ public class BasicMessageConsumer extends Closeable implements MessageConsumer } } - public void close() throws JMSException { close(true); @@ -441,7 +452,7 @@ public class BasicMessageConsumer extends Closeable implements MessageConsumer public void close(boolean sendClose) throws JMSException { - //synchronized (_closed) + // synchronized (_closed) if (_logger.isInfoEnabled()) { @@ -456,7 +467,8 @@ public class BasicMessageConsumer extends Closeable implements MessageConsumer { if (_closedStack != null) { - _logger.trace(_consumerTag + " close():" + Arrays.asList(Thread.currentThread().getStackTrace()).subList(3, 6)); + _logger.trace(_consumerTag + " close():" + + Arrays.asList(Thread.currentThread().getStackTrace()).subList(3, 6)); _logger.trace(_consumerTag + " previously:" + _closedStack.toString()); } else @@ -464,14 +476,14 @@ public class BasicMessageConsumer extends Closeable implements MessageConsumer _closedStack = Arrays.asList(Thread.currentThread().getStackTrace()).subList(3, 6); } } + if (sendClose) { // TODO: Be aware of possible changes to parameter order as versions change. - final AMQFrame cancelFrame = BasicCancelBody.createAMQFrame(_channelId, - _protocolHandler.getProtocolMajorVersion(), - _protocolHandler.getProtocolMinorVersion(), - _consumerTag, // consumerTag - false); // nowait + final AMQFrame cancelFrame = + BasicCancelBody.createAMQFrame(_channelId, _protocolHandler.getProtocolMajorVersion(), + _protocolHandler.getProtocolMinorVersion(), _consumerTag, // consumerTag + false); // nowait try { @@ -485,25 +497,28 @@ public class BasicMessageConsumer extends Closeable implements MessageConsumer } catch (AMQException e) { - _logger.error("Error closing consumer: " + e, e); - throw new JMSException("Error closing consumer: " + e); + // _logger.error("Error closing consumer: " + e, e); + JMSException jmse = new JMSException("Error closing consumer: " + e); + jmse.setLinkedException(e); + throw jmse; } } else { -// //fixme this probably is not right -// if (!isNoConsume()) - { //done in BasicCancelOK Handler but not sending one so just deregister. + // //fixme this probably is not right + // if (!isNoConsume()) + { // done in BasicCancelOK Handler but not sending one so just deregister. deregisterConsumer(); } } - if (_messageListener != null && _receiving.get()) + if ((_messageListener != null) && _receiving.get()) { if (_logger.isInfoEnabled()) { _logger.info("Interrupting thread: " + _receivingThread); } + _receivingThread.interrupt(); } } @@ -516,7 +531,7 @@ public class BasicMessageConsumer extends Closeable implements MessageConsumer */ void markClosed() { -// synchronized (_closed) + // synchronized (_closed) { _closed.set(true); @@ -524,7 +539,8 @@ public class BasicMessageConsumer extends Closeable implements MessageConsumer { if (_closedStack != null) { - _logger.trace(_consumerTag + " markClosed():" + Arrays.asList(Thread.currentThread().getStackTrace()).subList(3, 8)); + _logger.trace(_consumerTag + " markClosed():" + + Arrays.asList(Thread.currentThread().getStackTrace()).subList(3, 8)); _logger.trace(_consumerTag + " previously:" + _closedStack.toString()); } else @@ -533,6 +549,7 @@ public class BasicMessageConsumer extends Closeable implements MessageConsumer } } } + deregisterConsumer(); } @@ -551,22 +568,22 @@ public class BasicMessageConsumer extends Closeable implements MessageConsumer { _logger.debug("notifyMessage called with message number " + messageFrame.getDeliverBody().deliveryTag); } + try { - AbstractJMSMessage jmsMessage = _messageFactory.createMessage(messageFrame.getDeliverBody().deliveryTag, - messageFrame.getDeliverBody().redelivered, - messageFrame.getDeliverBody().exchange, - messageFrame.getDeliverBody().routingKey, - messageFrame.getContentHeader(), - messageFrame.getBodies()); + AbstractJMSMessage jmsMessage = + _messageFactory.createMessage(messageFrame.getDeliverBody().deliveryTag, + messageFrame.getDeliverBody().redelivered, messageFrame.getDeliverBody().exchange, + messageFrame.getDeliverBody().routingKey, messageFrame.getContentHeader(), messageFrame.getBodies()); if (debug) { _logger.debug("Message is of type: " + jmsMessage.getClass().getName()); } -// synchronized (_closed) + // synchronized (_closed) + { -// if (!_closed.get()) + // if (!_closed.get()) { jmsMessage.setConsumer(this); @@ -575,12 +592,12 @@ public class BasicMessageConsumer extends Closeable implements MessageConsumer notifyMessage(jmsMessage, channelId); } -// else -// { -// _logger.error("MESSAGE REJECTING!"); -// _session.rejectMessage(jmsMessage, true); -// //_logger.error("MESSAGE JUST DROPPED!"); -// } + // else + // { + // _logger.error("MESSAGE REJECTING!"); + // _session.rejectMessage(jmsMessage, true); + // //_logger.error("MESSAGE JUST DROPPED!"); + // } } } catch (Exception e) @@ -606,11 +623,11 @@ public class BasicMessageConsumer extends Closeable implements MessageConsumer { if (isMessageListenerSet()) { - //we do not need a lock around the test above, and the dispatch below as it is invalid - //for an application to alter an installed listener while the session is started -// synchronized (_closed) + // we do not need a lock around the test above, and the dispatch below as it is invalid + // for an application to alter an installed listener while the session is started + // synchronized (_closed) { -// if (!_closed.get()) + // if (!_closed.get()) { preApplicationProcessing(jmsMessage); @@ -641,9 +658,11 @@ public class BasicMessageConsumer extends Closeable implements MessageConsumer { switch (_acknowledgeMode) { + case Session.PRE_ACKNOWLEDGE: _session.acknowledgeMessage(msg.getDeliveryTag(), false); break; + case Session.CLIENT_ACKNOWLEDGE: // we set the session so that when the user calls acknowledge() it can call the method on session // to send out the appropriate frame @@ -657,17 +676,21 @@ public class BasicMessageConsumer extends Closeable implements MessageConsumer msg.setJMSDestination(_destination); switch (_acknowledgeMode) { + case Session.CLIENT_ACKNOWLEDGE: if (isNoConsume()) { _session.acknowledgeMessage(msg.getDeliveryTag(), false); } + break; + case Session.DUPS_OK_ACKNOWLEDGE: if (++_outstanding >= _prefetchHigh) { _dups_ok_acknowledge_send = true; } + if (_outstanding <= _prefetchLow) { _dups_ok_acknowledge_send = false; @@ -680,14 +703,18 @@ public class BasicMessageConsumer extends Closeable implements MessageConsumer _session.acknowledgeMessage(msg.getDeliveryTag(), true); } } + break; + case Session.AUTO_ACKNOWLEDGE: // we do not auto ack a message if the application code called recover() if (!_session.isInRecovery()) { _session.acknowledgeMessage(msg.getDeliveryTag(), false); } + break; + case Session.SESSION_TRANSACTED: if (isNoConsume()) { @@ -697,6 +724,7 @@ public class BasicMessageConsumer extends Closeable implements MessageConsumer { _receivedDeliveryTags.add(msg.getDeliveryTag()); } + break; } } @@ -721,14 +749,15 @@ public class BasicMessageConsumer extends Closeable implements MessageConsumer void notifyError(Throwable cause) { -// synchronized (_closed) + // synchronized (_closed) { _closed.set(true); if (_logger.isTraceEnabled()) { if (_closedStack != null) { - _logger.trace(_consumerTag + " notifyError():" + Arrays.asList(Thread.currentThread().getStackTrace()).subList(3, 8)); + _logger.trace(_consumerTag + " notifyError():" + + Arrays.asList(Thread.currentThread().getStackTrace()).subList(3, 8)); _logger.trace(_consumerTag + " previously" + _closedStack.toString()); } else @@ -737,7 +766,7 @@ public class BasicMessageConsumer extends Closeable implements MessageConsumer } } } - //QPID-293 can "request redelivery of this error through dispatcher" + // QPID-293 can "request redelivery of this error through dispatcher" // we have no way of propagating the exception to a message listener - a JMS limitation - so we // deal with the case where we have a synchronous receive() waiting for a message to arrive @@ -749,10 +778,10 @@ public class BasicMessageConsumer extends Closeable implements MessageConsumer _logger.debug("Passed exception to synchronous queue for propagation to receive()"); } } + deregisterConsumer(); } - /** * Perform cleanup to deregister this consumer. This occurs when closing the consumer in both the clean case and in * the case of an error occurring. @@ -782,7 +811,7 @@ public class BasicMessageConsumer extends Closeable implements MessageConsumer this.checkNotClosed(); - if (_session == null || _session.isClosed()) + if ((_session == null) || _session.isClosed()) { throw new javax.jms.IllegalStateException("Invalid Session"); } @@ -817,7 +846,6 @@ public class BasicMessageConsumer extends Closeable implements MessageConsumer return _autoClose; } - public boolean isNoConsume() { return _noConsume; @@ -827,10 +855,7 @@ public class BasicMessageConsumer extends Closeable implements MessageConsumer { _closeWhenNoMessages = b; - if (_closeWhenNoMessages - && _synchronousQueue.isEmpty() - && _receiving.get() - && _messageListener != null) + if (_closeWhenNoMessages && _synchronousQueue.isEmpty() && _receiving.get() && (_messageListener != null)) { _receivingThread.interrupt(); } @@ -846,13 +871,13 @@ public class BasicMessageConsumer extends Closeable implements MessageConsumer _logger.debug("Rejecting received messages in _receivedDTs (RQ)"); } - //rollback received but not committed messages + // rollback received but not committed messages while (!_receivedDeliveryTags.isEmpty()) { if (_logger.isDebugEnabled()) { - _logger.debug("Rejecting the messages(" + _receivedDeliveryTags.size() + ") in _receivedDTs (RQ)" + - "for consumer with tag:" + _consumerTag); + _logger.debug("Rejecting the messages(" + _receivedDeliveryTags.size() + ") in _receivedDTs (RQ)" + + "for consumer with tag:" + _consumerTag); } Long tag = _receivedDeliveryTags.poll(); @@ -876,14 +901,15 @@ public class BasicMessageConsumer extends Closeable implements MessageConsumer } } - //rollback pending messages + // rollback pending messages if (_synchronousQueue.size() > 0) { if (_logger.isDebugEnabled()) { - _logger.debug("Rejecting the messages(" + _synchronousQueue.size() + ") in _syncQueue (PRQ)" + - "for consumer with tag:" + _consumerTag); + _logger.debug("Rejecting the messages(" + _synchronousQueue.size() + ") in _syncQueue (PRQ)" + + "for consumer with tag:" + _consumerTag); } + Iterator iterator = _synchronousQueue.iterator(); while (iterator.hasNext()) @@ -898,13 +924,14 @@ public class BasicMessageConsumer extends Closeable implements MessageConsumer { _logger.trace("Rejected message:" + ((AbstractJMSMessage) o).getDeliveryTag()); } + iterator.remove(); } else { - _logger.error("Queue contained a :" + o.getClass() + - " unable to reject as it is not an AbstractJMSMessage. Will be cleared"); + _logger.error("Queue contained a :" + o.getClass() + + " unable to reject as it is not an AbstractJMSMessage. Will be cleared"); iterator.remove(); } } @@ -919,7 +946,6 @@ public class BasicMessageConsumer extends Closeable implements MessageConsumer } } - public String debugIdentity() { return String.valueOf(_consumerTag); diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer.java b/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer.java index b01e087ce1..bd7cc94582 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer.java @@ -21,6 +21,7 @@ package org.apache.qpid.client; import java.io.UnsupportedEncodingException; +import java.util.UUID; import javax.jms.BytesMessage; import javax.jms.DeliveryMode; @@ -118,6 +119,9 @@ public class BasicMessageProducer extends Closeable implements org.apache.qpid.j private final boolean _mandatory; private final boolean _waitUntilSent; + + private boolean _disableMessageId; + private static final ContentBody[] NO_CONTENT_BODIES = new ContentBody[0]; protected BasicMessageProducer(AMQConnection connection, AMQDestination destination, boolean transacted, int channelId, @@ -172,15 +176,14 @@ public class BasicMessageProducer extends Closeable implements org.apache.qpid.j { checkPreConditions(); checkNotClosed(); - // IGNORED + _disableMessageId = b; } public boolean getDisableMessageID() throws JMSException { checkNotClosed(); - // Always false for AMQP - return false; + return _disableMessageId; } public void setDisableMessageTimestamp(boolean b) throws JMSException @@ -450,6 +453,18 @@ public class BasicMessageProducer extends Closeable implements org.apache.qpid.j origMessage.setJMSDestination(destination); AbstractJMSMessage message = convertToNativeMessage(origMessage); + + if(_disableMessageId) + { + message.setJMSMessageID(null); + } + else + { + if (message.getJMSMessageID() == null) + { + message.setJMSMessageID(UUID.randomUUID().toString()); + } + } int type; if (destination instanceof Topic) @@ -667,4 +682,9 @@ public class BasicMessageProducer extends Closeable implements org.apache.qpid.j { return _session; } + + public boolean isBound(AMQDestination destination) throws JMSException + { + return _session.isQueueBound(destination.getExchangeName(),null,destination.getRoutingKey()); + } } diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/JMSAMQException.java b/qpid/java/client/src/main/java/org/apache/qpid/client/JMSAMQException.java index d2ab6bd2c2..d1237cff49 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/client/JMSAMQException.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/JMSAMQException.java @@ -1,5 +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. + * + */ +/* + * * Copyright (c) 2006 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -22,10 +42,35 @@ import javax.jms.JMSException; import org.apache.qpid.AMQException; /** + * JMSException does not accept wrapped exceptions in its constructor. Presumably this is because it is a relatively old + * Java exception class, before this was added as a default to Throwable. This exception class accepts wrapped exceptions + * as well as error messages, through its constructor, but is a JMSException. + * + * <p/><table id="crc"><caption>CRC Card</caption> + * <tr><th> Responsibilities <th> Collaborations + * <tr><td> Accept wrapped exceptions as a JMSException. + * </table> + * * @author Apache Software Foundation */ public class JMSAMQException extends JMSException { + /** + * Creates a JMSException, wrapping another exception class. + * + * @param message The error message. + * @param cause The underlying exception that caused this one. May be null if none is to be set. + */ + public JMSAMQException(String message, Exception cause) + { + super(message); + + if (cause != null) + { + setLinkedException(cause); + } + } + public JMSAMQException(AMQException s) { super(s.getMessage(), String.valueOf(s.getErrorCode())); diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/QueueSenderAdapter.java b/qpid/java/client/src/main/java/org/apache/qpid/client/QueueSenderAdapter.java index c9d29d8077..e0c4b61333 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/client/QueueSenderAdapter.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/QueueSenderAdapter.java @@ -7,14 +7,15 @@ import javax.jms.Message; import javax.jms.MessageProducer; import javax.jms.Queue; import javax.jms.QueueSender; +import javax.jms.InvalidDestinationException; public class QueueSenderAdapter implements QueueSender { - private MessageProducer _delegate; + private BasicMessageProducer _delegate; private Queue _queue; private boolean closed = false; - public QueueSenderAdapter(MessageProducer msgProducer, Queue queue){ + public QueueSenderAdapter(BasicMessageProducer msgProducer, Queue queue){ _delegate = msgProducer; _queue = queue; } @@ -122,12 +123,13 @@ public class QueueSenderAdapter implements QueueSender { _delegate.setTimeToLive(timeToLive); } - private void checkPreConditions() throws IllegalStateException, IllegalStateException + private void checkPreConditions() throws JMSException { checkPreConditions(_queue); } - private void checkPreConditions(Queue queue) throws IllegalStateException, IllegalStateException { + private void checkPreConditions(Queue queue) throws JMSException + { if (closed){ throw new javax.jms.IllegalStateException("Publisher is closed"); } @@ -137,5 +139,28 @@ public class QueueSenderAdapter implements QueueSender { if(session == null || session.isClosed()){ throw new javax.jms.IllegalStateException("Invalid Session"); } - } + + if(!(queue instanceof AMQDestination)) + { + throw new InvalidDestinationException("Queue: " + queue + " is not a valid Qpid queue"); + } + AMQDestination destination = (AMQDestination) queue; + if(!destination.isValidated() && checkQueueBeforePublish()) + { + + if (_delegate.isBound(destination)) + { + destination.setValidated(true); + } + else + { + throw new InvalidDestinationException("Queue: " + queue + " is not a valid destination (no bindings on server"); + } + } + } + + private boolean checkQueueBeforePublish() + { + return "true".equalsIgnoreCase(System.getProperty("org.apache.qpid.client.verifyQueueBindingBeforePublish", "true")); + } } diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/TopicPublisherAdapter.java b/qpid/java/client/src/main/java/org/apache/qpid/client/TopicPublisherAdapter.java index f67b984658..02a408465b 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/client/TopicPublisherAdapter.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/TopicPublisherAdapter.java @@ -175,5 +175,10 @@ public class TopicPublisherAdapter implements TopicPublisher { throw new InvalidDestinationException("Destination " + topic + " is not a topic"); } + if(!(topic instanceof AMQDestination)) + { + throw new InvalidDestinationException("Destination " + topic + " is not a Qpid topic"); + } + } } diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/handler/ChannelCloseMethodHandler.java b/qpid/java/client/src/main/java/org/apache/qpid/client/handler/ChannelCloseMethodHandler.java index e2b101ab79..f62baf2c3a 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/client/handler/ChannelCloseMethodHandler.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/handler/ChannelCloseMethodHandler.java @@ -94,6 +94,8 @@ public class ChannelCloseMethodHandler implements StateAwareMethodListener } } + //fixme why is this only done when the close is expected... + // should the above forced closes not also cause a close? protocolSession.channelClosed(evt.getChannelId(), errorCode, String.valueOf(reason)); } } diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/message/AbstractBytesMessage.java b/qpid/java/client/src/main/java/org/apache/qpid/client/message/AbstractBytesMessage.java index 8938130417..af254fbbaf 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/client/message/AbstractBytesMessage.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/message/AbstractBytesMessage.java @@ -27,6 +27,7 @@ import javax.jms.JMSException; import javax.jms.MessageEOFException; import org.apache.mina.common.ByteBuffer; + import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.BasicContentHeaderProperties; @@ -72,7 +73,7 @@ public abstract class AbstractBytesMessage extends AbstractJMSMessage } AbstractBytesMessage(long messageNbr, ContentHeaderBody contentHeader, AMQShortString exchange, - AMQShortString routingKey, ByteBuffer data) throws AMQException + AMQShortString routingKey, ByteBuffer data) throws AMQException { // TODO: this casting is ugly. Need to review whole ContentHeaderBody idea super(messageNbr, (BasicContentHeaderProperties) contentHeader.properties, exchange, routingKey, data); @@ -93,7 +94,9 @@ public abstract class AbstractBytesMessage extends AbstractJMSMessage } catch (IOException e) { - throw new JMSException(e.toString()); + JMSException jmse = new JMSException(e.toString()); + jmse.setLinkedException(e); + throw jmse; } } @@ -112,6 +115,7 @@ public abstract class AbstractBytesMessage extends AbstractJMSMessage { return null; } + int pos = _data.position(); _data.rewind(); // one byte left is for the end of frame marker @@ -119,12 +123,14 @@ public abstract class AbstractBytesMessage extends AbstractJMSMessage { // this is really redundant since pos must be zero _data.position(pos); + return null; } else { String data = _data.getString(Charset.forName("UTF8").newDecoder()); _data.position(pos); + return data; } } diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/message/AbstractJMSMessage.java b/qpid/java/client/src/main/java/org/apache/qpid/client/message/AbstractJMSMessage.java index 66524edce3..f87b4027f6 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/client/message/AbstractJMSMessage.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/message/AbstractJMSMessage.java @@ -23,6 +23,7 @@ package org.apache.qpid.client.message; import java.util.Collections; import java.util.Enumeration; import java.util.Map; +import java.util.UUID; import javax.jms.Destination; import javax.jms.JMSException; @@ -32,12 +33,7 @@ import javax.jms.MessageNotWriteableException; import org.apache.commons.collections.map.ReferenceMap; import org.apache.mina.common.ByteBuffer; import org.apache.qpid.AMQException; -import org.apache.qpid.client.AMQDestination; -import org.apache.qpid.client.AMQQueue; -import org.apache.qpid.client.AMQTopic; -import org.apache.qpid.client.AMQUndefinedDestination; -import org.apache.qpid.client.BasicMessageConsumer; -import org.apache.qpid.client.CustomJMSXProperty; +import org.apache.qpid.client.*; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.BasicContentHeaderProperties; import org.apache.qpid.framing.FieldTable; @@ -123,7 +119,7 @@ public abstract class AbstractJMSMessage extends AMQMessage implements org.apach { if (getContentHeaderProperties().getMessageIdAsString() == null) { - getContentHeaderProperties().setMessageId("ID:" + _deliveryTag); + getContentHeaderProperties().setMessageId("ID:" + UUID.randomUUID()); } return getContentHeaderProperties().getMessageIdAsString(); @@ -183,7 +179,7 @@ public abstract class AbstractJMSMessage extends AMQMessage implements org.apach } catch (URLSyntaxException e) { - throw new JMSException("Illegal value in JMS_ReplyTo property: " + replyToEncoding); + throw new JMSAMQException("Illegal value in JMS_ReplyTo property: " + replyToEncoding, e); } _destinationCache.put(replyToEncoding, dest); diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/message/JMSHeaderAdapter.java b/qpid/java/client/src/main/java/org/apache/qpid/client/message/JMSHeaderAdapter.java index 6352f7029f..348a0bd152 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/client/message/JMSHeaderAdapter.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/message/JMSHeaderAdapter.java @@ -384,7 +384,9 @@ public final class JMSHeaderAdapter }
catch (AMQPInvalidClassException aice)
{
- throw new MessageFormatException("Only primatives are allowed object is:" + object.getClass());
+ MessageFormatException mfe = new MessageFormatException("Only primatives are allowed object is:" + object.getClass());
+ mfe.setLinkedException(aice);
+ throw mfe;
}
}
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/message/JMSObjectMessage.java b/qpid/java/client/src/main/java/org/apache/qpid/client/message/JMSObjectMessage.java index df1400b167..caf8741280 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/client/message/JMSObjectMessage.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/message/JMSObjectMessage.java @@ -33,6 +33,7 @@ import javax.jms.MessageFormatException; import javax.jms.ObjectMessage; import org.apache.mina.common.ByteBuffer; + import org.apache.qpid.AMQException; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.framing.BasicContentHeaderProperties; @@ -61,14 +62,15 @@ public class JMSObjectMessage extends AbstractJMSMessage implements ObjectMessag _data = ByteBuffer.allocate(DEFAULT_BUFFER_SIZE); _data.setAutoExpand(true); } + getContentHeaderProperties().setContentType(MIME_TYPE_SHORT_STRING); } /** * Creates read only message for delivery to consumers */ - JMSObjectMessage(long messageNbr, ContentHeaderBody contentHeader, AMQShortString exchange, - AMQShortString routingKey, ByteBuffer data) throws AMQException + JMSObjectMessage(long messageNbr, ContentHeaderBody contentHeader, AMQShortString exchange, AMQShortString routingKey, + ByteBuffer data) throws AMQException { super(messageNbr, (BasicContentHeaderProperties) contentHeader.properties, exchange, routingKey, data); } @@ -79,6 +81,7 @@ public class JMSObjectMessage extends AbstractJMSMessage implements ObjectMessag { _data.release(); } + _data = null; } @@ -116,11 +119,13 @@ public class JMSObjectMessage extends AbstractJMSMessage implements ObjectMessag } catch (IOException e) { - throw new MessageFormatException("Message not serializable: " + e); + MessageFormatException mfe = new MessageFormatException("Message not serializable: " + e); + mfe.setLinkedException(e); + throw mfe; } } - + public Serializable getObject() throws JMSException { ObjectInputStream in = null; @@ -133,17 +138,20 @@ public class JMSObjectMessage extends AbstractJMSMessage implements ObjectMessag { _data.rewind(); in = new ObjectInputStream(_data.asInputStream()); + return (Serializable) in.readObject(); } catch (IOException e) { - e.printStackTrace(); - throw new MessageFormatException("Could not deserialize message: " + e); + MessageFormatException mfe = new MessageFormatException("Could not deserialize message: " + e); + mfe.setLinkedException(e); + throw mfe; } catch (ClassNotFoundException e) { - e.printStackTrace(); - throw new MessageFormatException("Could not deserialize message: " + e); + MessageFormatException mfe = new MessageFormatException("Could not deserialize message: " + e); + mfe.setLinkedException(e); + throw mfe; } finally { @@ -162,8 +170,7 @@ public class JMSObjectMessage extends AbstractJMSMessage implements ObjectMessag } } catch (IOException ignore) - { - } + { } } private static String toString(ByteBuffer data) @@ -172,6 +179,7 @@ public class JMSObjectMessage extends AbstractJMSMessage implements ObjectMessag { return null; } + int pos = data.position(); try { diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolHandler.java b/qpid/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolHandler.java index d0cc52271a..5bc1555df7 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolHandler.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolHandler.java @@ -34,6 +34,7 @@ import org.apache.qpid.AMQConnectionClosedException; import org.apache.qpid.AMQDisconnectedException; import org.apache.qpid.AMQException; import org.apache.qpid.AMQTimeoutException; +import org.apache.qpid.AMQChannelClosedException; import org.apache.qpid.client.AMQConnection; import org.apache.qpid.client.AMQSession; import org.apache.qpid.client.SSLConfiguration; @@ -248,6 +249,12 @@ public class AMQProtocolHandler extends IoHandlerAdapter sessionClosed(session); } + + //FIXME Need to correctly handle other exceptions. Things like ... +// if (cause instanceof AMQChannelClosedException) + // which will cause the JMSSession to end due to a channel close and so that Session needs + // to be removed from the map so we can correctly still call close without an exception when trying to close + // the server closed session. See also CloseChannelMethodHandler as the sessionClose is never called on exception } // we reach this point if failover was attempted and failed therefore we need to let the calling app // know since we cannot recover the situation @@ -510,11 +517,6 @@ public class AMQProtocolHandler extends IoHandlerAdapter _protocolSession.closeSession(session); } - public void closeConnection() throws AMQException - { - closeConnection(-1); - } - public void closeConnection(long timeout) throws AMQException { getStateManager().changeState(AMQState.CONNECTION_CLOSING); diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/security/CallbackHandlerRegistry.properties b/qpid/java/client/src/main/java/org/apache/qpid/client/security/CallbackHandlerRegistry.properties index 50e6f1efaa..89ee8337f8 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/client/security/CallbackHandlerRegistry.properties +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/security/CallbackHandlerRegistry.properties @@ -16,5 +16,6 @@ # specific language governing permissions and limitations # under the License. # +CallbackHandler.CRAM-MD5-HASHED=org.apache.qpid.client.security.UsernameHashedPasswordCallbackHandler CallbackHandler.CRAM-MD5=org.apache.qpid.client.security.UsernamePasswordCallbackHandler CallbackHandler.PLAIN=org.apache.qpid.client.security.UsernamePasswordCallbackHandler diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/security/DynamicSaslRegistrar.java b/qpid/java/client/src/main/java/org/apache/qpid/client/security/DynamicSaslRegistrar.java index f8ee22a5d9..04db8044de 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/client/security/DynamicSaslRegistrar.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/security/DynamicSaslRegistrar.java @@ -20,10 +20,6 @@ */ package org.apache.qpid.client.security; -import java.io.BufferedInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.security.Security; @@ -34,6 +30,7 @@ import java.util.TreeMap; import javax.security.sasl.SaslClientFactory; + import org.apache.log4j.Logger; import org.apache.qpid.util.FileUtils; @@ -50,14 +47,11 @@ import org.apache.qpid.util.FileUtils; * mechanism=fully.qualified.class.name * </pre> * - * <p/>Where mechanism is an IANA-registered mechanism name and the fully qualified class name refers to a - * class that implements javax.security.sasl.SaslClientFactory and provides the specified mechanism. + * <p/>Where mechanism is an IANA-registered mechanism name and the fully qualified class name refers to a class that + * implements javax.security.sasl.SaslClientFactory and provides the specified mechanism. * - * <p><table id="crc"><caption>CRC Card</caption> - * <tr><th> Responsibilities <th> Collaborations - * <tr><td> Parse SASL mechanism properties. - * <tr><td> Create and register security provider for SASL mechanisms. - * </table> + * <p><table id="crc"><caption>CRC Card</caption> <tr><th> Responsibilities <th> Collaborations <tr><td> Parse SASL + * mechanism properties. <tr><td> Create and register security provider for SASL mechanisms. </table> */ public class DynamicSaslRegistrar { @@ -69,10 +63,7 @@ public class DynamicSaslRegistrar /** The default name of the SASL properties file resource. */ public static final String DEFAULT_RESOURCE_NAME = "org/apache/qpid/client/security/DynamicSaslRegistrar.properties"; - /** - * Reads the properties file, and creates a dynamic security provider to register the SASL implementations - * with. - */ + /** Reads the properties file, and creates a dynamic security provider to register the SASL implementations with. */ public static void registerSaslProviders() { _logger.debug("public static void registerSaslProviders(): called"); @@ -80,8 +71,8 @@ public class DynamicSaslRegistrar // Open the SASL properties file, using the default name is one is not specified. String filename = System.getProperty(FILE_PROPERTY); InputStream is = - FileUtils.openFileOrDefaultResource(filename, DEFAULT_RESOURCE_NAME, - DynamicSaslRegistrar.class.getClassLoader()); + FileUtils.openFileOrDefaultResource(filename, DEFAULT_RESOURCE_NAME, + DynamicSaslRegistrar.class.getClassLoader()); try { @@ -94,7 +85,7 @@ public class DynamicSaslRegistrar if (factories.size() > 0) { - Security.addProvider(new JCAProvider(factories)); + Security.insertProviderAt(new JCAProvider(factories), 0); _logger.debug("Dynamic SASL provider added as a security provider"); } } @@ -170,15 +161,15 @@ public class DynamicSaslRegistrar * @return A map from SASL mechanism names to implementing client factory classes. * * @todo Why tree map here? Do really want mechanisms in alphabetical order? Seems more likely that the declared - * order of the mechanisms is intended to be preserved, so that they are registered in the declared order - * of preference. Consider LinkedHashMap instead. + * order of the mechanisms is intended to be preserved, so that they are registered in the declared order of + * preference. Consider LinkedHashMap instead. */ private static Map<String, Class<? extends SaslClientFactory>> parseProperties(Properties props) { Enumeration e = props.propertyNames(); TreeMap<String, Class<? extends SaslClientFactory>> factoriesToRegister = - new TreeMap<String, Class<? extends SaslClientFactory>>(); + new TreeMap<String, Class<? extends SaslClientFactory>>(); while (e.hasMoreElements()) { diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/security/DynamicSaslRegistrar.properties b/qpid/java/client/src/main/java/org/apache/qpid/client/security/DynamicSaslRegistrar.properties index c2a7d7928c..1bff43142b 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/client/security/DynamicSaslRegistrar.properties +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/security/DynamicSaslRegistrar.properties @@ -17,3 +17,4 @@ # under the License. # AMQPLAIN=org.apache.qpid.client.security.amqplain.AmqPlainSaslClientFactory +CRAM-MD5-HASHED=org.apache.qpid.client.security.crammd5hashed.CRAMMD5HashedSaslClientFactory diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/security/JCAProvider.java b/qpid/java/client/src/main/java/org/apache/qpid/client/security/JCAProvider.java index 2fa8dcddde..5bf120454e 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/client/security/JCAProvider.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/security/JCAProvider.java @@ -52,7 +52,7 @@ public class JCAProvider extends Provider super("AMQSASLProvider", 1.0, "A JCA provider that registers all " + "AMQ SASL providers that want to be registered"); register(providerMap); - Security.addProvider(this); +// Security.addProvider(this); } /** diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/security/UsernameHashedPasswordCallbackHandler.java b/qpid/java/client/src/main/java/org/apache/qpid/client/security/UsernameHashedPasswordCallbackHandler.java new file mode 100644 index 0000000000..46323e8c09 --- /dev/null +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/security/UsernameHashedPasswordCallbackHandler.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 + * + * 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.client.security; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.UnsupportedCallbackException; +import javax.security.sasl.RealmCallback; + +import com.sun.crypto.provider.HmacMD5; + +import org.apache.log4j.Logger; + +import org.apache.qpid.client.protocol.AMQProtocolSession; + +public class UsernameHashedPasswordCallbackHandler implements AMQCallbackHandler +{ + private static final Logger _logger = Logger.getLogger(UsernameHashedPasswordCallbackHandler.class); + + private AMQProtocolSession _protocolSession; + + public void initialise(AMQProtocolSession protocolSession) + { + _protocolSession = protocolSession; + } + + public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException + { + for (int i = 0; i < callbacks.length; i++) + { + Callback cb = callbacks[i]; + if (cb instanceof NameCallback) + { + ((NameCallback) cb).setName(_protocolSession.getUsername()); + } + else if (cb instanceof PasswordCallback) + { + try + { + ((PasswordCallback) cb).setPassword(getHash(_protocolSession.getPassword())); + } + catch (NoSuchAlgorithmException e) + { + UnsupportedCallbackException uce = new UnsupportedCallbackException(cb); + uce.initCause(e); + throw uce; + } + } + else + { + throw new UnsupportedCallbackException(cb); + } + } + } + + private char[] getHash(String text) throws NoSuchAlgorithmException, UnsupportedEncodingException + { + + byte[] data = text.getBytes("utf-8"); + + MessageDigest md = MessageDigest.getInstance("MD5"); + + for (byte b : data) + { + md.update(b); + } + + byte[] digest = md.digest(); + + char[] hash = new char[digest.length ]; + + int index = 0; + for (byte b : digest) + { + hash[index++] = (char) b; + } + + return hash; + } +} diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/security/crammd5hashed/CRAMMD5HashedSaslClientFactory.java b/qpid/java/client/src/main/java/org/apache/qpid/client/security/crammd5hashed/CRAMMD5HashedSaslClientFactory.java new file mode 100644 index 0000000000..22bb1ac156 --- /dev/null +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/security/crammd5hashed/CRAMMD5HashedSaslClientFactory.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.client.security.crammd5hashed; + +import org.apache.qpid.client.security.amqplain.AmqPlainSaslClient; + +import javax.security.sasl.SaslClientFactory; +import javax.security.sasl.SaslClient; +import javax.security.sasl.SaslException; +import javax.security.sasl.Sasl; +import javax.security.auth.callback.CallbackHandler; +import java.util.Map; +import java.security.Security; + +public class CRAMMD5HashedSaslClientFactory implements SaslClientFactory +{ + /** The name of this mechanism */ + public static final String MECHANISM = "CRAM-MD5-HASHED"; + + + public SaslClient createSaslClient(String[] mechanisms, String authorizationId, String protocol, String serverName, Map<String, ?> props, CallbackHandler cbh) throws SaslException + { + for (int i = 0; i < mechanisms.length; i++) + { + if (mechanisms[i].equals(MECHANISM)) + { + if (cbh == null) + { + throw new SaslException("CallbackHandler must not be null"); + } + + String[] mechs = {"CRAM-MD5"}; + return Sasl.createSaslClient(mechs, authorizationId, protocol, serverName, props, cbh); + } + } + return null; + } + + public String[] getMechanismNames(Map props) + { + if (props != null) + { + if (props.containsKey(Sasl.POLICY_NOPLAINTEXT) || + props.containsKey(Sasl.POLICY_NODICTIONARY) || + props.containsKey(Sasl.POLICY_NOACTIVE)) + { + // returned array must be non null according to interface documentation + return new String[0]; + } + } + + return new String[]{MECHANISM}; + } +} diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/transport/AMQNoTransportForProtocolException.java b/qpid/java/client/src/main/java/org/apache/qpid/client/transport/AMQNoTransportForProtocolException.java index 104c5bfc44..1ec3adc2eb 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/client/transport/AMQNoTransportForProtocolException.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/transport/AMQNoTransportForProtocolException.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 @@ -33,7 +33,7 @@ public class AMQNoTransportForProtocolException extends AMQTransportConnectionEx public AMQNoTransportForProtocolException(BrokerDetails details, String message) { - super(message); + super(null, message, null); _details = details; } diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/transport/AMQTransportConnectionException.java b/qpid/java/client/src/main/java/org/apache/qpid/client/transport/AMQTransportConnectionException.java index 4b17661bc3..fec7ff693c 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/client/transport/AMQTransportConnectionException.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/transport/AMQTransportConnectionException.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 @@ -21,12 +21,12 @@ package org.apache.qpid.client.transport; import org.apache.qpid.AMQException; +import org.apache.qpid.protocol.AMQConstant; public class AMQTransportConnectionException extends AMQException { - public AMQTransportConnectionException(String message) + public AMQTransportConnectionException(AMQConstant errorCode, String message, Throwable cause) { - super(message); - + super(errorCode, message, cause); } } diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/transport/TransportConnection.java b/qpid/java/client/src/main/java/org/apache/qpid/client/transport/TransportConnection.java index 8368eee125..0bc83e9804 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/client/transport/TransportConnection.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/transport/TransportConnection.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 @@ -26,12 +26,14 @@ import java.util.Iterator; import java.util.Map; import org.apache.log4j.Logger; + import org.apache.mina.common.IoConnector; import org.apache.mina.common.IoHandlerAdapter; import org.apache.mina.common.IoServiceConfig; import org.apache.mina.transport.socket.nio.SocketConnector; import org.apache.mina.transport.vmpipe.VmPipeAcceptor; import org.apache.mina.transport.vmpipe.VmPipeAddress; + import org.apache.qpid.client.AMQBrokerDetails; import org.apache.qpid.client.vmbroker.AMQVMBrokerCreationException; import org.apache.qpid.jms.BrokerDetails; @@ -64,13 +66,11 @@ public class TransportConnection int transport = getTransport(details.getTransport()); if (transport == -1) - { throw new AMQNoTransportForProtocolException(details); } if (transport == _currentInstance) - { if (transport == VM) { @@ -88,40 +88,42 @@ public class TransportConnection _currentInstance = transport; switch (transport) - { - case TCP: - _instance = new SocketTransportConnection(new SocketTransportConnection.SocketConnectorFactory() - { - public IoConnector newSocketConnector() + + case TCP: + _instance = new SocketTransportConnection(new SocketTransportConnection.SocketConnectorFactory() { - SocketConnector result; - //FIXME - this needs to be sorted to use the new Mina MultiThread SA. - if (Boolean.getBoolean("qpidnio")) + public IoConnector newSocketConnector() { - _logger.fatal("Using Qpid NIO - sysproperty 'qpidnio' is set."); -// result = new org.apache.qpid.nio.SocketConnector(); // non-blocking connector + SocketConnector result; + // FIXME - this needs to be sorted to use the new Mina MultiThread SA. + if (Boolean.getBoolean("qpidnio")) + { + _logger.fatal("Using Qpid NIO - sysproperty 'qpidnio' is set."); + // result = new org.apache.qpid.nio.SocketConnector(); // non-blocking connector + } + // else + + { + _logger.info("Using Mina NIO"); + result = new SocketConnector(); // non-blocking connector + } + + // Don't have the connector's worker thread wait around for other connections (we only use + // one SocketConnector per connection at the moment anyway). This allows short-running + // clients (like unit tests) to complete quickly. + result.setWorkerTimeout(0); + + return result; } -// else - { - _logger.info("Using Mina NIO"); - result = new SocketConnector(); // non-blocking connector - } - - // Don't have the connector's worker thread wait around for other connections (we only use - // one SocketConnector per connection at the moment anyway). This allows short-running - // clients (like unit tests) to complete quickly. - result.setWorkerTimeout(0); + }); + break; - return result; - } - }); - break; - case VM: - { - _instance = getVMTransport(details, Boolean.getBoolean("amqj.AutoCreateVMBroker")); - break; - } + case VM: + { + _instance = getVMTransport(details, Boolean.getBoolean("amqj.AutoCreateVMBroker")); + break; + } } return _instance; @@ -142,7 +144,8 @@ public class TransportConnection return -1; } - private static ITransportConnection getVMTransport(BrokerDetails details, boolean AutoCreate) throws AMQVMBrokerCreationException + private static ITransportConnection getVMTransport(BrokerDetails details, boolean AutoCreate) + throws AMQVMBrokerCreationException { int port = details.getPort(); @@ -154,14 +157,14 @@ public class TransportConnection } else { - throw new AMQVMBrokerCreationException(port, "VM Broker on port " + port + " does not exist. Auto create disabled."); + throw new AMQVMBrokerCreationException(null, port, "VM Broker on port " + port + + " does not exist. Auto create disabled.", null); } } return new VmPipeTransportConnection(port); } - public static void createVMBroker(int port) throws AMQVMBrokerCreationException { if (_acceptor == null) @@ -192,7 +195,7 @@ public class TransportConnection { _logger.error(e); - //Try and unbind provider + // Try and unbind provider try { VmPipeAddress pipe = new VmPipeAddress(port); @@ -203,7 +206,7 @@ public class TransportConnection } catch (Exception ignore) { - //ignore + // ignore } if (provider == null) @@ -227,7 +230,7 @@ public class TransportConnection because = e.getCause().toString(); } - throw new AMQVMBrokerCreationException(port, because + " Stopped binding of InVM Qpid.AMQP"); + throw new AMQVMBrokerCreationException(null, port, because + " Stopped binding of InVM Qpid.AMQP", e); } } } @@ -246,14 +249,14 @@ public class TransportConnection // can't use introspection to get Provider as it is a server class. // need to go straight to IoHandlerAdapter but that requries the queues and exchange from the ApplicationRegistry which we can't access. - //get right constructor and pass in instancec ID - "port" + // get right constructor and pass in instancec ID - "port" IoHandlerAdapter provider; try { - Class[] cnstr = {Integer.class}; - Object[] params = {port}; + Class[] cnstr = { Integer.class }; + Object[] params = { port }; provider = (IoHandlerAdapter) Class.forName(protocolProviderClass).getConstructor(cnstr).newInstance(params); - //Give the broker a second to create + // Give the broker a second to create _logger.info("Created VMBroker Instance:" + port); } catch (Exception e) @@ -270,8 +273,10 @@ public class TransportConnection because = e.getCause().toString(); } - - throw new AMQVMBrokerCreationException(port, because + " Stopped InVM Qpid.AMQP creation"); + AMQVMBrokerCreationException amqbce = + new AMQVMBrokerCreationException(null, port, because + " Stopped InVM Qpid.AMQP creation", null); + amqbce.initCause(e); + throw amqbce; } return provider; diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/vmbroker/AMQVMBrokerCreationException.java b/qpid/java/client/src/main/java/org/apache/qpid/client/vmbroker/AMQVMBrokerCreationException.java index 607ddcc26a..4b2982fe9c 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/client/vmbroker/AMQVMBrokerCreationException.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/vmbroker/AMQVMBrokerCreationException.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 @@ -21,19 +21,25 @@ package org.apache.qpid.client.vmbroker; import org.apache.qpid.client.transport.AMQTransportConnectionException; +import org.apache.qpid.protocol.AMQConstant; public class AMQVMBrokerCreationException extends AMQTransportConnectionException { private int _port; + /** + * @param port + * + * @deprecated + */ public AMQVMBrokerCreationException(int port) { - this(port, "Unable to create vm broker"); + this(null, port, "Unable to create vm broker", null); } - public AMQVMBrokerCreationException(int port, String message) + public AMQVMBrokerCreationException(AMQConstant errorCode, int port, String message, Throwable cause) { - super(message); + super(errorCode, message, cause); _port = port; } diff --git a/qpid/java/client/src/main/java/org/apache/qpid/jms/FailoverPolicy.java b/qpid/java/client/src/main/java/org/apache/qpid/jms/FailoverPolicy.java index 9adf04e182..6ad3fb4bae 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/jms/FailoverPolicy.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/jms/FailoverPolicy.java @@ -101,7 +101,7 @@ public class FailoverPolicy } catch (Exception cnfe) { - throw new IllegalArgumentException("Unknown failover method:" + failoverMethod); + throw new IllegalArgumentException("Unknown failover method:" + failoverMethod, cnfe); } } } diff --git a/qpid/java/client/src/test/java/org/apache/qpid/client/MessageListenerMultiConsumerTest.java b/qpid/java/client/src/test/java/org/apache/qpid/client/MessageListenerMultiConsumerTest.java index a406f9f86e..794fd5c8c1 100644 --- a/qpid/java/client/src/test/java/org/apache/qpid/client/MessageListenerMultiConsumerTest.java +++ b/qpid/java/client/src/test/java/org/apache/qpid/client/MessageListenerMultiConsumerTest.java @@ -65,6 +65,7 @@ public class MessageListenerMultiConsumerTest extends TestCase private final CountDownLatch _allMessagesSent = new CountDownLatch(2); //all messages Sent Lock + protected void setUp() throws Exception { super.setUp(); @@ -122,30 +123,39 @@ public class MessageListenerMultiConsumerTest extends TestCase TransportConnection.killAllVMBrokers(); } +// public void testRecieveC1thenC2() throws Exception +// { +// +// for (int msg = 0; msg < MSG_COUNT / 2; msg++) +// { +// +// assertTrue(_consumer1.receive() != null); +// } +// +// for (int msg = 0; msg < MSG_COUNT / 2; msg++) +// { +// assertTrue(_consumer2.receive() != null); +// } +// } - public void testRecieveC1thenC2() throws Exception + public void testRecieveInterleaved() throws Exception { - - for (int msg = 0; msg < MSG_COUNT / 2; msg++) + int msg = 0; + int MAX_LOOPS = MSG_COUNT * 2; + for (int loops = 0; msg < MSG_COUNT || loops < MAX_LOOPS; loops++) { - assertTrue(_consumer1.receive() != null); - } - - for (int msg = 0; msg < MSG_COUNT / 2; msg++) - { - assertTrue(_consumer2.receive() != null); + if (_consumer1.receive(100) != null) + { + msg++; + } + if (_consumer2.receive(100) != null) + { + msg++; + } } - } - - public void testRecieveInterleaved() throws Exception - { - for (int msg = 0; msg < MSG_COUNT / 2; msg++) - { - assertTrue(_consumer1.receive() != null); - assertTrue(_consumer2.receive() != null); - } + assertEquals("Not all messages received.", MSG_COUNT, msg); } @@ -161,7 +171,7 @@ public class MessageListenerMultiConsumerTest extends TestCase if (receivedCount1 == MSG_COUNT / 2) { - _allMessagesSent.countDown(); + _allMessagesSent.countDown(); } } @@ -196,6 +206,18 @@ public class MessageListenerMultiConsumerTest extends TestCase assertEquals(MSG_COUNT, receivedCount1 + receivedCount2); } + public void testRecieveC2Only_OnlyRunWith_REGISTER_CONSUMERS_FLOWED() throws Exception + { + if (Boolean.parseBoolean(System.getProperties().getProperty("REGISTER_CONSUMERS_FLOWED", "false"))) + { + for (int msg = 0; msg < MSG_COUNT; msg++) + { + assertTrue(MSG_COUNT + " msg should be received. Only received:" + msg, + _consumer2.receive(1000) != null); + } + } + } + public static junit.framework.Test suite() { diff --git a/qpid/java/client/src/test/java/org/apache/qpid/client/MessageListenerTest.java b/qpid/java/client/src/test/java/org/apache/qpid/client/MessageListenerTest.java index 5fb77af4db..7b5957ac8c 100644 --- a/qpid/java/client/src/test/java/org/apache/qpid/client/MessageListenerTest.java +++ b/qpid/java/client/src/test/java/org/apache/qpid/client/MessageListenerTest.java @@ -144,6 +144,36 @@ public class MessageListenerTest extends TestCase implements MessageListener } + public void testRecieveTheUseMessageListener() throws Exception + { + + _logger.error("Test disabled as initial receive is not called first"); + // Perform initial receive to start connection +// assertTrue(_consumer.receive(2000) != null); +// receivedCount++; + + // Sleep to ensure remaining 4 msgs end up on _synchronousQueue +// Thread.sleep(1000); + + // Set the message listener and wait for the messages to come in. + _consumer.setMessageListener(this); + + _logger.info("Waiting 3 seconds for messages"); + + try + { + _awaitMessages.await(3000, TimeUnit.MILLISECONDS); + } + catch (InterruptedException e) + { + //do nothing + } + //Should have recieved all async messages + assertEquals(MSG_COUNT, receivedCount); + + } + + public void onMessage(Message message) { _logger.info("Received Message(" + receivedCount + "):" + message); diff --git a/qpid/java/client/src/test/java/org/apache/qpid/client/ResetMessageListenerTest.java b/qpid/java/client/src/test/java/org/apache/qpid/client/ResetMessageListenerTest.java index 10bf1a8d6d..42594fff8e 100644 --- a/qpid/java/client/src/test/java/org/apache/qpid/client/ResetMessageListenerTest.java +++ b/qpid/java/client/src/test/java/org/apache/qpid/client/ResetMessageListenerTest.java @@ -83,7 +83,7 @@ public class ResetMessageListenerTest extends TestCase Hashtable<String, String> env = new Hashtable<String, String>(); env.put("connectionfactory.connection", "amqp://guest:guest@MLT_ID/test?brokerlist='vm://:1'"); - env.put("queue.queue", "direct://amq.direct//MessageListenerTest"); + env.put("queue.queue", "direct://amq.direct//ResetMessageListenerTest"); _context = factory.getInitialContext(env); diff --git a/qpid/java/client/src/test/java/org/apache/qpid/test/unit/basic/InvalidDestinationTest.java b/qpid/java/client/src/test/java/org/apache/qpid/test/unit/basic/InvalidDestinationTest.java new file mode 100644 index 0000000000..1b5da2631d --- /dev/null +++ b/qpid/java/client/src/test/java/org/apache/qpid/test/unit/basic/InvalidDestinationTest.java @@ -0,0 +1,109 @@ +package org.apache.qpid.test.unit.basic;
+
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQDestination;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.client.AMQQueue;
+import org.apache.qpid.client.vmbroker.AMQVMBrokerCreationException;
+import org.apache.qpid.client.transport.TransportConnection;
+
+import junit.framework.TestCase;
+
+import javax.jms.MessageConsumer;
+import javax.jms.Session;
+import javax.jms.QueueSession;
+import javax.jms.Queue;
+import javax.jms.QueueSender;
+import javax.jms.TextMessage;
+import javax.jms.InvalidDestinationException;
+
+public class InvalidDestinationTest extends TestCase
+{
+ private AMQConnection _connection;
+ private AMQDestination _destination;
+ private AMQSession _session;
+ private MessageConsumer _consumer;
+
+ private static final String VM_BROKER = "vm://:1";
+
+
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ createVMBroker();
+ _connection = new AMQConnection(VM_BROKER, "guest", "guest", "ReceiveTestClient", "test");
+ }
+
+ public void createVMBroker()
+ {
+ try
+ {
+ TransportConnection.createVMBroker(1);
+ }
+ catch (AMQVMBrokerCreationException e)
+ {
+ fail("Unable to create broker: " + e);
+ }
+ }
+
+ protected void tearDown() throws Exception
+ {
+ _connection.close();
+ TransportConnection.killVMBroker(1);
+ super.tearDown();
+ }
+
+
+
+ public void testInvalidDestination() throws Exception
+ {
+ Queue invalidDestination = new AMQQueue("amq.direct","unknownQ");
+ AMQQueue validDestination = new AMQQueue("amq.direct","knownQ");
+ QueueSession queueSession = _connection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ // This is the only easy way to create and bind a queue from the API :-(
+ MessageConsumer consumer = queueSession.createConsumer(validDestination);
+
+ QueueSender sender = queueSession.createSender(invalidDestination);
+ TextMessage msg = queueSession.createTextMessage("Hello");
+ try
+ {
+ sender.send(msg);
+ fail("Expected InvalidDestinationException");
+ }
+ catch (InvalidDestinationException ex)
+ {
+ // pass
+ }
+ sender.close();
+
+ sender = queueSession.createSender(null);
+ invalidDestination = new AMQQueue("amq.direct","unknownQ");
+
+ try
+ {
+ sender.send(invalidDestination,msg);
+ fail("Expected InvalidDestinationException");
+ }
+ catch (InvalidDestinationException ex)
+ {
+ // pass
+ }
+ sender.send(validDestination,msg);
+ sender.close();
+ validDestination = new AMQQueue("amq.direct","knownQ");
+ sender = queueSession.createSender(validDestination);
+ sender.send(msg);
+
+
+
+
+ }
+
+
+ public static junit.framework.Test suite()
+ {
+
+ return new junit.framework.TestSuite(InvalidDestinationTest.class);
+ }
+}
diff --git a/qpid/java/client/src/test/java/org/apache/qpid/test/unit/close/MessageRequeueTest.java b/qpid/java/client/src/test/java/org/apache/qpid/test/unit/close/MessageRequeueTest.java index 7762cb3fe9..62234ad21f 100644 --- a/qpid/java/client/src/test/java/org/apache/qpid/test/unit/close/MessageRequeueTest.java +++ b/qpid/java/client/src/test/java/org/apache/qpid/test/unit/close/MessageRequeueTest.java @@ -330,7 +330,7 @@ public class MessageRequeueTest extends TestCase public void testRequeue() throws JMSException, AMQException, URLSyntaxException { int run = 0; - while (run < 10) +// while (run < 10) { run++; @@ -350,17 +350,10 @@ public class MessageRequeueTest extends TestCase _logger.debug("Create Consumer"); MessageConsumer consumer = session.createConsumer(q); - try - { - Thread.sleep(2000); - } - catch (InterruptedException e) - { - // - } + conn.start(); _logger.debug("Receiving msg"); - Message msg = consumer.receive(1000); + Message msg = consumer.receive(2000); assertNotNull("Message should not be null", msg); diff --git a/qpid/java/client/src/test/java/org/apache/qpid/test/unit/topic/DurableSubscriptionTest.java b/qpid/java/client/src/test/java/org/apache/qpid/test/unit/topic/DurableSubscriptionTest.java index 0828ab398c..190b3861f0 100644 --- a/qpid/java/client/src/test/java/org/apache/qpid/test/unit/topic/DurableSubscriptionTest.java +++ b/qpid/java/client/src/test/java/org/apache/qpid/test/unit/topic/DurableSubscriptionTest.java @@ -100,7 +100,9 @@ public class DurableSubscriptionTest extends TestCase AMQTopic topic = new AMQTopic(con,"MyTopic"); Session session1 = con.createSession(false, AMQSession.NO_ACKNOWLEDGE); MessageConsumer consumer1 = session1.createConsumer(topic); - MessageProducer producer = session1.createProducer(topic); + + Session sessionProd = con.createSession(false, AMQSession.NO_ACKNOWLEDGE); + MessageProducer producer = sessionProd.createProducer(topic); Session session2 = con.createSession(false, AMQSession.NO_ACKNOWLEDGE); TopicSubscriber consumer2 = session2.createDurableSubscriber(topic, "MySubscription"); @@ -112,12 +114,12 @@ public class DurableSubscriptionTest extends TestCase Message msg; msg = consumer1.receive(); assertEquals("A", ((TextMessage) msg).getText()); - msg = consumer1.receive(1000); + msg = consumer1.receive(100); assertEquals(null, msg); msg = consumer2.receive(); assertEquals("A", ((TextMessage) msg).getText()); - msg = consumer2.receive(1000); + msg = consumer2.receive(100); assertEquals(null, msg); consumer2.close(); @@ -127,14 +129,14 @@ public class DurableSubscriptionTest extends TestCase producer.send(session1.createTextMessage("B")); - msg = consumer1.receive(); + msg = consumer1.receive(100); assertEquals("B", ((TextMessage) msg).getText()); - msg = consumer1.receive(1000); + msg = consumer1.receive(100); assertEquals(null, msg); - msg = consumer3.receive(); + msg = consumer3.receive(100); assertEquals("B", ((TextMessage) msg).getText()); - msg = consumer3.receive(1000); + msg = consumer3.receive(100); assertEquals(null, msg); con.close(); diff --git a/qpid/java/client/src/test/java/org/apache/qpid/test/unit/transacted/CommitRollbackTest.java b/qpid/java/client/src/test/java/org/apache/qpid/test/unit/transacted/CommitRollbackTest.java index 2abc139ced..685fe20048 100644 --- a/qpid/java/client/src/test/java/org/apache/qpid/test/unit/transacted/CommitRollbackTest.java +++ b/qpid/java/client/src/test/java/org/apache/qpid/test/unit/transacted/CommitRollbackTest.java @@ -53,12 +53,15 @@ public class CommitRollbackTest extends TestCase Queue _jmsQueue; private static final Logger _logger = Logger.getLogger(CommitRollbackTest.class); + private static final String BROKER = "vm://:1"; protected void setUp() throws Exception { super.setUp(); - TransportConnection.createVMBroker(1); - + if (BROKER.startsWith("vm")) + { + TransportConnection.createVMBroker(1); + } testMethod++; queue += testMethod; @@ -68,7 +71,7 @@ public class CommitRollbackTest extends TestCase private void newConnection() throws AMQException, URLSyntaxException, JMSException { - conn = new AMQConnection("amqp://guest:guest@client/test?brokerlist='vm://:1'"); + conn = new AMQConnection("amqp://guest:guest@client/test?brokerlist='" + BROKER + "'"); _session = conn.createSession(true, Session.CLIENT_ACKNOWLEDGE); @@ -87,7 +90,10 @@ public class CommitRollbackTest extends TestCase super.tearDown(); conn.close(); - TransportConnection.killVMBroker(1); + if (BROKER.startsWith("vm")) + { + TransportConnection.killVMBroker(1); + } } /** @@ -261,7 +267,7 @@ public class CommitRollbackTest extends TestCase assertTrue("session is not transacted", _pubSession.getTransacted()); _logger.info("sending test message"); - String MESSAGE_TEXT = "testGetThenDisconnect"; + String MESSAGE_TEXT = "testGetThenRollback"; _publisher.send(_pubSession.createTextMessage(MESSAGE_TEXT)); _pubSession.commit(); @@ -394,16 +400,60 @@ public class CommitRollbackTest extends TestCase _logger.info("receiving result"); result = _consumer.receive(1000); assertNotNull("test message was consumed and rolled back, but is gone", result); - assertEquals("1", ((TextMessage) result).getText()); - assertTrue("Messasge is not marked as redelivered" + result, result.getJMSRedelivered()); - - result = _consumer.receive(1000); - assertNotNull("test message was consumed and rolled back, but is gone", result); - assertEquals("2", ((TextMessage) result).getText()); - assertTrue("Messasge is not marked as redelivered" + result, result.getJMSRedelivered()); - + if (result.getJMSRedelivered()) + { + assertEquals("1", ((TextMessage) result).getText()); + + result = _consumer.receive(1000); + assertNotNull("test message was consumed and rolled back, but is gone", result); + assertEquals("2", ((TextMessage) result).getText()); + assertTrue("Messasge is not marked as redelivered" + result, result.getJMSRedelivered()); + } + else + { + assertEquals("2", ((TextMessage) result).getText()); + assertTrue("Messasge is marked as redelivered" + result, !result.getJMSRedelivered()); + + result = _consumer.receive(1000); + assertNotNull("test message was consumed and rolled back, but is gone", result); + assertEquals("1", ((TextMessage) result).getText()); + assertTrue("Messasge is not marked as redelivered" + result, result.getJMSRedelivered()); + + } result = _consumer.receive(1000); assertNull("test message should be null:" + result, result); + + } + + + public void testPutThenRollbackThenGet() throws Exception + { + assertTrue("session is not transacted", _session.getTransacted()); + assertTrue("session is not transacted", _pubSession.getTransacted()); + + _logger.info("sending test message"); + String MESSAGE_TEXT = "testPutThenRollbackThenGet"; + + _publisher.send(_pubSession.createTextMessage(MESSAGE_TEXT)); + _pubSession.commit(); + + assertNotNull(_consumer.receive(100)); + + _publisher.send(_pubSession.createTextMessage(MESSAGE_TEXT)); + + _logger.info("rolling back"); + _pubSession.rollback(); + + _logger.info("receiving result"); + Message result = _consumer.receive(1000); + assertNull("test message was put and rolled back, but is still present", result); + + _publisher.send(_pubSession.createTextMessage(MESSAGE_TEXT)); + + _pubSession.commit(); + + assertNotNull(_consumer.receive(100)); + } } diff --git a/qpid/java/client/src/test/java/org/apache/qpid/testutil/Config.java b/qpid/java/client/src/test/java/org/apache/qpid/testutil/Config.java index 8109d20a33..b777cf93b6 100644 --- a/qpid/java/client/src/test/java/org/apache/qpid/testutil/Config.java +++ b/qpid/java/client/src/test/java/org/apache/qpid/testutil/Config.java @@ -172,7 +172,7 @@ public class Config } catch(NumberFormatException e) { - throw new RuntimeException("Bad port number: " + value); + throw new RuntimeException("Bad port number: " + value, e); } } else if("-name".equalsIgnoreCase(key)) diff --git a/qpid/java/client/src/test/java/org/apache/qpid/testutil/QpidClientConnection.java b/qpid/java/client/src/test/java/org/apache/qpid/testutil/QpidClientConnection.java index f2afa472ab..195ed79dab 100644 --- a/qpid/java/client/src/test/java/org/apache/qpid/testutil/QpidClientConnection.java +++ b/qpid/java/client/src/test/java/org/apache/qpid/testutil/QpidClientConnection.java @@ -3,6 +3,7 @@ package org.apache.qpid.testutil; import org.apache.qpid.client.AMQConnectionFactory; import org.apache.qpid.client.AMQConnectionURL; import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.JMSAMQException; import org.apache.qpid.url.URLSyntaxException; import org.apache.log4j.Logger; @@ -70,7 +71,7 @@ public class QpidClientConnection implements ExceptionListener } catch (URLSyntaxException e) { - throw new JMSException("URL syntax error in [" + brokerUrl + "]: " + e.getMessage()); + throw new JMSAMQException("URL syntax error in [" + brokerUrl + "]: " + e.getMessage(), e); } } } diff --git a/qpid/java/common/bin/qpid-run b/qpid/java/common/bin/qpid-run index 6d7837c120..fe8fd0e9cc 100644 --- a/qpid/java/common/bin/qpid-run +++ b/qpid/java/common/bin/qpid-run @@ -106,15 +106,20 @@ usage() { export EXTERNAL_CLASSPATH=$CLASSPATH unset CLASSPATH -conf=$QPID_HOME/etc/$program.conf -if [ ! -e $conf ]; then - conf=$QPID_HOME/etc/$(basename ${sourced}).conf +#Use QPID_CLASSPATH if set +if [ -n "$QPID_CLASSPATH" ]; then + export CLASSPATH=$QPID_CLASSPATH + echo "Using QPID_CLASSPATH" $QPID_CLASSPATH +else + echo "Warning: Qpid classpath not set. CLASSPATH must include qpid jars." fi -if [ -r $conf ]; then - . $conf +#Use QPID_JAVA_MEM if set +if [ -n "$QPID_JAVA_MEM" ]; then + export JAVA_MEM=$QPID_JAVA_MEM + echo "Using QPID_JAVA_MEM setting" $QPID_JAVA_MEM else - die "unable to source $conf" + echo "Info: QPID_JAVA_MEM not set. Defaulting to JAVA_MEM" $JAVA_MEM fi declare -a RUN_ARGS JAVA_ARGS diff --git a/qpid/java/common/src/main/java/org/apache/qpid/AMQException.java b/qpid/java/common/src/main/java/org/apache/qpid/AMQException.java index 0222fd9b4e..3e93243a1d 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/AMQException.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/AMQException.java @@ -23,11 +23,41 @@ package org.apache.qpid; import org.apache.log4j.Logger; import org.apache.qpid.protocol.AMQConstant; -/** Generic AMQ exception. */ +/** + * AMQException forms the root exception of all exceptions relating to the AMQ protocol. It provides space to associate + * an AMQ error code with the exception, which is a numberic value, with a meaning defined by the protocol. + * + * <p/><table id="crc"><caption>CRC Card</caption> + * <tr><th> Responsibilities <th> Collaborations + * <tr><td> Represents an exception condition associated with an AMQ protocol error code. + * </table> + * + * @todo This exception class is also used as a generic exception throughout Qpid code. This usage may not be strictly + * correct if this is to signify a protocol exception. Should review. + */ public class AMQException extends Exception { + /** Holds the AMQ error code constant associated with this exception. */ private AMQConstant _errorCode; + /** + * Creates an exception with an optional error code, optional message and optional underlying cause. + * + * @param errorCode The error code. May be null if not to be set. + * @param msg The exception message. May be null if not to be set. + * @param t The underlying cause of the exception. May be null if not to be set. + */ + public AMQException(AMQConstant errorCode, String msg, Throwable t) + { + super(((msg == null) ? "" : msg) + ((errorCode == null) ? "" : (" [error code " + errorCode + "]")), t); + _errorCode = errorCode; + } + + /** + * @param message + * + * @deprecated Use {@link #AMQException(org.apache.qpid.protocol.AMQConstant, String, Throwable)} instead. + */ public AMQException(String message) { super(message); @@ -35,6 +65,12 @@ public class AMQException extends Exception _errorCode = AMQConstant.getConstant(-1); } + /** + * @param msg + * @param t + * + * @deprecated Use {@link #AMQException(org.apache.qpid.protocol.AMQConstant, String, Throwable)} instead. + */ public AMQException(String msg, Throwable t) { super(msg, t); @@ -42,18 +78,19 @@ public class AMQException extends Exception _errorCode = AMQConstant.getConstant(-1); } - public AMQException(AMQConstant errorCode, String msg, Throwable t) - { - super(msg + " [error code " + errorCode + ']', t); - _errorCode = errorCode; - } - + /** + * @param errorCode + * @param msg + * + * @deprecated Use {@link #AMQException(org.apache.qpid.protocol.AMQConstant, String, Throwable)} instead. + */ public AMQException(AMQConstant errorCode, String msg) { super(msg + " [error code " + errorCode + ']'); _errorCode = errorCode; } + /* public AMQException(Logger logger, String msg, Throwable t) { this(msg, t); @@ -71,10 +108,15 @@ public class AMQException extends Exception this(errorCode, msg); logger.error(getMessage(), this); } + */ + /** + * Gets the AMQ protocol exception code associated with this exception. + * + * @return The AMQ protocol exception code associated with this exception. + */ public AMQConstant getErrorCode() { return _errorCode; } - } diff --git a/qpid/java/common/src/main/java/org/apache/qpid/configuration/PropertyException.java b/qpid/java/common/src/main/java/org/apache/qpid/configuration/PropertyException.java index 958f59191f..7c85a08e11 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/configuration/PropertyException.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/configuration/PropertyException.java @@ -1,3 +1,4 @@ +/* Copyright Rupert Smith, 2005 to 2006, all rights reserved. */ /* * * Licensed to the Apache Software Foundation (ASF) under one @@ -7,9 +8,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 @@ -21,6 +22,7 @@ package org.apache.qpid.configuration; import org.apache.log4j.Logger; + import org.apache.qpid.AMQException; import org.apache.qpid.protocol.AMQConstant; @@ -49,7 +51,7 @@ public class PropertyException extends AMQException super(errorCode, msg); } - public PropertyException(Logger logger, String msg, Throwable t) + /*public PropertyException(Logger logger, String msg, Throwable t) { super(logger, msg, t); } @@ -62,5 +64,5 @@ public class PropertyException extends AMQException public PropertyException(Logger logger, AMQConstant errorCode, String msg) { super(logger, errorCode, msg); - } + }*/ } diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQDataBlockDecoder.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQDataBlockDecoder.java index 43f888c029..9f36448986 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQDataBlockDecoder.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQDataBlockDecoder.java @@ -94,7 +94,7 @@ public class AMQDataBlockDecoder if(bodyFactory == null) { - throw new AMQFrameDecodingException("Unsupported frame type: " + type); + throw new AMQFrameDecodingException(null, "Unsupported frame type: " + type, null); } final int channel = in.getUnsignedShort(); @@ -103,8 +103,8 @@ public class AMQDataBlockDecoder // bodySize can be zero if (channel < 0 || bodySize < 0) { - throw new AMQFrameDecodingException("Undecodable frame: type = " + type + " channel = " + channel + - " bodySize = " + bodySize); + throw new AMQFrameDecodingException(null, "Undecodable frame: type = " + type + " channel = " + channel + + " bodySize = " + bodySize, null); } AMQFrame frame = new AMQFrame(in, channel, bodySize, bodyFactory); @@ -113,7 +113,7 @@ public class AMQDataBlockDecoder byte marker = in.get(); if ((marker & 0xFF) != 0xCE) { - throw new AMQFrameDecodingException("End of frame marker not found. Read " + marker + " length=" + bodySize + " type=" + type); + throw new AMQFrameDecodingException(null, "End of frame marker not found. Read " + marker + " length=" + bodySize + " type=" + type, null); } return frame; } diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQFrameDecodingException.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQFrameDecodingException.java index a24bd6aaa9..c462dec2a3 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQFrameDecodingException.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQFrameDecodingException.java @@ -1,3 +1,4 @@ +/* Copyright Rupert Smith, 2005 to 2006, all rights reserved. */ /* * * Licensed to the Apache Software Foundation (ASF) under one @@ -7,9 +8,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 @@ -21,21 +22,23 @@ package org.apache.qpid.framing; import org.apache.log4j.Logger; + import org.apache.qpid.AMQException; +import org.apache.qpid.protocol.AMQConstant; public class AMQFrameDecodingException extends AMQException { - public AMQFrameDecodingException(String message) + /*public AMQFrameDecodingException(String message) { super(message); - } + }*/ - public AMQFrameDecodingException(String message, Throwable t) + public AMQFrameDecodingException(AMQConstant errorCode, String message, Throwable t) { - super(message, t); + super(errorCode, message, t); } - public AMQFrameDecodingException(Logger log, String message) + /*public AMQFrameDecodingException(Logger log, String message) { super(log, message); } @@ -43,6 +46,5 @@ public class AMQFrameDecodingException extends AMQException public AMQFrameDecodingException(Logger log, String message, Throwable t) { super(log, message, t); - } - + }*/ } diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQShortString.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQShortString.java index f51296dafc..f2492585bc 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQShortString.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQShortString.java @@ -9,7 +9,7 @@ import org.apache.mina.common.ByteBuffer; * and thus can be held more effectively in a byte buffer.
*
*/
-public final class AMQShortString implements CharSequence
+public final class AMQShortString implements CharSequence, Comparable<AMQShortString>
{
private static final Logger _logger = Logger.getLogger(AMQShortString.class);
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/BasicContentHeaderProperties.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/BasicContentHeaderProperties.java index 8b784fa3f7..008afb490e 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/framing/BasicContentHeaderProperties.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/BasicContentHeaderProperties.java @@ -341,7 +341,7 @@ public class BasicContentHeaderProperties implements CommonContentHeaderProperti } catch (AMQFrameDecodingException e) { - throw new RuntimeException("Error in content header data: " + e); + throw new RuntimeException("Error in content header data: " + e, e); } final int endPos = buffer.position(); @@ -381,7 +381,7 @@ public class BasicContentHeaderProperties implements CommonContentHeaderProperti } catch (AMQFrameDecodingException e) { - throw new RuntimeException("Error in content header data: " + e); + throw new RuntimeException("Error in content header data: " + e, e); } } diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/ContentHeaderPropertiesFactory.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/ContentHeaderPropertiesFactory.java index 7dac018872..712eb437db 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/framing/ContentHeaderPropertiesFactory.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/ContentHeaderPropertiesFactory.java @@ -49,7 +49,7 @@ public class ContentHeaderPropertiesFactory } else { - throw new AMQFrameDecodingException("Unsupport content header class id: " + classId); + throw new AMQFrameDecodingException(null, "Unsupport content header class id: " + classId, null); } properties.populatePropertiesFromBuffer(buffer, propertyFlags, size); return properties; diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/EncodingUtils.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/EncodingUtils.java index f94cd4934c..f0cdda487c 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/framing/EncodingUtils.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/EncodingUtils.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 @@ -23,6 +23,7 @@ package org.apache.qpid.framing; import java.nio.charset.Charset; import org.apache.log4j.Logger; + import org.apache.mina.common.ByteBuffer; public class EncodingUtils @@ -49,96 +50,95 @@ public class EncodingUtils } } - public static int encodedShortStringLength(short s) { - if( s == 0 ) + if (s == 0) { return 1 + 1; } int len = 0; - if(s < 0) + if (s < 0) { - len=1; + len = 1; // sloppy - doesn't work of Integer.MIN_VALUE - s=(short)-s; + s = (short) -s; } - if(s>9999) + if (s > 9999) { - return 1+5; + return 1 + 5; } - else if(s>999) + else if (s > 999) { - return 1+4; + return 1 + 4; } - else if(s>99) + else if (s > 99) { - return 1+3; + return 1 + 3; } - else if(s>9) + else if (s > 9) { - return 1+2; + return 1 + 2; } else { - return 1+1; + return 1 + 1; } } - public static int encodedShortStringLength(int i) { - if( i == 0 ) + if (i == 0) { return 1 + 1; } int len = 0; - if(i < 0) + if (i < 0) { - len=1; + len = 1; // sloppy - doesn't work of Integer.MIN_VALUE - i=-i; + i = -i; } // range is now 1 - 2147483647 - if(i < Short.MAX_VALUE) + if (i < Short.MAX_VALUE) { - return len + encodedShortStringLength((short)i); + return len + encodedShortStringLength((short) i); } else if (i > 999999) { - return len + 6 + encodedShortStringLength((short)(i/1000000)); + return len + 6 + encodedShortStringLength((short) (i / 1000000)); } else // if (i > 99999) { - return len + 5 + encodedShortStringLength((short)(i/100000)); + return len + 5 + encodedShortStringLength((short) (i / 100000)); } } public static int encodedShortStringLength(long l) { - if(l == 0) + if (l == 0) { return 1 + 1; } int len = 0; - if(l < 0) + if (l < 0) { - len=1; + len = 1; // sloppy - doesn't work of Long.MIN_VALUE - l=-l; + l = -l; } - if(l < Integer.MAX_VALUE) + + if (l < Integer.MAX_VALUE) { return len + encodedShortStringLength((int) l); } - else if(l > 9999999999L) + else if (l > 9999999999L) { return len + 10 + encodedShortStringLength((int) (l / 10000000000L)); } @@ -149,7 +149,6 @@ public class EncodingUtils } - public static int encodedShortStringLength(AMQShortString s) { if (s == null) @@ -162,7 +161,6 @@ public class EncodingUtils } } - public static int encodedLongStringLength(String s) { if (s == null) @@ -219,7 +217,6 @@ public class EncodingUtils return 0; } - public static void writeShortStringBytes(ByteBuffer buffer, String s) { if (s != null) @@ -230,6 +227,7 @@ public class EncodingUtils { encodedString[i] = (byte) cha[i]; } + writeBytes(buffer, encodedString); } else @@ -239,7 +237,6 @@ public class EncodingUtils } } - public static void writeShortStringBytes(ByteBuffer buffer, AMQShortString s) { if (s != null) @@ -256,7 +253,7 @@ public class EncodingUtils public static void writeLongStringBytes(ByteBuffer buffer, String s) { - assert s == null || s.length() <= 0xFFFE; + assert (s == null) || (s.length() <= 0xFFFE); if (s != null) { int len = s.length(); @@ -267,6 +264,7 @@ public class EncodingUtils { encodedString[i] = (byte) cha[i]; } + buffer.put(encodedString); } else @@ -277,7 +275,7 @@ public class EncodingUtils public static void writeLongStringBytes(ByteBuffer buffer, char[] s) { - assert s == null || s.length <= 0xFFFE; + assert (s == null) || (s.length <= 0xFFFE); if (s != null) { int len = s.length; @@ -287,6 +285,7 @@ public class EncodingUtils { encodedString[i] = (byte) s[i]; } + buffer.put(encodedString); } else @@ -297,7 +296,7 @@ public class EncodingUtils public static void writeLongStringBytes(ByteBuffer buffer, byte[] bytes) { - assert bytes == null || bytes.length <= 0xFFFE; + assert (bytes == null) || (bytes.length <= 0xFFFE); if (bytes != null) { writeUnsignedInteger(buffer, bytes.length); @@ -330,7 +329,6 @@ public class EncodingUtils } } - public static int unsignedIntegerLength() { return 4; @@ -356,7 +354,6 @@ public class EncodingUtils } } - public static void writeFieldTableBytes(ByteBuffer buffer, FieldTable table) { if (table != null) @@ -400,10 +397,9 @@ public class EncodingUtils if (value1) { - packedValue = (byte) (packedValue | (byte)(1 << 1)); + packedValue = (byte) (packedValue | (byte) (1 << 1)); } - buffer.put(packedValue); } @@ -413,213 +409,181 @@ public class EncodingUtils if (value1) { - packedValue = (byte) (packedValue | (byte)(1 << 1)); + packedValue = (byte) (packedValue | (byte) (1 << 1)); } if (value2) { - packedValue = (byte) (packedValue | (byte)(1 << 2)); + packedValue = (byte) (packedValue | (byte) (1 << 2)); } - buffer.put(packedValue); } - - - public static void writeBooleans(ByteBuffer buffer, - boolean value0, - boolean value1, - boolean value2, - boolean value3) + public static void writeBooleans(ByteBuffer buffer, boolean value0, boolean value1, boolean value2, boolean value3) { byte packedValue = value0 ? (byte) 1 : (byte) 0; if (value1) { - packedValue = (byte) (packedValue | (byte)(1 << 1)); + packedValue = (byte) (packedValue | (byte) (1 << 1)); } if (value2) { - packedValue = (byte) (packedValue | (byte)(1 << 2)); + packedValue = (byte) (packedValue | (byte) (1 << 2)); } if (value3) { - packedValue = (byte) (packedValue | (byte)(1 << 3)); + packedValue = (byte) (packedValue | (byte) (1 << 3)); } buffer.put(packedValue); } - public static void writeBooleans(ByteBuffer buffer, - boolean value0, - boolean value1, - boolean value2, - boolean value3, - boolean value4) + public static void writeBooleans(ByteBuffer buffer, boolean value0, boolean value1, boolean value2, boolean value3, + boolean value4) { byte packedValue = value0 ? (byte) 1 : (byte) 0; if (value1) { - packedValue = (byte) (packedValue | (byte)(1 << 1)); + packedValue = (byte) (packedValue | (byte) (1 << 1)); } if (value2) { - packedValue = (byte) (packedValue | (byte)(1 << 2)); + packedValue = (byte) (packedValue | (byte) (1 << 2)); } if (value3) { - packedValue = (byte) (packedValue | (byte)(1 << 3)); + packedValue = (byte) (packedValue | (byte) (1 << 3)); } if (value4) { - packedValue = (byte) (packedValue | (byte)(1 << 4)); + packedValue = (byte) (packedValue | (byte) (1 << 4)); } buffer.put(packedValue); } - public static void writeBooleans(ByteBuffer buffer, - boolean value0, - boolean value1, - boolean value2, - boolean value3, - boolean value4, - boolean value5) + public static void writeBooleans(ByteBuffer buffer, boolean value0, boolean value1, boolean value2, boolean value3, + boolean value4, boolean value5) { byte packedValue = value0 ? (byte) 1 : (byte) 0; if (value1) { - packedValue = (byte) (packedValue | (byte)(1 << 1)); + packedValue = (byte) (packedValue | (byte) (1 << 1)); } if (value2) { - packedValue = (byte) (packedValue | (byte)(1 << 2)); + packedValue = (byte) (packedValue | (byte) (1 << 2)); } if (value3) { - packedValue = (byte) (packedValue | (byte)(1 << 3)); + packedValue = (byte) (packedValue | (byte) (1 << 3)); } if (value4) { - packedValue = (byte) (packedValue | (byte)(1 << 4)); + packedValue = (byte) (packedValue | (byte) (1 << 4)); } if (value5) { - packedValue = (byte) (packedValue | (byte)(1 << 5)); + packedValue = (byte) (packedValue | (byte) (1 << 5)); } buffer.put(packedValue); } - public static void writeBooleans(ByteBuffer buffer, - boolean value0, - boolean value1, - boolean value2, - boolean value3, - boolean value4, - boolean value5, - boolean value6) + public static void writeBooleans(ByteBuffer buffer, boolean value0, boolean value1, boolean value2, boolean value3, + boolean value4, boolean value5, boolean value6) { byte packedValue = value0 ? (byte) 1 : (byte) 0; if (value1) { - packedValue = (byte) (packedValue | (byte)(1 << 1)); + packedValue = (byte) (packedValue | (byte) (1 << 1)); } if (value2) { - packedValue = (byte) (packedValue | (byte)(1 << 2)); + packedValue = (byte) (packedValue | (byte) (1 << 2)); } if (value3) { - packedValue = (byte) (packedValue | (byte)(1 << 3)); + packedValue = (byte) (packedValue | (byte) (1 << 3)); } if (value4) { - packedValue = (byte) (packedValue | (byte)(1 << 4)); + packedValue = (byte) (packedValue | (byte) (1 << 4)); } if (value5) { - packedValue = (byte) (packedValue | (byte)(1 << 5)); + packedValue = (byte) (packedValue | (byte) (1 << 5)); } if (value6) { - packedValue = (byte) (packedValue | (byte)(1 << 6)); + packedValue = (byte) (packedValue | (byte) (1 << 6)); } buffer.put(packedValue); } - public static void writeBooleans(ByteBuffer buffer, - boolean value0, - boolean value1, - boolean value2, - boolean value3, - boolean value4, - boolean value5, - boolean value6, - boolean value7) + public static void writeBooleans(ByteBuffer buffer, boolean value0, boolean value1, boolean value2, boolean value3, + boolean value4, boolean value5, boolean value6, boolean value7) { byte packedValue = value0 ? (byte) 1 : (byte) 0; if (value1) { - packedValue = (byte) (packedValue | (byte)(1 << 1)); + packedValue = (byte) (packedValue | (byte) (1 << 1)); } if (value2) { - packedValue = (byte) (packedValue | (byte)(1 << 2)); + packedValue = (byte) (packedValue | (byte) (1 << 2)); } if (value3) { - packedValue = (byte) (packedValue | (byte)(1 << 3)); + packedValue = (byte) (packedValue | (byte) (1 << 3)); } if (value4) { - packedValue = (byte) (packedValue | (byte)(1 << 4)); + packedValue = (byte) (packedValue | (byte) (1 << 4)); } if (value5) { - packedValue = (byte) (packedValue | (byte)(1 << 5)); + packedValue = (byte) (packedValue | (byte) (1 << 5)); } if (value6) { - packedValue = (byte) (packedValue | (byte)(1 << 6)); + packedValue = (byte) (packedValue | (byte) (1 << 6)); } if (value7) { - packedValue = (byte) (packedValue | (byte)(1 << 7)); + packedValue = (byte) (packedValue | (byte) (1 << 7)); } buffer.put(packedValue); } - - - /** * This is used for writing longstrs. * @@ -647,26 +611,27 @@ public class EncodingUtils public static boolean[] readBooleans(ByteBuffer buffer) { final byte packedValue = buffer.get(); - if(packedValue == 0) + if (packedValue == 0) { return ALL_FALSE_ARRAY; } + final boolean[] result = new boolean[8]; result[0] = ((packedValue & 1) != 0); result[1] = ((packedValue & (1 << 1)) != 0); result[2] = ((packedValue & (1 << 2)) != 0); result[3] = ((packedValue & (1 << 3)) != 0); - if((packedValue & 0xF0) == 0) + if ((packedValue & 0xF0) == 0) { result[0] = ((packedValue & 1) != 0); } + result[4] = ((packedValue & (1 << 4)) != 0); result[5] = ((packedValue & (1 << 5)) != 0); result[6] = ((packedValue & (1 << 6)) != 0); result[7] = ((packedValue & (1 << 7)) != 0); - return result; } @@ -742,6 +707,7 @@ public class EncodingUtils { stringChars[i] = (char) stringBytes[i]; } + return new String(stringChars); } } @@ -757,6 +723,7 @@ public class EncodingUtils { byte[] result = new byte[(int) length]; buffer.get(result); + return result; } } @@ -764,15 +731,14 @@ public class EncodingUtils public static long readTimestamp(ByteBuffer buffer) { // Discard msb from AMQ timestamp - //buffer.getUnsignedInt(); + // buffer.getUnsignedInt(); return buffer.getLong(); } - static byte[] hexToByteArray(String id) { // Should check param for null, long enough for this check, upper-case and trailing char - String s = (id.charAt(1) == 'x') ? id.substring(2) : id; // strip 0x + String s = (id.charAt(1) == 'x') ? id.substring(2) : id; // strip 0x int len = s.length(); int byte_len = len / 2; @@ -786,7 +752,7 @@ public class EncodingUtils byte b1 = Byte.parseByte(s.substring(ch, ch + 1), 16); byte b2 = Byte.parseByte(s.substring(ch + 1, ch + 2), 16); - b[i] = (byte) (b1 * 16 + b2); + b[i] = (byte) ((b1 * 16) + b2); } return (b); @@ -795,7 +761,7 @@ public class EncodingUtils public static char[] convertToHexCharArray(byte[] from) { int length = from.length; - char[] result_buff = new char[length * 2 + 2]; + char[] result_buff = new char[(length * 2) + 2]; result_buff[0] = '0'; result_buff[1] = 'x'; @@ -831,7 +797,7 @@ public class EncodingUtils byte[] from = new byte[size]; // Is this not the same. - //bb.get(from, 0, length); + // bb.get(from, 0, length); for (int i = 0; i < size; i++) { from[i] = bb.get(i); @@ -840,9 +806,9 @@ public class EncodingUtils return (new String(convertToHexCharArray(from))); } - private static char hex_chars[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; + private static char[] hex_chars = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; - //**** new methods + // **** new methods // AMQP_BOOLEAN_PROPERTY_PREFIX @@ -854,6 +820,7 @@ public class EncodingUtils public static boolean readBoolean(ByteBuffer buffer) { byte packedValue = buffer.get(); + return (packedValue == 1); } @@ -878,7 +845,6 @@ public class EncodingUtils return 1; } - // AMQP_SHORT_PROPERTY_PREFIX public static void writeShort(ByteBuffer buffer, Short aShort) { @@ -943,7 +909,6 @@ public class EncodingUtils return 4; } - // Double_PROPERTY_PREFIX public static void writeDouble(ByteBuffer buffer, Double aDouble) { @@ -960,7 +925,6 @@ public class EncodingUtils return 8; } - public static byte[] readBytes(ByteBuffer buffer) { short length = buffer.getUnsigned(); @@ -981,7 +945,7 @@ public class EncodingUtils { if (data != null) { - // TODO: check length fits in an unsigned byte + // TODO: check length fits in an unsigned byte writeUnsignedByte(buffer, (short) data.length); buffer.put(data); } @@ -992,7 +956,7 @@ public class EncodingUtils } } - //CHAR_PROPERTY + // CHAR_PROPERTY public static int encodedCharLength() { return encodedByteLength(); @@ -1000,31 +964,29 @@ public class EncodingUtils public static char readChar(ByteBuffer buffer) { - //This is valid as we know that the Character is ASCII 0..127 + // This is valid as we know that the Character is ASCII 0..127 return (char) buffer.get(); } public static void writeChar(ByteBuffer buffer, char character) { - //This is valid as we know that the Character is ASCII 0..127 + // This is valid as we know that the Character is ASCII 0..127 writeByte(buffer, (byte) character); } - - - public static long readLongAsShortString(ByteBuffer buffer) { short length = buffer.getUnsigned(); short pos = 0; - if(length == 0) + if (length == 0) { return 0L; } + byte digit = buffer.get(); boolean isNegative; long result = 0; - if(digit == (byte)'-') + if (digit == (byte) '-') { isNegative = true; pos++; @@ -1034,15 +996,16 @@ public class EncodingUtils { isNegative = false; } - result = digit - (byte)'0'; + + result = digit - (byte) '0'; pos++; - while(pos < length) + while (pos < length) { pos++; digit = buffer.get(); result = (result << 3) + (result << 1); - result += digit - (byte)'0'; + result += digit - (byte) '0'; } return result; @@ -1051,33 +1014,13 @@ public class EncodingUtils public static long readUnsignedInteger(ByteBuffer buffer) { long l = 0xFF & buffer.get(); - l <<=8; + l <<= 8; l = l | (0xFF & buffer.get()); - l <<=8; + l <<= 8; l = l | (0xFF & buffer.get()); - l <<=8; + l <<= 8; l = l | (0xFF & buffer.get()); return l; } - - - public static void main(String[] args) - { - ByteBuffer buf = ByteBuffer.allocate(8); - buf.setAutoExpand(true); - - long l = (long) Integer.MAX_VALUE; - l += 1024L; - - writeUnsignedInteger(buf, l); - - buf.flip(); - - long l2 = readUnsignedInteger(buf); - - System.out.println("before: " + l); - System.out.println("after: " + l2); - } - } diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/VersionSpecificRegistry.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/VersionSpecificRegistry.java index ec371453aa..faa7cc1e82 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/framing/VersionSpecificRegistry.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/VersionSpecificRegistry.java @@ -148,34 +148,30 @@ public class VersionSpecificRegistry }
catch(NullPointerException e)
{
- throw new AMQFrameDecodingException(_log,
- "Class " + classID + " unknown in AMQP version " + _protocolMajorVersion + "-" + _protocolMinorVersion
- + " (while trying to decode class " + classID + " method " + methodID + ".");
+ throw new AMQFrameDecodingException(null, "Class " + classID + " unknown in AMQP version " + _protocolMajorVersion
+ + "-" + _protocolMinorVersion + " (while trying to decode class " + classID + " method " + methodID + ".", e);
}
catch(IndexOutOfBoundsException e)
{
if(classID >= _registry.length)
{
- throw new AMQFrameDecodingException(_log,
- "Class " + classID + " unknown in AMQP version " + _protocolMajorVersion + "-" + _protocolMinorVersion
- + " (while trying to decode class " + classID + " method " + methodID + ".");
-
+ throw new AMQFrameDecodingException(null, "Class " + classID + " unknown in AMQP version " + _protocolMajorVersion
+ + "-" + _protocolMinorVersion + " (while trying to decode class " + classID + " method " + methodID
+ + ".", e);
}
else
{
- throw new AMQFrameDecodingException(_log,
- "Method " + methodID + " unknown in AMQP version " + _protocolMajorVersion + "-" + _protocolMinorVersion
- + " (while trying to decode class " + classID + " method " + methodID + ".");
-
+ throw new AMQFrameDecodingException(null, "Method " + methodID + " unknown in AMQP version "
+ + _protocolMajorVersion + "-" + _protocolMinorVersion + " (while trying to decode class " + classID
+ + " method " + methodID + ".", e);
}
}
if (bodyFactory == null)
{
- throw new AMQFrameDecodingException(_log,
- "Method " + methodID + " unknown in AMQP version " + _protocolMajorVersion + "-" + _protocolMinorVersion
- + " (while trying to decode class " + classID + " method " + methodID + ".");
+ throw new AMQFrameDecodingException(null, "Method " + methodID + " unknown in AMQP version " + _protocolMajorVersion
+ + "-" + _protocolMinorVersion + " (while trying to decode class " + classID + " method " + methodID + ".", null);
}
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/pool/Event.java b/qpid/java/common/src/main/java/org/apache/qpid/pool/Event.java index 09890a103d..7300ec8c3f 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/pool/Event.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/pool/Event.java @@ -85,4 +85,27 @@ abstract public class Event } + + public static final class CloseEvent extends Event + { + private final IoFilter.NextFilter _nextFilter; + + public CloseEvent(final IoFilter.NextFilter nextFilter) + { + super(); + _nextFilter = nextFilter; + } + + + public void process(IoSession session) + { + _nextFilter.sessionClosed(session); + } + + public IoFilter.NextFilter getNextFilter() + { + return _nextFilter; + } + } + } diff --git a/qpid/java/common/src/main/java/org/apache/qpid/pool/PoolingFilter.java b/qpid/java/common/src/main/java/org/apache/qpid/pool/PoolingFilter.java index 8126ca4bc8..c9c96925cb 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/pool/PoolingFilter.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/pool/PoolingFilter.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 @@ -24,10 +24,13 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import org.apache.log4j.Logger; + import org.apache.mina.common.IdleStatus; import org.apache.mina.common.IoFilterAdapter; import org.apache.mina.common.IoSession; +import org.apache.qpid.pool.Event.CloseEvent; + public class PoolingFilter extends IoFilterAdapter implements Job.JobCompletionHandler { private static final Logger _logger = Logger.getLogger(PoolingFilter.class); @@ -47,12 +50,12 @@ public class PoolingFilter extends IoFilterAdapter implements Job.JobCompletionH void fireAsynchEvent(IoSession session, Event event) { Job job = getJobForSession(session); - // job.acquire(); //prevents this job being removed from _jobs + // job.acquire(); //prevents this job being removed from _jobs job.add(event); - //Additional checks on pool to check that it hasn't shutdown. + // Additional checks on pool to check that it hasn't shutdown. // The alternative is to catch the RejectedExecutionException that will result from executing on a shutdown pool - if (job.activate() && _poolReference.getPool() != null && !_poolReference.getPool().isShutdown()) + if (job.activate() && (_poolReference.getPool() != null) && !_poolReference.getPool().isShutdown()) { _poolReference.getPool().execute(job); } @@ -68,16 +71,6 @@ public class PoolingFilter extends IoFilterAdapter implements Job.JobCompletionH private Job getJobForSession(IoSession session) { return (Job) session.getAttribute(_name); - -/* if(job == null) - { - System.err.println("Error in " + _name); - Thread.dumpStack(); - } - - - job = _jobs.get(session); - return job == null ? createJobForSession(session) : job;*/ } private Job createJobForSession(IoSession session) @@ -87,35 +80,36 @@ public class PoolingFilter extends IoFilterAdapter implements Job.JobCompletionH private Job addJobForSession(IoSession session, Job job) { - //atomic so ensures all threads agree on the same job + // atomic so ensures all threads agree on the same job Job existing = _jobs.putIfAbsent(session, job); - return existing == null ? job : existing; + + return (existing == null) ? job : existing; } - //Job.JobCompletionHandler + // Job.JobCompletionHandler public void completed(IoSession session, Job job) { -// if (job.isComplete()) -// { -// job.release(); -// if (!job.isReferenced()) -// { -// _jobs.remove(session); -// } -// } -// else - if(!job.isComplete()) + // if (job.isComplete()) + // { + // job.release(); + // if (!job.isReferenced()) + // { + // _jobs.remove(session); + // } + // } + // else + if (!job.isComplete()) { // ritchiem : 2006-12-13 Do we need to perform the additional checks here? - // Can the pool be shutdown at this point? - if (job.activate() && _poolReference.getPool() != null && !_poolReference.getPool().isShutdown()) + // Can the pool be shutdown at this point? + if (job.activate() && (_poolReference.getPool() != null) && !_poolReference.getPool().isShutdown()) { _poolReference.getPool().execute(job); } } } - //IoFilter methods that are processed by threads on the pool + // IoFilter methods that are processed by threads on the pool public void sessionOpened(final NextFilter nextFilter, final IoSession session) throws Exception { @@ -127,37 +121,33 @@ public class PoolingFilter extends IoFilterAdapter implements Job.JobCompletionH nextFilter.sessionClosed(session); } - public void sessionIdle(final NextFilter nextFilter, final IoSession session, - final IdleStatus status) throws Exception + public void sessionIdle(final NextFilter nextFilter, final IoSession session, final IdleStatus status) throws Exception { nextFilter.sessionIdle(session, status); } - public void exceptionCaught(final NextFilter nextFilter, final IoSession session, - final Throwable cause) throws Exception + public void exceptionCaught(final NextFilter nextFilter, final IoSession session, final Throwable cause) throws Exception { - nextFilter.exceptionCaught(session,cause); + nextFilter.exceptionCaught(session, cause); } - public void messageReceived(final NextFilter nextFilter, final IoSession session, - final Object message) throws Exception + public void messageReceived(final NextFilter nextFilter, final IoSession session, final Object message) throws Exception { - nextFilter.messageReceived(session,message); + nextFilter.messageReceived(session, message); } - public void messageSent(final NextFilter nextFilter, final IoSession session, - final Object message) throws Exception + public void messageSent(final NextFilter nextFilter, final IoSession session, final Object message) throws Exception { nextFilter.messageSent(session, message); } - public void filterWrite(final NextFilter nextFilter, final IoSession session, - final WriteRequest writeRequest) throws Exception + public void filterWrite(final NextFilter nextFilter, final IoSession session, final WriteRequest writeRequest) + throws Exception { nextFilter.filterWrite(session, writeRequest); } - //IoFilter methods that are processed on current thread (NOT on pooled thread) + // IoFilter methods that are processed on current thread (NOT on pooled thread) public void filterClose(NextFilter nextFilter, IoSession session) throws Exception { @@ -199,13 +189,17 @@ public class PoolingFilter extends IoFilterAdapter implements Job.JobCompletionH super(refCountingPool, name); } - public void messageReceived(final NextFilter nextFilter, final IoSession session, - final Object message) throws Exception + public void messageReceived(final NextFilter nextFilter, final IoSession session, final Object message) + throws Exception { fireAsynchEvent(session, new Event.ReceivedEvent(nextFilter, message)); } + public void sessionClosed(final NextFilter nextFilter, final IoSession session) throws Exception + { + fireAsynchEvent(session, new CloseEvent(nextFilter)); + } } @@ -217,26 +211,27 @@ public class PoolingFilter extends IoFilterAdapter implements Job.JobCompletionH super(refCountingPool, name); } - - public void filterWrite(final NextFilter nextFilter, final IoSession session, - final WriteRequest writeRequest) throws Exception + public void filterWrite(final NextFilter nextFilter, final IoSession session, final WriteRequest writeRequest) + throws Exception { fireAsynchEvent(session, new Event.WriteEvent(nextFilter, writeRequest)); } + public void sessionClosed(final NextFilter nextFilter, final IoSession session) throws Exception + { + fireAsynchEvent(session, new CloseEvent(nextFilter)); + } + } - public static PoolingFilter createAynschReadPoolingFilter(ReferenceCountingExecutorService refCountingPool,String name) + public static PoolingFilter createAynschReadPoolingFilter(ReferenceCountingExecutorService refCountingPool, String name) { - return new AsynchReadPoolingFilter(refCountingPool,name); + return new AsynchReadPoolingFilter(refCountingPool, name); } - - public static PoolingFilter createAynschWritePoolingFilter(ReferenceCountingExecutorService refCountingPool,String name) + public static PoolingFilter createAynschWritePoolingFilter(ReferenceCountingExecutorService refCountingPool, String name) { - return new AsynchWritePoolingFilter(refCountingPool,name); + return new AsynchWritePoolingFilter(refCountingPool, name); } } - - diff --git a/qpid/java/common/src/main/java/org/apache/qpid/url/AMQBindingURL.java b/qpid/java/common/src/main/java/org/apache/qpid/url/AMQBindingURL.java index f558523864..353c0d39c2 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/url/AMQBindingURL.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/url/AMQBindingURL.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 @@ -24,9 +24,10 @@ import java.net.URI; import java.net.URISyntaxException; import java.util.HashMap; +import org.apache.log4j.Logger; + import org.apache.qpid.exchange.ExchangeDefaults; import org.apache.qpid.framing.AMQShortString; -import org.apache.log4j.Logger; public class AMQBindingURL implements BindingURL { @@ -39,10 +40,9 @@ public class AMQBindingURL implements BindingURL AMQShortString _queueName; private HashMap<String, String> _options; - public AMQBindingURL(String url) throws URLSyntaxException { - //format: + // format: // <exch_class>://<exch_name>/[<destination>]/[<queue>]?<option>='<value>'[,<option>='<value>']* _logger.debug("Parsing URL: " + url); _url = url; @@ -61,10 +61,10 @@ public class AMQBindingURL implements BindingURL if (exchangeClass == null) { - _url = ExchangeDefaults.DIRECT_EXCHANGE_CLASS + "://" + - "" + "//" + _url; - //URLHelper.parseError(-1, "Exchange Class not specified.", _url); + _url = ExchangeDefaults.DIRECT_EXCHANGE_CLASS + "://" + "" + "//" + _url; + // URLHelper.parseError(-1, "Exchange Class not specified.", _url); parseBindingURL(); + return; } else @@ -76,7 +76,7 @@ public class AMQBindingURL implements BindingURL if (exchangeName == null) { - if(getExchangeClass().equals(ExchangeDefaults.DIRECT_EXCHANGE_CLASS)) + if (getExchangeClass().equals(ExchangeDefaults.DIRECT_EXCHANGE_CLASS)) { setExchangeName(""); } @@ -92,11 +92,10 @@ public class AMQBindingURL implements BindingURL String queueName; - if (connection.getPath() == null || - connection.getPath().equals("")) + if ((connection.getPath() == null) || connection.getPath().equals("")) { throw URLHelper.parseError(_url.indexOf(_exchangeName.toString()) + _exchangeName.length(), - "Destination or Queue requried", _url); + "Destination or Queue requried", _url); } else { @@ -104,7 +103,7 @@ public class AMQBindingURL implements BindingURL if (slash == -1) { throw URLHelper.parseError(_url.indexOf(_exchangeName.toString()) + _exchangeName.length(), - "Destination requried", _url); + "Destination requried", _url); } else { @@ -127,9 +126,8 @@ public class AMQBindingURL implements BindingURL setQueueName(queueName); - //Fragment is #string (not used) - //System.out.println(connection.getFragment()); - _logger.debug("URL Parsed: " + this); + // Fragment is #string (not used) + _logger.debug("URL Parsed: " + this); } catch (URISyntaxException uris) @@ -162,7 +160,7 @@ public class AMQBindingURL implements BindingURL private void processOptions() { - //this is where we would parse any options that needed more than just storage. + // this is where we would parse any options that needed more than just storage. } public String getURL() @@ -219,11 +217,13 @@ public class AMQBindingURL implements BindingURL { if (containsOption(BindingURL.OPTION_CLIENTID) && containsOption(BindingURL.OPTION_SUBSCRIPTION)) { - _queueName = new AMQShortString(getOption(BindingURL.OPTION_CLIENTID + ":" + BindingURL.OPTION_SUBSCRIPTION)); + _queueName = + new AMQShortString(getOption(BindingURL.OPTION_CLIENTID + ":" + BindingURL.OPTION_SUBSCRIPTION)); } else { - throw URLHelper.parseError(-1, "Durable subscription must have values for " + BindingURL.OPTION_CLIENTID + " and " + BindingURL.OPTION_SUBSCRIPTION + ".", _url); + throw URLHelper.parseError(-1, "Durable subscription must have values for " + BindingURL.OPTION_CLIENTID + + " and " + BindingURL.OPTION_SUBSCRIPTION + ".", _url); } } @@ -237,7 +237,6 @@ public class AMQBindingURL implements BindingURL _queueName = name; } - } public String getOption(String key) @@ -275,7 +274,6 @@ public class AMQBindingURL implements BindingURL setOption(OPTION_ROUTING_KEY, key.toString()); } - public String toString() { StringBuffer sb = new StringBuffer(); @@ -289,18 +287,7 @@ public class AMQBindingURL implements BindingURL sb.append(_queueName); sb.append(URLHelper.printOptions(_options)); - return sb.toString(); - } - - public static void main(String args[]) throws URLSyntaxException - { - String url = "exchangeClass://exchangeName/Destination/Queue?option='value',option2='value2'"; - - AMQBindingURL dest = new AMQBindingURL(url); - - System.out.println(url); - System.out.println(dest); + return sb.toString(); } - } diff --git a/qpid/java/common/src/main/java/org/apache/qpid/url/URLHelper.java b/qpid/java/common/src/main/java/org/apache/qpid/url/URLHelper.java index 806f879818..c08b443acf 100644 --- a/qpid/java/common/src/main/java/org/apache/qpid/url/URLHelper.java +++ b/qpid/java/common/src/main/java/org/apache/qpid/url/URLHelper.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 @@ -30,10 +30,10 @@ public class URLHelper public static void parseOptions(HashMap<String, String> optionMap, String options) throws URLSyntaxException { - //options looks like this - //brokerlist='tcp://host:port?option='value',option='value';vm://:3/virtualpath?option='value'',failover='method?option='value',option='value'' + // options looks like this + // brokerlist='tcp://host:port?option='value',option='value';vm://:3/virtualpath?option='value'',failover='method?option='value',option='value'' - if (options == null || options.indexOf('=') == -1) + if ((options == null) || (options.indexOf('=') == -1)) { return; } @@ -49,8 +49,8 @@ public class URLHelper // to store index of final "'" int valueIndex = optionIndex; - //Walk remainder of url. - while (nestedQuotes > 0 || valueIndex < length) + // Walk remainder of url. + while ((nestedQuotes > 0) || (valueIndex < length)) { valueIndex++; @@ -61,27 +61,24 @@ public class URLHelper if (options.charAt(valueIndex) == '\'') { - if (valueIndex + 1 < options.length()) + if ((valueIndex + 1) < options.length()) { - if (options.charAt(valueIndex + 1) == DEFAULT_OPTION_SEPERATOR || - options.charAt(valueIndex + 1) == ALTERNATIVE_OPTION_SEPARATOR || - options.charAt(valueIndex + 1) == BROKER_SEPARATOR || - options.charAt(valueIndex + 1) == '\'') + if ((options.charAt(valueIndex + 1) == DEFAULT_OPTION_SEPERATOR) + || (options.charAt(valueIndex + 1) == ALTERNATIVE_OPTION_SEPARATOR) + || (options.charAt(valueIndex + 1) == BROKER_SEPARATOR) + || (options.charAt(valueIndex + 1) == '\'')) { nestedQuotes--; -// System.out.println( -// options + "\n" + "-" + nestedQuotes + ":" + getPositionString(valueIndex - 2, 1)); + if (nestedQuotes == 0) { - //We've found the value of an option + // We've found the value of an option break; } } else { nestedQuotes++; -// System.out.println( -// options + "\n" + "+" + nestedQuotes + ":" + getPositionString(valueIndex - 2, 1)); } } else @@ -98,11 +95,11 @@ public class URLHelper } } - if (nestedQuotes != 0 || valueIndex < (optionIndex + 2)) + if ((nestedQuotes != 0) || (valueIndex < (optionIndex + 2))) { int sepIndex = 0; - //Try and identify illegal separator character + // Try and identify illegal separator character if (nestedQuotes > 1) { for (int i = 0; i < nestedQuotes; i++) @@ -112,14 +109,14 @@ public class URLHelper } } - if (sepIndex >= options.length() || sepIndex == 0) + if ((sepIndex >= options.length()) || (sepIndex == 0)) { throw parseError(valueIndex, "Unterminated option", options); } else { - throw parseError(sepIndex, "Unterminated option. Possible illegal option separator:'" + - options.charAt(sepIndex) + "'", options); + throw parseError(sepIndex, "Unterminated option. Possible illegal option separator:'" + + options.charAt(sepIndex) + "'", options); } } @@ -130,12 +127,11 @@ public class URLHelper if (valueIndex < (options.length() - 1)) { - //Recurse to get remaining options + // Recurse to get remaining options parseOptions(optionMap, options.substring(valueIndex + 2)); } } - public static URLSyntaxException parseError(int index, String error, String url) { return parseError(index, 1, error, url); diff --git a/qpid/java/distribution/src/main/assembly/bin.xml b/qpid/java/distribution/src/main/assembly/bin.xml index 0d4146ed1d..ef85137f90 100644 --- a/qpid/java/distribution/src/main/assembly/bin.xml +++ b/qpid/java/distribution/src/main/assembly/bin.xml @@ -83,6 +83,24 @@ <fileMode>420</fileMode> </file> <file> + <source>../broker/etc/jmxremote.access</source> + <outputDirectory>qpid-${qpid.version}/etc</outputDirectory> + <destName>jmxremote.access</destName> + <fileMode>420</fileMode> + </file> + <file> + <source>../broker/etc/transient_config.xml</source> + <outputDirectory>qpid-${qpid.version}/etc</outputDirectory> + <destName>transient_config.xml</destName> + <fileMode>420</fileMode> + </file> + <file> + <source>../broker/etc/persistent_config.xml</source> + <outputDirectory>qpid-${qpid.version}/etc</outputDirectory> + <destName>persistent_config.xml</destName> + <fileMode>420</fileMode> + </file> + <file> <source>../broker/etc/log4j.xml</source> <outputDirectory>qpid-${qpid.version}/etc</outputDirectory> <destName>log4j.xml</destName> @@ -113,6 +131,18 @@ <fileMode>420</fileMode> </file> <file> + <source>../broker/bin/qpid.stop</source> + <outputDirectory>qpid-${qpid.version}/bin</outputDirectory> + <destName>qpid.stop</destName> + <fileMode>493</fileMode> + </file> + <file> + <source>../broker/bin/qpid.stopall</source> + <outputDirectory>qpid-${qpid.version}/bin</outputDirectory> + <destName>qpid.stopall</destName> + <fileMode>493</fileMode> + </file> + <file> <source>../common/bin/qpid-run</source> <outputDirectory>qpid-${qpid.version}/bin</outputDirectory> <destName>qpid-run</destName> diff --git a/qpid/java/distribution/src/main/assembly/management-eclipse-plugin.xml b/qpid/java/distribution/src/main/assembly/management-eclipse-plugin.xml index 5d89c55968..98534d43d0 100644 --- a/qpid/java/distribution/src/main/assembly/management-eclipse-plugin.xml +++ b/qpid/java/distribution/src/main/assembly/management-eclipse-plugin.xml @@ -88,6 +88,13 @@ </includes> <fileMode>777</fileMode> </fileSet> + <fileSet> + <directory>../management/eclipse-plugin/src/main/resources/sasl</directory> + <outputDirectory>qpidmc/eclipse/plugins/jmxremote.optional_1.0.1/META-INF</outputDirectory> + <includes> + <include>MANIFEST.MF</include> + </includes> + </fileSet> </fileSets> <dependencySets> diff --git a/qpid/java/management/eclipse-plugin/META-INF/MANIFEST.MF b/qpid/java/management/eclipse-plugin/META-INF/MANIFEST.MF index 5e5ba41be0..a92f375886 100644 --- a/qpid/java/management/eclipse-plugin/META-INF/MANIFEST.MF +++ b/qpid/java/management/eclipse-plugin/META-INF/MANIFEST.MF @@ -7,6 +7,7 @@ Bundle-Activator: org.apache.qpid.management.ui.Activator Bundle-Localization: plugin Require-Bundle: org.eclipse.ui, org.eclipse.core.runtime, - org.eclipse.ui.forms + org.eclipse.ui.forms, + jmxremote.optional Eclipse-LazyStart: true Bundle-Vendor: Apache Software Foundation diff --git a/qpid/java/management/eclipse-plugin/bin/qpidmc.bat b/qpid/java/management/eclipse-plugin/bin/qpidmc.bat index 6250b53e68..e444bc5811 100644 --- a/qpid/java/management/eclipse-plugin/bin/qpidmc.bat +++ b/qpid/java/management/eclipse-plugin/bin/qpidmc.bat @@ -52,4 +52,4 @@ goto exit rem Slurp the command line arguments. This loop allows for an unlimited number
rem of agruments (up to the command line limit, anyway).
-"%JAVA_HOME%\bin\java" -Xms40m -Xmx256m -Declipse.consoleLog=true -jar %QPIDMC_HOME%\eclipse\startup.jar org.eclipse.core.launcher.Main -launcher %QPIDMC_HOME%\eclipse\eclipse -name "Qpid Management Console" -showsplash 600 -configuration "file:%QPIDMC_HOME%\configuration" -os win32 -ws win32 -arch x86
+"%JAVA_HOME%\bin\java" -Xms40m -Xmx256m -Declipse.consoleLog=false -Dsecurity=PLAIN -jar %QPIDMC_HOME%\eclipse\startup.jar org.eclipse.core.launcher.Main -launcher %QPIDMC_HOME%\eclipse\eclipse -name "Qpid Management Console" -showsplash 600 -configuration "file:%QPIDMC_HOME%\configuration" -os win32 -ws win32 -arch x86
diff --git a/qpid/java/management/eclipse-plugin/bin/qpidmc.sh b/qpid/java/management/eclipse-plugin/bin/qpidmc.sh index 2472545a14..aae61b14c7 100755 --- a/qpid/java/management/eclipse-plugin/bin/qpidmc.sh +++ b/qpid/java/management/eclipse-plugin/bin/qpidmc.sh @@ -61,4 +61,4 @@ elif [ $os = "Linux" ]; then os="linux" fi -"$JAVA_HOME/bin/java" -Xms40m -Xmx256m -Declipse.consoleLog=false -jar $QPIDMC_HOME/eclipse/startup.jar org.eclipse.core.launcher.Main -launcher $QPIDMC_HOME/eclipse/eclipse -name "Qpid Management Console" -showsplash 600 -configuration "file:$QPIDMC_HOME/configuration" -os $os -ws $ws -arch $arch +"$JAVA_HOME/bin/java" -Xms40m -Xmx256m -Declipse.consoleLog=false -Dsecurity=PLAIN -jar $QPIDMC_HOME/eclipse/startup.jar org.eclipse.core.launcher.Main -launcher $QPIDMC_HOME/eclipse/eclipse -name "Qpid Management Console" -showsplash 600 -configuration "file:$QPIDMC_HOME/configuration" -os $os -ws $ws -arch $arch 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 38a4d4561f..714f84ea49 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 @@ -41,7 +41,9 @@ public abstract class ApplicationRegistry { private static ImageRegistry imageRegistry = new ImageRegistry(); private static FontRegistry fontRegistry = new FontRegistry(); - + public static final boolean debug = Boolean.getBoolean("debug"); + public static final String securityMechanism = System.getProperty("security", null); + static { imageRegistry.put(Constants.CONSOLE_IMAGE, @@ -130,4 +132,9 @@ public abstract class ApplicationRegistry _closedServerList.clear(); return list; } + + public static String getSecurityMechanism() + { + return securityMechanism; + } } diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ApplicationWorkbenchWindowAdvisor.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ApplicationWorkbenchWindowAdvisor.java index 3d163fb111..e3aedef28e 100644 --- a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ApplicationWorkbenchWindowAdvisor.java +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ApplicationWorkbenchWindowAdvisor.java @@ -49,7 +49,7 @@ public class ApplicationWorkbenchWindowAdvisor extends WorkbenchWindowAdvisor IWorkbenchWindowConfigurer configurer = getWindowConfigurer(); int x = Display.getDefault().getBounds().width; int y = Display.getDefault().getBounds().height; - configurer.setInitialSize(new Point(4*x/5, 3*y/4)); + configurer.setInitialSize(new Point(9*x/10, 8*y/10)); configurer.setShowCoolBar(true); configurer.setShowStatusLine(false); diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/Constants.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/Constants.java index 91dec841cf..da70dc736c 100644 --- a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/Constants.java +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/Constants.java @@ -1,3 +1,4 @@ +/* Copyright Rupert Smith, 2005 to 2006, all rights reserved. */ /* * * Licensed to the Apache Software Foundation (ASF) under one @@ -7,9 +8,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 @@ -29,98 +30,110 @@ import static org.apache.qpid.management.ui.Constants.CONNECTION_PROTOCOLS; */ public class Constants { - public final static String APPLICATION_NAME = "Qpid Management Console"; - - public final static String ACTION_REMOVE_MBEANNODE = "Remove from list"; - public final static String VALUE = "value"; - public final static String TYPE = "type"; - public final static String NODE_TYPE_SERVER = "server"; - public final static String NODE_TYPE_DOMAIN = "domain"; - public final static String NODE_TYPE_MBEANTYPE = "mbeantype"; + public static final String APPLICATION_NAME = "Qpid Management Console"; + + public static final String ACTION_REMOVE_MBEANNODE = "Remove from list"; + public static final String VALUE = "value"; + public static final String TYPE = "type"; + public static final String NODE_TYPE_SERVER = "server"; + public static final String NODE_TYPE_DOMAIN = "domain"; + public static final String NODE_TYPE_MBEANTYPE = "mbeantype"; // currently used only for virtual host instances, but will work as general also - public final static String NODE_TYPE_TYPEINSTANCE = "mbeantype_instance"; - public final static String MBEAN = "mbean"; - public final static String ATTRIBUTE = "Attribute"; - public final static String ATTRIBUTES = "Attributes"; - public final static String NOTIFICATION = "Notifications"; - public final static String RESULT = "Result"; - public final static String VIRTUAL_HOST = "VirtualHost"; - public final static String DEFAULT_VH = "Default"; - public final static String DEFAULT_USERNAME = "guest"; - public final static String DEFAULT_PASSWORD = "guest"; - - public final static String USERNAME = "Username"; - public final static String PASSWORD = "Password"; - + public static final String NODE_TYPE_TYPEINSTANCE = "mbeantype_instance"; + public static final String MBEAN = "mbean"; + public static final String ATTRIBUTE = "Attribute"; + public static final String ATTRIBUTES = "Attributes"; + public static final String NOTIFICATIONS = "Notifications"; + public static final String RESULT = "Result"; + public static final String VIRTUAL_HOST = "VirtualHost"; + public static final String DEFAULT_VH = "Default"; + public static final String DEFAULT_USERNAME = "guest"; + public static final String DEFAULT_PASSWORD = "guest"; + + public static final String USERNAME = "Username"; + public static final String PASSWORD = "Password"; + // Attributes and operations are used to customize the GUI for Qpid. If these are changes in the // Qpid server, then these should be updated accordingly - public final static String ATTRIBUTE_QUEUE_OWNER = "owner"; - public final static String ATTRIBUTE_QUEUE_DEPTH = "QueueDepth"; - public final static String ATTRIBUTE_QUEUE_CONSUMERCOUNT = "ActiveConsumerCount"; - public final static String OPERATION_CREATE_QUEUE = "createNewQueue"; - public final static String OPERATION_CREATE_BINDING = "createNewBinding"; - public final static String OPERATION_MOVE_MESSAGES = "moveMessages"; - - public final static String ALL = "All"; - - public final static String NAVIGATION_ROOT = "Qpid Connections"; - public final static String DESCRIPTION = " Description"; - - public final static String QUEUE = "Queue"; - public final static String CONNECTION ="Connection"; - public final static String EXCHANGE = "Exchange"; - public final static String EXCHANGE_TYPE = "ExchangeType"; - public final static String[] EXCHANGE_TYPE_VALUES = {"direct", "topic", "headers"}; - public final static String[] BOOLEAN_TYPE_VALUES = {"false", "true"}; - public final static String[] ATTRIBUTE_TABLE_TITLES = {"Attribute Name", "Value"}; - public static final String[] CONNECTION_PROTOCOLS ={"RMI"}; + public static final String ATTRIBUTE_QUEUE_OWNER = "owner"; + public static final String ATTRIBUTE_QUEUE_DEPTH = "QueueDepth"; + public static final String ATTRIBUTE_QUEUE_CONSUMERCOUNT = "ActiveConsumerCount"; + public static final String OPERATION_CREATE_QUEUE = "createNewQueue"; + public static final String OPERATION_CREATE_BINDING = "createNewBinding"; + public static final String OPERATION_MOVE_MESSAGES = "moveMessages"; + + public static final String OPERATION_CREATEUSER = "createUser"; + public static final String OPERATION_VIEWUSERS = "viewUsers"; + public static final String OPERATION_PARAM_USERNAME = "username"; + + public static final String OPERATION_SUCCESSFUL = "Operation successful"; + public static final String OPERATION_UNSUCCESSFUL = "Operation unsuccessful"; + + public static final String ALL = "All"; + + public static final String NAVIGATION_ROOT = "Qpid Connections"; + public static final String DESCRIPTION = " Description"; + + public static final String ADMIN_MBEAN_TYPE = "UserManagement"; + public static final String QUEUE = "Queue"; + public static final String CONNECTION = "Connection"; + public static final String EXCHANGE = "Exchange"; + public static final String EXCHANGE_TYPE = "ExchangeType"; + public static final String[] EXCHANGE_TYPE_VALUES = { "direct", "fanout", "headers", "topic" }; + public static final String[] BOOLEAN_TYPE_VALUES = { "false", "true" }; + public static final String[] ATTRIBUTE_TABLE_TITLES = { "Attribute Name", "Value" }; + public static final String[] CONNECTION_PROTOCOLS = { "RMI" }; public static final String DEFAULT_PROTOCOL = CONNECTION_PROTOCOLS[0]; - - public final static String ACTION_ADDSERVER = "New Connection"; - public final static String ACTION_RECONNECT = "Reconnect"; - public final static String ACTION_LOGIN = "Login"; - - public final static String QUEUE_SORT_BY_NAME = "Queue Name"; - public final static String QUEUE_SORT_BY_DEPTH = "Queue Depth"; - public final static String QUEUE_SORT_BY_CONSUMERCOUNT = "Consumer Count"; - public final static String QUEUE_SHOW_TEMP_QUEUES= "show temporary queues"; - - public final static String SUBSCRIBE_BUTTON = "Subscribe"; - public final static String UNSUBSCRIBE_BUTTON = "Unsubscribe"; - - public final static String CONSOLE_IMAGE = "ConsoelImage"; - public final static String CLOSED_FOLDER_IMAGE = "ClosedFolderImage"; - public final static String OPEN_FOLDER_IMAGE = "OpenFolderImage"; - public final static String MBEAN_IMAGE = "MBeanImage"; - public final static String NOTIFICATION_IMAGE = "NotificationImage"; - - public final static String FONT_BUTTON = "ButtonFont"; - public final static String FONT_BOLD = "BoldFont"; - public final static String FONT_ITALIC = "ItalicFont"; - public final static String FONT_TABLE_CELL = "TableCellFont"; - public final static String FONT_NORMAL = "Normal"; - - public final static String BUTTON_DETAILS = "Details"; - public final static String BUTTON_EDIT_ATTRIBUTE = "Edit Attribute"; - public final static String BUTTON_REFRESH = "Refresh"; - public final static String BUTTON_GRAPH = "Graph"; - public final static int TIMER_INTERVAL = 5000; - public final static String BUTTON_EXECUTE = "Execute"; - public final static String BUTTON_CLEAR = "Clear"; - public final static String BUTTON_CONNECT = "Connect"; - public final static String BUTTON_CANCEL = "Cancel"; - public final static String BUTTON_UPDATE = "Update"; - - - public final static int OPERATION_IMPACT_INFO = 0; - public final static int OPERATION_IMPACT_ACTION = 1; - public final static int OPERATION_IMPACT_ACTIONINFO = 2; - public final static int OPERATION_IMPACT_UNKNOWN = 3; - - public final static String ERROR_SERVER_CONNECTION = "Server could not be connected"; - public final static String INFO_PROTOCOL = "Please select the protocol"; - public final static String INFO_HOST_ADDRESS = "Please enter the host address"; - public final static String INFO_HOST_PORT = "Please enter the port number"; - public final static String INFO_USERNAME = "Please enter the " + USERNAME; - public final static String INFO_PASSWORD = "Please enter the " + PASSWORD; + + public static final String ACTION_ADDSERVER = "New Connection"; + public static final String ACTION_RECONNECT = "Reconnect"; + public static final String ACTION_LOGIN = "Login"; + + public static final String QUEUE_SORT_BY_NAME = "Queue Name"; + public static final String QUEUE_SORT_BY_DEPTH = "Queue Depth"; + public static final String QUEUE_SORT_BY_CONSUMERCOUNT = "Consumer Count"; + public static final String QUEUE_SHOW_TEMP_QUEUES = "show temporary queues"; + + public static final String SUBSCRIBE_BUTTON = "Subscribe"; + public static final String UNSUBSCRIBE_BUTTON = "Unsubscribe"; + + public static final String CONSOLE_IMAGE = "ConsoelImage"; + public static final String CLOSED_FOLDER_IMAGE = "ClosedFolderImage"; + public static final String OPEN_FOLDER_IMAGE = "OpenFolderImage"; + public static final String MBEAN_IMAGE = "MBeanImage"; + public static final String NOTIFICATION_IMAGE = "NotificationImage"; + + public static final String FONT_BUTTON = "ButtonFont"; + public static final String FONT_BOLD = "BoldFont"; + public static final String FONT_ITALIC = "ItalicFont"; + public static final String FONT_TABLE_CELL = "TableCellFont"; + public static final String FONT_NORMAL = "Normal"; + + public static final String BUTTON_DETAILS = "Details"; + public static final String BUTTON_EDIT_ATTRIBUTE = "Edit Attribute"; + public static final String BUTTON_REFRESH = "Refresh"; + public static final String BUTTON_GRAPH = "Graph"; + public static final int TIMER_INTERVAL = 5000; + public static final String BUTTON_EXECUTE = "Execute"; + public static final String BUTTON_CLEAR = "Clear"; + public static final String BUTTON_CONNECT = "Connect"; + public static final String BUTTON_CANCEL = "Cancel"; + public static final String BUTTON_UPDATE = "Update"; + + public static final int OPERATION_IMPACT_INFO = 0; + public static final int OPERATION_IMPACT_ACTION = 1; + public static final int OPERATION_IMPACT_ACTIONINFO = 2; + public static final int OPERATION_IMPACT_UNKNOWN = 3; + + public static final String ERROR_SERVER_CONNECTION = "Server could not be connected"; + public static final String INFO_PROTOCOL = "Please select the protocol"; + public static final String INFO_HOST_ADDRESS = "Please enter the host address"; + public static final String INFO_HOST_PORT = "Please enter the port number"; + public static final String INFO_USERNAME = "Please enter the " + USERNAME; + public static final String INFO_PASSWORD = "Please enter the " + PASSWORD; + + public static final String MECH_CRAMMD5 = "CRAM-MD5"; + public static final String MECH_PLAIN = "PLAIN"; + public static final String SASL_CRAMMD5 = "SASL/CRAM-MD5"; + public static final String SASL_PLAIN = "SASL/PLAIN"; } diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ManagedBean.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ManagedBean.java index 38c3e8f413..31825e925d 100644 --- a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ManagedBean.java +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ManagedBean.java @@ -20,6 +20,7 @@ */ package org.apache.qpid.management.ui; +import static org.apache.qpid.management.ui.Constants.*; import java.util.HashMap; /** @@ -50,7 +51,7 @@ public abstract class ManagedBean extends ManagedObject this._properties = properties; setName(getProperty("name")); setType(getProperty("type")); - _virtualHostName = getProperty(Constants.VIRTUAL_HOST); + _virtualHostName = getProperty(VIRTUAL_HOST); } public String getDomain() { @@ -89,7 +90,7 @@ public abstract class ManagedBean extends ManagedObject public String getVirtualHostName() { // To make it work with the broker with no virtual host implementation - return _virtualHostName == null ? Constants.DEFAULT_VH : _virtualHostName; + return _virtualHostName == null ? DEFAULT_VH : _virtualHostName; } /** @@ -106,21 +107,26 @@ public abstract class ManagedBean extends ManagedObject public boolean isQueue() { - return _type.endsWith(Constants.QUEUE); + return _type.endsWith(QUEUE); } public boolean isConnection() { - return _type.endsWith(Constants.CONNECTION); + return _type.endsWith(CONNECTION); } public boolean isExchange() { - return _type.endsWith(Constants.EXCHANGE); + return _type.endsWith(EXCHANGE); } public boolean isTempQueue() { return (isQueue() && getName().startsWith("tmp_")); } + + public boolean isAdmin() + { + return _type.endsWith(ADMIN_MBEAN_TYPE); + } } diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/Perspective.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/Perspective.java index da49d70b88..f93200cadf 100644 --- a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/Perspective.java +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/Perspective.java @@ -37,8 +37,8 @@ public class Perspective implements IPerspectiveFactory layout.setEditorAreaVisible(false); // standalone view meaning it can't be docked or stacked with other views, and it doesn't have a title bar. - layout.addStandaloneView(NavigationView.ID, true, IPageLayout.LEFT, 0.25f, editorArea); - layout.addStandaloneView(MBeanView.ID, true, IPageLayout.RIGHT, 0.75f, editorArea); + layout.addStandaloneView(NavigationView.ID, true, IPageLayout.LEFT, 0.30f, editorArea); + layout.addStandaloneView(MBeanView.ID, true, IPageLayout.RIGHT, 0.70f, editorArea); layout.getViewLayout(NavigationView.ID).setCloseable(false); layout.getViewLayout(MBeanView.ID).setCloseable(false); diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ServerRegistry.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ServerRegistry.java index fa71ee9bc7..313e143df5 100644 --- a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ServerRegistry.java +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ServerRegistry.java @@ -128,6 +128,10 @@ public abstract class ServerRegistry return _virtualHosts; } + public abstract void setUserList(List<String> list); + + public abstract List<String> getUsernames(); + public abstract void addManagedObject(ManagedBean key); public abstract List<ManagedBean> getMBeans(); @@ -154,7 +158,7 @@ public abstract class ServerRegistry public abstract boolean hasSubscribedForNotifications(ManagedBean mbean, String name, String type); - public abstract void clearNotifications(ManagedBean mbean); + public abstract void clearNotifications(ManagedBean mbean, List<NotificationObject> list); public ClientListener getNotificationListener() { diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/actions/AddServer.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/actions/AddServer.java index 5a926e6474..0e12c59de4 100644 --- a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/actions/AddServer.java +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/actions/AddServer.java @@ -194,9 +194,6 @@ public class AddServer/* extends Action*/ implements IWorkbenchWindowActionDeleg } } - //If you create it, you dispose it. - shell.dispose(); - // enable the main shell _window.getShell().setEnabled(true); _window.getShell().open(); @@ -263,7 +260,7 @@ public class AddServer/* extends Action*/ implements IWorkbenchWindowActionDeleg user.setLayoutData(new GridData(SWT.TRAIL, SWT.TOP, false, false)); final Text textUser = new Text(composite, SWT.BORDER); - textUser.setText(DEFAULT_USERNAME); + textUser.setText(""); textUser.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); Label password = new Label(composite, SWT.NONE); @@ -271,7 +268,7 @@ public class AddServer/* extends Action*/ implements IWorkbenchWindowActionDeleg password.setLayoutData(new GridData(SWT.TRAIL, SWT.TOP, false, false)); final Text textPwd = new Text(composite, SWT.BORDER | SWT.SINGLE | SWT.PASSWORD); - textPwd.setText(DEFAULT_PASSWORD); + textPwd.setText(""); //textPwd.setEchoChar('*'); textPwd.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); @@ -327,11 +324,7 @@ public class AddServer/* extends Action*/ implements IWorkbenchWindowActionDeleg _domain = comboDomain.getText(); _addServer = true; - - if (!connectButton.getShell().isDisposed()) - { - connectButton.getShell().dispose(); - } + shell.dispose(); } }); diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/actions/ReconnectServer.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/actions/ReconnectServer.java index 8fe08462cd..9aa265ab3c 100644 --- a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/actions/ReconnectServer.java +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/actions/ReconnectServer.java @@ -168,9 +168,6 @@ public class ReconnectServer implements IWorkbenchWindowActionDelegate } } - //If you create it, you dispose it. - shell.dispose(); - // enable the main shell _window.getShell().setEnabled(true); _window.getShell().open(); @@ -194,7 +191,7 @@ public class ReconnectServer implements IWorkbenchWindowActionDelegate user.setLayoutData(new GridData(SWT.TRAIL, SWT.TOP, false, false)); final Text textUser = new Text(composite, SWT.BORDER); - textUser.setText(DEFAULT_USERNAME); + textUser.setText(""); textUser.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); // Put cursor on this field textUser.setFocus(); @@ -204,7 +201,7 @@ public class ReconnectServer implements IWorkbenchWindowActionDelegate password.setLayoutData(new GridData(SWT.TRAIL, SWT.TOP, false, false)); final Text textPwd = new Text(composite, SWT.BORDER | SWT.SINGLE | SWT.PASSWORD); - textPwd.setText(DEFAULT_PASSWORD); + textPwd.setText(""); textPwd.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); Composite buttonsComposite = new Composite(composite, SWT.NONE); @@ -240,11 +237,7 @@ public class ReconnectServer implements IWorkbenchWindowActionDelegate } _connect = true; - - if (!connectButton.getShell().isDisposed()) - { - connectButton.getShell().dispose(); - } + shell.dispose(); } }); diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/ClientListener.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/ClientListener.java index 82447d645e..2be0ddbebf 100644 --- a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/ClientListener.java +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/ClientListener.java @@ -45,10 +45,7 @@ public class ClientListener implements NotificationListener { ObjectName objName = null; String type = notification.getType(); - if (MBeanUtility.isDebug()) - { - System.out.println(type + ":" + objName); - } + MBeanUtility.printOutput(type + ":" + objName); if (MBeanServerNotification.REGISTRATION_NOTIFICATION.equals(type)) { diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/JMXServerRegistry.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/JMXServerRegistry.java index b0f9928c38..816c479cf9 100644 --- a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/JMXServerRegistry.java +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/JMXServerRegistry.java @@ -20,6 +20,10 @@ */ package org.apache.qpid.management.ui.jmx; +import static org.apache.qpid.management.ui.Constants.*; + +import java.lang.reflect.Constructor; +import java.security.Security; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; @@ -35,8 +39,9 @@ import javax.management.ObjectName; import javax.management.remote.JMXConnector; import javax.management.remote.JMXConnectorFactory; import javax.management.remote.JMXServiceURL; +import javax.security.sasl.SaslClientFactory; -import org.apache.qpid.management.ui.Constants; +import org.apache.qpid.management.ui.ApplicationRegistry; import org.apache.qpid.management.ui.ManagedBean; import org.apache.qpid.management.ui.ManagedServer; import org.apache.qpid.management.ui.ServerRegistry; @@ -44,6 +49,10 @@ import org.apache.qpid.management.ui.model.ManagedAttributeModel; import org.apache.qpid.management.ui.model.NotificationInfoModel; import org.apache.qpid.management.ui.model.NotificationObject; import org.apache.qpid.management.ui.model.OperationDataModel; +import org.apache.qpid.management.ui.sasl.JCAProvider; +import org.apache.qpid.management.ui.sasl.SaslProvider; +import org.apache.qpid.management.ui.sasl.UserPasswordCallbackHandler; +import org.apache.qpid.management.ui.sasl.UsernameHashedPasswordCallbackHandler; public class JMXServerRegistry extends ServerRegistry @@ -52,11 +61,12 @@ public class JMXServerRegistry extends ServerRegistry private JMXConnector _jmxc = null; private MBeanServerConnection _mbsc = null; + private List<String> _usersList; // When an mbean gets removed from mbean server, then the notification listener // will add that mbean in this list. private List<ManagedBean> _mbeansToBeRemoved = new ArrayList<ManagedBean>(); - // Map containing all managed beans and ampped with unique mbean name + // Map containing all managed beans and mapped with unique mbean name private HashMap<String, ManagedBean> _mbeansMap = new HashMap<String, ManagedBean>(); // Map containing MBeanInfo for all mbeans and mapped with unique mbean name private HashMap<String, MBeanInfo> _mbeanInfoMap = new HashMap<String, MBeanInfo>(); @@ -83,11 +93,69 @@ public class JMXServerRegistry extends ServerRegistry { super(server); JMXServiceURL jmxUrl = new JMXServiceURL(server.getUrl()); - Map<String, Object> env = new HashMap<String, Object>(); - String[] creds = {server.getUser(), server.getPassword()}; - env.put(JMXConnector.CREDENTIALS, creds); - - _jmxc = JMXConnectorFactory.connect(jmxUrl, env); + Map<String, Object> env = null; + String securityMechanism = ApplicationRegistry.getSecurityMechanism(); + + if (securityMechanism != null) + { + try + { + // Check if the JMXMP connector is available + Class klass = Class.forName("javax.management.remote.jmxmp.JMXMPConnector"); + + jmxUrl = new JMXServiceURL("jmxmp", server.getHost(), server.getPort()); + env = new HashMap<String, Object>(); + + if (MECH_CRAMMD5.equals(securityMechanism)) + { + // For SASL/CRAM-MD5 + Map<String, Class<? extends SaslClientFactory>> map = new HashMap<String, Class<? extends SaslClientFactory>>(); + Class<?> clazz = Class.forName("org.apache.qpid.management.ui.sasl.CRAMMD5HashedSaslClientFactory"); + map.put("CRAM-MD5-HASHED", (Class<? extends SaslClientFactory>) clazz); + + Security.addProvider(new JCAProvider(map)); + env.put("jmx.remote.profiles", SASL_CRAMMD5); + env.put("jmx.remote.sasl.callback.handler", + new UsernameHashedPasswordCallbackHandler(server.getUser(), server.getPassword())); + } + else if (MECH_PLAIN.equals(securityMechanism)) + { + // For SASL/PLAIN + Security.addProvider(new SaslProvider()); + env.put("jmx.remote.profiles", SASL_PLAIN); + env.put("jmx.remote.sasl.callback.handler", + new UserPasswordCallbackHandler(server.getUser(), server.getPassword())); + } + else + { + MBeanUtility.printOutput("Security mechanism " + securityMechanism + " is not supported."); + } + + // Now create the instance of JMXMPConnector + Class[] paramTypes = {JMXServiceURL.class, Map.class}; + Constructor cons = klass.getConstructor(paramTypes); + + Object[] args = {jmxUrl, env}; + Object theObject = cons.newInstance(args); + + _jmxc = (JMXConnector)theObject; + _jmxc.connect(); + MBeanUtility.printOutput("Starting JMXConnector with SASL. Server=" + server.getName()); + } + catch (Exception ex) + { + // When JMXMPConnector is not available + MBeanUtility.printOutput("Starting JMXConnector. Server=" + server.getName()); + jmxUrl = new JMXServiceURL(server.getUrl()); + _jmxc = JMXConnectorFactory.connect(jmxUrl, null); + } + } + else + { + jmxUrl = new JMXServiceURL(server.getUrl()); + _jmxc = JMXConnectorFactory.connect(jmxUrl, null); + } + _mbsc = _jmxc.getMBeanServerConnection(); _clientListener = new ClientListener(server); @@ -155,10 +223,7 @@ public class JMXServerRegistry extends ServerRegistry public void removeManagedObject(ManagedBean mbean) { - if (MBeanUtility.isDebug()) - { - System.out.println("Removing MBean:" + mbean.getUniqueName()); - } + MBeanUtility.printOutput("Removing MBean:" + mbean.getUniqueName()); if (mbean.isQueue()) { @@ -218,17 +283,78 @@ public class JMXServerRegistry extends ServerRegistry list.add(obj); } + /** + * Returns all the notification objects for a given mbean. If mbean is null, it returns + * notification objects for all the mbeans. + */ public List<NotificationObject> getNotifications(ManagedBean mbean) { - return _notificationsMap.get(mbean.getUniqueName()); + if (mbean == null) + { + List<NotificationObject> totalList = new ArrayList<NotificationObject>(); + for (List<NotificationObject> list : _notificationsMap.values()) + { + totalList.addAll(list); + } + return totalList; + } + else + { + return _notificationsMap.get(mbean.getUniqueName()); + } } - public void clearNotifications(ManagedBean mbean) + public void clearNotifications(ManagedBean mbean, List<NotificationObject> list) { - if (_notificationsMap.containsKey(mbean.getUniqueName())) - _notificationsMap.get(mbean.getUniqueName()).clear(); + if (mbean == null) + { + if (list == null || list.isEmpty()) + { + // All notifications of all mbeans to be cleared + _notificationsMap.clear(); + } + else + { + // Clear the selected notifications + for (NotificationObject obj : list) + { + mbean = _mbeansMap.get(obj.getSource().toString()); + List<NotificationObject> nList = _notificationsMap.get(mbean.getUniqueName()); + if (nList != null && !nList.isEmpty()) + { + nList.remove(obj); + } + } + } + } + else + { + if (list == null || list.isEmpty()) + { + // All notifications of this mbean to be cleared + List<NotificationObject> nList = _notificationsMap.get(mbean.getUniqueName()); + if (nList != null && !nList.isEmpty()) + { + nList.clear(); + } + } + else + { + // Clear the selected notifications + for (NotificationObject obj : list) + { + List<NotificationObject> nList = _notificationsMap.get(mbean.getUniqueName()); + if (nList != null && !nList.isEmpty()) + { + nList.remove(obj); + } + } + } + } } + + /** * Adds notification name and type to the map. The map contains all the notification names, * subscribed for an mbean. @@ -254,7 +380,7 @@ public class JMXServerRegistry extends ServerRegistry map.put(name, list); } // Now add the notification type to the list - if (Constants.ALL.equals(type)) + if (ALL.equals(type)) { List<NotificationInfoModel> infoList = _notificationInfoMap.get(mbean.getUniqueName()); for (NotificationInfoModel model : infoList) @@ -313,7 +439,7 @@ public class JMXServerRegistry extends ServerRegistry HashMap<String, List<String>> map = _subscribedNotificationMap.get(mbean.getUniqueName()); if (map.containsKey(name)) { - if (Constants.ALL.equals(type)) + if (ALL.equals(type)) { map.remove(name); } @@ -441,6 +567,16 @@ public class JMXServerRegistry extends ServerRegistry } return connections; } + + public void setUserList(List<String> list) + { + _usersList = list; + } + + public List<String> getUsernames() + { + return _usersList; + } public ClientNotificationListener getNotificationListener() { diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/MBeanUtility.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/MBeanUtility.java index 5ceeb879b4..41db11c10e 100644 --- a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/MBeanUtility.java +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/MBeanUtility.java @@ -60,13 +60,6 @@ import org.apache.qpid.management.ui.views.ViewUtility; */ public class MBeanUtility { - private static boolean _debug; - static - { - String debug = System.getProperty("debug"); - _debug = "true".equalsIgnoreCase(debug) ? true : false; - } - public static final BigInteger MAX_LONG = BigInteger.valueOf(Long.MAX_VALUE); public static final BigInteger MAX_INT = BigInteger.valueOf(Integer.MAX_VALUE); /** @@ -149,27 +142,27 @@ public class MBeanUtility * @param mbean managed bean * @param ex Exception */ - public static void handleException(ManagedBean mbean, Exception ex) + public static void handleException(ManagedBean mbean, Throwable ex) { if (mbean == null) { ViewUtility.popupErrorMessage("Error", "Managed Object is null \n" + ex.toString()); - ex.printStackTrace(); + printStackTrace(ex); } else if (ex instanceof IOException) { ViewUtility.popupErrorMessage(mbean.getInstanceName(), "IO Error occured \n" + ex.toString()); - ex.printStackTrace(); + printStackTrace(ex); } else if (ex instanceof ReflectionException) { ViewUtility.popupErrorMessage(mbean.getInstanceName(), "Server has thrown error \n" + ex.toString()); - ex.printStackTrace(); + printStackTrace(ex); } else if (ex instanceof InstanceNotFoundException) { ViewUtility.popupErrorMessage(mbean.getInstanceName(), "Managed Object Not Found \n" + ex.toString()); - ex.printStackTrace(); + printStackTrace(ex); } else if (ex instanceof MBeanException) { @@ -188,8 +181,20 @@ public class MBeanUtility } else { - ViewUtility.popupErrorMessage(mbean.getInstanceName(), ex.getMessage()); - ex.printStackTrace(); + if (ex.getCause() != null) + { + handleException(mbean, ex.getCause()); + } + else + { + String msg = ex.getMessage(); + if (msg == null) + { + msg = ex.toString(); + } + ViewUtility.popupErrorMessage(mbean.getInstanceName(), msg); + printStackTrace(ex); + } } } @@ -449,12 +454,19 @@ public class MBeanUtility return Arrays.asList(domains); } - /** - * return true if System property is set to true -Ddebug=true - * @return - */ - public static boolean isDebug() + public static void printOutput(String statement) { - return _debug; + if (ApplicationRegistry.debug) + { + System.out.println(statement); + } + } + + private static void printStackTrace(Throwable ex) + { + if (ApplicationRegistry.debug) + { + ex.printStackTrace(); + } } } diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/model/NotificationObject.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/model/NotificationObject.java index 8ba74b3ce8..926e5f0a24 100644 --- a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/model/NotificationObject.java +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/model/NotificationObject.java @@ -24,10 +24,12 @@ import java.text.SimpleDateFormat; import java.util.Date; import java.util.TimeZone; +import javax.management.ObjectName; + public class NotificationObject { - private long _sequenceNo; + private long _sequenceNo; private Date _timeStamp; private String _message; private Object _source; @@ -52,6 +54,17 @@ public class NotificationObject { this._source = _source; } + + public String getSourceName() + { + if (_source instanceof ObjectName) + { + return ((ObjectName)_source).getKeyProperty("name"); + } + + return null; + } + public String getMessage() { return _message; diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/model/OperationData.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/model/OperationData.java index 9b6750c21a..2b83645942 100644 --- a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/model/OperationData.java +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/model/OperationData.java @@ -80,5 +80,13 @@ public class OperationData this._returnType = returnType; } + public boolean isReturnTypeBoolean() + { + return (_returnType.equals("boolean") || _returnType.equals("java.lang.Boolean")); + } + public boolean isReturnTypeVoid() + { + return (_returnType.equals("void") || _returnType.equals("java.lang.Void")); + } }
\ No newline at end of file diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/sasl/CRAMMD5HashedSaslClientFactory.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/sasl/CRAMMD5HashedSaslClientFactory.java new file mode 100644 index 0000000000..32a0c12344 --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/sasl/CRAMMD5HashedSaslClientFactory.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.management.ui.sasl; + +import java.util.Map; + +import javax.security.auth.callback.CallbackHandler; +import javax.security.sasl.Sasl; +import javax.security.sasl.SaslClient; +import javax.security.sasl.SaslClientFactory; +import javax.security.sasl.SaslException; + +public class CRAMMD5HashedSaslClientFactory implements SaslClientFactory +{ + /** The name of this mechanism */ + public static final String MECHANISM = "CRAM-MD5-HASHED"; + + public SaslClient createSaslClient(String[] mechanisms, String authorizationId, String protocol, + String serverName, Map<String, ?> props, CallbackHandler cbh) + throws SaslException + { + for (int i = 0; i < mechanisms.length; i++) + { + if (mechanisms[i].equals(MECHANISM)) + { + if (cbh == null) + { + throw new SaslException("CallbackHandler must not be null"); + } + + String[] mechs = {"CRAM-MD5"}; + return Sasl.createSaslClient(mechs, authorizationId, protocol, serverName, props, cbh); + } + } + return null; + } + + public String[] getMechanismNames(Map props) + { + return new String[]{MECHANISM}; + } +} diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/sasl/ClientSaslFactory.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/sasl/ClientSaslFactory.java new file mode 100644 index 0000000000..ce9a273eaa --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/sasl/ClientSaslFactory.java @@ -0,0 +1,54 @@ +/* + * + * 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.sasl; + +import java.util.Map; + +import javax.security.auth.callback.CallbackHandler; +import javax.security.sasl.SaslClient; +import javax.security.sasl.SaslClientFactory; +import javax.security.sasl.SaslException; + +public class ClientSaslFactory implements SaslClientFactory +{ + public SaslClient createSaslClient(String[] mechs, String authorizationId, String protocol, + String serverName, Map props, CallbackHandler cbh) + throws SaslException + { + for (int i = 0; i < mechs.length; i++) + { + if (mechs[i].equals("PLAIN")) + { + return new PlainSaslClient(authorizationId, cbh); + } + } + return null; + } + + /** + * Simple-minded implementation that ignores props + */ + public String[] getMechanismNames(Map props) + { + return new String[]{"PLAIN"}; + } + +} diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/sasl/JCAProvider.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/sasl/JCAProvider.java new file mode 100644 index 0000000000..d8189f3ac3 --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/sasl/JCAProvider.java @@ -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. + * + */ +package org.apache.qpid.management.ui.sasl; + +import java.security.Provider; +import java.util.Map; + +import javax.security.sasl.SaslClientFactory; + +public class JCAProvider extends Provider +{ + private static final long serialVersionUID = 1L; + + /** + * Creates the security provider with a map from SASL mechanisms to implementing factories. + * + * @param providerMap The map from SASL mechanims to implementing factory classes. + */ + public JCAProvider(Map<String, Class<? extends SaslClientFactory>> providerMap) + { + super("AMQSASLProvider", 1.0, "A JCA provider that registers all " + + "AMQ SASL providers that want to be registered"); + register(providerMap); + } + + /** + * Registers client factory classes for a map of mechanism names to client factory classes. + * + * @param providerMap The map from SASL mechanims to implementing factory classes. + */ + private void register(Map<String, Class<? extends SaslClientFactory>> providerMap) + { + for (Map.Entry<String, Class<? extends SaslClientFactory>> me : providerMap.entrySet()) + { + put("SaslClientFactory." + me.getKey(), me.getValue().getName()); + } + } +} diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/sasl/PlainSaslClient.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/sasl/PlainSaslClient.java new file mode 100644 index 0000000000..22190f29eb --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/sasl/PlainSaslClient.java @@ -0,0 +1,203 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.management.ui.sasl; + +import java.io.*; +import javax.security.auth.callback.*; +import javax.security.sasl.*; + +public class PlainSaslClient implements SaslClient +{ + + private boolean completed; + private CallbackHandler cbh; + private String authorizationID; + private String authenticationID; + private byte password[]; + private static byte SEPARATOR = 0; + + public PlainSaslClient(String authorizationID, CallbackHandler cbh) throws SaslException + { + completed = false; + this.cbh = cbh; + Object[] userInfo = getUserInfo(); + this.authorizationID = authorizationID; + this.authenticationID = (String) userInfo[0]; + this.password = (byte[]) userInfo[1]; + if (authenticationID == null || password == null) + { + throw new SaslException("PLAIN: authenticationID and password must be specified"); + } + } + + public byte[] evaluateChallenge(byte[] challenge) throws SaslException + { + if (completed) + { + throw new IllegalStateException("PLAIN: authentication already " + + "completed"); + } + completed = true; + try + { + byte authzid[] = + authorizationID == null ? null : authorizationID.getBytes("UTF8"); + byte authnid[] = authenticationID.getBytes("UTF8"); + byte response[] = + new byte[ + password.length + + authnid.length + + 2 + // SEPARATOR + (authzid != null ? authzid.length : 0) + ]; + int size = 0; + if (authzid != null) { + System.arraycopy(authzid, 0, response, 0, authzid.length); + size = authzid.length; + } + response[size++] = SEPARATOR; + System.arraycopy(authnid, 0, response, size, authnid.length); + size += authnid.length; + response[size++] = SEPARATOR; + System.arraycopy(password, 0, response, size, password.length); + clearPassword(); + return response; + } catch (UnsupportedEncodingException e) { + throw new SaslException("PLAIN: Cannot get UTF-8 encoding of ids", + e); + } + } + + public String getMechanismName() + { + return "PLAIN"; + } + + public boolean hasInitialResponse() + { + return true; + } + + public boolean isComplete() + { + return completed; + } + + public byte[] unwrap(byte[] incoming, int offset, int len) throws SaslException + { + if (completed) { + throw new IllegalStateException("PLAIN: this mechanism supports " + + "neither integrity nor privacy"); + } else { + throw new IllegalStateException("PLAIN: authentication not " + + "completed"); + } + } + + public byte[] wrap(byte[] outgoing, int offset, int len) throws SaslException + { + if (completed) + { + throw new IllegalStateException("PLAIN: this mechanism supports " + + "neither integrity nor privacy"); + } + else + { + throw new IllegalStateException("PLAIN: authentication not " + + "completed"); + } + } + + public Object getNegotiatedProperty(String propName) + { + if (completed) + { + if (propName.equals(Sasl.QOP)) + { + return "auth"; + } + else + { + return null; + } + } + else + { + throw new IllegalStateException("PLAIN: authentication not " + + "completed"); + } + } + + private void clearPassword() + { + if (password != null) + { + for (int i = 0 ; i < password.length ; i++) + { + password[i] = 0; + } + password = null; + } + } + + public void dispose() throws SaslException + { + clearPassword(); + } + + protected void finalize() + { + clearPassword(); + } + + private Object[] getUserInfo() throws SaslException + { + try + { + final String userPrompt = "PLAIN authentication id: "; + final String pwPrompt = "PLAIN password: "; + NameCallback nameCb = new NameCallback(userPrompt); + PasswordCallback passwordCb = new PasswordCallback(pwPrompt, false); + cbh.handle(new Callback[] { nameCb, passwordCb }); + String userid = nameCb.getName(); + char pwchars[] = passwordCb.getPassword(); + byte pwbytes[]; + if (pwchars != null) + { + pwbytes = (new String(pwchars)).getBytes("UTF8"); + passwordCb.clearPassword(); + } + else + { + pwbytes = null; + } + return (new Object[] { userid, pwbytes }); + } + catch (IOException e) + { + throw new SaslException("Cannot get password", e); + } + catch (UnsupportedCallbackException e) + { + throw new SaslException("Cannot get userid/password", e); + } + } +} diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/sasl/SaslProvider.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/sasl/SaslProvider.java new file mode 100644 index 0000000000..2917de8740 --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/sasl/SaslProvider.java @@ -0,0 +1,35 @@ +/* + * + * 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.sasl; + +import java.security.Provider; + +public class SaslProvider extends Provider +{ + private static final long serialVersionUID = -6978096016899676466L; + + public SaslProvider() + { + super("SaslClientFactory", 1.0, "SASL PLAIN CLIENT MECHANISM"); + put("SaslClientFactory.PLAIN", "ClientSaslFactory"); + } + +} diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/sasl/UserPasswordCallbackHandler.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/sasl/UserPasswordCallbackHandler.java new file mode 100644 index 0000000000..1602229c85 --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/sasl/UserPasswordCallbackHandler.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.management.ui.sasl; + +import java.io.*; +import javax.security.auth.callback.*; + +public class UserPasswordCallbackHandler implements CallbackHandler +{ + private String user; + private char[] pwchars; + + public UserPasswordCallbackHandler(String user, String password) + { + this.user = user; + this.pwchars = password.toCharArray(); + } + + public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException + { + for (int i = 0; i < callbacks.length; i++) + { + if (callbacks[i] instanceof NameCallback) + { + NameCallback ncb = (NameCallback) callbacks[i]; + ncb.setName(user); + } + else if (callbacks[i] instanceof PasswordCallback) + { + PasswordCallback pcb = (PasswordCallback) callbacks[i]; + pcb.setPassword(pwchars); + } + else + { + throw new UnsupportedCallbackException(callbacks[i]); + } + } + } + + private void clearPassword() + { + if (pwchars != null) + { + for (int i = 0 ; i < pwchars.length ; i++) + { + pwchars[i] = 0; + } + pwchars = null; + } + } + + protected void finalize() + { + clearPassword(); + } +} diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/sasl/UsernameHashedPasswordCallbackHandler.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/sasl/UsernameHashedPasswordCallbackHandler.java new file mode 100644 index 0000000000..f4e3d2661e --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/sasl/UsernameHashedPasswordCallbackHandler.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.management.ui.sasl; + +import java.io.IOException; + +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.UnsupportedCallbackException; + +import org.apache.qpid.management.ui.views.ViewUtility; + +public class UsernameHashedPasswordCallbackHandler implements CallbackHandler +{ + private String user; + private char[] pwchars; + + public UsernameHashedPasswordCallbackHandler(String user, String password) throws Exception + { + this.user = user; + this.pwchars = ViewUtility.getHash(password); + } + + public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException + { + for (int i = 0; i < callbacks.length; i++) + { + if (callbacks[i] instanceof NameCallback) + { + NameCallback ncb = (NameCallback) callbacks[i]; + ncb.setName(user); + } + else if (callbacks[i] instanceof PasswordCallback) + { + PasswordCallback pcb = (PasswordCallback) callbacks[i]; + pcb.setPassword(pwchars); + } + else + { + throw new UnsupportedCallbackException(callbacks[i]); + } + } + } + + + private void clearPassword() + { + if (pwchars != null) + { + for (int i = 0 ; i < pwchars.length ; i++) + { + pwchars[i] = 0; + } + pwchars = null; + } + } + + protected void finalize() + { + clearPassword(); + } +} diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/AttributesTabControl.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/AttributesTabControl.java index 437afeeda1..a7e8bbfc4c 100644 --- a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/AttributesTabControl.java +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/AttributesTabControl.java @@ -596,7 +596,7 @@ public class AttributesTabControl extends TabControl } // Refresh from the server registry - private void refresh() + public void refresh() { JMXServerRegistry serverRegistry = (JMXServerRegistry)ApplicationRegistry.getServerRegistry(_mbean); ManagedAttributeModel attributesList = serverRegistry.getAttributeModel(_mbean); diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/MBeanView.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/MBeanView.java index 59b9fe3aaa..344c3c4e7f 100644 --- a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/MBeanView.java +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/MBeanView.java @@ -62,6 +62,7 @@ public class MBeanView extends ViewPart private FormToolkit _toolkit = null; private Form _form = null; + private String _formText = APPLICATION_NAME; private static ManagedServer _server = null; private TreeObject _selectedNode = null; private ManagedBean _mbean = null; @@ -73,6 +74,8 @@ public class MBeanView extends ViewPart // TabFolder to list all the mbeans for a given mbeantype(eg Connection, Queue, Exchange) private TabFolder typeTabFolder = null; + + private TabFolder notificationTabFolder = null; /* * Listener for the selection events in the navigation view */ @@ -91,16 +94,41 @@ public class MBeanView extends ViewPart // an mbeantype. For mbeantype selection(eg Connection, Queue, Exchange) _mbean will remain null. _mbean = null; setInvisible(); - _form.setText(APPLICATION_NAME); - // If a selected node(mbean) gets unregistered from mbena server, mbenaview should should + // If a selected node(mbean) gets unregistered from mbean server, mbeanview should // make the tabfolber for that mbean invisible if (_selectedNode == null) return; setServer(); refreshMBeanView(); + setFormTitle(); + } + } + + private void setFormTitle() + { + if (_mbean != null) + { + _formText = _mbean.getType(); + if ((_mbean.getVirtualHostName() != null) && (!DEFAULT_VH.equals(_mbean.getVirtualHostName())) ) + { + _formText = _formText.replaceFirst(VIRTUAL_HOST, _mbean.getVirtualHostName()); + if (_mbean.getName() != null && _mbean.getName().length() != 0) + { + _formText = _formText + ": " + _mbean.getName(); + } + } + } + else if ((_selectedNode.getVirtualHost() != null) && (!DEFAULT_VH.equals(_selectedNode.getVirtualHost()))) + { + _formText = _selectedNode.getVirtualHost(); } + else + { + _formText = APPLICATION_NAME; + } + _form.setText(_formText); } public void refreshMBeanView() @@ -121,10 +149,16 @@ public class MBeanView extends ViewPart { refreshTypeTabFolder(_selectedNode.getName()); } - else + else if (NOTIFICATIONS.equals(_selectedNode.getType())) + { + refreshNotificationPage(); + } + else if (MBEAN.equals(_selectedNode.getType())) { + _mbean = (ManagedBean)_selectedNode.getManagedObject(); showSelectedMBean(); } + _form.layout(true); _form.getBody().layout(true, true); } @@ -174,20 +208,7 @@ public class MBeanView extends ViewPart } private void showSelectedMBean() throws Exception - { - if (NOTIFICATION.equals(_selectedNode.getType())) - { - _mbean = (ManagedBean)_selectedNode.getParent().getManagedObject(); - } - else if (MBEAN.equals(_selectedNode.getType())) - { - _mbean = (ManagedBean)_selectedNode.getManagedObject(); - } - else - { - return; - } - + { try { MBeanUtility.getMBeanInfo(_mbean); @@ -213,14 +234,8 @@ public class MBeanView extends ViewPart tabFolder = createMBeanTabFolder(); } - String text = _mbean.getType(); - if (_mbean.getName() != null && _mbean.getName().length() != 0) - { - text = text + ": " + _mbean.getName(); - } - _form.setText(text); int tabIndex = 0; - if (NOTIFICATION.equals(_selectedNode.getType())) + if (NOTIFICATIONS.equals(_selectedNode.getType())) { tabIndex = tabFolder.getItemCount() -1; } @@ -247,6 +262,8 @@ public class MBeanView extends ViewPart // Add mbeantype TabFolder. This will list all the mbeans under a mbeantype (eg Queue, Exchange). // Using this list mbeans will be added in the navigation view createMBeanTypeTabFolder(); + + createNotificationsTabFolder(); } private TabFolder createMBeanTabFolder() @@ -345,7 +362,7 @@ public class MBeanView extends ViewPart NotificationsTabControl controller = new NotificationsTabControl(tabFolder); TabItem tab = new TabItem(tabFolder, SWT.NONE); - tab.setText(NOTIFICATION); + tab.setText(NOTIFICATIONS); tab.setData(CONTROLLER, controller); tab.setControl(controller.getControl()); } @@ -432,6 +449,32 @@ public class MBeanView extends ViewPart }); } + private void createNotificationsTabFolder() + { + notificationTabFolder = new TabFolder(_form.getBody(), SWT.NONE); + FormData layoutData = new FormData(); + layoutData.left = new FormAttachment(0); + layoutData.top = new FormAttachment(0); + layoutData.right = new FormAttachment(100); + layoutData.bottom = new FormAttachment(100); + notificationTabFolder.setLayoutData(layoutData); + notificationTabFolder.setVisible(false); + + VHNotificationsTabControl controller = new VHNotificationsTabControl(notificationTabFolder); + TabItem tab = new TabItem(notificationTabFolder, SWT.NONE); + tab.setText(NOTIFICATIONS); + tab.setData(CONTROLLER, controller); + tab.setControl(controller.getControl()); + } + + private void refreshNotificationPage() + { + TabItem tab = notificationTabFolder.getItem(0); + VHNotificationsTabControl controller = (VHNotificationsTabControl)tab.getData(CONTROLLER); + controller.refresh(); + notificationTabFolder.setVisible(true); + } + /** * Refreshes the Selected mbeantype tab. The control lists all the available mbeans * for an mbeantype(eg Queue, Exchange etc) @@ -492,6 +535,11 @@ public class MBeanView extends ViewPart { typeTabFolder.setVisible(false); } + + if (notificationTabFolder != null) + { + notificationTabFolder.setVisible(false); + } } } diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/NavigationView.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/NavigationView.java index a861405d30..68f95e01f0 100644 --- a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/NavigationView.java +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/NavigationView.java @@ -244,7 +244,8 @@ public class NavigationView extends ViewPart List<TreeObject> list = _serversRootNode.getChildren(); for (TreeObject node : list) { - if (url.equals(node.getUrl())) + ManagedServer nodeServer = (ManagedServer)node.getManagedObject(); + if (url.equals(nodeServer.getUrl())) { // Server is already in the list of added servers, so now connect it. // Set the server node as selected and then connect it. @@ -266,7 +267,6 @@ public class NavigationView extends ViewPart // Server connection is successful. Now add the server in the tree TreeObject serverNode = new TreeObject(serverAddress, NODE_TYPE_SERVER); - serverNode.setUrl(url); serverNode.setManagedObject(managedServer); _serversRootNode.addChild(serverNode); @@ -504,6 +504,11 @@ public class NavigationView extends ViewPart typeChild = new TreeObject(QUEUE, NODE_TYPE_MBEANTYPE); typeChild.setParent(parent); typeChild.setVirtualHost(parent.getVirtualHost()); + + // Add common notification node for virtual host + TreeObject notificationNode = new TreeObject(NOTIFICATIONS, NOTIFICATIONS); + notificationNode.setParent(parent); + notificationNode.setVirtualHost(parent.getVirtualHost()); } /** @@ -585,7 +590,10 @@ public class NavigationView extends ViewPart // create a node for "type" typeNode = createTypeNode(parentNode, type); - typeNode.setVirtualHost(mbean.getVirtualHostName()); + if (!type.equals(VIRTUAL_HOST)) + { + typeNode.setVirtualHost(mbean.getVirtualHostName()); + } } // now type node create becomes the parent node for next node in hierarchy @@ -641,8 +649,8 @@ public class NavigationView extends ViewPart // Add notification node // TODO: show this only if the mbean sends any notification - TreeObject notificationNode = new TreeObject(NOTIFICATION, NOTIFICATION); - notificationNode.setParent(mbeanNode); + //TreeObject notificationNode = new TreeObject(NOTIFICATION, NOTIFICATION); + //notificationNode.setParent(mbeanNode); } private TreeObject createTypeNode(TreeObject parent, String name) @@ -1044,7 +1052,7 @@ public class NavigationView extends ViewPart public Image getImage(Object element) { TreeObject node = (TreeObject) element; - if (node.getType().equals(NOTIFICATION)) + if (node.getType().equals(NOTIFICATIONS)) { return ApplicationRegistry.getImage(NOTIFICATION_IMAGE); } @@ -1107,8 +1115,11 @@ public class NavigationView extends ViewPart { return 1; } - - return 2; + if (node.getType().equals(NOTIFICATIONS)) + { + return 2; + } + return 3; } } diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/NotificationsTabControl.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/NotificationsTabControl.java index 4f0acde1b4..6894080859 100644 --- a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/NotificationsTabControl.java +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/NotificationsTabControl.java @@ -20,29 +20,28 @@ */ package org.apache.qpid.management.ui.views; -import java.util.ArrayList; +import static org.apache.qpid.management.ui.Constants.BUTTON_CLEAR; +import static org.apache.qpid.management.ui.Constants.BUTTON_REFRESH; +import static org.apache.qpid.management.ui.Constants.DESCRIPTION; +import static org.apache.qpid.management.ui.Constants.FONT_BOLD; +import static org.apache.qpid.management.ui.Constants.FONT_BUTTON; +import static org.apache.qpid.management.ui.Constants.FONT_ITALIC; +import static org.apache.qpid.management.ui.Constants.SUBSCRIBE_BUTTON; +import static org.apache.qpid.management.ui.Constants.UNSUBSCRIBE_BUTTON; + import java.util.List; -import static org.apache.qpid.management.ui.Constants.*; import org.apache.qpid.management.ui.ApplicationRegistry; import org.apache.qpid.management.ui.ManagedBean; import org.apache.qpid.management.ui.ServerRegistry; import org.apache.qpid.management.ui.jmx.MBeanUtility; import org.apache.qpid.management.ui.model.NotificationInfoModel; import org.apache.qpid.management.ui.model.NotificationObject; -import org.eclipse.jface.viewers.DoubleClickEvent; -import org.eclipse.jface.viewers.IDoubleClickListener; -import org.eclipse.jface.viewers.ILabelProviderListener; -import org.eclipse.jface.viewers.IStructuredContentProvider; -import org.eclipse.jface.viewers.ITableLabelProvider; -import org.eclipse.jface.viewers.StructuredSelection; -import org.eclipse.jface.viewers.TableViewer; -import org.eclipse.jface.viewers.Viewer; +import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; -import org.eclipse.swt.graphics.Image; import org.eclipse.swt.layout.FormAttachment; import org.eclipse.swt.layout.FormData; import org.eclipse.swt.layout.FormLayout; @@ -52,71 +51,35 @@ import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Combo; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.TabFolder; -import org.eclipse.swt.widgets.Table; -import org.eclipse.swt.widgets.TableColumn; -import org.eclipse.swt.widgets.Text; -import org.eclipse.ui.forms.widgets.Form; -import org.eclipse.ui.forms.widgets.FormToolkit; /** * Creates control composite for Notifications tab * @author Bhupendra Bhardwaj */ -public class NotificationsTabControl extends TabControl -{ - private FormToolkit _toolkit; - private Form _form; - private Table table = null; - private TableViewer _tableViewer = null; - - private IStructuredContentProvider contentProvider = new ContentProviderImpl(); - private SelectionListener selectionListener = new SelectionListenerImpl(); - private SelectionListener comboListener = new ComboSelectionListener(); - - private Thread worker = null; - - private List<NotificationObject> _notifications = null; - private static final String COLUMN_SEQ = "Sequence No"; - private static final String COLUMN_TIME = "TimeStamp"; - private static final String COLUMN_TYPE = "Type"; - private static final String COLUMN_MSG = "Notification Message"; - private static final String[] _tableTitles = new String [] { - COLUMN_SEQ, - COLUMN_TIME, - COLUMN_TYPE, - COLUMN_MSG - }; +public class NotificationsTabControl extends VHNotificationsTabControl +{ + private static final String SELECT_NOTIFICATIONNAME = "Select Notification"; + private static final String SELECT_NOTIFICATIONTYPE = "Select Type"; + private SelectionListener selectionListener; + private SelectionListener comboListener; private Combo notificationNameCombo = null; private Combo typesCombo = null; private Label descriptionLabel = null; private Button _subscribeButton = null; private Button _unsubscribeButton = null; - private Button _clearButton = null; - private Button _refreshButton = null; - public NotificationsTabControl(TabFolder tabFolder) { super(tabFolder); - _toolkit = new FormToolkit(_tabFolder.getDisplay()); - _form = _toolkit.createForm(_tabFolder); - GridLayout gridLayout = new GridLayout(); - gridLayout.marginWidth = 0; - gridLayout.marginHeight = 0; - _form.getBody().setLayout(gridLayout); - - createWidgets(); - worker = new Thread(new Worker()); - worker.start(); } - private void createWidgets() + protected void createWidgets() { + selectionListener = new SelectionListenerImpl(); + comboListener = new ComboSelectionListener(); createNotificationInfoComposite(); //addFilterComposite(); addButtons(); @@ -124,14 +87,6 @@ public class NotificationsTabControl extends TabControl } /** - * @see TabControl#getControl() - */ - public Control getControl() - { - return _form; - } - - /** * Creates composite and populates for displaying Notification Information (name, type, description) * and creates buttons for subscribing or unsubscribing for notifications */ @@ -205,7 +160,7 @@ public class NotificationsTabControl extends TabControl /** * Creates clear buttin and refresh button */ - private void addButtons() + protected void addButtons() { Composite composite = _toolkit.createComposite(_form.getBody(), SWT.NONE); composite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); @@ -224,8 +179,9 @@ public class NotificationsTabControl extends TabControl if (_mbean == null) return; + IStructuredSelection ss = (IStructuredSelection)_tableViewer.getSelection(); ServerRegistry serverRegistry = ApplicationRegistry.getServerRegistry(_mbean); - serverRegistry.clearNotifications(_mbean); + serverRegistry.clearNotifications(_mbean, ss.toList()); refresh(); } }); @@ -247,155 +203,13 @@ public class NotificationsTabControl extends TabControl } }); } - - /** - * Creates table to display notifications - */ - private void createTable() - { - table = _toolkit.createTable(_form.getBody(), SWT.FULL_SELECTION); - table.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); - - TableColumn column = new TableColumn(table, SWT.NONE); - column.setText(_tableTitles[0]); - column.pack(); //column.setWidth(200); - - column = new TableColumn(table, SWT.NONE); - column.setText(_tableTitles[1]); - column.setWidth(150); - - column = new TableColumn(table, SWT.NONE); - column.setText(_tableTitles[2]); - column.setWidth(100); - - column = new TableColumn(table, SWT.NONE); - column.setText(_tableTitles[3]); - column.setWidth(500); - - table.setHeaderVisible(true); - table.setLinesVisible(true); - } - - /** - * Creates JFace viewer for the notifications table - */ - protected void createTableViewer() - { - createTable(); - _tableViewer = new TableViewer(table); - //_tableViewer.getControl().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); - _tableViewer.setUseHashlookup(true); - _tableViewer.setContentProvider(contentProvider); - _tableViewer.setLabelProvider(new LabelProviderImpl()); - _tableViewer.setColumnProperties(_tableTitles); - /* - CellEditor[] cellEditors = new CellEditor[_tableTitles.length]; - TextCellEditor textEditor = new TextCellEditor(table); - cellEditors[0] = textEditor; - textEditor = new TextCellEditor(table); - cellEditors[1] = textEditor; - textEditor = new TextCellEditor(table); - cellEditors[2] = textEditor; - textEditor = new TextCellEditor(table); - cellEditors[3] = textEditor; - - // Assign the cell editors to the viewer - _tableViewer.setCellEditors(cellEditors); - _tableViewer.setCellModifier(new TableCellModifier()); - */ - - addTableListeners(); - - //_tableViewer.addSelectionChangedListener(new ); - - //_notificationDetails = new Composite(_tabControl, SWT.BORDER); - //_notificationDetails.setLayoutData(new GridData(GridData.FILL_BOTH)); - - //_tabControl.layout(); - //viewerComposite.layout(); - } - - /** - * Adds listeners to the viewer for displaying notification details - */ - private void addTableListeners() - { - _tableViewer.addDoubleClickListener(new IDoubleClickListener() - { - Display display = null; - Shell shell = null; - public void doubleClick(DoubleClickEvent event) - { - display = Display.getCurrent(); - shell = new Shell(display, SWT.BORDER | SWT.CLOSE | SWT.MIN | - SWT.MAX | SWT.RESIZE); - shell.setText("Notification"); - - int x = display.getBounds().width; - int y = display.getBounds().height; - shell.setBounds(x/4, y/4, x/2, y/3); - StructuredSelection selection = (StructuredSelection)event.getSelection(); - createPopupContents((NotificationObject)selection.getFirstElement()); - shell.open(); - while (!shell.isDisposed()) { - if (!display.readAndDispatch()) { - display.sleep(); - } - } - - //If you create it, you dispose it. - shell.dispose(); - } - - private void createPopupContents(NotificationObject obj) - { - shell.setLayout(new GridLayout()); - - Composite parent = new Composite(shell, SWT.NONE); - parent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); - GridLayout layout = new GridLayout(4, true); - parent.setLayout(layout); - - Label key = new Label(parent, SWT.TRAIL); - key.setText(COLUMN_SEQ); - GridData layoutData = new GridData(SWT.TRAIL, SWT.TOP, false, false,1,1); - key.setLayoutData(layoutData); - Text value = new Text(parent, SWT.BEGINNING | SWT.BORDER |SWT.READ_ONLY); - value.setText(""+obj.getSequenceNo()); - value.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false,3,1)); - - // Time row - key = new Label(parent, SWT.TRAIL); - key.setText(COLUMN_TIME); - key.setLayoutData(new GridData(SWT.TRAIL, SWT.TOP, true, false,1,1)); - value = new Text(parent, SWT.BEGINNING | SWT.BORDER | SWT.READ_ONLY); - value.setText(""+obj.getTimeStamp()); - value.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false,3,1)); - - key = new Label(parent, SWT.TRAIL); - key.setText(COLUMN_TYPE); - key.setLayoutData(new GridData(SWT.TRAIL, SWT.TOP, true, false,1,1)); - value = new Text(parent, SWT.BEGINNING | SWT.BORDER | SWT.READ_ONLY); - value.setText(""+obj.getType()); - value.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false,3,1)); - - key = new Label(parent, SWT.TRAIL); - key.setText(COLUMN_MSG); - key.setLayoutData(new GridData(SWT.TRAIL, SWT.TOP, true, false,1,1)); - value = new Text(parent, SWT.MULTI | SWT.WRAP| SWT.BORDER | SWT.V_SCROLL | SWT.READ_ONLY); - value.setText(""+obj.getMessage()); - GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true, 3, 1); - gridData.heightHint = 100; - value.setLayoutData(gridData); - } - }); - } - + @Override public void refresh(ManagedBean mbean) { _mbean = mbean; _notifications = null; + _table.deselectAll(); _tableViewer.getTable().clearAll(); if (_mbean == null) @@ -431,9 +245,10 @@ public class NotificationsTabControl extends TabControl _form.getBody().layout(true, true); } - private void refresh() + public void refresh() { _notifications = null; + _table.deselectAll(); _tableViewer.getTable().clearAll(); } @@ -444,7 +259,11 @@ public class NotificationsTabControl extends TabControl { notificationNameCombo.removeAll(); NotificationInfoModel[] items = MBeanUtility.getNotificationInfo(_mbean); - notificationNameCombo.add("Select Notification"); + if (items.length > 1) + { + notificationNameCombo.add(SELECT_NOTIFICATIONNAME); + } + for (int i = 0; i < items.length; i++) { notificationNameCombo.add(items[i].getName()); @@ -457,6 +276,7 @@ public class NotificationsTabControl extends TabControl typesCombo.select(0); typesCombo.setEnabled(false); + populateNotificationType(notificationNameCombo.getItem(0)); checkForEnablingButtons(); } @@ -466,7 +286,8 @@ public class NotificationsTabControl extends TabControl private void checkForEnablingButtons() { int nameIndex = notificationNameCombo.getSelectionIndex(); - if (nameIndex == 0) + int itemCount = notificationNameCombo.getItems().length; + if ((itemCount > 1) && (nameIndex == 0)) { _subscribeButton.setEnabled(false); _unsubscribeButton.setEnabled(false); @@ -475,7 +296,8 @@ public class NotificationsTabControl extends TabControl } int typeIndex = typesCombo.getSelectionIndex(); - if (typeIndex == 0) + itemCount = typesCombo.getItems().length; + if ((itemCount > 1) && (typeIndex == 0)) { _subscribeButton.setEnabled(false); _unsubscribeButton.setEnabled(false); @@ -560,164 +382,38 @@ public class NotificationsTabControl extends TabControl Combo combo = (Combo)e.getSource(); if (combo == notificationNameCombo) { - if (combo.getSelectionIndex() == 0) - { - descriptionLabel.setText(""); - typesCombo.select(0); - typesCombo.setEnabled(false); - return; - } - String index = combo.getItem(combo.getSelectionIndex()); - NotificationInfoModel data = (NotificationInfoModel)combo.getData(index); - descriptionLabel.setText(data.getDescription()); - typesCombo.removeAll(); - typesCombo.setItems(data.getTypes()); - typesCombo.add("Select Type", 0); - typesCombo.select(0); - typesCombo.setEnabled(true); + String selectedItem = combo.getItem(combo.getSelectionIndex()); + populateNotificationType(selectedItem); } checkForEnablingButtons(); } } - /** - * Content provider class for the table viewer - */ - private class ContentProviderImpl implements IStructuredContentProvider, INotificationViewer + private void populateNotificationType(String notificationName) { - public void inputChanged(Viewer v, Object oldInput, Object newInput) + NotificationInfoModel data = (NotificationInfoModel)notificationNameCombo.getData(notificationName); + if (data == null) { - - } - public void dispose() - { - - } - public Object[] getElements(Object parent) - { - return _notifications.toArray(new NotificationObject[0]); - } - public void addNotification(NotificationObject notification) - { - _tableViewer.add(notification); - } - - public void addNotification(List<NotificationObject> notificationList) - { - _tableViewer.add(notificationList.toArray(new NotificationObject[0])); - } - } - - /** - * Label provider for the table viewer - */ - private class LabelProviderImpl implements ITableLabelProvider - { - List<ILabelProviderListener> listeners = new ArrayList<ILabelProviderListener>(); - public void addListener(ILabelProviderListener listener) - { - listeners.add(listener); - } - - public void dispose(){ - - } - - public Image getColumnImage(Object element, int columnIndex) - { - return null; - } - - public String getColumnText(Object element, int columnIndex) - { - String result = null; - NotificationObject t = (NotificationObject)element; - switch(columnIndex) - { - case 0 : - result = String.valueOf(t.getSequenceNo()); - break; - case 1 : - result = String.valueOf(t.getTimeStamp()); - break; - case 2 : - result = t.getType(); - break; - case 3 : - result = t.getMessage(); - break; - default : - result = ""; - } - - return result; - } - - public boolean isLabelProperty(Object element, String property) - { - return false; - } - - public void removeListener(ILabelProviderListener listener) - { - listeners.remove(listener); - } - } // end of LabelProviderImpl - - private boolean workerRunning = false; - private void setWorkerRunning(boolean running) - { - workerRunning = running; - } - - /** - * Worker class which keeps looking if there are new notifications coming from server for the selected mbean - */ - private class Worker implements Runnable - { - public void run() - { - Display display = _tabFolder.getDisplay(); - while(true) - { - if (!workerRunning || _mbean == null || display == null) - { - sleep(); - continue; - } - - display.syncExec(new Runnable() - { - public void run() - { - setWorkerRunning(_form.isVisible()); - if (!workerRunning) return; - - updateTableViewer(); - } - }); - - sleep(); - } + descriptionLabel.setText(""); + typesCombo.select(0); + typesCombo.setEnabled(false); + return; } - - private void sleep() + descriptionLabel.setText(data.getDescription()); + typesCombo.removeAll(); + typesCombo.setItems(data.getTypes()); + if (typesCombo.getItemCount() > 1) { - try - { - Thread.sleep(2000); - } - catch(Exception ex) - { - - } + typesCombo.add(SELECT_NOTIFICATIONTYPE, 0); } + typesCombo.select(0); + typesCombo.setEnabled(true); } /** * Updates the table with new notifications received from mbean server for the selected mbean */ - private void updateTableViewer() + protected void updateTableViewer() { ServerRegistry serverRegistry = ApplicationRegistry.getServerRegistry(_mbean); List<NotificationObject> newList = serverRegistry.getNotifications(_mbean); diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/OperationTabControl.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/OperationTabControl.java index 49b61c0fc6..2ac037e4f0 100644 --- a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/OperationTabControl.java +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/OperationTabControl.java @@ -20,10 +20,16 @@ */ package org.apache.qpid.management.ui.views; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map.Entry; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.TabularDataSupport; + import static org.apache.qpid.management.ui.Constants.*; import org.apache.qpid.management.ui.ApplicationRegistry; import org.apache.qpid.management.ui.ManagedBean; @@ -76,7 +82,7 @@ public class OperationTabControl extends TabControl private SelectionListener operationExecutionListener = new OperationExecutionListener(); private SelectionListener refreshListener = new RefreshListener(); private SelectionListener parameterSelectionListener = new ParameterSelectionListener(); - private SelectionListener bolleanSelectionListener = new BooleanSelectionListener(); + private SelectionListener booleanSelectionListener = new BooleanSelectionListener(); private VerifyListener verifyListener = new VerifyListenerImpl(); private KeyListener keyListener = new KeyListenerImpl(); private KeyListener headerBindingListener = new HeaderBindingKeyListener(); @@ -249,6 +255,8 @@ public class OperationTabControl extends TabControl formData.top = new FormAttachment(0, parameterPositionOffset); formData.left = new FormAttachment(label, 5); formData.right = new FormAttachment(valueWidth); + // this will contain the list of items, if the list is to be made available to choose from + // e.g. the list of exchanges String[] items = null; if (param.getName().equals(QUEUE)) { @@ -269,6 +277,15 @@ public class OperationTabControl extends TabControl { items = EXCHANGE_TYPE_VALUES; } + else if (_mbean.isAdmin() && param.getName().equals(OPERATION_PARAM_USERNAME) + && !_opData.getName().equals(OPERATION_CREATEUSER)) + { + List<String> list = ApplicationRegistry.getServerRegistry(_mbean).getUsernames(); + if (list != null && !list.isEmpty()) + { + items = list.toArray(new String[0]); + } + } if (items != null) { @@ -295,12 +312,17 @@ public class OperationTabControl extends TabControl Button booleanButton = _toolkit.createButton(_paramsComposite, "", SWT.CHECK); booleanButton.setLayoutData(formData); booleanButton.setData(param); - booleanButton.addSelectionListener(bolleanSelectionListener); + booleanButton.addSelectionListener(booleanSelectionListener); valueInCombo = true; } else { - Text text = _toolkit.createText(_paramsComposite, "", SWT.NONE); + int style = SWT.NONE; + if (PASSWORD.equalsIgnoreCase(param.getName())) + { + style = SWT.PASSWORD; + } + Text text = _toolkit.createText(_paramsComposite, "", style); formData = new FormData(); formData.top = new FormAttachment(0, parameterPositionOffset); formData.left = new FormAttachment(label, 5); @@ -530,6 +552,8 @@ public class OperationTabControl extends TabControl ((org.eclipse.swt.widgets.List)controls[i]).deselectAll(); else if (controls[i] instanceof Text) ((Text)controls[i]).setText(""); + else if (controls[i] instanceof Button) + ((Button)controls[i]).setSelection(false); else if (controls[i] instanceof Composite) clearParameterValues((Composite)controls[i]); } @@ -557,6 +581,21 @@ public class OperationTabControl extends TabControl } // End of custom code + + // customized for passwords + if (PASSWORD.equalsIgnoreCase(param.getName())) + { + try + { + param.setValueFromString(ViewUtility.getHashedString(param.getValue())); + } + catch (Exception ex) + { + MBeanUtility.handleException(_mbean, ex); + return; + } + } + // end of customization ViewUtility.popupInfoMessage(_form.getText(), "Please select the " + ViewUtility.getDisplayText(param.getName())); @@ -609,6 +648,17 @@ public class OperationTabControl extends TabControl return; } + // Custom code for Admin mbean operation + /* These custome codes here are to make the GUI look more user friendly. + * Here we are adding the users to a list, which will be used to list username to be selected on + * pages like "delete user", "set password" instead of typing the username + */ + if (_mbean.isAdmin() && _opData.getName().equals(OPERATION_VIEWUSERS)) + { + ApplicationRegistry.getServerRegistry(_mbean).setUserList(extractUserList(result)); + } + // end of custom code + // Some mbeans have only "type" and no "name". String title = _mbean.getType(); if (_mbean.getName() != null && _mbean.getName().length() != 0) @@ -616,9 +666,15 @@ public class OperationTabControl extends TabControl title = _mbean.getName(); } - if (_opData.getReturnType().equals("void") || _opData.getReturnType().equals("java.lang.Void")) + if (_opData.isReturnTypeVoid()) + { + ViewUtility.popupInfoMessage(title, OPERATION_SUCCESSFUL); + } + else if (_opData.isReturnTypeBoolean()) { - ViewUtility.popupInfoMessage(title, "Operation successful"); + boolean success = Boolean.parseBoolean(result.toString()); + String message = success ? OPERATION_SUCCESSFUL : OPERATION_UNSUCCESSFUL; + ViewUtility.popupInfoMessage(title, message); } else if (_opData.getParameters() != null && !_opData.getParameters().isEmpty()) { @@ -634,6 +690,24 @@ public class OperationTabControl extends TabControl } + private List<String> extractUserList(Object result) + { + if (!(result instanceof TabularDataSupport)) + { + return null; + } + + TabularDataSupport tabularData = (TabularDataSupport)result; + Collection<CompositeData> records = tabularData.values(); + List<String> list = new ArrayList<String>(); + for (CompositeData data : records) + { + list.add(data.get(USERNAME).toString()); + } + Collections.sort(list); + return list; + } + /** * Listener class for the operation parameters widget */ diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/TabControl.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/TabControl.java index 0793e33538..c13c92066c 100644 --- a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/TabControl.java +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/TabControl.java @@ -69,7 +69,18 @@ public abstract class TabControl return null; } - public abstract void refresh(ManagedBean mbean); + public void refresh(ManagedBean mbean) + { + if (mbean == null) + { + refresh(); + } + } + + public void refresh() + { + + } public void refresh(ManagedBean mbean, OperationData opData) { diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/TreeObject.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/TreeObject.java index 511c2d7150..9545ed9876 100644 --- a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/TreeObject.java +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/TreeObject.java @@ -31,7 +31,6 @@ public class TreeObject { private String _name; private String _type; - private String _url; private String _virtualHost; private TreeObject _parent; private List<TreeObject> _children = new ArrayList<TreeObject>(); @@ -88,16 +87,6 @@ public class TreeObject { return _type; } - - public String getUrl() - { - return _url; - } - - public void setUrl(String url) - { - this._url = url; - } public String getVirtualHost() { @@ -131,7 +120,6 @@ public class TreeObject if (parent != null) { - this._url = parent.getUrl(); parent.addChild(this); } } diff --git a/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/VHNotificationsTabControl.java b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/VHNotificationsTabControl.java new file mode 100644 index 0000000000..258f5ce02a --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/views/VHNotificationsTabControl.java @@ -0,0 +1,462 @@ +package org.apache.qpid.management.ui.views; + +import static org.apache.qpid.management.ui.Constants.BUTTON_CLEAR; +import static org.apache.qpid.management.ui.Constants.BUTTON_REFRESH; +import static org.apache.qpid.management.ui.Constants.CONSOLE_IMAGE; +import static org.apache.qpid.management.ui.Constants.FONT_BUTTON; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.qpid.management.ui.ApplicationRegistry; +import org.apache.qpid.management.ui.ServerRegistry; +import org.apache.qpid.management.ui.model.NotificationObject; +import org.eclipse.jface.viewers.DoubleClickEvent; +import org.eclipse.jface.viewers.IDoubleClickListener; +import org.eclipse.jface.viewers.ILabelProviderListener; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredContentProvider; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.ITableLabelProvider; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.TabFolder; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableColumn; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.forms.widgets.Form; +import org.eclipse.ui.forms.widgets.FormToolkit; + +public class VHNotificationsTabControl extends TabControl +{ + protected FormToolkit _toolkit; + protected Form _form; + protected Table _table = null; + protected TableViewer _tableViewer = null; + + protected Thread worker = null; + + protected List<NotificationObject> _notifications = null; + + private static final String COLUMN_OBJ = "Object Name"; + private static final String COLUMN_SEQ = "Sequence No"; + private static final String COLUMN_TIME = "TimeStamp"; + private static final String COLUMN_TYPE = "Type"; + private static final String COLUMN_MSG = "Notification Message"; + protected static final String[] _tableTitles = new String [] { + COLUMN_OBJ, + COLUMN_SEQ, + COLUMN_TIME, + COLUMN_TYPE, + COLUMN_MSG + }; + + protected Button _clearButton = null; + protected Button _refreshButton = null; + + public VHNotificationsTabControl(TabFolder tabFolder) + { + super(tabFolder); + _toolkit = new FormToolkit(_tabFolder.getDisplay()); + _form = _toolkit.createForm(_tabFolder); + GridLayout gridLayout = new GridLayout(); + gridLayout.marginWidth = 0; + gridLayout.marginHeight = 0; + _form.getBody().setLayout(gridLayout); + + worker = new Thread(new Worker()); + worker.start(); + } + + protected void createWidgets() + { + addButtons(); + createTableViewer(); + } + + /** + * @see TabControl#getControl() + */ + public Control getControl() + { + if (_table == null) + { + createWidgets(); + } + return _form; + } + + /** + * Creates clear buttin and refresh button + */ + protected void addButtons() + { + Composite composite = _toolkit.createComposite(_form.getBody(), SWT.NONE); + composite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + composite.setLayout(new GridLayout(2, true)); + + // Add Clear Button + _clearButton = _toolkit.createButton(composite, BUTTON_CLEAR, SWT.PUSH | SWT.CENTER); + _clearButton.setFont(ApplicationRegistry.getFont(FONT_BUTTON)); + GridData gridData = new GridData(SWT.LEAD, SWT.TOP, true, false); + gridData.widthHint = 80; + _clearButton.setLayoutData(gridData); + _clearButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + //TODO : Get selected rows and clear those + IStructuredSelection ss = (IStructuredSelection)_tableViewer.getSelection(); + ServerRegistry serverRegistry = ApplicationRegistry.getServerRegistry(MBeanView.getServer()); + serverRegistry.clearNotifications(null, ss.toList()); + refresh(); + } + }); + + // Add Refresh Button + _refreshButton = _toolkit.createButton(composite, BUTTON_REFRESH, SWT.PUSH | SWT.CENTER); + _refreshButton.setFont(ApplicationRegistry.getFont(FONT_BUTTON)); + gridData = new GridData(SWT.TRAIL, SWT.TOP, true, false); + gridData.widthHint = 80; + _refreshButton.setLayoutData(gridData); + _refreshButton.addSelectionListener(new SelectionAdapter() + { + public void widgetSelected(SelectionEvent e) + { + refresh(); + } + }); + } + + /** + * Creates table to display notifications + */ + private void createTable() + { + _table = _toolkit.createTable(_form.getBody(), SWT.MULTI | SWT.FULL_SELECTION); + _table.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + + TableColumn column = new TableColumn(_table, SWT.NONE); + column.setText(_tableTitles[0]); + column.setWidth(100); + + column = new TableColumn(_table, SWT.NONE); + column.setText(_tableTitles[1]); + column.setWidth(100); + + column = new TableColumn(_table, SWT.NONE); + column.setText(_tableTitles[2]); + column.setWidth(130); + + column = new TableColumn(_table, SWT.NONE); + column.setText(_tableTitles[3]); + column.setWidth(100); + + column = new TableColumn(_table, SWT.NONE); + column.setText(_tableTitles[4]); + column.setWidth(500); + + _table.setHeaderVisible(true); + _table.setLinesVisible(true); + } + + /** + * Creates JFace viewer for the notifications table + */ + protected void createTableViewer() + { + createTable(); + _tableViewer = new TableViewer(_table); + //_tableViewer.getControl().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + _tableViewer.setUseHashlookup(true); + _tableViewer.setContentProvider(new ContentProviderImpl()); + _tableViewer.setLabelProvider(new LabelProviderImpl()); + _tableViewer.setColumnProperties(_tableTitles); + /* + CellEditor[] cellEditors = new CellEditor[_tableTitles.length]; + TextCellEditor textEditor = new TextCellEditor(table); + cellEditors[0] = textEditor; + textEditor = new TextCellEditor(table); + cellEditors[1] = textEditor; + textEditor = new TextCellEditor(table); + cellEditors[2] = textEditor; + textEditor = new TextCellEditor(table); + cellEditors[3] = textEditor; + + // Assign the cell editors to the viewer + _tableViewer.setCellEditors(cellEditors); + _tableViewer.setCellModifier(new TableCellModifier()); + */ + + addTableListeners(); + + //_tableViewer.addSelectionChangedListener(new ); + + //_notificationDetails = new Composite(_tabControl, SWT.BORDER); + //_notificationDetails.setLayoutData(new GridData(GridData.FILL_BOTH)); + + //_tabControl.layout(); + //viewerComposite.layout(); + } + + /** + * Adds listeners to the viewer for displaying notification details + */ + protected void addTableListeners() + { + _tableViewer.addDoubleClickListener(new IDoubleClickListener() + { + Display display = null; + Shell shell = null; + public void doubleClick(DoubleClickEvent event) + { + display = Display.getCurrent(); + shell = new Shell(display, SWT.BORDER | SWT.CLOSE | SWT.MIN | SWT.MAX | SWT.RESIZE); + shell.setText("Notification"); + shell.setImage(ApplicationRegistry.getImage(CONSOLE_IMAGE)); + + int x = display.getBounds().width; + int y = display.getBounds().height; + shell.setBounds(x/4, y/4, x/2, y/3); + StructuredSelection selection = (StructuredSelection)event.getSelection(); + createPopupContents((NotificationObject)selection.getFirstElement()); + shell.open(); + while (!shell.isDisposed()) { + if (!display.readAndDispatch()) { + display.sleep(); + } + } + + //If you create it, you dispose it. + shell.dispose(); + } + + private void createPopupContents(NotificationObject obj) + { + shell.setLayout(new GridLayout()); + + Composite parent = _toolkit.createComposite(shell, SWT.NONE); + parent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + GridLayout layout = new GridLayout(4, true); + parent.setLayout(layout); + + // Object name record + Label key = _toolkit.createLabel(parent, COLUMN_OBJ, SWT.TRAIL); + GridData layoutData = new GridData(SWT.TRAIL, SWT.TOP, false, false,1,1); + key.setLayoutData(layoutData); + Text value = _toolkit.createText(parent, obj.getSourceName(), SWT.BEGINNING | SWT.BORDER |SWT.READ_ONLY); + value.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false,3,1)); + + // Sequence no record + key = _toolkit.createLabel(parent, COLUMN_SEQ, SWT.TRAIL); + layoutData = new GridData(SWT.TRAIL, SWT.TOP, false, false,1,1); + key.setLayoutData(layoutData); + value = _toolkit.createText(parent, ""+obj.getSequenceNo(), SWT.BEGINNING | SWT.BORDER |SWT.READ_ONLY); + value.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false,3,1)); + + // Time row + key = _toolkit.createLabel(parent, COLUMN_TIME, SWT.TRAIL); + key.setLayoutData(new GridData(SWT.TRAIL, SWT.TOP, true, false,1,1)); + value = _toolkit.createText(parent, obj.getTimeStamp(), SWT.BEGINNING | SWT.BORDER | SWT.READ_ONLY); + value.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false,3,1)); + + key = _toolkit.createLabel(parent, COLUMN_TYPE, SWT.TRAIL); + key.setLayoutData(new GridData(SWT.TRAIL, SWT.TOP, true, false,1,1)); + value = _toolkit.createText(parent, obj.getType(), SWT.BEGINNING | SWT.BORDER | SWT.READ_ONLY); + value.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false,3,1)); + + key = _toolkit.createLabel(parent, COLUMN_MSG, SWT.TRAIL); + key.setLayoutData(new GridData(SWT.TRAIL, SWT.TOP, true, false,1,1)); + value = _toolkit.createText(parent, obj.getMessage(), SWT.MULTI | SWT.WRAP| SWT.BORDER | SWT.V_SCROLL | SWT.READ_ONLY); + GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true, 3, 1); + gridData.heightHint = 100; + value.setLayoutData(gridData); + } + }); + } + + public void refresh() + { + _notifications = null; + _table.deselectAll(); + _tableViewer.getTable().clearAll(); + + Control[] children = _form.getBody().getChildren(); + for (int i = 0; i < children.length; i++) + { + children[i].setVisible(true); + } + + workerRunning = true; + _form.layout(true); + _form.getBody().layout(true, true); + } + + /** + * Content provider class for the table viewer + */ + protected class ContentProviderImpl implements IStructuredContentProvider, INotificationViewer + { + public void inputChanged(Viewer v, Object oldInput, Object newInput) + { + + } + public void dispose() + { + + } + public Object[] getElements(Object parent) + { + return _notifications.toArray(new NotificationObject[0]); + } + public void addNotification(NotificationObject notification) + { + _tableViewer.add(notification); + } + + public void addNotification(List<NotificationObject> notificationList) + { + _tableViewer.add(notificationList.toArray(new NotificationObject[0])); + } + } + + /** + * Label provider for the table viewer + */ + protected class LabelProviderImpl implements ITableLabelProvider + { + List<ILabelProviderListener> listeners = new ArrayList<ILabelProviderListener>(); + public void addListener(ILabelProviderListener listener) + { + listeners.add(listener); + } + + public void dispose(){ + + } + + public Image getColumnImage(Object element, int columnIndex) + { + return null; + } + + public String getColumnText(Object element, int columnIndex) + { + String result = null; + NotificationObject t = (NotificationObject)element; + switch(columnIndex) + { + case 0 : + result = t.getSourceName(); + break; + case 1 : + result = String.valueOf(t.getSequenceNo()); + break; + case 2 : + result = String.valueOf(t.getTimeStamp()); + break; + case 3 : + result = t.getType(); + break; + case 4 : + result = t.getMessage(); + break; + default : + result = ""; + } + + return result; + } + + public boolean isLabelProperty(Object element, String property) + { + return false; + } + + public void removeListener(ILabelProviderListener listener) + { + listeners.remove(listener); + } + } // end of LabelProviderImpl + + protected boolean workerRunning = false; + protected void setWorkerRunning(boolean running) + { + workerRunning = running; + } + + /** + * Worker class which keeps looking if there are new notifications coming from server for the selected mbean + */ + private class Worker implements Runnable + { + public void run() + { + Display display = _tabFolder.getDisplay(); + while(true) + { + if (!workerRunning || display == null) + { + sleep(); + continue; + } + + display.syncExec(new Runnable() + { + public void run() + { + if (_form == null || _form.isDisposed()) + return; + setWorkerRunning(_form.isVisible()); + if (!workerRunning) return; + + updateTableViewer(); + } + }); + + sleep(); + } + } + + private void sleep() + { + try + { + Thread.sleep(2000); + } + catch(Exception ex) + { + + } + } + } + + /** + * Updates the table with new notifications received from mbean server for all mbeans + */ + protected void updateTableViewer() + { + ServerRegistry serverRegistry = ApplicationRegistry.getServerRegistry(MBeanView.getServer()); + List<NotificationObject> newList = serverRegistry.getNotifications(null); + if (newList == null) + return; + + _notifications = newList; + _tableViewer.setInput(_notifications); + _tableViewer.refresh(); + } + +} 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 9625a58f20..9b5cddd342 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 @@ -20,8 +20,13 @@ */ package org.apache.qpid.management.ui.views; +import java.io.UnsupportedEncodingException; import java.nio.charset.Charset; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.Set; @@ -70,6 +75,8 @@ public class ViewUtility public static final String PREV = "Previous"; public static final String INDEX = "Index"; + private static final Comparator tabularDataComparator = new TabularDataComparator(); + private static List<String> SUPPORTED_ARRAY_DATATYPES = new ArrayList<String>(); static { @@ -121,6 +128,9 @@ public class ViewUtility text.setLayoutData(layoutData); return; } + + Collections.sort(list, tabularDataComparator); + // Attach the tabular record to be retrieved and shown later when record is traversed // using first/next/previous/last buttons composite.setData(list); @@ -549,4 +559,63 @@ public class ViewUtility oldControls[i].dispose(); } } + + public static String getHashedString(Object text) throws NoSuchAlgorithmException, UnsupportedEncodingException + { + char[] chars = getHash((String)text); + return new String(chars); + } + + public static char[] getHash(String text) throws NoSuchAlgorithmException, UnsupportedEncodingException + { + byte[] data = text.getBytes("utf-8"); + + MessageDigest md = MessageDigest.getInstance("MD5"); + + for (byte b : data) + { + md.update(b); + } + + byte[] digest = md.digest(); + + char[] hash = new char[digest.length ]; + + int index = 0; + for (byte b : digest) + { + hash[index++] = (char) b; + } + + return hash; + } + + private static class TabularDataComparator implements java.util.Comparator<Map.Entry> + { + public int compare(Map.Entry data1, Map.Entry data2) + { + if (data1.getKey() instanceof List) + { + Object obj1 = ((List)data1.getKey()).get(0); + Object obj2 = ((List)data2.getKey()).get(0); + String str1 = obj1.toString(); + String str2 = obj2.toString(); + if (obj1 instanceof String) + { + return str1.compareTo(str2); + } + + try + { + return Long.valueOf(str1).compareTo(Long.valueOf(str2)); + } + catch (Exception ex) + { + return -1; + } + } + + return -1; + } + } } diff --git a/qpid/java/management/eclipse-plugin/src/main/resources/sasl/MANIFEST.MF b/qpid/java/management/eclipse-plugin/src/main/resources/sasl/MANIFEST.MF new file mode 100644 index 0000000000..7a9e5caaaf --- /dev/null +++ b/qpid/java/management/eclipse-plugin/src/main/resources/sasl/MANIFEST.MF @@ -0,0 +1,19 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Jmxmp Plug-in +Bundle-SymbolicName: jmxremote.optional +Bundle-Version: 1.0.1 +Bundle-ClassPath: . +Bundle-Vendor: +Bundle-Localization: plugin +Export-Package: com.sun.jmx.remote.generic, + com.sun.jmx.remote.opt.internal, + com.sun.jmx.remote.opt.security, + com.sun.jmx.remote.opt.util, + com.sun.jmx.remote.profile.sasl, + com.sun.jmx.remote.profile.tls, + com.sun.jmx.remote.protocol.jmxmp, + com.sun.jmx.remote.socket, + javax.management.remote.generic, + javax.management.remote.jmxmp, + javax.management.remote.message diff --git a/qpid/java/management/eclipse-plugin/src/main/resources/win32/configuration/config.ini b/qpid/java/management/eclipse-plugin/src/main/resources/win32/configuration/config.ini index dbe3f23fe9..1762840aff 100644 --- a/qpid/java/management/eclipse-plugin/src/main/resources/win32/configuration/config.ini +++ b/qpid/java/management/eclipse-plugin/src/main/resources/win32/configuration/config.ini @@ -22,5 +22,5 @@ osgi.splashPath=platform:/base/plugins/org.apache.qpid.management.ui
eclipse.product=org.apache.qpid.management.ui.product
eclipse.application=org.apache.qpid.management.ui.application
-osgi.bundles=org.eclipse.equinox.common@2:start,org.eclipse.core.runtime@start,com.ibm.icu,org.apache.qpid.management.ui,org.eclipse.core.commands,org.eclipse.core.contenttype,org.eclipse.core.expressions,org.eclipse.core.jobs,org.eclipse.core.runtime.compatibility.auth,org.eclipse.core.runtime.compatibility.registry,org.eclipse.equinox.preferences,org.eclipse.equinox.registry,org.eclipse.help,org.eclipse.jface,org.eclipse.swt,org.eclipse.swt.win32.win32.x86,org.eclipse.ui,org.eclipse.ui.forms,org.eclipse.ui.workbench
+osgi.bundles=org.eclipse.equinox.common@2:start,org.eclipse.core.runtime@start,com.ibm.icu,org.apache.qpid.management.ui,org.eclipse.core.commands,org.eclipse.core.contenttype,org.eclipse.core.expressions,org.eclipse.core.jobs,org.eclipse.core.runtime.compatibility.auth,org.eclipse.core.runtime.compatibility.registry,org.eclipse.equinox.preferences,org.eclipse.equinox.registry,org.eclipse.help,org.eclipse.jface,org.eclipse.swt,org.eclipse.swt.win32.win32.x86,org.eclipse.ui,org.eclipse.ui.forms,jmxremote.optional,org.eclipse.ui.workbench
osgi.bundles.defaultStartLevel=4
diff --git a/qpid/java/perftests/etc/scripts/BDB-Qpid-4.sh b/qpid/java/perftests/etc/scripts/BDB-Qpid-4.sh new file mode 100755 index 0000000000..f54c057640 --- /dev/null +++ b/qpid/java/perftests/etc/scripts/BDB-Qpid-4.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +if [ -z QPID_HOME ] ; then + +echo "QPID_HOME must be set" +exit 0 +fi + +configs=`pwd` + +pushd $QPID_HOME/bin/ + +echo "Starting qpid server - device config" +./qpid-server -c $configs/bdb-qpid-4/device.xml + +echo "Starting qpid server - filepath config" +./qpid-server -c $configs/bdb-qpid-4/filepath.xml + +echo "Starting qpid server - none existent path config" +./qpid-server -c $configs/bdb-qpid-4/noneexistantpath.xml + +echo "Starting qpid server - no permission config" +./qpid-server -c $configs/bdb-qpid-4/nopermission.xml + +echo "Starting qpid server - Star in path config" +./qpid-server -c $configs/bdb-qpid-4/starpath.xml + +popd diff --git a/qpid/java/perftests/etc/scripts/BDB-Qpid.sh b/qpid/java/perftests/etc/scripts/BDB-Qpid.sh new file mode 100755 index 0000000000..8ff233dc6d --- /dev/null +++ b/qpid/java/perftests/etc/scripts/BDB-Qpid.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +# Parse arguements taking all - prefixed args as JAVA_OPTS +for arg in "$@"; do + if [[ $arg == -java:* ]]; then + JAVA_OPTS="${JAVA_OPTS}-`echo $arg|cut -d ':' -f 2` " + else + ARGS="${ARGS}$arg " + fi +done + +java -Xms256m -Dlog4j.configuration=perftests.log4j -Xmx256m -Dbadger.level=warn -Damqj.test.logging.level=warn -Damqj.logging.level=warn ${JAVA_OPTS} -cp qpid-perftests-1.0-incubating-M2-SNAPSHOT-all-test-deps.jar org.apache.qpid.ping.PingDurableClient -o $QPID_WORK/results ${ARGS} diff --git a/qpid/java/perftests/etc/scripts/CTQ-Qpid-1.sh b/qpid/java/perftests/etc/scripts/CTQ-Qpid-1.sh new file mode 100755 index 0000000000..518b06aac4 --- /dev/null +++ b/qpid/java/perftests/etc/scripts/CTQ-Qpid-1.sh @@ -0,0 +1 @@ +./PQ-Qpid-1.sh $@ & ./PQ-Qpid-1-P.sh $@ diff --git a/qpid/java/perftests/etc/scripts/CTQ-Qpid-2.sh b/qpid/java/perftests/etc/scripts/CTQ-Qpid-2.sh new file mode 100755 index 0000000000..bbe5d75cd3 --- /dev/null +++ b/qpid/java/perftests/etc/scripts/CTQ-Qpid-2.sh @@ -0,0 +1 @@ +./PQ-Qpid-2.sh $@ & ./PQ-Qpid-2-P.sh $@ diff --git a/qpid/java/perftests/etc/scripts/CTQ-Qpid-3.sh b/qpid/java/perftests/etc/scripts/CTQ-Qpid-3.sh new file mode 100755 index 0000000000..7e9430c8a3 --- /dev/null +++ b/qpid/java/perftests/etc/scripts/CTQ-Qpid-3.sh @@ -0,0 +1 @@ +./PQ-Qpid-3.sh $@ & ./PQ-Qpid-3-P.sh $@ diff --git a/qpid/java/perftests/etc/scripts/CTQ-Qpid-4.sh b/qpid/java/perftests/etc/scripts/CTQ-Qpid-4.sh new file mode 100755 index 0000000000..720ca35fe1 --- /dev/null +++ b/qpid/java/perftests/etc/scripts/CTQ-Qpid-4.sh @@ -0,0 +1 @@ +./PQ-Qpid-4.sh $@ & ./PQ-Qpid-4-P.sh $@ diff --git a/qpid/java/perftests/etc/scripts/CTQ-Qpid-5.sh b/qpid/java/perftests/etc/scripts/CTQ-Qpid-5.sh new file mode 100755 index 0000000000..fe19f6a513 --- /dev/null +++ b/qpid/java/perftests/etc/scripts/CTQ-Qpid-5.sh @@ -0,0 +1 @@ +./PQ-Qpid-5.sh $@ & ./PQ-Qpid-5-P.sh $@ diff --git a/qpid/java/perftests/etc/scripts/CTQ-Qpid-6.sh b/qpid/java/perftests/etc/scripts/CTQ-Qpid-6.sh new file mode 100755 index 0000000000..09df5ce25a --- /dev/null +++ b/qpid/java/perftests/etc/scripts/CTQ-Qpid-6.sh @@ -0,0 +1 @@ +./PQ-Qpid-6.sh $@ & ./PQ-Qpid-6-P.sh $@ diff --git a/qpid/java/perftests/etc/scripts/PT-Qpid-13.sh b/qpid/java/perftests/etc/scripts/PT-Qpid-13.sh new file mode 100755 index 0000000000..630aa22ca3 --- /dev/null +++ b/qpid/java/perftests/etc/scripts/PT-Qpid-13.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +# Parse arguements taking all - prefixed args as JAVA_OPTS +for arg in "$@"; do + if [[ $arg == -java:* ]]; then + JAVA_OPTS="${JAVA_OPTS}-`echo $arg|cut -d ':' -f 2` " + else + ARGS="${ARGS}$arg " + fi +done + +echo "Starting 6 parallel tests" +java -Xms256m -Dlog4j.configuration=perftests.log4j -Xmx3072m -Dbadger.level=warn -Damqj.test.logging.level=info -Damqj.logging.level=warn ${JAVA_OPTS} -cp qpid-perftests-1.0-incubating-M2-SNAPSHOT-all-test-deps.jar uk.co.thebadgerset.junit.extensions.TKTestRunner -n PT-Qpid-13.1 -s [250] -c[200] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true messageSize=256 destinationName=newd1 uniqueDests=true batchSize=250 transacted=true commitBatchSize=50 -o $QPID_WORK/results ${ARGS} & + +java -Xms256m -Dlog4j.configuration=perftests.log4j -Xmx3072m -Dbadger.level=warn -Damqj.test.logging.level=info -Damqj.logging.level=warn ${JAVA_OPTS} -cp qpid-perftests-1.0-incubating-M2-SNAPSHOT-all-test-deps.jar uk.co.thebadgerset.junit.extensions.TKTestRunner -n PT-Qpid-13.2 -s [250] -c[200] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true messageSize=256 destinationName=newd2 uniqueDests=true batchSize=250 transacted=true commitBatchSize=50 -o $QPID_WORK/results ${ARGS} & + +java -Xms256m -Dlog4j.configuration=perftests.log4j -Xmx3072m -Dbadger.level=warn -Damqj.test.logging.level=info -Damqj.logging.level=warn ${JAVA_OPTS} -cp qpid-perftests-1.0-incubating-M2-SNAPSHOT-all-test-deps.jar uk.co.thebadgerset.junit.extensions.TKTestRunner -n PT-Qpid-13.3 -s [250] -c[200] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true messageSize=256 destinationName=newd3 uniqueDests=true batchSize=250 transacted=true commitBatchSize=50 -o $QPID_WORK/results ${ARGS} & + +java -Xms256m -Dlog4j.configuration=perftests.log4j -Xmx3072m -Dbadger.level=warn -Damqj.test.logging.level=info -Damqj.logging.level=warn ${JAVA_OPTS} -cp qpid-perftests-1.0-incubating-M2-SNAPSHOT-all-test-deps.jar uk.co.thebadgerset.junit.extensions.TKTestRunner -n PT-Qpid-13.4 -s [250] -c[200] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true messageSize=256 destinatioNname=newd4 uniqueDests=true batchSize=250 transacted=true commitBatchSize=50 -o $QPID_WORK/results ${ARGS} & + +java -Xms256m -Dlog4j.configuration=perftests.log4j -Xmx3072m -Dbadger.level=warn -Damqj.test.logging.level=info -Damqj.logging.level=warn ${JAVA_OPTS} -cp qpid-perftests-1.0-incubating-M2-SNAPSHOT-all-test-deps.jar uk.co.thebadgerset.junit.extensions.TKTestRunner -n PT-Qpid-13.5 -s [250] -c[100] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true messageSize=256 destinationName=newd5 uniqueDests=true batchSize=250 transacted=true commitBatchSize=50 -o $QPID_WORK/results ${ARGS} & + +java -Xms256m -Dlog4j.configuration=perftests.log4j -Xmx3072m -Dbadger.level=warn -Damqj.test.logging.level=info -Damqj.logging.level=warn ${JAVA_OPTS} -cp qpid-perftests-1.0-incubating-M2-SNAPSHOT-all-test-deps.jar uk.co.thebadgerset.junit.extensions.TKTestRunner -n PT-Qpid-13.6 -s [250] -c[100] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true messageSize=256 destinationName=newd6 uniqueDests=true batchSize=250 transacted=true commitBatchSize=50 -o $QPID_WORK/results ${ARGS} + diff --git a/qpid/java/perftests/etc/scripts/PT-Qpid-14.sh b/qpid/java/perftests/etc/scripts/PT-Qpid-14.sh new file mode 100755 index 0000000000..7499eedda4 --- /dev/null +++ b/qpid/java/perftests/etc/scripts/PT-Qpid-14.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +# Parse arguements taking all - prefixed args as JAVA_OPTS +for arg in "$@"; do + if [[ $arg == -java:* ]]; then + JAVA_OPTS="${JAVA_OPTS}-`echo $arg|cut -d ':' -f 2` " + else + ARGS="${ARGS}$arg " + fi +done +echo "Starting 6 parallel tests" + +java -Xms256m -Dlog4j.configuration=perftests.log4j -Xmx3072m -Dbadger.level=warn -Damqj.test.logging.level=info -Damqj.logging.level=warn ${JAVA_OPTS} -cp qpid-perftests-1.0-incubating-M2-SNAPSHOT-all-test-deps.jar uk.co.thebadgerset.junit.extensions.TKTestRunner -n PT-Qpid-14 -s [250] -c[200] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true messageSize=256 destinationName=ping1 batchSize=250 -o $QPID_WORK/results ${ARGS} & + +java -Xms256m -Dlog4j.configuration=perftests.log4j -Xmx3072m -Dbadger.level=warn -Damqj.test.logging.level=info -Damqj.logging.level=warn ${JAVA_OPTS} -cp qpid-perftests-1.0-incubating-M2-SNAPSHOT-all-test-deps.jar uk.co.thebadgerset.junit.extensions.TKTestRunner -n PT-Qpid-14 -s [250] -c[200] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true messageSize=256 destinationName=ping2 batchSize=250 -o $QPID_WORK/results ${ARGS} & + +java -Xms256m -Dlog4j.configuration=perftests.log4j -Xmx3072m -Dbadger.level=warn -Damqj.test.logging.level=info -Damqj.logging.level=warn ${JAVA_OPTS} -cp qpid-perftests-1.0-incubating-M2-SNAPSHOT-all-test-deps.jar uk.co.thebadgerset.junit.extensions.TKTestRunner -n PT-Qpid-14 -s [250] -c[200] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true messageSize=256 destinationName=ping3 batchSize=250 -o $QPID_WORK/results ${ARGS} & + +java -Xms256m -Dlog4j.configuration=perftests.log4j -Xmx3072m -Dbadger.level=warn -Damqj.test.logging.level=info -Damqj.logging.level=warn ${JAVA_OPTS} -cp qpid-perftests-1.0-incubating-M2-SNAPSHOT-all-test-deps.jar uk.co.thebadgerset.junit.extensions.TKTestRunner -n PT-Qpid-14 -s [250] -c[200] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true messageSize=256destinationname=ping4 batchSize=250 -o $QPID_WORK/results ${ARGS} & + +java -Xms256m -Dlog4j.configuration=perftests.log4j -Xmx3072m -Dbadger.level=warn -Damqj.test.logging.level=info -Damqj.logging.level=warn ${JAVA_OPTS} -cp qpid-perftests-1.0-incubating-M2-SNAPSHOT-all-test-deps.jar uk.co.thebadgerset.junit.extensions.TKTestRunner -n PT-Qpid-14 -s [250] -c[100] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true messageSize=256 destinationName=ping5 batchSize=250 -o $QPID_WORK/results ${ARGS} & + +java -Xms256m -Dlog4j.configuration=perftests.log4j -Xmx3072m -Dbadger.level=warn -Damqj.test.logging.level=info -Damqj.logging.level=warn ${JAVA_OPTS} -cp qpid-perftests-1.0-incubating-M2-SNAPSHOT-all-test-deps.jar uk.co.thebadgerset.junit.extensions.TKTestRunner -n PT-Qpid-14 -s [250] -c[100] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true messageSize=256 destinationName=ping6 batchSize=250 -o $QPID_WORK/results ${ARGS} diff --git a/qpid/java/perftests/etc/scripts/bdb-qpid-4/device.xml b/qpid/java/perftests/etc/scripts/bdb-qpid-4/device.xml new file mode 100644 index 0000000000..a052f85167 --- /dev/null +++ b/qpid/java/perftests/etc/scripts/bdb-qpid-4/device.xml @@ -0,0 +1,98 @@ +<?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>${QPID_HOME}</prefix> + <work>${QPID_WORK}</work> + <conf>${prefix}/etc</conf> + <userhome>$HOME</userhome> + <connector> + <!-- Uncomment out this block and edit the keystorePath and keystorePassword + to enable SSL support + <ssl> + <enabled>true</enabled> + <sslOnly>true</sslOnly> + <keystorePath>/path/to/keystore.ks</keystorePath> + <keystorePassword>keystorepass</keystorePassword> + </ssl>--> + <qpidnio>true</qpidnio> + <transport>nio</transport> + <port>5672</port> + <sslport>8672</sslport> + <socketReceiveBuffer>32768</socketReceiveBuffer> + <socketSendBuffer>32768</socketSendBuffer> + </connector> + <management> + <enabled>true</enabled> + </management> + <advanced> + <filterchain enableExecutorPool="true"/> + <enablePooledAllocator>false</enablePooledAllocator> + <enableDirectBuffers>false</enableDirectBuffers> + <framesize>65535</framesize> + <compressBufferOnQueue>false</compressBufferOnQueue> + </advanced> + + <security> + <principal-databases> + <principal-database> + <name>passwordfile</name> + <class>org.apache.qpid.server.security.auth.database.PlainPasswordVhostFilePrincipalDatabase</class> + <attributes> + <attribute> + <name>passwordFile</name> + <value>${conf}/passwdVhost</value> + </attribute> + </attributes> + </principal-database> + </principal-databases> + + <access> + <class>org.apache.qpid.server.security.access.AllowAll</class> + </access> + </security> + + <virtualhosts> + <virtualhost> + <name>device</name> + <device> + <store> + <!-- /dev/null give it a device --> + <class>org.apache.qpid.server.store.berkeleydb.BDBMessageStore</class> + <environment-path>/dev/null</environment-path> + </store> + </device> + </virtualhost> + + + </virtualhosts> + <heartbeat> + <delay>0</delay> + <timeoutFactor>2.0</timeoutFactor> + </heartbeat> + <queue> + <auto_register>true</auto_register> + </queue> + + <virtualhosts>${conf}/virtualhosts.xml</virtualhosts> +</broker> + + diff --git a/qpid/java/perftests/etc/scripts/bdb-qpid-4/filepath.xml b/qpid/java/perftests/etc/scripts/bdb-qpid-4/filepath.xml new file mode 100644 index 0000000000..ebce10cb95 --- /dev/null +++ b/qpid/java/perftests/etc/scripts/bdb-qpid-4/filepath.xml @@ -0,0 +1,97 @@ +<?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>${QPID_HOME}</prefix> + <work>${QPID_WORK}</work> + <conf>${prefix}/etc</conf> + <userhome>$HOME</userhome> + <connector> + <!-- Uncomment out this block and edit the keystorePath and keystorePassword + to enable SSL support + <ssl> + <enabled>true</enabled> + <sslOnly>true</sslOnly> + <keystorePath>/path/to/keystore.ks</keystorePath> + <keystorePassword>keystorepass</keystorePassword> + </ssl>--> + <qpidnio>true</qpidnio> + <transport>nio</transport> + <port>5672</port> + <sslport>8672</sslport> + <socketReceiveBuffer>32768</socketReceiveBuffer> + <socketSendBuffer>32768</socketSendBuffer> + </connector> + <management> + <enabled>true</enabled> + </management> + <advanced> + <filterchain enableExecutorPool="true"/> + <enablePooledAllocator>false</enablePooledAllocator> + <enableDirectBuffers>false</enableDirectBuffers> + <framesize>65535</framesize> + <compressBufferOnQueue>false</compressBufferOnQueue> + </advanced> + + <security> + <principal-databases> + <principal-database> + <name>passwordfile</name> + <class>org.apache.qpid.server.security.auth.database.PlainPasswordVhostFilePrincipalDatabase</class> + <attributes> + <attribute> + <name>passwordFile</name> + <value>${conf}/passwdVhost</value> + </attribute> + </attributes> + </principal-database> + </principal-databases> + + <access> + <class>org.apache.qpid.server.security.access.AllowAll</class> + </access> + </security> + + <virtualhosts> + <virtualhost> + <name>pathToAFile</name> + <pathToAFile> + <store> + <!-- ${conf}/config.xml give the path to a file --> + <class>org.apache.qpid.server.store.berkeleydb.BDBMessageStore</class> + <environment-path>${conf}/config.xml</environment-path> + </store> + </pathToAFile> + </virtualhost> + + </virtualhosts> + <heartbeat> + <delay>0</delay> + <timeoutFactor>2.0</timeoutFactor> + </heartbeat> + <queue> + <auto_register>true</auto_register> + </queue> + + <virtualhosts>${conf}/virtualhosts.xml</virtualhosts> +</broker> + + diff --git a/qpid/java/perftests/etc/scripts/bdb-qpid-4/noneexistantpath.xml b/qpid/java/perftests/etc/scripts/bdb-qpid-4/noneexistantpath.xml new file mode 100644 index 0000000000..c20beb1c92 --- /dev/null +++ b/qpid/java/perftests/etc/scripts/bdb-qpid-4/noneexistantpath.xml @@ -0,0 +1,97 @@ +<?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>${QPID_HOME}</prefix> + <work>${QPID_WORK}</work> + <conf>${prefix}/etc</conf> + <userhome>$HOME</userhome> + <connector> + <!-- Uncomment out this block and edit the keystorePath and keystorePassword + to enable SSL support + <ssl> + <enabled>true</enabled> + <sslOnly>true</sslOnly> + <keystorePath>/path/to/keystore.ks</keystorePath> + <keystorePassword>keystorepass</keystorePassword> + </ssl>--> + <qpidnio>true</qpidnio> + <transport>nio</transport> + <port>5672</port> + <sslport>8672</sslport> + <socketReceiveBuffer>32768</socketReceiveBuffer> + <socketSendBuffer>32768</socketSendBuffer> + </connector> + <management> + <enabled>true</enabled> + </management> + <advanced> + <filterchain enableExecutorPool="true"/> + <enablePooledAllocator>false</enablePooledAllocator> + <enableDirectBuffers>false</enableDirectBuffers> + <framesize>65535</framesize> + <compressBufferOnQueue>false</compressBufferOnQueue> + </advanced> + + <security> + <principal-databases> + <principal-database> + <name>passwordfile</name> + <class>org.apache.qpid.server.security.auth.database.PlainPasswordVhostFilePrincipalDatabase</class> + <attributes> + <attribute> + <name>passwordFile</name> + <value>${conf}/passwdVhost</value> + </attribute> + </attributes> + </principal-database> + </principal-databases> + + <access> + <class>org.apache.qpid.server.security.access.AllowAll</class> + </access> + </security> + + <virtualhosts> + <virtualhost> + <name>nonExistentPath</name> + <nonExistentPath> + <store> + <!-- Path to a location that doesn't exist --> + <class>org.apache.qpid.server.store.berkeleydb.BDBMessageStore</class> + <environment-path>${work}/bdb-qpid-5/1/localhost-store</environment-path> + </store> + </nonExistentPath> + </virtualhost> + + </virtualhosts> + <heartbeat> + <delay>0</delay> + <timeoutFactor>2.0</timeoutFactor> + </heartbeat> + <queue> + <auto_register>true</auto_register> + </queue> + + <virtualhosts>${conf}/virtualhosts.xml</virtualhosts> +</broker> + + diff --git a/qpid/java/perftests/etc/scripts/bdb-qpid-4/nopermission.xml b/qpid/java/perftests/etc/scripts/bdb-qpid-4/nopermission.xml new file mode 100644 index 0000000000..958a19cda2 --- /dev/null +++ b/qpid/java/perftests/etc/scripts/bdb-qpid-4/nopermission.xml @@ -0,0 +1,98 @@ +<?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>${QPID_HOME}</prefix> + <work>${QPID_WORK}</work> + <conf>${prefix}/etc</conf> + <userhome>$HOME</userhome> + <connector> + <!-- Uncomment out this block and edit the keystorePath and keystorePassword + to enable SSL support + <ssl> + <enabled>true</enabled> + <sslOnly>true</sslOnly> + <keystorePath>/path/to/keystore.ks</keystorePath> + <keystorePassword>keystorepass</keystorePassword> + </ssl>--> + <qpidnio>true</qpidnio> + <transport>nio</transport> + <port>5672</port> + <sslport>8672</sslport> + <socketReceiveBuffer>32768</socketReceiveBuffer> + <socketSendBuffer>32768</socketSendBuffer> + </connector> + <management> + <enabled>true</enabled> + </management> + <advanced> + <filterchain enableExecutorPool="true"/> + <enablePooledAllocator>false</enablePooledAllocator> + <enableDirectBuffers>false</enableDirectBuffers> + <framesize>65535</framesize> + <compressBufferOnQueue>false</compressBufferOnQueue> + </advanced> + + <security> + <principal-databases> + <principal-database> + <name>passwordfile</name> + <class>org.apache.qpid.server.security.auth.database.PlainPasswordVhostFilePrincipalDatabase</class> + <attributes> + <attribute> + <name>passwordFile</name> + <value>${conf}/passwdVhost</value> + </attribute> + </attributes> + </principal-database> + </principal-databases> + + <access> + <class>org.apache.qpid.server.security.access.AllowAll</class> + </access> + </security> + + <virtualhosts> + <virtualhost> + <name>noPermissions</name> + <noPermissions> + <store> + <!-- /etc/bdb-qpid-5 give it somewhere it doesn't have permission --> + <class>org.apache.qpid.server.store.berkeleydb.BDBMessageStore</class> + <environment-path>/etc/bdb-qpid-5/</environment-path> + </store> + </noPermissions> + </virtualhost> + + + </virtualhosts> + <heartbeat> + <delay>0</delay> + <timeoutFactor>2.0</timeoutFactor> + </heartbeat> + <queue> + <auto_register>true</auto_register> + </queue> + + <virtualhosts>${conf}/virtualhosts.xml</virtualhosts> +</broker> + + diff --git a/qpid/java/perftests/etc/scripts/bdb-qpid-4/starpath.xml b/qpid/java/perftests/etc/scripts/bdb-qpid-4/starpath.xml new file mode 100644 index 0000000000..c795ec5202 --- /dev/null +++ b/qpid/java/perftests/etc/scripts/bdb-qpid-4/starpath.xml @@ -0,0 +1,98 @@ +<?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>${QPID_HOME}</prefix> + <work>${QPID_WORK}</work> + <conf>${prefix}/etc</conf> + <userhome>$HOME</userhome> + <connector> + <!-- Uncomment out this block and edit the keystorePath and keystorePassword + to enable SSL support + <ssl> + <enabled>true</enabled> + <sslOnly>true</sslOnly> + <keystorePath>/path/to/keystore.ks</keystorePath> + <keystorePassword>keystorepass</keystorePassword> + </ssl>--> + <qpidnio>true</qpidnio> + <transport>nio</transport> + <port>5672</port> + <sslport>8672</sslport> + <socketReceiveBuffer>32768</socketReceiveBuffer> + <socketSendBuffer>32768</socketSendBuffer> + </connector> + <management> + <enabled>true</enabled> + </management> + <advanced> + <filterchain enableExecutorPool="true"/> + <enablePooledAllocator>false</enablePooledAllocator> + <enableDirectBuffers>false</enableDirectBuffers> + <framesize>65535</framesize> + <compressBufferOnQueue>false</compressBufferOnQueue> + </advanced> + + <security> + <principal-databases> + <principal-database> + <name>passwordfile</name> + <class>org.apache.qpid.server.security.auth.database.PlainPasswordVhostFilePrincipalDatabase</class> + <attributes> + <attribute> + <name>passwordFile</name> + <value>${conf}/passwdVhost</value> + </attribute> + </attributes> + </principal-database> + </principal-databases> + + <access> + <class>org.apache.qpid.server.security.access.AllowAll</class> + </access> + </security> + + <virtualhosts> + + <virtualhost> + <name>pathWithStar</name> + <pathWithStar> + <store> + <!-- ${work}/bdbd-qpid-5/2/* have a * in path--> + <class>org.apache.qpid.server.store.berkeleydb.BDBMessageStore</class> + <environment-path>${work}/bdb-qpid-5/2/*-store</environment-path> + </store> + </pathWithStar> + </virtualhost> + + </virtualhosts> + <heartbeat> + <delay>0</delay> + <timeoutFactor>2.0</timeoutFactor> + </heartbeat> + <queue> + <auto_register>true</auto_register> + </queue> + + <virtualhosts>${conf}/virtualhosts.xml</virtualhosts> +</broker> + + diff --git a/qpid/java/perftests/pom.xml b/qpid/java/perftests/pom.xml index c09d6a5a75..63edac1801 100644 --- a/qpid/java/perftests/pom.xml +++ b/qpid/java/perftests/pom.xml @@ -40,6 +40,18 @@ </properties> <!-- Temporary local maven repo, whilst JUnit Toolkit is still reaching stable version to add to central maven repository. --> + <repositories> + <repository> + <id>junit-toolkit.snapshots</id> + <name>JUnit Toolkit SNAPSHOT Repository</name> + <url>http://junit-toolkit.svn.sourceforge.net/svnroot/junit-toolkit/snapshots/</url> + <snapshots> + <enabled>true</enabled> + </snapshots> + </repository> + </repositories> + + <!-- Temporary local maven repo, whilst JUnit Toolkit is still reaching stable version to add to central maven repository. --> <pluginRepositories> <pluginRepository> <id>junit-toolkit-plugin.snapshots</id> @@ -86,18 +98,6 @@ <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-jar-plugin</artifactId> - <executions> - <execution> - <phase>package</phase> - <goals> - <goal>test-jar</goal> - </goals> - </execution> - </executions> - </plugin> <!-- The JUnit Toolkit maven2 plugin is in the process of being added to the maven repository. @@ -130,9 +130,16 @@ <configuration> <scriptOutDirectory>target</scriptOutDirectory> <testJar>${project.build.finalName}-all-test-deps.jar</testJar> - <systemproperties> <property> + <name>-Xms</name> + <value>256m</value> + </property> + <property> + <name>-Xmx</name> + <value>3072m</value> + </property> + <property> <name>log4j.configuration</name> <value>${log4j.perftests}</value> </property> @@ -185,6 +192,267 @@ <Ping-Failover-After-Commit> -n Ping-Failover-After-Commit -s [100] -o . -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf commitBatchSize=10 failAfterCommit=true </Ping-Failover-After-Commit> + + <!-- P2P Volume Tests. --> + <VT-Qpid-1>-n VT-Qpid-1 -d1H -s [1000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true messageSize=256 transacted=true -o $QPID_WORK/results</VT-Qpid-1> + <VT-Qpid-2>-n VT-Qpid-2 -d1H -s [1000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true commitBatchSize=100 messageSize=256 -o $QPID_WORK/results</VT-Qpid-2> + <!-- Setting sample to 3,000,000 will result in a log entry every 10 minutes so should have 144 data points for the run. --> + <VT-Qpid-3>-n VT-Qpid-3 -s [100000] -d 24H -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true rate=10000 messageSize=256 transacted=true -o $QPID_WORK/results commitBatchSize=100 batchSize=10000</VT-Qpid-3> + <VT-Qpid-4>-n VT-Qpid-4 -s [100000] -d 24H -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true rate=10000 messageSize=256 -o $QPID_WORK/results batchSize=10000</VT-Qpid-4> + <VT-Qpid-5>-n VT-Qpid-5 -s[1000] -c[1,32],samples=32 -d2M transacted=true commitBatchSize=100 persistent=false rate=1000 messageSize=256</VT-Qpid-5> + <VT-Qpid-6>-n VT-Qpid-6 -s[100] -c[1,32],samples=32 -d2M transacted=true commitBatchSize=100 persistent=true rate=100 messageSize=256</VT-Qpid-6> + + <!-- P2P Scalability Tests. --> + <!-- 250,000 Total, 1P-1T-1C --> + <PT-Qpid-1>-n PT-Qpid-1 -d 10M -s [1000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true messageSize=256 -o $QPID_WORK/results commitBatchSize=100 transacted=true</PT-Qpid-1> + <PT-Qpid-2>-n PT-Qpid-2 -d 10M -s [1000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true messageSize=256 -o $QPID_WORK/results</PT-Qpid-2> + + <!-- 25000 Msgs * 10 Brokers = 250,000 Total, 10P-1Q-10C --> + <PT-Qpid-3>-n PT-Qpid-3 -d 10M -s [1000] -c[10] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true messageSize=256 -o $QPID_WORK/results commitBatchSize=100 transacted=true</PT-Qpid-3> + <PT-Qpid-4>-n PT-Qpid-4 -d 10M -s [1000] -c[10] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true messageSize=256 -o $QPID_WORK/results</PT-Qpid-4> + + <!-- 25000 Msgs * 10 Brokers = 250,000 Tota,l 10P-10T-10C 10*(1P-1Q-1C) --> + <PT-Qpid-5>-n PT-Qpid-5 -d 10M -s [1000] -c[10] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true messageSize=256 -o $QPID_WORK/results transacted=true commitBatchSize=100</PT-Qpid-5> + <PT-Qpid-6>-n PT-Qpid-6 -d 10M -s [1000] -c[10] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true messageSize=256 -o $QPID_WORK/results</PT-Qpid-6> + + <!-- 2500 Msgs * 10 Brokers * 10 Topics/Clients = 250,000 Total, 10P-100T-10C 10*(1P-10T-1C) --> + <PT-Qpid-7>-n PT-Qpid-7 -d 10M -s [1000] -c[10] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true destinationsCount=10 transacted=true commitBatchSize=100 messageSize=256 -o $QPID_WORK/results</PT-Qpid-7> + <PT-Qpid-8>-n PT-Qpid-8 -d 10M -s [1000] -c[10] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true destinationsCount=10 messageSize=256 -o $QPID_WORK/results</PT-Qpid-8> + + <!-- 2500 Msgs * 100 Brokers = 250,000 Total, 100P-100T-100C 100*(1P-1T-1C) --> + <PT-Qpid-9>-n PT-Qpid-9 -d 10M -s [1000] -c[100] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true messageSize=256 commitBatchSize=100 transacted=true -o $QPID_WORK/results</PT-Qpid-9> + <PT-Qpid-10>-n PT-Qpid-10 -d 10M -s [1000] -c[100] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true messageSize=256 batchSize=250 -o $QPID_WORK/results</PT-Qpid-10> + + <!-- 250 Msgs * 100 Brokers * 10 Clients = 250,000 Total, 100P-1000T-100C 100*(1P-10T-1C) --> + <PT-Qpid-11>-n PT-Qpid-11 -d 10M -s [1000] -c[100] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true messageSize=256 destinationsCount=10 transacted=true commitBatchSize=100 -o $QPID_WORK/results</PT-Qpid-11> + <PT-Qpid-12>-n PT-Qpid-12 -d 10M -s [1000] -c[100] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true messageSize=256 destinationsCount=10 -o $QPID_WORK/results</PT-Qpid-12> + + <!-- 250 Msgs * 1000 Brokers = 250,000 Total, 1000P-1000T-1000C 1000*(1P-1T-1C) --> + <!-- PT-Qpid-13>-n PT-Qpid-13 -s [100] -c[1000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true messageSize=256 batchSize=100 transacted=true commitBatchSize=100 -o $QPID_WORK/results</PT-Qpid-13 --> + <!-- PT-Qpid-14>-n PT-Qpid-14 -s [100] -c[1000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true messageSize=256 batchSize=100 -o $QPID_WORK/results</PT-Qpid-14 --> + + <!-- P2P Volume Tests. --> + <VQ-Qpid-1>-n VQ-Qpid-1 -d 10M -s [1000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf messageSize=256 commitBatchSize=100 transacted=true -o $QPID_WORK/results</VQ-Qpid-1> + <VQ-Qpid-2>-n VQ-Qpid-2 -d 10M -s [1000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf messageSize=256 commitBatchSize=100 -o $QPID_WORK/results</VQ-Qpid-2> + <!-- Setting sample to 3,000,000 will result in a log entry every 10 minutes so should have 144 data points for the run. --> + <VQ-Qpid-3>-n VQ-Qpid-3 -s [100000] -d 24H -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf rate=10000 messageSize=256 commitBatchSize=100 transacted=true batchSize=100000 -o $QPID_WORK/results</VQ-Qpid-3> + <VQ-Qpid-4>-n VQ-Qpid-4 -s [100000] -d 24H -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf rate=10000 messageSize=256 batchSize=100000 -o $QPID_WORK/results</VQ-Qpid-4> + + <!-- P2P Scalability Tests. --> + <!-- 15,000 Total, 1P-1Q-1C --> + <PQ-Qpid-1>-n PQ-Qpid-1 -d 10M -s [1000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf transacted=true commitBatchSize=100 messageSize=256 -o $QPID_WORK/results</PQ-Qpid-1> + <PQ-Qpid-2>-n PQ-Qpid-2 -d 10M -s [1000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf messageSize=256 -o $QPID_WORK/results</PQ-Qpid-2> + + <!-- 1500 Messages * 10 Brokers = 15,000 Total, 10P-1Q-10C --> + <PQ-Qpid-3>-n PQ-Qpid-3 -d 10M -s [1000] -c[10] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf messageSize=256 destinationName=ping transacted=true commitBatchSize=100 -o $QPID_WORK/results</PQ-Qpid-3> + <PQ-Qpid-4>-n PQ-Qpid-4 -d 10M -s [1000] -c[10] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf messageSize=256 destinationName=ping -o $QPID_WORK/results</PQ-Qpid-4> + + <!-- 1500 Messages * 10 Brokers = 15,000 Total, 10P-10Q-10C 10*(1P-1Q-1C) --> + <PQ-Qpid-5>-n PQ-Qpid-5 -d 10M -s [1000] -c[10] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf messageSize=256 transacted=true commitBatchSize=100 -o $QPID_WORK/results</PQ-Qpid-5> + <PQ-Qpid-6>-n PQ-Qpid-6 -d 10M -s [1000] -c[10] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf messageSize=256 -o $QPID_WORK/results</PQ-Qpid-6> + + <!-- 1500 Messages * 10 Brokers = 15,000 Total, 10P-100Q-10C 10*(1P-10Q-1C) --> + <PQ-Qpid-7>-n PQ-Qpid-7 -d 10M -s [1000] -c[10] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf messageSize=256 commitBatchSize=100 destinationsCount=10 transacted=true -o $QPID_WORK/results</PQ-Qpid-7> + <PQ-Qpid-8>-n PQ-Qpid-8 -d 10M -s [1000] -c[10] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf messageSize=256 destinationsCount=10 -o $QPID_WORK/results</PQ-Qpid-8> + + <!-- 150 Messages * 100 Brokers = 15,000 Total, 100P-100Q-100C 100*(1P-1Q-1C) --> + <PQ-Qpid-9>-n PQ-Qpid-9 -d 20M -s [1000] -c[100] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf messageSize=256 transacted=true commitBatchSize=100 -o $QPID_WORK/results</PQ-Qpid-9> + <PQ-Qpid-10>-n PQ-Qpid-10 -d 10M -s [1000] -c[100] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf messageSize=256 -o $QPID_WORK/results</PQ-Qpid-10> + + + <!-- 150 Messages * 100 Brokers = 15,000 Total, 100P-1000Q-100C 100*(1P-10Q-1C) --> + <PQ-Qpid-11>-n PQ-Qpid-11 -d 10M -s [1000] -c[100] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf messageSize=256 destinationsCount=10 transacted=true commitBatchSize=100 -o $QPID_WORK/results</PQ-Qpid-11> + <PQ-Qpid-12>-n PQ-Qpid-12 -d 10M -s [1000] -c[100] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf messageSize=256 destinationsCount=10 -o $QPID_WORK/results</PQ-Qpid-12> + + <!-- 15 Messages * 1000 Brokers = 15,000 Total, 1000P-1000Q-1000C 1000*(1P-1Q-1C) --> + <!--PQ-Qpid-13>-n PQ-Qpid-13 -d 10M -s [1000] -c[1000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf messageSize=256 transacted=true commitBatchSize=100 -o $QPID_WORK/results</PQ-Qpid-13> + <PQ-Qpid-14>-n PQ-Qpid-14 -d 10M -s [1000] -c[1000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf messageSize=256 batchSize=15 -o $QPID_WORK/results</PQ-Qpid-14--> + + <!-- Increasing Message Payload Tests. --> + <!-- Topic Testing --> + <LT-Qpid-1-512b>-n LT-Qpid-1-512b -d 10M -s [1000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true messageSize=512 transacted=true commitBatchSize=100 -o $QPID_WORK/results</LT-Qpid-1-512b> + <LT-Qpid-2-512b>-n LT-Qpid-2-512b -d 10M -s [1000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true messageSize=512 -o $QPID_WORK/results</LT-Qpid-2-512b> + + <LT-Qpid-1-1K>-n LT-Qpid-1-1K -d 10M -s [1000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true commitBatchSize=100 transacted=true messageSize=1024 -o $QPID_WORK/results</LT-Qpid-1-1K> + <LT-Qpid-2-1K>-n LT-Qpid-2-1K -d 10M -s [1000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true messageSize=1024 -o $QPID_WORK/results</LT-Qpid-2-1K> + + <LT-Qpid-1-5K>-n LT-Qpid-1-5K -d 10M -s [1000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true commitBatchSize=100 messageSize=5120 transacted=true -o $QPID_WORK/results</LT-Qpid-1-5K> + <LT-Qpid-2-5K>-n LT-Qpid-2-5K -d 10M -s [1000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true messageSize=5120 -o $QPID_WORK/results</LT-Qpid-2-5K> + + <LT-Qpid-1-10K>-n LT-Qpid-1-10K -d10M -s [1000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true commitBatchSize=100 messageSize=10240 transacted=true -o $QPID_WORK/results</LT-Qpid-1-10K> + <LT-Qpid-2-10K>-n LT-Qpid-2-10K -d10M -s [1000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true messageSize=10240 -o $QPID_WORK/results</LT-Qpid-2-10K> + + <LT-Qpid-1-50K>-n LT-Qpid-1-50K -d10M -s [1000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true commitBatchSize=100 messageSize=51200 transacted=true -o $QPID_WORK/results</LT-Qpid-1-50K> + <LT-Qpid-2-50K>-n LT-Qpid-2-50K -d10M -s [1000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true messageSize=51200 -o $QPID_WORK/results</LT-Qpid-2-50K> + + <LT-Qpid-1-100K>-n LT-Qpid-1-100K -d10M -s [1000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true commitBatchSize=100 messageSize=102400 transacted=true -o $QPID_WORK/results</LT-Qpid-1-100K> + <LT-Qpid-2-100K>-n LT-Qpid-2-100K -d10M -s [1000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true messageSize=102400 -o $QPID_WORK/results</LT-Qpid-2-100K> + + <LT-Qpid-1-1M>-n LT-Qpid-1-1M -d10M -s [1000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true commitBatchSize=100 messageSize=1048576 transacted=true -o $QPID_WORK/results</LT-Qpid-1-1M> + <LT-Qpid-2-1M>-n LT-Qpid-2-1M -d10M -s [1000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf pubsub=true messageSize=1048476 -o $QPID_WORK/results</LT-Qpid-2-1M> + + <!-- Queue Testing --> + <LT-Qpid-3-512b>-n LT-Qpid-3-512b -d10M -s [1000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf commitBatchSize=100 messageSize=512 transacted=true -o $QPID_WORK/results</LT-Qpid-3-512b> + <LT-Qpid-4-512b>-n LT-Qpid-4-512b -d10M -s [1000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf messageSize=512 -o $QPID_WORK/results</LT-Qpid-4-512b> + + <LT-Qpid-3-1K>-n LT-Qpid-3-1K -d10M -s [1000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf commitBatchSize=100 messageSize=1024 transacted=true -o $QPID_WORK/results</LT-Qpid-3-1K> + <LT-Qpid-4-1K>-n LT-Qpid-4-1K -d10M -s [1000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPer messageSize=1024 -o $QPID_WORK/results</LT-Qpid-4-1K> + + <LT-Qpid-3-5K>-n LT-Qpid-3-5K -d10M -s [1000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf commitBatchSize=100 messageSize=5120 transacted=true -o $QPID_WORK/results</LT-Qpid-3-5K> + <LT-Qpid-4-5K>-n LT-Qpid-4-5K -d10M -s [1000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf messageSize=5120 -o $QPID_WORK/results</LT-Qpid-4-5K> + + <LT-Qpid-3-10K>-n LT-Qpid-3-10K -d10M -s [1000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf commitBatchSize=100 messageSize=10240 transacted=true -o $QPID_WORK/results</LT-Qpid-3-10K> + <LT-Qpid-4-10K>-n LT-Qpid-4-10K -d10M -s [1000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf messageSize=10240 -o $QPID_WORK/results</LT-Qpid-4-10K> + + <LT-Qpid-3-50K>-n LT-Qpid-3-50K -d10M -s [1000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf commitBatchSize=100 messageSize=51200 transacted=true -o $QPID_WORK/results</LT-Qpid-3-50K> + <LT-Qpid-4-50K>-n LT-Qpid-4-50K -d10M -s [1000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf messageSize=51200 -o $QPID_WORK/results</LT-Qpid-4-50K> + + <LT-Qpid-3-100K>-n LT-Qpid-3-100K -d10M -s [1000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf commitBatchSize=100 messageSize=102400 transacted=true -o $QPID_WORK/results</LT-Qpid-3-100K> + <LT-Qpid-4-100K>-n LT-Qpid-4-100K -d10M -s [1000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf messageSize=102400 -o $QPID_WORK/results</LT-Qpid-4-100K> + + <LT-Qpid-3-1M>-n LT-Qpid-3-1M -d10M -s [1000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf commitBatchSize=100 messageSize=1048576 transacted=true -o $QPID_WORK/results</LT-Qpid-3-1M> + <LT-Qpid-4-1M>-n LT-Qpid-4-1M -d10M -s [1000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf messageSize=1048576 -o $QPID_WORK/results</LT-Qpid-4-1M> + + <!-- Failover Tests. --> + <!-- Transactional --> + <FT-Qpid-1>-n FT-Qpid-1 -s [250000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf messageSize=256 batchSize=10000 transacted=true broker="tcp://10.0.0.1:5001;tcp://10.0.0.2:5002" FailBeforeSend=true -o $QPID_WORK/results</FT-Qpid-1> + <FT-Qpid-2>-n FT-Qpid-2 -s [250000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf messageSize=256 batchSize=10000 transacted=true broker="tcp://10.0.0.1:5001;tcp://10.0.0.2:5002" failAfterSend=true -o $QPID_WORK/results</FT-Qpid-2> + <FT-Qpid-3>-n FT-Qpid-3 -s [250000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf messageSize=256 batchSize=10000 transacted=true broker="tcp://10.0.0.1:5001;tcp://10.0.0.2:5002" failAfterCommit=true -o $QPID_WORK/results</FT-Qpid-3> + + <!-- Non Transactional --> + <FT-Qpid-4>-n FT-Qpid-4 -s [250000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf messageSize=256 batchSize=10000 broker="tcp://10.0.0.1:5001;tcp://10.0.0.2:5002" transacted=false failBeforeSend=true -o $QPID_WORK/results</FT-Qpid-4> + <FT-Qpid-5>-n FT-Qpid-5 -s [250000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf messageSize=256 batchSize=10000 broker="tcp://10.0.0.1:5001;tcp://10.0.0.2:5002" transacted=false failAfterSend=true -o $QPID_WORK/results</FT-Qpid-5> + + + <!-- Persistent Tests --> + + <!-- P2P Volume Tests. --> + <VT-Qpid-1-P>-n VT-Qpid-1 -d1H -s [1000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true messageSize=256 commitBatchSize=100 transacted=true -o $QPID_WORK/results</VT-Qpid-1-P> + <VT-Qpid-2-P>-n VT-Qpid-2 -d1H -s [1000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true messageSize=256 -o $QPID_WORK/results</VT-Qpid-2-P> + <!-- Setting sample to 3,000,000 will result in a log entry every 10 minutes so should have 144 data points for the run. --> + <VT-Qpid-3-P>-n VT-Qpid-3 -s [100000] -d 24H -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true rate=1000 messageSize=256 commitBatchSize=100 transacted=true -o $QPID_WORK/results batchSize=10000</VT-Qpid-3-P> + <VT-Qpid-4-P>-n VT-Qpid-4 -s [100000] -d 24H -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true rate=1000 messageSize=256 -o $QPID_WORK/results batchSize=10000</VT-Qpid-4-P> + + <!-- P2P Scalability Tests. --> + <!-- 25,000 Total, 1P-1T-1C --> + <PT-Qpid-1-P>-n PT-Qpid-1-P -d10M -s [1000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true messageSize=256 commitBatchSize=100 transacted=true -o $QPID_WORK/results</PT-Qpid-1-P> + <PT-Qpid-2-P>-n PT-Qpid-2-P -d10M -s [1000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true messageSize=256 -o $QPID_WORK/results</PT-Qpid-2-P> + + <!-- 2500 Msgs * 10 Brokers = 25,000 Total, 10P-1Q-10C --> + <PT-Qpid-3-P>-n PT-Qpid-3-P -d10M -s [1000] -c[10] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true messageSize=256 commitBatchSize=100 transacted=true -o $QPID_WORK/results</PT-Qpid-3-P> + <PT-Qpid-4-P>-n PT-Qpid-4-P -d10M -s [1000] -c[10] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true messageSize=256 -o $QPID_WORK/results</PT-Qpid-4-P> + + <!-- 2500 Msgs * 10 Brokers = 25,000 Tota,l 10P-10T-10C 10*(1P-1Q-1C) --> + <PT-Qpid-5-P>-n PT-Qpid-5-P -d10M -s [1000] -c[10] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true transacted=true messageSize=256 commitBatchSize=100 -o $QPID_WORK/results</PT-Qpid-5-P> + <PT-Qpid-6-P>-n PT-Qpid-6-P -d10M -s [1000] -c[10] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true messageSize=256 -o $QPID_WORK/results</PT-Qpid-6-P> + + <!-- 250 Msgs * 10 Brokers * 10 Topics/Clients = 250,000 Total, 10P-100T-10C 10*(1P-10T-1C) --> + <PT-Qpid-7-P>-n PT-Qpid-7-P -d10M -s [1000] -c[10] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true destinationsCount=10 transacted=true messageSize=256 commitBatchSize=100 -o $QPID_WORK/results</PT-Qpid-7-P> + <PT-Qpid-8-P>-n PT-Qpid-8-P -d10M -s [1000] -c[10] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true destinationsCount=10 messageSize=256 -o $QPID_WORK/results</PT-Qpid-8-P> + + <!-- 250 Msgs * 100 Brokers = 25,000 Total, 100P-100T-100C 100*(1P-1T-1C) --> + <PT-Qpid-9-P>-n PT-Qpid-9-P -d10M -s [1000] -c[100] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true messageSize=256 commitBatchSize=100 transacted=true -o $QPID_WORK/results</PT-Qpid-9-P> + <PT-Qpid-10-P>-n PT-Qpid-10-P -d10M -s [1000] -c[100] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true messageSize=256 batchSize=250 -o $QPID_WORK/results</PT-Qpid-10-P> + + <!-- 25 Msgs * 100 Brokers * 10 Clients = 250,000 Total, 100P-1000T-100C 100*(1P-10T-1C) --> + <PT-Qpid-11-P>-n PT-Qpid-11-P -d10M -s [1000] -c[100] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true messageSize=256 destinationsCount=10 transacted=true commitBatchSize=100 -o $QPID_WORK/results</PT-Qpid-11-P> + <PT-Qpid-12-P>-n PT-Qpid-12-P -d10M -s [1000] -c[100] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true messageSize=256 destinationsCount=10 -o $QPID_WORK/results</PT-Qpid-12-P> + + <!-- 25 Msgs * 1000 Brokers = 25,000 Total, 1000P-1000T-1000C 1000*(1P-1T-1C) --> + <!--PT-Qpid-13-P>-n PT-Qpid-13-P -d10M -s [1000] -c[1000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true messageSize=256 transacted=true commitBatchSize=100 -o $QPID_WORK/results</PT-Qpid-13-P--> + <!--PT-Qpid-14-P>-n PT-Qpid-14-P -d10M -s [1000] -c[1000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true messageSize=256 -o $QPID_WORK/results</PT-Qpid-14-P--> + + <!-- P2P Volume Tests. --> + <VQ-Qpid-1-P>-n VQ-Qpid-1-P -d1H -s [1000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true messageSize=256 commitBatchSize=100 transacted=true -o $QPID_WORK/results</VQ-Qpid-1-P> + <VQ-Qpid-2-P>-n VQ-Qpid-2-P -d1H -s [1000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true messageSize=256 -o $QPID_WORK/results</VQ-Qpid-2-P> + <!-- Setting sample to 3,000,000 will result in a log entry every 10 minutes so should have 144 data points for the run. --> + <VQ-Qpid-3-P>-n VQ-Qpid-3-P -s [100000] -d 24H -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true rate=10000 messageSize=256 commitBatchSize=100 transacted=true -o $QPID_WORK/results batchSize=100000</VQ-Qpid-3-P> + <VQ-Qpid-4-P>-n VQ-Qpid-4-P -s [100000] -d 24H -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true rate=10000 messageSize=256 -o $QPID_WORK/results batchSize=100000</VQ-Qpid-4-P> + + <!-- P2P Scalability Tests. --> + <!-- 1500 Total, 1P-1Q-1C --> + <PQ-Qpid-1-P>-n PQ-Qpid-1-P -d10M -s [1000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true transacted=true commitBatchSize=100 messageSize=256 -o $QPID_WORK/results</PQ-Qpid-1-P> + <PQ-Qpid-2-P>-n PQ-Qpid-2-P -d10M -s [100] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true messageSize=256 -o $QPID_WORK/results</PQ-Qpid-2-P> + + <!-- 150 Messages * 10 Brokers = 15,000 Total, 10P-1Q-10C --> + <PQ-Qpid-3-P>-n PQ-Qpid-3-P -d10M -s [1000] -c[10] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true messageSize=256 destinationName=ping transacted=true commitBatchSize=100 -o $QPID_WORK/results</PQ-Qpid-3-P> + <PQ-Qpid-4-P>-n PQ-Qpid-4-P -d10M -s [100] -c[10] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true messageSize=256 destinationName=ping -o $QPID_WORK/results</PQ-Qpid-4-P> + + <!-- 150 Messages * 10 Brokers = 15,000 Total, 10P-10Q-10C 10*(1P-1Q-1C) --> + <PQ-Qpid-5-P>-n PQ-Qpid-5-P -d10M -s [1000] -c[10] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true messageSize=256 transacted=true commitBatchSize=100 -o $QPID_WORK/results</PQ-Qpid-5-P> + <PQ-Qpid-6-P>-n PQ-Qpid-6-P -d10M -s [100] -c[10] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true messageSize=256 -o $QPID_WORK/results</PQ-Qpid-6-P> + + <!-- 150 Messages * 10 Brokers = 15,000 Total, 10P-100Q-10C 10*(1P-10Q-1C) --> + <PQ-Qpid-7-P>-n PQ-Qpid-7-P -d10M -s [1000] -c[10] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true messageSize=256 batchSize=100 destinationsCount=10 transacted=true commitBatchSize=100 -o $QPID_WORK/results</PQ-Qpid-7-P> + <PQ-Qpid-8-P>-n PQ-Qpid-8-P -d10M -s [100] -c[10] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true messageSize=256 destinationsCount=10 -o $QPID_WORK/results rate=200</PQ-Qpid-8-P> + + <!-- 15 Messages * 100 Brokers = 15,000 Total, 100P-100Q-100C 100*(1P-1Q-1C) --> + <PQ-Qpid-9-P>-n PQ-Qpid-9-P -d10M -s [1000] -c[100] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true messageSize=256 batchSize=50 transacted=true commitBatchSize=100 -o $QPID_WORK/results</PQ-Qpid-9-P> + <PQ-Qpid-10-P>-n PQ-Qpid-10-P -d10M -s [100] -c[100] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true messageSize=256 -o $QPID_WORK/results</PQ-Qpid-10-P> + + <!-- 15 Messages * 100 Brokers = 15,000 Total, 100P-1000Q-100C 100*(1P-10Q-1C) --> + <PQ-Qpid-11-P>-n PQ-Qpid-11-P -d10M -s [100] -c[100] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true messageSize=256 destinationsCount=10 transacted=true commitBatchSize=100 -o $QPID_WORK/results</PQ-Qpid-11-P> + <PQ-Qpid-12-P>-n PQ-Qpid-12-P -d10M -s [100] -c[100] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true messageSize=256 destinationsCount=10 -o $QPID_WORK/results</PQ-Qpid-12-P> + + <!-- 2 Messages * 1000 Brokers = 2,000 Total, 1000P-1000Q-1000C 1000*(1P-1Q-1C) --> + <!--PQ-Qpid-13-P>-n PQ-Qpid-13-P -d10M -s [1000] -c[1000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true messageSize=256 transacted=true commitBatchSize=100 -o $QPID_WORK/results</PQ-Qpid-13-P> + <PQ-Qpid-14-P>-n PQ-Qpid-14-P -d10M -s [1000] -c[1000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true messageSize=256 -o $QPID_WORK/results</PQ-Qpid-14-P--> + + <!-- Increasing Message Payload Tests. --> + <!-- Topic Testing --> + <LT-Qpid-1-512b-P>-n LT-Qpid-1-512b-P -d10M -s [1000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true messageSize=512 transacted=true commitBatchSize=100 -o $QPID_WORK/results</LT-Qpid-1-512b-P> + <LT-Qpid-2-512b-P>-n LT-Qpid-2-512b-P -d10M -s [100] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true messageSize=512 -o $QPID_WORK/results</LT-Qpid-2-512b-P> + + <LT-Qpid-1-1K-P>-n LT-Qpid-1-1K-P -d10M -s [1000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true commitBatchSize=100 transacted=true messageSize=1024 -o $QPID_WORK/results</LT-Qpid-1-1K-P> + <LT-Qpid-2-1K-P>-n LT-Qpid-2-1K-P -d10M -s [100] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true messageSize=1024 -o $QPID_WORK/results</LT-Qpid-2-1K-P> + + <LT-Qpid-1-5K-P>-n LT-Qpid-1-5K-P -d10M -s [1000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true messageSize=5120 transacted=true -o $QPID_WORK/results</LT-Qpid-1-5K-P> + <LT-Qpid-2-5K-P>-n LT-Qpid-2-5K-P -d10M -s [100] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true messageSize=5120 -o $QPID_WORK/results</LT-Qpid-2-5K-P> + + <LT-Qpid-1-10K-P>-n LT-Qpid-1-10K-P -d10M -s [1000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true commitBatchSize=100 messageSize=10240 transacted=true -o $QPID_WORK/results</LT-Qpid-1-10K-P> + <LT-Qpid-2-10K-P>-n LT-Qpid-2-10K-P -d10M -s [100] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true messageSize=10240 -o $QPID_WORK/results</LT-Qpid-2-10K-P> + + <LT-Qpid-1-50K-P>-n LT-Qpid-1-50K-P -d10M -s [1000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true messageSize=51200 commitBatchSize=100 transacted=true -o $QPID_WORK/results</LT-Qpid-1-50K-P> + <LT-Qpid-2-50K-P>-n LT-Qpid-2-50K-P -d10M -s [100] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true messageSize=51200 -o $QPID_WORK/results</LT-Qpid-2-50K-P> + + <LT-Qpid-1-100K-P>-n LT-Qpid-1-100K-P -d10M -s [1000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true commitBatchSize=100 messageSize=102400 transacted=true -o $QPID_WORK/results</LT-Qpid-1-100K-P> + <LT-Qpid-2-100K-P>-n LT-Qpid-2-100K-P -d10M -s [100] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true messageSize=102400 -o $QPID_WORK/results</LT-Qpid-2-100K-P> + + <LT-Qpid-1-1M-P>-n LT-Qpid-1-1M-P -d10M -s [1000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true commitBatchSize=100 messageSize=1048576 transacted=true -o $QPID_WORK/results</LT-Qpid-1-1M-P> + <LT-Qpid-2-1M-P>-n LT-Qpid-2-1M-P -d10M -s [100] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true pubsub=true messageSize=1048476 -o $QPID_WORK/results</LT-Qpid-2-1M-P> + + <!-- Queue Testing --> + <LT-Qpid-3-512b-P>-n LT-Qpid-3-512b-P -d10M -s [1000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true commitBatchSize=100 messageSize=512 transacted=true -o $QPID_WORK/results</LT-Qpid-3-512b-P> + <LT-Qpid-4-512b-P>-n LT-Qpid-4-512b-P -d10M -s [100] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true messageSize=512 -o $QPID_WORK/results</LT-Qpid-4-512b-P> + + <LT-Qpid-3-1K-P>-n LT-Qpid-3-1K-P -d10M -s [1000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true commitBatchSize=100 transacted=true messageSize=1024 -o $QPID_WORK/results</LT-Qpid-3-1K-P> + <LT-Qpid-4-1K-P>-n LT-Qpid-4-1K-P -d10M -s [100] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true messageSize=1024 -o $QPID_WORK/results</LT-Qpid-4-1K-P> + + <LT-Qpid-3-5K-P>-n LT-Qpid-3-5K-P -d10M -s [1000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true commitBatchSize=100 messageSize=5120 transacted=true -o $QPID_WORK/results</LT-Qpid-3-5K-P> + <LT-Qpid-4-5K-P>-n LT-Qpid-4-5K-P -d10M -s [100] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true messageSize=5120 -o $QPID_WORK/results</LT-Qpid-4-5K-P> + + <LT-Qpid-3-10K-P>-n LT-Qpid-3-10K-P -d10M -s [1000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true commitBatchSize=100 messageSize=10240 transacted=true -o $QPID_WORK/results</LT-Qpid-3-10K-P> + <LT-Qpid-4-10K-P>-n LT-Qpid-4-10K-P -d10M -s [100] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true messageSize=10240 -o $QPID_WORK/results</LT-Qpid-4-10K-P> + + <LT-Qpid-3-50K-P>-n LT-Qpid-3-50K-P -d10M -s [1000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true commitBatchSize=100 messageSize=51200 transacted=true -o $QPID_WORK/results</LT-Qpid-3-50K-P> + <LT-Qpid-4-50K-P>-n LT-Qpid-4-50K-P -d10M -s [100] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true messageSize=51200 -o $QPID_WORK/results</LT-Qpid-4-50K-P> + + <LT-Qpid-3-100K-P>-n LT-Qpid-3-100K-P -d10M -s [1000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true commitBatchSize=100 messageSize=102400 transacted=true -o $QPID_WORK/results</LT-Qpid-3-100K-P> + <LT-Qpid-4-100K-P>-n LT-Qpid-4-100K-P -d10M -s [100] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true messageSize=102400 -o $QPID_WORK/results</LT-Qpid-4-100K-P> + + <LT-Qpid-3-1M-P>-n LT-Qpid-3-1M-P -d10M -s [1000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true commitBatchSize=100 messageSize=1048576 transacted=true -o $QPID_WORK/results</LT-Qpid-3-1M-P> + <LT-Qpid-4-1M-P>-n LT-Qpid-4-1M-P -d10M -s [100] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true messageSize=1048576 -o $QPID_WORK/results</LT-Qpid-4-1M-P> + + <!-- Failover Tests. --> + <!-- Transactional --> + <FT-Qpid-1-P>-n FT-Qpid-1-P -s [25000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true messageSize=256 batchSize=10000 transacted=true broker="tcp://10.0.0.1:5001;tcp://10.0.0.2:5002" failBeforeSend=true -o $QPID_WORK/results</FT-Qpid-1-P> + <FT-Qpid-2-P>-n FT-Qpid-2-P -s [25000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true messageSize=256 batchSize=10000 transacted=true broker="tcp://10.0.0.1:5001;tcp://10.0.0.2:5002" failAfterSend=true -o $QPID_WORK/results</FT-Qpid-2-P> + <FT-Qpid-3-P>-n FT-Qpid-3-P -s [25000] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true messageSize=256 batchSize=10000 transacted=true broker="tcp://10.0.0.1:5001;tcp://10.0.0.2:5002" failAfterCommit=true -o $QPID_WORK/results</FT-Qpid-3-P> + + <!-- Non Transactional --> + <FT-Qpid-4-P>-n FT-Qpid-4-P -s [250] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true messageSize=256 broker="tcp://10.0.0.1:5001;tcp://10.0.0.2:5002" transacted=false failBeforeSend=true -o $QPID_WORK/results</FT-Qpid-4-P> + <FT-Qpid-5-P>-n FT-Qpid-5-P -s [250] -t testAsyncPingOk org.apache.qpid.ping.PingAsyncTestPerf persistent=true messageSize=256 broker="tcp://10.0.0.1:5001;tcp://10.0.0.2:5002" transacted=false failAfterSend=true -o $QPID_WORK/results</FT-Qpid-5-P> + </commands> </configuration> diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/client/message/TestMessageFactory.java b/qpid/java/perftests/src/main/java/org/apache/qpid/client/message/TestMessageFactory.java index c0f236b833..eeb4021f34 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/client/message/TestMessageFactory.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/client/message/TestMessageFactory.java @@ -103,7 +103,7 @@ public class TestMessageFactory { StringBuffer buf = new StringBuffer(size); int count = 0; - while (count < size) + while (count <= (size - MESSAGE_DATA_BYTES.length())) { buf.append(MESSAGE_DATA_BYTES); count += MESSAGE_DATA_BYTES.length(); diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/config/AbstractConfig.java b/qpid/java/perftests/src/main/java/org/apache/qpid/config/AbstractConfig.java index 04381d66a0..14db74438f 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/config/AbstractConfig.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/config/AbstractConfig.java @@ -49,7 +49,7 @@ public abstract class AbstractConfig } catch(NumberFormatException e) { - throw new RuntimeException(msg + ": " + i); + throw new RuntimeException(msg + ": " + i, e); } } @@ -61,7 +61,7 @@ public abstract class AbstractConfig } catch(NumberFormatException e) { - throw new RuntimeException(msg + ": " + i); + throw new RuntimeException(msg + ": " + i, e); } } diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/config/JBossConnectionFactoryInitialiser.java b/qpid/java/perftests/src/main/java/org/apache/qpid/config/JBossConnectionFactoryInitialiser.java index 44285efd96..a0248a8f79 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/config/JBossConnectionFactoryInitialiser.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/config/JBossConnectionFactoryInitialiser.java @@ -22,6 +22,7 @@ package org.apache.qpid.config; import org.apache.qpid.config.ConnectionFactoryInitialiser; import org.apache.qpid.config.ConnectorConfig; +import org.apache.qpid.client.JMSAMQException; import javax.jms.ConnectionFactory; import javax.jms.JMSException; @@ -63,11 +64,11 @@ public class JBossConnectionFactoryInitialiser implements ConnectionFactoryIniti } catch (NamingException e) { - throw new JMSException("Unable to lookup object: " + e); + throw new JMSAMQException("Unable to lookup object: " + e, e); } catch (Exception e) { - throw new JMSException("Error creating topic: " + e); + throw new JMSAMQException("Error creating topic: " + e, e); } } diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingDurableClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingDurableClient.java index 82e43e542f..0e832ef100 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingDurableClient.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingDurableClient.java @@ -1,3 +1,4 @@ +/* Copyright Rupert Smith, 2005 to 2006, all rights reserved. */
/*
*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -178,6 +179,7 @@ public class PingDurableClient extends PingPongProducer implements ExceptionList // Run the test procedure.
int sent = pingProducer.send();
+ pingProducer.closeConnection();
pingProducer.waitForUser("Press return to begin receiving the pings.");
pingProducer.receive(sent);
@@ -302,6 +304,13 @@ public class PingDurableClient extends PingPongProducer implements ExceptionList System.out.println("Messages sent: " + messagesSent + ", Messages Committed = " + messagesCommitted
+ ", Messages not Committed = " + messagesNotCommitted);
+
+
+ return messagesSent;
+ }
+
+ protected void closeConnection()
+ {
// Clean up the connection.
try
{
@@ -309,10 +318,11 @@ public class PingDurableClient extends PingPongProducer implements ExceptionList }
catch (JMSException e)
{
+ log.debug("There was an error whilst closing the connection: " + e, e);
+ System.out.println("There was an error whilst closing the connection.");
+
// Ignore as did best could manage to clean up.
}
-
- return messagesSent;
}
protected void receive(int messagesSent) throws Exception
@@ -354,6 +364,32 @@ public class PingDurableClient extends PingPongProducer implements ExceptionList }
}
+ // Ensure messages received are committed.
+ if (_transacted)
+ {
+ try
+ {
+ _consumerSession.commit();
+ System.out.println("Committed for all messages received.");
+ }
+ catch (JMSException e)
+ {
+ log.debug("Error during commit: " + e, e);
+ System.out.println("Error during commit.");
+ try
+ {
+ _consumerSession.rollback();
+ System.out.println("Rolled back on all messages received.");
+ }
+ catch (JMSException e2)
+ {
+ log.debug("Error during rollback: " + e, e);
+ System.out.println("Error on roll back of all messages received.");
+ }
+
+ }
+ }
+
log.debug("messagesReceived = " + messagesReceived);
System.out.println("Messages received: " + messagesReceived);
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingSendOnlyClient.java b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingSendOnlyClient.java new file mode 100644 index 0000000000..7cf5e4516f --- /dev/null +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/ping/PingSendOnlyClient.java @@ -0,0 +1,57 @@ +/* Copyright Rupert Smith, 2005 to 2006, all rights reserved. */
+package org.apache.qpid.ping;
+
+import java.util.Properties;
+
+import org.apache.log4j.Logger;
+
+import org.apache.qpid.util.CommandLineParser;
+
+/**
+ * <p><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * </table>
+ */
+public class PingSendOnlyClient extends PingDurableClient
+{
+ private static final Logger log = Logger.getLogger(PingSendOnlyClient.class);
+
+ public PingSendOnlyClient(Properties overrides) throws Exception
+ {
+ super(overrides);
+ }
+
+ /**
+ * Starts the ping/wait/receive process.
+ *
+ * @param args The command line arguments.
+ */
+ public static void main(String[] args)
+ {
+ try
+ {
+ // Create a ping producer overriding its defaults with all options passed on the command line.
+ Properties options = CommandLineParser.processCommandLine(args, new CommandLineParser(new String[][] {}));
+ PingDurableClient pingProducer = new PingSendOnlyClient(options);
+
+ // Create a shutdown hook to terminate the ping-pong producer.
+ Runtime.getRuntime().addShutdownHook(pingProducer.getShutdownHook());
+
+ // Ensure that the ping pong producer is registered to listen for exceptions on the connection too.
+ // pingProducer.getConnection().setExceptionListener(pingProducer);
+
+ // Run the test procedure.
+ int sent = pingProducer.send();
+ pingProducer.waitForUser("Press return to close connection and quit.");
+ pingProducer.closeConnection();
+
+ System.exit(0);
+ }
+ catch (Exception e)
+ {
+ System.err.println(e.getMessage());
+ log.error("Top level handler caught execption.", e);
+ System.exit(1);
+ }
+ }
+}
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java index 913685bca2..ecaf27167f 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/requestreply/PingPongProducer.java @@ -116,7 +116,7 @@ import uk.co.thebadgerset.junit.extensions.util.ParsedProperties; * by the PPP that it is atteched to.
*
* @todo Use read/write lock in the onmessage, not for reading writing but to make use of a shared and exlcusive lock pair.
- * Obtian read lock on all messages, before decrementing the message count. At the end of the on message method add a
+ * Obtain read lock on all messages, before decrementing the message count. At the end of the on message method add a
* block that obtains the write lock for the very last message, releases any waiting producer. Means that the last
* message waits until all other messages have been handled before releasing producers but allows messages to be
* processed concurrently, unlike the current synchronized block.
@@ -725,6 +725,8 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis log.debug("public void createReplyConsumers(Collection<Destination> destinations = " + destinations
+ ", String selector = " + selector + "): called");
+ log.debug("Creating " + destinations.size() + " reply consumers.");
+
for (Destination destination : destinations)
{
// Create a consumer for the destination and set this pinger to listen to its messages.
@@ -732,6 +734,8 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis _consumerSession.createConsumer(destination, PREFETCH_DEFAULT, NO_LOCAL_DEFAULT, EXCLUSIVE_DEFAULT,
selector);
_consumer.setMessageListener(this);
+
+ log.debug("Set this to listen to replies sent to destination: " + destination);
}
}
@@ -743,13 +747,13 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis */
public void onMessage(Message message)
{
- log.debug("public void onMessage(Message message): called");
+ // log.debug("public void onMessage(Message message): called");
try
{
// Extract the messages correlation id.
String correlationID = message.getJMSCorrelationID();
- log.debug("correlationID = " + correlationID);
+ // log.debug("correlationID = " + correlationID);
// Countdown on the traffic light if there is one for the matching correlation id.
PerCorrelationId perCorrelationId = perCorrelationIds.get(correlationID);
@@ -761,7 +765,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis // Restart the timeout timer on every message.
perCorrelationId.timeOutStart = System.nanoTime();
- log.debug("Reply was expected, decrementing the latch for the id, " + correlationID);
+ // log.debug("Reply was expected, decrementing the latch for the id, " + correlationID);
// Decrement the countdown latch. Before this point, it is possible that two threads might enter this
// method simultanesouly with the same correlation id. Decrementing the latch in a synchronized block
@@ -776,8 +780,8 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis trueCount = trafficLight.getCount();
remainingCount = trueCount - 1;
- log.debug("remainingCount = " + remainingCount);
- log.debug("trueCount = " + trueCount);
+ // log.debug("remainingCount = " + remainingCount);
+ // log.debug("trueCount = " + trueCount);
// Commit on transaction batch size boundaries. At this point in time the waiting producer remains
// blocked, even on the last message.
@@ -806,23 +810,23 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis }
// Print out ping times for every message in verbose mode only.
- if (_verbose)
+ /*if (_verbose)
{
Long timestamp = message.getLongProperty(MESSAGE_TIMESTAMP_PROPNAME);
if (timestamp != null)
{
long diff = System.nanoTime() - timestamp;
- log.trace("Time for round trip (nanos): " + diff);
+ //log.trace("Time for round trip (nanos): " + diff);
}
- }
+ }*/
}
catch (JMSException e)
{
log.warn("There was a JMSException: " + e.getMessage(), e);
}
- log.debug("public void onMessage(Message message): ending");
+ // log.debug("public void onMessage(Message message): ending");
}
/**
@@ -955,16 +959,16 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis committed = false;
// Re-timestamp the message.
- message.setLongProperty(MESSAGE_TIMESTAMP_PROPNAME, System.nanoTime());
+ // message.setLongProperty(MESSAGE_TIMESTAMP_PROPNAME, System.nanoTime());
// Send the message, passing in the message count.
committed = sendMessage(i, message);
// Spew out per message timings on every message sonly in verbose mode.
- if (_verbose)
+ /*if (_verbose)
{
log.info(timestampFormatter.format(new Date()) + ": Pinged at with correlation id, " + messageCorrelationId);
- }
+ }*/
}
// Call commit if the send loop finished before reaching a batch size boundary so there may still be uncommitted messages.
@@ -1003,7 +1007,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis _failBeforeSend = false;
}
- log.trace("Failing Before Send");
+ // log.trace("Failing Before Send");
waitForUser(KILL_BROKER_PROMPT);
}
@@ -1176,6 +1180,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis if (_connection != null)
{
_connection.close();
+ log.debug("Close connection.");
}
}
finally
@@ -1213,20 +1218,20 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis */
protected boolean commitTx(Session session) throws JMSException
{
- log.debug("protected void commitTx(Session session): called");
+ // log.debug("protected void commitTx(Session session): called");
boolean committed = false;
- log.trace("Batch time reached");
+ // log.trace("Batch time reached");
if (_failAfterSend)
{
- log.trace("Batch size reached");
+ // log.trace("Batch size reached");
if (_failOnce)
{
_failAfterSend = false;
}
- log.trace("Failing After Send");
+ // log.trace("Failing After Send");
waitForUser(KILL_BROKER_PROMPT);
}
@@ -1241,14 +1246,14 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis _failBeforeCommit = false;
}
- log.trace("Failing Before Commit");
+ // log.trace("Failing Before Commit");
waitForUser(KILL_BROKER_PROMPT);
}
- long l = System.nanoTime();
+ // long l = System.nanoTime();
session.commit();
committed = true;
- log.debug("Time taken to commit :" + ((System.nanoTime() - l) / 1000000f) + " ms");
+ // log.debug("Time taken to commit :" + ((System.nanoTime() - l) / 1000000f) + " ms");
if (_failAfterCommit)
{
@@ -1257,15 +1262,15 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis _failAfterCommit = false;
}
- log.trace("Failing After Commit");
+ // log.trace("Failing After Commit");
waitForUser(KILL_BROKER_PROMPT);
}
- log.trace("Session Commited.");
+ // log.trace("Session Commited.");
}
catch (JMSException e)
{
- log.trace("JMSException on commit:" + e.getMessage(), e);
+ log.debug("JMSException on commit:" + e.getMessage(), e);
// Warn that the bounce back client is not available.
if (e.getLinkedException() instanceof AMQNoConsumersException)
@@ -1276,11 +1281,11 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis try
{
session.rollback();
- log.trace("Message rolled back.");
+ log.debug("Message rolled back.");
}
catch (JMSException jmse)
{
- log.trace("JMSE on rollback:" + jmse.getMessage(), jmse);
+ log.debug("JMSE on rollback:" + jmse.getMessage(), jmse);
// Both commit and rollback failed. Throw the rollback exception.
throw jmse;
@@ -1296,7 +1301,7 @@ public class PingPongProducer implements Runnable, MessageListener, ExceptionLis *
* @param prompt The prompt to display on the console.
*/
- protected void waitForUser(String prompt)
+ public void waitForUser(String prompt)
{
System.out.println(prompt);
diff --git a/qpid/java/perftests/src/main/java/org/apache/qpid/topic/Config.java b/qpid/java/perftests/src/main/java/org/apache/qpid/topic/Config.java index 342b28ca17..d5c0979399 100644 --- a/qpid/java/perftests/src/main/java/org/apache/qpid/topic/Config.java +++ b/qpid/java/perftests/src/main/java/org/apache/qpid/topic/Config.java @@ -221,7 +221,7 @@ public class Config extends AbstractConfig implements ConnectorConfig } catch(NumberFormatException e) { - throw new RuntimeException("Bad port number: " + value); + throw new RuntimeException("Bad port number: " + value, e); } } else if("-payload".equalsIgnoreCase(key)) diff --git a/qpid/java/perftests/src/test/java/org/apache/qpid/ping/PingAsyncTestPerf.java b/qpid/java/perftests/src/test/java/org/apache/qpid/ping/PingAsyncTestPerf.java index 3b8e670f8f..6c7f22c19a 100644 --- a/qpid/java/perftests/src/test/java/org/apache/qpid/ping/PingAsyncTestPerf.java +++ b/qpid/java/perftests/src/test/java/org/apache/qpid/ping/PingAsyncTestPerf.java @@ -133,12 +133,13 @@ public class PingAsyncTestPerf extends PingTestPerf implements TimingControllerA */ public void testAsyncPingOk(int numPings) throws Exception { - _logger.debug("public void testAsyncPingOk(int numPings): called"); + // _logger.debug("public void testAsyncPingOk(int numPings): called"); // Ensure that at least one ping was requeusted. if (numPings == 0) { _logger.error("Number of pings requested was zero."); + fail("Number of pings requested was zero."); } // Get the per thread test setup to run the test through. @@ -147,8 +148,8 @@ public class PingAsyncTestPerf extends PingTestPerf implements TimingControllerA // Advance the correlation id of messages to send, to make it unique for this run. perThreadSetup._correlationId = Long.toString(corellationIdGenerator.incrementAndGet()); - String messageCorrelationId = perThreadSetup._correlationId; - _logger.debug("messageCorrelationId = " + messageCorrelationId); + // String messageCorrelationId = perThreadSetup._correlationId; + // _logger.debug("messageCorrelationId = " + messageCorrelationId); // Initialize the count and timing controller for the new correlation id. PerCorrelationId perCorrelationId = new PerCorrelationId(); @@ -246,9 +247,9 @@ public class PingAsyncTestPerf extends PingTestPerf implements TimingControllerA // Extract the correlation id from the message. String correlationId = message.getJMSCorrelationID(); - _logger.debug("public void onMessage(Message message, int remainingCount = " + remainingCount + /*_logger.debug("public void onMessage(Message message, int remainingCount = " + remainingCount + "): called on batch boundary for message id: " + correlationId + " with thread id: " - + Thread.currentThread().getId()); + + Thread.currentThread().getId());*/ // Get the details for the correlation id and check that they are not null. They can become null // if a test times out. diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBeanTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBeanTest.java index 7c14de23a6..20de0d5df0 100644 --- a/qpid/java/systests/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBeanTest.java +++ b/qpid/java/systests/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBeanTest.java @@ -44,9 +44,9 @@ public class AMQBrokerManagerMBeanTest extends TestCase VirtualHost vHost = ApplicationRegistry.getInstance().getVirtualHostRegistry().getVirtualHost("test"); ManagedBroker mbean = new AMQBrokerManagerMBean((VirtualHost.VirtualHostMBean)vHost.getManagedObject()); - mbean.createNewExchange(exchange1,"direct",false, false); - mbean.createNewExchange(exchange2,"topic",false, false); - mbean.createNewExchange(exchange3,"headers",false, false); + 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); @@ -70,7 +70,7 @@ public class AMQBrokerManagerMBeanTest extends TestCase assertTrue(_queueRegistry.getQueue(new AMQShortString(queueName)) == null); - mbean.createNewQueue(queueName, "test", false, true); + mbean.createNewQueue(queueName, "test", false); assertTrue(_queueRegistry.getQueue(new AMQShortString(queueName)) != null); mbean.deleteQueue(queueName); diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/failure/HeapExhaustion.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/failure/HeapExhaustion.java new file mode 100644 index 0000000000..52eb5414ff --- /dev/null +++ b/qpid/java/systests/src/main/java/org/apache/qpid/server/failure/HeapExhaustion.java @@ -0,0 +1,208 @@ +package org.apache.qpid.server.failure; + +import junit.framework.TestCase; +import org.apache.qpid.testutil.QpidClientConnection; +import org.apache.qpid.client.failover.FailoverException; +import org.apache.qpid.AMQException; +import org.apache.qpid.protocol.AMQConstant; +import org.apache.log4j.Logger; + +import javax.jms.JMSException; +import java.io.IOException; + + +/** Test Case provided by client Non-functional Test NF101: heap exhaustion behaviour */ +public class HeapExhaustion extends TestCase +{ + private static final Logger _logger = Logger.getLogger(HeapExhaustion.class); + + protected QpidClientConnection conn; + protected final String BROKER = "localhost"; + protected final String vhost = "/test"; + protected final String queue = "direct://amq.direct//queue"; + + protected String hundredK; + protected String megabyte; + + protected String generatePayloadOfSize(Integer numBytes) + { + return new String(new byte[numBytes]); + } + + protected void setUp() throws Exception + { + conn = new QpidClientConnection(BROKER); + conn.setVirtualHost(vhost); + + conn.connect(); + // clear queue + _logger.debug("setup: clearing test queue"); + conn.consume(queue, 2000); + + hundredK = generatePayloadOfSize(1024 * 100); + megabyte = generatePayloadOfSize(1024 * 1024); + } + + protected void tearDown() throws Exception + { + conn.disconnect(); + } + + + /** + * PUT at maximum rate (although we commit after each PUT) until failure + * + * @throws Exception on error + */ + public void testUntilFailure() throws Exception + { + int copies = 0; + int total = 0; + String payload = hundredK; + int size = payload.getBytes().length; + while (true) + { + conn.put(queue, payload, 1); + copies++; + total += size; + _logger.info("put copy " + copies + " OK for total bytes: " + total); + } + } + + /** + * PUT at lower rate (5 per second) until failure + * + * @throws Exception on error + */ + public void testUntilFailureWithDelays() throws Exception + { + int copies = 0; + int total = 0; + String payload = hundredK; + int size = payload.getBytes().length; + while (true) + { + conn.put(queue, payload, 1); + copies++; + total += size; + _logger.debug("put copy " + copies + " OK for total bytes: " + total); + Thread.sleep(200); + } + } + + public static void noDelay() + { + HeapExhaustion he = new HeapExhaustion(); + + try + { + he.setUp(); + } + catch (Exception e) + { + _logger.info("Unable to connect"); + System.exit(0); + } + + try + { + _logger.info("Running testUntilFailure"); + try + { + he.testUntilFailure(); + } + catch (FailoverException fe) + { + _logger.error("Caught failover:" + fe); + } + _logger.info("Finishing Connection "); + + try + { + he.tearDown(); + } + catch (JMSException jmse) + { + if (((AMQException) jmse.getLinkedException()).getErrorCode() == AMQConstant.REQUEST_TIMEOUT) + { + _logger.info("Successful test of testUntilFailure"); + } + else + { + _logger.error("Test Failed due to:" + jmse); + } + } + } + catch (Exception e) + { + _logger.error("Test Failed due to:" + e); + } + } + + public static void withDelay() + { + HeapExhaustion he = new HeapExhaustion(); + + try + { + he.setUp(); + } + catch (Exception e) + { + _logger.info("Unable to connect"); + System.exit(0); + } + + try + { + _logger.info("Running testUntilFailure"); + try + { + he.testUntilFailureWithDelays(); + } + catch (FailoverException fe) + { + _logger.error("Caught failover:" + fe); + } + _logger.info("Finishing Connection "); + + try + { + he.tearDown(); + } + catch (JMSException jmse) + { + if (((AMQException) jmse.getLinkedException()).getErrorCode() == AMQConstant.REQUEST_TIMEOUT) + { + _logger.info("Successful test of testUntilFailure"); + } + else + { + _logger.error("Test Failed due to:" + jmse); + } + } + } + catch (Exception e) + { + _logger.error("Test Failed due to:" + e); + } + } + + public static void main(String args[]) + { + noDelay(); + + + try + { + System.out.println("Restart failed broker now to retest broker with delays in send."); + System.in.read(); + } + catch (IOException e) + { + _logger.info("Continuing"); + } + + withDelay(); + } +} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/MockProtocolSession.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/MockProtocolSession.java index 8795adbc55..0ad6502755 100644 --- a/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/MockProtocolSession.java +++ b/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/MockProtocolSession.java @@ -35,6 +35,7 @@ import org.apache.qpid.server.store.MessageStore; import javax.security.sasl.SaslServer; import java.util.HashMap; import java.util.Map; +import java.security.Principal; /** * A protocol session that can be used for testing purposes. @@ -177,12 +178,12 @@ public class MockProtocolSession implements AMQProtocolSession return ProtocolOutputConverterRegistry.getConverter(this); } - public void setAuthorizedID(String authorizedID) + public void setAuthorizedID(Principal authorizedID) { //To change body of implemented methods use File | Settings | File Templates. } - public String getAuthorizedID() + public Principal getAuthorizedID() { return null; //To change body of implemented methods use File | Settings | File Templates. } diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/PersistentTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/PersistentTest.java new file mode 100644 index 0000000000..4ad10b68ff --- /dev/null +++ b/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/PersistentTest.java @@ -0,0 +1,276 @@ +/* + * 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.client.AMQConnection; +import org.apache.qpid.client.AMQSession; +import org.apache.qpid.AMQException; +import org.apache.qpid.AMQChannelClosedException; +import org.apache.qpid.AMQConnectionClosedException; +import org.apache.qpid.util.CommandLineParser; +import org.apache.qpid.url.URLSyntaxException; +import org.apache.log4j.Logger; + +import javax.jms.Session; +import javax.jms.JMSException; +import javax.jms.Queue; +import javax.jms.MessageProducer; +import javax.jms.TextMessage; +import java.io.IOException; +import java.util.Properties; + +public class PersistentTest +{ + private static final Logger _logger = Logger.getLogger(PersistentTest.class); + + + private static final String QUEUE = "direct://amq.direct//PersistentTest-Queue2?durable='true',exclusive='true'"; + + protected AMQConnection _connection; + + protected Session _session; + + protected Queue _queue; + private Properties properties; + + private String _brokerDetails; + private String _username; + private String _password; + private String _virtualpath; + + public PersistentTest(Properties overrides) + { + properties = new Properties(defaults); + properties.putAll(overrides); + + _brokerDetails = properties.getProperty(BROKER_PROPNAME); + _username = properties.getProperty(USERNAME_PROPNAME); + _password = properties.getProperty(PASSWORD_PROPNAME); + _virtualpath = properties.getProperty(VIRTUAL_HOST_PROPNAME); + + createConnection(); + } + + protected void createConnection() + { + try + { + _connection = new AMQConnection(_brokerDetails, _username, _password, "PersistentTest", _virtualpath); + + _session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + _connection.start(); + } + catch (Exception e) + { + _logger.error("Unable to create test class due to:" + e.getMessage(), e); + System.exit(0); + } + } + + public void test() throws AMQException, URLSyntaxException + { + + //Create the Durable Queue + try + { + _session.createConsumer(_session.createQueue(QUEUE)).close(); + } + catch (JMSException e) + { + _logger.error("Unable to create Queue due to:" + e.getMessage(), e); + System.exit(0); + } + + try + { + if (testQueue()) + { + // close connection + _connection.close(); + // wait + System.out.println("Restart Broker Now"); + try + { + System.in.read(); + } + catch (IOException e) + { + // + } + finally + { + System.out.println("Continuing...."); + } + + //Test queue is still there. + AMQConnection connection = new AMQConnection(_brokerDetails, _username, _password, "DifferentClientID", _virtualpath); + + AMQSession session = (AMQSession) connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + try + { + session.createConsumer(session.createQueue(QUEUE)); + _logger.error("Create consumer succeeded." + + " This shouldn't be allowed as this means the queue didn't exist when it should"); + + connection.close(); + + exit(); + } + catch (JMSException e) + { + try + { + connection.close(); + } + catch (JMSException cce) + { + if (cce.getLinkedException() instanceof AMQConnectionClosedException) + { + _logger.error("Channel Close Bug still present QPID-432, should see an 'Error closing session'"); + } + else + { + exit(cce); + } + } + + if (e.getLinkedException() instanceof AMQChannelClosedException) + { + _logger.info("AMQChannelClosedException received as expected"); + } + else + { + exit(e); + } + } + } + } + catch (JMSException e) + { + _logger.error("Unable to test Queue due to:" + e.getMessage(), e); + System.exit(0); + } + } + + private void exit(JMSException e) + { + _logger.error("JMSException received:" + e.getMessage()); + e.printStackTrace(); + exit(); + } + + private void exit() + { + try + { + _connection.close(); + } + catch (JMSException e) + { + // + } + System.exit(0); + } + + private boolean testQueue() throws JMSException + { + String TEST_TEXT = "init"; + + //Create a new session to send producer + Session session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + Queue q = session.createQueue(QUEUE); + MessageProducer producer = session.createProducer(q); + + producer.send(session.createTextMessage(TEST_TEXT)); + + //create a new consumer on the original session + TextMessage m = (TextMessage) _session.createConsumer(q).receive(); + + + if ((m != null) && m.getText().equals(TEST_TEXT)) + { + return true; + } + else + { + _logger.error("Incorrect values returned from Queue Test:" + m); + System.exit(0); + return false; + } + } + + /** Holds the name of the property to get the test broker url from. */ + public static final String BROKER_PROPNAME = "broker"; + + /** Holds the default broker url for the test. */ + public static final String BROKER_DEFAULT = "tcp://localhost:5672"; + + /** Holds the name of the property to get the test broker virtual path. */ + public static final String VIRTUAL_HOST_PROPNAME = "virtualHost"; + + /** Holds the default virtual path for the test. */ + public static final String VIRTUAL_HOST_DEFAULT = ""; + + /** Holds the name of the property to get the broker access username from. */ + public static final String USERNAME_PROPNAME = "username"; + + /** Holds the default broker log on username. */ + public static final String USERNAME_DEFAULT = "guest"; + + /** Holds the name of the property to get the broker access password from. */ + public static final String PASSWORD_PROPNAME = "password"; + + /** Holds the default broker log on password. */ + public static final String PASSWORD_DEFAULT = "guest"; + + /** Holds the default configuration properties. */ + public static Properties defaults = new Properties(); + + static + { + defaults.setProperty(BROKER_PROPNAME, BROKER_DEFAULT); + defaults.setProperty(USERNAME_PROPNAME, USERNAME_DEFAULT); + defaults.setProperty(PASSWORD_PROPNAME, PASSWORD_DEFAULT); + defaults.setProperty(VIRTUAL_HOST_PROPNAME, VIRTUAL_HOST_DEFAULT); + } + + public static void main(String[] args) + { + PersistentTest test; + + Properties options = CommandLineParser.processCommandLine(args, new CommandLineParser(new String[][]{})); + + + test = new PersistentTest(options); + try + { + test.test(); + System.out.println("Test was successfull."); + } + catch (Exception e) + { + _logger.error("Unable to test due to:" + e.getMessage(), e); + } + } +} diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/testutil/QpidClientConnection.java b/qpid/java/systests/src/main/java/org/apache/qpid/testutil/QpidClientConnection.java new file mode 100644 index 0000000000..80773c102d --- /dev/null +++ b/qpid/java/systests/src/main/java/org/apache/qpid/testutil/QpidClientConnection.java @@ -0,0 +1,268 @@ +package org.apache.qpid.testutil; + +import org.apache.qpid.client.AMQConnectionFactory; +import org.apache.qpid.client.AMQConnectionURL; +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.JMSAMQException; +import org.apache.qpid.url.URLSyntaxException; +import org.apache.log4j.Logger; + +import javax.jms.ExceptionListener; +import javax.jms.Session; +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.Queue; +import javax.jms.MessageProducer; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.TextMessage; + +public class QpidClientConnection implements ExceptionListener +{ + + private static final Logger _logger = Logger.getLogger(QpidClientConnection.class); + + private boolean transacted = true; + private int ackMode = Session.CLIENT_ACKNOWLEDGE; + private Connection connection; + + private String virtualHost; + private String brokerlist; + private int prefetch; + protected Session session; + protected boolean connected; + + public QpidClientConnection(String broker) + { + super(); + setVirtualHost("/test"); + setBrokerList(broker); + setPrefetch(5000); + } + + + public void connect() throws JMSException + { + if (!connected) + { + /* + * amqp://[user:pass@][clientid]/virtualhost? + * brokerlist='[transport://]host[:port][?option='value'[&option='value']];' + * [&failover='method[?option='value'[&option='value']]'] + * [&option='value']" + */ + String brokerUrl = "amqp://guest:guest@" + virtualHost + "?brokerlist='" + brokerlist + "'"; + try + { + AMQConnectionFactory factory = new AMQConnectionFactory(new AMQConnectionURL(brokerUrl)); + _logger.info("connecting to Qpid :" + brokerUrl); + connection = factory.createConnection(); + + // register exception listener + connection.setExceptionListener(this); + + session = ((AMQConnection) connection).createSession(transacted, ackMode, prefetch); + + + _logger.info("starting connection"); + connection.start(); + + connected = true; + } + catch (URLSyntaxException e) + { + throw new JMSAMQException("URL syntax error in [" + brokerUrl + "]: " + e.getMessage(), e); + } + } + } + + public void disconnect() throws JMSException + { + if (connected) + { + session.commit(); + session.close(); + connection.close(); + connected = false; + _logger.info("disconnected"); + } + } + + public void disconnectWithoutCommit() throws JMSException + { + if (connected) + { + session.close(); + connection.close(); + connected = false; + _logger.info("disconnected without commit"); + } + } + + public String getBrokerList() + { + return brokerlist; + } + + public void setBrokerList(String brokerlist) + { + this.brokerlist = brokerlist; + } + + public String getVirtualHost() + { + return virtualHost; + } + + public void setVirtualHost(String virtualHost) + { + this.virtualHost = virtualHost; + } + + public void setPrefetch(int prefetch) + { + this.prefetch = prefetch; + } + + + /** override as necessary */ + public void onException(JMSException exception) + { + _logger.info("ExceptionListener event: error " + exception.getErrorCode() + ", message: " + exception.getMessage()); + } + + public boolean isConnected() + { + return connected; + } + + public Session getSession() + { + return session; + } + + /** + * Put a String as a text messages, repeat n times. A null payload will result in a null message. + * + * @param queueName The queue name to put to + * @param payload the content of the payload + * @param copies the number of messages to put + * + * @throws javax.jms.JMSException any exception that occurs + */ + public void put(String queueName, String payload, int copies) throws JMSException + { + if (!connected) + { + connect(); + } + + _logger.info("putting to queue " + queueName); + Queue queue = session.createQueue(queueName); + + final MessageProducer sender = session.createProducer(queue); + + for (int i = 0; i < copies; i++) + { + Message m = session.createTextMessage(payload + i); + m.setIntProperty("index", i + 1); + sender.send(m); + } + + session.commit(); + sender.close(); + _logger.info("put " + copies + " copies"); + } + + /** + * GET the top message on a queue. Consumes the message. Accepts timeout value. + * + * @param queueName The quename to get from + * @param readTimeout The timeout to use + * + * @return the content of the text message if any + * + * @throws javax.jms.JMSException any exception that occured + */ + public Message getNextMessage(String queueName, long readTimeout) throws JMSException + { + if (!connected) + { + connect(); + } + + Queue queue = session.createQueue(queueName); + + final MessageConsumer consumer = session.createConsumer(queue); + + Message message = consumer.receive(readTimeout); + session.commit(); + consumer.close(); + + Message result; + + // all messages we consume should be TextMessages + if (message instanceof TextMessage) + { + result = ((TextMessage) message); + } + else if (null == message) + { + result = null; + } + else + { + _logger.info("warning: received non-text message"); + result = message; + } + + return result; + } + + /** + * GET the top message on a queue. Consumes the message. + * + * @param queueName The Queuename to get from + * + * @return The string content of the text message, if any received + * + * @throws javax.jms.JMSException any exception that occurs + */ + public Message getNextMessage(String queueName) throws JMSException + { + return getNextMessage(queueName, 0); + } + + /** + * Completely clears a queue. For readTimeout behaviour see Javadocs for javax.jms.MessageConsumer. + * + * @param queueName The Queue name to consume from + * @param readTimeout The timeout for each consume + * + * @throws javax.jms.JMSException Any exception that occurs during the consume + * @throws InterruptedException If the consume thread was interrupted during a consume. + */ + public void consume(String queueName, int readTimeout) throws JMSException, InterruptedException + { + if (!connected) + { + connect(); + } + + _logger.info("consuming queue " + queueName); + Queue queue = session.createQueue(queueName); + + final MessageConsumer consumer = session.createConsumer(queue); + int messagesReceived = 0; + + _logger.info("consuming..."); + while ((consumer.receive(readTimeout)) != null) + { + messagesReceived++; + } + + session.commit(); + consumer.close(); + _logger.info("consumed: " + messagesReceived); + } +} |