diff options
Diffstat (limited to 'RC9/qpid/java/management/client')
113 files changed, 13638 insertions, 0 deletions
diff --git a/RC9/qpid/java/management/client/README.txt b/RC9/qpid/java/management/client/README.txt new file mode 100644 index 0000000000..0c2a702a46 --- /dev/null +++ b/RC9/qpid/java/management/client/README.txt @@ -0,0 +1,117 @@ +1)DESCRIPTION
+Q-Man is a Management bridge that exposes one (or several) Qpid broker domain model as MBeans that are accessible through the Java Management Extensions (JMX).
+The following README content could be read also in http://cwiki.apache.org/confluence/display/qpid/Qman+Tool
+
+2)HOW TO RUN Q-Man
+
+2.1)PREREQUISITES
+QMan is a standalone application that is packaged as qpid-management-client-<version>.jar. To run QMan you need to add the following jars in your CLASSPATH:
+
+log4j-1.2.12.jar
+slf4j-api-1.4.0.jar
+slf4j-log4j12-1.4.0.jar
+commons-pool-1.4.jar
+commons-codec-1.3.jar
+commons-lang-2.2.jar
+commons-collections-3.2.jar
+commons-configuration-1.2.jar
+qpid-client-<version>.jar (were <version> is the current qpid version)
+qpid-common-<version>.jar (were <version> is the current qpid version)
+
+alternatively you can run the following script (that add all the qpid jars to the CLASSPATH):
+
+> CLASSPATH=`find <lib-root> -name '*.jar' | tr '\n' ":"`
+
+Where <lib-root> is the directory containing the qpid jars (when qpid is built from source <lib-root> is equal to qpid/java/build/lib)
+
+You should have in your classpath a log4j.xml configuration file too with a category defined as this :
+
+<category name="org.apache.qpid.management">
+<priority value="INFO"/>
+</category>
+
+2.2) CONFIGURATION
+QMan can be connected at run time against any broker. However if you wish to automatically connect to one or several brokers you can do so by providing a configuration file as follows:
+
+<configuration>
+ <brokers>
+ <broker>
+ <host>localhost</host>
+ <port>5672</port>
+ <virtual-host>test</virtual-host>
+ <user>guest</user>
+ <password>guest</password>
+ <max-pool-capacity>4</max-pool-capacity>
+ <initial-pool-capacity>0</initial-pool-capacity>
+ <max-wait-timeout>-1</max-wait-timeout>
+ </broker>
+ <broker>
+ <host>myhost</host>
+ <port>5672</port>
+ <virtual-host>test</virtual-host>
+ <user>guest</user>
+ <password>guest</password>
+ <max-pool-capacity>4</max-pool-capacity>
+ <initial-pool-capacity>0</initial-pool-capacity>
+ <max-wait-timeout>-1</max-wait-timeout>
+ </broker>
+ </brokers>
+</configuration>
+The configuration above specifies that QMan should connect to two brokers, one on localhos and one on myhost, both listening on port 5672.
+
+The configuration file to use is specified through the JVM parameter "qman-config" that must point onto a valid configuration file.
+
+2.3)RUNNING Q-Man
+
+To run QMan in a console run the following command:
+
+> java -Dcom.sun.management.jmxremote org.apache.qpid.management.domain.services.QMan
+
+Messages similar to those should be displayed:
+
+... [org.apache.qpid.management.domain.services.QMan] <QMAN-000001> : Starting Q-Man...
+...
+Type "q" to quit.
+
+if you wish to use a configuration file <home>/myconfiguration.xml so QMan establishes a connection with one or several brokers, run the following command:
+
+java -Dqman-config="<home>/myconfiguration.xml" org.apache.qpid.management.domain.services.QMan
+
+
+2.4) STOPPING Q-Man
+Type "q" In the console from which QMan has been started.
+
+3) Browsing Manageable Beans using JConsole
+The jconsole tool (JMX-compliant graphical tool for monitoring a Java virtual machine) can be used for monitoring and QMan Mbeans. for more information see http://java.sun.com/javase/6/docs/technotes/guides/management/jconsole.html
+
+The jconsole executable can be found in JDK_HOME/bin, where JDK_HOME is the directory in which the JDK software is installed. If this directory is in your system path, you can start JConsole by simply typing jconsole in a console. Otherwise, you have to type the full path to the executable file.
+
+As jconsole needs to perform operations invocation you will need to add the QMan jar in jconsole classpath. In a console type:
+
+jconsole -J-Djava.class.path=$CLASSPATH:$JAVA_HOME/lib/jconsole.jar:$JAVA_HOME/lib/tools.jar
+Where CLASSPATH contains the QMan jars and JAVA_HOME point on your JDK home.
+
+NOte that in order to see QMan JVM on JConsole you need to add the following command line option to QMan launcher : -Dcom.sun.management.jmxremote
+
+4) Deploying Q-Man on JBoss
+QMan comes with a servlet that can be deployed in any application server. In the following we show how to deploy the qman servlet within JBoss application server.
+
+4.1) PREREQUISITES
+You mus install JBoss:
+
+- Download the latest stable version from: http://www.jboss.org/jbossas/downloads/
+- Unzip the download archive in <jboss-home>
+
+4.2) Deploying
+First you need to copy the provided qman.war in <jboss-home>/server/default/deploy/ (note that you can use another server configuration like for example minimal)
+
+Then run JBoss:
+
+Add the following option-Djboss.platform.mbeanserver to JAVA_OPTS (for example: export JAVA_OPTS=-Djboss.platform.mbeanserver)
+Execute <jboss-home>/binrun.sh (or run.bat on a windows platform)
+Notes:
+
+If you wish to configure QMan via a configuration file so QMan establishes a connection with one or several broker at starting time then add the options -Dqman-config=myconfigFile.xml to JAVA_OPTS.
+When Qpid is built form source, the war archive qman.war is located in qpid/java/build/management/client/servlet
+
+Enjoy!
diff --git a/RC9/qpid/java/management/client/bin/qman b/RC9/qpid/java/management/client/bin/qman new file mode 100755 index 0000000000..7352bb0388 --- /dev/null +++ b/RC9/qpid/java/management/client/bin/qman @@ -0,0 +1,31 @@ +#!/bin/sh + +# 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. +# + +if [ "$QPID_LIB_PATH" = "" ] ; then + QPID_LIB_PATH=/usr/share/java +fi + +if [ "$QPID_CONFIG_PATH" = "" ] ; then + QPID_CONFIG_PATH=/etc +fi + +QMAN_CLASSPATH=`find $QPID_LIB_PATH | tr '\n' ":"` + +java -cp $QMAN_CLASSPATH -Dcom.sun.management.jmxremote -Dlog4j.configuration=qman.log4j -Dqman-config=$QPID_CONFIG_PATH/qman-config.xml org.apache.qpid.management.domain.services.QMan diff --git a/RC9/qpid/java/management/client/build.xml b/RC9/qpid/java/management/client/build.xml new file mode 100644 index 0000000000..bf32233214 --- /dev/null +++ b/RC9/qpid/java/management/client/build.xml @@ -0,0 +1,66 @@ +<!-- + - + - Licensed to the Apache Software Foundation (ASF) under one + - or more contributor license agreements. See the NOTICE file + - distributed with this work for additional information + - regarding copyright ownership. The ASF licenses this file + - to you under the Apache License, Version 2.0 (the + - "License"); you may not use this file except in compliance + - with the License. You may obtain a copy of the License at + - + - http://www.apache.org/licenses/LICENSE-2.0 + - + - Unless required by applicable law or agreed to in writing, + - software distributed under the License is distributed on an + - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + - KIND, either express or implied. See the License for the + - specific language governing permissions and limitations + - under the License. + - + --> +<project name="Qpid Management Client" default="build"> + + <property name="module.depends" value="client common"/> + + <import file="../../module.xml"/> + + + <property name="servlet.war" value="qman.war"/> + <property name="servlet.root" value="${module.build}/servlet"/> + <property name="servlet.web-inf" value="${servlet.root}/WEB-INF"/> + <property name="servlet.classes" value="${servlet.web-inf}/classes"/> + + + <target name="servlet-prepare"> + <mkdir dir="${servlet.root}"/> + <mkdir dir="${servlet.web-inf}"/> + <mkdir dir="${servlet.classes}"/> + <copy file="./web.xml" todir="${servlet.web-inf}" verbose="false"/> + <copy todir="${servlet.classes}" verbose="false"> + <fileset dir="${module.classes}"> + <include name="org/apache/qpid/management/servlet/*"/> + </fileset> + </copy> + <copy todir="${servlet.web-inf}"> + <fileset dir="${build}" includes="${module.libs}"/> + </copy> + <copy todir="${servlet.web-inf}/lib"> + <fileset dir="${build}/lib"> + <include name="qpid-client-*.jar"/> + <include name="qpid-common-*.jar"/> + <include name="qpid-management-client-*.jar"/> + </fileset> + </copy> + </target> + + <target name="servlet-clean"> + <delete dir="${servlet.root}"/> + </target> + + <target name="servlet"> + <jar destfile="${servlet.root}/${servlet.war}" basedir="${servlet.root}"/> + </target> + + <target name="postbuild" depends="servlet-clean,servlet-prepare,servlet" description="run after a build"/> + +</project> diff --git a/RC9/qpid/java/management/client/doc/man/qman b/RC9/qpid/java/management/client/doc/man/qman new file mode 100644 index 0000000000..cf4f90845c --- /dev/null +++ b/RC9/qpid/java/management/client/doc/man/qman @@ -0,0 +1,17 @@ +.TH qman +.SH NAME +qman is a Management bridge that exposes one (or several) Qpid broker domain model as MBeans that are accessible through the Java Management Extensions (JMX). Once you run qman you need to start a JMX Console such as JConsole to browse the MBeans exposed by Q-Man. +.SH SYNOPSIS +qman +.SH DESCRIPTION +For more information on customizing QMan for your own environment please read http://cwiki.apache.org/confluence/display/qpid/Qman+Tool +.SH Configuration +.SS Classpath +By default qman jars will be loaded from /usr/share/java. If you want to load from an alternative location you could specify it using QPID_LIB_PATH var. +.SS Config file +qman can be configured to connect to one or more brokers at startup by adding brokers in +.I /etc/qman-config.xml +If you want to load qman with qma-config.xml from a different location, you can specify it using QPID_CONFIG_PATH var. +.SS log4j configuration +qman expects qman.log4j file to be in the classpath. By default it will be put in +.I /usr/share/java diff --git a/RC9/qpid/java/management/client/etc/qman-config.xml b/RC9/qpid/java/management/client/etc/qman-config.xml new file mode 100644 index 0000000000..68ca3c6edf --- /dev/null +++ b/RC9/qpid/java/management/client/etc/qman-config.xml @@ -0,0 +1,47 @@ +<!-- + - + - Licensed to the Apache Software Foundation (ASF) under one + - or more contributor license agreements. See the NOTICE file + - distributed with this work for additional information + - regarding copyright ownership. The ASF licenses this file + - to you under the Apache License, Version 2.0 (the + - "License"); you may not use this file except in compliance + - with the License. You may obtain a copy of the License at + - + - http://www.apache.org/licenses/LICENSE-2.0 + - + - Unless required by applicable law or agreed to in writing, + - software distributed under the License is distributed on an + - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + - KIND, either express or implied. See the License for the + - specific language governing permissions and limitations + - under the License. + - + --> + +<configuration> + <brokers> + <broker> + <host>localhost</host> + <port>5672</port> + <virtual-host>test</virtual-host> + <user>guest</user> + <password>guest</password> + <max-pool-capacity>4</max-pool-capacity> + <initial-pool-capacity>0</initial-pool-capacity> + <max-wait-timeout>-1</max-wait-timeout> + </broker> +<!-- + <broker> + <host>myhost</host> + <port>5672</port> + <virtual-host>test</virtual-host> + <user>guest</user> + <password>guest</password> + <max-pool-capacity>4</max-pool-capacity> + <initial-pool-capacity>0</initial-pool-capacity> + <max-wait-timeout>-1</max-wait-timeout> + </broker> +--> + </brokers> +</configuration> diff --git a/RC9/qpid/java/management/client/etc/qman.log4j b/RC9/qpid/java/management/client/etc/qman.log4j new file mode 100644 index 0000000000..c2d0b050bb --- /dev/null +++ b/RC9/qpid/java/management/client/etc/qman.log4j @@ -0,0 +1,30 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +log4j.rootLogger=${root.logging.level} + +log4j.logger.org.apache.qpid=ERROR, console +log4j.additivity.org.apache.qpid=false + +log4j.logger.org.apache.qpid.management.client=DEBUG, console + +log4j.appender.console=org.apache.log4j.ConsoleAppender +log4j.appender.console.Threshold=error +log4j.appender.console.layout=org.apache.log4j.PatternLayout +log4j.appender.console.layout.ConversionPattern=%t %d %p [%c{4}] %m%n + diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/Messages.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/Messages.java new file mode 100644 index 0000000000..579b00c2db --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/Messages.java @@ -0,0 +1,119 @@ +/*
+*
+ * 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;
+
+/**
+ * Enumerative interfaces containing all QMan messages.
+ *
+ * @author Andrea Gazzarini
+ */
+public interface Messages
+{
+ // INFO
+ String QMAN_000001_STARTING_QMAN = "<QMAN-000001> : Starting Q-Man...";
+ String QMAN_000002_READING_CONFIGURATION = "<QMAN-000002> : Reading Q-Man configuration...";
+ String QMAN_000003_CREATING_MANAGEMENT_CLIENTS = "<QMAN-000003> : Creating management client(s)...";
+ String QMAN_000004_MANAGEMENT_CLIENT_CONNECTED = "<QMAN-000004> : Management client for broker %s successfully connected.";
+ String QMAN_000005_TYPE_MAPPING_CONFIGURED = "<QMAN-000005> : Type mapping : code = %s associated to %s (validator class is %s)";
+ String QMAN_000006_ACCESS_MODE_MAPPING_CONFIGURED = "<QMAN-000006> : Access Mode mapping : code = %s associated to %s";
+ String QMAN_000007_MANAGEMENT_HANDLER_MAPPING_CONFIGURED = "<QMAN-000007> : Management Queue Message Handler Mapping : opcode = %s associated with %s";
+ String QMAN_000008_METHOD_REPLY_HANDLER_MAPPING_CONFIGURED = "<QMAN-000008> : Method-Reply Queue Message Handler Mapping : opcode = %s associated with %s";
+ String QMAN_000009_BROKER_DATA_CONFIGURED = "<QMAN-000009> : Broker configuration %s: %s";
+ String QMAN_000010_INCOMING_SCHEMA = "<QMAN-000010> : Incoming schema for %s::%s.%s";
+ String QMAN_000011_SHUTDOWN_INITIATED = "<QMAN-000011> : The shutdown sequence has been initiated for management client connected with broker %s";
+ String QMAN_000012_MANAGEMENT_CLIENT_SHUT_DOWN = "<QMAN-000012> : Management client connected with broker %s shut down successfully.";
+ String QMAN_000013_METHOD_REPLY_CONSUMER_INSTALLED = "<QMAN-000013> : Method-reply queue consumer has been successfully installed and bound on broker %s.";
+ String QMAN_000014_MANAGEMENT_CONSUMER_INSTALLED ="<QMAN-000014> : Management queue consumer has been successfully installed and bound on broker %s.";
+ String QMAN_000015_MANAGEMENT_QUEUE_DECLARED = "<QMAN-000015> : Management queue with name %s has been successfully declared and bound on broker %s.";
+ String QMAN_000016_METHOD_REPLY_QUEUE_DECLARED = "<QMAN-000016> : Method-reply queue with name %s has been successfully declared and bound on broker %s.";
+ String QMAN_000017_CONSUMER_HAS_BEEN_REMOVED = "<QMAN-000017> : Consumer %s has been removed from broker %s.";
+ String QMAN_000018_QUEUE_UNDECLARED = "<QMAN-000018> : Queue %s has been removed from broker %s.";
+ String QMAN_000019_QMAN_STARTED = "<QMAN-000019> : Q-Man open for e-business.";
+ String QMAN_000020_SHUTTING_DOWN_QMAN = "<QMAN-000020> : Shutting down Q-Man...";
+ String QMAN_000021_SHUT_DOWN = "<QMAN-000021> : Q-Man shut down.";
+ String QMAN_000022_NO_BROKER_CONFIGURED = "<QMAN-000022> : Q-Man has no configured broker : in order to connect with a running one use Q-Man Administration interface.";
+ String QMAN_000023_QMAN_REGISTERED_AS_MBEAN = "<QMAN-000023> : Q-Man service is now available on MBeanServer.";
+
+ // DEBUG
+ String QMAN_200001_INCOMING_MESSAGE_HAS_BEEN_RECEIVED = "<QMAN-200001> : New incoming message has been received. Message content is %s";
+ String QMAN_200002_OPCODE_HANDLER_ASSOCIATION = "<QMAN-200002> : \"%s\" opcode is associated to handler %s";
+ String QMAN_200003_MESSAGE_FORWARDING = "<QMAN-200003> : Incoming message with \"%s\" as opcode will be forwarded to %s for processing.";
+ String QMAN_200004_MANAGEMENT_QUEUE_NAME = "<QMAN-200004> : Management queue name : %s";
+ String QMAN_200005_METHOD_REPLY_QUEUE_NAME = "<QMAN-200005> : Method-reply queue name : %s";
+ String QMAN_200006_QPID_CONNECTION_RELEASED = "<QMAN-200006> : Connection %s returned to the pool.";
+ String QMAN_200007_TEST_CONNECTION_ON_RESERVE = "<QMAN-200007> : Test connection on reserve. Is valid? %s";
+ String QMAN_200008_CONNECTION_DESTROYED = "<QMAN-200008> : Connection has been destroyed.";
+ String QMAN_200009_CONNECTION_DESTROY_FAILURE = "<QMAN-200009> : Unable to destroy a connection object.";
+ String QMAN_200010_EVENT_MBEAN_REGISTERED = "<QMAN-200010> : Event instance %s::%s::%s successfully registered with MBean Server with name %s";
+ String QMAN_200011_OBJECT_MBEAN_REGISTERED = "<QMAN-200011> : Object instance %s::%s::%s:%s successfully registered with MBean Server with name %s";
+ String QMAN_200012_OBJECT_MBEAN_UNREGISTERED = "<QMAN-200012> : Object instance %s::%s::%s:%s successfully unregistered from MBean Server. Name was %s";
+ String QMAN_200013_ARGUMENT_VALUE_ENCODED = "<QMAN-200013> : Encoded value %S for argument %s. Type is %s";
+ String QMAN_200014_INCOMING_INSTRUMENTATION_DATA = "<QMAN-200014> : Incoming instrumentation data for %s::%s.%s.%s";
+ String QMAN_200015_INCOMING_CONFIGURATION_DATA = "<QMAN-200015> : Incoming configuration data for %s::%s.%s.%s";
+ String QMAN_200016_PROPERTY_DEFINITION_HAS_BEEN_BUILT = "<QMAN-200016> : Property definition for %s::%s.%s has been built.";
+ String QMAN_200017_STATISTIC_DEFINITION_HAS_BEEN_BUILT = "<QMAN-200017> : Statistic definition for %s::%s.%s has been built.";
+ String QMAN_200018_OPTIONAL_PROPERTIES_INFO = "<QMAN-200018> : Class %s::%s.%s has %s optional properties.";
+ String QMAN_200019_EVENT_ARGUMENT_DEFINITION_HAS_BEEN_BUILT = "<QMAN-200019> : Event argument definition for %s::%s.%s has been built.";
+ String QMAN_200020_ENTITY_DEFINITION_HAS_BEEN_BUILT = "<QMAN-200020> : Entity definition has been built (without schema) for %s::%s.%s";
+ String QMAN_200021_INCOMING_EVENT_DATA = "<QMAN-200021> : Incoming data for event %s::%s.%s";
+ String QMAN_200022_VALIDATOR_INSTALLED = "<QMAN-200022> : Validator %s for type %s successfully installed.";
+ String QMAN_200023_VALIDATOR_NOT_FOUND = "<QMAN-200023> : No validator was found for type %s. The default (empty) validator will be used.";
+ String QMAN_200024_MANAGEMENT_MESSAGE_HAS_BEEN_SENT = "<QMAN-200024> : Message has been sent to management exchange. Message content : %s";
+ String QMAN_200025_SUBSCRIPTION_DECLARED = "<QMAN-200025> : New subscription between queue %s and destination %s has been declared.";
+ String QMAN_200026_SUBSCRIPTION_REMOVED = "<QMAN-200026> : Subscription named %s has been removed from remote broker.";
+ String QMAN_200027_QUEUE_DECLARED = "<QMAN-200027> : New queue with name %s has been declared.";
+ String QMAN_200028_QUEUE_REMOVED= "<QMAN-200028> : New queue with name %s has been undeclared.";
+ String QMAN_200029_BINDING_DECLARED = "<QMAN-200029> : New binding with %s as routing key has been declared between queue %s and exchange %s.";
+ String QMAN_200030_BINDING_REMOVED = "<QMAN-200030> : Binding with %s as routing key has been removed between queue %s and exchange %s.";
+ String QMAN_200031_COMPOUND_MESSAGE_CONTAINS = "<QMAN-200031> : Incoming compound message contains %s message(s).";
+ String QMAN_200032_COMMAND_MESSAGE_ROUTING_KEY = "<QMAN-200032> : Command message routing key : %s";
+
+ // WARNING
+ String QMAN_300001_MESSAGE_DISCARDED = "<QMAN-300001> : No handler has been configured for processing messages with \"%s\" as opcode. Message will be discarded.";
+ String QMAN_300002_UNKNOWN_SEQUENCE_NUMBER = "<QMAN-300002> : Unable to deal with incoming message because it contains a unknown sequence number (%s).";
+ String QMAN_300003_BROKER_ALREADY_CONNECTED = "<QMAN-300003> : Unable to enlist given broker connection data : QMan is already connected with broker %s";
+ String QMAN_300004_INVALID_CONFIGURATION_FILE = "<QMAN-300004> : The given configuration file (%s) is not valid (it doesn't exist or cannot be read)";
+
+ // ERROR
+ String QMAN_100001_BAD_MAGIC_NUMBER_FAILURE = "<QMAN-100001> : Message processing failure : incoming message contains a bad magic number (%s) and therefore will be discaded.";
+ String QMAN_100002_MESSAGE_READ_FAILURE = "<QMAN-100002> : Message I/O failure : unable to read byte message content and therefore it will be discarded.";
+ String QMAN_100003_MESSAGE_PROCESS_FAILURE = "<QMAN-100003> : Message processing failure : unknown exception; see logs for more details.";
+ String QMAN_100004_HANDLER_INITIALIZATION_FAILURE = "<QMAN-100004> : Message handler configured for opcode %s thrown an exception in initialization and therefore will be discarded.";
+ String QMAN_100005_CLASS_SCHEMA_PROCESSING_FAILURE = "<QMAN-100005> : Q-Man was unable to process the schema response message.";
+ String QMAN_100006_EVENT_SCHEMA_PROCESSING_FAILURE = "<QMAN-100006> : Q-Man was unable to process the schema response message.";
+ String QMAN_100007_UNABLE_TO_CONNECT_WITH_BROKER = "<QMAN-100007> : Unable to connect with broker located on %s. This broker will be ignored.";
+ String QMAN_100008_MANAGEMENT_MESSAGE_HANDLER_NOT_AVAILABLE = "<QMAN-100008> : Management Message Handler configured for opcode %s is not available and therefore will be discarded.";
+ String QMAN_100009_METHOD_REPLY_MESSAGE_HANDLER_NOT_AVAILABLE = "<QMAN-100009> :Method-Reply Message Handler configured for opcode %s is not available and therefore will be discarded.";
+ String QMAN_100010_METHOD_INVOCATION_RESULT_FAILURE = "<QMAN-100010> : an exception occurred while storing the result of a method invocation. Sequence number was %s";
+ String QMAN_100011_UNKNOWN_CLASS_KIND = "<QMAN-100011> : Unknwon class kind : %s).";
+ String QMAN_100012_SCHEMA_MESSAGE_PROCESSING_FAILURE = "<QMAN-100012> : Q-Man was unable to process the schema response message.";
+ String QMAN_100013_MBEAN_REGISTRATION_FAILURE = "<QMAN-100013> : Unable to unregister object instance %s.";
+ String QMAN_100014_ATTRIBUTE_DECODING_FAILURE = "<QMAN-100014> : Unable to decode value for attribute %s";
+ String QMAN_100015_UNABLE_TO_SEND_SCHEMA_REQUEST = "<QMAN-100015> : Unable to send a schema request schema for %s.%s";
+ String QMAN_100016_UNABLE_TO_DECODE_FEATURE_VALUE = "<QMAN-100016> : Unable to decode value for %s::%s::%s";
+ String QMAN_100017_UNABLE_TO_CONNECT = "<QMAN-100017>: Cannot connect to broker %s on %s";
+ String QMAN_100018_UNABLE_TO_STARTUP_CORRECTLY = "<QMAN-100018> : Q-Man was unable to startup correctly : see logs for further details.";
+
+ // MESSAGES
+ String EVENT_SEVERITY_ATTRIBUTE_DESCRIPTION = "Severity level for this event.";
+ String EVENT_TIMESTAMP_ATTRIBUTE_DESCRIPTION = "Current timestamp of this event.";
+}
diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/Names.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/Names.java new file mode 100644 index 0000000000..7ed0f8b24d --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/Names.java @@ -0,0 +1,57 @@ +/* + * + * 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; + +/** + * Enumeration of literal strings to avoid code duplication. + * + * @author Andrea Gazzarini + */ +public interface Names +{ + /** Name of the qpid management exchange. */ + String MANAGEMENT_EXCHANGE = "qpid.management"; + String MANAGEMENT_ROUTING_KEY = "console.#"; + + String MANAGEMENT_QUEUE_PREFIX = "management."; + String METHOD_REPLY_QUEUE_PREFIX = "reply."; + + String AMQ_DIRECT_QUEUE = "amq.direct"; + String AGENT_ROUTING_KEY_PREFIX = "agent."; + String AGENT_ROUTING_KEY = AGENT_ROUTING_KEY_PREFIX+"1.0"; + + // Attributes + String PACKAGE = "package"; + String CLASS = "class"; + String OBJECT_ID="objectID"; + String BROKER_ID = "brokerID"; + String DOMAIN_NAME = "Q-MAN"; + + String ARG_COUNT_PARAM_NAME = "argCount"; + String DEFAULT_PARAM_NAME ="default"; + + String NUMBER_VALIDATOR = "org.apache.qpid.management.domain.model.QpidProperty$NumberValidator"; + String STRING_VALIDATOR = "org.apache.qpid.management.domain.model.QpidProperty$StringValidator"; + + String QMAN_CONFIG_OPTION_NAME = "qman-config"; + + String ADD_BROKER_OPERATION_NAME = "addBroker"; +} diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/Protocol.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/Protocol.java new file mode 100644 index 0000000000..5b41785b11 --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/Protocol.java @@ -0,0 +1,47 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.management; + +/** + * Protocol defined constants. + * + * @author Andrea Gazzarini + */ +public interface Protocol +{ + String MAGIC_NUMBER = "AM2"; + + char SCHEMA_REQUEST_OPCODE = 'S'; + char SCHEMA_RESPONSE_OPCODE = Character.toLowerCase(SCHEMA_REQUEST_OPCODE); + + char OPERATION_INVOCATION_REQUEST_OPCODE = 'M'; + char OPERATION_INVOCATION_RESPONSE_OPCODE = Character.toLowerCase(OPERATION_INVOCATION_REQUEST_OPCODE); + + char INSTRUMENTATION_CONTENT_RESPONSE_OPCODE = 'i'; + char CONFIGURATION_CONTENT_RESPONSE_OPCDE = 'c'; + char EVENT_CONTENT_RESPONSE_OPCDE = 'e'; + char INSTR_AND_CONFIG_CONTENT_RESPONSE_OPCODE = 'g'; + + char HEARTBEAT_INDICATION_RESPONSE_OPCODE = 'h'; + + int CLASS = 1; + int EVENT = 2; +} diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/configuration/AccessModeMapping.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/configuration/AccessModeMapping.java new file mode 100644 index 0000000000..af6aaa36bf --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/configuration/AccessModeMapping.java @@ -0,0 +1,83 @@ +/* + * + * 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.configuration; + +import org.apache.qpid.management.domain.model.AccessMode; + +/** + * Class used to encapsulate a mapping between an access mode and a code. + * + * @author Andrea Gazzarini + */ +class AccessModeMapping +{ + private final int _code; + private final AccessMode _accessMode; + + /** + * Builds a new access mode mapping with the given parameters. + * + * @param code the access code. + * @param accessMode the access mode. + */ + AccessModeMapping(int code, AccessMode accessMode) + { + this._code = code; + this._accessMode = accessMode; + } + + /** + * Returns the access mode of this mapping. + * + * @return the access mode of this mapping. + */ + AccessMode getAccessMode () + { + return _accessMode; + } + + /** + * Returns the code of this mapping. + * + * @return the code of this mapping. + */ + int getCode () + { + return _code; + } + + /** + * Returns a string representation of this mapping. + * The returned string is indicating the code and the corresponding access mode. + * + * @return a string representation of this mapping. + */ + @Override + public String toString () + { + return new StringBuilder() + .append("AccessMode mapping (") + .append(_code) + .append(',') + .append(_accessMode) + .append(')').toString(); + } +} diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/configuration/BrokerAlreadyConnectedException.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/configuration/BrokerAlreadyConnectedException.java new file mode 100644 index 0000000000..f23bf9d25e --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/configuration/BrokerAlreadyConnectedException.java @@ -0,0 +1,53 @@ +/*
+*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.management.configuration;
+
+/**
+ * Thrown when an attempt is made in order to connect QMan with an already connected broker.
+ *
+ * @author Andrea Gazzarini
+ */
+public class BrokerAlreadyConnectedException extends Exception {
+
+ private static final long serialVersionUID = -5082431738056504669L;
+
+ private BrokerConnectionData _connectionData;
+
+ /**
+ * Builds a new exception with the given data.
+ *
+ * @param connectionData the broker connection data.
+ */
+ public BrokerAlreadyConnectedException(BrokerConnectionData connectionData) {
+ this._connectionData = connectionData;
+ }
+
+ /**
+ * Returns the connection data of the connected broker.
+ *
+ * @return the connection data of the connected broker.
+ */
+ public BrokerConnectionData getBrokerConnectionData()
+ {
+ return _connectionData;
+ }
+}
diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/configuration/BrokerConnectionData.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/configuration/BrokerConnectionData.java new file mode 100644 index 0000000000..be04c67555 --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/configuration/BrokerConnectionData.java @@ -0,0 +1,270 @@ +/* + * + * 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.configuration; + +/** + * Value object which is holding connection data for a specific broker. + * + * @author Andrea Gazzarini + */ +public class BrokerConnectionData +{ + private String _host; + private int _port; + private String _virtualHost; + private String _username; + private String _password; + private int _maxPoolCapacity; + private int _initialPoolCapacity; + private long _maxWaitTimeout; + + /** + * Builds a connection data with the given parameters. + * + * @param host the hostname where the broker is running. + * @param port the port where the broker is running. + * @param username the username for connecting with the broker. + * @param password the password for connecting with the broker. + * @param virtualHost the virtual host. + * @param initialPoolCapacity the number of the connection that must be immediately opened. + * @param maxPoolCapacity the maximum number of opened connection. + * @param maxWaitTimeout the maximum amount of time that a client will wait for obtaining a connection. + */ + public BrokerConnectionData( + String host, + int port, + String virtualHost, + String username, + String password, + int initialPoolCapacity, + int maxPoolCapacity, + long waitTimeout) { + + this._host = host; + this._port = port; + this._virtualHost = virtualHost; + this._username = username; + this._password = password; + _maxPoolCapacity = maxPoolCapacity; + _initialPoolCapacity = initialPoolCapacity; + _maxWaitTimeout = waitTimeout; + } + + /** + * Builds a new empty broker connection data object. + */ + BrokerConnectionData() + { + } + + /** + * Sets the value of host property for this connection data. + * + * @param host the host name. + */ + void setHost (String host) + { + this._host = host; + } + + /** + * Sets the value of port property for this connection data. + * + * @param port the port. + */ + void setPort (String port) + { + this._port = Integer.parseInt(port); + } + + /** + * Sets the value of virtual host property for this connection data. + * + * @param virtualHost the virtual host. + */ + void setVirtualHost (String virtualHost) + { + this._virtualHost = virtualHost; + } + + /** + * Sets the value of username property for this connection data. + * + * @param username the username. + */ + void setUsername(String username) + { + this._username = username; + } + + /** + * Sets the value of password property for this connection data. + * + * @param password the password. + */ + void setPassword(String password) + { + this._password = password; + } + + /** + * Returns the value of the host property. + * + * @return the value of the host property. + */ + public String getHost () + { + return _host; + } + + /** + * Returns the value of the port property. + * + * @return the value of the port property. + */ + public int getPort () + { + return _port; + } + + /** + * Returns the value of the virtual host property. + * + * @return the value of the virtual host property. + */ + public String getVirtualHost () + { + return _virtualHost; + } + + /** + * Returns the value of the username property. + * + * @return the value of the username property. + */ + public String getUsername () + { + return _username; + } + + /** + * Returns the value of the password property. + * + * @return the value of the password property. + */ + public String getPassword () + { + return _password; + } + + // sofia:5663@pippo/sung1 + @Override + public String toString () + { + return new StringBuilder() + .append(_host) + .append(':') + .append(_port) + .append('@') + .append(_virtualHost) + .toString(); + } + + /** + * Sets the max number of allowed connections that can be opened. + * + * @param value the max number of allowed connections that can be opened. + * @throws NumberFormatException if the given value is not a valid integer. + */ + public void setMaxPoolCapacity (String value) + { + _maxPoolCapacity = Integer.parseInt(value); + } + + /** + * Sets the max wait timeout for retrieving an available connections from the pool. + * + * @param value the max wait timeout for retrieving an available connections from the pool.. + * @throws NumberFormatException if the given value is not a valid long. + */ + public void setMaxWaitTimeout (String value) + { + this._maxWaitTimeout = Long.parseLong(value); + } + + /** + * Returns the max number of allowed connections that can be opened. + * + * @return the max number of allowed connections that can be opened. + */ + public int getMaxPoolCapacity () + { + return _maxPoolCapacity; + } + + /** + * Returns the max wait timeout for retrieving an available connections from the pool. + * + * @return the max wait timeout for retrieving an available connections from the pool. + */ + public long getMaxWaitTimeout () + { + return _maxWaitTimeout; + } + + /** + * Sets the initial connection pool capacity. + * + * @param capacity the initial connection pool capacity. + */ + public void setInitialPoolCapacity (String capacity) + { + _initialPoolCapacity = Integer.parseInt(capacity); + } + + /** + * Returns the initial connection pool capacity. + * + * @return the initial connection pool capacity. + */ + public int getInitialPoolCapacity () + { + return _initialPoolCapacity; + } + + @Override + public boolean equals(Object object) { + try + { + BrokerConnectionData connectionData = (BrokerConnectionData) object; + return (_host.equals(connectionData._host) ) + && (_port == connectionData._port) + && (_virtualHost.equals(connectionData._virtualHost)); + } catch (Exception exception) { + return false; + } + } + + @Override + public int hashCode() { + return _host.hashCode()+_port+_virtualHost.hashCode(); + } +} diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/configuration/BrokerConnectionDataParser.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/configuration/BrokerConnectionDataParser.java new file mode 100644 index 0000000000..368970af00 --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/configuration/BrokerConnectionDataParser.java @@ -0,0 +1,137 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.management.configuration; + +import java.util.UUID; + +import org.apache.qpid.management.Messages; +import org.apache.qpid.transport.util.Logger; + +/** + * Parser used for building access mode mappings. + * For each access-mode-mappings/mapping element found in the configuration file, a new access mode mapping + * is built and injected into the bridge configuration. + * + <broker> + <host>192.168.148.131</host> + <port>5672</port> + <virtual-host>test</virtual-host> + <user>guest</user> + <password>guest</password> + <max-pool-capacity>4</max-pool-capacity> + <initial-pool-capacity>4</initial-pool-capacity> + <max-wait-timeout>-1</max-wait-timeout> + </broker> + * + * @author Andrea Gazzarini + */ +class BrokerConnectionDataParser implements IParser +{ + private final static Logger LOGGER = Logger.get(Configuration.class); + private BrokerConnectionData _connectionData = new BrokerConnectionData(); + private String _currentValue; + + /** + * Callback : the given value is the text content of the current node. + */ + public void setCurrrentAttributeValue (String value) + { + this._currentValue = value; + } + + /** + * Callback: each time the end of an element is reached this method is called. + * It's here that the built mapping is injected into the configuration. + * <broker> + <host>192.168.61.130</host> + <port>5673</port> + <virtual-host>test</virtual-host> + <user>andrea</user> + <password>andrea</password> + </broker> + */ + public void setCurrentAttributeName (String name) + { + switch (Tag.get(name)) + { + case HOST: + { + _connectionData.setHost(_currentValue); + break; + } + case PORT : + { + _connectionData.setPort(_currentValue); + break; + } + case VIRTUAL_HOST: + { + _connectionData.setVirtualHost(_currentValue); + break; + } + case USER : + { + _connectionData.setUsername(_currentValue); + break; + } + case MAX_POOL_CAPACITY: + { + _connectionData.setMaxPoolCapacity (_currentValue); + break; + } + case INITIAL_POOL_CAPACITY: + { + _connectionData.setInitialPoolCapacity(_currentValue); + break; + } + case MAX_WAIT_TIMEOUT: + { + _connectionData.setMaxWaitTimeout(_currentValue); + break; + } + case PASSWORD: + { + _connectionData.setPassword(_currentValue); + break; + } + case BROKER: + { + try + { + Configuration.getInstance().addBrokerConnectionData(getUUId(),_connectionData); + } catch(Exception exception) + { + LOGGER.error(exception, Messages.QMAN_100007_UNABLE_TO_CONNECT_WITH_BROKER, _connectionData); + } + _connectionData = new BrokerConnectionData(); + break; + } + } + } + + /** + * Gets an uuid in order to associate current connection data with a broker. + * @return + */ + UUID getUUId(){ + return UUID.randomUUID(); + } +} diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/configuration/BrokerConnectionException.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/configuration/BrokerConnectionException.java new file mode 100644 index 0000000000..9294cf740e --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/configuration/BrokerConnectionException.java @@ -0,0 +1,42 @@ +/*
+*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.management.configuration;
+
+/**
+ * Thrown when a connection to a broker cannot be estabilished.
+ *
+ * @author Andrea Gazzarini
+ */
+public class BrokerConnectionException extends Exception
+{
+ private static final long serialVersionUID = 8170112238862494025L;
+
+ /**
+ * Builds a new exception with the given cause.
+ *
+ * @param cause the exception cause.
+ */
+ BrokerConnectionException(Throwable cause)
+ {
+ super(cause);
+ }
+}
diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/configuration/Configuration.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/configuration/Configuration.java new file mode 100644 index 0000000000..12b3c6be9e --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/configuration/Configuration.java @@ -0,0 +1,383 @@ +/* + * + * 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.configuration; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.Map.Entry; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.SynchronousQueue; + +import org.apache.qpid.management.Messages; +import org.apache.qpid.management.Names; +import org.apache.qpid.management.domain.handler.base.IMessageHandler; +import org.apache.qpid.management.domain.handler.impl.InvocationResult; +import org.apache.qpid.management.domain.model.AccessMode; +import org.apache.qpid.management.domain.model.type.Type; +import org.apache.qpid.transport.DeliveryProperties; +import org.apache.qpid.transport.Header; +import org.apache.qpid.transport.MessageProperties; +import org.apache.qpid.transport.ReplyTo; +import org.apache.qpid.transport.util.Logger; + +/** + * Qpid Management bridge configuration. + * Basically iy is a singleton that is holding all the configurtion data loaded at startup. + * + * @author Andrea Gazzarini + */ +public final class Configuration +{ + private final static Logger LOGGER = Logger.get(Configuration.class); + private static Configuration INSTANCE = new Configuration(); + + Map<Integer, Type> _typeMappings = new HashMap<Integer,Type>(); + Map<Integer,AccessMode> _accessModes = new HashMap<Integer, AccessMode>(); + Map<Type,String> _validators = new HashMap<Type, String>(); + + Map<UUID,BrokerConnectionData> _brokerConnectionInfos = new HashMap<UUID, BrokerConnectionData>(); + + Map<Character, String> _managementQueueHandlers = new HashMap<Character, String>(); + Map<Character, String> _methodReplyQueueHandlers = new HashMap<Character, String>(); + + private String _managementQueueName; + private String _methodReplyQueueName; + + private Header _headerForCommandMessages; + private DeliveryProperties _deliveryProperties = new DeliveryProperties(); + private MessageProperties _messageProperties = new MessageProperties(); + public BlockingQueue<InvocationResult> _resultExchangeChannel = new SynchronousQueue<InvocationResult>(); + + // Private constructor. + private Configuration() + { + defineQueueNames(); + createHeaderForCommandMessages(); + } + + /** + * Returns the singleton instance. + * + * @return the singleton instance. + */ + public static Configuration getInstance () + { + return INSTANCE; + } + + /** + * Returns true if this configuration has at least one broker connection data. + * + * @return true if this configuration has at least one broker connection data. + */ + public boolean hasOneOrMoreBrokersDefined() + { + return !_brokerConnectionInfos.isEmpty(); + } + + /** + * Returns the type associated to the given code. + * + * @param code the code used as search criteria. + * @return the type associated to the given code. + * @throws UnknownTypeCodeException when the given code is not associated to any type. + */ + public Type getType(int code) throws UnknownTypeCodeException + { + Type result = _typeMappings.get(code); + if (result == null) + { + throw new UnknownTypeCodeException(code); + } + return result; + } + + /** + * Returns the access mode associated to the given code. + * + * @param code the code used as search criteria. + * @return the access mode associated to the given code. + * @throws UnknownAccessCodeException when the given code is not associated to any access mode. + */ + public AccessMode getAccessMode(int code) throws UnknownAccessCodeException + { + AccessMode result = _accessModes.get(code); + if (result == null) + { + throw new UnknownAccessCodeException(code); + } + return result; + } + + /** + * Returns the validator class name associated to the given type. + * + * @param type the type. + * @return the validator class name associated to the given type. + */ + public String getValidatorClassName (Type type) + { + return _validators.get(type); + } + + /** + * Gets from this configuration the list of known broker (I mean, only their connection data). + * + * @return the list of known broker + */ + public Set<Entry<UUID, BrokerConnectionData>> getConnectionInfos(){ + return _brokerConnectionInfos.entrySet(); + } + + /** + * Gets from this configuration the connection data of the broker associated with the given id. + * + * @param brokerId the broker identifier. + * @return the connection data of the broker associated with the given id. + * @throws UnknownBrokerException when the given id is not associated with any broker. + */ + public BrokerConnectionData getBrokerConnectionData (UUID brokerId) throws UnknownBrokerException + { + BrokerConnectionData connectionData = _brokerConnectionInfos.get(brokerId); + if (connectionData == null) + { + throw new UnknownBrokerException(brokerId); + } + return _brokerConnectionInfos.get(brokerId); + } + + /** + * Returns the name of the management queue. + * + * @return the name of the management queue. + */ + public String getManagementQueueName() { + return _managementQueueName; + } + + /** + * Returns the name of the method-reply queue. + * + * @return the name of the method-reply queue. + */ + public String getMethodReplyQueueName() { + return _methodReplyQueueName; + } + + /** + * Returns a map containing all the configured management message handlers. + * A management message handler it is a basically a processor for a management queue incoming message associated + * with a specific opcode. + * + * @return a map containing all the configured management message handlers. + */ + public Map<Character, IMessageHandler> getManagementQueueHandlers() + { + Map<Character, IMessageHandler> result = new HashMap<Character, IMessageHandler>(); + + for (Entry<Character, String> entry : _managementQueueHandlers.entrySet()) + { + Character opcode = entry.getKey(); + String className = entry.getValue(); + try + { + result.put(opcode, (IMessageHandler)Class.forName(className).newInstance()); + } catch(Exception exception) + { + LOGGER.error(exception,Messages.QMAN_100008_MANAGEMENT_MESSAGE_HANDLER_NOT_AVAILABLE,opcode); + } + } + return result; + } + + /** + * Returns a map containing all the configured method-reply message handlers. + * A management message handler it is a basically a processor for a method-reply queue incoming message associated + * with a specific opcode. + * + * @return a map containing all the configured method-reply message handlers. + */ + public Map<Character, IMessageHandler> getMethodReplyQueueHandlers() + { + Map<Character, IMessageHandler> result = new HashMap<Character, IMessageHandler>(); + + for (Entry<Character, String> entry : _methodReplyQueueHandlers.entrySet()) + { + Character opcode = entry.getKey(); + String className = entry.getValue(); + try + { + result.put(opcode, (IMessageHandler)Class.forName(className).newInstance()); + } catch(Exception exception) + { + LOGGER.error(exception,Messages.QMAN_100009_METHOD_REPLY_MESSAGE_HANDLER_NOT_AVAILABLE,opcode); + } + } + return result; + } + + /** + * Returns the message header used for sending command message on management queue. + * + * @return the message header used for sending command message on management queue. + */ + public Header getCommandMessageHeader () + { + return _headerForCommandMessages; + } + + /** + * Returns the command message properties. + * + * @return the command message properties. + */ + public MessageProperties getCommandMessageProperties () + { + return _messageProperties; + } + + /** + * Returns the command message delivery properties. + * + * @return the command message delivery properties. + */ + public DeliveryProperties getCommandDeliveryProperties () + { + return _deliveryProperties; + } + + /** + * Adds a new type mapping to this configuration. + * + * @param mapping the type mapping that will be added. + */ + void addTypeMapping(TypeMapping mapping) { + int code = mapping.getCode(); + Type type = mapping.getType(); + String validatorClassName = mapping.getValidatorClassName(); + _typeMappings.put(code, type); + _validators.put(type, validatorClassName); + + LOGGER.info(Messages.QMAN_000005_TYPE_MAPPING_CONFIGURED, code,type,validatorClassName); + } + + /** + * Adds a new access mode mapping to this configuration. + * + * @param mapping the mapping that will be added. + */ + void addAccessModeMapping(AccessModeMapping mapping){ + int code = mapping.getCode(); + AccessMode accessMode = mapping.getAccessMode(); + _accessModes.put(code, accessMode); + + LOGGER.info(Messages.QMAN_000006_ACCESS_MODE_MAPPING_CONFIGURED, code,accessMode); + } + + /** + * Adds a new management message handler to this configuration. + * The incoming mapping object will contains an opcode and the class (as a string) of the message handler that will be used + * for processing incoming messages with that opcode. + * + * @param mapping the message handler mapping. + */ + void addManagementMessageHandlerMapping (MessageHandlerMapping mapping) + { + Character opcode = mapping.getOpcode(); + String handlerClass = mapping.getMessageHandlerClass(); + _managementQueueHandlers.put(opcode, handlerClass); + + LOGGER.info(Messages.QMAN_000007_MANAGEMENT_HANDLER_MAPPING_CONFIGURED, opcode,handlerClass); + } + + /** + * Adds a new method-reply message handler to this configuration. + * The incoming mapping object will contains an opcode and the class (as a string) of the message handler that will be used + * for processing incoming messages with that opcode. + * + * @param mapping the message handler mapping. + */ + void addMethodReplyMessageHandlerMapping (MessageHandlerMapping mapping) + { + Character opcode = mapping.getOpcode(); + String handlerClass = mapping.getMessageHandlerClass(); + _methodReplyQueueHandlers.put(opcode, handlerClass); + + LOGGER.info(Messages.QMAN_000008_METHOD_REPLY_HANDLER_MAPPING_CONFIGURED, opcode,handlerClass); + } + + /** + * Adds to this configuration a new broker connection data. + * + * @param brokerId the broker identifier. + * @param connectionData the connection data. + * @throws BrokerAlreadyConnectedException when the broker is already connected. + * @throws BrokerConnectionException when a connection cannot be estabilished. + */ + void addBrokerConnectionData (UUID brokerId, BrokerConnectionData connectionData) throws BrokerAlreadyConnectedException, BrokerConnectionException + { + if (_brokerConnectionInfos.containsValue(connectionData)) + { + throw new BrokerAlreadyConnectedException(connectionData); + } + + try + { + QpidDatasource.getInstance().addConnectionPool(brokerId, connectionData); + _brokerConnectionInfos.put(brokerId,connectionData); + + LOGGER.info(Messages.QMAN_000009_BROKER_DATA_CONFIGURED,brokerId,connectionData); + } catch(Exception exception) + { + throw new BrokerConnectionException(exception); + } + + } + + /** + * Header for command messages is created once because it only contains static values. + */ + private void createHeaderForCommandMessages () + { + ReplyTo replyTo=new ReplyTo(); + replyTo.setRoutingKey(_methodReplyQueueName); + _messageProperties.setReplyTo(replyTo); + _deliveryProperties.setRoutingKey(Names.AGENT_ROUTING_KEY); + _headerForCommandMessages = new Header(_deliveryProperties, _messageProperties); + } + + /** + * Creates the name of the queues used by this service. + * This is done because if a broker should be managed by one or more management client, then each of them + * must have its own channels to communicate with. + */ + private void defineQueueNames() + { + UUID uuid = UUID.randomUUID(); + _managementQueueName = Names.MANAGEMENT_QUEUE_PREFIX+uuid; + _methodReplyQueueName = Names.METHOD_REPLY_QUEUE_PREFIX+uuid; + + LOGGER.debug(Messages.QMAN_200004_MANAGEMENT_QUEUE_NAME,_managementQueueName); + LOGGER.debug(Messages.QMAN_200005_METHOD_REPLY_QUEUE_NAME,_methodReplyQueueName); + } +} diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/configuration/ConfigurationException.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/configuration/ConfigurationException.java new file mode 100644 index 0000000000..6eed515e11 --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/configuration/ConfigurationException.java @@ -0,0 +1,51 @@ +/* + * + * 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.configuration; + +/** + * Thrown when a problem is encountered during building the configuration. + * + * @author Andrea Gazzarini + */ +public class ConfigurationException extends Exception +{ + private static final long serialVersionUID = 8238481177714286259L; + + public ConfigurationException(String msg) + { + super(msg); + } + + /** + * Builds a new ConfigurationException with the given cause. + * + * @param exception the exception cause. + */ + public ConfigurationException(Exception exception) + { + super(exception); + } + + public ConfigurationException(String msg,Exception exception) + { + super(msg,exception); + } +}
\ No newline at end of file diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/configuration/Configurator.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/configuration/Configurator.java new file mode 100644 index 0000000000..0051b19c99 --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/configuration/Configurator.java @@ -0,0 +1,287 @@ +/* + * + * 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.configuration; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStreamReader; +import java.util.UUID; + +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; + +import org.apache.qpid.management.Messages; +import org.apache.qpid.management.Names; +import org.apache.qpid.management.Protocol; +import org.apache.qpid.management.domain.handler.impl.ConfigurationMessageHandler; +import org.apache.qpid.management.domain.handler.impl.EventContentMessageHandler; +import org.apache.qpid.management.domain.handler.impl.HeartBeatIndicationMessageHandler; +import org.apache.qpid.management.domain.handler.impl.InstrumentationMessageHandler; +import org.apache.qpid.management.domain.handler.impl.MethodResponseMessageHandler; +import org.apache.qpid.management.domain.handler.impl.SchemaResponseMessageHandler; +import org.apache.qpid.management.domain.model.AccessMode; +import org.apache.qpid.management.domain.model.type.AbsTime; +import org.apache.qpid.management.domain.model.type.DeltaTime; +import org.apache.qpid.management.domain.model.type.Int16; +import org.apache.qpid.management.domain.model.type.Int32; +import org.apache.qpid.management.domain.model.type.Int64; +import org.apache.qpid.management.domain.model.type.Int8; +import org.apache.qpid.management.domain.model.type.ObjectReference; +import org.apache.qpid.management.domain.model.type.Str16; +import org.apache.qpid.management.domain.model.type.Str8; +import org.apache.qpid.management.domain.model.type.Uint16; +import org.apache.qpid.management.domain.model.type.Uint32; +import org.apache.qpid.management.domain.model.type.Uint64; +import org.apache.qpid.management.domain.model.type.Uint8; +import org.apache.qpid.transport.util.Logger; +import org.xml.sax.Attributes; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + +/** + * Director used for coordinating the build process of configuration. + * This is the only component which has a read-write permission on Configuration object. + * + * @author Andrea Gazzarini + */ +public class Configurator extends DefaultHandler +{ + private final static Logger LOGGER = Logger.get(Configurator.class); + + /** + * Default (empty) parser used when there's no need to process data (non relevant elements). + */ + final static IParser DEFAULT_PARSER = new IParser() { + + public void setCurrrentAttributeValue (String value) + { + } + + public void setCurrentAttributeName (String name) + { + } + }; + + IParser _brokerConfigurationParser = new BrokerConnectionDataParser(); + IParser _currentParser = DEFAULT_PARSER; + + /** + * Delegates the processing to the current parser. + */ + @Override + public void characters (char[] ch, int start, int length) throws SAXException + { + String value = new String(ch,start,length).trim(); + if (value.length() != 0) { + _currentParser.setCurrrentAttributeValue(value); + } + } + + /** + * Here is defined what parser needs to be used for processing the current data. + */ + @Override + public void startElement (String uri, String localName, String name, Attributes attributes) throws SAXException + { + switch(Tag.get(name)) { + case BROKERS: + { + _currentParser = _brokerConfigurationParser; + break; + } + } + } + + @Override + public void endElement (String uri, String localName, String name) throws SAXException + { + _currentParser.setCurrentAttributeName(name); + } + + /** + * Builds whole configuration. + * + * @throws ConfigurationException when the build fails. + */ + public void configure() throws ConfigurationException + { + BufferedReader reader = null; + try + { + String initialConfigFileName = System.getProperty(Names.QMAN_CONFIG_OPTION_NAME); + if (initialConfigFileName != null && initialConfigFileName.trim().length() != 0) + { + File initialConfigurationFile = new File(initialConfigFileName); + if (initialConfigurationFile.canRead()) + { + SAXParser parser = SAXParserFactory.newInstance().newSAXParser(); + reader = new BufferedReader(new InputStreamReader(new FileInputStream(initialConfigFileName))); + InputSource source = new InputSource(reader); + parser.parse(source, this); + } else { + LOGGER.warn(Messages.QMAN_300004_INVALID_CONFIGURATION_FILE, initialConfigFileName); + throw new ConfigurationException(String.format(Messages.QMAN_300004_INVALID_CONFIGURATION_FILE, initialConfigFileName)); + } + } + + addTypeMappings(); + addAccessModeMappings(); + + addMandatoryManagementMessageHandlers(); + addMandatoryMethodReplyMessageHandlers(); + } catch (Exception exception) + { + throw new ConfigurationException(exception); + } finally + { + try + { + reader.close(); + } catch (Exception ignore) + { + } + } + } + + /** + * Creates and return a value object (BrokerConnectionData) with the given parameters. + * Note that that object will be stored on configuration and it could be used to set a connection with the broker. + * This happens when the "initialPoolCapacity" is greater than 0 : in this case the caller is indicatinf that it wants to open + * one or more connections immediately at startup and therefore Q-Man will try to do that. + * + * @param host the hostname where the broker is running. + * @param port the port where the broker is running. + * @param username the username for connecting with the broker. + * @param password the password for connecting with the broker. + * @param virtualHost the virtual host. + * @param initialPoolCapacity the number of the connection that must be immediately opened. + * @param maxPoolCapacity the maximum number of opened connection. + * @param maxWaitTimeout the maximum amount of time that a client will wait for obtaining a connection. + * @return the value object containing the data above. + * @throws BrokerAlreadyConnectedException when the broker is already connected. + * @throws BrokerConnectionException when a connection cannot be estabilished. + */ + public BrokerConnectionData createAndReturnBrokerConnectionData( + UUID brokerId, + String host, + int port, + String username, + String password, + String virtualHost, + int initialPoolCapacity, + int maxPoolCapacity, + long maxWaitTimeout) throws BrokerAlreadyConnectedException, BrokerConnectionException + { + BrokerConnectionData data = new BrokerConnectionData( + host, + port, + virtualHost, + username, + password, + initialPoolCapacity, + maxPoolCapacity, + maxWaitTimeout); + Configuration.getInstance().addBrokerConnectionData(brokerId, data); + return data; + } + + /** + * Configures access mode mappings. + * An access mode mapping is an association between a code and an access mode. + */ + private void addAccessModeMappings() { + Configuration configuration = Configuration.getInstance(); + configuration.addAccessModeMapping(new AccessModeMapping(1,AccessMode.RC)); + configuration.addAccessModeMapping(new AccessModeMapping(2,AccessMode.RW)); + configuration.addAccessModeMapping(new AccessModeMapping(3,AccessMode.RO)); + } + + /** + * Configures type mappings. + * A type mapping is an association between a code and a management type. + */ + private void addTypeMappings() + { + Configuration configuration = Configuration.getInstance(); + configuration.addTypeMapping(new TypeMapping(1,new Uint8(),Names.NUMBER_VALIDATOR)); + configuration.addTypeMapping(new TypeMapping(2,new Uint16(),Names.NUMBER_VALIDATOR)); + configuration.addTypeMapping(new TypeMapping(3,new Uint32(),Names.NUMBER_VALIDATOR)); + configuration.addTypeMapping(new TypeMapping(4,new Uint64(),Names.NUMBER_VALIDATOR)); + configuration.addTypeMapping(new TypeMapping(6,new Str8(),Names.STRING_VALIDATOR)); + configuration.addTypeMapping(new TypeMapping(7,new Str16(),Names.STRING_VALIDATOR)); + configuration.addTypeMapping(new TypeMapping(8,new AbsTime())); + configuration.addTypeMapping(new TypeMapping(9,new DeltaTime())); + configuration.addTypeMapping(new TypeMapping(10,new ObjectReference())); + configuration.addTypeMapping(new TypeMapping(11,new org.apache.qpid.management.domain.model.type.Boolean())); + configuration.addTypeMapping(new TypeMapping(12,new org.apache.qpid.management.domain.model.type.Float(),Names.NUMBER_VALIDATOR)); + configuration.addTypeMapping(new TypeMapping(13,new org.apache.qpid.management.domain.model.type.Double(),Names.NUMBER_VALIDATOR)); + configuration.addTypeMapping(new TypeMapping(14,new org.apache.qpid.management.domain.model.type.Uuid())); + configuration.addTypeMapping(new TypeMapping(15,new org.apache.qpid.management.domain.model.type.Map())); + configuration.addTypeMapping(new TypeMapping(16,new Int8(),Names.NUMBER_VALIDATOR)); + configuration.addTypeMapping(new TypeMapping(17,new Int16(),Names.NUMBER_VALIDATOR)); + configuration.addTypeMapping(new TypeMapping(18,new Int32(),Names.NUMBER_VALIDATOR)); + configuration.addTypeMapping(new TypeMapping(19,new Int64(),Names.NUMBER_VALIDATOR)); + } + + /** + * Configures the mandatory management message handlers. + */ + private void addMandatoryMethodReplyMessageHandlers () + { + Configuration.getInstance().addMethodReplyMessageHandlerMapping( + new MessageHandlerMapping( + Protocol.OPERATION_INVOCATION_RESPONSE_OPCODE, + MethodResponseMessageHandler.class.getName())); + + Configuration.getInstance().addMethodReplyMessageHandlerMapping( + new MessageHandlerMapping( + Protocol.SCHEMA_RESPONSE_OPCODE, + SchemaResponseMessageHandler.class.getName())); + } + + /** + * Configures the mandatory management message handlers. + */ + private void addMandatoryManagementMessageHandlers () + { + Configuration.getInstance().addManagementMessageHandlerMapping( + new MessageHandlerMapping( + Protocol.INSTRUMENTATION_CONTENT_RESPONSE_OPCODE, + InstrumentationMessageHandler.class.getName())); + + Configuration.getInstance().addManagementMessageHandlerMapping( + new MessageHandlerMapping( + Protocol.CONFIGURATION_CONTENT_RESPONSE_OPCDE, + ConfigurationMessageHandler.class.getName())); + + Configuration.getInstance().addManagementMessageHandlerMapping( + new MessageHandlerMapping( + Protocol.EVENT_CONTENT_RESPONSE_OPCDE, + EventContentMessageHandler.class.getName())); + + Configuration.getInstance().addManagementMessageHandlerMapping( + new MessageHandlerMapping( + Protocol.HEARTBEAT_INDICATION_RESPONSE_OPCODE, + HeartBeatIndicationMessageHandler.class.getName())); + } +} diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/configuration/IParser.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/configuration/IParser.java new file mode 100644 index 0000000000..a221686765 --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/configuration/IParser.java @@ -0,0 +1,44 @@ +/* + * + * 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.configuration; + +/** + * Interface definition for configuration parser + * Concrete implementors are responsible for parsing a specific XML part of configuration data. + * + * @author Andrea Gazzarini + */ +interface IParser +{ + /** + * Main director callback : Sets the name of the current attribute. + * + * @param name the name of the current attribute. + */ + void setCurrentAttributeName(String name); + + /** + * Main director callback : sets the value of the current attribute. + * + * @param value the value of the current attribute. + */ + void setCurrrentAttributeValue(String value); +}
\ No newline at end of file diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/configuration/MessageHandlerMapping.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/configuration/MessageHandlerMapping.java new file mode 100644 index 0000000000..5e38346a2d --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/configuration/MessageHandlerMapping.java @@ -0,0 +1,90 @@ +/* + * + * 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.configuration; + +/** + * Message Handler mapping used for associating an opcode with a message handler. + * + * @author Andrea Gazzarini + */ +class MessageHandlerMapping +{ + private Character _opcode; + private String _handlerClass; + + /** + * Builds an empty message handler mapping. + */ + MessageHandlerMapping() + { + } + + /** + * Builds a new mapping with the given opcode and handler class. + * + * @param opcode the opcode. + * @param handlerClass the handler class. + */ + MessageHandlerMapping(Character opcode, String handlerClass) { + this._opcode = opcode; + this._handlerClass = handlerClass; + } + + /** + * Returns the opcode of this mapping. + * + * @return the code of this mapping. + */ + Character getOpcode () + { + return _opcode; + } + + /** + * Sets the opcode for this mapping. + * + * @param codeAsString the opcode as a string. + */ + void setOpcode (String codeAsString) + { + this._opcode = codeAsString.charAt(0); + } + + /** + * Returns the message handler for this mapping. + * + * @return the message handler for this mapping. + */ + String getMessageHandlerClass() + { + return _handlerClass; + } + + /** + * Sets the message handler of this mapping. + * + * @param handlerClass the handler class as a string. + */ + void setMessageHandlerClass(String handlerClass) + { + this._handlerClass = handlerClass; + } +}
\ No newline at end of file diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/configuration/QpidDatasource.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/configuration/QpidDatasource.java new file mode 100644 index 0000000000..569a65a782 --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/configuration/QpidDatasource.java @@ -0,0 +1,249 @@ +/* + * + * 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.configuration; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import org.apache.commons.pool.BasePoolableObjectFactory; +import org.apache.commons.pool.ObjectPool; +import org.apache.commons.pool.impl.GenericObjectPool; +import org.apache.commons.pool.impl.GenericObjectPoolFactory; +import org.apache.qpid.management.Messages; +import org.apache.qpid.transport.Connection; +import org.apache.qpid.transport.ConnectionException; +import org.apache.qpid.transport.util.Logger; + +/** + * Qpid datasource. + * Basically it is a connection pool manager used for optimizing broker connections usage. + * + * @author Andrea Gazzarini + */ +public final class QpidDatasource +{ + private final static Logger LOGGER = Logger.get(QpidDatasource.class); + + /** + * A connection decorator used for adding pool interaction behaviour to an existing connection. + * + * @author Andrea Gazzarini + */ + class PooledConnection extends Connection + { + private final UUID _brokerId; + private boolean _valid; + + /** + * Builds a new decorator with the given connection. + * + * @param brokerId the broker identifier. + */ + private PooledConnection(UUID brokerId) + { + this._brokerId = brokerId; + _valid = true; + } + + /** + * Returns true if the underlying connection is still valid and can be used. + * + * @return true if the underlying connection is still valid and can be used. + */ + boolean isValid() + { + return _valid; + } + + void reallyClose() + { + super.close(); + } + + /** + * Returns the connection to the pool. That is, marks this connections as available. + * After that, this connection will be available for further operations. + */ + public void close() + { + try + { + pools.get(_brokerId).returnObject(this); + + LOGGER.debug(Messages.QMAN_200006_QPID_CONNECTION_RELEASED, this); + } + catch (Exception e) + { + throw new ConnectionException(e); + } + } + + public void exception(Throwable t) + { + //super.exception(t); + _valid = false; + } + } + + /** + * This is the connection factory, that is, the factory used to manage the lifecycle (create, validate & destroy) of + * the broker connection(s). + * + * @author Andrea Gazzarini + */ + class QpidConnectionFactory extends BasePoolableObjectFactory + { + private final BrokerConnectionData _connectionData; + private final UUID _brokerId; + + /** + * Builds a new connection factory with the given parameters. + * + * @param brokerId the broker identifier. + * @param connectionData the connecton data. + */ + private QpidConnectionFactory(UUID brokerId, BrokerConnectionData connectionData) + { + this._connectionData = connectionData; + this._brokerId = brokerId; + } + + /** + * Creates a new underlying connection. + */ + @Override + public Connection makeObject () throws Exception + { + PooledConnection connection = new PooledConnection(_brokerId); + connection.connect( + _connectionData.getHost(), + _connectionData.getPort(), + _connectionData.getVirtualHost(), + _connectionData.getUsername(), + _connectionData.getPassword(), + false); + return connection; + } + + /** + * Validates the underlying connection. + */ + @Override + public boolean validateObject (Object obj) + { + PooledConnection connection = (PooledConnection) obj; + boolean isValid = connection.isValid(); + + LOGGER.debug(Messages.QMAN_200007_TEST_CONNECTION_ON_RESERVE,isValid); + + return isValid; + } + + /** + * Closes the underlying connection. + */ + @Override + public void destroyObject (Object obj) throws Exception + { + try + { + PooledConnection connection = (PooledConnection) obj; + connection.reallyClose(); + + LOGGER.debug(Messages.QMAN_200008_CONNECTION_DESTROYED); + } catch (Exception exception) + { + LOGGER.debug(exception, Messages.QMAN_200009_CONNECTION_DESTROY_FAILURE); + } + } + } + + // Singleton instance. + private static QpidDatasource instance = new QpidDatasource(); + + // Each entry contains a connection pool for a specific broker. + private Map<UUID, ObjectPool> pools = new HashMap<UUID, ObjectPool>(); + + // Private constructor. + private QpidDatasource() + { + } + + /** + * Gets an available connection from the pool of the given broker. + * + * @param brokerId the broker identifier. + * @return a valid connection to the broker associated with the given identifier. + */ + public Connection getConnection(UUID brokerId) throws Exception + { + return (Connection) pools.get(brokerId).borrowObject(); + } + + /** + * Entry point method for retrieving the singleton instance of this datasource. + * + * @return the qpid datasource singleton instance. + */ + public static QpidDatasource getInstance() + { + return instance; + } + + /** + * Adds a connection pool to this datasource. + * + * @param brokerId the broker identifier that will be associated with the new connection pool. + * @param connectionData the broker connection data. + * @throws Exception when the pool cannot be created. + */ + void addConnectionPool(UUID brokerId,BrokerConnectionData connectionData) throws Exception + { + GenericObjectPoolFactory factory = new GenericObjectPoolFactory( + new QpidConnectionFactory(brokerId,connectionData), + connectionData.getMaxPoolCapacity(), + GenericObjectPool.WHEN_EXHAUSTED_BLOCK, + connectionData.getMaxWaitTimeout(),-1, + true, + false); + + ObjectPool pool = factory.createPool(); + + // Open connections at startup according to initial capacity param value. + int howManyConnectionAtStartup = connectionData.getInitialPoolCapacity(); + Object [] openStartupList = new Object[howManyConnectionAtStartup]; + + // Open... + for (int index = 0; index < howManyConnectionAtStartup; index++) + { + openStartupList[index] = pool.borrowObject(); + } + + // ...and immediately return them to pool. In this way the pooled connection has been opened. + for (int index = 0; index < howManyConnectionAtStartup; index++) + { + pool.returnObject(openStartupList[index]); + } + + pools.put(brokerId,pool); + } +} diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/configuration/Tag.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/configuration/Tag.java new file mode 100644 index 0000000000..7ff23c9d13 --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/configuration/Tag.java @@ -0,0 +1,51 @@ +/* +* + * 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.configuration; + +/** + * Configuration Tag catalogue. + * + * @author Andrea Gazzarini + */ +public enum Tag { + CONFIGURATION { @Override public String toString() { return "configuration"; }}, + BROKER { @Override public String toString() { return "broker"; }}, + HOST { @Override public String toString() { return "host"; }}, + PORT { @Override public String toString() { return "port"; }}, + MAX_POOL_CAPACITY { @Override public String toString() { return "max-pool-capacity"; }}, + MAX_WAIT_TIMEOUT { @Override public String toString() { return "max-wait-timeout"; }}, + INITIAL_POOL_CAPACITY { @Override public String toString() { return "initial-pool-capacity"; }}, + VIRTUAL_HOST { @Override public String toString() { return "virtual-host"; }}, + USER { @Override public String toString() { return "user"; }}, + PASSWORD { @Override public String toString() { return "password"; }}, + BROKERS { @Override public String toString() { return "brokers"; }}; + + /** + * Returns the enum entry associated to the given tag name. + * + * @param name the name of tag. + * @return the enum entry associated to the given tag name. + */ + public static Tag get(String name) { + return valueOf(name.replaceAll("-", "_").toUpperCase()); + } +} diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/configuration/TypeMapping.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/configuration/TypeMapping.java new file mode 100644 index 0000000000..2c0a460c1a --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/configuration/TypeMapping.java @@ -0,0 +1,90 @@ +/* + * + * 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.configuration; + +import org.apache.qpid.management.domain.model.type.Type; + +/** + * Type Mapping used for associating a code with a management type. + * + * @author Andrea Gazzarini + */ +class TypeMapping +{ + private final int _code; + private final Type _type; + private final String _validatorClass; + + /** + * Builds a new type mapping with the given parameters and no validator. + * + * @param code the code. + * @param type the management type. + */ + TypeMapping(int code, Type type) + { + this(code,type,null); + } + + /** + * Builds a new type mapping with the given parameters. + * + * @param code the code. + * @param type the management type. + * @param validatorClassName the class name of the validator to be used. + */ + TypeMapping(int code, Type type, String validatorClassName) + { + this._code = code; + this._type = type; + this._validatorClass = validatorClassName; + } + + /** + * Returns the code of this mapping. + * + * @return the code of this mapping. + */ + int getCode () + { + return _code; + } + + /** + * Returns the type for this mapping. + * + * @return the type for this mapping. + */ + Type getType () + { + return _type; + } + + /** + * Returns the validator class of this mapping. + * + * @return the validator class (as a string) of this mapping. + */ + public String getValidatorClassName() + { + return _validatorClass; + } +} diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/configuration/UnknownAccessCodeException.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/configuration/UnknownAccessCodeException.java new file mode 100644 index 0000000000..b7f1c0a7ec --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/configuration/UnknownAccessCodeException.java @@ -0,0 +1,53 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.management.configuration; + +/** + * Thrown when no access mode is found in configuration associated to the given code. + * + * @author Andrea Gazzarini + */ +public class UnknownAccessCodeException extends Exception +{ + private static final long serialVersionUID = 2350963503092509119L; + private final int _code; + + /** + * Builds a new UnknownAccessCodeException with the given code. + * + * @param code the access code. + */ + UnknownAccessCodeException(int code) + { + super(String.valueOf(code)); + this._code = code; + } + + /** + * Returns the unknown code. + * + * @return the unknown code. + */ + public int getCode () + { + return _code; + } +}
\ No newline at end of file diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/configuration/UnknownBrokerException.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/configuration/UnknownBrokerException.java new file mode 100644 index 0000000000..5b08e09c24 --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/configuration/UnknownBrokerException.java @@ -0,0 +1,43 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.management.configuration; + +import java.util.UUID; + +/** + * Thrown when someone requests connection data for an unknown broker. + * + * @author Andrea Gazzarini + */ +public class UnknownBrokerException extends Exception +{ + private static final long serialVersionUID = 4965395428832158924L; + + /** + * Builds a new UnknownBrokerException with the given broker id. + * + * @param brokerId the broker identifier. + */ + UnknownBrokerException(UUID brokerId) + { + super(String.valueOf(brokerId)); + } +}
\ No newline at end of file diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/configuration/UnknownTypeCodeException.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/configuration/UnknownTypeCodeException.java new file mode 100644 index 0000000000..57005d21e5 --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/configuration/UnknownTypeCodeException.java @@ -0,0 +1,53 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.management.configuration; + +/** + * Thrown when no type is found in configuration associated to the given code. + * + * @author Andrea Gazzarini + */ +public class UnknownTypeCodeException extends Exception +{ + private static final long serialVersionUID = 5440934037645111591L; + private int _code; + + /** + * Builds a new UnknownTypeCodeException with the given code. + * + * @param code the access code. + */ + UnknownTypeCodeException(int code) + { + super(String.valueOf(code)); + this._code = code; + } + + /** + * Returns the unknown code. + * + * @return the unknown code. + */ + public int getCode () + { + return _code; + } +} diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/base/BaseMessageHandler.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/base/BaseMessageHandler.java new file mode 100644 index 0000000000..798e835ff4 --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/base/BaseMessageHandler.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.domain.handler.base; + +import org.apache.qpid.management.domain.model.DomainModel; +import org.apache.qpid.transport.util.Logger; + +/** + * Base class for all message handlers. + * A message handler is an handler for a specific type of message. + * Message type is defined by the opcode. + * + * @author Andrea Gazzarini + */ +public abstract class BaseMessageHandler implements IMessageHandler +{ + /** + * Logger used for logging. + */ + protected final Logger _logger = Logger.get(getClass()); + + /** + * Managed broker domain model. + */ + protected DomainModel _domainModel; + + /** + * Sets the broker domain model. + * + * @param domainModel the broker domain model. + */ + public void setDomainModel(DomainModel domainModel) + { + this._domainModel = domainModel; + } +}
\ No newline at end of file diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/base/ContentIndicationMessageHandler.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/base/ContentIndicationMessageHandler.java new file mode 100644 index 0000000000..be000e9a05 --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/base/ContentIndicationMessageHandler.java @@ -0,0 +1,114 @@ +/* + * + * 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.domain.handler.base; + +import org.apache.qpid.management.domain.model.type.Binary; +import org.apache.qpid.transport.codec.Decoder; + +/** + * Base class for content indication message handlers. + * + * @author Andrea Gazzarini + */ +public abstract class ContentIndicationMessageHandler extends BaseMessageHandler +{ + /** + * Processes the income message. + * + * @param decoder the decoder used to parse the message. + * @param sequenceNumber the sequence number of the message. + */ + public final void process (Decoder decoder, int sequenceNumber) + { + String packageName = decoder.readStr8(); + String className = decoder.readStr8(); + Binary classHash = new Binary(decoder.readBin128()); + + long timeStampOfCurrentSample = decoder.readDatetime(); + long timeObjectWasCreated = decoder.readDatetime(); + long timeObjectWasDeleted = decoder.readDatetime(); + + Binary objectId = new Binary(decoder.readBin128()); + + if (objectHasBeenRemoved(timeObjectWasDeleted, timeStampOfCurrentSample)) + { + removeObjectInstance(packageName,className,classHash,objectId); + } else + { + updateDomainModel( + packageName, + className, + classHash, + objectId, + timeStampOfCurrentSample, + timeObjectWasCreated, + timeObjectWasDeleted, + decoder.readReaminingBytes()); + } + } + + /** + * Removes an object instance from the domain model. + * + * @param packageName the package name. + * @param className the class name. + * @param classHash the class hash. + * @param objectId the object identifier. + */ + void removeObjectInstance(String packageName, String className,Binary classHash, Binary objectId) + { + _domainModel.removeObjectInstance(packageName,className,classHash,objectId); + } + + /** + * Checks if the timestamps contained in the message indicate that the object has been removed. + * + * @param deletionTimestamp time object was deleted. + * @param now timestamp of the current message. + * @return true if the object has been removed, false otherwise. + */ + boolean objectHasBeenRemoved(long deletionTimestamp, long now) { + return (deletionTimestamp != 0) && (now > deletionTimestamp); + } + + /** + * Updates domain model with the incoming data. + * This is a template method that each concrete subclass must implement in order to update the domain model + * with the incoming data. + * + * @param packageName the name of the package. + * @param className the name of the class. + * @param objectId the object identifier. + * @param timeStampOfCurrentSample timestamp of current sample. + * @param timeObjectWasCreated time object was created. + * @param timeObjectWasDeleted time object was deleted. + * @param contentData object instance incoming data. + */ + protected abstract void updateDomainModel( + String packageName, + String className, + Binary classHash, + Binary objectId, + long timeStampOfCurrentSample, + long timeObjectWasCreated, + long timeObjectWasDeleted, + byte []contentData ); +}
\ No newline at end of file diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/base/IMessageHandler.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/base/IMessageHandler.java new file mode 100644 index 0000000000..c120334d30 --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/base/IMessageHandler.java @@ -0,0 +1,52 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.management.domain.handler.base; + +import org.apache.qpid.management.domain.model.DomainModel; +import org.apache.qpid.transport.codec.Decoder; + +/** + * Interface definition for a processor able to deal with a specific message. + * The concrete implementor must define what has to be done with the supplied (incoming) stream and the sequence + * number. + * + * @author Andrea Gazzarini. + */ +public interface IMessageHandler +{ + /** + * Processes the (incoming) stream message. + * Note that the main controller (the component that is controlling this handler) has already read the magic number and + * the sequence number so here concrete implementors must start from that point (that is, just after the sequence + * number). + * + * @param decoder the stream decoder. + * @param sequenceNumber the sequence number of the message. + */ + void process (Decoder decoder, int sequenceNumber); + + /** + * Injects the domain model into this handler. + * + * @param domainModel the domain model. + */ + void setDomainModel(DomainModel domainModel); +}
\ No newline at end of file diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/ConfigurationMessageHandler.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/ConfigurationMessageHandler.java new file mode 100644 index 0000000000..3158138172 --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/ConfigurationMessageHandler.java @@ -0,0 +1,57 @@ +/* + * + * 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.domain.handler.impl; + +import org.apache.qpid.management.domain.handler.base.ContentIndicationMessageHandler; +import org.apache.qpid.management.domain.model.type.Binary; + +/** + * Schema Response message handler. + * This handler is responsible to process 'c'(opcode) messages sent by the management broker. + * + * @author Andrea Gazzarini + */ +public class ConfigurationMessageHandler extends ContentIndicationMessageHandler +{ + /** + * Broker domain model is going to be updated with incoming configuration data. + * + * @param packageName the name of the package. + * @param className the name of the class. + * @param objectId the object identifier. + * @param timeStampOfCurrentSample the timestamp of incoming data. + * @param timeObjectWasCreated time object was created. + * @param timeObjectWasDeleted time object was deleted. + */ + @Override + protected void updateDomainModel ( + String packageName, + String className, + Binary classHash, + Binary objectId, + long timeStampOfCurrentSample, + long timeObjectWasCreated, + long timeObjectWasDeleted, + byte[] contentData) + { + _domainModel.addConfigurationRawData(packageName,className,classHash,objectId,contentData); + } + } diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/EventContentMessageHandler.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/EventContentMessageHandler.java new file mode 100644 index 0000000000..0a590d2836 --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/EventContentMessageHandler.java @@ -0,0 +1,51 @@ +/*
+ *
+ * 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.domain.handler.impl;
+
+import org.apache.qpid.management.domain.handler.base.BaseMessageHandler;
+import org.apache.qpid.management.domain.model.type.Binary;
+import org.apache.qpid.transport.codec.Decoder;
+
+/**
+ * Base class for content indication message handlers.
+ *
+ * @author Andrea Gazzarini
+ */
+public class EventContentMessageHandler extends BaseMessageHandler
+{
+ /**
+ * Processes the income message.
+ *
+ * @param decoder the decoder used to parse the message.
+ * @param sequenceNumber the sequence number of the message.
+ */
+ public final void process (Decoder decoder, int sequenceNumber)
+ {
+ String packageName = decoder.readStr8();
+ String eventName = decoder.readStr8();
+ Binary eventHash = new Binary(decoder.readBin128());
+ long timeStampOfCurrentSample = decoder.readDatetime();
+ int severity = decoder.readUint8();
+ byte[] argumentsData = decoder.readReaminingBytes();
+
+ _domainModel.addEventRawData(packageName, eventName, eventHash, argumentsData,timeStampOfCurrentSample,severity);
+ }
+}
diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/HeartBeatIndicationMessageHandler.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/HeartBeatIndicationMessageHandler.java new file mode 100644 index 0000000000..08c4f1bc5d --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/HeartBeatIndicationMessageHandler.java @@ -0,0 +1,39 @@ +/*
+*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.management.domain.handler.impl;
+
+import org.apache.qpid.management.domain.handler.base.BaseMessageHandler;
+import org.apache.qpid.transport.codec.Decoder;
+
+/**
+ * This is the handler responsible for processing the heartbeat indication response messages.
+ * At the moment it simply updates the last refresh update timestamp of the domain model.
+ *
+ * @author Andrea Gazzarini.
+ */
+public class HeartBeatIndicationMessageHandler extends BaseMessageHandler
+{
+ public void process(Decoder decoder, int sequenceNumber)
+ {
+ _domainModel.updateLastRefreshDate();
+ }
+}
diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/IMethodInvocationListener.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/IMethodInvocationListener.java new file mode 100644 index 0000000000..4ce64dd339 --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/IMethodInvocationListener.java @@ -0,0 +1,41 @@ +/* + * + * 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.domain.handler.impl; + +import java.util.EventListener; + +import org.apache.qpid.management.domain.model.InvocationEvent; + +/** + * Listener interface used to denote a component interested in method invocation events. + * + * @author Andrea Gazzarini + */ +public interface IMethodInvocationListener extends EventListener +{ + /** + * An operation is going to be invoked on a specific object instance. + * This lets this listener to be informed about the imminent invocation. + * + * @param event the invocation event. + */ + void operationIsGoingToBeInvoked(InvocationEvent event); +}
\ No newline at end of file diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/InstrumentationMessageHandler.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/InstrumentationMessageHandler.java new file mode 100644 index 0000000000..e86a44f829 --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/InstrumentationMessageHandler.java @@ -0,0 +1,57 @@ +/* + * + * 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.domain.handler.impl; + +import org.apache.qpid.management.domain.handler.base.ContentIndicationMessageHandler; +import org.apache.qpid.management.domain.model.type.Binary; + +/** + * Schema Response message handler. + * This handler is responsible to process 'i'(opcode) messages sent by the management broker. + * + * @author Andrea Gazzarini + */ +public class InstrumentationMessageHandler extends ContentIndicationMessageHandler +{ + /** + * Broker domain model is going to be updated with incoming instrumentation data. + * + * @param packageName the name of the package. + * @param className the name of the class. + * @param objectId the object identifier. + * @param timeStampOfCurrentSample the timestamp of incoming data. + * @param timeObjectWasCreated time object was created. + * @param timeObjectWasDeleted time object was deleted. + */ + @Override + protected void updateDomainModel ( + String packageName, + String className, + Binary classHash, + Binary objectId, + long timeStampOfCurrentSample, + long timeObjectWasCreated, + long timeObjectWasDeleted, + byte[] contentData) + { + _domainModel.addInstrumentationRawData(packageName,className,classHash,objectId,contentData); + } + } diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/InvocationResult.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/InvocationResult.java new file mode 100644 index 0000000000..d188d20976 --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/InvocationResult.java @@ -0,0 +1,157 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.management.domain.handler.impl; + +import java.io.Serializable; +import java.util.Map; +import java.util.Map.Entry; + +import org.apache.qpid.management.domain.services.MethodInvocationException; + +/** + * Value object used for storing an invocation method result. + * This is done in order to accomplish multiple return value requirement. + * As we know, it's not possible to do that only with method signature and therefore this value object / struct is used. + * + * @author Andrea Gazzarini + */ +public class InvocationResult implements Serializable +{ + private static final long serialVersionUID = 2062662997326399693L; + + private final long _returnCode; + private final String _statusText; + private final byte [] _outputAndBidirectionalArgumentValues; + private Map<String, Object> _outputSection; + + /** + * Builds an invocation result with the given status code and status text. + * + * @param statusCode the status code. + * @param statusText the status text. + */ + InvocationResult(long statusCode, String statusText,byte [] outputAndBidirectionalArgumentValues) + { + this._returnCode = statusCode; + this._statusText = statusText; + this._outputAndBidirectionalArgumentValues = outputAndBidirectionalArgumentValues; + } + + /** + * Checks if this result contains an error return code. + * + * @return true if this result object contains an error return code. + */ + public boolean isException () + { + return _returnCode != 0; + } + + /** + * Simply throws a new MethodInvocationException. + * Usually this method is called in conjunction with the isException() method in order to raise an exception if + * the wrapped return code means that there was an error. + * + * @throws MethodInvocationException always. + */ + public void createAndThrowException() throws MethodInvocationException + { + throw new MethodInvocationException(_returnCode, _statusText); + } + + @Override + public String toString () + { + StringBuilder builder = new StringBuilder() + .append("Status code : ") + .append(_returnCode) + .append(",") + .append("Status Text : ") + .append(_statusText); + if (_outputSection != null && !_outputSection.isEmpty()) + { + builder.append(". Parameters : "); + for (Entry<String, Object> outputEntry : _outputSection.entrySet()) + { + builder.append(outputEntry.getKey()).append('=').append(outputEntry.getValue()); + builder.append(','); + } + } + return builder.toString(); + } + + /** + * Returns the return code of this invocation result. + * + * @return the return code of this invocation result. + */ + public long getReturnCode () + { + return _returnCode; + } + + /** + * Contains the status text of this invocation result. + * + * @return the status text of this invocation result. + */ + public String getStatusText () + { + return _statusText; + } + + /** + * Returns the output and bidirectional argument values in raw format (byte []) + * + * @return the output and bidirectional argument values in raw format (byte []) + */ + public byte [] getOutputAndBidirectionalArgumentValues() + { + return _outputAndBidirectionalArgumentValues; + } + + /** + * Sets the output section (decoded) of this invocation result. + * When an incoming message arrives, the output section (output and bidirectional argument values) are + * initially stored in raw format. + * After that, their values need to be converted. + * The final result is a map containing (for each Output or Input/Output parameter) the name of the argument as key + * and its value as value. + * + * @param output a map containing outptu and bidirectional values (not in schema order). + */ + public void setOutputSection (Map<String, Object> outputSection) + { + this._outputSection = outputSection; + } + + /** + * Returns the output section of this invocation result. + * The output section consists in output and bidirectional argument values. + * Note that the order of the arguments is not guaranteed. + * + * @param outputSection the output section of this invocation result; + */ + public Map<String, Object> getOutputSection () + { + return _outputSection; + } +}
\ No newline at end of file diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/MethodOrEventDataTransferObject.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/MethodOrEventDataTransferObject.java new file mode 100644 index 0000000000..bc6a77d804 --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/MethodOrEventDataTransferObject.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.management.domain.handler.impl; + +import java.util.List; +import java.util.Map; + +/** + * Simple transfer object used for holding method / event definition data. + * + * @author Andrea Gazzarini + */ +public class MethodOrEventDataTransferObject +{ + private final Map<String, Object> _definition; + private List<Map<String, Object>> _argumentDefinitions; + + /** + * Builds a new trasfer object with the given parameters. + * + * @param definition the method definition. + * @param argumentDefinitions the arguments definitions. + */ + public MethodOrEventDataTransferObject( + Map<String, Object> definition, + List<Map<String, Object>> argumentDefinitions) + { + this._definition = definition; + this._argumentDefinitions = argumentDefinitions; + } + + /** + * Returns the method definition. + * + * @return the method definition. + */ + public Map<String, Object> getDefinition() { + return _definition; + } + + /** + * Returns the arguemnts definitions. + * + * @return the arguemnts definitions. + */ + public List<Map<String, Object>> getArgumentsDefinitions() + { + return _argumentDefinitions; + } +}
\ No newline at end of file diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/MethodResponseMessageHandler.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/MethodResponseMessageHandler.java new file mode 100644 index 0000000000..9c99eb09aa --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/MethodResponseMessageHandler.java @@ -0,0 +1,106 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.management.domain.handler.impl; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.BlockingQueue; + +import org.apache.qpid.management.Messages; +import org.apache.qpid.management.domain.handler.base.BaseMessageHandler; +import org.apache.qpid.management.domain.model.DomainModel; +import org.apache.qpid.management.domain.model.InvocationEvent; +import org.apache.qpid.transport.codec.Decoder; +import org.apache.qpid.transport.util.Logger; + +/** + * Message handler for method response messages. + * This handler is installed on domain model as a method invocation result listener. + * When a method is going to be invoked this listener is notified with the exchange channel that will be used between it and + * the event (method invocation) source object. + * + * @author Andrea Gazzarini + * + */ +public class MethodResponseMessageHandler extends BaseMessageHandler +{ + private final static Logger LOGGER = Logger.get(MethodResponseMessageHandler.class); + + private Map<Integer, BlockingQueue<InvocationResult>> _exchangeChannels = new HashMap<Integer, BlockingQueue<InvocationResult>>(); + + /** + * This is the listener installed on domain model for method invocations. + */ + private final IMethodInvocationListener methodInvocationListener = new IMethodInvocationListener() + { + /** + * Event source callback. + * A method is going to be invoked and this method lets this listener take the exchange channel that will be used + * with the event source for synchronous communication. + * + * @param event the operation invocation event. + */ + public void operationIsGoingToBeInvoked (InvocationEvent event) + { + _exchangeChannels.put(event.getSequenceNumber(), event.getExchangeChannel()); + } + }; + + /** + * Processes the incoming message. + * + * @param decoder the decoder used for parsing incoming data. + * @param sequenceNumber the sequence number of the incoming message. + */ + public void process (Decoder decoder, int sequenceNumber) + { + InvocationResult result = new InvocationResult(decoder.readUint32(), decoder.readStr16(),decoder.readReaminingBytes()); + BlockingQueue<InvocationResult> exchangeChannel = _exchangeChannels.remove(sequenceNumber); + if (exchangeChannel != null) + { + try + { + exchangeChannel.put(result); + } catch (InterruptedException exception) + { + LOGGER.error(exception,Messages.QMAN_100010_METHOD_INVOCATION_RESULT_FAILURE,sequenceNumber); + } + } else + { + LOGGER.warn( + "Unable to deal with incoming message because it contains a unknown sequence number (%s).", + sequenceNumber); + } + } + + /** + * Sets the domain model on this handler. + * In addiction, this handler registers a method invocation listener on the domain model. + * + * @param domainModel the managed broker domain model. + */ + @Override + public void setDomainModel (DomainModel domainModel) + { + super.setDomainModel(domainModel); + domainModel.setMethodInvocationListener(methodInvocationListener); + } +} diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/SchemaResponseMessageHandler.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/SchemaResponseMessageHandler.java new file mode 100644 index 0000000000..ee5efe2af6 --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/handler/impl/SchemaResponseMessageHandler.java @@ -0,0 +1,217 @@ +/* + * + * 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.domain.handler.impl; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.apache.qpid.management.Messages; +import org.apache.qpid.management.Names; +import org.apache.qpid.management.Protocol; +import org.apache.qpid.management.domain.handler.base.BaseMessageHandler; +import org.apache.qpid.management.domain.model.type.Binary; +import org.apache.qpid.transport.codec.Decoder; + +/** + * Schema Response message handler. + * This handler is responsible to process 'S'(opcode) messages sent by the management broker containing the full + * schema details for a class. + * + * @author Andrea Gazzarini + */ +public class SchemaResponseMessageHandler extends BaseMessageHandler +{ + /** + * Behavioural interface for classes that are responsible to deal with schema messages. + * + * @author Andrea Gazzarini + */ + interface IProcessor + { + /** + * Processes the incoming message using the given decoder. + * + * @param decoder the decoder used for dealing with incoming message. + */ + void process(Decoder decoder); + } + + /** + * Processor responsible to deal with class schema related messages. + */ + final IProcessor _classSchemaProcessor = new IProcessor() + { + public void process(Decoder decoder) + { + try + { + String packageName = decoder.readStr8(); + String className = decoder.readStr8(); + + Binary schemaHash = new Binary(decoder.readBin128()); + + int howManyProperties = decoder.readUint16(); + int howManyStatistics = decoder.readUint16(); + int howManyMethods = decoder.readUint16(); + + _domainModel.addSchema( + packageName, + className, + schemaHash, + getAttributes(decoder, howManyProperties), + getAttributes(decoder, howManyStatistics), + getMethods(decoder, howManyMethods)); + } catch(Exception exception) + { + _logger.error(exception,Messages.QMAN_100005_CLASS_SCHEMA_PROCESSING_FAILURE); + } + } + }; + + /** + * Processor responsible to deal with class event related messages. + */ + final IProcessor _eventSchemaProcessor = new IProcessor() + { + public void process(Decoder decoder) + { + try + { + String packageName = decoder.readStr8(); + String className = decoder.readStr8(); + Binary hash = new Binary(decoder.readBin128()); + int howManyArguments = decoder.readUint16(); + + _domainModel.addEventSchema( + packageName, + className, + hash, + getAttributes(decoder, howManyArguments)); + } catch(Exception exception) + { + _logger.error(exception,Messages.QMAN_100006_EVENT_SCHEMA_PROCESSING_FAILURE); + } + } + }; + + /** + * Processes an incoming schema response. + * This will be used for building the corresponding class definition. + * + * @param decoder the decoder used for parsing the incoming stream. + * @param sequenceNumber the sequence number of the incoming message. + */ + public void process (Decoder decoder, int sequenceNumber) + { + try + { + int classKind = decoder.readUint8(); + switch(classKind) + { + case Protocol.CLASS : + { + _classSchemaProcessor.process(decoder); + break; + } + case Protocol.EVENT : + { + _eventSchemaProcessor.process(decoder); + break; + } + default : + { + _logger.error(Messages.QMAN_100011_UNKNOWN_CLASS_KIND,classKind); + } + } + } catch(Exception exception) + { + _logger.error(exception,Messages.QMAN_100012_SCHEMA_MESSAGE_PROCESSING_FAILURE); + } + } + + /** + * Reads from the incoming message stream the properties definitions. + * + * @param decoder the decoder used for decode incoming data. + * @param howManyProperties the number of properties to read. + * @return a list of maps. Each map contains a property definition. + */ + List<Map<String, Object>> getAttributes(Decoder decoder,int howMany) + { + List<Map<String, Object>> result = new ArrayList<Map<String, Object>>(howMany); + for (int i = 0; i < howMany; i++ ) + { + result.add(decoder.readMap()); + } + return result; + } + + /** + * Reads the methods definitions from the incoming message stream. + * + * @param decoder the decoder used for decode incoming data. + * @param howManyMethods the number of methods to read. + * @return a list method definitions. + */ + List<MethodOrEventDataTransferObject> getMethods(Decoder decoder, int howManyMethods) + { + List<MethodOrEventDataTransferObject> result = new ArrayList<MethodOrEventDataTransferObject>(howManyMethods); + for (int i = 0; i < howManyMethods; i++) + { + Map<String,Object> method = decoder.readMap(); + int howManyArguments = (Integer) method.get(Names.ARG_COUNT_PARAM_NAME); + + List<Map<String,Object>> arguments = new ArrayList<Map<String,Object>>(howManyArguments); + for (int argIndex = 0; argIndex < howManyArguments; argIndex++) + { + arguments.add(decoder.readMap()); + } + result.add(new MethodOrEventDataTransferObject(method,arguments)); + } + return result; + } + + /** + * Reads the events definitions from the incoming message stream. + * + * @param decoder the decoder used for decode incoming data. + * @param howManyEvents the number of events to read. + * @return a list event definitions. + */ + List<MethodOrEventDataTransferObject> getEvents(Decoder decoder, int howManyEvents) + { + List<MethodOrEventDataTransferObject> result = new ArrayList<MethodOrEventDataTransferObject>(howManyEvents); + for (int i = 0; i < howManyEvents; i++) + { + Map<String,Object> method = decoder.readMap(); + int howManyArguments = (Integer) method.get(Names.ARG_COUNT_PARAM_NAME); + + List<Map<String,Object>> arguments = new ArrayList<Map<String,Object>>(howManyArguments); + for (int argIndex = 0; argIndex < howManyArguments; argIndex++) + { + arguments.add(decoder.readMap()); + } + result.add(new MethodOrEventDataTransferObject(method,arguments)); + } + return result; + } + }
\ No newline at end of file diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/AccessMode.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/AccessMode.java new file mode 100644 index 0000000000..6d1426c122 --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/AccessMode.java @@ -0,0 +1,33 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.management.domain.model; + +/** + * Enumeration for Access modes. + * + * @author Andrea Gazzarini + */ +public enum AccessMode +{ + RC { @Override public String toString() { return "Read-Create"; }}, + RO { @Override public String toString() { return "Read-Only"; }}, + RW { @Override public String toString() { return "Read-Write"; }} +}
\ No newline at end of file diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/Direction.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/Direction.java new file mode 100644 index 0000000000..8166c35eb6 --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/Direction.java @@ -0,0 +1,33 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.management.domain.model; + +/** + * Enumeration of allowed method argument direction codes. + * + * @author Andrea Gazzarini + */ +public enum Direction +{ + I{ @Override public String toString() { return "Input"; }}, + O{ @Override public String toString() { return "Output"; }}, + IO{ @Override public String toString() { return "Input-Output"; }}; +}
\ No newline at end of file diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/DomainModel.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/DomainModel.java new file mode 100644 index 0000000000..5a0ebaf1f7 --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/DomainModel.java @@ -0,0 +1,239 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.management.domain.model; + +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import org.apache.qpid.management.domain.handler.impl.IMethodInvocationListener; +import org.apache.qpid.management.domain.handler.impl.MethodOrEventDataTransferObject; +import org.apache.qpid.management.domain.model.type.Binary; + +/** + * Broker domain model. + * This is the local representation of a remote broker domain model. + * + * @author Andrea Gazzarini + */ +public class DomainModel +{ + private final UUID _id; + + /** Here the known packages of the remote broker are stored. */ + Map<String,QpidPackage> _packages = new HashMap<String, QpidPackage>(); + + private Date _lastRefreshDate = new Date(); + + private IMethodInvocationListener _methodInvocationListener; + + /** + * Builds a new domain model with the given broker identifier. + * + * @param brokerId the broker identifier. + */ + public DomainModel(UUID brokerId) + { + this._id = brokerId; + } + + /** + * Returns the identifier of the broker associated with this domain model. + * + * @return the identifier of the broker associated with this domain model. + */ + public UUID getBrokerId() + { + return _id; + } + + /** + * Adds the specified schema to this domain model. + * + * @param packageName the package name. + * @param className the class name. + * @param classHash the class schema hash. + * @param properties the class properties. + * @param statistics the class statistics. + * @param methods the class methods. + * @throws UnableToBuildFeatureException + */ + public void addSchema( + String packageName, + String className, + Binary classHash, + List<Map<String, Object>> properties, + List<Map<String, Object>> statistics, + List<MethodOrEventDataTransferObject> methods) throws UnableToBuildFeatureException + { + QpidPackage qpidPackage = getPackageByName(packageName); + qpidPackage.addClassDefinition(className,classHash,properties,statistics,methods); + } + + /** + * Updates the last refresh date. + */ + public void updateLastRefreshDate() + { + this._lastRefreshDate = new Date(); + } + + /** + * Returns the last refresh date. + * + * @return the last refresh date. + */ + public Date getLastRefreshDate() + { + return _lastRefreshDate; + } + + /** + * Adds the specified schema to this domain model. + * + * @param packageName the package name. + * @param className the class name. + * @param classHash the class schema hash. + * @param properties the class properties. + * @param statistics the class statistics. + * @param methods the class methods. + * @throws UnableToBuildFeatureException + */ + public void addEventSchema( + String packageName, + String className, + Binary classHash, + List<Map<String, Object>> arguments) throws UnableToBuildFeatureException + { + QpidPackage qpidPackage = getPackageByName(packageName); + qpidPackage.addEventDefinition(className,classHash,arguments); + } + + /** + * Gets the package with the specified name. + * Note that if the package doesn't exist a new one will be created and returned. + * + * @param packageName the name of the package. + * @return the package. + */ + QpidPackage getPackageByName (String packageName) + { + QpidPackage qpidPackage = _packages.get(packageName); + if (qpidPackage == null) + { + qpidPackage = new QpidPackage(packageName,this); + _packages.put(packageName, qpidPackage); + } + return qpidPackage; + } + + /** + * Returns true if a package with the specified name already exists on this domain model. + * + * @param packageName the name of the package. + * @return true if the package exists, false otherwise. + */ + boolean containsPackage (String packageName) + { + return _packages.containsKey(packageName); + } + + /** + * Adds the given instrumentation data (raw format) to this domain model. + * Note that this data is belonging to a specific object instance. + * + * @param packageName the name of the ower package. + * @param className the name of the owner class. + * @param classHash the schema hash for this class. + * @param objectId the object instance identifier. + * @param rawData the instrumentation data. + */ + public void addInstrumentationRawData (String packageName, String className,Binary classHash, Binary objectId, byte[] rawData) + { + QpidPackage qpidPackage = getPackageByName(packageName); + qpidPackage.setObjectInstanceInstrumentationRawData(className,classHash,objectId,rawData); + } + + public void addEventRawData ( + String packageName, + String eventName, + Binary eventHash, + byte[] rawData, + long currentTimestamp, + int severity) + { + QpidPackage qpidPackage = getPackageByName(packageName); + qpidPackage.setEventInstanceRawData(eventName,eventHash,rawData,currentTimestamp,severity); + } + + /** + * Adds the given configuration data (raw format) to this domain model. + * Note that this data is belonging to a specific object instance. + * + * @param packageName the name of the ower package. + * @param className the name of the owner class. + * @param classHash the schema hash for this class. + * @param objectId the object instance identifier. + * @param rawData the configuration data. + */ + public void addConfigurationRawData (String packageName, String className, Binary classHash,Binary objectId, byte[] rawData) + { + QpidPackage qpidPackage = getPackageByName(packageName); + qpidPackage.setObjectInstanceConfigurationRawData(className,classHash,objectId,rawData); + } + + /** + * Removes the object instance associated to the given parameters. + * + * @param packageName the owner package. + * @param className the class definition of the object instance. + * @param classHash the class hash + * @param objectId the object identifier. + */ + public void removeObjectInstance (String packageName, String className, Binary classHash, Binary objectId) + { + QpidPackage qpidPackage = getPackageByName(packageName); + qpidPackage.removeObjectInstance(className, classHash, objectId); + } + + /** + * Releases all the resources kept by domain model entitiies. + */ + public void releaseResources() + { + for (QpidPackage qpidPackage : _packages.values()) + { + qpidPackage.releaseResources(); + } + } + + public void setMethodInvocationListener(IMethodInvocationListener listener) + { + this._methodInvocationListener = listener; + } + + IMethodInvocationListener getMethodInvocationListener () + { + return _methodInvocationListener; + } +} diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/IValidator.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/IValidator.java new file mode 100644 index 0000000000..1ede559145 --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/IValidator.java @@ -0,0 +1,38 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.management.domain.model; + +/** + * Interface definition for attribute validators. + * + * @author Andrea Gazzarini + */ +interface IValidator +{ + /** + * Validates the given value according to the rules definied by this validator. + * + * @param value the value be checked. + * + * @throws ValidationException when the value is violating validator's rules. + */ + void validate(Object value) throws ValidationException; +}
\ No newline at end of file diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/InvocationEvent.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/InvocationEvent.java new file mode 100644 index 0000000000..d84a018346 --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/InvocationEvent.java @@ -0,0 +1,76 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.management.domain.model; + +import java.util.EventObject; +import java.util.concurrent.BlockingQueue; + +import org.apache.qpid.management.domain.handler.impl.InvocationResult; + +/** + * Operation invocation event. + * This encapsulates all the information that a method invocation listener needs to know about an operation which is + * going to be invoked. + * + * @author Andrea Gazzarini + */ +public class InvocationEvent extends EventObject +{ + private static final long serialVersionUID = 240229490753008597L; + + private final int _sequenceNumber; + private final BlockingQueue<InvocationResult> _exchangeChannel; + + /** + * Builds a new invocation event with the given data. + * + * @param source the event source. + * @param sequenceNumber the sequence number of the method invocation. + * @param exchangeChannel the exchange channel for synchronous communication. + */ + InvocationEvent(Object source, int sequenceNumber, BlockingQueue<InvocationResult> exchangeChannel) + { + super(source); + this._sequenceNumber = sequenceNumber; + this._exchangeChannel = exchangeChannel; + } + + /** + * Returns the sequence number that will be / has been used for method invocation. + * + * @return the sequence number that will be / has been used for method invocation. + */ + public int getSequenceNumber() + { + return _sequenceNumber; + } + + /** + * Returns the exchange channel that will be used between event source and event listener for synchronous + * communication. + * + * @return the exchange channel that will be used for synchronous communication. + */ + public BlockingQueue<InvocationResult> getExchangeChannel() + { + return _exchangeChannel; + } +}
\ No newline at end of file diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/JmxService.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/JmxService.java new file mode 100644 index 0000000000..d919fdacae --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/JmxService.java @@ -0,0 +1,348 @@ +/* + * + * 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.domain.model; + +import java.lang.management.ManagementFactory; +import java.util.Set; +import java.util.UUID; + +import javax.management.MBeanException; +import javax.management.MBeanServer; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; + +import org.apache.qpid.management.Messages; +import org.apache.qpid.management.Names; +import org.apache.qpid.management.domain.model.QpidClass.QpidManagedObject; +import org.apache.qpid.management.domain.model.QpidEvent.QpidManagedEvent; +import org.apache.qpid.management.domain.model.type.Binary; +import org.apache.qpid.management.domain.services.QMan; +import org.apache.qpid.transport.util.Logger; + +/** + * A simple facade used to perform operations on Mbean server. + * + * @author Andrea Gazzarini + */ +public class JmxService +{ + private final static Logger LOGGER = Logger.get(JmxService.class); + MBeanServer _mxServer = ManagementFactory.getPlatformMBeanServer(); + + /** + * Registers QMan with the MBeanServer. + * After that QMan management interface will be JMX-exposed. + * + * @param qman QMan + * @throws MBeanException when some error occurs during registration. + */ + public void registerQManService(QMan qman) throws MBeanException + { + ObjectName name = createQManName(); + if (!_mxServer.isRegistered(name)) + { + try { + _mxServer.registerMBean(qman, name); + } catch (Exception exception) { + throw new MBeanException(exception); + } + } + } + + void registerEventInstance( + QpidManagedEvent eventInstance, + UUID brokerId, + String packageName, + String eventClassName) + { + ObjectName name = createEventName(brokerId, packageName, eventClassName); + if (!_mxServer.isRegistered(name)) + { + try + { + _mxServer.registerMBean(eventInstance, name); + + LOGGER.debug( + Messages.QMAN_200010_EVENT_MBEAN_REGISTERED, + brokerId, + packageName, + eventClassName, + name); + } catch (Exception exception) + { + throw new RuntimeException(exception); + } + } +} + + /** + * Registers a pre-existing object instance as an MBean with the MBean + * server. + * + * @param instance the object instance. + * @param brokerId the broker identifier. + * @param packageName the name of the package containing this instance. + * @param className the name of the owner class of this instance. + * @param objectId the object instance identifier. + */ + void registerObjectInstance( + QpidManagedObject instance, + UUID brokerId, + String packageName, + String className, + Binary objectId) + { + ObjectName name = createObjectName(brokerId, packageName, className, objectId); + if (!_mxServer.isRegistered(name)) + { + try + { + _mxServer.registerMBean(instance, name); + + LOGGER.debug( + Messages.QMAN_200011_OBJECT_MBEAN_REGISTERED, + brokerId, + packageName, + className, + objectId, + name); + } catch (Exception exception) + { + throw new RuntimeException(exception); + } + } + } + + /** + * Removes / unregisters a managed object instance from the MBean Server. + * + * @param brokerId the broker identifier. + * @param packageName the name of the package containing this instance. + * @param className the name of the owner class of this instance. + * @param objectId the object instance identifier. + */ + void unregisterObjectInstance( + UUID brokerId, + String packageName, + String className, + Binary objectId) + { + ObjectName name = createObjectName(brokerId, packageName, className, objectId); + if (_mxServer.isRegistered(name)) + { + try + { + _mxServer.unregisterMBean(name); + + LOGGER.debug( + Messages.QMAN_200012_OBJECT_MBEAN_UNREGISTERED, + brokerId, + packageName, + className, + objectId, + name); + } catch (Exception exception) + { + LOGGER.error(exception,Messages.QMAN_100013_MBEAN_REGISTRATION_FAILURE,name); + } + } + } + + /** + * Removes (unregister) all events from MBean Server. + */ + void unregisterEvents() + { + for (ObjectName name : getEventMBeans()) + { + try + { + _mxServer.unregisterMBean(name); + } catch(Exception ignore) + { + } + } + } + + Set<ObjectName> getEventMBeans() + { + return _mxServer.queryNames(createEventSearchName(),null); + } + + /** + * Removes (unregister) all object instances from MBean Server. + */ + void unregisterObjectInstances() + { + Set<ObjectName> names = _mxServer.queryNames(createObjectInstanceSearchName(),null); + for (ObjectName name : names) + { + try + { + _mxServer.unregisterMBean(name); + } catch(Exception ignore) + { + } + } + } + + /** + * Factory method for ObjectNames. + * + * @param brokerId the broker identifier. + * @param packageName the name of the package containing this instance. + * @param className the name of the owner class of this instance. + * @param objectId the object instance identifier. + * @return the object name built according to the given parameters. + */ + private ObjectName createObjectName(UUID brokerId, String packageName, String className, Binary objectId) + { + String asString = new StringBuilder() + .append(Names.DOMAIN_NAME) + .append(':') + .append(Names.BROKER_ID) + .append('=') + .append(brokerId) + .append(",type=Object,") + .append(Names.PACKAGE) + .append('=') + .append(packageName) + .append(',') + .append(Names.CLASS) + .append('=') + .append(className) + .append(',') + .append(Names.OBJECT_ID) + .append('=') + .append(objectId) + .toString(); + try + { + return new ObjectName(asString); + } catch (MalformedObjectNameException exception) + { + throw new RuntimeException(exception); + } + } + + /** + * Creates an object name that will be used for searching all registered events. + * + * @return the object name that will be used for searching all registered events. + */ + ObjectName createEventSearchName() + { + String asString = new StringBuilder() + .append(Names.DOMAIN_NAME) + .append(':') + .append('*') + .append(",type=Event") + .toString(); + try + { + return new ObjectName(asString); + } catch (MalformedObjectNameException exception) + { + throw new RuntimeException(exception); + } + } + + /** + * Creates an object name that will be used for searching all registered object instances. + * + * @return the object name that will be used for searching all registered object instances. + */ + private ObjectName createObjectInstanceSearchName() + { + String asString = new StringBuilder() + .append(Names.DOMAIN_NAME) + .append(':') + .append('*') + .append(",type=Object") + .toString(); + try + { + return new ObjectName(asString); + } catch (MalformedObjectNameException exception) + { + throw new RuntimeException(exception); + } + } + + /** + * Factory method for ObjectNames. + * + * @param brokerId the broker identifier. + * @param packageName the name of the package containing this instance. + * @param className the name of the owner class of this instance. + * @return the object name built according to the given parameters. + */ + private ObjectName createEventName(UUID brokerId, String packageName, String className) + { + String asString = new StringBuilder() + .append(Names.DOMAIN_NAME) + .append(':') + .append(Names.BROKER_ID) + .append('=') + .append(brokerId) + .append(",type=Event,") + .append(Names.PACKAGE) + .append('=') + .append(packageName) + .append(',') + .append(Names.CLASS) + .append('=') + .append(className) + .append(',') + .append(Names.OBJECT_ID) + .append('=') + .append(UUID.randomUUID()) + .toString(); + try + { + return new ObjectName(asString); + } catch (MalformedObjectNameException exception) + { + throw new RuntimeException(exception); + } + } + + /** + * Creates the QMan object name. + * + * @return the QMan object name. + */ + private ObjectName createQManName() + { + String asString = new StringBuilder() + .append(Names.DOMAIN_NAME) + .append(':') + .append("Type=Service") + .toString(); + try + { + return new ObjectName(asString); + } catch (MalformedObjectNameException exception) + { + throw new RuntimeException(exception); + } + } +} diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/MissingFeatureAttributesException.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/MissingFeatureAttributesException.java new file mode 100644 index 0000000000..160054059b --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/MissingFeatureAttributesException.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.domain.model; + +import java.util.List; + +import org.apache.qpid.management.domain.model.QpidFeatureBuilder.Attribute; + +public class MissingFeatureAttributesException extends UnableToBuildFeatureException +{ + private static final long serialVersionUID = 671471705085787235L; + + public MissingFeatureAttributesException(List<Attribute> missingAttributeList) + { + super(String.valueOf(missingAttributeList)); + } +} diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidArgument.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidArgument.java new file mode 100644 index 0000000000..1e90479c0b --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidArgument.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.domain.model; + +import org.apache.qpid.management.Messages; +import org.apache.qpid.transport.codec.Encoder; +import org.apache.qpid.transport.util.Logger; + +class QpidArgument extends QpidProperty +{ + private final static Logger LOGGER = Logger.get(QpidArgument.class); + + private Object _defaultValue; + + private Direction _direction; + + public void setDirection(String code) + { + this._direction = Direction.valueOf(code); + } + + public Direction getDirection() + { + return _direction; + } + + public void setDefaultValue(Object defaultValue) + { + this._defaultValue = defaultValue; + } + + public Object getDefaultValue() + { + return _defaultValue; + } + + public boolean isInput(){ + return _direction != Direction.O; + } + + @Override + public String toString () + { + return new StringBuilder() + .append(getJavaType().getName()) + .append(' ') + .append(_name) + .append("(") + .append(_direction) + .append(")") + .toString(); + } + + public void encode(Object value,Encoder encoder) + { + _type.encode(value, encoder); + LOGGER.debug(Messages.QMAN_200013_ARGUMENT_VALUE_ENCODED,value,_name,_type); + } + + public Object decode(org.apache.qpid.transport.codec.Decoder decoder) + { + return _type.decode(decoder); + } +} diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidAttribute.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidAttribute.java new file mode 100644 index 0000000000..6712a14075 --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidAttribute.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.management.domain.model; + +import org.apache.qpid.management.Messages; +import org.apache.qpid.management.domain.model.type.Type; +import org.apache.qpid.transport.codec.Decoder; +import org.apache.qpid.transport.util.Logger; + +/** + * Layer supertype for qpid properties and statistics. + * + * @author Andrea Gazzarini + */ +class QpidAttribute extends QpidFeature +{ + private final static Logger LOGGER = Logger.get(QpidAttribute.class); + + /** feature type */ + protected Type _type; + + /** feature unit */ + protected String _unit; + + /** + * Returns the units used for numeric values (i.e. seconds, bytes, etc.) + * + * @return the units used for numeric values (i.e. seconds, bytes, etc.) + */ + String getUnit () + { + return _unit; + } + + /** + * Sets the unit for this property. + * + * @param unit the unit of this property. + */ + void setUnit (String unit) + { + this._unit = unit; + } + + /** + * Returns the java type (class) of this feature. + * + * @return the java type (class) of this feature. + */ + Class<?> getJavaType () + { + return _type.getJavaType(); + } + + /** + * Sets the type of this feature. + * + * @param type the type of this feature. + */ + void setType (Type type) + { + this._type = type; + } + + /** + * Gets the value of this feature according to its type definition. + * + * @param decoder the decoder used to extract the value. + * @return the value of this feature according to its type definition + */ + Object decodeValue(Decoder decoder) + { + try { + return _type.decode(decoder); + } catch(RuntimeException exception) + { + LOGGER.error(exception,Messages.QMAN_100014_ATTRIBUTE_DECODING_FAILURE,this); + throw exception; + } + } + + @Override + public String toString () + { + return super.toString()+",type="+_type; + } +} diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidClass.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidClass.java new file mode 100644 index 0000000000..c7dfcb033c --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidClass.java @@ -0,0 +1,768 @@ +/* + * + * 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.domain.model; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.SynchronousQueue; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import javax.management.Attribute; +import javax.management.AttributeList; +import javax.management.AttributeNotFoundException; +import javax.management.InvalidAttributeValueException; +import javax.management.MBeanAttributeInfo; +import javax.management.MBeanException; +import javax.management.MBeanInfo; +import javax.management.MBeanOperationInfo; +import javax.management.MBeanRegistration; +import javax.management.MBeanServer; +import javax.management.ObjectName; +import javax.management.ReflectionException; +import javax.management.RuntimeOperationsException; + +import org.apache.qpid.management.Messages; +import org.apache.qpid.management.domain.handler.impl.IMethodInvocationListener; +import org.apache.qpid.management.domain.handler.impl.InvocationResult; +import org.apache.qpid.management.domain.handler.impl.MethodOrEventDataTransferObject; +import org.apache.qpid.management.domain.model.type.Binary; +import org.apache.qpid.management.domain.services.SequenceNumberGenerator; +import org.apache.qpid.transport.codec.BBDecoder; +import org.apache.qpid.transport.util.Logger; + +/** + * Qpid Class definition. + * A type definition for a manageable object. + * This class is also responsible to manage incoming obejct instance data (configuration & instrumentation). + * How can we handle data before schema is injected into this class? simply we must retain that data in raw format. + * This class has 2 states : + * 1) first state is when schema is not yet injected. In this case the incoming object data is retained as is (in raw format); + * 2) second state is when schema is injected. In this case each injection of data will result in an update / create / delete of + * the corresponding object instance. In addition, the first time the state change, the old retained raw data is cnverted in + * object instance(s). + * + * @author Andrea Gazzarini + */ +class QpidClass extends QpidEntity +{ + /** + * State interface for this class definition. + * Each state is responsible to handle the injection of the data and / or schema. + * + * @author Andrea Gazzarini + */ + interface State + { + /** + * Adds configuration data for the object instance associated to the given object identifier. + * + * @param objectId the object identifier. + * @param rawData the raw configuration data. + */ + void addInstrumentationData (Binary objectId, byte[] rawData); + + /** + * Adds instrumentation data for the object instance associated to the given object identifier. + * + * @param objectId the object identifier. + * @param rawData the raw instrumentation data. + */ + void addConfigurationData (Binary objectId, byte[] rawData); + + /** + * Inject the schema into this class definition. + * + * @param propertyDefinitions + * @param statisticDefinitions + * @param methodDefinitions + * @throws UnableToBuildFeatureException when it's not possibile to parse schema and build the class definition. + */ + public void setSchema ( + List<Map<String, Object>> propertyDefinitions, + List<Map<String, Object>> statisticDefinitions, + List<MethodOrEventDataTransferObject> methodDefinitions) throws UnableToBuildFeatureException; + }; + + /** + * This is the initial state of every qpid class. + * The class definition instance is created but its schema has not been injected. + * Incoming configuration & instrumentation data will be stored in raw format because we don't know how to + * parse it until the schema arrives. + * In addition, this state is responsible (when data arrives) to request its schema. + */ + final State _schemaNotRequested = new State() { + + /** + * Stores the incoming data in raw format and request the schema for this class. + * After that a transition to the next state is made. + * + * @param objectId the object instance identifier. + * @param rawData incoming configuration data. + */ + public synchronized void addConfigurationData (Binary objectId, byte[] rawData) + { + try + { + requestSchema(); + _state = _schemaRequestedButNotYetInjected; + } catch (Exception e) + { + _logger.error( + Messages.QMAN_100015_UNABLE_TO_SEND_SCHEMA_REQUEST, + _parent.getName(), + _name); + } finally { + QpidManagedObject instance = getObjectInstance(objectId,false); + instance._rawConfigurationData.add(rawData); + } + } + + /** + * Stores the incoming data in raw format and request the schema for this class. + * After that a transition to the next state is made. + * + * @param objectId the object instance identifier. + * @param rawData incoming instrumentation data. + */ + public synchronized void addInstrumentationData (Binary objectId, byte[] rawData) + { + try + { + requestSchema(); + _state = _schemaRequestedButNotYetInjected; + } catch (Exception e) + { + _logger.error( + Messages.QMAN_100015_UNABLE_TO_SEND_SCHEMA_REQUEST, + _parent.getName(), + _name); + } finally { + QpidManagedObject instance = getObjectInstance(objectId,false); + instance._rawConfigurationData.add(rawData); + } + } + + /** + * This method only throws an illegal state exception because when a schema arrives + * this state is no longer valid. + */ + public void setSchema ( + List<Map<String, Object>> propertyDefinitions, + List<Map<String, Object>> statisticDefinitions, + List<MethodOrEventDataTransferObject> methodDefinitions) throws UnableToBuildFeatureException + { + throw new IllegalStateException("When a schema arrives it's not possible for this class to be in this state."); + } + }; + + /** + * This is the first state of this class definition : the schema is not yet injected so each injection of object data will be + * retained in raw format. + */ + final State _schemaRequestedButNotYetInjected = new State() + { + /** + * Stores the incoming data in raw format. + * + * @param objectId the object instance identifier. + * @param rawData incoming configuration data. + */ + public void addConfigurationData (Binary objectId, byte[] rawData) + { + QpidManagedObject instance = getObjectInstance(objectId,false); + instance._rawConfigurationData.add(rawData); + } + + /** + * Stores the incoming data in raw format. + * + * @param objectId the object instance identifier. + * @param rawData incoming instrumentation data. + */ + public void addInstrumentationData (Binary objectId, byte[] rawData) + { + QpidManagedObject instance = getObjectInstance(objectId,false); + instance._rawInstrumentationData.add(rawData); + } + + /** + * When a schema is injected into this defintiion the following should happen : + * 1) the incoming schema is parsed and the class definition is built; + * 2) the retained raw data is converted into object instance(s) + * 3) the internal state of this class changes; + * + * If someting is wrong during that process the schema is not built and the state don't change. + */ + public synchronized void setSchema ( + List<Map<String, Object>> propertyDefinitions, + List<Map<String, Object>> statisticDefinitions, + List<MethodOrEventDataTransferObject> methodDefinitions) throws UnableToBuildFeatureException + { + + MBeanAttributeInfo [] attributesMetadata = new MBeanAttributeInfo[propertyDefinitions.size()+statisticDefinitions.size()]; + MBeanOperationInfo [] operationsMetadata = new MBeanOperationInfo[methodDefinitions.size()]; + + buildAttributes(propertyDefinitions,statisticDefinitions,attributesMetadata); + buildMethods(methodDefinitions,operationsMetadata); + + _metadata = new MBeanInfo(_name,_name,attributesMetadata,null,operationsMetadata,null); + + // Converting stored object instances into JMX MBean and removing raw instance data. + for (Entry<Binary, QpidManagedObject> instanceEntry : _objectInstances.entrySet()) + { + Binary objectId = instanceEntry.getKey(); + QpidManagedObject instance = instanceEntry.getValue(); + + for (Iterator<byte[]> iterator = instance._rawInstrumentationData.iterator(); iterator.hasNext();) + { + updateInstanceWithInstrumentationData(instance,iterator.next()); + iterator.remove(); + } + + for (Iterator<byte[]> iterator = instance._rawConfigurationData.iterator(); iterator.hasNext();) + { + updateInstanceWithConfigurationData(instance, iterator.next()); + iterator.remove(); + } + + JMX_SERVICE.registerObjectInstance(instance,_parent.getOwnerId(),_parent.getName(),_name,objectId); + } + _state = _schemaInjected; + } + }; + + /** + * After a schema is built into this definition this is the current state of the class. + */ + final State _schemaInjected = new State() + { + /** + * Updates the configuration state of the object instance associates with the given object identifier. + * + * @param objectId the object identifier. + * @param rawData the configuration data (raw format). + */ + public void addConfigurationData (Binary objectId, byte[] rawData) + { + QpidManagedObject instance = getObjectInstance(objectId,true); + updateInstanceWithConfigurationData(instance, rawData); + } + + /** + * Updates the instrumentation state of the object instance associates with the given object identifier. + * + * @param objectId the object identifier. + * @param rawData the instrumentation data (raw format). + */ + public void addInstrumentationData (Binary objectId, byte[] rawData) + { + QpidManagedObject instance = getObjectInstance(objectId,true); + updateInstanceWithInstrumentationData(instance, rawData); + } + + /** + * Never called when the class definition has this state. + */ + public void setSchema ( + List<Map<String, Object>> propertyDefinitions, + List<Map<String, Object>> statisticDefinitions, + List<MethodOrEventDataTransferObject> methodDefinitions) throws UnableToBuildFeatureException + { + throw new IllegalStateException("When a schema arrives it's not possible for this class to be in this state."); + } + }; + + /** + * MBean used for representing remote broker object instances. + * This is the core component of the QMan domain model + * + * @author Andrea Gazzarini + */ + class QpidManagedObject extends QpidManagedEntity implements MBeanRegistration + { + private Binary _objectId; + + // Arrays used for storing raw data before this mbean is registered to mbean server. + List<byte[]> _rawInstrumentationData = new ArrayList<byte[]>(); + List<byte[]> _rawConfigurationData = new ArrayList<byte[]>(); + + /** + * Builds a new managed object with the given object identifier. + * + * @param objectId the object identifier. + */ + QpidManagedObject(Binary objectId) + { + this._objectId = objectId; + } + + /** + * Returns the value of the given attribute.s + * + * @throws AttributeNotFoundException when no attribute is found with the given name. + */ + public Object getAttribute (String attributeName) throws AttributeNotFoundException, MBeanException, ReflectionException + { + if (attributeName == null) + { + throw new RuntimeOperationsException(new IllegalArgumentException("attribute name must not be null")); + } + + if (_properties.containsKey(attributeName) || _statistics.containsKey(attributeName)) + { + return _attributes.get(attributeName); + } else + { + throw new AttributeNotFoundException(attributeName); + } + } + + /** + * Executes an operation on this object instance. + * + * @param actionName the name of the method. + * @param params the method parameters + * @param signature the method signature. + */ + public Object invoke (String actionName, Object[] params, String[] signature) throws MBeanException,ReflectionException + { + // TODO : Overloaded methods + QpidMethod method = _methods.get(actionName); + if (method != null) + { + try + { + method.validate(params); + return invokeMethod(_objectId, method, params); + } catch (Exception exception) + { + throw new MBeanException(exception); + } + } else { + throw new ReflectionException(new NoSuchMethodException(actionName)); + } + } + + /** + * Sets the value of the given attribute on this object instance. + * + * @param attribute contains the new value of the attribute. + * @throws AttributeNotFoundException when the given attribute is not found on this object instance. + * @throws InvalidAttributeValueException when the given value is violating one attribute invariant. + */ + public void setAttribute (Attribute attribute) throws AttributeNotFoundException, + InvalidAttributeValueException, MBeanException, ReflectionException + { + QpidProperty property = _properties.get(attribute.getName()); + try + { + property.validate(attribute.getValue()); + } catch(ValidationException exception) + { + throw new InvalidAttributeValueException(exception.getMessage()); + } + throw new RuntimeException("Not yet implemented."); + } + + /** + * Sets the values of several attributes of this MBean. + * + * @param attributes a list of attributes: The identification of the attributes to be set and the values they are to be set to. + * @return The list of attributes that were set, with their new values. + */ + public AttributeList setAttributes (AttributeList attributes) + { + throw new RuntimeException("Not yet implemented."); + } + + /** + * MBean server callback after deregistration. + */ + public void postDeregister () + { + } + + /** + * After the object is registered the raw data is set to null. + * This is done because we no longer need this data : it has already been + * injected into this object instance. + * + * @param registrationDone a flag indicating if the instance has been registered to mbean server. + */ + public void postRegister (Boolean registrationDone) + { + if (registrationDone) + { + _rawConfigurationData = null; + _rawInstrumentationData = null; + } + } + + /** + * MBean server callback before deregistration. + */ + public void preDeregister () throws Exception + { + } + + /** + * MBean server callback before registration. + */ + public ObjectName preRegister (MBeanServer server, ObjectName name) throws Exception + { + return name; + } + } + + Map<String, QpidProperty> _properties = new HashMap<String, QpidProperty>(); + Map<String, QpidStatistic> _statistics = new HashMap<String, QpidStatistic>(); + private Map<String, QpidMethod> _methods = new HashMap<String, QpidMethod>(); + + private List<QpidProperty> _schemaOrderedProperties = new ArrayList<QpidProperty>(); + private List<QpidStatistic> _schemaOrderedStatistics= new ArrayList<QpidStatistic>(); + + private int _howManyPresenceBitMasks; + private BlockingQueue<InvocationResult> _exchangeChannelForMethodInvocations; + private final IMethodInvocationListener _methodInvocationListener; + + Map<Binary, QpidManagedObject> _objectInstances = new HashMap<Binary, QpidManagedObject>(); + State _state = _schemaNotRequested;; + + private final static class Log + { + private final static Logger LOGGER = Logger.get(QpidClass.class); + final static void logMethodInvocationResult(InvocationResult result) + { + if (LOGGER.isDebugEnabled()) + { + LOGGER.debug(String.valueOf(result)); + } + } + } + + /** + * Builds a new class with the given name and package as parent. + * + * @param className the name of the class. + * @param hash the class schema hash. + * @param parentPackage the parent of this class. + */ + QpidClass(String className, Binary hash, QpidPackage parentPackage) + { + super(className,hash, parentPackage); + this._methodInvocationListener = _parent.getMethodInvocationListener(); + this._exchangeChannelForMethodInvocations = new SynchronousQueue<InvocationResult>(); + } + + /** + * Adds the configuration data for the object instance associated to the given object identifier. + * + * @param objectId the object identifier. + * @param rawData the raw configuration data. + */ + void addInstrumentationData (Binary objectId, byte[] rawData) + { + _logger.debug( + Messages.QMAN_200014_INCOMING_INSTRUMENTATION_DATA, + _parent.getOwnerId(), + _parent.getName(), + _name, + objectId); + _state.addInstrumentationData(objectId, rawData); + } + + /** + * Adds the instrumentation data for the object instance associated to the given object identifier. + * + * @param objectId the object identifier. + * @param rawData the raw instrumentation data. + */ + void addConfigurationData (Binary objectId, byte[] rawData) + { + _logger.debug( + Messages.QMAN_200015_INCOMING_CONFIGURATION_DATA, + _parent.getOwnerId(), + _parent.getName(), + _name, + objectId); + _state.addConfigurationData(objectId, rawData); + } + + /** + * Sets the schema for this class definition. + * A schema is basically a metadata description of all properties, statistics, methods and events of this class. + * + * @param propertyDefinitions properties metadata. + * @param statisticDefinitions statistics metadata. + * @param methodDefinitions methods metadata. + * @throws UnableToBuildFeatureException when some error occurs while parsing the incoming schema. + */ + void setSchema ( + List<Map<String, Object>> propertyDefinitions, + List<Map<String, Object>> statisticDefinitions, + List<MethodOrEventDataTransferObject> methodDefinitions) throws UnableToBuildFeatureException + { + _logger.info(Messages.QMAN_000010_INCOMING_SCHEMA,_parent.getOwnerId(),_parent.getName(),_name); + _state.setSchema(propertyDefinitions, statisticDefinitions, methodDefinitions); + } + + /** + * Internal method used for building attributes definitions. + * + * @param props the map contained in the properties schema. + * @param stats the map contained in the statistics schema. + * @param attributes the management metadata for attributes. + * @throws UnableToBuildFeatureException when it's not possibile to build one attribute definition. + */ + void buildAttributes ( + List<Map<String, Object>> props, + List<Map<String, Object>> stats, + MBeanAttributeInfo[] attributes) throws UnableToBuildFeatureException + { + int index = 0; + int howManyOptionalProperties = 0; + + for (Map<String, Object> propertyDefinition : props) + { + QpidFeatureBuilder builder = QpidFeatureBuilder.createPropertyBuilder(propertyDefinition); + builder.build(); + + QpidProperty property = (QpidProperty) builder.getQpidFeature(); + + howManyOptionalProperties += (property.isOptional()) ? 1 : 0; + + _properties.put(property.getName(),property); + _schemaOrderedProperties.add(property); + attributes[index++]=(MBeanAttributeInfo) builder.getManagementFeature(); + + _logger.debug( + Messages.QMAN_200016_PROPERTY_DEFINITION_HAS_BEEN_BUILT, + _parent.getName(), + _name, + property); + } + + _howManyPresenceBitMasks = (int)Math.ceil((double)howManyOptionalProperties / 8); + + _logger.debug( + Messages.QMAN_200018_OPTIONAL_PROPERTIES_INFO, + _parent.getOwnerId(), + _parent.getName(), + _name, + _howManyPresenceBitMasks); + + for (Map<String, Object> statisticDefinition : stats) + { + QpidFeatureBuilder builder = QpidFeatureBuilder.createStatisticBuilder(statisticDefinition); + builder.build(); + QpidStatistic statistic = (QpidStatistic) builder.getQpidFeature(); + + _statistics.put(statistic.getName(),statistic); + _schemaOrderedStatistics.add(statistic); + attributes[index++]=(MBeanAttributeInfo) builder.getManagementFeature(); + + _logger.debug( + Messages.QMAN_200017_STATISTIC_DEFINITION_HAS_BEEN_BUILT, + _parent.getName(), + _name, + statistic); + } + } + + /** + * Returns the object instance associated to the given identifier. + * Note that if the identifier is not associated to any obejct instance, a new one will be created. + * + * @param objectId the object identifier. + * @param registration a flag indicating whenever the (new ) instance must be registered with MBean server. + * @return the object instance associated to the given identifier. + */ + QpidManagedObject getObjectInstance(Binary objectId, boolean registration) + { + QpidManagedObject objectInstance = _objectInstances.get(objectId); + if (objectInstance == null) + { + objectInstance = new QpidManagedObject(objectId); + _objectInstances.put(objectId, objectInstance); + if (registration) + { + JMX_SERVICE.registerObjectInstance(objectInstance,_parent.getOwnerId(),_parent.getName(),_name,objectId); + } + } + return objectInstance; + } + + /** + * Internal method used for building method defintiions. + * + * @param definitions the properties map contained in the incoming schema. + * @param operationsMetadata + * @throws UnableToBuildFeatureException when it's not possibile to build one or more definitions. + */ + void buildMethods (List<MethodOrEventDataTransferObject> definitions, MBeanOperationInfo[] operationsMetadata) throws UnableToBuildFeatureException + { + int index = 0; + for (MethodOrEventDataTransferObject definition: definitions) + { + QpidFeatureBuilder builder = QpidFeatureBuilder.createMethodBuilder(definition); + builder.build(); + operationsMetadata [index++]= (MBeanOperationInfo) builder.getManagementFeature(); + QpidMethod method = (QpidMethod) builder.getQpidFeature(); + _methods.put(method.getName(),method); + } + } + + /** + * Header (opcode='M') + * ObjectId of target object (128 bits) + * Package name (str8) + * Class name (str8) + * Class hash (bin128) + * Method name (str8) [as defined in the schema] + * Now encode all input ("I") and i/o (IO) arguments in the order in which they are defined in the schema. + * (i.e. make one pass over the argument list and encode arguments that are either input or inptu/output). + + * @param objectId + * @param method + * @param parameters + * @throws Exception + */ + private InvocationResult invokeMethod(Binary objectId,QpidMethod method,Object [] parameters) throws Exception + { + try + { + _service.connect(); + + int sequenceNumber = SequenceNumberGenerator.getNextSequenceNumber(); + _methodInvocationListener.operationIsGoingToBeInvoked(new InvocationEvent(this,sequenceNumber,_exchangeChannelForMethodInvocations)); + _service.invoke(_parent.getName(), _name, _hash,objectId,parameters, method,sequenceNumber,objectId.getBankId(),objectId.getBrokerId()); + + InvocationResult result = _exchangeChannelForMethodInvocations.poll(5000,TimeUnit.MILLISECONDS); + + if (result == null) + { + throw new TimeoutException(); + } + + Map<String, Object> output = method.decodeParameters(result.getOutputAndBidirectionalArgumentValues()); + result.setOutputSection(output); + + Log.logMethodInvocationResult(result); + + if (result.isException()) + { + result.createAndThrowException(); + } + return result; + } finally + { + _service.close(); + } + } + + /** + * Updates the given obejct instance with the given incoming configuration data. + * + * @param instance the managed object instance. + * @param rawData the incoming configuration data which contains new values for instance properties. + */ + void updateInstanceWithConfigurationData(QpidManagedObject instance,byte [] rawData) + { + BBDecoder decoder = new BBDecoder(); + decoder.init(ByteBuffer.wrap(rawData)); + + byte [] presenceBitMasks = decoder.readBytes(_howManyPresenceBitMasks); + for (QpidProperty property : _schemaOrderedProperties) + { + try { + Object value = property.decodeValue(decoder,presenceBitMasks); + instance.createOrReplaceAttributeValue(property.getName(),value); + } catch(Exception ignore) { + _logger.error(Messages.QMAN_100016_UNABLE_TO_DECODE_FEATURE_VALUE, _parent.getName(),_name,property.getName()); + } + } + } + + /** + * Updates the given object instance with the given incoming instrumentation data. + * + * @param instance the managed object instance. + * @param rawData the incoming instrumentation data which contains new values for instance properties. + */ + void updateInstanceWithInstrumentationData(QpidManagedObject instance,byte [] rawData) + { + BBDecoder decoder = new BBDecoder(); + decoder.init(ByteBuffer.wrap(rawData)); + + for (QpidStatistic statistic : _schemaOrderedStatistics) + { + try { + Object value = statistic.decodeValue(decoder); + instance.createOrReplaceAttributeValue(statistic.getName(),value); + } catch(Exception ignore) { + _logger.error(Messages.QMAN_100016_UNABLE_TO_DECODE_FEATURE_VALUE, _parent.getName(),_name,statistic.getName()); + } + } + } + + @Override + public String toString () + { + return new StringBuilder() + .append(_parent.getOwnerId()) + .append("::") + .append(_parent.getName()) + .append('.') + .append(_name) + .toString(); + } + + /** + * Removes the object instance associated to the given identifier. + * + * @param objectId the object identifier. + */ + void removeObjectInstance (Binary objectId) + { + QpidManagedObject toBeRemoved = _objectInstances.remove(objectId); + if (toBeRemoved != null) + { + JMX_SERVICE.unregisterObjectInstance(_parent.getOwnerId(),_parent.getName(),_name,toBeRemoved._objectId); + } + } + + /** + * Deregisters all the object instances and release all previously acquired resources. + */ + void releaseResources () + { + _objectInstances.clear(); + JMX_SERVICE.unregisterObjectInstances(); + _service.close(); + } +} diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidEntity.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidEntity.java new file mode 100644 index 0000000000..59f8d807b2 --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidEntity.java @@ -0,0 +1,158 @@ +/*
+*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.management.domain.model;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.management.Attribute;
+import javax.management.AttributeList;
+import javax.management.DynamicMBean;
+import javax.management.MBeanInfo;
+import javax.management.RuntimeOperationsException;
+
+import org.apache.qpid.management.Messages;
+import org.apache.qpid.management.domain.model.type.Binary;
+import org.apache.qpid.management.domain.services.QpidService;
+import org.apache.qpid.transport.util.Logger;
+
+/**
+ * Layer supertype for QMan entities.
+ *
+ * @author Andrea Gazzarini
+ */
+public abstract class QpidEntity
+{
+ /**
+ * Layer supertype for QMan managed bean entities.
+ *
+ * @author Andrea Gazzarini
+ */
+ abstract class QpidManagedEntity implements DynamicMBean
+ {
+ // After mbean is registered with the MBean server this collection holds the mbean attribute values.
+ Map<String,Object> _attributes = new HashMap<String, Object>();
+
+ /**
+ * Creates or replace the given attribute.
+ * Note that this is not part of the management interface of this object instance and therefore will be accessible only
+ * from within this class.
+ * It is used to update directly the object attributes bypassing jmx interface.
+ *
+ * @param attributeName the name of the attribute.
+ * @param property newValue the new value of the attribute.
+ */
+ void createOrReplaceAttributeValue(String attributeName, Object newValue)
+ {
+ _attributes.put(attributeName, newValue);
+ }
+
+ /**
+ * Get the values of several attributes of the Dynamic MBean.
+ *
+ * @param attributes A list of the attributes to be retrieved.
+ *
+ * @return The list of attributes retrieved.
+ */
+ public AttributeList getAttributes (String[] attributes)
+ {
+ if (attributes == null)
+ {
+ throw new RuntimeOperationsException(new IllegalArgumentException("Attributes array must not be null"));
+ }
+
+ AttributeList result = new AttributeList(attributes.length);
+ for (int i = 0; i < attributes.length; i++)
+ {
+ String attributeName = attributes[i];
+ try
+ {
+ result.add(new Attribute(attributeName,getAttribute(attributeName)));
+ } catch(Exception exception)
+ {
+ // Already logged.
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Returns metadata for this object instance.
+ */
+ // Developer Note : note that this metadata is a member of the outer class definition : in that way we create
+ // that metadata only once and then it will be shared between all object instances (it's a readonly object)
+ public MBeanInfo getMBeanInfo ()
+ {
+ return _metadata;
+ }
+ };
+
+ final Logger _logger = Logger.get(getClass());
+ final static JmxService JMX_SERVICE = new JmxService();
+
+ final String _name;
+ final Binary _hash;
+
+ final QpidPackage _parent;
+ MBeanInfo _metadata;
+
+ final QpidService _service;
+
+ /**
+ * Builds a new class with the given name and package as parent.
+ *
+ * @param className the name of the class.
+ * @param hash the class schema hash.
+ * @param parentPackage the parent of this class.
+ */
+ QpidEntity(String className, Binary hash, QpidPackage parentPackage)
+ {
+ this._name = className;
+ this._parent = parentPackage;
+ this._hash = hash;
+ this._service = new QpidService(_parent.getOwnerId());
+
+ _logger.debug(
+ Messages.QMAN_200020_ENTITY_DEFINITION_HAS_BEEN_BUILT,
+ _parent.getOwnerId(),
+ _parent.getName(),
+ _name);
+ }
+
+ /**
+ * Internal method used to send a schema request for this entity.
+ *
+ * @throws Exception when the request cannot be sent.
+ */
+ void requestSchema() throws Exception
+ {
+ try
+ {
+ _service.connect();
+ _service.requestSchema(_parent.getName(), _name, _hash);
+ _service.sync();
+ } finally
+ {
+ _service.close();
+ }
+ }
+}
diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidEvent.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidEvent.java new file mode 100644 index 0000000000..273ae650c1 --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidEvent.java @@ -0,0 +1,456 @@ +/* + * + * 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.domain.model; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import javax.management.Attribute; +import javax.management.AttributeList; +import javax.management.AttributeNotFoundException; +import javax.management.InvalidAttributeValueException; +import javax.management.MBeanAttributeInfo; +import javax.management.MBeanException; +import javax.management.MBeanInfo; +import javax.management.ReflectionException; +import javax.management.RuntimeOperationsException; + +import org.apache.qpid.management.Messages; +import org.apache.qpid.management.domain.model.type.Binary; +import org.apache.qpid.transport.codec.BBDecoder; + +/** + * Qpid event definition. + * + * @author Andrea Gazzarini + */ +class QpidEvent extends QpidEntity +{ + + /** + * State interface for this event definition. + * Each state is responsible to handle the injection of the data and / or schema. + * + * @author Andrea Gazzarini + */ + interface State + { + /** + * Adds the given data for the object instance associated to the given object identifier. + * + * @param rawData the raw configuration data. + */ + void addNewEventData (byte[] rawData, long currentTimestamp, int severity); + + /** + * Inject the schema into this class definition. + * + * @param propertyDefinitions + * @param statisticDefinitions + * @param methodDefinitions + * @throws UnableToBuildFeatureException when it's not possibile to parse schema and build the class definition. + */ + public void setSchema (List<Map<String, Object>> agumentDefinitions) throws UnableToBuildFeatureException; + }; + + + /** + * This is the initial state of every qpid class. + * The class definition instance is created but its schema has not been injected. + * Incoming configuration & instrumentation data will be stored in raw format because we don't know how to + * parse it until the schema arrives. + * In addition, this state is responsible (when data arrives) to request its schema. + */ + final State _schemaNotRequested = new State() { + + /** + * Stores the incoming data in raw format and request the schema for this class. + * After that a transition to the next state is made. + * + * @param objectId the object instance identifier. + * @param rawData incoming configuration data. + */ + public synchronized void addNewEventData (byte[] rawData, long currentTimestamp, int severity) + { + try + { + requestSchema(); + _state = _schemaRequestedButNotYetInjected; + } catch (Exception e) + { + _logger.error( + Messages.QMAN_100015_UNABLE_TO_SEND_SCHEMA_REQUEST, + _parent.getName(), + _name); + } finally { + createEventInstance(rawData,currentTimestamp,severity); + } + } + + /** + * This method only throws an illegal state exception because when a schema arrives + * this state is no longer valid. + */ + public void setSchema (List<Map<String, Object>> agumentDefinitions) throws UnableToBuildFeatureException + { + throw new IllegalStateException("When a schema arrives it's not possible for this class to be in this state."); + } + }; + + /** + * This is the first state of this class definition : the schema is not yet injected so each injection of object data will be + * retained in raw format. + */ + final State _schemaRequestedButNotYetInjected = new State() + { + /** + * Stores the incoming data in raw format and request the schema for this class. + * After that a transition to the next state is made. + * + * @param objectId the object instance identifier. + * @param rawData incoming configuration data. + */ + public synchronized void addNewEventData (byte[] rawData,long currentTimestamp, int severity) + { + createEventInstance(rawData,currentTimestamp, severity); + } + + /** + * When a schema is injected into this defintiion the following should happen : + * 1) the incoming schema is parsed and the class definition is built; + * 2) the retained raw data is converted into object instance(s) + * 3) the internal state of this class changes; + * + * If someting is wrong during that process the schema is not built and the state don't change. + */ + public synchronized void setSchema (List<Map<String, Object>> argumentDefinitions) throws UnableToBuildFeatureException + { + MBeanAttributeInfo [] attributesMetadata = new MBeanAttributeInfo[argumentDefinitions.size()+2]; + + buildArguments(argumentDefinitions, attributesMetadata); + + _metadata = new MBeanInfo(_name,_name,attributesMetadata,null,null,null); + + // Converting stored object instances into JMX MBean and removing raw instance data. + for (QpidManagedEvent instance : _eventInstances) + { + updateEventInstanceWithData(instance); + JMX_SERVICE.registerEventInstance(instance,_parent.getOwnerId(),_parent.getName(),_name); + } + _state = _schemaInjected; + } + }; + + /** + * After a schema is built into this definition this is the current state of the class. + */ + final State _schemaInjected = new State() + { + /** + * Updates the configuration state of the object instance associates with the given object identifier. + * + * @param objectId the object identifier. + * @param rawData the configuration data (raw format). + */ + public void addNewEventData (byte[] rawData,long currentTimestamp, int severity) + { + QpidManagedEvent instance = createEventInstance(rawData,currentTimestamp, severity); + updateEventInstanceWithData(instance); + JMX_SERVICE.registerEventInstance(instance,_parent.getOwnerId(),_parent.getName(),_name); + } + + /** + * Never called when the class definition has this state. + */ + public void setSchema (List<Map<String, Object>> agumentDefinitions) throws UnableToBuildFeatureException + { + // N.A. : Schema is already injected. + } + }; + + /** + * MBean used for representing remote broker object instances. + * This is the core component of the QMan domain model + * + * @author Andrea Gazzarini + */ + class QpidManagedEvent extends QpidManagedEntity + { + + + // Arrays used for storing raw data before this mbean is registered to mbean server. + final byte[] _rawEventData; + final long _timestamp; + final int _severity; + + /** + * Builds a new managed object with the given object identifier. + * + * @param objectId the object identifier. + */ + private QpidManagedEvent(byte [] data, long timestamp, int severity) + { + this._rawEventData = data; + this._timestamp = timestamp; + this._severity = severity; + _attributes.put(SEVERITY_ATTR_NAME, _severity); + _attributes.put(TIMESTAMP_ATTR_NAME, new Date(_timestamp)); + } + + /** + * Returns the value of the given attribute.s + * + * @throws AttributeNotFoundException when no attribute is found with the given name. + */ + public Object getAttribute (String attributeName) throws AttributeNotFoundException, MBeanException, ReflectionException + { + if (attributeName == null) + { + throw new RuntimeOperationsException(new IllegalArgumentException("Attribute name must not be null.")); + } + + if (_arguments.containsKey(attributeName) || SEVERITY_ATTR_NAME.equals(attributeName) || TIMESTAMP_ATTR_NAME.equals(attributeName)) + { + return _attributes.get(attributeName); + } else + { + throw new AttributeNotFoundException(attributeName); + } + } + + /** + * Executes an operation on this object instance. + * + * @param actionName the name of the method. + * @param params the method parameters + * @param signature the method signature. + */ + public Object invoke (String actionName, Object[] params, String[] signature) throws MBeanException,ReflectionException + { + throw new ReflectionException(new NoSuchMethodException(actionName)); + } + + /** + * Sets the value of the given attribute on this object instance. + * + * @param attribute contains the new value of the attribute. + * @throws AttributeNotFoundException when the given attribute is not found on this object instance. + * @throws InvalidAttributeValueException when the given value is violating one attribute invariant. + */ + public void setAttribute (Attribute attribute) throws AttributeNotFoundException, + InvalidAttributeValueException, MBeanException, ReflectionException + { + throw new ReflectionException(new NoSuchMethodException()); + } + + /** + * Sets the values of several attributes of this MBean. + * + * @param attributes a list of attributes: The identification of the attributes to be set and the values they are to be set to. + * @return The list of attributes that were set, with their new values. + */ + public AttributeList setAttributes (AttributeList attributes) + { + throw new RuntimeException(); + } + } + + final static String SEVERITY_ATTR_NAME = "Severity"; + final static String TIMESTAMP_ATTR_NAME = "Date"; + + private List<QpidProperty> _schemaOrderedArguments = new ArrayList<QpidProperty>(); + + Map<String, QpidProperty> _arguments = new HashMap<String, QpidProperty>(); + List<QpidManagedEvent> _eventInstances = new LinkedList<QpidManagedEvent>(); + State _state = _schemaNotRequested;; + + /** + * Builds a new class with the given name and package as parent. + * + * @param className the name of the class. + * @param hash the class schema hash. + * @param parentPackage the parent of this class. + */ + QpidEvent(String eventClassName, Binary hash, QpidPackage parentPackage) + { + super(eventClassName,hash,parentPackage); + } + + /** + * Adds the configuration data for the object instance associated to the given object identifier. + * + * @param objectId the object identifier. + * @param rawData the raw configuration data. + */ + void addEventData (byte[] rawData, long currentTimestamp, int severity) + { + _logger.debug( + Messages.QMAN_200021_INCOMING_EVENT_DATA, + _parent.getOwnerId(), + _parent.getName(), + _name); + _state.addNewEventData(rawData, currentTimestamp, severity); + } + + /** + * Sets the schema for this class definition. + * A schema is basically a metadata description of all properties, statistics, methods and events of this class. + * + * @param propertyDefinitions properties metadata. + * @param statisticDefinitions statistics metadata. + * @param methodDefinitions methods metadata. + * @throws UnableToBuildFeatureException when some error occurs while parsing the incoming schema. + */ + void setSchema (List<Map<String, Object>> argumentDefinitions) throws UnableToBuildFeatureException + { + _logger.info(Messages.QMAN_000010_INCOMING_SCHEMA,_parent.getOwnerId(),_parent.getName(),_name); + _state.setSchema(argumentDefinitions); + } + + /** + * Internal method used for building attributes definitions. + * + * @param props the map contained in the properties schema. + * @param stats the map contained in the statistics schema. + * @param attributes the management metadata for attributes. + * @throws UnableToBuildFeatureException when it's not possibile to build one attribute definition. + */ + void buildArguments ( + List<Map<String, Object>> arguments,MBeanAttributeInfo[] attributes) throws UnableToBuildFeatureException + { + int index = 0; + + for (Map<String, Object> argumentDefinition : arguments) + { + // Force metadata attributes. It is needed because arguments are "similar" to properties but they + // aren't properties and then they haven't optional, index and access metadata attributes + // (mandatory for build a property definition). + argumentDefinition.put(QpidFeatureBuilder.Attribute.optional.name(),0); + argumentDefinition.put(QpidFeatureBuilder.Attribute.index.name(),1); + argumentDefinition.put(QpidFeatureBuilder.Attribute.access.name(),3); + + QpidFeatureBuilder builder = QpidFeatureBuilder.createPropertyBuilder(argumentDefinition); + builder.build(); + + QpidProperty argument = (QpidProperty) builder.getQpidFeature(); + + _arguments.put(argument.getName(),argument); + _schemaOrderedArguments.add(argument); + attributes[index++]=(MBeanAttributeInfo) builder.getManagementFeature(); + + _logger.debug( + Messages.QMAN_200019_EVENT_ARGUMENT_DEFINITION_HAS_BEEN_BUILT, + _parent.getName(), + _name, + argument); + } + + attributes[index++] = new MBeanAttributeInfo( + SEVERITY_ATTR_NAME, + Integer.class.getName(), + Messages.EVENT_SEVERITY_ATTRIBUTE_DESCRIPTION, + true, + false, + false); + + attributes[index++] = new MBeanAttributeInfo( + TIMESTAMP_ATTR_NAME, + Date.class.getName(), + Messages.EVENT_TIMESTAMP_ATTRIBUTE_DESCRIPTION, + true, + false, + false); + } + + /** + * Returns the object instance associated to the given identifier. + * Note that if the identifier is not associated to any obejct instance, a new one will be created. + * + * @param objectId the object identifier. + * @param registration a flag indicating whenever the (new ) instance must be registered with MBean server. + * @return the object instance associated to the given identifier. + */ + QpidManagedEvent createEventInstance(byte [] data, long timestamp, int severity) + { + QpidManagedEvent eventInstance = new QpidManagedEvent(data, timestamp, severity); + _eventInstances.add(eventInstance); + return eventInstance; + } + + /** + * Updates the given obejct instance with the given incoming configuration data. + * + * @param instance the managed object instance. + * @param rawData the incoming configuration data which contains new values for instance properties. + */ + void updateEventInstanceWithData(QpidManagedEvent instance) + { + BBDecoder decoder = new BBDecoder(); + decoder.init(ByteBuffer.wrap(instance._rawEventData)); + + for (QpidProperty property : _schemaOrderedArguments) + { + try { + Object value = property.decodeValue(decoder); + instance.createOrReplaceAttributeValue(property.getName(),value); + } catch(Exception ignore) { + _logger.error(Messages.QMAN_100016_UNABLE_TO_DECODE_FEATURE_VALUE, _parent.getName(),_name,property.getName()); + } + } + } + + @Override + public String toString () + { + return new StringBuilder() + .append(_parent.getOwnerId()) + .append("::") + .append(_parent.getName()) + .append(".") + .append(_name) + .toString(); + } + + /** + * Deregisters all the object instances and release all previously acquired resources. + */ + void releaseResources () + { + _eventInstances.clear(); + JMX_SERVICE.unregisterEvents(); + _service.close(); + } + + /** + * Checks if this event definition contains event instance(s). + * + * @return true if there is one or more managed instances. + */ + boolean hasNoInstances() + { + return _eventInstances.isEmpty(); + } +} diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidFeature.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidFeature.java new file mode 100644 index 0000000000..e1ca5a4d42 --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidFeature.java @@ -0,0 +1,88 @@ +/* + * + * 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.domain.model; + +/** + * Layer Supertype for all qpid management features. + * + * @author Andrea Gazzarini + */ +abstract class QpidFeature +{ + /** The name of the feature. */ + protected String _name; + + /** + * The description of the feature. + */ + protected String _description; + + /** + * Returns the description of this feature. + * + * @return the description of this feature. + */ + String getDescription () + { + return _description; + } + + /** + * Sets the description for this feature. + * + * @param description the description for this feature. + */ + void setDescription (String description) + { + this._description = description; + } + + /** + * Returns the name of the feature. + * + * @return the name of the feature. + */ + public String getName () + { + return _name; + } + + /** + * Sets the name for this feature. + * + * @param name the name of this feature. + */ + void setName (String name) + { + this._name = name; + } + + /** + * Returns the name of the feature. + * + * @return the name of the feature. + */ + @Override + public String toString () + { + return _name; + } +}
\ No newline at end of file diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidFeatureBuilder.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidFeatureBuilder.java new file mode 100644 index 0000000000..d0862c15ca --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidFeatureBuilder.java @@ -0,0 +1,454 @@ +/* + * + * 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.domain.model; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import javax.management.MBeanAttributeInfo; +import javax.management.MBeanFeatureInfo; +import javax.management.MBeanOperationInfo; +import javax.management.MBeanParameterInfo; + +import org.apache.qpid.management.configuration.Configuration; +import org.apache.qpid.management.configuration.UnknownTypeCodeException; +import org.apache.qpid.management.domain.handler.impl.MethodOrEventDataTransferObject; +import org.apache.qpid.management.Names; + +/** + * A builder used to parse incoming schema message and therefore to build a feature (property, statistic, method, event) + * definition. + * In order to set up the correct state for this builder, clients must create an instance of this class + * The product of the builder will be a QpidFeature and a JMX Managemtn feature used for describing that feature in a + * JMX environment. So, for example, for building a property definition client code should be : + * + * <br>- QpidFeatureBuilder builder = QpidFeature.createPropertyBuilder(...); + * <br>- builder.build(); + * <br>- QpidProperty property = (QpidProperty) builder.getQpidFeature(); + * <br>- MBeanAttributeInfo managementAttributeInfo = (MBeanAttributeInfo)builder.getManagementFeature(); + * + * <br>N.B.: a builder instance is not supposed to be reused. One instance for one feature! + * + * @author Andrea Gazzarini + */ +class QpidFeatureBuilder +{ + + static enum Attribute { + name,type,access,index,optional,unit,min,max,maxlen,desc,dir,argCount; + }; + + private List<Attribute> _mandatoryAttributes = new ArrayList<Attribute>(); + + /** + * Builder state for this class. + * Each concrete implementor is a builder for a specific feature. + * using the appropriate factory method. + * + * @author Andrea Gazzarini + */ + interface State { + void build() throws UnableToBuildFeatureException; + } + + /** + * Builder used for building property definition. + */ + final State _propertyBuilder = new State() { + + /** + * Builds a property definition as well a management attribute feature. + */ + public void build () throws UnableToBuildFeatureException + { + QpidProperty property = new QpidProperty(); + try { + int optionalIndex = 0; + for (Entry<String, Object> propertyAttribute : _featureDefinition.entrySet()) + { + Attribute attribute = Attribute.valueOf(propertyAttribute.getKey()); + switch(attribute) + { + case name : + { + property.setName(String.valueOf(propertyAttribute.getValue())); + break; + } + case access : + { + int code = (Integer)propertyAttribute.getValue(); + property.setAccessMode(Configuration.getInstance().getAccessMode(code)); + break; + } + case unit : + { + property.setUnit(String.valueOf(propertyAttribute.getValue())); + break; + } + case min : + { + property.setMinValue((Integer)propertyAttribute.getValue()); + break; + } + case max : + { + property.setMaxValue((Integer)propertyAttribute.getValue()); + break; + } + case maxlen : + { + property.setMaxLength((Integer)propertyAttribute.getValue()); + break; + } + case desc : + { + property.setDescription(String.valueOf(propertyAttribute.getValue())); + break; + } + case type : + { + int code = (Integer) propertyAttribute.getValue(); + property.setType(Configuration.getInstance().getType(code)); + break; + } + case index : + { + break; + } + case optional : + { + int code = (Integer) propertyAttribute.getValue(); + if (code == 1) + { + property.markAsOptional(optionalIndex); + optionalIndex++; + } + break; + } + } + _mandatoryAttributes.remove(attribute); + } + } catch(Exception exception) + { + throw new UnableToBuildFeatureException(exception,property.getName()); + } + + if (!_mandatoryAttributes.isEmpty()) + { + throw new MissingFeatureAttributesException(_mandatoryAttributes); + } + + _managementFeatureInfo = new MBeanAttributeInfo( + property.getName(), + property.getJavaType().getName(), + property.getDescription(), + true, + property.getAccessMode()==AccessMode.RW, + false); + _qpidFeature = property; + } + }; + + final State _statisticBuilder = new State() + { + public void build () throws UnableToBuildFeatureException + { + QpidStatistic statistic = new QpidStatistic(); + try + { + for (Entry<String, Object> statisticAttribute : _featureDefinition.entrySet()) + { + Attribute attribute = Attribute.valueOf(statisticAttribute.getKey()); + switch(attribute) + { + case name : + { + statistic.setName(String.valueOf(statisticAttribute.getValue())); + break; + } + case unit : + { + statistic.setUnit(String.valueOf(statisticAttribute.getValue())); + break; + } + case desc : + { + statistic.setDescription(String.valueOf(statisticAttribute.getValue())); + break; + } + case type : + { + int code = (Integer) statisticAttribute.getValue(); + statistic.setType(Configuration.getInstance().getType(code)); + break; + } + } + _mandatoryAttributes.remove(attribute); + } + } catch(Exception exception) + { + throw new UnableToBuildFeatureException(exception,statistic.getName()); + } + + if (!_mandatoryAttributes.isEmpty()) + { + throw new MissingFeatureAttributesException(_mandatoryAttributes); + } + + _managementFeatureInfo = new MBeanAttributeInfo( + statistic.getName(), + statistic.getJavaType().getName(), + statistic.getDescription(), + true, + false, + false); + _qpidFeature = statistic; + } + }; + + /** + * Builder used for building a statistic definition. + */ + final State _argumentBuilder = new State() + { + /** + * Builds a property definition as well a management attribute feature. + */ + public void build () throws UnableToBuildFeatureException + { + QpidArgument argument = new QpidArgument(); + for (Entry<String, Object> argumentAttribute : _featureDefinition.entrySet()) + { + String key = argumentAttribute.getKey(); + if (Names.DEFAULT_PARAM_NAME.equals(key)) + { + argument.setDefaultValue(argumentAttribute.getValue()); + } else { + Attribute attribute = Attribute.valueOf(key); + switch (attribute) + { + case name : + { + argument.setName((String)argumentAttribute.getValue()); + break; + } + case desc : + { + argument.setDescription((String)argumentAttribute.getValue()); + break; + } + case type : + { + try + { + argument.setType(Configuration.getInstance().getType((Integer)argumentAttribute.getValue())); + break; + } catch(UnknownTypeCodeException exception) + { + throw new UnableToBuildFeatureException(exception,argument.getName()); + } + } + case dir : + { + argument.setDirection((String)argumentAttribute.getValue()); + break; + } + case unit : + { + argument.setUnit((String)argumentAttribute.getValue()); + break; + + } + } + } + } + + if (!_mandatoryAttributes.isEmpty()) + { + throw new MissingFeatureAttributesException(_mandatoryAttributes); + } + + _qpidFeature = argument; + _managementFeatureInfo = new MBeanParameterInfo( + argument.getName(), + argument.getJavaType().getName(), + argument.getDescription()); + } + }; + + final State _methodBuilder = new State() + { + public void build () throws UnableToBuildFeatureException + { + Map<String,Object> definition = _methodOrEventDefinition.getDefinition(); + String name = (String)definition.get(Attribute.name.name()); + if (name == null) + { + throw new MissingFeatureAttributesException(_mandatoryAttributes); + } + + QpidMethod method = new QpidMethod((String)definition.get(Attribute.name.name()),(String) definition.get(Attribute.desc.name())); + + List<Map<String,Object>> args = _methodOrEventDefinition.getArgumentsDefinitions(); + + List<MBeanParameterInfo> signature = new LinkedList<MBeanParameterInfo>(); + + for (Map<String,Object> argumentDefinition : args) + { + QpidFeatureBuilder builder = QpidFeatureBuilder.createArgumentBuilder(argumentDefinition); + builder.build(); + + QpidArgument argument = (QpidArgument) builder.getQpidFeature(); + method.addArgument(argument); + if (argument.isInput()) + { + signature.add((MBeanParameterInfo) builder.getManagementFeature()); + } + } + + _qpidFeature = method; + _managementFeatureInfo = new MBeanOperationInfo( + method.getName(), + method.getDescription(), + (MBeanParameterInfo[])signature.toArray(new MBeanParameterInfo[signature.size()]), + void.class.getName(), + MBeanOperationInfo.ACTION); + } + }; + + final State _eventBuilder = new State() + { + public void build () throws UnableToBuildFeatureException + { + } + }; + + private MBeanFeatureInfo _managementFeatureInfo; + private QpidFeature _qpidFeature; + private final Map <String, Object> _featureDefinition; + private final MethodOrEventDataTransferObject _methodOrEventDefinition; + private State _state; + + static QpidFeatureBuilder createPropertyBuilder(Map<String, Object> propertyDefinition) + { + QpidFeatureBuilder result = new QpidFeatureBuilder(propertyDefinition); + result._state = result._propertyBuilder; + result._mandatoryAttributes.add(Attribute.name); + result._mandatoryAttributes.add(Attribute.access); + result._mandatoryAttributes.add(Attribute.type); + result._mandatoryAttributes.add(Attribute.optional); + result._mandatoryAttributes.add(Attribute.index); + return result; + } + + static QpidFeatureBuilder createStatisticBuilder(Map<String, Object> statisticDefinition) + { + QpidFeatureBuilder result = new QpidFeatureBuilder(statisticDefinition); + result._state = result._statisticBuilder; + result._mandatoryAttributes.add(Attribute.name); + result._mandatoryAttributes.add(Attribute.type); + return result; + } + + static QpidFeatureBuilder createEventBuilder(Map<String, Object> eventDefinition) + { + QpidFeatureBuilder result = new QpidFeatureBuilder(eventDefinition); + result._state = result._eventBuilder; + return result; + } + + static QpidFeatureBuilder createMethodBuilder(MethodOrEventDataTransferObject methodDefinition) + { + QpidFeatureBuilder result = new QpidFeatureBuilder(methodDefinition); + result._state = result._methodBuilder; + result._mandatoryAttributes.add(Attribute.name); + return result; + } + + private static QpidFeatureBuilder createArgumentBuilder(Map<String, Object> argumentDefinition) + { + QpidFeatureBuilder result = new QpidFeatureBuilder(argumentDefinition); + result._state = result._argumentBuilder; + return result; + } + + + /** + * Builds new builder with the given data. + * This constructor is used for building properties, statistics and arguments. + * + * @param definition the feature definition data. + */ + private QpidFeatureBuilder(Map<String, Object> definition) + { + this._featureDefinition = definition; + this._methodOrEventDefinition = null; + } + + /** + * Builds new builder with the given data. + * This constructor is used for building properties, statistics and arguments. + * + * @param definition the feature definition data. + */ + private QpidFeatureBuilder(MethodOrEventDataTransferObject definition) + { + this._featureDefinition = null; + this._methodOrEventDefinition = definition; + } + + /** + * Returns the just built qpid feature. + * + * @return the qpid feature. + */ + QpidFeature getQpidFeature() + { + return _qpidFeature; + } + + /** + * Return the jmx metadata for the built feature. + * + * @return the jmx metadata for the built feature. + */ + MBeanFeatureInfo getManagementFeature() + { + return _managementFeatureInfo; + } + + void build() throws UnableToBuildFeatureException + { + try + { + _state.build(); + } catch(UnableToBuildFeatureException exception) + { + throw exception; + } catch(Exception exception) + { + throw new UnableToBuildFeatureException(exception,"Feature name is not available for debugging."); + } + } +} diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidMethod.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidMethod.java new file mode 100644 index 0000000000..7824ecc9a4 --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidMethod.java @@ -0,0 +1,147 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.management.domain.model; + +import java.nio.ByteBuffer; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import org.apache.qpid.transport.codec.BBDecoder; +import org.apache.qpid.transport.codec.Encoder; + + +/** + * Qpid method definition. + * An entity describing an invocation that can be made on a managed object instance. + * + * @author Andrea Gazzarini + */ +public class QpidMethod extends QpidFeature +{ + /** Argument list */ + List<QpidArgument> arguments = new LinkedList<QpidArgument>(); + + /** + * Builds a new qpid method definition with the given name and description. + * + * @param name the method name. + * @param description the method description. + */ + QpidMethod(String name, String description) + { + this._name = name; + this._description = description; + } + + /** + * Adds an argument to this method. + * + * @param argument the new argument to be added. + */ + void addArgument(QpidArgument argument) + { + arguments.add(argument); + } + + /** + * Returns a string representation of this method. + * The result format is <method name>(argType1 argName1 (Direction), argType2 argName2 (Direction), etc...) + * + * @return a string representation of this method. + */ + @Override + public String toString () + { + StringBuilder builder = new StringBuilder() + .append(_name) + .append('('); + + for (QpidArgument argument : arguments) + { + builder.append(argument).append(','); + } + + builder.append(')'); + return builder.toString(); + } + + /** + * Encodes the given parameter values according to this method arguments definitions. + * Note that only Input/Output and Input parameters are encoded. + * + * @param parameters the parameters values. + * @param encoder the encoder used for encoding. + */ + public void encodeParameters (Object[] parameters, Encoder encoder) + { + int index = 0; + for (QpidArgument argument : arguments) + { + if (argument.getDirection() != Direction.O) + { + argument.encode(parameters[index++],encoder); + } + } + } + + /** + * Decodes the given input raw according to this method arguments definitions. + * Note that only Input/Output and Output parameters are encoded. + * + * @param parameters the parameters values. + * @param encoder the encoder used for encoding. + */ + public Map<String, Object> decodeParameters (byte [] values) + { + BBDecoder decoder = new BBDecoder(); + decoder.init(ByteBuffer.wrap(values)); + Map<String, Object> result = new HashMap<String, Object>(); + + for (QpidArgument argument : arguments) + { + if (argument.getDirection() != Direction.I) + { + result.put(argument.getName(),argument.decode(decoder)); + } + } + return result; + } + + /** + * Validates the given array of parameters against the constraint defined on this method's arguments. + * + * @param parameters the parameters (values) to be validated. + * @throws ValidationException when one of the supplied values is violating some constraint. + */ + public void validate (Object[] parameters) throws ValidationException + { + int index = 0; + for (QpidArgument argument : arguments) + { + if (argument.getDirection() != Direction.O) + { + argument.validate(parameters[index++]); + } + } + } +}
\ No newline at end of file diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidPackage.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidPackage.java new file mode 100644 index 0000000000..e9799cb147 --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidPackage.java @@ -0,0 +1,279 @@ +/* + * + * 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.domain.model; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import org.apache.qpid.management.domain.handler.impl.IMethodInvocationListener; +import org.apache.qpid.management.domain.handler.impl.MethodOrEventDataTransferObject; +import org.apache.qpid.management.domain.model.type.Binary; + +/** + * Qpid package definition. + * A grouping of class definitions that are related to a single software component. + * The package concept is used to extend the management schema beyond just the QPID software components. + * The name is prefixed with "Qpid" for avoiding name conficts with java.lang.Package. + * + * @author Andrea Gazzarini + */ +final class QpidPackage +{ + /** + * Qpid class identity. + * Each qpid class is uniquely identifier by its name and schema-hash. + * The schema hash is an MD5 checksum of the schema for a class. + * It is there so we can support the case where two different versions of the same class are present at the same time. + * + * @author Andrea Gazzarini + */ + class QpidClassIdentity { + final String name; + final Binary hash; + + /** + * Builds a new class identity with the given name and hash. + * + * @param name the class name. + * @param hash is an MD5 checksum of the schema of this outer class. + */ + QpidClassIdentity(String name,Binary hash) { + this.name = name; + this.hash = hash; + } + + @Override + public int hashCode () + { + return name.hashCode()+hash.hashCode(); + } + + @Override + public boolean equals (Object obj) + { + QpidClassIdentity identity = (QpidClassIdentity) obj; + return name.equals(identity.name) && hash.equals(identity.hash); + } + } + + private String _name; + private DomainModel _parent; + private Map<QpidClassIdentity, QpidClass> _classes = new HashMap<QpidClassIdentity, QpidClass>(); + private Map<QpidClassIdentity, QpidEvent> _events = new HashMap<QpidClassIdentity, QpidEvent>(); + + /** + * Builds a new package with the supplied name. + * + * @param name the name of the package. + */ + QpidPackage(String name, DomainModel parent) + { + this._name = name; + this._parent = parent; + } + + /** + * Returns the identifier of the broker which contains this package. + * @return + */ + UUID getOwnerId() + { + return _parent.getBrokerId(); + } + + /** + * Returns the name of this package. + * + * @return the name of this package. + */ + String getName () + { + return _name; + } + + /** + * Adds a class definition to this package. + * The class will be added only if its definition doesn't already exists. + * + * @param className the name of the class. + * @param classHash the class schema hash. + * @param properties the properties of the class. + * @param statistics the statistics of the class. + * @param methods the methods of the class. + * @param events the events of the class. + * + * @throws UnableToBuildFeatureException when the class definition cannot be built due to a feature build failure. + */ + void addClassDefinition ( + String className, + Binary classHash, + List<Map<String, Object>> properties, + List<Map<String, Object>> statistics, + List<MethodOrEventDataTransferObject> methods) throws UnableToBuildFeatureException + { + getQpidClass(className,classHash,true).setSchema(properties,statistics,methods); + } + + void addEventDefinition ( + String eventClassName, + Binary classHash, + List<Map<String, Object>> arguments) throws UnableToBuildFeatureException + { + getQpidEvent(eventClassName,classHash,true).setSchema(arguments); + } + + /** + * Returns true if this package contains the given class definition. + * + * @param className the name of the class. + * @return true if this package contains the class definition, false otherwise. + */ + boolean alreadyContainsClassDefinition (String className, Binary hash) + { + return _classes.containsKey(new QpidClassIdentity(className,hash)); + } + + /** + * Injects into a class the given object instance instrumentation data. + * + * @param className the of the class the injected object data belongs to. + * @param objectId the object identifier. + * @param rawData the instrumentation data (in raw format). + */ + void setObjectInstanceInstrumentationRawData (String className, Binary classHash,Binary objectId, byte[] rawData) + { + getQpidClass(className, classHash,true).addInstrumentationData(objectId,rawData); + } + + /** + * Injects into a class the given object instance configuration data. + * + * @param className the of the class the injected object data belongs to. + * @param objectId the object identifier. + * @param rawData the configuration data (in raw format). + */ + void setObjectInstanceConfigurationRawData (String className,Binary classHash, Binary objectId, byte[] rawData) + { + getQpidClass(className,classHash,true).addConfigurationData(objectId,rawData); + } + + void setEventInstanceRawData (String eventName,Binary eventHash, byte[] rawData,long currentTimestamp,int severity) + { + getQpidEvent(eventName,eventHash,true).addEventData(rawData, currentTimestamp, severity); + } + + /** + * Returns the definition of the class with given name. + * + * @param className the name of the class. + * @param hash the class hash. + * @param store a flag indicating if a just created class must be stored or not. + * @return the definition of the class with given name. + */ + QpidClass getQpidClass(String className, Binary hash, boolean store) + { + QpidClassIdentity identity = new QpidClassIdentity(className,hash); + QpidClass classDefinition = _classes.get(identity); + if (classDefinition == null) + { + classDefinition = new QpidClass(className, hash,this); + if (store) + { + _classes.put(identity,classDefinition); + } + } + return classDefinition; + } + + /** + * Returns the definition of the class with given name. + * + * @param className the name of the class. + * @param hash the class hash. + * @param store a flag indicating if a just created class must be stored or not. + * @return the definition of the class with given name. + */ + QpidEvent getQpidEvent(String className, Binary hash, boolean store) + { + QpidClassIdentity identity = new QpidClassIdentity(className,hash); + QpidEvent eventDefinition = _events.get(identity); + if (eventDefinition == null) + { + eventDefinition = new QpidEvent(className, hash,this); + if (store) + { + _events.put(identity,eventDefinition); + } + } + return eventDefinition; + } + + /** + * Returns a string representation of this class. + * That is, this method returns the simple name (not FQN) of this class. + */ + @Override + public String toString () + { + return _name; + } + + /** + * Removes the object instance associated to the given parameters. + * + * @param className the class definition of the object instance. + * @param classHash the class hash + * @param objectId the object identifier. + */ + void removeObjectInstance (String className, Binary classHash, Binary objectId) + { + QpidClass qpidClass = getQpidClass(className,classHash,false); + qpidClass.removeObjectInstance(objectId); + } + + /** + * Releases all previously acquired resources of this package. + */ + void releaseResources () + { + for (QpidClass qpidClass : _classes.values()) + { + qpidClass.releaseResources(); + } + + for (QpidEvent qpidEvent: _events.values()) + { + qpidEvent.releaseResources(); + } + } + + /** + * Returns the method invocation listener of the corresponing parent domain model. + * + * @return the method invocation listener of the corresponing parent domain model. + */ + IMethodInvocationListener getMethodInvocationListener () + { + return _parent.getMethodInvocationListener(); + } +} diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidProperty.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidProperty.java new file mode 100644 index 0000000000..089b00c71c --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidProperty.java @@ -0,0 +1,295 @@ +/* + * + * 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.domain.model; + +import java.lang.reflect.Constructor; + +import org.apache.qpid.management.Messages; +import org.apache.qpid.management.configuration.Configuration; +import org.apache.qpid.management.domain.model.type.Type; +import org.apache.qpid.transport.util.Logger; + +/** + * Qpid property definition. + * + * @author Andrea Gazzarini + */ +class QpidProperty extends QpidAttribute +{ + private final static Logger LOGGER = Logger.get(QpidProperty.class); + + private final static int [] MASKS = {1,2,4,8,16,32,64,128}; + + /** + * Decoder interface used for decoding incomng values for this property. + * + * @author Andrea Gazzarini + */ + interface Decoder + { + Object decodeValue(org.apache.qpid.transport.codec.Decoder decoder,byte [] presenceBitMasks); + } + + /** + * Decoder used for decoding incoming values for this optional property. + */ + final Decoder _optionalPropertyDecoder = new Decoder() { + + public Object decodeValue (org.apache.qpid.transport.codec.Decoder decoder, byte[] presenceBitMasks) + { + return ((presenceBitMasks[_optionalIndex/8] & MASKS[_maskIndex]) != 0) + ? QpidProperty.this.decodeValue(decoder) + : null; + } + }; + + /** + * Decoder used for decoding incoming values for this mandatory property. + */ + final Decoder _mandatoryPropertyDecoder = new Decoder() { + + public Object decodeValue (org.apache.qpid.transport.codec.Decoder decoder, byte[] presenceBitMasks) + { + return QpidProperty.this.decodeValue(decoder); + } + }; + + + /** + * Null object used to perform a dummy validation. + * This is the default validator installed at creation time. + */ + final static IValidator EMPTY_VALIDATOR = new IValidator() + { + public void validate (Object value) throws ValidationException + { + // Nothing to do here. + } + }; + + /** + * Validator responsible for validating strings. + * At the moment the only constraint that should be applied to a string feature is the "max length" + */ + class StringValidator implements IValidator + { + public void validate (Object value) throws ValidationException + { + if ((_maxLength != Integer.MIN_VALUE) && (value != null)){ + int length = value.toString().length(); + if (length > _maxLength) { + throw new ValidationException( + ValidationException.MAX_LENGTH, + _maxLength, + _name, + length); + } + } + } + }; + + /** + * Validator responsible for validating numbers. + */ + class NumberValidator implements IValidator + { + public void validate (Object value) throws ValidationException + { + if (value != null) { + double numericValue = ((Number)value).doubleValue(); + if (_minValue != Integer.MIN_VALUE && numericValue < _minValue) { + throw new ValidationException( + ValidationException.MIN_VALUE, + _minValue, + _name, + numericValue); + } + + if (_maxValue != Integer.MIN_VALUE && numericValue > _maxValue) { + throw new ValidationException( + ValidationException.MAX_VALUE, + _maxValue, + _name, + numericValue); + } + } + } + }; + + private AccessMode _accessMode; + private int _minValue = Integer.MIN_VALUE; + private int _maxValue = Integer.MIN_VALUE; + private int _maxLength = Integer.MIN_VALUE; + + private int _optionalIndex; + private int _maskIndex; + + Decoder _decoder = _mandatoryPropertyDecoder; + + private IValidator _validator = EMPTY_VALIDATOR; + + /** + * Validates the given value according to the current validator. + * It delegates the validation to the current installed validator. + * + * @param value the value of this qpid property. + * @throws ValidationException when the given value is violating the current validator constraints. + */ + void validate(Object value) throws ValidationException { + _validator.validate(value); + } + + /** + * Sets the type of this property. + * In addition this method tries to detect if a validator has been associated with the type. + * If no validator is found then the default validator will be used; that is : no validator will be performed on this + * property. + * + * @param type the type of this property. + */ + void setType (Type type) + { + super.setType(type); + try { + Class<?> validatorClass = Class.forName(Configuration.getInstance().getValidatorClassName(type)); + Constructor<?> validatorConstructor = validatorClass.getDeclaredConstructor(QpidProperty.class); + _validator = (IValidator) validatorConstructor.newInstance(this); + LOGGER.debug(Messages.QMAN_200022_VALIDATOR_INSTALLED ,validatorClass.getName(), type); + } catch(Exception exception) { + _validator = EMPTY_VALIDATOR; + LOGGER.debug(Messages.QMAN_200023_VALIDATOR_NOT_FOUND , type); + } + } + + /** + * Gets the value of this property according to its type definition. + * + * @param decoder the decoder used to extract the value. + * @return the value of this feature according to its type definition + */ + Object decodeValue(org.apache.qpid.transport.codec.Decoder decoder,byte [] presenceBitMasks) + { + return _decoder.decodeValue(decoder, presenceBitMasks); + } + + /** + * Sets access mode for this property. + * + * @param accessMode the access mode for this property. + */ + void setAccessMode (AccessMode accessMode) + { + this._accessMode = accessMode; + } + + /** + * Gets the minimum allowed value for this property. + * + * @return the minimum allowed value for this property. + */ + int getMinValue () + { + return _minValue; + } + + /** + * Sets the minimum allowed value for this property. + * + * @param minValue the minimum allowed value for this property. + */ + void setMinValue (int minValue) + { + this._minValue = minValue; + } + + /** + * Gets the maximum allowed value for this property. + * + * @return the maximum allowed value for this property. + */ + int getMaxValue () + { + return _maxValue; + } + + /** + * Sets the masimum allowed value for this property. + * + * @param maxValue the maximum allowed value for this property. + */ + void setMaxValue (int maxValue) + { + this._maxValue = maxValue; + } + + /** + * Gets the max length value for this property. + * + * @return the max length value for this property. + */ + int getMaxLength () + { + return _maxLength; + } + + /** + * Sets the max length value for this property. + * + * @param maxLength the max length value for this property. + */ + void setMaxLength (int maxLength) + { + this._maxLength = maxLength; + } + + /** + * Gets the description of this property. + * + * @return the description of this property. + */ + AccessMode getAccessMode () + { + return _accessMode; + } + + /** + * Marks this property as optional. + * + * @param optional the optional attribute value for this property. + * @param index the index of this optional property + */ + void markAsOptional (int index) + { + this._optionalIndex = index; + this._maskIndex = (_optionalIndex >= 8) ? _optionalIndex-8 : _optionalIndex; + _decoder = _optionalPropertyDecoder; + } + + /** + * Returns true if this property is marked as optional. + * + * @return true if this property is marked as optional, false otherwise. + */ + boolean isOptional () + { + return _decoder == _optionalPropertyDecoder; + } +} diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidStatistic.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidStatistic.java new file mode 100644 index 0000000000..37a652c098 --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/QpidStatistic.java @@ -0,0 +1,34 @@ +/* + * + * 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.domain.model; + +/** + * Qpid statistic definition. + * + * A statistic is a typed member of a class which represents an instrumentation attribute of the class. + * Statistics are always read-only in nature and tend to change rapidly. + * + * @author Andrea Gazzarini + */ +class QpidStatistic extends QpidAttribute +{ + // EMPTY CLASS : Statistic metadata are all defined in superclasses. +}
\ No newline at end of file diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/UnableToBuildFeatureException.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/UnableToBuildFeatureException.java new file mode 100644 index 0000000000..fc4506779b --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/UnableToBuildFeatureException.java @@ -0,0 +1,51 @@ +/* + * + * 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.domain.model; + +/** + * Thrown when a feature (property, statistic, method or event) definition cannot be built due to schema parsing errors. + * + * @author Andrea Gazzarini + */ +public class UnableToBuildFeatureException extends Exception +{ + private static final long serialVersionUID = 5180111828887602836L; + + /** + * Builds a new UnableToBuildFeatureException with the specified cause. + * + * @param exception the exception cause. + */ + UnableToBuildFeatureException(Exception exception, String featureName) + { + super( (featureName != null) ? featureName : "Feature name is not available for debugging purposes." ,exception); + } + + /** + * Builds a new UnableToBuildFeatureException with the specified message. + * + * @param message the detail message. + */ + UnableToBuildFeatureException(String message) + { + super(message); + } +} diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/ValidationException.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/ValidationException.java new file mode 100644 index 0000000000..3b117e5b9d --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/ValidationException.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.management.domain.model; + +/** + * Thrown when an attempt is made in order to update / change the state of an object and a constraint on that state + * is violated. + * + * @author Andrea Gazzarini + */ +public class ValidationException extends Exception +{ + private static final long serialVersionUID = -5218828669655586205L; + + public final static String MAX_LENGTH = "Max Length"; + public final static String MAX_VALUE = "Max Value"; + public final static String MIN_VALUE = "Min Value"; + + private final String _featureName; + private final Object _featureValue; + + private final Number _constraintValue; + private final String _constraintName; + + /** + * Builds a new validation exception with the specified parameters. + * + * @param constraintName the name of the violated constraint. + * @param constraintValue the value of the violated constraint. + * @param featureName the name of the violating feature. + * @param featureValue the value of the violating feature. + */ + ValidationException(String constraintName,Number constraintValue, String featureName,Object featureValue) + { + super(String.format( + "Property constraint violation : " + + "%s allowed for property %s is %s but received value was %s", + constraintName, + featureName, + constraintValue, + featureValue)); + this._constraintName = constraintName; + this._constraintValue = constraintValue; + this._featureName = featureName; + this._featureValue = featureValue; + } + + /** + * Returns the value of the violating feature. + * + * @return the value of the violating feature. + */ + public Object getFeatureValue () + { + return _featureValue; + } + + /** + * Returns the name of the violating feature. + * + * @return the name of the violating feature. + */ + public String getFeatureName() + { + return _featureName; + } + + /** + * Returns the value of the violated constraint. + * + * @return the value of the violated constraint. + */ + public Number getConstraintValue () + { + return _constraintValue; + } + + /** + * Returns the name of the violated constraint. + * + * @return the name of the violated constraint. + */ + public String getConstraintName () + { + return _constraintName; + } +}
\ No newline at end of file diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/AbsTime.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/AbsTime.java new file mode 100644 index 0000000000..28f5f70c04 --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/AbsTime.java @@ -0,0 +1,44 @@ +/* + * + * 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.domain.model.type; + +import org.apache.qpid.transport.codec.Decoder; +import org.apache.qpid.transport.codec.Encoder; + +public class AbsTime extends Type +{ + public AbsTime() + { + super(Long.class); + } + + @Override + public Object decode (Decoder decoder) + { + return decoder.readInt64(); + } + + @Override + public void encode (Object value, Encoder encoder) + { + encoder.writeInt64((Long)value); + } +}
\ No newline at end of file diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Binary.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Binary.java new file mode 100644 index 0000000000..8009150eb2 --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Binary.java @@ -0,0 +1,151 @@ +/* + * + * 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.domain.model.type; + +import java.io.Serializable; +import java.util.Arrays; +import java.util.UUID; + +import org.apache.qpid.management.messages.AmqpCoDec; +import org.apache.qpid.transport.codec.Encoder; + +/** + * It is a simple wrapper for a byte array (for example a 128bin). + * It is used to let QMan deal with an object instead of an array. + * + * @author Andrea Gazzarini + */ +public final class Binary implements Serializable +{ + private static final long serialVersionUID = -6865585077320637567L; + + // Marker internal (empty) interface + private interface State extends Serializable{} + + /** + * Internal state of this object used to denote the situation when the hashcode() method has never been called. + * After the hashcode has been computed this class switches the state of the outer object to the next state. + */ + State hashCodeNotYetComputed = new State() + { + private static final long serialVersionUID = 221632033761266959L; + + @Override + public int hashCode () + { + hashCode = Arrays.hashCode(_bytes); + state = hashCodeAlreadyComputed; + return hashCode; + } + }; + + /** + * Internal state of this object used to denote the situation where the hashcode() method has already been computed. + * Simply it returns the just computed value for the hashcode. + */ + State hashCodeAlreadyComputed = new State() + { + private static final long serialVersionUID = 221632033761266959L; + + @Override + public int hashCode () + { + return hashCode; + } + }; + + private final UUID uuid; + private final byte [] _bytes; + private long _first; + private int hashCode; + + /** Current state (hashcode computation). */ + State state = hashCodeNotYetComputed; + + /** + * Builds a new binary with the given byte array. + * + * @param bytes the wrapped data. + */ + public Binary(byte [] bytes) + { + this._bytes = bytes; + byte [] array = new byte [8]; + System.arraycopy(_bytes, 0, array, 0, 8); + _first = AmqpCoDec.unpack64(array); + uuid = UUID.randomUUID(); + } + + @Override + public int hashCode () + { + return state.hashCode(); + } + + @Override + public boolean equals (Object obj) + { + try + { + Binary binary = (Binary)obj; + return Arrays.equals(_bytes, binary._bytes); + } catch (Exception exception) + { + return false; + } + } + + /** + * Encodes the content (wrapped byte array) of this instance using the given encoder. + * + * @param encoder the encoder used to encode instance content. + */ + public void encode(Encoder encoder) + { + encoder.writeBin128(_bytes); + } + + @Override + public String toString () + { + return uuid.toString(); + } + + /** + * Returns the bank identifier derived from this object identifier. + * + * @return the bank identifier derived from this object identifier. + */ + public long getBankId() + { + return _first & 0x000000000FFFFFFF; + } + + /** + * Returns the broker identifier derived from this object identifier. + * + * @return the broker identifier derived from this object identifier. + */ + public long getBrokerId() + { + return (_first & 281474708275200L) >> 28; + } +} diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Boolean.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Boolean.java new file mode 100644 index 0000000000..c339b870ac --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Boolean.java @@ -0,0 +1,44 @@ +/* + * + * 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.domain.model.type; + +import org.apache.qpid.transport.codec.Decoder; +import org.apache.qpid.transport.codec.Encoder; + +public class Boolean extends Type +{ + public Boolean() + { + super(java.lang.Boolean.class); + } + + @Override + public Object decode (Decoder decoder) + { + return (decoder.readUint8() == 1); + } + + @Override + public void encode (Object value, Encoder encoder) + { + encoder.writeUint8( ((java.lang.Boolean)value) ? (short)1 : 0 ); + } +}
\ No newline at end of file diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/DeltaTime.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/DeltaTime.java new file mode 100644 index 0000000000..a788e2f8e1 --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/DeltaTime.java @@ -0,0 +1,44 @@ +/* + * + * 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.domain.model.type; + +import org.apache.qpid.transport.codec.Decoder; +import org.apache.qpid.transport.codec.Encoder; + +public class DeltaTime extends Type +{ + public DeltaTime() + { + super(Long.class); + } + + @Override + public Object decode (Decoder decoder) + { + return decoder.readUint64(); + } + + @Override + public void encode (Object value, Encoder encoder) + { + encoder.writeUint64((Long)value); + } +}
\ No newline at end of file diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Double.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Double.java new file mode 100644 index 0000000000..d36af3d3df --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Double.java @@ -0,0 +1,44 @@ +/*
+ *
+ * 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.domain.model.type;
+
+import org.apache.qpid.transport.codec.Decoder;
+import org.apache.qpid.transport.codec.Encoder;
+
+public class Double extends Type
+{
+ public Double()
+ {
+ super(java.lang.Double.class);
+ }
+
+ @Override
+ public Object decode(Decoder decoder)
+ {
+ return decoder.readDouble();
+ }
+
+ @Override
+ public void encode(Object value, Encoder encoder)
+ {
+ encoder.writeDouble((java.lang.Double)value);
+ }
+}
diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Float.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Float.java new file mode 100644 index 0000000000..cb1f6e78a7 --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Float.java @@ -0,0 +1,44 @@ +/*
+ *
+ * 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.domain.model.type;
+
+import org.apache.qpid.transport.codec.Decoder;
+import org.apache.qpid.transport.codec.Encoder;
+
+public class Float extends Type
+{
+ public Float()
+ {
+ super(java.lang.Float.class);
+ }
+
+ @Override
+ public Object decode(Decoder decoder)
+ {
+ return decoder.readFloat();
+ }
+
+ @Override
+ public void encode(Object value, Encoder encoder)
+ {
+ encoder.writeFloat((java.lang.Float)value);
+ }
+}
diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Int16.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Int16.java new file mode 100644 index 0000000000..f4685f0295 --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Int16.java @@ -0,0 +1,44 @@ +/* + * + * 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.domain.model.type; + +import org.apache.qpid.transport.codec.Decoder; +import org.apache.qpid.transport.codec.Encoder; + +public class Int16 extends Type +{ + public Int16() + { + super(Short.class); + } + + @Override + public Object decode (Decoder decoder) + { + return decoder.readInt16(); + } + + @Override + public void encode (Object value, Encoder encoder) + { + encoder.writeInt16((Short)value); + } +}
\ No newline at end of file diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Int32.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Int32.java new file mode 100644 index 0000000000..ae5be90a2d --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Int32.java @@ -0,0 +1,44 @@ +/* + * + * 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.domain.model.type; + +import org.apache.qpid.transport.codec.Decoder; +import org.apache.qpid.transport.codec.Encoder; + +public class Int32 extends Type +{ + public Int32() + { + super(Integer.class); + } + + @Override + public Object decode (Decoder decoder) + { + return decoder.readInt32(); + } + + @Override + public void encode (Object value, Encoder encoder) + { + encoder.writeInt32((Integer)value); + } +}
\ No newline at end of file diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Int64.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Int64.java new file mode 100644 index 0000000000..f76818344e --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Int64.java @@ -0,0 +1,44 @@ +/* + * + * 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.domain.model.type; + +import org.apache.qpid.transport.codec.Decoder; +import org.apache.qpid.transport.codec.Encoder; + +public class Int64 extends Type +{ + public Int64() + { + super(Long.class); + } + + @Override + public Object decode (Decoder decoder) + { + return decoder.readInt64(); + } + + @Override + public void encode (Object value, Encoder encoder) + { + encoder.writeInt64((Long)value); + } +}
\ No newline at end of file diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Int8.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Int8.java new file mode 100644 index 0000000000..6f7c3b24d0 --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Int8.java @@ -0,0 +1,44 @@ +/* + * + * 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.domain.model.type; + +import org.apache.qpid.transport.codec.Decoder; +import org.apache.qpid.transport.codec.Encoder; + +public class Int8 extends Type +{ + public Int8() + { + super(Byte.class); + } + + @Override + public Object decode (Decoder decoder) + { + return decoder.readInt8(); + } + + @Override + public void encode (Object value, Encoder encoder) + { + encoder.writeInt8((Byte)value); + } +}
\ No newline at end of file diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Map.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Map.java new file mode 100644 index 0000000000..cc540ff4da --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Map.java @@ -0,0 +1,44 @@ +/* + * + * 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.domain.model.type; + +import org.apache.qpid.transport.codec.Decoder; +import org.apache.qpid.transport.codec.Encoder; + +public class Map extends Type +{ + public Map() + { + super(java.util.Map.class); + } + + @Override + public Object decode (Decoder decoder) + { + return decoder.readMap(); + } + + @Override + public void encode (Object value, Encoder encoder) + { + encoder.writeMap((java.util.Map<String, Object>)value); + } +}
\ No newline at end of file diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/ObjectReference.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/ObjectReference.java new file mode 100644 index 0000000000..13e1b68d26 --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/ObjectReference.java @@ -0,0 +1,44 @@ +/* + * + * 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.domain.model.type; + +import org.apache.qpid.transport.codec.Decoder; +import org.apache.qpid.transport.codec.Encoder; + +public class ObjectReference extends Type +{ + public ObjectReference() + { + super(byte[].class); + } + + @Override + public Object decode (Decoder decoder) + { + return decoder.readBin128(); + } + + @Override + public void encode (Object value, Encoder encoder) + { + ((Binary)value).encode(encoder); + } +}
\ No newline at end of file diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Str16.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Str16.java new file mode 100644 index 0000000000..42829ce176 --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Str16.java @@ -0,0 +1,44 @@ +/* + * + * 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.domain.model.type; + +import org.apache.qpid.transport.codec.Decoder; +import org.apache.qpid.transport.codec.Encoder; + +public class Str16 extends Type +{ + public Str16() + { + super(String.class); + } + + @Override + public Object decode (Decoder decoder) + { + return decoder.readStr16(); + } + + @Override + public void encode (Object value, Encoder encoder) + { + encoder.writeStr16((String)value); + } +}
\ No newline at end of file diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Str8.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Str8.java new file mode 100644 index 0000000000..f9b747ce6d --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Str8.java @@ -0,0 +1,44 @@ +/* + * + * 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.domain.model.type; + +import org.apache.qpid.transport.codec.Decoder; +import org.apache.qpid.transport.codec.Encoder; + +public class Str8 extends Type +{ + public Str8() + { + super(String.class); + } + + @Override + public Object decode (Decoder decoder) + { + return decoder.readStr8(); + } + + @Override + public void encode (Object value, Encoder encoder) + { + encoder.writeStr8((String)value); + } +}
\ No newline at end of file diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Type.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Type.java new file mode 100644 index 0000000000..c455faaf2c --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Type.java @@ -0,0 +1,101 @@ +/* + * + * 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.domain.model.type; + +import org.apache.qpid.transport.codec.Decoder; +import org.apache.qpid.transport.codec.Encoder; + +/** + * Layer supertype for all management "types". + * + * @author Andrea Gazzarini + */ +public abstract class Type +{ + /** Java representation of this type. */ + protected final Class<?> javaType; + + /** + * Builds a new management type wiich wraps the given java type. + * + * @param javaType the java type. + */ + Type(Class<?> javaType) + { + this.javaType = javaType; + } + + /** + * Returns the wrapped java type. + * + * @return the wrapped java type. + */ + public Class<?> getJavaType () + { + return javaType; + } + + /** + * Each concrete subclass must define here how to decode incoming data according. + * + * @param decoder the decoder used to extract data. + * @return the "typed" value. + * + */ + public abstract Object decode(Decoder decoder); + + /** + * Returns a string representation of this type. + * + * @return a string representation of this type. + */ + @Override + public String toString () + { + return new StringBuilder(getClass().getName()) + .append(" (wraps ") + .append(javaType.getName()) + .append(')').toString(); + } + + /** + * Identity for types is based on wrapped java type identity. + */ + @Override + public boolean equals (Object obj) + { + return getClass() == obj.getClass(); + } + + @Override + public int hashCode () + { + return getClass().hashCode(); + } + + /** + * Encodes the given values according to this type definition. + * + * @param value the value to be encoded. + * @param encoder the encoder. + */ + public abstract void encode (Object value,Encoder encoder); +}
\ No newline at end of file diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Uint16.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Uint16.java new file mode 100644 index 0000000000..2d3edd41ea --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Uint16.java @@ -0,0 +1,44 @@ +/* + * + * 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.domain.model.type; + +import org.apache.qpid.transport.codec.Decoder; +import org.apache.qpid.transport.codec.Encoder; + +public class Uint16 extends Type +{ + public Uint16() + { + super(Integer.class); + } + + @Override + public Object decode (Decoder decoder) + { + return new Integer(decoder.readUint16()); + } + + @Override + public void encode (Object value, Encoder encoder) + { + encoder.writeUint16((Integer)value); + } +}
\ No newline at end of file diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Uint32.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Uint32.java new file mode 100644 index 0000000000..c5fb981bb0 --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Uint32.java @@ -0,0 +1,44 @@ +/* + * + * 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.domain.model.type; + +import org.apache.qpid.transport.codec.Decoder; +import org.apache.qpid.transport.codec.Encoder; + +public class Uint32 extends Type +{ + public Uint32() + { + super(Long.class); + } + + @Override + public Object decode (Decoder decoder) + { + return new Long(decoder.readUint32()); + } + + @Override + public void encode (Object value, Encoder encoder) + { + encoder.writeUint32((Long)value); + } +} diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Uint64.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Uint64.java new file mode 100644 index 0000000000..9182f883bf --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Uint64.java @@ -0,0 +1,44 @@ +/* + * + * 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.domain.model.type; + +import org.apache.qpid.transport.codec.Decoder; +import org.apache.qpid.transport.codec.Encoder; + +public class Uint64 extends Type +{ + public Uint64() + { + super(Long.class); + } + + @Override + public Object decode (Decoder decoder) + { + return new Long(decoder.readUint64()); + } + + @Override + public void encode (Object value, Encoder encoder) + { + encoder.writeUint64((Long)value); + } +}
\ No newline at end of file diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Uint8.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Uint8.java new file mode 100644 index 0000000000..ab7e78856c --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Uint8.java @@ -0,0 +1,44 @@ +/* + * + * 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.domain.model.type; + +import org.apache.qpid.transport.codec.Decoder; +import org.apache.qpid.transport.codec.Encoder; + +public class Uint8 extends Type +{ + public Uint8() + { + super(Short.class); + } + + @Override + public Object decode (Decoder decoder) + { + return new Short(decoder.readUint8()); + } + + @Override + public void encode (Object value, Encoder encoder) + { + encoder.writeUint8((Short)value); + } +}
\ No newline at end of file diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Uuid.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Uuid.java new file mode 100644 index 0000000000..1b3be954d6 --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/model/type/Uuid.java @@ -0,0 +1,46 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.management.domain.model.type; + +import java.util.UUID; + +import org.apache.qpid.transport.codec.Decoder; +import org.apache.qpid.transport.codec.Encoder; + +public class Uuid extends Type +{ + public Uuid() + { + super(UUID.class); + } + + @Override + public Object decode (Decoder decoder) + { + return decoder.readUuid(); + } + + @Override + public void encode (Object value, Encoder encoder) + { + encoder.writeUuid((UUID)value); + } +}
\ No newline at end of file diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/services/BrokerMessageListener.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/services/BrokerMessageListener.java new file mode 100644 index 0000000000..aa588043aa --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/services/BrokerMessageListener.java @@ -0,0 +1,177 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.management.domain.services; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; + +import org.apache.qpid.api.Message; +import org.apache.qpid.management.Messages; +import org.apache.qpid.management.Protocol; +import org.apache.qpid.management.domain.handler.base.IMessageHandler; +import org.apache.qpid.management.domain.model.DomainModel; +import org.apache.qpid.nclient.util.MessageListener; +import org.apache.qpid.transport.codec.BBDecoder; +import org.apache.qpid.transport.util.Logger; + +/** + * Message listener used for processing incoming messages. + * So it is installed as a consumer on a specific channel and when a new message arrives: + * + * 1) Performs a sanity check on the message (magic number, sequence number) + * 2) Extracts the opcode and looks for one message handler associated with that opcode. + * 3) If a message handler is found the delegates the message processing; otherwise a log message is written to indicate + * that the message will be skipped. + * + * @author Andrea Gazzarini + */ +class BrokerMessageListener implements MessageListener +{ + private final static Logger LOGGER = Logger.get(BrokerMessageListener.class); + + private static class Log + { + // Debugs the content of the incoming message. + static void debugIncomingMessage(ByteBuffer message) + { + if (LOGGER.isDebugEnabled()) + { + LOGGER.debug(Messages.QMAN_200001_INCOMING_MESSAGE_HAS_BEEN_RECEIVED, Arrays.toString(message.array())); + } + } + + // Debugs all the configured handlers. + static void debugConfiguredHandlers (Map<Character, IMessageHandler> _handlers) + { + if (LOGGER.isDebugEnabled()) + { + for (Entry<Character, IMessageHandler> entry : _handlers.entrySet()) + { + LOGGER.debug(Messages.QMAN_200002_OPCODE_HANDLER_ASSOCIATION,entry.getKey(),entry.getValue()); + } + } + } + } + + Map<Character, IMessageHandler> _handlers = new HashMap<Character, IMessageHandler>(); + private DomainModel _domainModel; + + /** + * Builds a new message listener with the given broker domain model. + * + * @param model the managed broker domain model. + */ + BrokerMessageListener(DomainModel model) + { + this._domainModel = model; + } + + /** + * When a new message arrives this method is called. + * 1) Performs a sanity check on the message (magic number, sequence number) + * 2) Extracts the opcode and looks for one message handler associated with that opcode. + * 3) If a message handler is found the delegates the message processing; otherwise a log message is written to indicate + * that the message will be skipped. + * + * @param message the incoming message. + */ + public void onMessage (Message compoundMessage) + { + try + { + MessageTokenizer tokenizer = new MessageTokenizer(compoundMessage); + while (tokenizer.hasMoreElements()) + { + dispatch(tokenizer.nextElement()); + } + } catch(IOException exception) + { + LOGGER.error(exception,Messages.QMAN_100002_MESSAGE_READ_FAILURE); + } catch(Exception exception) + { + LOGGER.error(exception,Messages.QMAN_100003_MESSAGE_PROCESS_FAILURE); + } + } + + /** + * Configures a new handler with this listener. + * After that, each time a message arrives with the specified opcode, this handler will be responsible for + * processing. + * Note that calling this method will switch this listener to a WORKING state. + * + * @param opcode the operation code. + * @param handler the message handler. + */ + void setHandlers(Map<Character, IMessageHandler> handlers) + { + for (Entry<Character, IMessageHandler> entry : handlers.entrySet()) + { + char opcode = entry.getKey(); + IMessageHandler handler = entry.getValue(); + try + { + handler.setDomainModel(_domainModel); + _handlers.put(opcode, handler); + } catch(Exception exception) { + LOGGER.error(exception,Messages.QMAN_100004_HANDLER_INITIALIZATION_FAILURE, opcode); + } + } + } + + /** + * Dispatches the given message to the appropriate handler. + * + * @param message the incoming message. + * @throws IOException when the message content cannot be read. + */ + private void dispatch(Message message) throws IOException + { + ByteBuffer buffer = message.readData(); + + String magicNumber = new String(new byte[] {buffer.get(),buffer.get(),buffer.get()}); + if (!Protocol.MAGIC_NUMBER.equals(magicNumber)) + { + LOGGER.error(Messages.QMAN_100001_BAD_MAGIC_NUMBER_FAILURE,magicNumber); + return; + } + + char opcode = (char)buffer.get(); + + IMessageHandler handler = _handlers.get(opcode); + if (handler != null) + { + BBDecoder decoder = new BBDecoder(); + decoder.init(buffer); + + LOGGER.debug(Messages.QMAN_200003_MESSAGE_FORWARDING,opcode,handler); + + handler.process(decoder,decoder.readSequenceNo()); + } else + { + LOGGER.warn(Messages.QMAN_300001_MESSAGE_DISCARDED,opcode); + Log.debugConfiguredHandlers(_handlers); + } + } +} diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/services/ManagementClient.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/services/ManagementClient.java new file mode 100644 index 0000000000..a3584571f3 --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/services/ManagementClient.java @@ -0,0 +1,231 @@ +/* + * + * 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.domain.services; + +import java.util.UUID; + +import org.apache.qpid.QpidException; +import org.apache.qpid.management.Messages; +import org.apache.qpid.management.Names; +import org.apache.qpid.management.configuration.BrokerConnectionData; +import org.apache.qpid.management.configuration.Configuration; +import org.apache.qpid.management.domain.model.DomainModel; +import org.apache.qpid.transport.util.Logger; + +/** + * This is the Object representation of a management client. + * According to specification : "A software component that is separate from the messaging broker, connected to the + * management broker via an AMQP connection, which allows any software component to be managed remotely by QPID." + * + * @author Andrea Gazzarini + */ +final class ManagementClient +{ + private final static Logger LOGGER = Logger.get(ManagementClient.class); + + private final String _managementQueueName; + private final String _methodReplyQueueName; + + private DomainModel _domainModel; + private QpidService _service; + + /** + * Builds a new <code>ManagementClient</code> with the given identifier and connection data. + * + * @param brokerId the broker identifier. + * @param connectionData the broker connection data (host, port, etc...) + */ + ManagementClient(UUID brokerId,BrokerConnectionData connectionData) + { + _service = new QpidService(brokerId); + _domainModel = new DomainModel(brokerId); + _managementQueueName = Configuration.getInstance().getManagementQueueName(); + _methodReplyQueueName = Configuration.getInstance().getMethodReplyQueueName(); + } + + /** + * Establishing initial communication Between Client and Broker. + * According to specification : + * "Communication is established between the management client and management agent using normal AMQP procedures. + * The client creates a connection to the broker and then establishes a session with its corresponding channel. + * Two private queues are then declared. + * A management queue is declared and bound to the qpid.management exchange with "mgmt.#" as routing key; in that + * way all management-related messages sent to the exchange will be received by this client. + * When a client successfully binds to the qpid.management exchange, the management agent schedules a schema + * broadcast to be sent to the exchange. + * The agent will publish, via the exchange, a description of the schema for all manageable objects in its control. That + * schema is therefore received by this service and it will be part of service's domain model." + * + * @throws StartupFailureException when this management client cannot perform startup operations due to an error. + */ + void estabilishFirstConnectionWithBroker() throws StartupFailureException{ + try { + connectWithBroker(); + + createAndBindMethodReplyQueue(); + createAndBindManagementQueue(); + + registerConsumerOnManagementQueue(); + registerConsumerOnMethodReplyQueue(); + + synchronize(); + } catch(Exception exception) + { + try { + _service.close(); + } catch(Exception ignore) + { + } + throw new StartupFailureException(exception); + } + } + + /** + * Shutdown procedure for this management client. + */ + void shutdown () + { + LOGGER.info(Messages.QMAN_000011_SHUTDOWN_INITIATED,_domainModel.getBrokerId()); + + removeMethodReplyConsumer(); + destroyAndUnbingMethodReplyQueue(); + + removeManagementConsumer(); + destroyAndUnbingManagementQueue(); + + _domainModel.releaseResources(); + + _service.close(); + + LOGGER.info(Messages.QMAN_000012_MANAGEMENT_CLIENT_SHUT_DOWN,_domainModel.getBrokerId()); + } + + /** + * Registers a consumer (that is, a listener) on the method-reply queue. + */ + private void registerConsumerOnMethodReplyQueue () + { + BrokerMessageListener methodReplyChannelListener = new BrokerMessageListener(_domainModel); + methodReplyChannelListener.setHandlers(Configuration.getInstance().getMethodReplyQueueHandlers()); + _service.createSubscription(_methodReplyQueueName, _methodReplyQueueName, methodReplyChannelListener); + + LOGGER.info(Messages.QMAN_000013_METHOD_REPLY_CONSUMER_INSTALLED, _domainModel.getBrokerId()); + } + + /** + * Registers a consumer (listener) on the management queue. + */ + private void registerConsumerOnManagementQueue () throws QpidException + { + BrokerMessageListener managementChannelListener = new BrokerMessageListener(_domainModel); + managementChannelListener.setHandlers(Configuration.getInstance().getManagementQueueHandlers()); + _service.createSubscription(_managementQueueName, _managementQueueName, managementChannelListener); + + LOGGER.info(Messages.QMAN_000014_MANAGEMENT_CONSUMER_INSTALLED, _domainModel.getBrokerId()); + } + + /** + * Declares a management queue and bound it to the "qpid.management" exchange with "mgmt.#" as routing key; + */ + private void createAndBindManagementQueue () + { + _service.declareQueue(_managementQueueName); + _service.declareBinding( + _managementQueueName, + Names.MANAGEMENT_EXCHANGE, + Names.MANAGEMENT_ROUTING_KEY); + + LOGGER.info(Messages.QMAN_000015_MANAGEMENT_QUEUE_DECLARED,_managementQueueName,_domainModel.getBrokerId()); + } + + /** + * Declares a private queue for receiving method replies (after method invocations). + * This queue is bound to the amq.direct exchange using a routing key equal to the name of the queue. + */ + private void createAndBindMethodReplyQueue () + { + _service.declareQueue(_methodReplyQueueName); + _service.declareBinding(_methodReplyQueueName, Names.AMQ_DIRECT_QUEUE, _methodReplyQueueName); + + LOGGER.info(Messages.QMAN_000016_METHOD_REPLY_QUEUE_DECLARED,_methodReplyQueueName, _domainModel.getBrokerId()); + } + + /** + * Removes the method-reply queue consumer. + */ + private void removeMethodReplyConsumer() + { + _service.removeSubscription(_methodReplyQueueName); + + LOGGER.info(Messages.QMAN_000017_CONSUMER_HAS_BEEN_REMOVED,_methodReplyQueueName,_domainModel.getBrokerId()); + } + + /** + * Unbind the method reply queue and after that destroy it from remote broker. + */ + private void destroyAndUnbingMethodReplyQueue() + { + _service.declareUnbinding(_methodReplyQueueName, Names.AMQ_DIRECT_QUEUE, _methodReplyQueueName); + _service.deleteQueue(_methodReplyQueueName); + + LOGGER.info(Messages.QMAN_000018_QUEUE_UNDECLARED,_methodReplyQueueName,_domainModel.getBrokerId()); + } + + /** + * Removes the management queue consumer. + */ + private void removeManagementConsumer() + { + _service.removeSubscription(_managementQueueName); + + LOGGER.info(Messages.QMAN_000017_CONSUMER_HAS_BEEN_REMOVED,_managementQueueName,_domainModel.getBrokerId()); + } + + /** + * Unbind the management queue and after that destroy it from remote broker. + */ + private void destroyAndUnbingManagementQueue() + { + _service.declareUnbinding(_managementQueueName, Names.MANAGEMENT_EXCHANGE, Names.MANAGEMENT_ROUTING_KEY); + _service.deleteQueue(_managementQueueName); + + LOGGER.info(Messages.QMAN_000018_QUEUE_UNDECLARED, _managementQueueName,_domainModel.getBrokerId()); + } + + /** + * Connects this client with the broker. + * + * @throws QpidException when it's not possibile to connect with the broker. + */ + private void connectWithBroker() throws Exception + { + _service.connect(); + } + + /** + * All the Management client commands are asynchronous. + * Synchronous behavior is achieved through invoking the sync method. + */ + private void synchronize() + { + _service.sync(); + } +} diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/services/MessageTokenizer.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/services/MessageTokenizer.java new file mode 100644 index 0000000000..9275255517 --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/services/MessageTokenizer.java @@ -0,0 +1,152 @@ +/*
+*
+ * 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.domain.services;
+
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.LinkedList;
+
+import org.apache.qpid.api.Message;
+import org.apache.qpid.management.Messages;
+import org.apache.qpid.management.Protocol;
+import org.apache.qpid.nclient.util.ByteBufferMessage;
+import org.apache.qpid.transport.codec.BBDecoder;
+import org.apache.qpid.transport.util.Logger;
+
+/**
+ * The message tokenizer class allows a multi message listener to break a
+ * message into tokens where each token is itself a valid AMQP message.
+ *
+ * @author Andrea Gazzarini
+ * @see QPID-1368
+ */
+class MessageTokenizer implements Enumeration<Message>
+{
+ private final static Logger LOGGER = Logger.get(MessageTokenizer.class);
+
+ static byte [] MAGIC_NUMBER_BYTES;
+
+ private LinkedList<Message> _messages = new LinkedList<Message>();
+ private Iterator<Message> _iterator;
+
+ static
+ {
+ try
+ {
+ MAGIC_NUMBER_BYTES = Protocol.MAGIC_NUMBER.getBytes("UTF-8");
+ } catch(Exception exception)
+ {
+ throw new ExceptionInInitializerError(exception);
+ }
+ }
+
+ /**
+ * Builds a new Message tokenizer with the given message.
+ * Note that if the given message is not a "compound" message this tokenizer will producer only one token;
+ * That is, the token is a message equals to the given message.
+ *
+ * @param compoundMessage the compound message
+ * @throws IOException when it's not possible to read the given message content.
+ */
+ MessageTokenizer(Message compoundMessage) throws IOException
+ {
+ build(compoundMessage);
+ }
+
+ public boolean hasMoreElements()
+ {
+ return _iterator.hasNext();
+ }
+
+ public Message nextElement()
+ {
+ return _iterator.next();
+ }
+
+ /**
+ * Retruns the number of the tokens produced by this tokenizer.
+ *
+ * @return the number of the tokens produced by this tokenizer.
+ */
+ public int countTokens()
+ {
+ return _messages.size();
+ }
+
+ // Internal methods used for splitting the multi message byte array.
+ int indexOf(byte[] source, int startIndex)
+ {
+ int currentSourceIndex;
+ int currentExampleIndex;
+
+ if (startIndex + 3 > source.length)
+ return -1;
+
+ for (currentSourceIndex = startIndex; currentSourceIndex <= source.length - 3; currentSourceIndex++)
+ {
+ for (currentExampleIndex = 0; currentExampleIndex < 3; currentExampleIndex++)
+ {
+ if (source[currentSourceIndex + currentExampleIndex] != MAGIC_NUMBER_BYTES[currentExampleIndex])
+ break;
+ }
+
+ if (currentExampleIndex == 3)
+ return currentSourceIndex;
+ }
+ return -1;
+ }
+
+ // Internal method used for building the tokens.
+ private void build(Message compoundMessage) throws IOException
+ {
+ int startIndex = 0;
+ int indexOfMagicNumber = 0;
+
+ BBDecoder decoder = new BBDecoder();
+ decoder.init(compoundMessage.readData());
+ byte [] source = decoder.readReaminingBytes();
+
+ int howManyTokens = 1;
+
+ while ((indexOfMagicNumber = indexOf(source, startIndex+1)) != -1)
+ {
+ addMessageToken(source, startIndex, (indexOfMagicNumber-startIndex));
+ startIndex = indexOfMagicNumber;
+ howManyTokens++;
+ }
+ addMessageToken(source, startIndex, (source.length-startIndex));
+ _iterator = _messages.iterator();
+
+ LOGGER.debug(Messages.QMAN_200031_COMPOUND_MESSAGE_CONTAINS,howManyTokens);
+ };
+
+ // Builds & adds a new "message" token
+ private void addMessageToken(byte [] source,int startIndex,int length) throws IOException
+ {
+ byte [] messageData = new byte[length];
+ System.arraycopy(source, startIndex, messageData, 0, messageData.length);
+ Message message = new ByteBufferMessage();
+ message.appendData(messageData);
+ _messages.add(message);
+ }
+}
diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/services/MethodInvocationException.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/services/MethodInvocationException.java new file mode 100644 index 0000000000..26fd8eee24 --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/services/MethodInvocationException.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.management.domain.services; + +public class MethodInvocationException extends Exception +{ + private static final long serialVersionUID = -7772343434879470351L; + private final long _returnCode; + private final String _statusText; + + public MethodInvocationException(long code, String text) + { + this._returnCode = code; + this._statusText = text; + } + + @Override + public String getMessage () + { + return String.format("Return code : \"%s, reason : \"%s\"",_returnCode,_statusText); + } + + public long getReturnCode () + { + return _returnCode; + } + + public String getStatusText () + { + return _statusText; + } +}
\ No newline at end of file diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/services/QMan.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/services/QMan.java new file mode 100644 index 0000000000..600b54a6c9 --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/services/QMan.java @@ -0,0 +1,365 @@ +/* + * + * 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.domain.services; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.Map.Entry; + +import javax.management.Attribute; +import javax.management.AttributeList; +import javax.management.DynamicMBean; +import javax.management.MBeanException; +import javax.management.MBeanInfo; +import javax.management.MBeanOperationInfo; +import javax.management.MBeanParameterInfo; +import javax.management.ReflectionException; + +import org.apache.log4j.xml.DOMConfigurator; +import org.apache.qpid.management.Messages; +import org.apache.qpid.management.Names; +import org.apache.qpid.management.configuration.BrokerAlreadyConnectedException; +import org.apache.qpid.management.configuration.BrokerConnectionData; +import org.apache.qpid.management.configuration.BrokerConnectionException; +import org.apache.qpid.management.configuration.Configuration; +import org.apache.qpid.management.configuration.Configurator; +import org.apache.qpid.management.domain.model.JmxService; +import org.apache.qpid.transport.util.Logger; + +/** + * Main entry point for starting Q-Man application. + * + * @author Andrea Gazzarini + */ +public class QMan implements DynamicMBean +{ + private final static Logger LOGGER = Logger.get(QMan.class); + private final List<ManagementClient> managementClients = new ArrayList<ManagementClient>(); + + /** + * Starts QMan. + * @throws StartupFailureException when it's not possible to proceed with startup. + */ + public void start() throws StartupFailureException + { + LOGGER.info(Messages.QMAN_000001_STARTING_QMAN); + LOGGER.info(Messages.QMAN_000002_READING_CONFIGURATION); + + Configurator configurator = new Configurator(); + try + { + configurator.configure(); + Configuration configuration = Configuration.getInstance(); + if (configuration.hasOneOrMoreBrokersDefined()) + { + LOGGER.info(Messages.QMAN_000003_CREATING_MANAGEMENT_CLIENTS); + for (Entry<UUID, BrokerConnectionData> entry : Configuration.getInstance().getConnectionInfos()) + { + createManagementClient(entry.getKey(), entry.getValue()); + } + } else + { + LOGGER.info(Messages.QMAN_000022_NO_BROKER_CONFIGURED); + } + + registerQManService(); + + LOGGER.info(Messages.QMAN_000019_QMAN_STARTED); + } catch(Exception exception) { + LOGGER.error(exception,Messages.QMAN_100018_UNABLE_TO_STARTUP_CORRECTLY ); + throw new StartupFailureException(exception); + } + } + + /** + * Creates a management client using the given data. + * + * @param brokerId the broker identifier. + * @param data the broker connection data. + */ + private void createManagementClient(UUID brokerId, BrokerConnectionData data) + { + try + { + ManagementClient client = new ManagementClient(brokerId,data); + client.estabilishFirstConnectionWithBroker(); + managementClients.add(client); + + LOGGER.info(Messages.QMAN_000004_MANAGEMENT_CLIENT_CONNECTED,brokerId); + } catch(StartupFailureException exception) { + LOGGER.error(exception, Messages.QMAN_100017_UNABLE_TO_CONNECT,brokerId,data); + } + } + + /** + * Connects Q-Man with a broker defined by the given parameter. + * + * @param host the hostname where the broker is running. + * @param port the port where the broker is running. + * @param username the username for connecting with the broker. + * @param password the password for connecting with the broker. + * @param virtualHost the virtual host. + * @param initialPoolCapacity the number of the connection that must be immediately opened. + * @param maxPoolCapacity the maximum number of opened connection. + * @param maxWaitTimeout the maximum amount of time that a client will wait for obtaining a connection. + * @throws MBeanException when it's not possible to connect with the broker. + */ + public void addBroker( + String host, + int port, + String username, + String password, + String virtualHost, + int initialPoolCapacity, + int maxPoolCapacity, + long maxWaitTimeout) throws BrokerAlreadyConnectedException, BrokerConnectionException + { + Configurator configurator = new Configurator(); + try { + UUID brokerId = UUID.randomUUID(); + BrokerConnectionData data = configurator.createAndReturnBrokerConnectionData( + brokerId, + host, + port, + username, + password, + virtualHost, + initialPoolCapacity, + maxPoolCapacity, + maxWaitTimeout); + createManagementClient(brokerId, data); + } catch (BrokerAlreadyConnectedException exception) + { + LOGGER.warn(Messages.QMAN_300003_BROKER_ALREADY_CONNECTED, exception.getBrokerConnectionData()); + throw exception; + } + } + + /** + * Stop Qman + */ + public void stop() + { + LOGGER.info(Messages.QMAN_000020_SHUTTING_DOWN_QMAN); + try + { + for (ManagementClient client : managementClients) + { + client.shutdown(); + } + } catch(Exception exception) + { + } + LOGGER.info(Messages.QMAN_000021_SHUT_DOWN); + } + + /** + * Main method used for starting Q-Man. + * + * @param args the command line arguments. + */ + public static void main (String[] args) + { + if (args.length == 1) + { + String logFileName = args[0]; + DOMConfigurator.configureAndWatch(logFileName,5000); + } + + final QMan qman = new QMan(); + + Thread hook = new Thread() + { + @Override + public void run () + { + qman.stop(); + } + }; + + Runtime.getRuntime().addShutdownHook(hook); + try + { + qman.start(); + + System.out.println("Type \"q\" to quit."); + BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); + while ( !"q".equals(reader.readLine()) ) + { + + } + Runtime.getRuntime().removeShutdownHook(hook); + qman.stop(); + System.exit(-1); + } catch (StartupFailureException exception) + { + qman.stop(); + System.exit(-1); + } catch (IOException exception) + { + System.exit(-1); + } + } + + /** + * Not implemented for this MBean. + */ + public Object getAttribute(String attribute) + { + return null; + } + + /** + * Not implemented for this MBean. + */ + public AttributeList getAttributes(String[] attributes) + { + return null; + } + + /** + * Returns the metadata for this MBean + * + * @return the metadata for this MBean + */ + public MBeanInfo getMBeanInfo() + { + MBeanParameterInfo parameters [] = new MBeanParameterInfo[8]; + + parameters[0] = new MBeanParameterInfo( + "host", + String.class.getName(), + "The IP address or DNS name that Qpid Broker uses to listen for incoming connections."); + parameters[1] = new MBeanParameterInfo( + "port", + int.class.getName(), + "The port number that Qpid Broker uses to listen for incoming connections."); + parameters[2] = new MBeanParameterInfo( + "username", + String.class.getName(), + "The Qpid account name used in the physical connection."); + parameters[3] = new MBeanParameterInfo( + "password", + String.class.getName(), + "The Qpid account password used in the physical connection."); + parameters[4]= new MBeanParameterInfo( + "virtualHost", + String.class.getName(), + "The virtualHost name."); + parameters[5]= new MBeanParameterInfo( + "initialPoolCapacity", + int.class.getName(), + "The number of physical connections (between 0 and a positive 32-bit integer) to create when creating the (Qpid) connection pool."); + parameters[6]= new MBeanParameterInfo( + "maxPoolCapacity", + int.class.getName(), + "The maximum number of physical database connections (between 0 and a positive 32-bit integer) that the (Qpid) connection pool can contain. "); + parameters[7]= new MBeanParameterInfo( + "maxWaitTimeout", + long.class.getName(), + "The maximum amount of time to wait for an idle connection.A value of -1 indicates an illimted amount of time (i.e. forever)"); + + MBeanOperationInfo operation = new MBeanOperationInfo( + "addBroker", + "Connects QMan with a broker.", + parameters, + void.class.getName(), + MBeanOperationInfo.ACTION); + + MBeanInfo mbean = new MBeanInfo( + QMan.class.getName(), + "QMan Management & Administration interface.", + null, + null, + new MBeanOperationInfo[]{operation}, + null); + + return mbean; + } + + /** + * Invokes an operation on QMan (MBean). + * + * @param actionName the operation name. + * @param params the operation parameters. + * @param signature the operation signature. + * @return the result of the invocation (if the operation is not void); + * @exception MBeanException Wraps a <CODE>java.lang.Exception</CODE> thrown by the MBean's invoked method. + * @exception ReflectionException Wraps a <CODE>java.lang.Exception</CODE> thrown while trying to invoke the method + */ + public Object invoke(String actionName, Object[] params, String[] signature) throws MBeanException, ReflectionException + { + if (Names.ADD_BROKER_OPERATION_NAME.equals(actionName)) + { + try + { + addBroker( + (String)params[0], + (Integer)params[1], + (String)params[2], + (String)params[3], + (String)params[4], + (Integer)params[5], + (Integer)params[6], + (Long)params[7]); + } catch(Exception exception) + { + throw new MBeanException(exception); + } + } else + { + throw new ReflectionException(new NoSuchMethodException(actionName)); + } + return null; + } + + /** + * Not implemented for this MBean. + */ + public void setAttribute(Attribute attribute) + { + } + + /** + * Not implemented for this MBean. + */ + public AttributeList setAttributes(AttributeList attributes) + { + return null; + } + + /** + * Registers QMan as an MBean on MBeanServer. + * + * @throws MBeanException when it's not possible to proceeed with registration. + */ + private void registerQManService() throws MBeanException + { + JmxService service = new JmxService(); + service.registerQManService(this); + + LOGGER.info(Messages.QMAN_000023_QMAN_REGISTERED_AS_MBEAN); + } +} diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/services/QpidService.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/services/QpidService.java new file mode 100644 index 0000000000..a12993d40e --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/services/QpidService.java @@ -0,0 +1,360 @@ +/* + * + * 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.domain.services; + +import java.io.IOException; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; + +import org.apache.qpid.QpidException; +import org.apache.qpid.api.Message; +import org.apache.qpid.management.Messages; +import org.apache.qpid.management.Names; +import org.apache.qpid.management.configuration.QpidDatasource; +import org.apache.qpid.management.domain.model.QpidMethod; +import org.apache.qpid.management.domain.model.type.Binary; +import org.apache.qpid.management.messages.MethodInvocationRequestMessage; +import org.apache.qpid.management.messages.SchemaRequestMessage; +import org.apache.qpid.nclient.util.MessageListener; +import org.apache.qpid.nclient.util.MessagePartListenerAdapter; +import org.apache.qpid.transport.Connection; +import org.apache.qpid.transport.MessageAcceptMode; +import org.apache.qpid.transport.MessageAcquireMode; +import org.apache.qpid.transport.MessageCreditUnit; +import org.apache.qpid.transport.MessageTransfer; +import org.apache.qpid.transport.Option; +import org.apache.qpid.transport.Session; +import org.apache.qpid.transport.SessionException; +import org.apache.qpid.transport.SessionListener; +import org.apache.qpid.transport.util.Logger; + +/** + * Qpid Broker facade. + * + * @author Andrea Gazzarini + */ +public class QpidService implements SessionListener +{ + private final static Logger LOGGER = Logger.get(QpidService.class); + + private UUID _brokerId; + private Connection _connection; + private Session _session; + private Map<String,MessagePartListenerAdapter> _listeners; + + /** + * Builds a new service with the given connection data. + * + * @param connectionData the connection data of the broker. + */ + public QpidService(UUID brokerId) + { + this._brokerId = brokerId; + } + + /** + * Estabilishes a connection with the broker. + * + * @throws QpidException in case of connection failure. + */ + public void connect() throws Exception + { + _connection = QpidDatasource.getInstance().getConnection(_brokerId); + _listeners = new ConcurrentHashMap<String,MessagePartListenerAdapter>(); + _session = _connection.createSession(0); + _session.setSessionListener(this); + } + + public void opened(Session ssn) {} + + public void message(Session ssn, MessageTransfer xfr) + { + MessagePartListenerAdapter l = _listeners.get(xfr.getDestination()); + if (l == null) + { + LOGGER.error("unhandled message: %s", xfr); + } + else + { + l.messageTransfer(xfr); + } + } + + + public void exception(Session ssn, SessionException exc) + { + + } + + public void closed(Session ssn) {} + + /** + * All the previously entered outstanding commands are asynchronous. + * Synchronous behavior is achieved through invoking this method. + */ + public void sync() + { + _session.sync(); + } + + /** + * Closes communication with broker. + */ + public void close() + { + try + { + _session.close(); + _session = null; + _listeners = null; + } catch (Exception e) + { + } + try + { + _connection.close(); + _connection = null; + } catch (Exception e) + { + } + } + + /** + * Associate a message listener with a destination therefore creating a new subscription. + * + * @param queueName The name of the queue that the subscriber is receiving messages from. + * @param destinationName the name of the destination, or delivery tag, for the subscriber. + * @param listener the listener for this destination. + * + * @see Session#messageSubscribe(String, String, short, short, org.apache.qpid.nclient.MessagePartListener, java.util.Map, org.apache.qpid.transport.Option...) + */ + public void createSubscription(String queueName, String destinationName, MessageListener listener) + { + _listeners.put(destinationName, new MessagePartListenerAdapter(listener)); + _session.messageSubscribe + (queueName, + destinationName, + MessageAcceptMode.NONE, + MessageAcquireMode.PRE_ACQUIRED, + null, 0, null); + + _session.messageFlow(destinationName, MessageCreditUnit.BYTE, Session.UNLIMITED_CREDIT); + _session.messageFlow(destinationName, MessageCreditUnit.MESSAGE, Session.UNLIMITED_CREDIT); + + LOGGER.debug(Messages.QMAN_200025_SUBSCRIPTION_DECLARED,queueName,destinationName); + } + + /** + * Removes a previously declared consumer from the broker. + * + * @param destinationName the name of the destination, or delivery tag, for the subscriber. + * @see Session#messageCancel(String, Option...) + */ + public void removeSubscription(String destinationName) + { + _session.messageCancel(destinationName); + LOGGER.debug(Messages.QMAN_200026_SUBSCRIPTION_REMOVED,destinationName); + } + + /** + * Declares a queue on the broker with the given name. + * + * @param queueName the name of the declared queue. + * @see Session#queueDeclare(String, String, java.util.Map, Option...) + */ + public void declareQueue(String queueName) + { + _session.queueDeclare(queueName, null, null); + LOGGER.debug(Messages.QMAN_200027_QUEUE_DECLARED,queueName); + } + + /** + * Removes the queue with the given name from the broker. + * + * @param queueName the name of the queue. + * @see Session#queueDelete(String, Option...) + */ + public void deleteQueue(String queueName) + { + _session.queueDelete(queueName); + LOGGER.debug(Messages.QMAN_200028_QUEUE_REMOVED,queueName); + } + + /** + * Binds (on the broker) a queue with an exchange. + * + * @param queueName the name of the queue to bind. + * @param exchangeName the exchange name. + * @param routingKey the routing key used for the binding. + * @see Session#exchangeBind(String, String, String, java.util.Map, Option...) + */ + public void declareBinding(String queueName, String exchangeName, String routingKey) + { + _session.exchangeBind(queueName, exchangeName, routingKey, null); + LOGGER.debug(Messages.QMAN_200029_BINDING_DECLARED,routingKey,queueName,exchangeName); + } + + /** + * Removes a previously declare binding between an exchange and a queue. + * + * @param queueName the name of the queue. + * @param exchangeName the name of the exchange. + * @param routingKey the routing key used for binding. + */ + public void declareUnbinding(String queueName, String exchangeName, String routingKey) + { + _session.exchangeUnbind(queueName, exchangeName, routingKey); + LOGGER.debug(Messages.QMAN_200030_BINDING_REMOVED,routingKey,queueName,exchangeName); + } + + /** + * Sends a command message with the given data on the management queue. + * + * @param messageData the command message content. + */ + + /** + * Requests a schema for the given package.class.hash. + * + * @param packageName the package name. + * @param className the class name. + * @param schemaHash the schema hash. + * @throws IOException when the schema request cannot be sent. + */ + public void requestSchema(final String packageName, final String className, final Binary schemaHash) throws IOException + { + Message message = new SchemaRequestMessage() + { + @Override + protected String className () + { + return className; + } + + @Override + protected String packageName () + { + return packageName; + } + + @Override + protected Binary schemaHash () + { + return schemaHash; + } + }; + + sendMessage(message); + } + + /** + * Invokes an operation on a broker object instance. + * + * @param packageName the package name. + * @param className the class name. + * @param schemaHash the schema hash of the corresponding class. + * @param objectId the object instance identifier. + * @param parameters the parameters for this invocation. + * @param method the method (definition) invoked. + * @param bankId the object bank identifier. + * @param brokerId the broker identifier. + * @return the sequence number used for this message. + * @throws MethodInvocationException when the invoked method returns an error code. + * @throws UnableToComplyException when it wasn't possibile to invoke the requested operation. + */ + public void invoke( + final String packageName, + final String className, + final Binary schemaHash, + final Binary objectId, + final Object[] parameters, + final QpidMethod method, + final int sequenceNumber, + final long bankId, + final long brokerId) throws MethodInvocationException, UnableToComplyException + { + Message message = new MethodInvocationRequestMessage(bankId, brokerId) + { + + @Override + protected int sequenceNumber () + { + return sequenceNumber; + } + + protected Binary objectId() { + return objectId; + } + + protected String packageName() + { + return packageName; + } + + protected String className() + { + return className; + } + + @Override + protected QpidMethod method () + { + return method; + } + + @Override + protected Object[] parameters () + { + return parameters; + } + + @Override + protected Binary schemaHash () + { + return schemaHash; + } + }; + + try { + sendMessage(message); + sync(); + } catch(Exception exception) { + throw new UnableToComplyException(exception); + } + } + + /** + * Sends a command message. + * + * @param message the command message. + * @throws IOException when the message cannot be sent. + */ + public void sendMessage(Message message) throws IOException + { + _session.messageTransfer( + Names.MANAGEMENT_EXCHANGE, + MessageAcceptMode.EXPLICIT, + MessageAcquireMode.PRE_ACQUIRED, + message.getHeader(), + message.readData()); + } +} diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/services/SequenceNumberGenerator.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/services/SequenceNumberGenerator.java new file mode 100644 index 0000000000..e6d99971cd --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/services/SequenceNumberGenerator.java @@ -0,0 +1,41 @@ +/* + * + * 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.domain.services; + +/** + * Sequence number generator utility class. + * + * @author Andrea Gazzarini + */ +public class SequenceNumberGenerator +{ + private static int sequenceNumber; + + /** + * Returns a valid sequence number. + * + * @return a sequence number. + */ + public static synchronized int getNextSequenceNumber() + { + return sequenceNumber++; + } +} diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/services/StartupFailureException.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/services/StartupFailureException.java new file mode 100644 index 0000000000..9da8832624 --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/services/StartupFailureException.java @@ -0,0 +1,42 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.management.domain.services; + +/** + * Thrown in case of service startup failure. + * For example the configuration file couldn't be read because is not well-formed. + * + * @author Andrea Gazzarini. + */ +public class StartupFailureException extends Exception +{ + private static final long serialVersionUID = -4102037574602857703L; + + /** + * Builds a new StartupFailureException with the given exception. + * + * @param exception the exception cause. + */ + public StartupFailureException(Exception exception) + { + super(exception); + } +}
\ No newline at end of file diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/services/UnableToComplyException.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/services/UnableToComplyException.java new file mode 100644 index 0000000000..2ab9a41e75 --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/domain/services/UnableToComplyException.java @@ -0,0 +1,31 @@ +/* + * + * 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.domain.services; + +public class UnableToComplyException extends Exception +{ + public UnableToComplyException(Exception exception) + { + super(exception); + } + + private static final long serialVersionUID = -3071434478559509435L; +} diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/messages/AmqpCoDec.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/messages/AmqpCoDec.java new file mode 100644 index 0000000000..4d1dfe796a --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/messages/AmqpCoDec.java @@ -0,0 +1,178 @@ +/* +* + * 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.messages; + +import java.io.UnsupportedEncodingException; +import java.nio.ByteBuffer; + +/** + * AMQP Management messages codec. + * + * @author Andrea Gazzarini + */ +public class AmqpCoDec +{ + private byte [] _buffer; + private int _position; + + /** + * Builds a new codec. + */ + AmqpCoDec() + { + _buffer = new byte [1000]; + _buffer[0] = 'A'; + _buffer[1] = 'M'; + _buffer[2] = '2'; + _position = 3; + } + + + /** + * Int32-to-4 byte array marshalling. + * Marshalles an integer using four bytes. + * + * @param data the result array. + * @param pos the starting position of the array to be filled. + * @param value the value to be marshalled. + */ + public final void pack32(int value) { + _buffer[_position++] = (byte) (value >> 24 & 0xff); + _buffer[_position++] = (byte) (value >> 16 & 0xff); + _buffer[_position++] = (byte) (value >> 8 & 0xff); + _buffer[_position++] = (byte) (value & 0xff); + } + + /** + * Int32-to-4 byte array marshalling. + * Marshalles an integer using four bytes. + * + * @param data the result array. + * @param pos the starting position of the array to be filled. + * @param value the value to be marshalled. + */ + public final void pack16(int value) { + _buffer[_position++] = (byte) (value >> 8 & 0xff); + _buffer[_position++] = (byte) (value & 0xff); + } + + /** + * Int32-to-4 byte array marshalling. + * Marshalles an integer using four bytes. + * + * @param data the result array. + * @param pos the starting position of the array to be filled. + * @param value the value to be marshalled. + */ + public final void pack64(long value) { + _buffer[_position++] = (byte) (value >> 56 & 0xff); + _buffer[_position++] = (byte) (value >> 48 & 0xff); + _buffer[_position++] = (byte) (value >> 40 & 0xff); + _buffer[_position++] = (byte) (value >> 32 & 0xff); + _buffer[_position++] = (byte) (value >> 24 & 0xff); + _buffer[_position++] = (byte) (value >> 16 & 0xff); + _buffer[_position++] = (byte) (value >> 8 & 0xff); + _buffer[_position++] = (byte) (value & 0xff); + } + + /** + * Int32-to-byte array marshalling. + * Marshalles an integer using two bytes. + * + * @param data the result array. + * @param pos the starting position of the array to be filled. + * @param value the value to be marshalled. + */ + public final void pack24(int value) { + _buffer[_position++] = (byte) (value >> 16 & 0xff); + _buffer[_position++] = (byte) (value >> 8 & 0xff); + _buffer[_position++] = (byte) (value & 0xff); + } + + public final void pack8(int value) { + _buffer[_position++] = (byte) (value & 0xff); + } + + public void pack8 (byte aByte) + { + _buffer[_position++] = aByte; + } + + public void packStr8(String aString) + { + try + { + byte [] toBytes = aString.getBytes("UTF-8"); + int length = toBytes.length; + pack8(length); + System.arraycopy(toBytes, 0, _buffer, _position, length); + _position+=length; + } catch (UnsupportedEncodingException exception) + { + throw new RuntimeException(exception); + } + } + + public void packStr16(String aString) + { + try + { + byte [] toBytes = aString.getBytes("UTF-8"); + int length = toBytes.length; + pack16(length); + System.arraycopy(toBytes, 0, _buffer, _position, length); + _position+=length; + } catch (UnsupportedEncodingException exception) + { + throw new RuntimeException(exception); + } + } + + public static final long unpack64(byte data[]) { + return ( + ((long) (data[0] & 0xff) << 56) | + ((long)(data[1] & 0xff) << 48) | + ((long)(data[2] & 0xff) << 40) | + ((long)(data[3] & 0xff) << 32) | + ((long)(data[4] & 0xff) << 24) | + ((long)(data[5] & 0xff) << 16) | + ((long)(data[6] & 0xff) << 8) | + (long) data[7] & 0xff); + } + + + public void pack (byte[] bytes) + { + System.arraycopy(bytes, 0, _buffer, _position, bytes.length); + _position+=bytes.length; + } + + /** + * Retruns the byte buffer that is wrapping the backing array of this codec. + * + * @return the byte buffer that is wrapping the backing array of this codec. + */ + public ByteBuffer getEncodedBuffer () + { + return ByteBuffer.wrap(_buffer,0,_position); + } +} diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/messages/ManagementMessage.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/messages/ManagementMessage.java new file mode 100644 index 0000000000..2fa20fb456 --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/messages/ManagementMessage.java @@ -0,0 +1,189 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.management.messages; + +import java.io.IOException; +import java.nio.ByteBuffer; + +import org.apache.qpid.api.Message; +import org.apache.qpid.management.configuration.Configuration; +import org.apache.qpid.management.domain.services.SequenceNumberGenerator; +import org.apache.qpid.transport.DeliveryProperties; +import org.apache.qpid.transport.Header; +import org.apache.qpid.transport.MessageProperties; +import org.apache.qpid.transport.codec.BBEncoder; + +/** + * Message implementation used for specific management purposes. + * + * @author Andrea Gazzarini + */ +public abstract class ManagementMessage implements Message +{ + /** + * Strategy interface for building / getting data. + * + * @author Andrea Gazzarini + */ + private interface IDataBuilderStrategy + { + ByteBuffer getData(); + }; + + /** + * Strategy used for retrieving raw data from this message when it has been already encoded. + */ + IDataBuilderStrategy READING = new IDataBuilderStrategy() + { + public ByteBuffer getData() { + return _data; + }; + }; + + /** + * Strategy used for retrieving raw data from this message when it hasn't been already encoded. + */ + IDataBuilderStrategy ACCUMULATING = new IDataBuilderStrategy() + { + public ByteBuffer getData() { + _codec.writeInt8((byte)opcode()); + _codec.writeSequenceNo(sequenceNumber()); + + specificMessageEncoding(); + + _data =_codec.segment(); + _reader = READING; + return _data; + } + }; + + protected BBEncoder _codec; + protected ByteBuffer _data; + private int _messageTransferId; + private IDataBuilderStrategy _reader = ACCUMULATING; + + /** + * Builds an empty management message. + */ + ManagementMessage() + { + _codec = new BBEncoder(100); + _codec.writeMagicNumber(); + } + + /** + * Returns the sequence number that will be used for this message. + * + * @return the sequence number that will be used for this message. + */ + protected int sequenceNumber () + { + return SequenceNumberGenerator.getNextSequenceNumber(); + } + + /** + * Returns the opcode that will be used for this message. + * + * @return the opcode that will be used for this message. + */ + abstract char opcode (); + + /** + * Returns the delivery properties of this message. + * + * @return the delivery properties of this message. + */ + public DeliveryProperties getDeliveryProperties () + { + return Configuration.getInstance().getCommandDeliveryProperties(); + } + + /** + * Returns the header of this message. + * + * @return the header of this message. + */ + public Header getHeader () + { + return Configuration.getInstance().getCommandMessageHeader(); + } + + /** + * Returns the messages header properties of this message. + * + * @return the message header properties of this message. + */ + public MessageProperties getMessageProperties () + { + return Configuration.getInstance().getCommandMessageProperties(); + } + + /** + * Returns the transfer Id of this message. + * + * @return the transfer Id of this message. + */ + public int getMessageTransferId () + { + return _messageTransferId; + } + + /** + * Returns the encoded data of this message. + * + * @return the encoded data of this message. + */ + public ByteBuffer readData () throws IOException + { + return _reader.getData(); + } + + /** + * Sets the header for this message. + * + * @param header the new message header. + */ + public void setHeader (Header header) + { + // N.A. at the moment. + } + + public void appendData (byte[] src) throws IOException + { + } + + public void appendData (ByteBuffer src) throws IOException + { + } + + public void clearData () + { + } + + public void readData (byte[] target) throws IOException + { + } + + /** + * Concrete subclasses (message implementations) must define here their specific data encoding. + */ + abstract void specificMessageEncoding(); +}
\ No newline at end of file diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/messages/MethodInvocationRequestMessage.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/messages/MethodInvocationRequestMessage.java new file mode 100644 index 0000000000..99916085d6 --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/messages/MethodInvocationRequestMessage.java @@ -0,0 +1,161 @@ +/* + * + * 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.messages; + +import org.apache.qpid.management.Messages; +import org.apache.qpid.management.Names; +import org.apache.qpid.management.Protocol; +import org.apache.qpid.management.configuration.Configuration; +import org.apache.qpid.management.domain.model.QpidMethod; +import org.apache.qpid.management.domain.model.type.Binary; +import org.apache.qpid.transport.DeliveryProperties; +import org.apache.qpid.transport.Header; +import org.apache.qpid.transport.MessageProperties; +import org.apache.qpid.transport.ReplyTo; +import org.apache.qpid.transport.util.Logger; + +/** + * Abstract representation of a method invocation request message. + * Concrete subclasses must supply the values needed to build & encode the message. + * + * @author Andrea Gazzarini + */ +public abstract class MethodInvocationRequestMessage extends ManagementMessage +{ + private final static Logger LOGGER = Logger.get(MethodInvocationRequestMessage.class); + + private DeliveryProperties _deliveryProperties; + private MessageProperties _messageProperties; + private Header _header; + + /** + * Builds a new method invocation request message with the given target identifiers. + * + * @param bankId the bank identifier. + * @param brokerId the broker identifier. + */ + public MethodInvocationRequestMessage(long bankId, long brokerId) + { + ReplyTo replyTo=new ReplyTo(); + replyTo.setRoutingKey(Configuration.getInstance().getMethodReplyQueueName()); + _messageProperties = new MessageProperties(); + _messageProperties.setReplyTo(replyTo); + + String routingKey = String.format(Names.AGENT_ROUTING_KEY_PREFIX+"%s.%s", brokerId,bankId); + + LOGGER.debug(Messages.QMAN_200032_COMMAND_MESSAGE_ROUTING_KEY, routingKey); + + _deliveryProperties = new DeliveryProperties(); + _deliveryProperties.setRoutingKey(routingKey); + _header = new Header(_deliveryProperties, _messageProperties); + } + + @Override + char opcode () + { + return Protocol.OPERATION_INVOCATION_REQUEST_OPCODE; + } + + /** + * Returns the package name. + * + * @return the package name. + */ + protected abstract String packageName(); + + /** + * Returns the class name. + * + * @return the class name. + */ + protected abstract String className(); + + /** + * Returns the schema hash. + * + * @return the schema hash. + */ + protected abstract Binary schemaHash(); + + /** + * Returns the object identifier. + * + * @return the object identifier. + */ + protected abstract Binary objectId(); + + /** + * Returns the method to be invoked. + * + * @return the method to be invoked. + */ + protected abstract QpidMethod method(); + + /** + * Returns the parameters used for method invocation. + * + * @return the parameters used for method invocation. + */ + protected abstract Object[] parameters(); + + /** + * Returns the delivery properties of this message. + * + * @return the delivery properties of this message. + */ + public DeliveryProperties getDeliveryProperties () + { + return _deliveryProperties; + } + + /** + * Returns the header of this message. + * + * @return the header of this message. + */ + public Header getHeader () + { + return _header; + } + + /** + * Returns the messages header properties of this message. + * + * @return the message header properties of this message. + */ + public MessageProperties getMessageProperties () + { + return _messageProperties; + } + + @Override + void specificMessageEncoding () + { + objectId().encode(_codec); + _codec.writeStr8(packageName()); + _codec.writeStr8(className()); + schemaHash().encode(_codec); + + QpidMethod method = method(); + _codec.writeStr8(method.getName()); + method.encodeParameters(parameters(), _codec); + } +} diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/messages/SchemaRequestMessage.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/messages/SchemaRequestMessage.java new file mode 100644 index 0000000000..9df1733649 --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/messages/SchemaRequestMessage.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.management.messages; + +import org.apache.qpid.management.Protocol; +import org.apache.qpid.management.domain.model.type.Binary; + +/** + * Abstract representation of a schema request message. + * Concrete subclasses must supply the values needed to build & encode the message. + * + * @author Andrea Gazzarini + */ +public abstract class SchemaRequestMessage extends ManagementMessage +{ + @Override + char opcode () + { + return Protocol.SCHEMA_REQUEST_OPCODE; + } + + /** + * Returns the package name. + * + * @return the package name. + */ + protected abstract String packageName(); + + /** + * Returns the class name. + * + * @return the class name. + */ + protected abstract String className(); + + /** + * Returns the schema hash. + * + * @return the schema hash. + */ + protected abstract Binary schemaHash(); + + @Override + final void specificMessageEncoding () + { + _codec.writeStr8(packageName()); + _codec.writeStr8(className()); + schemaHash().encode(_codec); + } +} diff --git a/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/servlet/QManServlet.java b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/servlet/QManServlet.java new file mode 100644 index 0000000000..f0d663701b --- /dev/null +++ b/RC9/qpid/java/management/client/src/main/java/org/apache/qpid/management/servlet/QManServlet.java @@ -0,0 +1,66 @@ +/*
+ *
+ * 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.servlet;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+
+import org.apache.qpid.management.domain.services.QMan;
+import org.apache.qpid.management.domain.services.StartupFailureException;
+
+/**
+ * QMan initializer.
+ *
+ * @author Andrea Gazzarini
+ */
+public class QManServlet extends HttpServlet {
+
+ private static final long serialVersionUID = 6149614872902682208L;
+
+ // QMan instance
+ private QMan qman;
+
+ /**
+ * Initializes QMan instance.
+ *
+ * @throws ServletException when It's not possibile to proceed with initialization.
+ */
+ @Override
+ public void init() throws ServletException
+ {
+ qman = new QMan();
+ try {
+ qman.start();
+ } catch (StartupFailureException exception)
+ {
+ throw new ServletException(exception);
+ }
+ }
+
+ /**
+ * Stops QMan instance.
+ */
+ @Override
+ public void destroy()
+ {
+ qman.stop();
+ }
+}
diff --git a/RC9/qpid/java/management/client/src/test/java/org/apache/qpid/management/TestConstants.java b/RC9/qpid/java/management/client/src/test/java/org/apache/qpid/management/TestConstants.java new file mode 100644 index 0000000000..5855a3e60b --- /dev/null +++ b/RC9/qpid/java/management/client/src/test/java/org/apache/qpid/management/TestConstants.java @@ -0,0 +1,64 @@ +/* + * + * 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; + +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import org.apache.qpid.management.domain.handler.impl.MethodOrEventDataTransferObject; +import org.apache.qpid.management.domain.model.DomainModel; +import org.apache.qpid.management.domain.model.type.Binary; + +public interface TestConstants +{ + UUID BROKER_ID = UUID.randomUUID(); + Binary OBJECT_ID = new Binary(new byte []{1,2,3,2,1,1,2,3}); + + DomainModel DOMAIN_MODEL = new DomainModel(BROKER_ID); + + String AGE_ATTRIBUTE_NAME = "age"; + String AGE_ATTRIBUTE_DESCRIPTION = "The age of a person."; + String SURNAME_ATTRIBUTE_NAME = "surname"; + String SURNAME_ATTRIBUTE_DESCRIPTION = "The surname of a person."; + Integer _1 = new Integer(1); + + byte [] TEST_RAW_DATA= new byte []{1,4,5,7,8,9,4,44}; + long NOW = System.currentTimeMillis(); + int SEVERITY = _1; + + String QPID_PACKAGE_NAME = "qpid"; + String EXCHANGE_CLASS_NAME = "exchange"; + String BIND_EVENT_NAME = "bind"; + Binary HASH = new Binary(new byte []{1,2,3,4,5,6,7,8,9}); + int VALID_CODE = _1; + + List<Map<String, Object>> EMPTY_PROPERTIES_SCHEMA = new LinkedList<Map<String,Object>>(); + List<Map<String, Object>> EMPTY_STATISTICS_SCHEMA = new LinkedList<Map<String,Object>>(); + List<MethodOrEventDataTransferObject> EMPTY_METHODS_SCHEMA = new LinkedList<MethodOrEventDataTransferObject>(); + List<Map<String, Object>> EMPTY_ARGUMENTS_SCHEMA = new LinkedList<Map<String,Object>>(); + int _0 = 0; + int SAMPLE_ACCESS_CODE = 1; + String YEARS = "years"; + int SAMPLE_MIN_VALUE = 1; + int SAMPLE_MAX_VALUE = 120; +} diff --git a/RC9/qpid/java/management/client/src/test/java/org/apache/qpid/management/configuration/ConfigurationTest.java b/RC9/qpid/java/management/client/src/test/java/org/apache/qpid/management/configuration/ConfigurationTest.java new file mode 100644 index 0000000000..efd5990bd7 --- /dev/null +++ b/RC9/qpid/java/management/client/src/test/java/org/apache/qpid/management/configuration/ConfigurationTest.java @@ -0,0 +1,229 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.management.configuration; + +import java.util.Map; +import java.util.UUID; + +import org.apache.qpid.management.TestConstants; +import org.apache.qpid.management.domain.handler.base.IMessageHandler; +import org.apache.qpid.management.domain.handler.impl.ConfigurationMessageHandler; +import org.apache.qpid.management.domain.handler.impl.InstrumentationMessageHandler; +import org.apache.qpid.management.domain.handler.impl.SchemaResponseMessageHandler; +import org.apache.qpid.management.domain.model.AccessMode; +import org.apache.qpid.management.domain.model.type.Type; +import org.apache.qpid.management.domain.model.type.Uint8; + +import junit.framework.TestCase; + +/** + * Test case for Configuration singleton. + * + * @author Andrea Gazzarini + */ +public class ConfigurationTest extends TestCase +{ + /** + * Tests the singleton behaviour of the configuration object. + */ + public void testSingleton() + { + assertSame(Configuration.getInstance(),Configuration.getInstance()); + } + + /** + * Tests the execution of getType() method when a valid code is supplied. + * + * <br>precondition : the requested type already exist on the configuration. + * <br>postcondition : the requested type is returned and no exception is thrown. + */ + public void testGetTypeOk() throws UnknownTypeCodeException + { + TypeMapping mapping = new TypeMapping(TestConstants.VALID_CODE,new Uint8()); + Configuration.getInstance().addTypeMapping(mapping); + Type type = Configuration.getInstance().getType(TestConstants.VALID_CODE); + + assertTrue(type instanceof Uint8); + } + + /** + * Tests the execution of getType() method when a unknown code is supplied. + * + * <br>precondition : the requested type doesn't exist on the configuration. + * <br>postcondition : an exception is thrown indicating the failure. + */ + public void testGetTypeKO() + { + try + { + Configuration.getInstance().getType(Integer.MIN_VALUE); + fail("If an unknwon code is supplied an exception must be thrown."); + } catch (UnknownTypeCodeException expected) + { + assertEquals(Integer.MIN_VALUE,expected.getCode()); + } + } + + /** + * Tests the execution of getAccessMode() method when a valid code is supplied. + * + * <br>precondition : the requested access mode already exist on the configuration. + * <br>postcondition : the requested access mode is returned and no exception is thrown. + */ + public void testGetAccessModeOk() throws UnknownAccessCodeException + { + AccessModeMapping mapping = new AccessModeMapping(TestConstants.VALID_CODE,AccessMode.RW); + Configuration.getInstance().addAccessModeMapping(mapping); + AccessMode accessMode = Configuration.getInstance().getAccessMode(TestConstants.VALID_CODE); + + assertSame(AccessMode.RW,accessMode); + } + + /** + * Tests the execution of getAccessMode() method when a unknown code is supplied. + * + * <br>precondition : the requested access mode doesn't exist on the configuration. + * <br>postcondition : an exception is thrown indicating the failure. + */ + public void testGetAccessModeKO() + { + try + { + Configuration.getInstance().getAccessMode(Integer.MIN_VALUE); + fail("If an unknwon code is supplied an exception must be thrown."); + } catch (UnknownAccessCodeException expected) + { + assertEquals(Integer.MIN_VALUE,expected.getCode()); + } + } + + /** + * Tests the execution of the getBrokerConnectionData when a valid broker id is supplied. + * + * <br>precondition : on configuration a connection data is stored and associated with the supplied id. + * <br>postcondition : the requested connection data is returned and no exception is thrown. + */ + public void testGetBrokerConnectionDataOK() throws Exception + { + BrokerConnectionData connectionData = new BrokerConnectionData(); + connectionData.setHost("host"); + connectionData.setPort("7001"); + connectionData.setInitialPoolCapacity("0"); + connectionData.setMaxPoolCapacity("10"); + connectionData.setMaxWaitTimeout("1"); + Configuration.getInstance().addBrokerConnectionData(TestConstants.BROKER_ID, connectionData); + + BrokerConnectionData result = Configuration.getInstance().getBrokerConnectionData(TestConstants.BROKER_ID); + assertSame(connectionData, result); + } + + /** + * Tests the execution of the getBrokerConnectionData when a unknown broker id is supplied. + * + * <br>precondition : on configuration there's no connection data associated with the supplied id. + * <br>postcondition : an exception is thrown indicating the failure. + */ + public void testGetBrokerConnectionDataKO_withUnknownBrokerId() + { + UUID brokerId = UUID.randomUUID(); + try + { + Configuration.getInstance().getBrokerConnectionData(brokerId); + fail("If an unknown broker id is supplied then an exception must be thrown."); + } catch(UnknownBrokerException expected) + { + assertEquals(brokerId.toString(),expected.getMessage()); + } + } + + /** + * Tests the execution of the getBrokerConnectionData when a null id is supplied. + * + * <br>precondition : a null broker is given. + * <br>postcondition : an exception is thrown indicating the failure. + */ + public void testGetBrokerConnectionDataKO_withNullBrokerId() + { + try + { + Configuration.getInstance().getBrokerConnectionData(null); + fail("If a null broker id is supplied then an exception must be thrown."); + } catch(UnknownBrokerException expected) + { + } + } + + /** + * Tests the behaviour of the getManagementQueueHandlers() method. + * + * <br>precondition: 2 management handlers are in stored configuration + * <br>postcondition : 2 management handlers are returned. + */ + public void testGetManagementQueueHandlersOk() + { + String i = "i"; + String c = "c"; + + String instrMessageHandlerClassName = InstrumentationMessageHandler.class.getName(); + String configMessageHandlerClassName = ConfigurationMessageHandler.class.getName(); + + MessageHandlerMapping instrMapping = new MessageHandlerMapping(); + MessageHandlerMapping configMapping = new MessageHandlerMapping(); + + instrMapping.setOpcode(i); + instrMapping.setMessageHandlerClass(instrMessageHandlerClassName); + + configMapping.setOpcode(c); + configMapping.setMessageHandlerClass(configMessageHandlerClassName); + + Configuration.getInstance().addManagementMessageHandlerMapping(instrMapping); + Configuration.getInstance().addManagementMessageHandlerMapping(configMapping); + + Map<Character, IMessageHandler> handlerMappings = Configuration.getInstance().getManagementQueueHandlers(); + + assertEquals(instrMessageHandlerClassName,handlerMappings.get(instrMapping.getOpcode()).getClass().getName()); + assertEquals(configMessageHandlerClassName,handlerMappings.get(configMapping.getOpcode()).getClass().getName()); + } + + /** + * Tests the behaviour of the getManagementQueueHandlers() method. + * + * <br>precondition: 2 management handlers are in stored configuration + * <br>postcondition : 2 management handlers are returned. + */ + public void testGetMethodReplyQueueHandlersOk() + { + String s = "s"; + + String schemaMessageHandlerClassName = SchemaResponseMessageHandler.class.getName(); + + MessageHandlerMapping schemaMapping = new MessageHandlerMapping(); + + schemaMapping.setOpcode(s); + schemaMapping.setMessageHandlerClass(schemaMessageHandlerClassName); + + Configuration.getInstance().addMethodReplyMessageHandlerMapping(schemaMapping); + + Map<Character, IMessageHandler> handlerMappings = Configuration.getInstance().getMethodReplyQueueHandlers(); + + assertEquals(schemaMessageHandlerClassName,handlerMappings.get(schemaMapping.getOpcode()).getClass().getName()); + } +} diff --git a/RC9/qpid/java/management/client/src/test/java/org/apache/qpid/management/configuration/ConfiguratorTest.java b/RC9/qpid/java/management/client/src/test/java/org/apache/qpid/management/configuration/ConfiguratorTest.java new file mode 100644 index 0000000000..6237f21cc9 --- /dev/null +++ b/RC9/qpid/java/management/client/src/test/java/org/apache/qpid/management/configuration/ConfiguratorTest.java @@ -0,0 +1,164 @@ +/* + * + * 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.configuration; + +import java.util.Map; +import java.util.UUID; + +import junit.framework.TestCase; + +import org.apache.qpid.management.Names; +import org.apache.qpid.management.Protocol; +import org.apache.qpid.management.domain.handler.base.IMessageHandler; +import org.apache.qpid.management.domain.handler.impl.ConfigurationMessageHandler; +import org.apache.qpid.management.domain.handler.impl.EventContentMessageHandler; +import org.apache.qpid.management.domain.handler.impl.HeartBeatIndicationMessageHandler; +import org.apache.qpid.management.domain.handler.impl.InstrumentationMessageHandler; +import org.apache.qpid.management.domain.handler.impl.MethodResponseMessageHandler; +import org.apache.qpid.management.domain.handler.impl.SchemaResponseMessageHandler; +import org.apache.qpid.management.domain.model.AccessMode; +import org.apache.qpid.management.domain.model.type.AbsTime; +import org.apache.qpid.management.domain.model.type.DeltaTime; +import org.apache.qpid.management.domain.model.type.ObjectReference; +import org.apache.qpid.management.domain.model.type.Str16; +import org.apache.qpid.management.domain.model.type.Str8; +import org.apache.qpid.management.domain.model.type.Uint16; +import org.apache.qpid.management.domain.model.type.Uint32; +import org.apache.qpid.management.domain.model.type.Uint64; +import org.apache.qpid.management.domain.model.type.Uint8; +import org.xml.sax.SAXException; + +/** + * Test case for configurator. + * + * @author Andrea Gazzarini + * + */ +public class ConfiguratorTest extends TestCase +{ + /** + * Tests the execution of the configure() method when no configuration file is given. + * + * <br>precondition : configuration file option is not set + * <br>postcondition : no exception is thrown, the configuration is holding no broker data and the predefined mappings are + * stored in configuration. + */ + public void testConfigureOK_WithNoConfigurationFile() throws Exception + { + Configurator configurator = new Configurator(); + configurator.configure(); + Configuration configuration = Configuration.getInstance(); + + assertEquals(new Uint8(), configuration.getType(1)); + assertEquals(new Uint16(), configuration.getType(2)); + assertEquals(new Uint32(), configuration.getType(3)); + assertEquals(new Uint64(), configuration.getType(4)); + assertEquals(new Str8(), configuration.getType(6)); + assertEquals(new Str16(), configuration.getType(7)); + assertEquals(new AbsTime(), configuration.getType(8)); + assertEquals(new DeltaTime(), configuration.getType(9)); + assertEquals(new ObjectReference(), configuration.getType(10)); + assertEquals(new org.apache.qpid.management.domain.model.type.Boolean(), configuration.getType(11)); + assertEquals(new org.apache.qpid.management.domain.model.type.Uuid(), configuration.getType(14)); + assertEquals(new org.apache.qpid.management.domain.model.type.Map(), configuration.getType(15)); + + assertEquals(AccessMode.RC,configuration.getAccessMode(1)); + assertEquals(AccessMode.RW,configuration.getAccessMode(2)); + assertEquals(AccessMode.RO,configuration.getAccessMode(3)); + + Map<Character, IMessageHandler> managementHandlers = configuration.getManagementQueueHandlers(); + assertEquals(4,managementHandlers.size()); + assertEquals( + InstrumentationMessageHandler.class, + managementHandlers.get(Protocol.INSTRUMENTATION_CONTENT_RESPONSE_OPCODE).getClass()); + + assertEquals( + ConfigurationMessageHandler.class, + managementHandlers.get(Protocol.CONFIGURATION_CONTENT_RESPONSE_OPCDE).getClass()); + + assertEquals( + EventContentMessageHandler.class, + managementHandlers.get(Protocol.EVENT_CONTENT_RESPONSE_OPCDE).getClass()); + + assertEquals( + HeartBeatIndicationMessageHandler.class, + managementHandlers.get(Protocol.HEARTBEAT_INDICATION_RESPONSE_OPCODE).getClass()); + + Map<Character, IMessageHandler> methodReplyHandlers = configuration.getMethodReplyQueueHandlers(); + assertEquals(2, methodReplyHandlers.size()); + + assertEquals( + MethodResponseMessageHandler.class, + methodReplyHandlers.get(Protocol.OPERATION_INVOCATION_RESPONSE_OPCODE).getClass()); + + assertEquals( + SchemaResponseMessageHandler.class, + methodReplyHandlers.get(Protocol.SCHEMA_RESPONSE_OPCODE).getClass()); + } + + /** + * Tests the changes of the configurator internal state while configuration file is parsed. + * + * <br>precondition: N.A. + * <br>postcondition: N.A. + */ + public void testDirectorParsing() throws SAXException{ + Configurator configurator = new Configurator(); + + assertSame(Configurator.DEFAULT_PARSER,configurator._currentParser); + + configurator.startElement(null, null, Tag.BROKERS.toString(), null); + assertSame(configurator._brokerConfigurationParser,configurator._currentParser); + } + + /** + * It's not possibile to add twice the same broker connection data. + * Is so an exception must be thrown indicating that the given broker is already connected. + * + * <br>precondition : the given data identifies an already connected broker. + * <br>postcondition : an exception is thrown indicating the failure. + */ + public void testAddTwoIdenticalBrokers() throws ConfigurationException, BrokerConnectionException + { + Configurator configurator = new Configurator(); + configurator.configure(); + + BrokerConnectionData data = new BrokerConnectionData("sofia.gazzax.com",5672,"virtualHost","user","pwd",1,4,-1); + + Configuration.getInstance()._brokerConnectionInfos.put(UUID.randomUUID(),data); + + try { + configurator.createAndReturnBrokerConnectionData( + UUID.randomUUID(), + data.getHost(), + data.getPort(), + "anotherUser", + "anotherPassword", + data.getVirtualHost(), + 33, + 12, + 1000); + fail("If a broker is added twice an exception must be thrown."); + } catch (BrokerAlreadyConnectedException expected) { + assertEquals(data,expected.getBrokerConnectionData()); + } + } +} diff --git a/RC9/qpid/java/management/client/src/test/java/org/apache/qpid/management/configuration/MappingParsersTest.java b/RC9/qpid/java/management/client/src/test/java/org/apache/qpid/management/configuration/MappingParsersTest.java new file mode 100644 index 0000000000..af261024bd --- /dev/null +++ b/RC9/qpid/java/management/client/src/test/java/org/apache/qpid/management/configuration/MappingParsersTest.java @@ -0,0 +1,79 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.management.configuration; + +import java.util.UUID; + +import junit.framework.TestCase; + +import org.apache.qpid.management.TestConstants; + +/** + * Test case for mapping parsers. + * + * @author Andrea Gazzarini. + */ +public class MappingParsersTest extends TestCase +{ + /** + * Tests the execution of the broker connection data mapping parser. + * + * <br>precondition: A broker connection datamapping is built by the parser; + * <br>postcondition: the corresponding connection data is available on the configuration. + */ + public void testBrokerConnectionDataParser() throws UnknownBrokerException + { + String host = "127.0.0.1"; + String port = "7001"; + String virtualHost = "test"; + String username = "username_guest"; + String password ="password_guest"; + + BrokerConnectionDataParser parser = new BrokerConnectionDataParser() + { + @Override + UUID getUUId () + { + return TestConstants.BROKER_ID; + } + }; + + parser.setCurrrentAttributeValue(host); + parser.setCurrentAttributeName(Tag.HOST.toString()); + parser.setCurrrentAttributeValue(port); + parser.setCurrentAttributeName(Tag.PORT.toString()); + parser.setCurrrentAttributeValue(virtualHost); + parser.setCurrentAttributeName(Tag.VIRTUAL_HOST.toString()); + parser.setCurrrentAttributeValue(username); + parser.setCurrentAttributeName(Tag.USER.toString()); + parser.setCurrrentAttributeValue(password); + parser.setCurrentAttributeName(Tag.PASSWORD.toString()); + parser.setCurrentAttributeName(Tag.BROKER.toString()); + + BrokerConnectionData result = Configuration.getInstance().getBrokerConnectionData(TestConstants.BROKER_ID); + + assertEquals(host,result.getHost()); + assertEquals(Integer.parseInt(port),result.getPort()); + assertEquals(virtualHost,result.getVirtualHost()); + assertEquals(username,result.getUsername()); + assertEquals(password,result.getPassword()); + } +} diff --git a/RC9/qpid/java/management/client/src/test/java/org/apache/qpid/management/domain/handler/base/ContentIndicationMessageHandlerTest.java b/RC9/qpid/java/management/client/src/test/java/org/apache/qpid/management/domain/handler/base/ContentIndicationMessageHandlerTest.java new file mode 100644 index 0000000000..d6b51b64fc --- /dev/null +++ b/RC9/qpid/java/management/client/src/test/java/org/apache/qpid/management/domain/handler/base/ContentIndicationMessageHandlerTest.java @@ -0,0 +1,59 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.management.domain.handler.base; + +import junit.framework.TestCase; + +import org.apache.qpid.management.domain.model.type.Binary; + +/** + * Test case for Content indication message handler (base class). + * + * @author Andrea Gazzarini + */ +public class ContentIndicationMessageHandlerTest extends TestCase +{ + /** + * Tests the behaviour of the objectHasBeenRemoved method(). + */ + public void testObjectHasBeenRemoved() + { + ContentIndicationMessageHandler mockHandler = new ContentIndicationMessageHandler() + { + @Override + protected void updateDomainModel (String packageName, String className, Binary classHash, Binary objectId, + long timeStampOfCurrentSample, long timeObjectWasCreated, long timeObjectWasDeleted, byte[] contentData) + { + } + }; + + long deletionTimestamp = 0; + long now = System.currentTimeMillis(); + + assertFalse(mockHandler.objectHasBeenRemoved(deletionTimestamp, now)); + + deletionTimestamp = now + 1000; + assertFalse(mockHandler.objectHasBeenRemoved(deletionTimestamp, now)); + + deletionTimestamp = now - 1000; + assertTrue(mockHandler.objectHasBeenRemoved(deletionTimestamp, now)); + } +}
\ No newline at end of file diff --git a/RC9/qpid/java/management/client/src/test/java/org/apache/qpid/management/domain/model/BaseDomainModelTestCase.java b/RC9/qpid/java/management/client/src/test/java/org/apache/qpid/management/domain/model/BaseDomainModelTestCase.java new file mode 100644 index 0000000000..c528392a93 --- /dev/null +++ b/RC9/qpid/java/management/client/src/test/java/org/apache/qpid/management/domain/model/BaseDomainModelTestCase.java @@ -0,0 +1,44 @@ +/* + * + * 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.domain.model; + +import org.apache.qpid.management.configuration.Configurator; + +import junit.framework.TestCase; + +/** + * Layer supertype for all domain model related test cases. + * + * @author Andrea Gazzarini + */ +public abstract class BaseDomainModelTestCase extends TestCase +{ + /** + * Set up fixture for this test case. + * In order to execute tests on domain model we need to build the configuration. + */ + @Override + protected void setUp () throws Exception + { + Configurator configurator = new Configurator(); + configurator.configure(); + } +}
\ No newline at end of file diff --git a/RC9/qpid/java/management/client/src/test/java/org/apache/qpid/management/domain/model/BaseQpidFeatureBuilderTestCase.java b/RC9/qpid/java/management/client/src/test/java/org/apache/qpid/management/domain/model/BaseQpidFeatureBuilderTestCase.java new file mode 100644 index 0000000000..3d3783eb04 --- /dev/null +++ b/RC9/qpid/java/management/client/src/test/java/org/apache/qpid/management/domain/model/BaseQpidFeatureBuilderTestCase.java @@ -0,0 +1,96 @@ +/* + * + * 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.domain.model; + +import static org.apache.qpid.management.domain.model.QpidFeatureBuilder.Attribute.desc; +import static org.apache.qpid.management.domain.model.QpidFeatureBuilder.Attribute.name; + +import java.util.HashMap; +import java.util.Map; + +import junit.framework.TestCase; + +import org.apache.qpid.management.configuration.Configurator; +import org.apache.qpid.management.domain.model.QpidFeatureBuilder.Attribute; + +/** + * Layer supertype for feature builder test cases. + * + * @author Andrea Gazzarini + */ +public abstract class BaseQpidFeatureBuilderTestCase extends TestCase +{ + protected final static String NAME = "aName"; + + protected final static String DESCRIPTION = "A description."; + + protected Map <String,Object> _featureDefinition; + protected QpidFeatureBuilder _builder; + + /** + * Set up fixture for all concrete builder test cases. + */ + @Override + protected void setUp () throws Exception + { + Configurator configurator = new Configurator(); + configurator.configure(); + _featureDefinition = new HashMap<String, Object>(); + _featureDefinition.put(name.name(),NAME); + _featureDefinition.put(desc.name(), DESCRIPTION); + } + + // Internal test used to avoid code duplication. + protected void internalTestForMissingMandatoryAttribute(Attribute ...toBeRemoved) + { + try + { + for (Attribute attribute : toBeRemoved) + { + _featureDefinition.remove(attribute.name()); + } + _builder.build(); + fail("If a mandatory attribute is missing an exception must be thrown!"); + } catch (UnableToBuildFeatureException expected) + { + assertTrue(expected instanceof MissingFeatureAttributesException); + for (Attribute attribute : toBeRemoved) + { + assertTrue(expected.getMessage().contains(attribute.name())); + } + } + } + + // Internal test used to avoid code duplication. + protected void internalTestForMissingOptionalAttribute(Attribute ...toBeRemoved) throws UnableToBuildFeatureException + { + for (Attribute attribute : toBeRemoved) + { + _featureDefinition.remove(attribute.name()); + } + _builder.build(); + + assertNotNull(_builder.getQpidFeature()); + assertNotNull(_builder.getManagementFeature()); + } + + +} diff --git a/RC9/qpid/java/management/client/src/test/java/org/apache/qpid/management/domain/model/DomainModelTest.java b/RC9/qpid/java/management/client/src/test/java/org/apache/qpid/management/domain/model/DomainModelTest.java new file mode 100644 index 0000000000..578fa36bc7 --- /dev/null +++ b/RC9/qpid/java/management/client/src/test/java/org/apache/qpid/management/domain/model/DomainModelTest.java @@ -0,0 +1,55 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.management.domain.model; + +import java.util.UUID; + +import org.apache.qpid.management.TestConstants; + +/** + * Test case for domain model entity. + * + * @author Andrea Gazzarini + */ +public class DomainModelTest extends BaseDomainModelTestCase +{ + private DomainModel _model; + + @Override + protected void setUp () throws Exception + { + _model = new DomainModel(UUID.randomUUID()); + } + + /** + * Tests the execution of the getPackage() method. + */ + public void testGetPackage() + { + assertFalse(_model.containsPackage(TestConstants.QPID_PACKAGE_NAME)); + + QpidPackage qpidPackage = _model.getPackageByName(TestConstants.QPID_PACKAGE_NAME); + assertEquals(TestConstants.QPID_PACKAGE_NAME,qpidPackage.getName()); + + QpidPackage theSameAsPreviousOne = _model.getPackageByName(TestConstants.QPID_PACKAGE_NAME); + assertSame(qpidPackage, theSameAsPreviousOne); + } +}
\ No newline at end of file diff --git a/RC9/qpid/java/management/client/src/test/java/org/apache/qpid/management/domain/model/OptionalPropertiesTest.java b/RC9/qpid/java/management/client/src/test/java/org/apache/qpid/management/domain/model/OptionalPropertiesTest.java new file mode 100644 index 0000000000..553c1c21de --- /dev/null +++ b/RC9/qpid/java/management/client/src/test/java/org/apache/qpid/management/domain/model/OptionalPropertiesTest.java @@ -0,0 +1,187 @@ +/* + * + * 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.domain.model; + +import java.nio.ByteBuffer; +import java.util.LinkedList; +import java.util.List; + +import junit.framework.TestCase; + +import org.apache.qpid.management.domain.model.type.Uint64; +import org.apache.qpid.transport.codec.BBDecoder; + +public class OptionalPropertiesTest extends TestCase +{ + public void testDecoderStateChange() + { + QpidProperty property = new QpidProperty(); + assertSame( + "Default decoder for properties is the one for mandatory properties.", + property._mandatoryPropertyDecoder, + property._decoder); + + property.markAsOptional(1); + assertSame( + "After a property has been marked as optional the corresponding decoder must be installed.", + property._optionalPropertyDecoder, + property._decoder); + } + + /** + * Tests the execution of the decode() method when the current property is optional but in the presence bitmask + * there's no the corresponding bit set. + * + * <br>precondition : property is optional and corresponding presence bit is not set. + * <br>postcondition : result must be null. + */ + public void testDecodeValueWithOptionalPropertyAndMissingValue() + { + byte [] presenceBytes = {2}; + + QpidProperty property = new QpidProperty(); + + // We don't need a decoder so in order to be sure that it won't be invoked set it to null. + BBDecoder nullDecoder = null; + + for (int i = 0; i < 8; i++) + { + // Property number 1 is declaring a value so skip it! + if (i != 1) + { + property.markAsOptional(i); + assertNull(property.decodeValue(nullDecoder, presenceBytes)); + } + } + } + + /** + * Tests the execution of the decode() method when the current property is optional but in the presence bitmask + * there's no the corresponding bit set. + * + * <br>precondition : property is optional and corresponding presence bit is not set. + * <br>postcondition : result must be null. + */ + public void testDecodeValueWithOptionalPropertyAndDeclaredValue() + { + byte [] presenceBytes = {4}; + Long _44 = new Long(44); + + QpidProperty property = new QpidProperty(); + property.setType(new Uint64()); + property.markAsOptional(2); + + ByteBuffer buffer = ByteBuffer.allocate(8); + buffer.putLong(_44); + buffer.rewind(); + BBDecoder decoder = new BBDecoder(); + + decoder.init(buffer); + assertEquals(_44,property.decodeValue(decoder, presenceBytes)); + } + + /** + * Tests the execution of the decode() method with a real scenario where there are mandatory and optional + * properties. + */ + public void testDecodeValueWithOptionalAndMandatoryProperties() + { + // With this bitset : + // + // 1th opt property is null; + // 2th opt property is null; + // 3th opt property is not null; + // 4th opt property is null; + // 5th opt propertyis null; + // 6th opt property is null; + // 7th opt property is null; + // 8th opt property is not null; + byte [] presenceBytes = {4,1}; + + List<QpidProperty> properties = new LinkedList<QpidProperty>(); + + properties.add(createProperty(false, -1)); + properties.add(createProperty(false, -1)); + properties.add(createProperty(true, 0)); + properties.add(createProperty(false, -1)); + properties.add(createProperty(false, -1)); + properties.add(createProperty(true, 1)); + properties.add(createProperty(false, -1)); + properties.add(createProperty(false, -1)); + properties.add(createProperty(true, 2)); + properties.add(createProperty(true, 3)); + properties.add(createProperty(true, 4)); + properties.add(createProperty(true, 5)); + properties.add(createProperty(true, 6)); + properties.add(createProperty(true, 7)); + properties.add(createProperty(false, -1)); + properties.add(createProperty(true, 8)); + + Long expectedResults [] = { + 1L, // p1 + 22L, // p2 + null, // p3 + 232L, // p4 + 211L, // p5 + null, // p6 + 232L, // p7 + 211L, // p8 + 999L, // p9 + null, // p10 + null, // p11 + null, // p12 + null, // p13 + null, // p14 + 626L, // p15 + 969L // p16 + }; + + + ByteBuffer buffer = ByteBuffer.allocate(expectedResults.length * 8); + for (Long expected : expectedResults) + { + if (expected != null) + { + buffer.putLong(expected); + } + } + buffer.rewind(); + BBDecoder decoder = new BBDecoder(); + + decoder.init(buffer); + int index = 0; + for (QpidProperty property : properties) + { + assertEquals(expectedResults[index++],property.decodeValue(decoder, presenceBytes)); + } + } + + private QpidProperty createProperty(boolean isOptional, int optionalIndex) + { + QpidProperty property = new QpidProperty(); + property.setType(new Uint64()); + if (isOptional) + { + property.markAsOptional(optionalIndex); + } + return property; + } +}
\ No newline at end of file diff --git a/RC9/qpid/java/management/client/src/test/java/org/apache/qpid/management/domain/model/QpidClassTest.java b/RC9/qpid/java/management/client/src/test/java/org/apache/qpid/management/domain/model/QpidClassTest.java new file mode 100644 index 0000000000..284f3841b8 --- /dev/null +++ b/RC9/qpid/java/management/client/src/test/java/org/apache/qpid/management/domain/model/QpidClassTest.java @@ -0,0 +1,408 @@ +/* +* + * 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.domain.model; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import javax.management.MBeanAttributeInfo; +import javax.management.MBeanInfo; + +import junit.framework.TestCase; + +import org.apache.qpid.management.TestConstants; +import org.apache.qpid.management.configuration.ConfigurationException; +import org.apache.qpid.management.configuration.Configurator; +import org.apache.qpid.management.domain.handler.impl.MethodOrEventDataTransferObject; +import org.apache.qpid.management.domain.model.QpidClass.QpidManagedObject; + +/** + * Test case for Qpid Class. + * + * @author Andrea Gazzarini + */ +public class QpidClassTest extends TestCase +{ + private QpidClass _class; + private QpidPackage _package; + + @Override + protected void setUp () throws ConfigurationException + { + Configurator configurator = new Configurator(); + configurator.configure(); + _package = new QpidPackage(TestConstants.QPID_PACKAGE_NAME,TestConstants.DOMAIN_MODEL); + _class = new QpidClass(TestConstants.EXCHANGE_CLASS_NAME,TestConstants.HASH,_package); + } + + /** + * Tests the execution of the getObjectInstance() method. + * Basically it tests the addition of a new object instance. + * + * <br>precondition: class has no object instances. + * <br>precondition : class contains the added object instance. + */ + public void testGetObjectInstance() + { + assertFalse ( + "Nobody set instance #"+TestConstants.OBJECT_ID+" into this class so why is it there?", + _class._objectInstances.containsKey(TestConstants.OBJECT_ID)); + + QpidManagedObject instance = _class.getObjectInstance(TestConstants.OBJECT_ID, false); + + assertTrue ( + "Now the instance #"+TestConstants.OBJECT_ID+" should be there...", + _class._objectInstances.containsKey(TestConstants.OBJECT_ID)); + + assertEquals(instance,_class.getObjectInstance(TestConstants.OBJECT_ID, false)); + } + + /** + * Tests the injection of instrumentation and configuration data (related to a specific object instance) before the + * schema is installed. + * + * <br>precondition : the schema hasn't yet installed on this class. + * <br>postcondition : incoming configuration & instrumentation data is stored into the corresponding object instance. + */ + public void testAddInstrumentationAndConfigurationDataBeforeSchemaInstallation() + { + _class._state = _class._schemaRequestedButNotYetInjected; + QpidManagedObject objectInstance = _class.getObjectInstance(TestConstants.OBJECT_ID,false); + + assertTrue( + "This object instance is a new one so how is it possible that it has already instrumentation data? ", + objectInstance._rawInstrumentationData.isEmpty()); + assertTrue( + "This object instance is a new one so how is it possible that it has already configuration data? ", + objectInstance._rawConfigurationData.isEmpty()); + + byte [] dummyConfigurationData = {1,2,3,4,5,6,7,8}; + byte [] dummyInstrumentationData = {11,21,31,41,51,61,71,81}; + + _class.addConfigurationData(TestConstants.OBJECT_ID, dummyConfigurationData); + _class.addInstrumentationData(TestConstants.OBJECT_ID, dummyInstrumentationData); + + assertEquals("Now configuration data should be there...",1,objectInstance._rawConfigurationData.size()); + assertEquals("Now instrumentation data should be there...",1,objectInstance._rawInstrumentationData.size()); + + assertTrue( + "Object instance configuration data should be the previously set...", + Arrays.equals(objectInstance._rawConfigurationData.get(0), + dummyConfigurationData)); + + assertTrue( + "Object instance instrumentation data should be the previously set...", + Arrays.equals(objectInstance._rawInstrumentationData.get(0), + dummyInstrumentationData)); + } + + /** + * Tests the internal state change of a class definition. + */ + public void testStateChange() throws UnableToBuildFeatureException + { + _class = new QpidClass(TestConstants.EXCHANGE_CLASS_NAME,TestConstants.HASH,_package) + { + @Override + void requestSchema() throws Exception { + _state = _schemaRequestedButNotYetInjected; + } + + @Override + void setSchema(List<Map<String, Object>> propertyDefinitions, + List<Map<String, Object>> statisticDefinitions, + List<MethodOrEventDataTransferObject> methodDefinitions) throws UnableToBuildFeatureException { + _state = _schemaInjected; + } + }; + + assertSame( + "Initial state doesn't match.", + _class._schemaNotRequested, + _class._state); + + _class.addConfigurationData(TestConstants.OBJECT_ID, TestConstants.TEST_RAW_DATA); + _class.addInstrumentationData(TestConstants.OBJECT_ID, TestConstants.TEST_RAW_DATA); + + assertSame( + "Request schema has been requested but not yet injected. The current state is not indicating that!", + _class._schemaRequestedButNotYetInjected, + _class._state); + + _class.setSchema( + TestConstants.EMPTY_PROPERTIES_SCHEMA, + TestConstants.EMPTY_STATISTICS_SCHEMA, + new LinkedList<MethodOrEventDataTransferObject>()); + + assertSame( + "Request schema has been injected. The current state is not indicating that!", + _class._schemaInjected, + _class._state); + } + + /** + * Tests the injection of a valid schema on a QpidClass. + * + * <br>precondition : a valid arguments is injected on the qpid class. + * <br>postcondition : class definition is built successfully. + */ + public void testSchemaInjectionOk() throws UnableToBuildFeatureException + { + _class = new QpidClass(TestConstants.EXCHANGE_CLASS_NAME,TestConstants.HASH,_package) + { + @Override + void requestSchema() throws Exception + { + // DO NOTHING : QMan is not running and therefore the schema will be manually injected. + } + + @Override + void updateInstanceWithConfigurationData(QpidManagedObject instance, byte[] rawData) + { + // DO NOTHING Given raw data is not valid so it cannot be converted. + } + }; + + // Incoming configuration data : that will fire the schema request and a state change + // from schema-not-requested to schema-requested-but-not-injected + _class.addConfigurationData(TestConstants.OBJECT_ID, TestConstants.TEST_RAW_DATA); + + // I must be sure that what is obvious for me it's obvious for QMan... :) + assertSame( + "Request schema has been requested but not yet injected. The current state is not indicating that!", + _class._schemaRequestedButNotYetInjected, + _class._state); + + List<Map<String,Object>> propertyDefinitions = new ArrayList<Map<String,Object>>(2); + propertyDefinitions.add( + createProperty( + TestConstants.AGE_ATTRIBUTE_NAME, + 1, + TestConstants.YEARS, + TestConstants.SAMPLE_MIN_VALUE, + TestConstants.SAMPLE_MAX_VALUE, + null, + TestConstants.AGE_ATTRIBUTE_DESCRIPTION, + TestConstants._1, + false, + TestConstants._0)); + + propertyDefinitions.add( + createProperty( + TestConstants.SURNAME_ATTRIBUTE_NAME, + TestConstants.SAMPLE_ACCESS_CODE, + null, + null, + null, + TestConstants.SAMPLE_MAX_VALUE, + TestConstants.SURNAME_ATTRIBUTE_DESCRIPTION, + TestConstants._1, + true, + TestConstants._1)); + + _class.setSchema(propertyDefinitions, TestConstants.EMPTY_STATISTICS_SCHEMA, TestConstants.EMPTY_METHODS_SCHEMA); + + assertEquals(2,_class._properties.size()); + + QpidProperty property = _class._properties.get(TestConstants.AGE_ATTRIBUTE_NAME); + assertEquals(TestConstants.AGE_ATTRIBUTE_NAME,property.getName()); + assertEquals(AccessMode.RC,property.getAccessMode()); + assertEquals(TestConstants.YEARS,property.getUnit()); + assertEquals(TestConstants.SAMPLE_MIN_VALUE,property.getMinValue()); + assertEquals(TestConstants.SAMPLE_MAX_VALUE,property.getMaxValue()); + assertEquals(Integer.MIN_VALUE,property.getMaxLength()); + assertEquals(TestConstants.AGE_ATTRIBUTE_DESCRIPTION,property.getDescription()); + assertEquals(Short.class,property.getJavaType()); + assertFalse(property.isOptional()); + + property = _class._properties.get(TestConstants.SURNAME_ATTRIBUTE_NAME); + assertEquals(TestConstants.SURNAME_ATTRIBUTE_NAME,property.getName()); + assertEquals(AccessMode.RC,property.getAccessMode()); + assertNull(property.getUnit()); + assertEquals(Integer.MIN_VALUE,property.getMinValue()); + assertEquals(Integer.MIN_VALUE,property.getMaxValue()); + assertEquals(TestConstants.SAMPLE_MAX_VALUE,property.getMaxLength()); + assertEquals(TestConstants.SURNAME_ATTRIBUTE_DESCRIPTION,property.getDescription()); + assertEquals(Short.class,property.getJavaType()); + assertTrue(property.isOptional()); + + MBeanInfo mbeanInfo = _class._metadata; + assertEquals(TestConstants.EXCHANGE_CLASS_NAME,mbeanInfo.getClassName()); + + MBeanAttributeInfo [] attributes = mbeanInfo.getAttributes(); + assertEquals(2,attributes.length); + + MBeanAttributeInfo attribute = attributes[0]; + assertEquals(TestConstants.AGE_ATTRIBUTE_NAME,attribute.getName()); + assertEquals(TestConstants.AGE_ATTRIBUTE_DESCRIPTION,attribute.getDescription()); + assertFalse(attribute.isWritable()); + assertTrue(attribute.isReadable()); + assertEquals(Short.class.getName(),attribute.getType()); + + attribute = attributes[1]; + assertEquals(TestConstants.SURNAME_ATTRIBUTE_NAME,attribute.getName()); + assertEquals(TestConstants.SURNAME_ATTRIBUTE_DESCRIPTION,attribute.getDescription()); + assertFalse(attribute.isWritable()); + assertTrue(attribute.isReadable()); + assertEquals(Short.class.getName(),attribute.getType()); + } + + /** + * Tests the behaviour of the class when a schema request can't be made. + * + * <br>precondition : class must be in "schema-not-requested" state when incoming data arrives. + * <br>postcondition : no exception is thrown and no state transition happens. + */ + public void testStateChange_withRequestSchemaFailure() + { + _class= new QpidClass(TestConstants.EXCHANGE_CLASS_NAME,TestConstants.HASH,_package) + { + @Override + void requestSchema() throws Exception { + throw new Exception(); + } + + @Override + void setSchema( + List<Map<String, Object>> propertyDefinitions, + List<Map<String, Object>> statisticDefinitions, + List<MethodOrEventDataTransferObject> methodDefinitions) throws UnableToBuildFeatureException + { + } + }; + + assertSame( + "Initial state must be schema-not-requested.", + _class._schemaNotRequested, + _class._state); + + _class.addInstrumentationData(TestConstants.OBJECT_ID, TestConstants.TEST_RAW_DATA); + + assertSame( + "Current state must be still schema-not-requested.", + _class._schemaNotRequested, + _class._state); + } + + /** + * Tests the behaviour of the class when a schema injection fails. + * + * <br>precondition : class must be in "schema-not-requested" state when incoming data arrives. + * <br>postcondition : an exception is thrown and no state transition happens. + */ + public void testStateChange_withSchemaInjectionFailure() + { + _class = new QpidClass(TestConstants.EXCHANGE_CLASS_NAME,TestConstants.HASH,_package) + { + @Override + void requestSchema() throws Exception + { + // DO NOTHING. + } + + @Override + void setSchema(List<Map<String, Object>> propertyDefinitions, + List<Map<String, Object>> statisticDefinitions, + List<MethodOrEventDataTransferObject> methodDefinitions) + throws UnableToBuildFeatureException + { + throw new UnableToBuildFeatureException(""); + } + }; + + assertSame( + "Initial state must be schema-not-requested.", + _class._schemaNotRequested, + _class._state); + + _class.addInstrumentationData(TestConstants.OBJECT_ID, TestConstants.TEST_RAW_DATA); + + assertSame( + "Request schema has been requested but not yet injected. The current state is not indicating that!", + _class._schemaRequestedButNotYetInjected, + _class._state); + + try { + _class.setSchema( + TestConstants.EMPTY_PROPERTIES_SCHEMA, + TestConstants.EMPTY_STATISTICS_SCHEMA, + TestConstants.EMPTY_METHODS_SCHEMA); + fail("If we are here something was wrong becuase the setSchema() of this event is throwing an exception..."); + } catch (UnableToBuildFeatureException expected) { + assertSame( + "Request schema has been requested but not yet injected. The current state is not indicating that!", + _class._schemaRequestedButNotYetInjected, + _class._state); + } + } + + private Map<String,Object> createProperty( + String name, + Integer accessCode, + String unit, + Integer min, + Integer max, + Integer maxLength, + String description, + Integer type, + boolean optional, + Integer index) + { + Map <String,Object> result = new HashMap<String, Object>(); + result.put(QpidFeatureBuilder.Attribute.name.name(),name); + result.put(QpidFeatureBuilder.Attribute.access.name(), accessCode); + + if (unit != null) + { + result.put(QpidFeatureBuilder.Attribute.unit.name(),unit); + } + + if (min != null) + { + result.put(QpidFeatureBuilder.Attribute.min.name(), min); + } + + if (max != null) + { + result.put(QpidFeatureBuilder.Attribute.max.name(),max); + } + + if (maxLength != null) + { + result.put(QpidFeatureBuilder.Attribute.maxlen.name(),maxLength); + } + + result.put(QpidFeatureBuilder.Attribute.desc.name(), description); + result.put(QpidFeatureBuilder.Attribute.type.name(), type); + result.put(QpidFeatureBuilder.Attribute.optional.name(),optional ? 1 : 0); + + if (index != null) + { + result.put(QpidFeatureBuilder.Attribute.index.name(), index); + } + return result; + } +} diff --git a/RC9/qpid/java/management/client/src/test/java/org/apache/qpid/management/domain/model/QpidEventTest.java b/RC9/qpid/java/management/client/src/test/java/org/apache/qpid/management/domain/model/QpidEventTest.java new file mode 100644 index 0000000000..954a419787 --- /dev/null +++ b/RC9/qpid/java/management/client/src/test/java/org/apache/qpid/management/domain/model/QpidEventTest.java @@ -0,0 +1,293 @@ +/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.management.domain.model;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.management.InstanceNotFoundException;
+import javax.management.MBeanException;
+import javax.management.ObjectName;
+import javax.management.ReflectionException;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.management.TestConstants;
+import org.apache.qpid.management.configuration.ConfigurationException;
+import org.apache.qpid.management.configuration.Configurator;
+import org.apache.qpid.management.domain.model.QpidEvent.QpidManagedEvent;
+
+/**
+ * Test case for qpid class entity.
+ *
+ * @author Andrea Gazzarini
+ */
+public class QpidEventTest extends TestCase
+{
+ private QpidEvent _event;
+ private QpidPackage _qpidPackage;
+
+ @Override
+ protected void setUp () throws Exception
+ {
+ _qpidPackage = new QpidPackage(TestConstants.QPID_PACKAGE_NAME,TestConstants.DOMAIN_MODEL);
+ _event = new QpidEvent(TestConstants.BIND_EVENT_NAME,TestConstants.HASH,_qpidPackage);
+ }
+
+ /**
+ * Tests the execution of the createEventInstance() method.
+ * Basically it tests the addition of a new event instance.
+ *
+ * <br>precondition: event deifinition has no object instances.
+ * <br>precondition : event definition contains the new object instance.
+ */
+ public void testCreateEventInstance()
+ {
+ assertTrue(
+ "A just created event should be empty. I mean there shouldn't be event instances inside.",
+ _event.hasNoInstances());
+
+ QpidManagedEvent instance = createEventInstance();
+
+ assertFalse (
+ "Now a new instance should be there...",
+ _event.hasNoInstances());
+
+ assertEquals(TestConstants.TEST_RAW_DATA,instance._rawEventData);
+ assertEquals(TestConstants.NOW,instance._timestamp);
+ assertEquals(TestConstants.SEVERITY, instance._severity);
+ }
+
+ /**
+ * Tests the internal state change of an event definition.
+ */
+ public void testStateChange() throws UnableToBuildFeatureException
+ {
+ // Let's override this class because this is not an online tests and therefore
+ // QMan is not supposed to be up.
+ _event = new QpidEvent(TestConstants.BIND_EVENT_NAME,TestConstants.HASH,_qpidPackage)
+ {
+ @Override
+ void requestSchema() throws Exception {
+ // Do Nothing.
+ }
+
+ @Override
+ void setSchema(List<Map<String, Object>> argumentDefinitions)throws UnableToBuildFeatureException {
+ _state = _schemaInjected;
+ }
+ };
+
+ assertSame(
+ "Initial state doesn't match.",
+ _event._schemaNotRequested,
+ _event._state);
+
+ _event.addEventData(TestConstants.TEST_RAW_DATA, TestConstants.NOW, TestConstants.SEVERITY);
+
+ assertSame(
+ "Request schema has been requested but not yet injected. The current state is not indicating that!",
+ _event._schemaRequestedButNotYetInjected,
+ _event._state);
+
+ _event.setSchema(TestConstants.EMPTY_ARGUMENTS_SCHEMA);
+
+ assertSame(
+ "Request schema has been injected. The current state is not indicating that!",
+ _event._schemaInjected,
+ _event._state);
+ }
+
+ /**
+ * Tests the injection of a valid schema on a QpidEvent.
+ *
+ * <br>precondition : a valid arguments is injected on the qpid event.
+ * <br>postcondition : event definition is built successfully.
+ */
+ public void testSchemaInjectionOK() throws UnableToBuildFeatureException, ConfigurationException, InstanceNotFoundException, MBeanException, ReflectionException
+ {
+ _event = new QpidEvent(TestConstants.BIND_EVENT_NAME,TestConstants.HASH,_qpidPackage)
+ {
+ @Override
+ void requestSchema() throws Exception
+ {
+ // DO NOTHING : QMan is not running and therefore the schema will be manually injected.
+ }
+
+ @Override
+ void updateEventInstanceWithData(QpidManagedEvent instance)
+ {
+ // DO NOTHING : otherwise we should supply a valid raw data to be converted. ;-)
+ }
+ };
+
+ Configurator configurator = new Configurator();
+ configurator.configure();
+
+ List<Map<String,Object>> arguments = new ArrayList<Map<String, Object>>();
+ arguments.add(createArgument(TestConstants.AGE_ATTRIBUTE_NAME, TestConstants.AGE_ATTRIBUTE_DESCRIPTION));
+ arguments.add(createArgument(TestConstants.SURNAME_ATTRIBUTE_NAME, TestConstants.SURNAME_ATTRIBUTE_DESCRIPTION));
+
+ // Incoming data : that will fire the schema request and a state change from schema-not-requested to schema-requested-but-not-injected
+ _event.addEventData(TestConstants.TEST_RAW_DATA, TestConstants.NOW, TestConstants.SEVERITY);
+
+ // I must be sure that what is obvious for me it's obvious for QMan... :)
+ assertSame(
+ "Request schema has been requested but not yet injected. The current state is not indicating that!",
+ _event._schemaRequestedButNotYetInjected,
+ _event._state);
+
+ // Inject schema
+ _event.setSchema(arguments);
+
+ // Arguments must be 2 + 2 (severity)
+ assertEquals(2,_event._arguments.size());
+
+ QpidProperty argument = _event._arguments.get(TestConstants.AGE_ATTRIBUTE_NAME);
+ assertEquals(TestConstants.AGE_ATTRIBUTE_NAME,argument.getName());
+ assertEquals(AccessMode.RO,argument.getAccessMode());
+ assertEquals(TestConstants.AGE_ATTRIBUTE_DESCRIPTION,argument.getDescription());
+ assertEquals(Short.class,argument.getJavaType());
+ assertFalse(argument.isOptional());
+
+ argument = _event._arguments.get(TestConstants.SURNAME_ATTRIBUTE_NAME);
+ assertEquals(TestConstants.SURNAME_ATTRIBUTE_NAME,argument.getName());
+ assertEquals(AccessMode.RO,argument.getAccessMode());
+ assertEquals(TestConstants.SURNAME_ATTRIBUTE_DESCRIPTION,argument.getDescription());
+ assertEquals(Short.class,argument.getJavaType());
+ assertFalse(argument.isOptional());
+
+ assertEquals(1,_event._eventInstances.size());
+
+ JmxService service = new JmxService();
+ Set<ObjectName> objectNames = service.getEventMBeans();
+
+ assertEquals(1,objectNames.size());
+ }
+
+ /**
+ * Tests the behaviour of the event class when a schema request can't be made.
+ *
+ * <br>precondition : event must be in "schema-not-requested" state when incoming data arrives.
+ * <br>postcondition : no exception is thrown and no state transition happens.
+ */
+ public void testStateChange_withRequestSchemaFailure()
+ {
+ _event = new QpidEvent(TestConstants.BIND_EVENT_NAME,TestConstants.HASH,_qpidPackage)
+ {
+ @Override
+ void requestSchema() throws Exception {
+ throw new Exception();
+ }
+
+ @Override
+ void setSchema(List<Map<String, Object>> argumentDefinitions)throws UnableToBuildFeatureException {
+ _state = _schemaInjected;
+ }
+ };
+
+ assertSame(
+ "Initial state must be schema-not-requested.",
+ _event._schemaNotRequested,
+ _event._state);
+
+ _event.addEventData(TestConstants.TEST_RAW_DATA, TestConstants.NOW, TestConstants.SEVERITY);
+
+ assertSame(
+ "Current state must be still schema-not-requested.",
+ _event._schemaNotRequested,
+ _event._state);
+ }
+
+ /**
+ * Tests the behaviour of the event class when a schema injection fails.
+ *
+ * <br>precondition : event must be in "schema-not-requested" state when incoming data arrives.
+ * <br>postcondition : an exception is thrown and no state transition happens.
+ */
+ public void testStateChange_withSchemaInjectionFailure()
+ {
+ _event = new QpidEvent(TestConstants.BIND_EVENT_NAME,TestConstants.HASH,_qpidPackage)
+ {
+ @Override
+ void requestSchema() throws Exception {
+ // DO NOTHING.
+ }
+
+ @Override
+ void setSchema(List<Map<String, Object>> argumentDefinitions)throws UnableToBuildFeatureException {
+ throw new UnableToBuildFeatureException("");
+ }
+ };
+
+ assertSame(
+ "Initial state must be schema-not-requested.",
+ _event._schemaNotRequested,
+ _event._state);
+
+ _event.addEventData(TestConstants.TEST_RAW_DATA, TestConstants.NOW, TestConstants.SEVERITY);
+
+ assertSame(
+ "Request schema has been requested but not yet injected. The current state is not indicating that!",
+ _event._schemaRequestedButNotYetInjected,
+ _event._state);
+
+ try {
+ _event.setSchema(TestConstants.EMPTY_ARGUMENTS_SCHEMA);
+ fail("If we are here something was wrong becuase the setSchema() of this event is throwing an exception...");
+ } catch (UnableToBuildFeatureException expected) {
+ assertSame(
+ "Request schema has been requested but not yet injected. The current state is not indicating that!",
+ _event._schemaRequestedButNotYetInjected,
+ _event._state);
+ }
+ }
+
+ /**
+ * Factory method for qpid managed event instances.
+ *
+ * @return a new QpidManagedEvent with test data inside.
+ */
+ private QpidManagedEvent createEventInstance()
+ {
+ return _event.createEventInstance(
+ TestConstants.TEST_RAW_DATA,
+ TestConstants.NOW,
+ TestConstants.SEVERITY);
+ }
+
+ /**
+ * Factory method for event argument.
+ *
+ * @return a new argument metadata.
+ */
+ private Map<String,Object> createArgument(String name,String desc)
+ {
+ Map <String,Object> argument = new HashMap<String, Object>();
+ argument.put(QpidFeatureBuilder.Attribute.name.name(),name);
+ argument.put(QpidFeatureBuilder.Attribute.desc.name(), desc);
+ argument.put(QpidFeatureBuilder.Attribute.type.name(), TestConstants._1);
+ return argument;
+ }
+}
diff --git a/RC9/qpid/java/management/client/src/test/java/org/apache/qpid/management/domain/model/QpidMethodBuilderTest.java b/RC9/qpid/java/management/client/src/test/java/org/apache/qpid/management/domain/model/QpidMethodBuilderTest.java new file mode 100644 index 0000000000..06dc35b0b1 --- /dev/null +++ b/RC9/qpid/java/management/client/src/test/java/org/apache/qpid/management/domain/model/QpidMethodBuilderTest.java @@ -0,0 +1,147 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.management.domain.model; + +import static org.apache.qpid.management.domain.model.QpidFeatureBuilder.Attribute.dir; +import static org.apache.qpid.management.domain.model.QpidFeatureBuilder.Attribute.name; +import static org.apache.qpid.management.domain.model.QpidFeatureBuilder.Attribute.type; +import static org.apache.qpid.management.domain.model.QpidFeatureBuilder.Attribute.unit; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.management.MBeanOperationInfo; + +import org.apache.qpid.management.Names; +import org.apache.qpid.management.domain.handler.impl.MethodOrEventDataTransferObject; +import org.apache.qpid.management.domain.model.QpidFeatureBuilder.Attribute; + +/** + * Test case for Qpid Statistic builder. + * + * @author Andrea Gazzarini + */ +public class QpidMethodBuilderTest extends BaseQpidFeatureBuilderTestCase +{ + private final static Integer ARG_COUNT = 3; + private MethodOrEventDataTransferObject _methodDefinition; + + private List<Map<String,Object>> _argumentsDefinitons = new ArrayList<Map<String, Object>>(); + + @Override + protected void setUp () throws Exception + { + super.setUp(); + _featureDefinition.put(Names.ARG_COUNT_PARAM_NAME, ARG_COUNT); + + Map<String,Object> arg1 = new HashMap<String,Object>(); + arg1.put(name.name(), "arg1"); + arg1.put(type.name(),1); + arg1.put(dir.name(),Direction.I.name()); + arg1.put(unit.name(), "bytes"); + + Map<String,Object> arg2 = new HashMap<String,Object>(); + arg2.put(name.name(), "arg2"); + arg2.put(type.name(),1); + arg2.put(dir.name(),Direction.O.name()); + arg2.put(unit.name(), "bytes"); + + Map<String,Object> arg3 = new HashMap<String,Object>(); + arg3.put(name.name(), "arg3"); + arg3.put(type.name(),1); + arg3.put(dir.name(),Direction.IO.name()); + arg3.put(unit.name(), "bytes"); + + /* + dir yes no yes Direction code for method arguments + unit yes yes yes Units for numeric values (i.e. seconds, bytes, etc.) + min yes no yes Minimum value for numerics + max yes no yes Maximum value for numerics + maxlen yes no yes Maximum length for strings + desc yes yes yes Description of the argument + default yes no yes Default value for the argument + */ + _argumentsDefinitons.add(arg1); + _argumentsDefinitons.add(arg2); + + _methodDefinition = new MethodOrEventDataTransferObject(_featureDefinition,_argumentsDefinitons); + _builder = QpidFeatureBuilder.createMethodBuilder(_methodDefinition); + } + + /** + * Tests the build process for a statistic when the definition map doesn't contains type attribute. + * + * <br>precondition: definition map doesn't contains type attribute. + * <br>postcondition : an exception should be thrown indicating the failure. That exception must contain the name of the + * missing attribute. + */ + public void testMethodBuilderKO_WithMissingName() + { + internalTestForMissingMandatoryAttribute(Attribute.name); + } + + /** + * Tests the build process for a statistic when the definition map doesn't contain type, name, index & optional attributes. + * + * <br>precondition: definition map doesn't contain type, name, index & optional attributes. + * <br>postcondition : an exception should be thrown indicating the failure. That exception must contain the name of the + * missing attributes. + */ + public void testMethodBuilderOK_WithMissingUnit() throws UnableToBuildFeatureException + { + internalTestForMissingOptionalAttribute(Attribute.unit); + } + + /** + * Tests the build process for a statistic when the definition map doesn't unit attribute. + * Note that this attribute is optional and therefore the build must succeed. + * + * <br>precondition: definition map doesn't contain unit attribute. + * <br>postcondition : no exception is thrown and the statistic is built. + */ + public void testMethodBuilderOK_WithMissingDescription() throws UnableToBuildFeatureException + { + internalTestForMissingOptionalAttribute(Attribute.desc); + } + + /** + * Tests the build process for a statistic when the definition map contains valid values. + * + * <br>precondition : the statistic definiton map contains valid values. + * <br>postcondition : no exception is thrown and the statistisc is built as expected. + */ + public void testMethodBuilderOK() throws UnableToBuildFeatureException + { + _builder.build(); + + QpidMethod method = (QpidMethod) _builder.getQpidFeature(); + MBeanOperationInfo info = (MBeanOperationInfo) _builder.getManagementFeature(); + + assertEquals(NAME,method.getName()); + + assertEquals(DESCRIPTION,method.getDescription()); + + assertEquals(method.getDescription(),info.getDescription()); + assertEquals(method.getName(),info.getName()); + } +} diff --git a/RC9/qpid/java/management/client/src/test/java/org/apache/qpid/management/domain/model/QpidNumberPropertyTest.java b/RC9/qpid/java/management/client/src/test/java/org/apache/qpid/management/domain/model/QpidNumberPropertyTest.java new file mode 100644 index 0000000000..374011d150 --- /dev/null +++ b/RC9/qpid/java/management/client/src/test/java/org/apache/qpid/management/domain/model/QpidNumberPropertyTest.java @@ -0,0 +1,171 @@ +/* + * + * 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.domain.model; + +import junit.framework.TestCase; + +import org.apache.qpid.management.configuration.Configurator; +import org.apache.qpid.management.domain.model.type.Uint8; + +public class QpidNumberPropertyTest extends TestCase +{ + private QpidProperty _property; + private Long _value = 55432L; + + @Override + protected void setUp () throws Exception + { + Configurator configurator = new Configurator(); + configurator.configure(); + _property = new QpidProperty(); + _property.setName("average"); + _property.setAccessMode(AccessMode.RW); + _property.setType(new Uint8()); + } + + /** + * Tests the validation of a qpid property when the type is a number and no constraint has been set. + * + * <br>precondition : property type is a string, no constraint has been set. + * <br>postcondition : no exception is thrown and the validation succeeds. + */ + public void testValidationWithoutConstraints() { + try + { + _property.validate(_value); + } catch (ValidationException notExpected) + { + fail("If no constraint has been set on this property why the validation is failing?"); + } + } + + /** + * Tests the validation of a qpid property when the type is a number and a max value constraint has been set. + * + * <br>precondition : property type is a number, max value has been set and property value is greater than max value. + * <br>postcondition : an exception is thrown indicating the validation failure. + */ + public void testValidationKO_withMaxValue() { + int maxValue = (int)(_value-1); + _property.setMaxValue(maxValue); + + try + { + _property.validate(_value); + fail("The given value is violating the installed constraint so an exception must be thrown."); + } catch (ValidationException expected) + { + assertEquals(ValidationException.MAX_VALUE,expected.getConstraintName()); + assertEquals(maxValue,expected.getConstraintValue()); + assertEquals((double)_value,expected.getFeatureValue()); + assertEquals(_property.getName(),expected.getFeatureName()); + } + } + + /** + * Tests the validation of a qpid property when the type is a number and a min value constraint has been set. + * + * <br>precondition : property type is a number, min value has been set and property value is lesser than min value. + * <br>postcondition : an exception is thrown indicating the validation failure. + */ + public void testValidationKO_withMinValue() { + int minValue = (int)(_value+1); + _property.setMinValue(minValue); + + try + { + _property.validate(_value); + fail("The given value is violating the installed constraint so an exception must be thrown."); + } catch (ValidationException expected) + { + assertEquals(ValidationException.MIN_VALUE,expected.getConstraintName()); + assertEquals(minValue,expected.getConstraintValue()); + assertEquals((double)_value,expected.getFeatureValue()); + assertEquals(_property.getName(),expected.getFeatureName()); + } + } + + + /** + * Tests the validation of a qpid property when the number is a string and the property value is null. + * + * <br>precondition : property type is a number and property value is null.. + * <br>postcondition : no exception is thrown. That is : the validation succeeds. + */ + public void testValidationOK_withNullValue() { + try + { + _property.validate(null); + } catch (ValidationException notExpected) + { + fail("No constraint has been violated so validate() shouldn't raise an exception."); + } + + _property.setMinValue(1); + _property.setMaxValue(10); + + try + { + _property.validate(null); + } catch (ValidationException notExpected) + { + fail("No constraint has been violated so validate() shouldn't raise an exception."); + } + } + + /** + * Tests the validation of a qpid property when the type is a number and a max / min constraints have been set. + * + * <br>precondition : property type is a number, max / min constraint have been set and property value is wrong. + * <br>postcondition : an exception is thrown indicating the validation failure. + */ + public void testValidationOK_withMinAndMaxConstraint() { + int minValue = (int)(_value+1); + int maxValue = (int)(_value-1); + _property.setMinValue(minValue); + _property.setMaxValue(maxValue); + + try + { + _property.validate(_value); + fail("The given value is violating the installed constraint so an exception must be thrown."); + } catch (ValidationException expected) + { + assertEquals(ValidationException.MIN_VALUE,expected.getConstraintName()); + assertEquals(minValue,expected.getConstraintValue()); + assertEquals((double)_value,expected.getFeatureValue()); + assertEquals(_property.getName(),expected.getFeatureName()); + } + + _property.setMinValue(0); + try + { + _property.validate(_value); + fail("The given value is violating the installed constraint so an exception must be thrown."); + } catch (ValidationException expected) + { + assertEquals(ValidationException.MAX_VALUE,expected.getConstraintName()); + assertEquals(maxValue,expected.getConstraintValue()); + assertEquals((double)_value,expected.getFeatureValue()); + assertEquals(_property.getName(),expected.getFeatureName()); + } + } +} diff --git a/RC9/qpid/java/management/client/src/test/java/org/apache/qpid/management/domain/model/QpidPackageTest.java b/RC9/qpid/java/management/client/src/test/java/org/apache/qpid/management/domain/model/QpidPackageTest.java new file mode 100644 index 0000000000..b7eb9055ba --- /dev/null +++ b/RC9/qpid/java/management/client/src/test/java/org/apache/qpid/management/domain/model/QpidPackageTest.java @@ -0,0 +1,53 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.management.domain.model; + +import org.apache.qpid.management.TestConstants; + +/** + * Test case for Qpid package entity. + * + * @author Andrea Gazzarini + */ +public class QpidPackageTest extends BaseDomainModelTestCase +{ + private QpidPackage _qpidPackage; + + @Override + protected void setUp () throws Exception + { + _qpidPackage = new QpidPackage(TestConstants.QPID_PACKAGE_NAME, TestConstants.DOMAIN_MODEL); + } + + /** + * Tests the association of a new class with a qpid package. + * + * <br>precondition : the package is not associated with any class. + * <br>postcondition : the package is now associated with the given class. + */ + public void testAddClass() throws UnableToBuildFeatureException { + assertFalse(_qpidPackage.alreadyContainsClassDefinition(TestConstants.EXCHANGE_CLASS_NAME, TestConstants.HASH)); + + _qpidPackage.getQpidClass(TestConstants.EXCHANGE_CLASS_NAME, TestConstants.HASH, true); + + assertTrue(_qpidPackage.alreadyContainsClassDefinition(TestConstants.EXCHANGE_CLASS_NAME, TestConstants.HASH)); + } +}
\ No newline at end of file diff --git a/RC9/qpid/java/management/client/src/test/java/org/apache/qpid/management/domain/model/QpidPropertyBuilderTest.java b/RC9/qpid/java/management/client/src/test/java/org/apache/qpid/management/domain/model/QpidPropertyBuilderTest.java new file mode 100644 index 0000000000..8ad177645c --- /dev/null +++ b/RC9/qpid/java/management/client/src/test/java/org/apache/qpid/management/domain/model/QpidPropertyBuilderTest.java @@ -0,0 +1,269 @@ +/* + * + * 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.domain.model; + +import static org.apache.qpid.management.domain.model.QpidFeatureBuilder.Attribute.access; +import static org.apache.qpid.management.domain.model.QpidFeatureBuilder.Attribute.index; +import static org.apache.qpid.management.domain.model.QpidFeatureBuilder.Attribute.max; +import static org.apache.qpid.management.domain.model.QpidFeatureBuilder.Attribute.min; +import static org.apache.qpid.management.domain.model.QpidFeatureBuilder.Attribute.optional; +import static org.apache.qpid.management.domain.model.QpidFeatureBuilder.Attribute.type; +import static org.apache.qpid.management.domain.model.QpidFeatureBuilder.Attribute.unit; + +import javax.management.MBeanAttributeInfo; + +import org.apache.qpid.management.configuration.UnknownTypeCodeException; +import org.apache.qpid.management.domain.model.QpidFeatureBuilder.Attribute; + +/** + * Test case for Qpid Property builder. + * + * @author Andrea Gazzarini + */ +public class QpidPropertyBuilderTest extends BaseQpidFeatureBuilderTestCase +{ + private final static Integer MIN = 0; + private final static Integer MAX = 120; + private final static String UNIT = "bytes"; + + private Integer _access; + + @Override + protected void setUp () throws Exception + { + super.setUp(); + + _access = 1; + _featureDefinition.put(access.name(), _access); + _featureDefinition.put(unit.name(),UNIT); + _featureDefinition.put(min.name(), MIN); + _featureDefinition.put(max.name(),MAX); + + _featureDefinition.put(type.name(), 1); + _featureDefinition.put(optional.name(),0); + _featureDefinition.put(index.name(), 0); + + _builder = QpidFeatureBuilder.createPropertyBuilder(_featureDefinition); + } + + /** + * Tests the build process for a statistic when the definition map contains an unknown type code. + * + * <br>precondition : the statistic definiton map contains an unknown type code. + * <br>postcondition : an exception is thrown indicating the failure. + */ + public void testStatisticBuilderKO_WithUnknownType() + { + int unknownTypeCode =999; + try + { + _featureDefinition.put(type.name(), unknownTypeCode); + _builder.build(); + fail("An unknown type code should raise an exception to indicate a failure."); + } catch (UnableToBuildFeatureException expected) + { + assertEquals(unknownTypeCode,((UnknownTypeCodeException)expected.getCause()).getCode()); + } + } + + /** + * Tests the build process for a statistic when the definition map contains a null value for a metadata attribute. + * + * <br>precondition : the statistic definiton map contains a null value for a metadata attribute. + * <br>postcondition : an exception is thrown indicating the failure. + */ + public void testMethodBuilderKO_WithNullMetadataValue() + { + try + { + _featureDefinition.put(type.name(), null); + _builder.build(); + fail("An null value for a metadata attribute should raise an exception to indicate a failure."); + } catch (UnableToBuildFeatureException expected) + { + assertTrue(expected.getCause() instanceof NullPointerException); + } + } + + /** + * Tests the build process for a property when the definition map contains an invalid metadata type. + * + * <br>precondition : the property definiton map contains a wrong type for a metadata attribute. + * <br>postcondition : an exception is thrown indicating the failure. + */ + public void testPropertyBuilderKO_WithClassCastException() + { + try + { + _featureDefinition.put(access.name(), new String("a")); + _builder.build(); + fail("A wrong metadata attribute type should raise an exception to indicate a failure."); + } catch (UnableToBuildFeatureException expected) + { + assertTrue(expected.getCause() instanceof ClassCastException); + } + } + + /** + * Tests the build process for a property when the definition map contains an unknown type code. + * + * <br>precondition : the property definiton map contains an unknown type code. + * <br>postcondition : an exception is thrown indicating the failure. + */ + public void testPropertyBuilderKO_WithUnknownType() + { + int unknownTypeCode = 999; + try + { + _featureDefinition.put(type.name(), unknownTypeCode); + _builder.build(); + fail("An unknown type code should raise an exception to indicate a failure."); + } catch (UnableToBuildFeatureException expected) + { + assertEquals(unknownTypeCode,((UnknownTypeCodeException)expected.getCause()).getCode()); + } + } + + /** + * Tests the build process for a property when the definition map doesn't contains type attribute. + * + * <br>precondition: definition map doesn't contains type attribute. + * <br>postcondition : an exception should be thrown indicating the failure. That exception must contain the name of the + * missing attribute. + */ + public void testPropertyBuilderKO_WithMissingType() + { + internalTestForMissingMandatoryAttribute(Attribute.type); + } + + /** + * Tests the build process for a property when the definition map doesn't contain type & name attributes. + * + * <br>precondition: definition map doesn't contain type & name attributes. + * <br>postcondition : an exception should be thrown indicating the failure. That exception must contain the name of the + * missing attributes. + */ + public void testPropertyBuilderKO_WithMissingTypeAndName() + { + internalTestForMissingMandatoryAttribute(Attribute.type, Attribute.name); + } + + /** + * Tests the build process for a property when the definition map doesn't contain type & name & index attributes. + * + * <br>precondition: definition map doesn't contain type & name & index attributes. + * <br>postcondition : an exception should be thrown indicating the failure. That exception must contain the name of the + * missing attributes. + */ + public void testPropertyBuilderKO_WithMissingTypeAndNameAndIndex() + { + internalTestForMissingMandatoryAttribute(Attribute.type, Attribute.name,Attribute.index); + } + + /** + * Tests the build process for a property when the definition map doesn't contain type, name, index & optional attributes. + * + * <br>precondition: definition map doesn't contain type, name, index & optional attributes. + * <br>postcondition : an exception should be thrown indicating the failure. That exception must contain the name of the + * missing attributes. + */ + public void testPropertyBuilderKO_WithMissingTypeAndNameAndIndexAndOptional() + { + internalTestForMissingMandatoryAttribute(Attribute.type, Attribute.name,Attribute.index,Attribute.optional); + } + + /** + * Tests the build process for a property when the definition map doesn't contain type, name, index, optional and access + * attributes. + * + * <br>precondition: definition map doesn't contain type, name, index, optional and access attributes. + * <br>postcondition : an exception should be thrown indicating the failure. That exception must contain the name of the + * missing attributes. + */ + public void testPropertyBuilderKO_WithMissingTypeAndNameAndIndexAndOptionalAndAccess() + { + internalTestForMissingMandatoryAttribute(Attribute.type, Attribute.name,Attribute.index,Attribute.optional,Attribute.access); + } + + /** + * Tests the build process for a property when the definition map doesn't unit attribute. + * Note that this attribute is optional and therefore the build must succeed. + * + * <br>precondition: definition map doesn't contain unit attribute. + * <br>postcondition : no exception is thrown and the property is built. + */ + public void testBuilderOK_WithMissingUnit() throws UnableToBuildFeatureException + { + internalTestForMissingOptionalAttribute(Attribute.unit); + } + + /** + * Tests the build process for a property when the definition map doesn't min and max attributes. + * Note that those attributes are optional and therefore the build must succeed. + * + * <br>precondition: definition map doesn't contain min and max attributes. + * <br>postcondition : no exception is thrown and the property is built. + */ + public void testBuilderOK_WithMissingMinAndMax() throws UnableToBuildFeatureException + { + internalTestForMissingOptionalAttribute(Attribute.min,Attribute.max); + } + + /** + * Tests the build process for a property when the definition map doesn't description attribute. + * Note that this attribute is optional and therefore the build must succeed. + * + * <br>precondition: definition map doesn't contain description attribute. + * <br>postcondition : no exception is thrown and the property is built. + */ + public void testBuilderOK_WithMissingDescription() throws UnableToBuildFeatureException + { + internalTestForMissingOptionalAttribute(Attribute.desc); + } + + /** + * Tests the build process for a property when the definition map contains valid values. + * + * <br>precondition : the property definiton map contains valid values. + * <br>postcondition : no exception is thrown and the property is built as expected. + */ + public void testPropertyBuilderOK() throws UnableToBuildFeatureException + { + _builder.build(); + + QpidProperty property = (QpidProperty) _builder.getQpidFeature(); + MBeanAttributeInfo info = (MBeanAttributeInfo) _builder.getManagementFeature(); + + assertEquals(NAME,property.getName()); + assertEquals(AccessMode.RC,property.getAccessMode()); + assertEquals(UNIT,property.getUnit()); + assertEquals(MIN.intValue(),property.getMinValue()); + assertEquals(MAX.intValue(),property.getMaxValue()); + assertEquals(Integer.MIN_VALUE,property.getMaxLength()); + assertEquals(DESCRIPTION,property.getDescription()); + assertEquals(Short.class,property.getJavaType()); + assertFalse(property.isOptional()); + + assertEquals(property.getDescription(),info.getDescription()); + assertEquals(property.getName(),info.getName()); + assertEquals(property.getJavaType().getName(),info.getType()); + } +} diff --git a/RC9/qpid/java/management/client/src/test/java/org/apache/qpid/management/domain/model/QpidStatisticBuilderTest.java b/RC9/qpid/java/management/client/src/test/java/org/apache/qpid/management/domain/model/QpidStatisticBuilderTest.java new file mode 100644 index 0000000000..b7a8540b2d --- /dev/null +++ b/RC9/qpid/java/management/client/src/test/java/org/apache/qpid/management/domain/model/QpidStatisticBuilderTest.java @@ -0,0 +1,159 @@ +/* + * + * 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.domain.model; + +import static org.apache.qpid.management.domain.model.QpidFeatureBuilder.Attribute.type; +import static org.apache.qpid.management.domain.model.QpidFeatureBuilder.Attribute.unit; + +import javax.management.MBeanAttributeInfo; + +import org.apache.qpid.management.configuration.UnknownTypeCodeException; +import org.apache.qpid.management.domain.model.QpidFeatureBuilder.Attribute; + +/** + * Test case for Qpid Statistic builder. + * + * @author Andrea Gazzarini + */ +public class QpidStatisticBuilderTest extends BaseQpidFeatureBuilderTestCase +{ + private final static String UNIT = "bytes"; + + @Override + protected void setUp () throws Exception + { + super.setUp(); + _featureDefinition.put(unit.name(),UNIT); + _featureDefinition.put(type.name(), 1); + + _builder = QpidFeatureBuilder.createStatisticBuilder(_featureDefinition); + } + + /** + * Tests the build process for a statistic when the definition map contains an unknown type code. + * + * <br>precondition : the statistic definiton map contains an unknown type code. + * <br>postcondition : an exception is thrown indicating the failure. + */ + public void testStatisticBuilderKO_WithUnknownType() + { + int unknownTypeCode = 999; + try + { + _featureDefinition.put(type.name(), unknownTypeCode); + _builder.build(); + fail("An unknown type code should raise an exception to indicate a failure."); + } catch (UnableToBuildFeatureException expected) + { + assertEquals(unknownTypeCode,((UnknownTypeCodeException)expected.getCause()).getCode()); + } + } + + /** + * Tests the build process for a statistic when the definition map contains a null value for a metadata attribute. + * + * <br>precondition : the statistic definiton map contains a null value for a metadata attribute. + * <br>postcondition : an exception is thrown indicating the failure. + */ + public void testMethodBuilderKO_WithNullMetadataValue() + { + try + { + _featureDefinition.put(type.name(), null); + _builder.build(); + fail("An null value for a metadata attribute should raise an exception to indicate a failure."); + } catch (UnableToBuildFeatureException expected) + { + assertTrue(expected.getCause() instanceof NullPointerException); + } + } + + /** + * Tests the build process for a statistic when the definition map doesn't contains type attribute. + * + * <br>precondition: definition map doesn't contains type attribute. + * <br>postcondition : an exception should be thrown indicating the failure. That exception must contain the name of the + * missing attribute. + */ + public void testStatisticBuilderKO_WithMissingType() + { + internalTestForMissingMandatoryAttribute(Attribute.type); + } + + /** + * Tests the build process for a statistic when the definition map doesn't contain type & name attributes. + * + * <br>precondition: definition map doesn't contain type & name attributes. + * <br>postcondition : an exception should be thrown indicating the failure. That exception must contain the name of the + * missing attributes. + */ + public void testStatisticBuilderKO_WithMissingTypeAndName() + { + internalTestForMissingMandatoryAttribute(Attribute.type, Attribute.name); + } + + /** + * Tests the build process for a statistic when the definition map doesn't contain type, name, index & optional attributes. + * + * <br>precondition: definition map doesn't contain type, name, index & optional attributes. + * <br>postcondition : an exception should be thrown indicating the failure. That exception must contain the name of the + * missing attributes. + */ + public void testStatisticBuilderOK_WithMissingUnit() throws UnableToBuildFeatureException + { + internalTestForMissingOptionalAttribute(Attribute.unit); + } + + /** + * Tests the build process for a statistic when the definition map doesn't unit attribute. + * Note that this attribute is optional and therefore the build must succeed. + * + * <br>precondition: definition map doesn't contain unit attribute. + * <br>postcondition : no exception is thrown and the statistic is built. + */ + public void testBuilderOK_WithMissingDescription() throws UnableToBuildFeatureException + { + internalTestForMissingOptionalAttribute(Attribute.desc); + } + + /** + * Tests the build process for a statistic when the definition map contains valid values. + * + * <br>precondition : the statistic definiton map contains valid values. + * <br>postcondition : no exception is thrown and the statistisc is built as expected. + */ + public void testStatisticBuilderOK() throws UnableToBuildFeatureException + { + _builder.build(); + + QpidStatistic statistic= (QpidStatistic) _builder.getQpidFeature(); + MBeanAttributeInfo info = (MBeanAttributeInfo) _builder.getManagementFeature(); + + assertEquals(NAME,statistic.getName()); + assertEquals(UNIT,statistic.getUnit()); + assertEquals(DESCRIPTION,statistic.getDescription()); + assertEquals(Short.class,statistic.getJavaType()); + + assertEquals(statistic.getDescription(),info.getDescription()); + assertEquals(statistic.getName(),info.getName()); + assertEquals(statistic.getJavaType().getName(),info.getType()); + } +} diff --git a/RC9/qpid/java/management/client/src/test/java/org/apache/qpid/management/domain/model/QpidStringPropertyTest.java b/RC9/qpid/java/management/client/src/test/java/org/apache/qpid/management/domain/model/QpidStringPropertyTest.java new file mode 100644 index 0000000000..8aeb7c8550 --- /dev/null +++ b/RC9/qpid/java/management/client/src/test/java/org/apache/qpid/management/domain/model/QpidStringPropertyTest.java @@ -0,0 +1,127 @@ +/* + * + * 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.domain.model; + +import junit.framework.TestCase; + +import org.apache.qpid.management.configuration.Configurator; +import org.apache.qpid.management.domain.model.type.Str16; + +public class QpidStringPropertyTest extends TestCase +{ + private QpidProperty _property; + private final String _5LettersString = "12345"; + + @Override + protected void setUp () throws Exception + { + Configurator configurator = new Configurator(); + configurator.configure(); + _property = new QpidProperty(); + _property.setName("name"); + _property.setAccessMode(AccessMode.RW); + _property.setType(new Str16()); + } + + /** + * Tests the validation of a qpid property when the type is a string and a max length constraint hasn't been set. + * + * <br>precondition : property type is a string, max length hasn't been set. + * <br>postcondition : no exception is thrown. That is : the validation succeeds. + */ + public void testValidationWithoutMaxLength() { + try + { + _property.validate(_5LettersString); + } catch (ValidationException notExpected) + { + fail("No max length has been set on property so validation must succeed."); + } + } + + /** + * Tests the validation of a qpid property when the type is a string and a max length constraint has been set. + * + * <br>precondition : property type is a string, max length has been set and property value is longer than max length. + * <br>postcondition : an exception is thrown indicating the validation failure. + */ + public void testValidationKO_withMaxLength() { + int maxLength = 2; + _property.setMaxLength(maxLength); + + try + { + _property.validate(_5LettersString); + fail("No max length has been set on property so validation must proceed."); + } catch (ValidationException expected) + { + assertEquals(ValidationException.MAX_LENGTH,expected.getConstraintName()); + assertEquals(maxLength,expected.getConstraintValue()); + assertEquals(_5LettersString.length(),expected.getFeatureValue()); + assertEquals(_property.getName(),expected.getFeatureName()); + } + } + + /** + * Tests the validation of a qpid property when the type is a string and the property value is null. + * + * <br>precondition : property type is a string and property value is null.. + * <br>postcondition : no exception is thrown. That is : the validation succeeds. + */ + public void testValidationOK_withNullValue() { + try + { + _property.validate(null); + } catch (ValidationException notExpected) + { + fail("No constraint has been violated so validate() shouldn't raise an exception."); + } + + _property.setMaxLength(1); + + try + { + _property.validate(null); + } catch (ValidationException notExpected) + { + fail("No constraint has been violated so validate() shouldn't raise an exception."); + } + } + + /** + * Tests the validation of a qpid property when the type is a string and a max length constraint has been set. + * + * <br>precondition : property type is a string, max length has been set and property value is not violating that. + * <br>postcondition : no exception is thrown. That is : the validation succeeds. + */ + public void testValidationOK_withMaxLength() { + int maxLength = (_5LettersString.length()+1); + _property.setMaxLength(maxLength); + + try + { + _property.validate(_5LettersString); + } catch (ValidationException notExpected) + { + fail("No constraint has been violated so validate() shouldn't raise an exception."); + } + } +} diff --git a/RC9/qpid/java/management/client/src/test/java/org/apache/qpid/management/domain/model/type/BinaryTest.java b/RC9/qpid/java/management/client/src/test/java/org/apache/qpid/management/domain/model/type/BinaryTest.java new file mode 100644 index 0000000000..6636c08710 --- /dev/null +++ b/RC9/qpid/java/management/client/src/test/java/org/apache/qpid/management/domain/model/type/BinaryTest.java @@ -0,0 +1,59 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.management.domain.model.type; + +import junit.framework.TestCase; + +/** + * Test case for "Binary" type. + * + * @author Andrea Gazzarini + */ +public class BinaryTest extends TestCase +{ + /** + * Tests the lazy & once hash code computation behaviour of the binary type. + */ + public void testHashCodeComputation(){ + Binary binary = new Binary(new byte[]{1,2,3,4,5,6,7,6,3,3}); + assertSame(binary.state,binary.hashCodeNotYetComputed); + + int firstResult = binary.hashCode(); + assertSame(binary.state,binary.hashCodeAlreadyComputed); + + int secondResult = binary.hashCode(); + assertSame(binary.state,binary.hashCodeAlreadyComputed); + assertEquals(firstResult,secondResult); + } + + /** + * Tests the equals() method of the binary class. + * Two binary must be equals only if they contain the same array (that is, two arrays with the same size & content) + */ + public void testIdentity() { + Binary binary = new Binary(new byte[]{1,2,3,4,5,6,7,6,3,3}); + Binary theSame= new Binary(new byte[]{1,2,3,4,5,6,7,6,3,3}); + Binary aDifferentOne = new Binary(new byte[]{4,2,3,3,4,4,5,3,3,2}); + + assertTrue(binary.equals(theSame)); + assertFalse(binary.equals(aDifferentOne)); + } +}
\ No newline at end of file diff --git a/RC9/qpid/java/management/client/src/test/java/org/apache/qpid/management/domain/services/BrokerMessageListenerTest.java b/RC9/qpid/java/management/client/src/test/java/org/apache/qpid/management/domain/services/BrokerMessageListenerTest.java new file mode 100644 index 0000000000..805c039a6f --- /dev/null +++ b/RC9/qpid/java/management/client/src/test/java/org/apache/qpid/management/domain/services/BrokerMessageListenerTest.java @@ -0,0 +1,241 @@ +/* + * + * 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.domain.services; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.Random; + +import junit.framework.TestCase; + +import org.apache.qpid.api.Message; +import org.apache.qpid.management.TestConstants; +import org.apache.qpid.management.domain.handler.base.IMessageHandler; +import org.apache.qpid.management.domain.model.DomainModel; +import org.apache.qpid.nclient.util.ByteBufferMessage; +import org.apache.qpid.transport.codec.Decoder; + +/** + * Test case for Broker Message Listener. + * + * @author Andrea Gazzarini + */ +public class BrokerMessageListenerTest extends TestCase +{ + // An empty message handler user for test. + private IMessageHandler _emptyMessageHandler = new IMessageHandler() + { + public void process (Decoder decoder, int sequenceNumber) + { + } + public void setDomainModel (DomainModel domainModel) + { + } + }; + + // Another empty message handler user for test. + private IMessageHandler _anotherEmptyMessageHandler = new IMessageHandler() + { + public void process (Decoder decoder, int sequenceNumber) + { + } + public void setDomainModel (DomainModel domainModel) + { + } + }; + + private Map<Character,IMessageHandler> _handlers = new HashMap<Character, IMessageHandler>(); + private BrokerMessageListener _listener; + private final char opcode1 = 'x'; + private final char opcode2 = 'y'; + + + @Override + protected void setUp () throws Exception + { + DomainModel domainModel = new DomainModel(TestConstants.BROKER_ID); + _listener = new BrokerMessageListener(domainModel); + + _handlers.put(opcode1, _emptyMessageHandler); + _handlers.put(opcode2, _anotherEmptyMessageHandler); + } + + /** + * Tests the installation of message handlers on a broker message listener. + * + * <br>precondition : no message handler has been installed on message listener. + * <br>postcondition : two message handlers are installed on message listener. + */ + public void testSetHandlersOK() + { + assertTrue( + "No handler has yet been installed so how is it possible that the handlers map is not empty?", + _listener._handlers.isEmpty()); + + _listener.setHandlers(_handlers); + + assertEquals("Now we should have two handlers configured.",2,_listener._handlers.size()); + assertSame(_listener._handlers.get(opcode1),_emptyMessageHandler); + assertSame(_listener._handlers.get(opcode2),_anotherEmptyMessageHandler); + } + + /** + * Tests the installation of message handlers on a broker message listener. + * Specifically it tries to install three message handlers and one of them is throwing an exception at installation time. + * + * <br>precondition : no message handler has been installed on message listener. + * <br>postcondition : two message handlers are installed on message listener. (the one that thrown exception has been + * discarded). + */ + public void testSetHandlerOK() + { + IMessageHandler wrongMessageHandler = new IMessageHandler() + { + + public void process (Decoder decoder, int sequenceNumber) + { + } + + public void setDomainModel (DomainModel domainModel) + { + throw new RuntimeException(); + } + }; + + char opcodeForWrongHandler = 'k'; + + assertTrue( + "No handler has yet been installed so how is it possible that the handlers map is not empty?", + _listener._handlers.isEmpty()); + + _handlers.put(opcodeForWrongHandler,wrongMessageHandler); + + _listener.setHandlers(_handlers); + + assertEquals("Now we should have two handlers configured.",2,_listener._handlers.size()); + assertSame(_listener._handlers.get(opcode1),_emptyMessageHandler); + assertSame(_listener._handlers.get(opcode2),_anotherEmptyMessageHandler); + assertNull(_listener._handlers.get(opcodeForWrongHandler)); + } + + /** + * Tests the execution of the onMessage() method when a message with a bad magic number is received. + * + * <br>precondition : a message with a bad magic number is received. + * <br>postcondition : the processing of the incoming message is skipped and therefore no handler will be called. + */ + public void testOnMessageKO_withBadMagicNumber() throws IOException + { + IMessageHandler neverCallMe = new IMessageHandler() + { + + public void process (Decoder decoder, int sequenceNumber) + { + fail("This test shouldn't never arrive at this point..."); + } + + public void setDomainModel (DomainModel domainModel) + { + } + }; + + String opcodeForNeverCallMeHandler = "w"; + + _handlers.put('w',neverCallMe); + _listener.setHandlers(_handlers); + + Message message = new ByteBufferMessage(); + message.appendData( ("AMG"+opcodeForNeverCallMeHandler).getBytes()); + + _listener.onMessage(message); + } + + /** + * Tests the execution of the onMessage() method when the incoming message is a compound message. + * + * <br>precondition : the incoming message is a compound message. + * <br>postcondition : each tokenized message is forwarded to the appropriate handler. + */ + public void testOnMessageOK_WithCompoundMessage() throws Exception + { + final Map<Character,IMessageHandler> handlersMap = new HashMap<Character,IMessageHandler>(); + char [] opcodes = {'a','b','c','d','e'}; + + class MockMessageHandler implements IMessageHandler + { + private final char _opcode; + + public MockMessageHandler(char opcode) + { + this._opcode = opcode; + } + + public void process (Decoder decoder, int sequenceNumber) + { + handlersMap.remove(_opcode); + } + + public void setDomainModel (DomainModel domainModel) + { + // Do nothing here. It's just a mock handler. + } + }; + + for (char opcode : opcodes) + { + handlersMap.put(opcode, new MockMessageHandler(opcode)); + } + + // Removes previously injected handlers (i.e. x & y) + _listener._handlers.clear(); + _listener.setHandlers(handlersMap); + + Message compoundMessage = createCompoundMessage(opcodes); + _listener.onMessage(compoundMessage); + + assertTrue(handlersMap.isEmpty()); + } + + // Creates a (non valid) compound message. + private Message createCompoundMessage(char[] opcodes) throws IOException { + byte [] compoundMessageData = new byte [12 * opcodes.length]; + Random randomizer = new Random(); + int position = 0; + + for (char opcode : opcodes) { + System.arraycopy(MessageTokenizer.MAGIC_NUMBER_BYTES, 0, compoundMessageData, position, MessageTokenizer.MAGIC_NUMBER_BYTES.length); + position+=MessageTokenizer.MAGIC_NUMBER_BYTES.length; + + compoundMessageData[position++] = (byte)opcode; + + for (int c = 4; c < 12; c++) + { + byte aByte = (byte)randomizer.nextInt(127); + compoundMessageData[position++] = aByte; + } + } + + Message compoundMessage = new ByteBufferMessage(); + compoundMessage.appendData(compoundMessageData); + return compoundMessage; + } +} diff --git a/RC9/qpid/java/management/client/src/test/java/org/apache/qpid/management/domain/services/MessageTokenizerTest.java b/RC9/qpid/java/management/client/src/test/java/org/apache/qpid/management/domain/services/MessageTokenizerTest.java new file mode 100644 index 0000000000..55b8b17f9d --- /dev/null +++ b/RC9/qpid/java/management/client/src/test/java/org/apache/qpid/management/domain/services/MessageTokenizerTest.java @@ -0,0 +1,140 @@ +/*
+*
+ * 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.domain.services;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.*;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.api.Message;
+import org.apache.qpid.nclient.util.ByteBufferMessage;
+import org.apache.qpid.transport.codec.BBDecoder;
+
+/**
+ * Tests case for messaeg tokenizer.
+ *
+ * @author Andrea Gazzarini
+ */
+public class MessageTokenizerTest extends TestCase {
+
+ /**
+ * Tests the execution of the message tokenizer when the given message is not a valid AMQP message.
+ *
+ * <br>precondition : the incoming message is not a valid AMQP message.
+ * <br>postcondition : no exception is thrown and there will be exactly one token with the given message.
+ */
+ public void testOK_WithNoMessage() throws IOException{
+ byte [] noMessage = {2,10,120,23,23,23,4,10,11,12,2,1,3,-22};
+
+ Message multiMessage = new ByteBufferMessage();
+ multiMessage.appendData(noMessage);
+ MessageTokenizer tokenizer = new MessageTokenizer(multiMessage);
+
+ assertEquals(1, tokenizer.countTokens());
+ assertEquals(tokenizer.nextElement(),noMessage);
+ assertFalse(tokenizer.hasMoreElements());
+ }
+
+ /**
+ * Tests the execution of the message tokenizer when the given message contains only one message.
+ *
+ * <br>precondition : the incoming message contains only one message.
+ * <br>postcondition : no exception is thrown and there will be exactly one token with the given message.
+ */
+ public void testOK_WithOneMessage() throws IOException{
+ byte [] oneEncodedMessage = {'A','M','2',23,23,23,4,10,11,12,2,1,3,-22};
+
+ Message multiMessage = new ByteBufferMessage();
+ multiMessage.appendData(oneEncodedMessage);
+ MessageTokenizer tokenizer = new MessageTokenizer(multiMessage);
+
+ assertEquals(1, tokenizer.countTokens());
+ assertEquals(tokenizer.nextElement(),oneEncodedMessage);
+ assertFalse(tokenizer.hasMoreElements());
+ }
+
+ /**
+ * Tests the execution of the message tokenizer when the given message contains a random number of messages.
+ *
+ * <br>precondition : the incoming message contains a random number of messages.
+ * <br>postcondition : no exception is thrown and each built token is a valid message starting with right header.
+ */
+ public void testOK_WithRandomNUmberOfMessages() throws IOException{
+ Random randomizer = new Random();
+
+ int howManyLoops = randomizer.nextInt(10000);
+ howManyLoops = (howManyLoops == 0) ? 10 : howManyLoops;
+ byte [] compoundMessageData = new byte [12 * howManyLoops];
+
+ List<byte []> messages = new ArrayList<byte[]>(howManyLoops);
+
+ int position = 0;
+ for (int i = 0; i < howManyLoops; i++)
+ {
+ byte [] message = new byte[12];
+ System.arraycopy(MessageTokenizer.MAGIC_NUMBER_BYTES, 0, compoundMessageData, position, MessageTokenizer.MAGIC_NUMBER_BYTES.length);
+ System.arraycopy(MessageTokenizer.MAGIC_NUMBER_BYTES, 0, message, 0, MessageTokenizer.MAGIC_NUMBER_BYTES.length);
+ position+=MessageTokenizer.MAGIC_NUMBER_BYTES.length;
+
+ for (int c = 3; c < 12; c++)
+ {
+ byte aByte = (byte)randomizer.nextInt(127);
+ aByte = (aByte == 77) ? (byte)c : aByte;
+ compoundMessageData[position++] = aByte;
+ message[c] = aByte;
+ }
+ messages.add(message);
+ }
+
+ Message multiMessage = new ByteBufferMessage();
+ multiMessage.appendData(compoundMessageData);
+ MessageTokenizer tokenizer = new MessageTokenizer(multiMessage);
+
+ int howManyTokens = tokenizer.countTokens();
+ assertEquals(howManyLoops, howManyTokens);
+
+ int index = 0;
+ while (tokenizer.hasMoreElements())
+ {
+ assertEquals(tokenizer.nextElement(),messages.get(index++));
+ }
+
+ assertEquals((index),howManyTokens);
+ }
+
+ /**
+ * Internal method used for comparison of two messages.
+ *
+ * @param message the token message just built by the tokenizer.
+ * @param expected the expected result.
+ */
+ private void assertEquals(Message message, byte [] expected) throws IOException
+ {
+ ByteBuffer messageContent = message.readData();
+ BBDecoder decoder = new BBDecoder();
+ decoder.init(messageContent);
+ byte [] content = decoder.readReaminingBytes();
+ assertTrue(Arrays.equals(content, expected));
+ }
+}
diff --git a/RC9/qpid/java/management/client/src/test/java/org/apache/qpid/management/online/BaseOnlineTestCase.java b/RC9/qpid/java/management/client/src/test/java/org/apache/qpid/management/online/BaseOnlineTestCase.java new file mode 100644 index 0000000000..82a7a1698c --- /dev/null +++ b/RC9/qpid/java/management/client/src/test/java/org/apache/qpid/management/online/BaseOnlineTestCase.java @@ -0,0 +1,58 @@ +/* + * + * 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.online; + +import javax.management.MBeanServerConnection; +import javax.management.remote.JMXConnector; +import javax.management.remote.JMXConnectorFactory; +import javax.management.remote.JMXServiceURL; + +import junit.framework.TestCase; + +/** + * Layer supertype for all online QMan test cases. + * Note that QMan must be running and up in order to run concrete subclasses (test cases). + * + * @author AGazzarini + */ +public abstract class BaseOnlineTestCase extends TestCase +{ + protected MBeanServerConnection connection; + + /** + * Setup fixture for this test case. + * Basically it estabilishes a connection to QMan using RMI JMX connector. + */ + @Override + protected void setUp () + { + try + { + JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:1099/jmxrmi"); + JMXConnector jmxc = JMXConnectorFactory.connect(url); + connection = jmxc.getMBeanServerConnection(); + } catch(Exception exception) + { + fail("QMan must be running and up in order to run this test!"); + exception.printStackTrace(); + } + } +} diff --git a/RC9/qpid/java/management/client/web.xml b/RC9/qpid/java/management/client/web.xml new file mode 100644 index 0000000000..71ca74b2e5 --- /dev/null +++ b/RC9/qpid/java/management/client/web.xml @@ -0,0 +1,32 @@ +<!-- + - + - Licensed to the Apache Software Foundation (ASF) under one + - or more contributor license agreements. See the NOTICE file + - distributed with this work for additional information + - regarding copyright ownership. The ASF licenses this file + - to you under the Apache License, Version 2.0 (the + - "License"); you may not use this file except in compliance + - with the License. You may obtain a copy of the License at + - + - http://www.apache.org/licenses/LICENSE-2.0 + - + - Unless required by applicable law or agreed to in writing, + - software distributed under the License is distributed on an + - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + - KIND, either express or implied. See the License for the + - specific language governing permissions and limitations + - under the License. + - + --> + +<?xml version="1.0" encoding="UTF-8"?> +<web-app id="WebApp_ID" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"> + <display-name>QManEE</display-name> + <description>Web Application used for integrating QMan onto an Application Server.</description> + <servlet> + <display-name>QMan Servlet (Initializer)</display-name> + <servlet-name>QManServlet</servlet-name> + <servlet-class>org.apache.qpid.management.servlet.QManServlet</servlet-class> + <load-on-startup>1</load-on-startup> + </servlet> +</web-app> |
