diff --git a/modules/broker/distribution/lib/home/images/bottom.gif b/modules/broker/distribution/lib/home/images/bottom.gif
new file mode 100644
index 00000000..56792668
Binary files /dev/null and b/modules/broker/distribution/lib/home/images/bottom.gif differ
diff --git a/modules/broker/distribution/lib/home/images/content-bg.gif b/modules/broker/distribution/lib/home/images/content-bg.gif
new file mode 100644
index 00000000..6d0a5795
Binary files /dev/null and b/modules/broker/distribution/lib/home/images/content-bg.gif differ
diff --git a/modules/broker/distribution/lib/home/images/favicon.ico b/modules/broker/distribution/lib/home/images/favicon.ico
new file mode 100644
index 00000000..f7b2bbfb
Binary files /dev/null and b/modules/broker/distribution/lib/home/images/favicon.ico differ
diff --git a/modules/broker/distribution/lib/home/images/feature-01-icon.gif b/modules/broker/distribution/lib/home/images/feature-01-icon.gif
new file mode 100644
index 00000000..b4ea8cda
Binary files /dev/null and b/modules/broker/distribution/lib/home/images/feature-01-icon.gif differ
diff --git a/modules/broker/distribution/lib/home/images/feature-02-icon.gif b/modules/broker/distribution/lib/home/images/feature-02-icon.gif
new file mode 100644
index 00000000..8754de14
Binary files /dev/null and b/modules/broker/distribution/lib/home/images/feature-02-icon.gif differ
diff --git a/modules/broker/distribution/lib/home/images/feature-03-icon.gif b/modules/broker/distribution/lib/home/images/feature-03-icon.gif
new file mode 100644
index 00000000..d81f1fec
Binary files /dev/null and b/modules/broker/distribution/lib/home/images/feature-03-icon.gif differ
diff --git a/modules/broker/distribution/lib/home/images/intro-bg.gif b/modules/broker/distribution/lib/home/images/intro-bg.gif
new file mode 100644
index 00000000..a38a0dfa
Binary files /dev/null and b/modules/broker/distribution/lib/home/images/intro-bg.gif differ
diff --git a/modules/broker/distribution/lib/home/images/logo.gif b/modules/broker/distribution/lib/home/images/logo.gif
new file mode 100644
index 00000000..ee9beef1
Binary files /dev/null and b/modules/broker/distribution/lib/home/images/logo.gif differ
diff --git a/modules/broker/distribution/lib/home/images/powered-logo.gif b/modules/broker/distribution/lib/home/images/powered-logo.gif
new file mode 100644
index 00000000..fb478bf9
Binary files /dev/null and b/modules/broker/distribution/lib/home/images/powered-logo.gif differ
diff --git a/modules/broker/distribution/lib/home/images/register.gif b/modules/broker/distribution/lib/home/images/register.gif
new file mode 100644
index 00000000..98c53620
Binary files /dev/null and b/modules/broker/distribution/lib/home/images/register.gif differ
diff --git a/modules/broker/distribution/lib/home/images/sign-in.gif b/modules/broker/distribution/lib/home/images/sign-in.gif
new file mode 100644
index 00000000..9e992cc2
Binary files /dev/null and b/modules/broker/distribution/lib/home/images/sign-in.gif differ
diff --git a/modules/broker/distribution/lib/home/images/title-bg.gif b/modules/broker/distribution/lib/home/images/title-bg.gif
new file mode 100644
index 00000000..2d539a7e
Binary files /dev/null and b/modules/broker/distribution/lib/home/images/title-bg.gif differ
diff --git a/modules/broker/distribution/lib/home/images/top.gif b/modules/broker/distribution/lib/home/images/top.gif
new file mode 100644
index 00000000..9ed482c2
Binary files /dev/null and b/modules/broker/distribution/lib/home/images/top.gif differ
diff --git a/modules/broker/distribution/lib/home/index.html b/modules/broker/distribution/lib/home/index.html
new file mode 100644
index 00000000..cc82a56b
--- /dev/null
+++ b/modules/broker/distribution/lib/home/index.html
@@ -0,0 +1,69 @@
+
+
+
+
+
+
+
+ StratosLive
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
WSO2 MB brings Event Driven Architecture capabilities to WSO2 Carbon platform. It provides WS-Eventing, JMS and SQS interfaces to client. It uses Apache Qpid as the underling broker which supports AMQP.
+
+
+
+
Features
+
+
+
Bring CEP to SOA
+
+ Bring CEP to SOA by processing XML events and produce results as XML events.
+
+
+
+
+
Registry Storage
+
+ Ability to define different event streams, queries and out put streams and store them in the registry as a bucket.
+
+WSO2 Message Broker brings messaging and eventing capabilities into your SOA framework.
+The latest version of this product possesses following key features. All these features
+can be used as standalone message broker or as a distributed message brokering system.
+
+WSO2 Message Broker compatible with Advanced Message Queuing Protocol (AMQP)(0-91))
+and Message Queuing Telemetry Transport Protocol (MQTT) v 3.1.1.
+
+
JMS Queuing support
+
JMS Pub/Sub mechanism for topics
+
Hierarchical Topics Subscriptions
+
Queue Message browsing with added UI support
+
Message Re-Delivery Tries Configuration
+
Message Re delivery Header Field support
+
Sample text message sender tool in UI
+
Queue purging support
+
Simple clustering machanism based on carbon clustering
+
Ability to view details of the cluster using Management Console
+
Message delivery fine tuning capabilities
+
Relational databases as a storage machanism
+
+
+
System Requirements
+
+
Minimum memory - 2GB
+
Processor - Pentium 800MHz or equivalent at minimum
+
Java SE Development Kit 1.7 or higher
+
The Management Console requires you to enable Javascript of the Web browser,
+ with MS IE 7. In addition to JavaScript, ActiveX should also be enabled
+ with IE. This can be achieved by setting your security level to
+ medium or lower.
+
To compile and run the sample clients, an Ant version is required. Ant 1.7.0
+ version is recommended.
+
To build WSO2 MB from the Source distribution, it is necessary that you have
+ JDK 7 and Maven 3.0.4 or later
+
+
+For more details see
+ https://docs.wso2.com/display/MB320/Installation+Prerequisites
+
+
Installation & Running
+
+
+
Extract the wso2mb-3.2.0.zip and go to the extracted directory
+
Run the wso2server.sh or wso2server.bat as appropriate
+
Point your favourite browser to
+
+ https://localhost:9443/carbon
+
+
Use the following username and password to login
+
+ username : admin
+ password : admin
+
+
+
+
WSO2 MB 3.2.0 distribution directory structure
+
+ CARBON_HOME
+ |-- bin
+ |-- dbscripts
+ |-- client-lib
+ |-- lib
+ |-- repository
+ | |-- components
+ | |-- conf
+ | |-- Advanced
+ |-- datasources
+ | |-- database
+ | |-- deployment
+ | |-- logs
+ | |-- tenants
+ | |-- resources
+ | |-- security
+ |-- tmp
+ |-- LICENSE.txt
+ |-- README.txt
+ `-- release-notes.html
+
+ - bin
+ Contains various scripts .sh & .bat scripts
+
+ - dbscripts
+ Contains the SQL scripts for setting up the database on a variety of
+ Database Management Systems, including H2, Derby, MSSQL, MySQL abd
+ Oracle.
+
+ - client-lib
+ Contains required libraries for JMS,Event Clients
+
+ - lib
+ Contains the basic set of libraries required to start-up WSO2 MB
+ in standalone mode
+
+ - repository
+ The repository where services and modules deployed in WSO2 MB
+ are stored.
+
+ - components
+ Contains OSGi bundles and configurations
+
+ - conf
+ Contains configuration files
+ - datasources
+ contains configuration for setting up databases.
+
+ - database
+ Contains the database
+
+ - deployment
+ Contains Axis2 deployment details
+
+ - logs
+ Contains all log files created during execution
+
+ - tenants
+ Contains tenant details
+
+ - resources
+ Contains additional resources that may be required
+
+ - security
+ Contains security resources
+
+ - tmp
+ Used for storing temporary files, and is pointed to by the
+ java.io.tmpdir System property
+
+ - LICENSE.txt
+ Apache License 2.0 under which WSO2 MB is distributed.
+
+ - README.txt
+ This document.
+
+
+
+
Support
+WSO2 Inc. offers a variety of development and production support
+programs, ranging from Web-based support up through normal business
+hours, to premium 24x7 phone support.
+
+For additional support information please refer to http://wso2.com/support/
+
+For more information on WSO2 MB, visit the WSO2 Oxygen Tank (http://wso2.org)
+
+For more details and to take advantage of this unique opportunity please visit
+http://wso2.com/support/
+
+Thank you for your interest in WSO2 Message Broker.
+
+
Known Issues
+
+https://wso2.org/jira/issues/?filter=12509
+
+ WSO2 Message Broker is compatible with AMQP 0-91 version only.
+
+
Build Status
+
+| Branch | Build Status |
+| :------------ |:-------------
+| Java 7 | [](https://wso2.org/jenkins/job/product-mb) |
+| Java 8 | [](https://wso2.org/jenkins/job/product-mb__java8/) |
+
+
+(c) 2015, WSO2 Inc.
+
diff --git a/modules/broker/distribution/src/main/resources/README.txt b/modules/broker/distribution/src/main/resources/README.txt
new file mode 100644
index 00000000..429b4114
--- /dev/null
+++ b/modules/broker/distribution/src/main/resources/README.txt
@@ -0,0 +1,205 @@
+================================================================================
+ WSO2 Message Broker Server 3.2.0
+================================================================================
+
+Welcome to the WSO2 MB 3.1.0 release
+
+WSO2 MB is a lightweight and easy-to-use Open Source Distributed Message Brokering
+Server (MB) which is available under the Apache Software License v2.0.
+
+This is based on the revolutionary WSO2 Carbon [Middleware a' la carte]
+framework. All the major features have been developed as pluggable Carbon
+components.
+
+Key Features of WSO2 MB
+==================================
+WSO2 Message Broker brings messaging and eventing capabilities into your SOA framework.
+The latest version of this product possesses following key features. All these features
+can be used as standalone message broker or as a distributed message brokering system.
+
+WSO2 Message Broker compatible with Advanced Message Queuing Protocol (AMQP)(0-91))
+and Message Queuing Telemetry Transport Protocol (MQTT) v 3.1.1.
+
+• JMS Queuing support
+• JMS Pub/Sub mechanism for topics
+• Hierarchical Topics Subscriptions
+• Queue Message browsing with added UI support
+• Message Re-Delivery Tries Configuration
+• Message Re delivery Header Field support
+• Sample text message sender tool in UI
+• Queue purging support
+• Simple clustering machanism based on carbon clustering
+• Ability to view details of the cluster using Management Console
+• Message delivery fine tuning capabilities
+• Relational databases as a storage machanism
+
+System Requirements
+=======================
+1. Minimum memory - 2GB
+2. Processor - Pentium 800MHz or equivalent at minimum
+3. Java SE Development Kit 1.7 or higher
+4. The Management Console requires you to enable Javascript of the Web browser,
+ with MS IE 7. In addition to JavaScript, ActiveX should also be enabled
+ with IE. This can be achieved by setting your security level to
+ medium or lower.
+5. To compile and run the sample clients, an Ant version is required. Ant 1.7.0
+ version is recommended
+6. To build WSO2 MB from the Source distribution, it is necessary that you have
+ JDK 7 and Maven 3.0.4 or later
+
+
+For more details see
+ https://docs.wso2.com/display/MB310/Installation+Prerequisites
+
+Installation & Running
+==================================
+
+1. Extract the wso2mb-3.1.0.zip and go to the extracted directory
+2. Run the wso2server.sh or wso2server.bat as appropriate
+3. Point your favourite browser to
+
+ https://localhost:9443/carbon
+
+4. Use the following username and password to login
+
+ username : admin
+ password : admin
+
+
+
+WSO2 MB 3.1.0 distribution directory structure
+=============================================
+
+ CARBON_HOME
+ |-- bin
+ |-- dbscripts
+ |-- client-lib
+ |-- lib
+ |-- repository
+ | |-- components
+ | |-- conf
+ | |-- Advanced
+ |-- datasources
+ | |-- database
+ | |-- deployment
+ | |-- logs
+ | |-- tenants
+ | |-- resources
+ | |-- security
+ |-- tmp
+ |-- LICENSE.txt
+ |-- README.txt
+ `-- release-notes.html
+
+ - bin
+ Contains various scripts .sh & .bat scripts
+
+ - dbscripts
+ Contains the SQL scripts for setting up the database on a variety of
+ Database Management Systems, including H2, Derby, MSSQL, MySQL abd
+ Oracle.
+
+ - client-lib
+ Contains required libraries for JMS,Event Clients
+
+ - lib
+ Contains the basic set of libraries required to start-up WSO2 MB
+ in standalone mode
+
+ - repository
+ The repository where services and modules deployed in WSO2 MB
+ are stored.
+
+ - components
+ Contains OSGi bundles and configurations
+
+ - conf
+ Contains configuration files
+ - datasources
+ contains configuration for setting up databases.
+
+ - database
+ Contains the database
+
+ - deployment
+ Contains Axis2 deployment details
+
+ - logs
+ Contains all log files created during execution
+
+ - tenants
+ Contains tenant details
+
+ - resources
+ Contains additional resources that may be required
+
+ - security
+ Contains security resources
+
+ - tmp
+ Used for storing temporary files, and is pointed to by the
+ java.io.tmpdir System property
+
+ - LICENSE.txt
+ Apache License 2.0 under which WSO2 MB is distributed.
+
+ - README.txt
+ This document.
+
+
+
+Support
+==================================
+WSO2 Inc. offers a variety of development and production support
+programs, ranging from Web-based support up through normal business
+hours, to premium 24x7 phone support.
+
+For additional support information please refer to http://wso2.com/support/
+
+For more information on WSO2 MB, visit the WSO2 Oxygen Tank (http://wso2.org)
+
+For more details and to take advantage of this unique opportunity please visit
+http://wso2.com/support/
+
+Thank you for your interest in WSO2 Message Broker.
+
+Known Issues
+==================================
+
+https://wso2.org/jira/issues/?filter=12509
+
+ WSO2 Message Broker is compatible with AMQP 0-91 version only.
+
+Crypto Notice
+==================================
+
+ This distribution includes cryptographic software. The country in
+ which you currently reside may have restrictions on the import,
+ possession, use, and/or re-export to another country, of
+ encryption software. BEFORE using any encryption software, please
+ check your country's laws, regulations and policies concerning the
+ import, possession, or use, and re-export of encryption software, to
+ see if this is permitted. See for more
+ information.
+
+ The U.S. Government Department of Commerce, Bureau of Industry and
+ Security (BIS), has classified this software as Export Commodity
+ Control Number (ECCN) 5D002.C.1, which includes information security
+ software using or performing cryptographic functions with asymmetric
+ algorithms. The form and manner of this Apache Software Foundation
+ distribution makes it eligible for export under the License Exception
+ ENC Technology Software Unrestricted (TSU) exception (see the BIS
+ Export Administration Regulations, Section 740.13) for both object
+ code and source code.
+
+ The following provides more details on the included cryptographic
+ software:
+
+ Apache Rampart : http://ws.apache.org/rampart/
+ Apache WSS4J : http://ws.apache.org/wss4j/
+ Apache Santuario : http://santuario.apache.org/
+ Bouncycastle : http://www.bouncycastle.org/
+
+--------------------------------------------------------------------------------
+(c) Copyright 2015 WSO2 Inc.
+
diff --git a/modules/broker/distribution/src/main/resources/launch.ini b/modules/broker/distribution/src/main/resources/launch.ini
new file mode 100644
index 00000000..02f4cb9b
--- /dev/null
+++ b/modules/broker/distribution/src/main/resources/launch.ini
@@ -0,0 +1,249 @@
+# Eclipse Runtime Configuration Overrides
+# These properties are loaded prior to starting the framework and can also be used to override System Properties
+# @null is a special value used to override and clear the framework's copy of a System Property prior to starting the framework
+# "*" can be used together with @null to clear System Properties that match a prefix name.
+
+osgi.*=@null
+org.osgi.*=@null
+eclipse.*=@null
+
+osgi.parentClassloader=app
+osgi.contextClassLoaderParent=app
+
+# When osgi.clean is set to "true", any cached data used by the OSGi framework
+# will be wiped clean. This will clean the caches used to store bundle
+# dependency resolution and eclipse extension registry data. Using this
+# option will force OSGi framework to reinitialize these caches.
+# The following setting is put in place to get rid of the problems
+# faced when re-starting the system. Please note that, when this setting is
+# true, if you manually start a bundle, it would not be available when
+# you re-start the system. To avid this, copy the bundle jar to the plugins
+# folder, before you re-start the system.
+osgi.clean=true
+
+# Uncomment the following line to turn on Eclipse Equinox debugging.
+# You may also edit the osgi-debug.options file and fine tune the debugging
+# options to suite your needs.
+#osgi.debug=./repository/conf/osgi-debug.options
+
+# Following system property allows us to control the public JDK packages exported through the system bundle.
+org.osgi.framework.system.packages=javax.accessibility,\
+javax.activity,\
+javax.crypto,\
+javax.crypto.interfaces,\
+javax.crypto.spec,\
+javax.imageio,\
+javax.imageio.event,\
+javax.imageio.metadata,\
+javax.imageio.plugins.bmp,\
+javax.imageio.plugins.jpeg,\
+javax.imageio.spi,\
+javax.imageio.stream,\
+javax.jms,\
+javax.management,\
+javax.management.loading,\
+javax.management.modelmbean,\
+javax.management.monitor,\
+javax.management.openmbean,\
+javax.management.relation,\
+javax.management.remote,\
+javax.management.remote.rmi,\
+javax.management.timer,\
+javax.naming,\
+javax.naming.directory,\
+javax.naming.event,\
+javax.naming.ldap,\
+javax.naming.spi,\
+javax.net,\
+javax.net.ssl,\
+javax.print,\
+javax.print.attribute,\
+javax.print.attribute.standard,\
+javax.print.event,\
+javax.rmi,\
+javax.rmi.CORBA,\
+javax.rmi.ssl,\
+javax.script,\
+javax.security.auth,\
+javax.security.auth.callback,\
+javax.security.auth.kerberos,\
+javax.security.auth.login,\
+javax.security.auth.spi,\
+javax.security.auth.x500,\
+javax.security.cert,\
+javax.security.sasl,\
+javax.sound.midi,\
+javax.sound.midi.spi,\
+javax.sound.sampled,\
+javax.sound.sampled.spi,\
+javax.sql,\
+javax.sql.rowset,\
+javax.sql.rowset.serial,\
+javax.sql.rowset.spi,\
+javax.swing,\
+javax.swing.border,\
+javax.swing.colorchooser,\
+javax.swing.event,\
+javax.swing.filechooser,\
+javax.swing.plaf,\
+javax.swing.plaf.basic,\
+javax.swing.plaf.metal,\
+javax.swing.plaf.multi,\
+javax.swing.plaf.synth,\
+javax.swing.table,\
+javax.swing.text,\
+javax.swing.text.html,\
+javax.swing.text.html.parser,\
+javax.swing.text.rtf,\
+javax.swing.tree,\
+javax.swing.undo,\
+javax.transaction,\
+javax.transaction.xa,\
+javax.xml.namespace,\
+javax.xml.parsers,\
+javax.xml.transform,\
+javax.xml.transform.stream,\
+javax.xml.transform.dom,\
+javax.xml.transform.sax,\
+javax.xml,\
+javax.xml.validation,\
+javax.xml.datatype,\
+javax.xml.xpath,\
+javax.activation,\
+com.sun.activation.registries,\
+com.sun.activation.viewers,\
+org.ietf.jgss,\
+org.omg.CORBA,\
+org.omg.CORBA_2_3,\
+org.omg.CORBA_2_3.portable,\
+org.omg.CORBA.DynAnyPackage,\
+org.omg.CORBA.ORBPackage,\
+org.omg.CORBA.portable,\
+org.omg.CORBA.TypeCodePackage,\
+org.omg.CosNaming,\
+org.omg.CosNaming.NamingContextExtPackage,\
+org.omg.CosNaming.NamingContextPackage,\
+org.omg.Dynamic,\
+org.omg.DynamicAny,\
+org.omg.DynamicAny.DynAnyFactoryPackage,\
+org.omg.DynamicAny.DynAnyPackage,\
+org.omg.IOP,\
+org.omg.IOP.CodecFactoryPackage,\
+org.omg.IOP.CodecPackage,\
+org.omg.Messaging,\
+org.omg.PortableInterceptor,\
+org.omg.PortableInterceptor.ORBInitInfoPackage,\
+org.omg.PortableServer,\
+org.omg.PortableServer.CurrentPackage,\
+org.omg.PortableServer.POAManagerPackage,\
+org.omg.PortableServer.POAPackage,\
+org.omg.PortableServer.portable,\
+org.omg.PortableServer.ServantLocatorPackage,\
+org.omg.SendingContext,\
+org.omg.stub.java.rmi,\
+org.w3c.dom,\
+org.w3c.dom.bootstrap,\
+org.w3c.dom.css,\
+org.w3c.dom.events,\
+org.w3c.dom.html,\
+org.w3c.dom.ls,\
+org.w3c.dom.ranges,\
+org.w3c.dom.stylesheets,\
+org.w3c.dom.traversal,\
+org.w3c.dom.views ,\
+org.xml.sax,\
+org.xml.sax.ext,\
+org.xml.sax.helpers,\
+org.apache.xerces.xpointer,\
+org.apache.xerces.xni.grammars,\
+org.apache.xerces.impl.xs.util,\
+org.apache.xerces.jaxp.validation,\
+org.apache.xerces.impl.dtd.models,\
+org.apache.xerces.impl.xpath,\
+org.apache.xerces.dom3.as,\
+org.apache.xerces.impl.dv.xs,\
+org.apache.xerces.util,\
+org.apache.xerces.impl.xs.identity,\
+org.apache.xerces.impl.xs.opti,\
+org.apache.xerces.jaxp,\
+org.apache.xerces.impl.dv,\
+org.apache.xerces.xs.datatypes,\
+org.apache.xerces.dom.events,\
+org.apache.xerces.impl.msg,\
+org.apache.xerces.xni,\
+org.apache.xerces.impl.xs,\
+org.apache.xerces.impl,\
+org.apache.xerces.impl.io,\
+org.apache.xerces.xinclude,\
+org.apache.xerces.jaxp.datatype,\
+org.apache.xerces.parsers,\
+org.apache.xerces.impl.dv.util,\
+org.apache.xerces.xni.parser,\
+org.apache.xerces.impl.xs.traversers,\
+org.apache.xerces.impl.dv.dtd,\
+org.apache.xerces.xs,\
+org.apache.xerces.impl.dtd,\
+org.apache.xerces.impl.validation,\
+org.apache.xerces.impl.xs.models,\
+org.apache.xerces.impl.xpath.regex,\
+org.apache.xml.serialize,\
+org.apache.xerces.dom,\
+org.apache.xalan,\
+org.apache.xalan.xslt,\
+org.apache.xalan.templates,\
+org.apache.xalan.xsltc,\
+org.apache.xalan.xsltc.cmdline,\
+org.apache.xalan.xsltc.cmdline.getopt,\
+org.apache.xalan.xsltc.trax,\
+org.apache.xalan.xsltc.dom,\
+org.apache.xalan.xsltc.runtime,\
+org.apache.xalan.xsltc.runtime.output,\
+org.apache.xalan.xsltc.util,\
+org.apache.xalan.xsltc.compiler,\
+org.apache.xalan.xsltc.compiler.util,\
+org.apache.xalan.serialize,\
+org.apache.xalan.client,\
+org.apache.xalan.res,\
+org.apache.xalan.transformer,\
+org.apache.xalan.extensions,\
+org.apache.xalan.lib,\
+org.apache.xalan.lib.sql,\
+org.apache.xalan.processor,\
+org.apache.xalan.trace,\
+org.apache.xml.dtm,\
+org.apache.xml.dtm.ref,\
+org.apache.xml.dtm.ref.sax2dtm,\
+org.apache.xml.dtm.ref.dom2dtm,\
+org.apache.xml.utils,\
+org.apache.xml.utils.res,\
+org.apache.xml.res,\
+org.apache.xml.serializer,\
+org.apache.xml.serializer.utils,\
+org.apache.xpath,\
+org.apache.xpath.domapi,\
+org.apache.xpath.objects,\
+org.apache.xpath.patterns,\
+org.apache.xpath.jaxp,\
+org.apache.xpath.res,\
+org.apache.xpath.operations,\
+org.apache.xpath.functions,\
+org.apache.xpath.axes,\
+org.apache.xpath.compiler,\
+org.apache.xml.resolver,\
+org.apache.xml.resolver.tools,\
+org.apache.xml.resolver.helpers,\
+org.apache.xml.resolver.readers,\
+org.apache.xml.resolver.etc,\
+org.apache.xml.resolver.apps,\
+javax.xml.ws,\
+javax.xml.bind,\
+javax.xml.bind.annotation,\
+javax.annotation,\
+javax.jws,\
+javax.jws.soap,\
+javax.xml.soap,\
+com.sun.xml.internal.messaging.saaj.soap.ver1_1,\
+com.sun.xml.internal.messaging.saaj.soap,\
+com.sun.tools.internal.ws.spi,\
+org.github.jamm,\
+org.wso2.carbon.bootstrap
diff --git a/modules/broker/distribution/src/main/resources/log4j.properties b/modules/broker/distribution/src/main/resources/log4j.properties
new file mode 100644
index 00000000..568e1781
--- /dev/null
+++ b/modules/broker/distribution/src/main/resources/log4j.properties
@@ -0,0 +1,239 @@
+#
+# Copyright 2009-2015 WSO2, Inc. (http://wso2.com)
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+#
+# This is the log4j configuration file used by WSO2 Carbon
+#
+# IMPORTANT : Please do not remove or change the names of any
+# of the Appenders defined here. The layout pattern & log file
+# can be changed using the WSO2 Carbon Management Console, and those
+# settings will override the settings in this file.
+#
+
+log4j.rootLogger=INFO, CARBON_CONSOLE, CARBON_LOGFILE, CARBON_MEMORY, CARBON_SYS_LOG
+
+log4j.logger.AUDIT_LOG=INFO, AUDIT_LOGFILE
+log4j.logger.org.apache.axis2.wsdl.codegen.writer.PrettyPrinter=ERROR, CARBON_LOGFILE, CARBON_MEMORY
+log4j.logger.org.apache.axis2.clustering=INFO, CARBON_CONSOLE, CARBON_LOGFILE
+log4j.logger.org.apache=INFO, CARBON_LOGFILE, CARBON_MEMORY
+log4j.logger.org.apache.catalina=WARN
+log4j.logger.org.apache.tomcat=WARN
+log4j.logger.org.wso2.carbon.apacheds=WARN
+log4j.logger.org.apache.directory.server.ldap=WARN
+log4j.logger.org.apache.directory.server.core.event=WARN
+log4j.logger.com.atomikos=INFO,ATOMIKOS
+log4j.logger.org.quartz=WARN
+log4j.logger.org.apache.jackrabbit.webdav=WARN
+log4j.logger.org.apache.juddi=ERROR
+log4j.logger.org.apache.commons.digester.Digester=WARN
+log4j.logger.org.apache.jasper.compiler.TldLocationsCache=WARN
+log4j.logger.org.apache.qpid=WARN
+log4j.logger.org.apache.qpid.server.Main=INFO
+log4j.logger.qpid.message=WARN
+log4j.logger.qpid.message.broker.listening=INFO
+log4j.logger.org.apache.tiles=WARN
+log4j.logger.org.apache.commons.httpclient=ERROR
+log4j.logger.org.apache.coyote=WARN
+log4j.logger.org.apache.solr=ERROR
+log4j.logger.org.infinispan=WARN
+log4j.logger.org.jgroups=ERROR
+log4j.logger.org.wso2=INFO
+log4j.logger.org.apache.axis2.enterprise=FATAL, CARBON_LOGFILE, CARBON_MEMORY
+log4j.logger.org.opensaml.xml=WARN, CARBON_LOGFILE, CARBON_MEMORY
+log4j.logger.org.apache.directory.shared.ldap=WARN, CARBON_LOGFILE, CARBON_MEMORY
+log4j.logger.org.apache.directory.server.ldap.handlers=WARN, CARBON_LOGFILE, CARBON_MEMORY
+#Following are to remove false error messages from startup (IS)
+log4j.logger.org.apache.directory.shared.ldap.entry.DefaultServerAttribute=FATAL, CARBON_LOGFILE, CARBON_MEMORY
+log4j.logger.org.apache.directory.server.core.DefaultDirectoryService=ERROR, CARBON_LOGFILE, CARBON_MEMORY
+log4j.logger.org.apache.directory.shared.ldap.ldif.LdifReader=ERROR, CARBON_LOGFILE, CARBON_MEMORY
+log4j.logger.org.apache.directory.server.ldap.LdapProtocolHandler=ERROR, CARBON_LOGFILE, CARBON_MEMORY
+log4j.logger.org.apache.directory.server.core=ERROR, CARBON_LOGFILE, CARBON_MEMORY
+#Hive Related Log configurations
+log4j.logger.DataNucleus=ERROR
+log4j.logger.Datastore=ERROR
+log4j.logger.Datastore.Schema=ERROR
+log4j.logger.JPOX.Datastore=ERROR
+log4j.logger.JPOX.Plugin=ERROR
+log4j.logger.JPOX.MetaData=ERROR
+log4j.logger.JPOX.Query=ERROR
+log4j.logger.JPOX.General=ERROR
+log4j.logger.JPOX.Enhancer=ERROR
+log4j.logger.org.apache.hadoop.hive=WARN
+log4j.logger.hive=WARN
+log4j.logger.ExecMapper=WARN
+log4j.logger.ExecReducer=WARN
+
+#andes specific
+log4j.logger.org.wso2.andes.server.handler.ConnectionStartOkMethodHandler=WARN
+log4j.logger.org.wso2.andes.server.handler.ChannelOpenHandler=WARN
+log4j.logger.org.wso2.andes.server.handler.ChannelCloseHandler=WARN
+log4j.logger.org.wso2.andes.server.AMQChannel=WARN
+log4j.logger.org.wso2.andes.server.handler.ConnectionCloseMethodHandler=WARN
+log4j.logger.org.wso2.andes.server.handler.QueueDeclareHandler=WARN
+log4j.logger.org.wso2.andes.server.handler.QueueBindHandler=WARN
+log4j.logger.org.wso2.andes.server.virtualhost.VirtualHostConfigRecoveryHandler=WARN
+log4j.logger.org.wso2.andes.amqp.QpidAndesBridge=WARN
+log4j.logger.trace.messages=TRACE,CARBON_TRACE_LOGFILE
+
+#trace level logs for WSO2 Message Broker
+#log4j.logger.org.wso2.andes.server.trace=TRACE,CARBON_TRACE_LOGFILE
+
+# Uncomment to enable MessageTracer
+log4j.logger.org.wso2.andes.tools.utils.MessageTracer=INFO,CARBON_TRACE_LOGFILE
+
+#Andes logs for troubleshooting
+#log4j.logger.org.wso2.andes.kernel.MessageFlusher=DEBUG
+#log4j.logger.org.wso2.andes.kernel.slot.SlotDeliveryWorker=DEBUG
+#log4j.logger.org.wso2.andes.amqp.QpidAndesBridge=DEBUG
+#log4j.logger.org.wso2.andes.server.AMQChannel=DEBUG
+#log4j.logger.org.wso2.andes.kernel.slot.SlotDeliveryWorkerManager=DEBUG
+#log4j.logger.org.wso2.andes.kernel.distruptor.inbound.MessageWriter=DEBUG
+#log4j.logger.org.wso2.andes.kernel.distruptor.inbound.AckHandler=DEBUG
+#log4j.logger.org.wso2.andes.kernel.distruptor.inbound.StateEventHandler=DEBUG
+#log4j.logger.org.wso2.andes.kernel.slot.SlotManagerClusterMode=DEBUG
+#log4j.logger.org.wso2.andes.subscription.LocalSubscription=DEBUG
+#log4j.logger.org.wso2.andes.subscription.SubscriptionStore=DEBUG
+
+#MQTT specific
+#log4j.logger.org.dna.mqtt.wso2.AndesMQTTBridge=DEBUG
+#log4j.logger.org.dna.mqtt.moquette.messaging.spi.impl.ProtocolProcessor=DEBUG
+
+# DAS_AGENT is set to be a Custom Log Appender.
+#log4j.appender.DAS_AGENT=org.wso2.carbon.analytics.shared.data.agents.log4j.appender.LogEventAppender
+# DAS_AGENT uses PatternLayout.
+#log4j.appender.DAS_AGENT.layout=org.wso2.carbon.analytics.shared.data.agents.log4j.util.TenantAwarePatternLayout
+#log4j.appender.DAS_AGENT.columnList=%D,%S,%A,%d,%c,%p,%m,%H,%I,%Stacktrace
+#log4j.appender.DAS_AGENT.userName=admin
+#log4j.appender.DAS_AGENT.password=admin
+#log4j.appender.DAS_AGENT.url=tcp://localhost:7612
+#log4j.appender.DAS_AGENT.maxTolerableConsecutiveFailure=5
+#log4j.appender.DAS_AGENT.streamDef=loganalyzer:1.0.0
+
+log4j.additivity.org.apache.axis2.clustering=false
+log4j.additivity.com.atomikos=false
+
+# CARBON_CONSOLE is set to be a ConsoleAppender using a PatternLayout.
+log4j.appender.CARBON_CONSOLE=org.apache.log4j.ConsoleAppender
+log4j.appender.CARBON_CONSOLE.layout=org.wso2.carbon.utils.logging.TenantAwarePatternLayout
+# ConversionPattern will be overridden by the configuration setting in the DB
+log4j.appender.CARBON_CONSOLE.layout.ConversionPattern=[%d] %P%5p {%c} - %x %m%n
+log4j.appender.CARBON_CONSOLE.layout.TenantPattern=%U%@%D[%T]
+log4j.appender.CARBON_CONSOLE.threshold=DEBUG
+
+
+# The memory appender for logging
+log4j.appender.CARBON_MEMORY=org.wso2.carbon.logging.service.appender.CarbonMemoryAppender
+log4j.appender.CARBON_MEMORY.bufferSize=2000
+log4j.appender.CARBON_MEMORY.layout=org.wso2.carbon.utils.logging.TenantAwarePatternLayout
+# ConversionPattern will be overridden by the configuration setting in the DB
+log4j.appender.CARBON_MEMORY.layout.ConversionPattern=TID: [%T] [%S] [%d] %P%5p {%c} - %x %m {%c}%n
+log4j.appender.CARBON_MEMORY.layout.TenantPattern=%U%@%D [%T] [%S]
+log4j.appender.CARBON_MEMORY.columnList=%T,%S,%A,%d,%c,%p,%m,%H,%I,%Stacktrace
+log4j.appender.CARBON_MEMORY.threshold=DEBUG
+
+# CARBON_LOGFILE is set to be a DailyRollingFileAppender using a PatternLayout.
+log4j.appender.CARBON_LOGFILE=org.apache.log4j.DailyRollingFileAppender
+# Log file will be overridden by the configuration setting in the DB
+# This path should be relative to WSO2 Carbon Home
+log4j.appender.CARBON_LOGFILE.File=${carbon.home}/repository/logs/${instance.log}/wso2carbon${instance.log}.log
+log4j.appender.CARBON_LOGFILE.Append=true
+log4j.appender.CARBON_LOGFILE.layout=org.wso2.carbon.utils.logging.TenantAwarePatternLayout
+# ConversionPattern will be overridden by the configuration setting in the DB
+log4j.appender.CARBON_LOGFILE.layout.ConversionPattern=TID: [%T] [%S] [%d] %P%5p {%c} - %x %m {%c}%n
+log4j.appender.CARBON_LOGFILE.layout.TenantPattern=%U%@%D [%T] [%S]
+log4j.appender.CARBON_LOGFILE.threshold=DEBUG
+
+log4j.appender.CARBON_SYS_LOG = org.apache.log4j.net.SyslogAppender
+log4j.appender.CARBON_SYS_LOG.layout=org.apache.log4j.PatternLayout
+log4j.appender.CARBON_SYS_LOG.layout.ConversionPattern=[%d] %5p {%c} - %x %m {%c}%n
+log4j.appender.CARBON_SYS_LOG.SyslogHost=localhost
+log4j.appender.CARBON_SYS_LOG.Facility=USER
+log4j.appender.CARBON_SYS_LOG.threshold=DEBUG
+
+# LOGEVENT is set to be a LogEventAppender using a PatternLayout to send logs to LOGEVENT
+log4j.appender.LOGEVENT=org.wso2.carbon.logging.appender.LogEventAppender
+log4j.appender.LOGEVENT.url=tcp://10.100.3.103:7611
+log4j.appender.LOGEVENT.layout=org.wso2.carbon.utils.logging.TenantAwarePatternLayout
+log4j.appender.LOGEVENT.columnList=%T,%S,%A,%d,%c,%p,%m,%H,%I,%Stacktrace
+log4j.appender.LOGEVENT.userName=admin
+log4j.appender.LOGEVENT.password=admin
+
+# Appender config to CARBON_TRACE_LOGFILE
+log4j.appender.CARBON_TRACE_LOGFILE=org.apache.log4j.DailyRollingFileAppender
+log4j.appender.CARBON_TRACE_LOGFILE.File=${carbon.home}/repository/logs/${instance.log}/wso2carbon-trace-messages${instance.log}.log
+log4j.appender.CARBON_TRACE_LOGFILE.Append=true
+log4j.appender.CARBON_TRACE_LOGFILE.layout=org.wso2.carbon.utils.logging.TenantAwarePatternLayout
+log4j.appender.CARBON_TRACE_LOGFILE.layout.ConversionPattern=[%d] %P%5p {%c} - %x %m {%c}%n
+log4j.appender.CARBON_TRACE_LOGFILE.layout.TenantPattern=%U%@%D [%T] [%S]
+log4j.appender.CARBON_TRACE_LOGFILE.threshold=TRACE
+log4j.additivity.trace.messages=false
+
+# Appender config to AUDIT_LOGFILE
+log4j.appender.AUDIT_LOGFILE=org.apache.log4j.DailyRollingFileAppender
+log4j.appender.AUDIT_LOGFILE.File=${carbon.home}/repository/logs/audit.log
+log4j.appender.AUDIT_LOGFILE.Append=true
+log4j.appender.AUDIT_LOGFILE.layout=org.wso2.carbon.utils.logging.TenantAwarePatternLayout
+log4j.appender.AUDIT_LOGFILE.layout.ConversionPattern=[%d] %P%5p - %x %m %n
+log4j.appender.AUDIT_LOGFILE.layout.TenantPattern=%U%@%D [%T] [%S]
+log4j.appender.AUDIT_LOGFILE.threshold=INFO
+log4j.additivity.AUDIT_LOG=false
+
+# Appender config to send Atomikos transaction logs to new log file tm.out.
+log4j.appender.ATOMIKOS = org.apache.log4j.RollingFileAppender
+log4j.appender.ATOMIKOS.File = repository/logs/tm.out
+log4j.appender.ATOMIKOS.Append = true
+log4j.appender.ATOMIKOS.layout = org.apache.log4j.PatternLayout
+log4j.appender.ATOMIKOS.layout.ConversionPattern=%p %t %c - %m%n
+
+# This file is used to override the default logger settings, and is used to remove unwanted logs from Shindig appearing on the console.
+
+# Specification of Handler used by Console Logger
+handlers=java.util.logging.ConsoleHandler
+
+# Replacing default INFO level with SEVERE
+java.util.logging.ConsoleHandler.level=SEVERE
+
+# moquette-log properties
+
+log4j.logger.org.dna.mqtt=INFO
+log4j.logger.org.dna.mqtt.moquette.messaging.spi.impl.ProtocolProcessor=INFO
+log4j.logger.org.dna.mqtt.moquette.messaging.spi.impl.SimpleMessaging=WARN
+
+#Protocol parsing
+log4j.logger.org.dna.mqtt.moquette.server.netty.NettyMQTTHandler=WARN
+#log4j.logger.org.dna.mqtt.moquette.server.netty.NettyMQTTHandler=DEBUG
+log4j.logger.org.dna.mqtt.moquette.parser.netty=WARN
+#Storage server
+#log4j.logger.org.dna.mqtt.moquette.messaging.spi.impl.subscriptions.SubscriptionsStore=DEBUG
+#log4j.logger.org.dna.mqtt.moquette.messaging.spi.impl.HawtDBStorageService=DEBUG
+
+# stdout appender is set to be a ConsoleAppender.
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+#log4j.appender.stdout.Threshold=WARN
+#log4j.appender.stdout.Threshold=INFO
+#log4j.appender.stdout.Threshold=DEBUG
+#log4j.appender.stdout.Threshold=TRACE
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%-4r [%t] %-5p %c{1} %x - %m%n
+
+#file appender
+log4j.appender.file=org.apache.log4j.RollingFileAppender
+log4j.appender.file.Threshold=INFO
+log4j.appender.file.File=wso2carbon.log
+log4j.appender.file.MaxFileSize=1MB
+log4j.appender.file.MaxBackupIndex=1
+log4j.appender.file.layout=org.apache.log4j.PatternLayout
+log4j.appender.file.layout.ConversionPattern=%-4r [%t] %-5p %c{1} %x - %m%n
diff --git a/modules/broker/distribution/src/main/resources/release-notes.xml b/modules/broker/distribution/src/main/resources/release-notes.xml
new file mode 100644
index 00000000..0dc11433
--- /dev/null
+++ b/modules/broker/distribution/src/main/resources/release-notes.xml
@@ -0,0 +1,223 @@
+
+
+
+
+
+
+
+ WSO2 Message Broker 3.1.0 Released!
+
+
+
+
+
+
+
+
+
WSO2 Message Broker (MB) 3.1.0 Released!
+
+
+ The WSO2 Message Broker team is pleased to announce the 3.1.0 release of WSO2 Message Broker (MB).
+
+
WSO2 MB is a lightweight and easy-to-use Open Source Distributed Message Brokering
+ Server (MB) which is available under the Apache Software License v2.0.
+
+ This is based on the revolutionary WSO2 Carbon [Middleware a' la carte]
+ framework. All the major features have been developed as pluggable Carbon
+ components.
+
+
+ WSO2 MB v 3.1.0 is developed on top of the revolutionary
+ WSO2 Carbon platform (Middleware a' la carte),
+ an OSGi based framework that provides seamless modularity to your SOA via
+ componentization. This release also contains many new features and a range of optional
+ components (add-ons) that can be installed to customize the behavior of the MB. Further, any
+ existing features of the MB which are not required to your environment can be easily
+ removed using the underlying provisioning framework of Carbon. In brief, WSO2 MB can
+ be fully customized and tailored to meet your exact SOA needs.
+
WSO2 Message Broker brings messaging and eventing capabilities into your SOA
+ framework. Message Broker contains all the previously available features except
+ SQS support. Those are :
+
+
+
JMS Queuing support
+
JMS Pub/Sub mechanism for topics
+
Hierarchical Topics Subscriptions
+
Queue Message browsing with added UI support
+
Message Re-Delivery Tries Configuration
+
Message Re delivery Header Field support
+
Sample text message sender tool in UI
+
Queue purging support
+
Simple clustering machanism based on carbon clustering
+
Ability to view details of the cluster using Management Console
+
Message delivery fine tuning capabilities
+
Relational databases as a storage machanism
+
+
+
+
The underlying JMS engine handles WS-Eventing/JMS synchronisation that enables
+ exposing and consuming your events using two different standard API's.
+
+ This release of WSO2 MB comes with a number of bug fixes, both in the base
+ framework and the MB specific components. All the issues which have been
+ fixed in MB v 3.1.0 are recorded at following locations:
+
+ WSO2 encourages you to report issues and your enhancement requests for the
+ WSO2 MB using the public JIRA.
+
+
+ You can also watch how they are resolved, and comment on the progress..
+
+
+
Support
+
We are committed to ensuring that your enterprise middleware deployment is completely
+ supported from evaluation to production. Our unique approach ensures that all
+ support leverages our open development methodology and is provided by the very same
+ engineers who build the technology.
+
+
+
For more details and to take advantage of this unique opportunity please visit
+ http://wso2.com/support/
+
Thank you for your interest in WSO2 Message Broker.
+
+
+
+ -- The WSO2 MB Team --
+
+
+
+
diff --git a/modules/broker/distribution/src/main/resources/wso2server.bat b/modules/broker/distribution/src/main/resources/wso2server.bat
new file mode 100644
index 00000000..8031ba30
--- /dev/null
+++ b/modules/broker/distribution/src/main/resources/wso2server.bat
@@ -0,0 +1,177 @@
+@echo off
+
+REM ---------------------------------------------------------------------------
+REM Copyright 2005-2009 WSO2, Inc. http://www.wso2.org
+REM
+REM Licensed under the Apache License, Version 2.0 (the "License");
+REM you may not use this file except in compliance with the License.
+REM You may obtain a copy of the License at
+REM
+REM http://www.apache.org/licenses/LICENSE-2.0
+REM
+REM Unless required by applicable law or agreed to in writing, software
+REM distributed under the License is distributed on an "AS IS" BASIS,
+REM WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+REM See the License for the specific language governing permissions and
+REM limitations under the License.
+
+rem ---------------------------------------------------------------------------
+rem Main Script for WSO2 Carbon
+rem
+rem Environment Variable Prequisites
+rem
+rem CARBON_HOME Home of CARBON installation. If not set I will try
+rem to figure it out.
+rem
+rem JAVA_HOME Must point at your Java Development Kit installation.
+rem
+rem JAVA_OPTS (Optional) Java runtime options used when the commands
+rem is executed.
+rem ---------------------------------------------------------------------------
+
+rem ----- if JAVA_HOME is not set we're not happy ------------------------------
+:checkJava
+
+if "%JAVA_HOME%" == "" goto noJavaHome
+if not exist "%JAVA_HOME%\bin\java.exe" goto noJavaHome
+goto checkServer
+
+:noJavaHome
+echo "You must set the JAVA_HOME variable before running CARBON."
+goto end
+
+rem ----- Only set CARBON_HOME if not already set ----------------------------
+:checkServer
+rem %~sdp0 is expanded pathname of the current script under NT with spaces in the path removed
+if "%CARBON_HOME%"=="" set CARBON_HOME=%~sdp0..
+SET curDrive=%cd:~0,1%
+SET wsasDrive=%CARBON_HOME:~0,1%
+if not "%curDrive%" == "%wsasDrive%" %wsasDrive%:
+
+rem find CARBON_HOME if it does not exist due to either an invalid value passed
+rem by the user or the %0 problem on Windows 9x
+if not exist "%CARBON_HOME%\bin\version.txt" goto noServerHome
+
+set AXIS2_HOME=%CARBON_HOME%
+goto updateClasspath
+
+:noServerHome
+echo CARBON_HOME is set incorrectly or CARBON could not be located. Please set CARBON_HOME.
+goto end
+
+rem ----- update classpath -----------------------------------------------------
+:updateClasspath
+
+setlocal EnableDelayedExpansion
+cd %CARBON_HOME%
+set CARBON_CLASSPATH=
+FOR %%C in ("%CARBON_HOME%\bin\*.jar") DO set CARBON_CLASSPATH=!CARBON_CLASSPATH!;".\bin\%%~nC%%~xC"
+
+set CARBON_CLASSPATH="%JAVA_HOME%\lib\tools.jar";%CARBON_CLASSPATH%;
+
+FOR %%D in ("%CARBON_HOME%\lib\commons-lang*.jar") DO set CARBON_CLASSPATH=!CARBON_CLASSPATH!;".\lib\%%~nD%%~xD"
+
+rem ----- Process the input command -------------------------------------------
+
+rem Slurp the command line arguments. This loop allows for an unlimited number
+rem of arguments (up to the command line limit, anyway).
+
+
+:setupArgs
+if ""%1""=="""" goto doneStart
+
+if ""%1""==""-run"" goto commandLifecycle
+if ""%1""==""--run"" goto commandLifecycle
+if ""%1""==""run"" goto commandLifecycle
+
+if ""%1""==""-restart"" goto commandLifecycle
+if ""%1""==""--restart"" goto commandLifecycle
+if ""%1""==""restart"" goto commandLifecycle
+
+if ""%1""==""debug"" goto commandDebug
+if ""%1""==""-debug"" goto commandDebug
+if ""%1""==""--debug"" goto commandDebug
+
+if ""%1""==""version"" goto commandVersion
+if ""%1""==""-version"" goto commandVersion
+if ""%1""==""--version"" goto commandVersion
+
+shift
+goto setupArgs
+
+rem ----- commandVersion -------------------------------------------------------
+:commandVersion
+shift
+type "%CARBON_HOME%\bin\version.txt"
+type "%CARBON_HOME%\bin\wso2carbon-version.txt"
+goto end
+
+rem ----- commandDebug ---------------------------------------------------------
+:commandDebug
+shift
+set DEBUG_PORT=%1
+if "%DEBUG_PORT%"=="" goto noDebugPort
+if not "%JAVA_OPTS%"=="" echo Warning !!!. User specified JAVA_OPTS will be ignored, once you give the --debug option.
+set JAVA_OPTS=-Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=%DEBUG_PORT%
+echo Please start the remote debugging client to continue...
+goto findJdk
+
+:noDebugPort
+echo Please specify the debug port after the --debug option
+goto end
+
+rem ----- commandLifecycle -----------------------------------------------------
+:commandLifecycle
+goto findJdk
+
+:doneStart
+if "%OS%"=="Windows_NT" @setlocal
+if "%OS%"=="WINNT" @setlocal
+
+rem ---------- Handle the SSL Issue with proper JDK version --------------------
+rem find the version of the jdk
+:findJdk
+
+set CMD=RUN %*
+
+:checkJdk17
+"%JAVA_HOME%\bin\java" -version 2>&1 | findstr /r "1.[7|8]" >NUL
+IF ERRORLEVEL 1 goto unknownJdk
+goto jdk17
+
+:unknownJdk
+echo Starting WSO2 Carbon (in unsupported JDK)
+echo [ERROR] CARBON is supported only on JDK 1.7 and 1.8
+goto jdk17
+
+:jdk17
+goto runServer
+
+rem ----------------- Execute The Requested Command ----------------------------
+
+:runServer
+cd %CARBON_HOME%
+
+rem ------------------ Remove tmp folder on startup -----------------------------
+set TMP_DIR=%CARBON_HOME%\tmp
+rmdir "%TMP_DIR%" /s /q
+
+rem ---------- Add jars to classpath ----------------
+
+set CARBON_CLASSPATH=.\lib;%CARBON_CLASSPATH%
+
+set JAVA_ENDORSED=".\lib\endorsed";"%JAVA_HOME%\jre\lib\endorsed";"%JAVA_HOME%\lib\endorsed"
+
+set CMD_LINE_ARGS=-Xbootclasspath/a:%CARBON_XBOOTCLASSPATH% -Xms1024m -Xmx2048m -XX:MaxPermSize=256m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath="%CARBON_HOME%\repository\logs\heap-dump.hprof" -Dcom.sun.management.jmxremote -classpath %CARBON_CLASSPATH% %JAVA_OPTS% -Djava.endorsed.dirs=%JAVA_ENDORSED% -DandesConfig=broker.xml -Dcarbon.registry.root=/ -Dcarbon.home="%CARBON_HOME%" -Dwso2.server.standalone=true -Djava.command="%JAVA_HOME%\bin\java" -Djava.opts="%JAVA_OPTS%" -Djava.io.tmpdir="%CARBON_HOME%\tmp" -Dcatalina.base="%CARBON_HOME%\lib\tomcat" -Dwso2.carbon.xml=%CARBON_HOME%\repository\conf\carbon.xml -Dwso2.registry.xml="%CARBON_HOME%\repository\conf\registry.xml" -Dwso2.user.mgt.xml="%CARBON_HOME%\repository\conf\user-mgt.xml" -Dwso2.transports.xml="%CARBON_HOME%\repository\conf\mgt-transports.xml" -Djava.util.logging.config.file="%CARBON_HOME%\repository\conf\log4j.properties" -Dcarbon.config.dir.path="%CARBON_HOME%\repository\conf" -Dcarbon.logs.path="%CARBON_HOME%\repository\logs" -Dcomponents.repo="%CARBON_HOME%\repository\components" -Dconf.location="%CARBON_HOME%\repository\conf" -Dcom.atomikos.icatch.file="%CARBON_HOME%\lib\transactions.properties" -Dcom.atomikos.icatch.hide_init_file_path="true" -Dorg.apache.jasper.compiler.Parser.STRICT_QUOTE_ESCAPING=false -Dorg.apache.jasper.runtime.BodyContentImpl.LIMIT_BUFFER=true -Dcom.sun.jndi.ldap.connect.pool.authentication=simple -Dcom.sun.jndi.ldap.connect.pool.timeout=3000 -Dorg.terracotta.quartz.skipUpdateCheck=true -Dcarbon.classpath=%CARBON_CLASSPATH% -Dfile.encoding=UTF8
+
+:runJava
+echo JAVA_HOME environment variable is set to %JAVA_HOME%
+echo CARBON_HOME environment variable is set to %CARBON_HOME%
+"%JAVA_HOME%\bin\java" %CMD_LINE_ARGS% org.wso2.carbon.bootstrap.Bootstrap %CMD%
+if "%ERRORLEVEL%"=="121" goto runJava
+:end
+goto endlocal
+
+:endlocal
+
+:END
diff --git a/modules/broker/distribution/src/main/resources/wso2server.sh b/modules/broker/distribution/src/main/resources/wso2server.sh
new file mode 100644
index 00000000..14694e89
--- /dev/null
+++ b/modules/broker/distribution/src/main/resources/wso2server.sh
@@ -0,0 +1,308 @@
+#!/bin/sh
+# ----------------------------------------------------------------------------
+# Copyright 2005-2012 WSO2, Inc. http://www.wso2.org
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# ----------------------------------------------------------------------------
+# Main Script for the WSO2 Carbon Server
+#
+# Environment Variable Prequisites
+#
+# CARBON_HOME Home of WSO2 Carbon installation. If not set I will try
+# to figure it out.
+#
+# JAVA_HOME Must point at your Java Development Kit installation.
+#
+# JAVA_OPTS (Optional) Java runtime options used when the commands
+# is executed.
+#
+# NOTE: Borrowed generously from Apache Tomcat startup scripts.
+# -----------------------------------------------------------------------------
+
+# OS specific support. $var _must_ be set to either true or false.
+#ulimit -n 100000
+
+cygwin=false;
+darwin=false;
+os400=false;
+mingw=false;
+case "`uname`" in
+CYGWIN*) cygwin=true;;
+MINGW*) mingw=true;;
+OS400*) os400=true;;
+Darwin*) darwin=true
+ if [ -z "$JAVA_VERSION" ] ; then
+ JAVA_VERSION="CurrentJDK"
+ else
+ echo "Using Java version: $JAVA_VERSION"
+ fi
+ if [ -z "$JAVA_HOME" ] ; then
+ JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/${JAVA_VERSION}/Home
+ fi
+ ;;
+esac
+
+# resolve links - $0 may be a softlink
+PRG="$0"
+
+while [ -h "$PRG" ]; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '.*/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`/"$link"
+ fi
+done
+
+# Get standard environment variables
+PRGDIR=`dirname "$PRG"`
+
+# Only set CARBON_HOME if not already set
+[ -z "$CARBON_HOME" ] && CARBON_HOME=`cd "$PRGDIR/.." ; pwd`
+
+# Set AXIS2_HOME. Needed for One Click JAR Download
+AXIS2_HOME=$CARBON_HOME
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched
+if $cygwin; then
+ [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+ [ -n "$CARBON_HOME" ] && CARBON_HOME=`cygpath --unix "$CARBON_HOME"`
+ [ -n "$AXIS2_HOME" ] && CARBON_HOME=`cygpath --unix "$CARBON_HOME"`
+fi
+
+# For OS400
+if $os400; then
+ # Set job priority to standard for interactive (interactive - 6) by using
+ # the interactive priority - 6, the helper threads that respond to requests
+ # will be running at the same priority as interactive jobs.
+ COMMAND='chgjob job('$JOBNAME') runpty(6)'
+ system $COMMAND
+
+ # Enable multi threading
+ QIBM_MULTI_THREADED=Y
+ export QIBM_MULTI_THREADED
+fi
+
+# For Migwn, ensure paths are in UNIX format before anything is touched
+if $mingw ; then
+ [ -n "$CARBON_HOME" ] &&
+ CARBON_HOME="`(cd "$CARBON_HOME"; pwd)`"
+ [ -n "$JAVA_HOME" ] &&
+ JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
+ [ -n "$AXIS2_HOME" ] &&
+ CARBON_HOME="`(cd "$CARBON_HOME"; pwd)`"
+ # TODO classpath?
+fi
+
+if [ -z "$JAVACMD" ] ; then
+ if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ else
+ JAVACMD=java
+ fi
+fi
+
+if [ ! -x "$JAVACMD" ] ; then
+ echo "Error: JAVA_HOME is not defined correctly."
+ echo " CARBON cannot execute $JAVACMD"
+ exit 1
+fi
+
+# if JAVA_HOME is not set we're not happy
+if [ -z "$JAVA_HOME" ]; then
+ echo "You must set the JAVA_HOME variable before running CARBON."
+ exit 1
+fi
+
+if [ -e "$CARBON_HOME/wso2carbon.pid" ]; then
+ PID=`cat "$CARBON_HOME"/wso2carbon.pid`
+fi
+
+# ----- Process the input command ----------------------------------------------
+args=""
+for c in $*
+do
+ if [ "$c" = "--debug" ] || [ "$c" = "-debug" ] || [ "$c" = "debug" ]; then
+ CMD="--debug"
+ continue
+ elif [ "$CMD" = "--debug" ]; then
+ if [ -z "$PORT" ]; then
+ PORT=$c
+ fi
+ elif [ "$c" = "--stop" ] || [ "$c" = "-stop" ] || [ "$c" = "stop" ]; then
+ CMD="stop"
+ elif [ "$c" = "--start" ] || [ "$c" = "-start" ] || [ "$c" = "start" ]; then
+ CMD="start"
+ elif [ "$c" = "--version" ] || [ "$c" = "-version" ] || [ "$c" = "version" ]; then
+ CMD="version"
+ elif [ "$c" = "--restart" ] || [ "$c" = "-restart" ] || [ "$c" = "restart" ]; then
+ CMD="restart"
+ elif [ "$c" = "--test" ] || [ "$c" = "-test" ] || [ "$c" = "test" ]; then
+ CMD="test"
+ else
+ args="$args $c"
+ fi
+done
+
+if [ "$CMD" = "--debug" ]; then
+ if [ "$PORT" = "" ]; then
+ echo " Please specify the debug port after the --debug option"
+ exit 1
+ fi
+ if [ -n "$JAVA_OPTS" ]; then
+ echo "Warning !!!. User specified JAVA_OPTS will be ignored, once you give the --debug option."
+ fi
+ CMD="RUN"
+ JAVA_OPTS="-Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=$PORT"
+ echo "Please start the remote debugging client to continue..."
+elif [ "$CMD" = "start" ]; then
+ if [ -e "$CARBON_HOME/wso2carbon.pid" ]; then
+ if ps -p $PID > /dev/null ; then
+ echo "Process is already running"
+ exit 0
+ fi
+ fi
+ export CARBON_HOME=$CARBON_HOME
+# using nohup sh to avoid erros in solaris OS.TODO
+ nohup sh $CARBON_HOME/bin/wso2server.sh $args > /dev/null 2>&1 &
+ exit 0
+elif [ "$CMD" = "stop" ]; then
+ export CARBON_HOME=$CARBON_HOME
+ kill -term `cat $CARBON_HOME/wso2carbon.pid`
+ exit 0
+elif [ "$CMD" = "restart" ]; then
+ export CARBON_HOME=$CARBON_HOME
+ kill -term `cat $CARBON_HOME/wso2carbon.pid`
+ process_status=0
+ pid=`cat $CARBON_HOME/wso2carbon.pid`
+ while [ "$process_status" -eq "0" ]
+ do
+ sleep 1;
+ ps -p$pid 2>&1 > /dev/null
+ process_status=$?
+ done
+
+# using nohup sh to avoid erros in solaris OS.TODO
+ nohup sh $CARBON_HOME/bin/wso2server.sh $args > /dev/null 2>&1 &
+ exit 0
+elif [ "$CMD" = "test" ]; then
+ JAVACMD="exec "$JAVACMD""
+elif [ "$CMD" = "version" ]; then
+ cat $CARBON_HOME/bin/version.txt
+ cat $CARBON_HOME/bin/wso2carbon-version.txt
+ exit 0
+fi
+
+# ---------- Handle the SSL Issue with proper JDK version --------------------
+jdk_17=`$JAVA_HOME/bin/java -version 2>&1 | grep "1.[7|8]"`
+if [ "$jdk_17" = "" ]; then
+ echo " Starting WSO2 Carbon (in unsupported JDK)"
+ echo " [ERROR] CARBON is supported only on JDK 1.7 and 1.8"
+fi
+
+CARBON_XBOOTCLASSPATH=""
+for f in "$CARBON_HOME"/lib/xboot/*.jar
+do
+ if [ "$f" != "$CARBON_HOME/lib/xboot/*.jar" ];then
+ CARBON_XBOOTCLASSPATH="$CARBON_XBOOTCLASSPATH":$f
+ fi
+done
+
+JAVA_ENDORSED_DIRS="$CARBON_HOME/lib/endorsed":"$JAVA_HOME/jre/lib/endorsed":"$JAVA_HOME/lib/endorsed"
+
+CARBON_CLASSPATH=""
+if [ -e "$JAVA_HOME/lib/tools.jar" ]; then
+ CARBON_CLASSPATH="$JAVA_HOME/lib/tools.jar"
+fi
+for f in "$CARBON_HOME"/bin/*.jar
+do
+ if [ "$f" != "$CARBON_HOME/bin/*.jar" ];then
+ CARBON_CLASSPATH="$CARBON_CLASSPATH":$f
+ fi
+done
+for t in "$CARBON_HOME"/lib/commons-lang*.jar
+do
+ CARBON_CLASSPATH="$CARBON_CLASSPATH":$t
+done
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin; then
+ JAVA_HOME=`cygpath --absolute --windows "$JAVA_HOME"`
+ CARBON_HOME=`cygpath --absolute --windows "$CARBON_HOME"`
+ AXIS2_HOME=`cygpath --absolute --windows "$CARBON_HOME"`
+ CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
+ JAVA_ENDORSED_DIRS=`cygpath --path --windows "$JAVA_ENDORSED_DIRS"`
+ CARBON_CLASSPATH=`cygpath --path --windows "$CARBON_CLASSPATH"`
+ CARBON_XBOOTCLASSPATH=`cygpath --path --windows "$CARBON_XBOOTCLASSPATH"`
+fi
+
+# ----- Execute The Requested Command -----------------------------------------
+
+echo JAVA_HOME environment variable is set to $JAVA_HOME
+echo CARBON_HOME environment variable is set to $CARBON_HOME
+
+cd "$CARBON_HOME"
+
+TMP_DIR=$CARBON_HOME/tmp
+if [ -d "$TMP_DIR" ]; then
+rm -rf "$TMP_DIR"
+fi
+
+START_EXIT_STATUS=121
+status=$START_EXIT_STATUS
+
+#To monitor a Carbon server in remote JMX mode on linux host machines, set the below system property.
+# -Djava.rmi.server.hostname="your.IP.goes.here"
+
+while [ "$status" = "$START_EXIT_STATUS" ]
+do
+ $JAVACMD \
+ -Xbootclasspath/a:"$CARBON_XBOOTCLASSPATH" \
+ -Xms2048m -Xmx2048m -XX:MaxPermSize=256m \
+ -XX:+HeapDumpOnOutOfMemoryError \
+ -XX:HeapDumpPath="$CARBON_HOME/repository/logs/heap-dump.hprof" \
+ $JAVA_OPTS \
+ -DandesConfig=broker.xml \
+ -Dcom.sun.management.jmxremote \
+ -classpath "$CARBON_CLASSPATH" \
+ -Djava.endorsed.dirs="$JAVA_ENDORSED_DIRS" \
+ -Djava.io.tmpdir="$CARBON_HOME/tmp" \
+ -Dcatalina.base="$CARBON_HOME/lib/tomcat" \
+ -Dwso2.server.standalone=true \
+ -Dcarbon.registry.root=/ \
+ -Djava.command="$JAVACMD" \
+ -Dcarbon.home="$CARBON_HOME" \
+ -Djava.util.logging.config.file="$CARBON_HOME/repository/conf/log4j.properties" \
+ -Dcarbon.config.dir.path="$CARBON_HOME/repository/conf" \
+ -Dcomponents.repo="$CARBON_HOME/repository/components/plugins" \
+ -Dconf.location="$CARBON_HOME/repository/conf"\
+ -Dcom.atomikos.icatch.file="$CARBON_HOME/lib/transactions.properties" \
+ -Dcom.atomikos.icatch.hide_init_file_path=true \
+ -Dorg.apache.jasper.compiler.Parser.STRICT_QUOTE_ESCAPING=false \
+ -Dorg.apache.jasper.runtime.BodyContentImpl.LIMIT_BUFFER=true \
+ -Dcom.sun.jndi.ldap.connect.pool.authentication=simple \
+ -Dcom.sun.jndi.ldap.connect.pool.timeout=3000 \
+ -Dorg.terracotta.quartz.skipUpdateCheck=true \
+ -Djava.security.egd=file:/dev/./urandom \
+ -Dfile.encoding=UTF8 \
+ -Djava.net.preferIPv4Stack=true \
+ -Dcom.ibm.cacheLocalHost=true \
+ org.wso2.carbon.bootstrap.Bootstrap $*
+ status=$?
+done
diff --git a/modules/broker/features/pom.xml b/modules/broker/features/pom.xml
new file mode 100644
index 00000000..ae0a42fa
--- /dev/null
+++ b/modules/broker/features/pom.xml
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+ org.wso2.iot
+ wso2iot-broker-parent
+ 1.0.0-SNAPSHOT
+ ../pom.xml
+
+
+ 4.0.0
+ wso2iot-broker-features-parent
+ pom
+ WSO2 MB Features Parent
+ http://wso2.com/products/message-broker
+ WSO2 Message Broker Server Features Parent
+
+
+
+ Apache License Version 2.0
+ http://www.apache.org/licenses/LICENSE-2.0
+
+
+
+
+ product
+ service
+
+
diff --git a/modules/broker/features/product/feature.properties b/modules/broker/features/product/feature.properties
new file mode 100644
index 00000000..2bcfafeb
--- /dev/null
+++ b/modules/broker/features/product/feature.properties
@@ -0,0 +1,217 @@
+################################################################################
+# Copyright 2009 WSO2, Inc. (http://wso2.com)
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+################################################################################
+
+providerName=WSO2 Inc.
+
+########################## license properties ##################################
+licenseURL=http://www.apache.org/licenses/LICENSE-2.0
+
+license=\
+ Apache License\n\
+ Version 2.0, January 2004\n\
+ http://www.apache.org/licenses/\n\
+\n\
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\
+\n\
+ 1. Definitions.\n\
+\n\
+ "License" shall mean the terms and conditions for use, reproduction,\n\
+ and distribution as defined by Sections 1 through 9 of this document.\n\
+\n\
+ "Licensor" shall mean the copyright owner or entity authorized by\n\
+ the copyright owner that is granting the License.\n\
+\n\
+ "Legal Entity" shall mean the union of the acting entity and all\n\
+ other entities that control, are controlled by, or are under common\n\
+ control with that entity. For the purposes of this definition,\n\
+ "control" means (i) the power, direct or indirect, to cause the\n\
+ direction or management of such entity, whether by contract or\n\
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the\n\
+ outstanding shares, or (iii) beneficial ownership of such entity.\n\
+\n\
+ "You" (or "Your") shall mean an individual or Legal Entity\n\
+ exercising permissions granted by this License.\n\
+\n\
+ "Source" form shall mean the preferred form for making modifications,\n\
+ including but not limited to software source code, documentation\n\
+ source, and configuration files.\n\
+\n\
+ "Object" form shall mean any form resulting from mechanical\n\
+ transformation or translation of a Source form, including but\n\
+ not limited to compiled object code, generated documentation,\n\
+ and conversions to other media types.\n\
+\n\
+ "Work" shall mean the work of authorship, whether in Source or\n\
+ Object form, made available under the License, as indicated by a\n\
+ copyright notice that is included in or attached to the work\n\
+ (an example is provided in the Appendix below).\n\
+\n\
+ "Derivative Works" shall mean any work, whether in Source or Object\n\
+ form, that is based on (or derived from) the Work and for which the\n\
+ editorial revisions, annotations, elaborations, or other modifications\n\
+ represent, as a whole, an original work of authorship. For the purposes\n\
+ of this License, Derivative Works shall not include works that remain\n\
+ separable from, or merely link (or bind by name) to the interfaces of,\n\
+ the Work and Derivative Works thereof.\n\
+\n\
+ "Contribution" shall mean any work of authorship, including\n\
+ the original version of the Work and any modifications or additions\n\
+ to that Work or Derivative Works thereof, that is intentionally\n\
+ submitted to Licensor for inclusion in the Work by the copyright owner\n\
+ or by an individual or Legal Entity authorized to submit on behalf of\n\
+ the copyright owner. For the purposes of this definition, "submitted"\n\
+ means any form of electronic, verbal, or written communication sent\n\
+ to the Licensor or its representatives, including but not limited to\n\
+ communication on electronic mailing lists, source code control systems,\n\
+ and issue tracking systems that are managed by, or on behalf of, the\n\
+ Licensor for the purpose of discussing and improving the Work, but\n\
+ excluding communication that is conspicuously marked or otherwise\n\
+ designated in writing by the copyright owner as "Not a Contribution."\n\
+\n\
+ "Contributor" shall mean Licensor and any individual or Legal Entity\n\
+ on behalf of whom a Contribution has been received by Licensor and\n\
+ subsequently incorporated within the Work.\n\
+\n\
+ 2. Grant of Copyright License. Subject to the terms and conditions of\n\
+ this License, each Contributor hereby grants to You a perpetual,\n\
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n\
+ copyright license to reproduce, prepare Derivative Works of,\n\
+ publicly display, publicly perform, sublicense, and distribute the\n\
+ Work and such Derivative Works in Source or Object form.\n\
+\n\
+ 3. Grant of Patent License. Subject to the terms and conditions of\n\
+ this License, each Contributor hereby grants to You a perpetual,\n\
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n\
+ (except as stated in this section) patent license to make, have made,\n\
+ use, offer to sell, sell, import, and otherwise transfer the Work,\n\
+ where such license applies only to those patent claims licensable\n\
+ by such Contributor that are necessarily infringed by their\n\
+ Contribution(s) alone or by combination of their Contribution(s)\n\
+ with the Work to which such Contribution(s) was submitted. If You\n\
+ institute patent litigation against any entity (including a\n\
+ cross-claim or counterclaim in a lawsuit) alleging that the Work\n\
+ or a Contribution incorporated within the Work constitutes direct\n\
+ or contributory patent infringement, then any patent licenses\n\
+ granted to You under this License for that Work shall terminate\n\
+ as of the date such litigation is filed.\n\
+\n\
+ 4. Redistribution. You may reproduce and distribute copies of the\n\
+ Work or Derivative Works thereof in any medium, with or without\n\
+ modifications, and in Source or Object form, provided that You\n\
+ meet the following conditions:\n\
+\n\
+ (a) You must give any other recipients of the Work or\n\
+ Derivative Works a copy of this License; and\n\
+\n\
+ (b) You must cause any modified files to carry prominent notices\n\
+ stating that You changed the files; and\n\
+\n\
+ (c) You must retain, in the Source form of any Derivative Works\n\
+ that You distribute, all copyright, patent, trademark, and\n\
+ attribution notices from the Source form of the Work,\n\
+ excluding those notices that do not pertain to any part of\n\
+ the Derivative Works; and\n\
+\n\
+ (d) If the Work includes a "NOTICE" text file as part of its\n\
+ distribution, then any Derivative Works that You distribute must\n\
+ include a readable copy of the attribution notices contained\n\
+ within such NOTICE file, excluding those notices that do not\n\
+ pertain to any part of the Derivative Works, in at least one\n\
+ of the following places: within a NOTICE text file distributed\n\
+ as part of the Derivative Works; within the Source form or\n\
+ documentation, if provided along with the Derivative Works; or,\n\
+ within a display generated by the Derivative Works, if and\n\
+ wherever such third-party notices normally appear. The contents\n\
+ of the NOTICE file are for informational purposes only and\n\
+ do not modify the License. You may add Your own attribution\n\
+ notices within Derivative Works that You distribute, alongside\n\
+ or as an addendum to the NOTICE text from the Work, provided\n\
+ that such additional attribution notices cannot be construed\n\
+ as modifying the License.\n\
+\n\
+ You may add Your own copyright statement to Your modifications and\n\
+ may provide additional or different license terms and conditions\n\
+ for use, reproduction, or distribution of Your modifications, or\n\
+ for any such Derivative Works as a whole, provided Your use,\n\
+ reproduction, and distribution of the Work otherwise complies with\n\
+ the conditions stated in this License.\n\
+\n\
+ 5. Submission of Contributions. Unless You explicitly state otherwise,\n\
+ any Contribution intentionally submitted for inclusion in the Work\n\
+ by You to the Licensor shall be under the terms and conditions of\n\
+ this License, without any additional terms or conditions.\n\
+ Notwithstanding the above, nothing herein shall supersede or modify\n\
+ the terms of any separate license agreement you may have executed\n\
+ with Licensor regarding such Contributions.\n\
+\n\
+ 6. Trademarks. This License does not grant permission to use the trade\n\
+ names, trademarks, service marks, or product names of the Licensor,\n\
+ except as required for reasonable and customary use in describing the\n\
+ origin of the Work and reproducing the content of the NOTICE file.\n\
+\n\
+ 7. Disclaimer of Warranty. Unless required by applicable law or\n\
+ agreed to in writing, Licensor provides the Work (and each\n\
+ Contributor provides its Contributions) on an "AS IS" BASIS,\n\
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n\
+ implied, including, without limitation, any warranties or conditions\n\
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n\
+ PARTICULAR PURPOSE. You are solely responsible for determining the\n\
+ appropriateness of using or redistributing the Work and assume any\n\
+ risks associated with Your exercise of permissions under this License.\n\
+\n\
+ 8. Limitation of Liability. In no event and under no legal theory,\n\
+ whether in tort (including negligence), contract, or otherwise,\n\
+ unless required by applicable law (such as deliberate and grossly\n\
+ negligent acts) or agreed to in writing, shall any Contributor be\n\
+ liable to You for damages, including any direct, indirect, special,\n\
+ incidental, or consequential damages of any character arising as a\n\
+ result of this License or out of the use or inability to use the\n\
+ Work (including but not limited to damages for loss of goodwill,\n\
+ work stoppage, computer failure or malfunction, or any and all\n\
+ other commercial damages or losses), even if such Contributor\n\
+ has been advised of the possibility of such damages.\n\
+\n\
+ 9. Accepting Warranty or Additional Liability. While redistributing\n\
+ the Work or Derivative Works thereof, You may choose to offer,\n\
+ and charge a fee for, acceptance of support, warranty, indemnity,\n\
+ or other liability obligations and/or rights consistent with this\n\
+ License. However, in accepting such obligations, You may act only\n\
+ on Your own behalf and on Your sole responsibility, not on behalf\n\
+ of any other Contributor, and only if You agree to indemnify,\n\
+ defend, and hold each Contributor harmless for any liability\n\
+ incurred by, or claims asserted against, such Contributor by reason\n\
+ of your accepting any such warranty or additional liability.\n\
+\n\
+ END OF TERMS AND CONDITIONS\n
+
+######################### copyright properties #################################
+copyrightURL=TODO
+
+copyright=\
+Copyright 2012 WSO2, Inc. (http://wso2.com)\n\
+\n\
+Licensed under the Apache License, Version 2.0 (the "License");\n\
+you may not use this file except in compliance with the License.\n\
+You may obtain a copy of the License at\n\
+\n\
+http://www.apache.org/licenses/LICENSE-2.0\n\
+\n\
+Unless required by applicable law or agreed to in writing, software\n\
+distributed under the License is distributed on an "AS IS" BASIS,\n\
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n\
+See the License for the specific language governing permissions and\n\
+limitations under the License.\n
+
diff --git a/modules/broker/features/product/org.wso2.iot.broker.styles.feature/pom.xml b/modules/broker/features/product/org.wso2.iot.broker.styles.feature/pom.xml
new file mode 100644
index 00000000..c8b89c91
--- /dev/null
+++ b/modules/broker/features/product/org.wso2.iot.broker.styles.feature/pom.xml
@@ -0,0 +1,79 @@
+
+
+
+
+
+
+ org.wso2.iot
+ wso2iot-broker-product-features
+ 1.0.0-SNAPSHOT
+ ../pom.xml
+
+
+ 4.0.0
+ org.wso2.iot.broker.styles.feature
+ pom
+ WSO2 MB - Styles Features
+ http://wso2.org
+
+
+
+ org.wso2.iot
+ org.wso2.iot.broker.styles
+
+
+
+
+
+
+ org.wso2.maven
+ carbon-p2-plugin
+ ${carbon.p2.plugin.version}
+
+
+ p2-feature-generation
+ package
+
+ p2-feature-gen
+
+
+ org.wso2.iot.broker.styles
+ ../feature.properties
+
+
+ org.wso2.carbon.p2.category.type:console
+
+ org.eclipse.equinox.p2.type.group:false
+
+
+
+
+ org.wso2.iot:org.wso2.iot.broker.styles
+
+
+ org.wso2.carbon.core.ui:${carbon.kernel.version}
+
+
+
+
+
+
+
+
+
diff --git a/modules/broker/features/product/pom.xml b/modules/broker/features/product/pom.xml
new file mode 100644
index 00000000..3b1f2873
--- /dev/null
+++ b/modules/broker/features/product/pom.xml
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+ org.wso2.iot
+ wso2iot-broker-features-parent
+ 1.0.0-SNAPSHOT
+ ../pom.xml
+
+
+ 4.0.0
+ wso2iot-broker-product-features
+ pom
+ WSO2 MB Features Aggregator Module
+ Features specific to the WSO2 MB
+
+
+ org.wso2.iot.broker.styles.feature
+
+
+
diff --git a/modules/broker/features/service/etc/feature.properties b/modules/broker/features/service/etc/feature.properties
new file mode 100644
index 00000000..2bcfafeb
--- /dev/null
+++ b/modules/broker/features/service/etc/feature.properties
@@ -0,0 +1,217 @@
+################################################################################
+# Copyright 2009 WSO2, Inc. (http://wso2.com)
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+################################################################################
+
+providerName=WSO2 Inc.
+
+########################## license properties ##################################
+licenseURL=http://www.apache.org/licenses/LICENSE-2.0
+
+license=\
+ Apache License\n\
+ Version 2.0, January 2004\n\
+ http://www.apache.org/licenses/\n\
+\n\
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\
+\n\
+ 1. Definitions.\n\
+\n\
+ "License" shall mean the terms and conditions for use, reproduction,\n\
+ and distribution as defined by Sections 1 through 9 of this document.\n\
+\n\
+ "Licensor" shall mean the copyright owner or entity authorized by\n\
+ the copyright owner that is granting the License.\n\
+\n\
+ "Legal Entity" shall mean the union of the acting entity and all\n\
+ other entities that control, are controlled by, or are under common\n\
+ control with that entity. For the purposes of this definition,\n\
+ "control" means (i) the power, direct or indirect, to cause the\n\
+ direction or management of such entity, whether by contract or\n\
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the\n\
+ outstanding shares, or (iii) beneficial ownership of such entity.\n\
+\n\
+ "You" (or "Your") shall mean an individual or Legal Entity\n\
+ exercising permissions granted by this License.\n\
+\n\
+ "Source" form shall mean the preferred form for making modifications,\n\
+ including but not limited to software source code, documentation\n\
+ source, and configuration files.\n\
+\n\
+ "Object" form shall mean any form resulting from mechanical\n\
+ transformation or translation of a Source form, including but\n\
+ not limited to compiled object code, generated documentation,\n\
+ and conversions to other media types.\n\
+\n\
+ "Work" shall mean the work of authorship, whether in Source or\n\
+ Object form, made available under the License, as indicated by a\n\
+ copyright notice that is included in or attached to the work\n\
+ (an example is provided in the Appendix below).\n\
+\n\
+ "Derivative Works" shall mean any work, whether in Source or Object\n\
+ form, that is based on (or derived from) the Work and for which the\n\
+ editorial revisions, annotations, elaborations, or other modifications\n\
+ represent, as a whole, an original work of authorship. For the purposes\n\
+ of this License, Derivative Works shall not include works that remain\n\
+ separable from, or merely link (or bind by name) to the interfaces of,\n\
+ the Work and Derivative Works thereof.\n\
+\n\
+ "Contribution" shall mean any work of authorship, including\n\
+ the original version of the Work and any modifications or additions\n\
+ to that Work or Derivative Works thereof, that is intentionally\n\
+ submitted to Licensor for inclusion in the Work by the copyright owner\n\
+ or by an individual or Legal Entity authorized to submit on behalf of\n\
+ the copyright owner. For the purposes of this definition, "submitted"\n\
+ means any form of electronic, verbal, or written communication sent\n\
+ to the Licensor or its representatives, including but not limited to\n\
+ communication on electronic mailing lists, source code control systems,\n\
+ and issue tracking systems that are managed by, or on behalf of, the\n\
+ Licensor for the purpose of discussing and improving the Work, but\n\
+ excluding communication that is conspicuously marked or otherwise\n\
+ designated in writing by the copyright owner as "Not a Contribution."\n\
+\n\
+ "Contributor" shall mean Licensor and any individual or Legal Entity\n\
+ on behalf of whom a Contribution has been received by Licensor and\n\
+ subsequently incorporated within the Work.\n\
+\n\
+ 2. Grant of Copyright License. Subject to the terms and conditions of\n\
+ this License, each Contributor hereby grants to You a perpetual,\n\
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n\
+ copyright license to reproduce, prepare Derivative Works of,\n\
+ publicly display, publicly perform, sublicense, and distribute the\n\
+ Work and such Derivative Works in Source or Object form.\n\
+\n\
+ 3. Grant of Patent License. Subject to the terms and conditions of\n\
+ this License, each Contributor hereby grants to You a perpetual,\n\
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n\
+ (except as stated in this section) patent license to make, have made,\n\
+ use, offer to sell, sell, import, and otherwise transfer the Work,\n\
+ where such license applies only to those patent claims licensable\n\
+ by such Contributor that are necessarily infringed by their\n\
+ Contribution(s) alone or by combination of their Contribution(s)\n\
+ with the Work to which such Contribution(s) was submitted. If You\n\
+ institute patent litigation against any entity (including a\n\
+ cross-claim or counterclaim in a lawsuit) alleging that the Work\n\
+ or a Contribution incorporated within the Work constitutes direct\n\
+ or contributory patent infringement, then any patent licenses\n\
+ granted to You under this License for that Work shall terminate\n\
+ as of the date such litigation is filed.\n\
+\n\
+ 4. Redistribution. You may reproduce and distribute copies of the\n\
+ Work or Derivative Works thereof in any medium, with or without\n\
+ modifications, and in Source or Object form, provided that You\n\
+ meet the following conditions:\n\
+\n\
+ (a) You must give any other recipients of the Work or\n\
+ Derivative Works a copy of this License; and\n\
+\n\
+ (b) You must cause any modified files to carry prominent notices\n\
+ stating that You changed the files; and\n\
+\n\
+ (c) You must retain, in the Source form of any Derivative Works\n\
+ that You distribute, all copyright, patent, trademark, and\n\
+ attribution notices from the Source form of the Work,\n\
+ excluding those notices that do not pertain to any part of\n\
+ the Derivative Works; and\n\
+\n\
+ (d) If the Work includes a "NOTICE" text file as part of its\n\
+ distribution, then any Derivative Works that You distribute must\n\
+ include a readable copy of the attribution notices contained\n\
+ within such NOTICE file, excluding those notices that do not\n\
+ pertain to any part of the Derivative Works, in at least one\n\
+ of the following places: within a NOTICE text file distributed\n\
+ as part of the Derivative Works; within the Source form or\n\
+ documentation, if provided along with the Derivative Works; or,\n\
+ within a display generated by the Derivative Works, if and\n\
+ wherever such third-party notices normally appear. The contents\n\
+ of the NOTICE file are for informational purposes only and\n\
+ do not modify the License. You may add Your own attribution\n\
+ notices within Derivative Works that You distribute, alongside\n\
+ or as an addendum to the NOTICE text from the Work, provided\n\
+ that such additional attribution notices cannot be construed\n\
+ as modifying the License.\n\
+\n\
+ You may add Your own copyright statement to Your modifications and\n\
+ may provide additional or different license terms and conditions\n\
+ for use, reproduction, or distribution of Your modifications, or\n\
+ for any such Derivative Works as a whole, provided Your use,\n\
+ reproduction, and distribution of the Work otherwise complies with\n\
+ the conditions stated in this License.\n\
+\n\
+ 5. Submission of Contributions. Unless You explicitly state otherwise,\n\
+ any Contribution intentionally submitted for inclusion in the Work\n\
+ by You to the Licensor shall be under the terms and conditions of\n\
+ this License, without any additional terms or conditions.\n\
+ Notwithstanding the above, nothing herein shall supersede or modify\n\
+ the terms of any separate license agreement you may have executed\n\
+ with Licensor regarding such Contributions.\n\
+\n\
+ 6. Trademarks. This License does not grant permission to use the trade\n\
+ names, trademarks, service marks, or product names of the Licensor,\n\
+ except as required for reasonable and customary use in describing the\n\
+ origin of the Work and reproducing the content of the NOTICE file.\n\
+\n\
+ 7. Disclaimer of Warranty. Unless required by applicable law or\n\
+ agreed to in writing, Licensor provides the Work (and each\n\
+ Contributor provides its Contributions) on an "AS IS" BASIS,\n\
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n\
+ implied, including, without limitation, any warranties or conditions\n\
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n\
+ PARTICULAR PURPOSE. You are solely responsible for determining the\n\
+ appropriateness of using or redistributing the Work and assume any\n\
+ risks associated with Your exercise of permissions under this License.\n\
+\n\
+ 8. Limitation of Liability. In no event and under no legal theory,\n\
+ whether in tort (including negligence), contract, or otherwise,\n\
+ unless required by applicable law (such as deliberate and grossly\n\
+ negligent acts) or agreed to in writing, shall any Contributor be\n\
+ liable to You for damages, including any direct, indirect, special,\n\
+ incidental, or consequential damages of any character arising as a\n\
+ result of this License or out of the use or inability to use the\n\
+ Work (including but not limited to damages for loss of goodwill,\n\
+ work stoppage, computer failure or malfunction, or any and all\n\
+ other commercial damages or losses), even if such Contributor\n\
+ has been advised of the possibility of such damages.\n\
+\n\
+ 9. Accepting Warranty or Additional Liability. While redistributing\n\
+ the Work or Derivative Works thereof, You may choose to offer,\n\
+ and charge a fee for, acceptance of support, warranty, indemnity,\n\
+ or other liability obligations and/or rights consistent with this\n\
+ License. However, in accepting such obligations, You may act only\n\
+ on Your own behalf and on Your sole responsibility, not on behalf\n\
+ of any other Contributor, and only if You agree to indemnify,\n\
+ defend, and hold each Contributor harmless for any liability\n\
+ incurred by, or claims asserted against, such Contributor by reason\n\
+ of your accepting any such warranty or additional liability.\n\
+\n\
+ END OF TERMS AND CONDITIONS\n
+
+######################### copyright properties #################################
+copyrightURL=TODO
+
+copyright=\
+Copyright 2012 WSO2, Inc. (http://wso2.com)\n\
+\n\
+Licensed under the Apache License, Version 2.0 (the "License");\n\
+you may not use this file except in compliance with the License.\n\
+You may obtain a copy of the License at\n\
+\n\
+http://www.apache.org/licenses/LICENSE-2.0\n\
+\n\
+Unless required by applicable law or agreed to in writing, software\n\
+distributed under the License is distributed on an "AS IS" BASIS,\n\
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n\
+See the License for the specific language governing permissions and\n\
+limitations under the License.\n
+
diff --git a/modules/broker/features/service/org.wso2.stratos.mb.dashboard.ui.feature/pom.xml b/modules/broker/features/service/org.wso2.stratos.mb.dashboard.ui.feature/pom.xml
new file mode 100644
index 00000000..c4caf7f9
--- /dev/null
+++ b/modules/broker/features/service/org.wso2.stratos.mb.dashboard.ui.feature/pom.xml
@@ -0,0 +1,82 @@
+
+
+
+
+ org.wso2.iot
+ wso2stratos-mb-features
+ 1.0.0-SNAPSHOT
+ ../pom.xml
+
+
+ 4.0.0
+ org.wso2.stratos.mb.dashboard.ui.feature
+ pom
+ WSO2 Stratos Message Broker - Dashboard UI Features
+ http://wso2.org
+
+
+
+ org.wso2.iot
+ org.wso2.stratos.mb.dashboard.ui
+
+
+ org.wso2.carbon
+ org.wso2.carbon.ui.menu.stratos
+
+
+
+
+
+
+ org.wso2.maven
+ carbon-p2-plugin
+ ${carbon.p2.plugin.version}
+
+
+ p2-feature-generation
+ package
+
+ p2-feature-gen
+
+
+ org.wso2.stratos.mb.dashboard.ui
+ ../etc/feature.properties
+
+
+ org.wso2.carbon.p2.category.type:console
+
+
+
+
+ org.wso2.iot:org.wso2.stratos.mb.dashboard.ui
+ org.wso2.carbon:org.wso2.carbon.ui.menu.stratos
+
+
+
+ org.wso2.carbon.core.ui:${carbon.kernel.version}
+
+
+
+
+
+
+
+
+
+
diff --git a/modules/broker/features/service/org.wso2.stratos.mb.login.ui.feature/pom.xml b/modules/broker/features/service/org.wso2.stratos.mb.login.ui.feature/pom.xml
new file mode 100644
index 00000000..1e5f0c42
--- /dev/null
+++ b/modules/broker/features/service/org.wso2.stratos.mb.login.ui.feature/pom.xml
@@ -0,0 +1,71 @@
+
+
+
+
+ org.wso2.iot
+ wso2stratos-mb-features
+ 1.0.0-SNAPSHOT
+ ../pom.xml
+
+
+ 4.0.0
+ org.wso2.stratos.mb.login.ui.feature
+ pom
+ WSO2 Stratos Message Broker - Deployment Features
+ http://wso2.org
+
+
+
+ org.wso2.iot
+ org.wso2.stratos.mb.login.ui
+
+
+
+
+
+
+ org.wso2.maven
+ carbon-p2-plugin
+ ${carbon.p2.plugin.version}
+
+
+ p2-feature-generation
+ package
+
+ p2-feature-gen
+
+
+ org.wso2.stratos.mb.login.ui
+ ../etc/feature.properties
+
+
+ org.wso2.carbon.p2.category.type:console
+
+
+
+ org.wso2.iot:org.wso2.stratos.mb.login.ui
+
+
+
+
+
+
+
+
+
diff --git a/modules/broker/features/service/pom.xml b/modules/broker/features/service/pom.xml
new file mode 100644
index 00000000..97212cc6
--- /dev/null
+++ b/modules/broker/features/service/pom.xml
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+ org.wso2.iot
+ wso2iot-broker-features-parent
+ 1.0.0-SNAPSHOT
+ ../pom.xml
+
+
+ 4.0.0
+ wso2stratos-mb-features
+ pom
+ WSO2 Stratos Message Broker - Features Aggregator Module
+ Features specific to the WSO2 Message Broker
+
+
+ org.wso2.stratos.mb.login.ui.feature
+ org.wso2.stratos.mb.dashboard.ui.feature
+
+
+
diff --git a/modules/broker/integration/pom.xml b/modules/broker/integration/pom.xml
new file mode 100644
index 00000000..9f74b322
--- /dev/null
+++ b/modules/broker/integration/pom.xml
@@ -0,0 +1,72 @@
+
+
+
+
+
+
+ org.wso2.iot
+ wso2iot-broker-parent
+ 1.0.0-SNAPSHOT
+ ../pom.xml
+
+
+ 4.0.0
+ wso2iot-broker-integration-tests
+ pom
+ WSO2 MB - Integration Tests
+ http://wso2.com/products/message-broker/
+ WSO2 Message Broker Server Parent
+
+
+ tests-common/admin-clients
+ tests-common/integration-tests-utils
+ tests-common/platform-tests-utils
+ tests-integration
+ tests-ui-integration
+ tests-platform
+
+
+
+
+ org.testng
+ testng
+
+
+ commons-logging
+ commons-logging
+
+
+ org.wso2.andes.wso2
+ andes
+
+
+ org.wso2.andes.wso2
+ andes-client
+
+
+ org.wso2.carbon.messaging
+ org.wso2.carbon.andes.event.stub
+
+
+ org.wso2.carbon.messaging
+ org.wso2.carbon.andes.stub
+
+
+
+
diff --git a/modules/broker/integration/tests-common/admin-clients/pom.xml b/modules/broker/integration/tests-common/admin-clients/pom.xml
new file mode 100644
index 00000000..28b136fc
--- /dev/null
+++ b/modules/broker/integration/tests-common/admin-clients/pom.xml
@@ -0,0 +1,45 @@
+
+
+
+
+ org.wso2.iot
+ wso2iot-broker-integration-tests
+ 1.0.0-SNAPSHOT
+ ../../pom.xml
+
+
+ 4.0.0
+ WSO2 MB - Integration Test Common Module
+ org.wso2.iot.broker.integration.common.clients
+ jar
+
+
+
+ org.wso2.carbon.automation
+ org.wso2.carbon.automation.engine
+ compile
+
+
+ org.wso2.carbon
+ org.wso2.carbon.utils
+ compile
+
+
+ org.apache.geronimo.specs.wso2
+ geronimo-jms_1.1_spec
+
+
+ org.eclipse.paho
+ org.eclipse.paho.client.mqttv3
+
+
+ commons-configuration
+ commons-configuration
+ compile
+
+
+ org.apache.commons
+ commons-lang3
+
+
+
diff --git a/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/AndesClient.java b/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/AndesClient.java
new file mode 100644
index 00000000..fe5d617d
--- /dev/null
+++ b/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/AndesClient.java
@@ -0,0 +1,352 @@
+/*
+* Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+*
+* WSO2 Inc. licenses this file to you under the Apache License,
+* Version 2.0 (the "License"); you may not use this file except
+* in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT 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.wso2.mb.integration.common.clients;
+
+
+import org.apache.log4j.Logger;
+import org.wso2.mb.integration.common.clients.configurations.AndesJMSClientConfiguration;
+import org.wso2.mb.integration.common.clients.configurations.AndesJMSConsumerClientConfiguration;
+import org.wso2.mb.integration.common.clients.configurations.AndesJMSPublisherClientConfiguration;
+import org.wso2.mb.integration.common.clients.exceptions.AndesClientException;
+import org.wso2.mb.integration.common.clients.operations.utils.AndesClientOutputParser;
+import org.wso2.mb.integration.common.clients.operations.utils.AndesClientUtils;
+
+import javax.jms.JMSException;
+import javax.naming.NamingException;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * This class represents the Andes Client which is used to publish/consume JMS messages. The JMS
+ * publishers and consumers are created within this class with the help of a configuration file.
+ * This class also provides functionality which can be used to evaluate JMS message publishers and
+ * consumers.
+ */
+public class AndesClient {
+ /**
+ * The logger used to log information, warnings, errors, etc.
+ */
+ private static Logger log = Logger.getLogger(AndesClient.class);
+
+ /**
+ * The delay between starting publishers or consumers
+ */
+ private long startDelay = 0L;
+
+ /**
+ * The consumers that are started concurrently
+ */
+ List consumers = new ArrayList<>();
+
+ /**
+ * The publishers that are started concurrently
+ */
+ List publishers = new ArrayList<>();
+
+ /**
+ * Creates a single consumer or publisher based on the configuration passed
+ *
+ * @param config The configuration.
+ * @param createConsumersAndProducers True if the client needs to create connections, sessions
+ * and respecting receivers or consumers. False otherwise.
+ * @throws JMSException Thrown when creating the JMS sessions, connection and receiver
+ * or sender based on consumer or producer.
+ * @throws NamingException Thrown when invalid lookup is used in the initial context.
+ */
+ public AndesClient(AndesJMSClientConfiguration config, boolean createConsumersAndProducers)
+ throws NamingException, JMSException, AndesClientException, IOException {
+ this(config, 1, createConsumersAndProducers);
+ }
+
+ /**
+ * The constructor used for creating multiple consumer or publishers based on the configuration
+ * passed.
+ *
+ * @param config The configuration.
+ * @param numberOfThreads The amount of publishers or consumers. This amount of
+ * threads will be started.
+ * @param createConsumersAndProducers True if the client needs to create connections, sessions
+ * and respective receivers or consumers. False otherwise.
+ * @throws JMSException Thrown when creating the JMS sessions, connection and receiver
+ * or sender based on consumer or producer.
+ * @throws NamingException Thrown when invalid lookup is used in the initial context.
+ * @throws AndesClientException Thrown when invalid number of threads are used.
+ */
+ public AndesClient(AndesJMSClientConfiguration config, int numberOfThreads,
+ boolean createConsumersAndProducers)
+ throws IOException, JMSException, NamingException, AndesClientException {
+ if (0 < numberOfThreads) {
+ if (config instanceof AndesJMSConsumerClientConfiguration) {
+ AndesClientUtils.initializeReceivedMessagesPrintWriter(((AndesJMSConsumerClientConfiguration) config)
+ .getFilePathToWriteReceivedMessages());
+ }
+
+ if (config instanceof AndesJMSPublisherClientConfiguration) {
+ AndesClientUtils.initializePublishedPrintWriter(((AndesJMSPublisherClientConfiguration) config).getFilePathToWritePublishedMessages());
+ }
+
+ for (int i = 0; i < numberOfThreads; i++) {
+ if (config instanceof AndesJMSConsumerClientConfiguration) {
+ consumers
+ .add(new AndesJMSConsumer((AndesJMSConsumerClientConfiguration) config, createConsumersAndProducers));
+ } else if (config instanceof AndesJMSPublisherClientConfiguration) {
+ publishers
+ .add(new AndesJMSPublisher((AndesJMSPublisherClientConfiguration) config, createConsumersAndProducers));
+ }
+ }
+ } else {
+ throw new AndesClientException("The amount of subscribers cannot be less than 1. " +
+ "Value entered is " + Integer.toString(numberOfThreads));
+ }
+ }
+
+ /**
+ * Starts up the consumer(s) or publisher(s) to consume or publish messages.
+ *
+ * @throws JMSException Thrown when broker does not adhere to JMS functions.
+ * @throws IOException Thrown when trying to read contents from a file.
+ */
+ public void startClient() throws AndesClientException, JMSException, IOException {
+ boolean isStartDelaySet = this.startDelay > 0L;
+ for (AndesJMSConsumer consumer : consumers) {
+ consumer.startClient();
+ if (isStartDelaySet) {
+ AndesClientUtils.sleepForInterval(this.startDelay);
+ }
+ }
+ for (AndesJMSPublisher publisher : publishers) {
+ publisher.startClient();
+ if (isStartDelaySet) {
+ AndesClientUtils.sleepForInterval(this.startDelay);
+ }
+ }
+ }
+
+ /**
+ * Stops the client from publishing or consuming messages.
+ *
+ * @throws JMSException Thrown when closing the connections, session and receiver or sender
+ * based on a consumer and a publisher.
+ */
+ public void stopClient() throws JMSException {
+ for (AndesJMSConsumer consumer : consumers) {
+ consumer.stopClient();
+ }
+ for (AndesJMSPublisher publisher : publishers) {
+ publisher.stopClient();
+ }
+
+ log.info("TPS:" + this.getConsumerTPS() + " AverageLatency:" + this.getAverageLatency());
+ }
+
+ /**
+ * Gets the received messages for all consumers in the client.
+ *
+ * @return The total number of messages received for all consumers.
+ */
+ public long getReceivedMessageCount() {
+ long allReceivedMessageCount = 0L;
+ for (AndesJMSConsumer consumer : consumers) {
+ allReceivedMessageCount = allReceivedMessageCount + consumer.getReceivedMessageCount().get();
+ }
+ return allReceivedMessageCount;
+ }
+
+ /**
+ * Gets the average transactions per second for consumer(s).
+ *
+ * @return The average TPS.
+ */
+ public double getConsumerTPS() {
+ double tps = 0L;
+ for (AndesJMSConsumer consumer : consumers) {
+ tps = tps + consumer.getConsumerTPS();
+ }
+ return tps / consumers.size();
+ }
+
+ /**
+ * Gets the average latency for consumer(s).
+ *
+ * @return The average latency.
+ */
+ public double getAverageLatency() {
+ double averageLatency = 0L;
+ for (AndesJMSConsumer consumer : consumers) {
+ averageLatency = averageLatency + consumer.getAverageLatency();
+ }
+ return averageLatency / consumers.size();
+ }
+
+ /**
+ * Gets the number of messages sent by the publisher(s).
+ *
+ * @return The number of messages.
+ */
+ public long getSentMessageCount() {
+ long allSentMessageCount = 0L;
+ for (AndesJMSPublisher publisher : publishers) {
+ allSentMessageCount = allSentMessageCount + publisher.getSentMessageCount();
+ }
+ return allSentMessageCount;
+ }
+
+ /**
+ * Gets the average transactions per seconds for publisher(s). Suppressing "UnusedDeclaration"
+ * as the client acts as an service.
+ * Suppressing "UnusedDeclaration" as currently it is not being used within product-mb test
+ * cases. But the client can be exported so that any other use can use the client for publishing
+ * and subscribing messages.
+ *
+ * @return the average transactions per seconds.
+ */
+ @SuppressWarnings("UnusedDeclaration")
+ public double getPublisherTPS() {
+ double tps = 0L;
+ for (AndesJMSPublisher publisher : publishers) {
+ tps = tps + publisher.getPublisherTPS();
+ }
+ return tps / publishers.size();
+ }
+
+ /**
+ * Gets the duplicated messages received for a single consumer. This is not valid when is comes
+ * to multiple consumers.
+ *
+ * @return A map of message identifiers and message content.
+ * @throws IOException Thrown when the received messages file is either missing or corrupted.
+ */
+ public Map checkIfMessagesAreDuplicated()
+ throws IOException {
+ if (!consumers.isEmpty()) {
+ AndesClientUtils.flushPrintWriters();
+ AndesClientOutputParser andesClientOutputParser =
+ new AndesClientOutputParser(consumers.get(0).getConfig()
+ .getFilePathToWriteReceivedMessages());
+ return andesClientOutputParser.getDuplicatedMessages();
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Checks whether the received messages are in order for a single consumer. This is not valid
+ * when is comes to multiple consumers.
+ *
+ * @return true if messages are in order, false otherwise.
+ * @throws IOException Thrown when the received messages file is either missing or corrupted.
+ */
+ public boolean checkIfMessagesAreInOrder()
+ throws IOException {
+ if (!consumers.isEmpty()) {
+ AndesClientOutputParser andesClientOutputParser =
+ new AndesClientOutputParser(consumers.get(0).getConfig()
+ .getFilePathToWriteReceivedMessages());
+ return andesClientOutputParser.checkIfMessagesAreInOrder();
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * This method returns whether received messages are transacted for a single consumer. This is
+ * not valid when is comes to multiple consumers.
+ *
+ * @param operationOccurredIndex Index of the operated message most of the time last message.
+ * @return true if all messages are transacted, false otherwise.
+ */
+ public boolean transactedOperation(long operationOccurredIndex)
+ throws IOException {
+ if (0 < consumers.size()) {
+ AndesClientOutputParser andesClientOutputParser =
+ new AndesClientOutputParser(consumers.get(0).getConfig()
+ .getFilePathToWriteReceivedMessages());
+ return andesClientOutputParser.transactedOperations(operationOccurredIndex);
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * This method will check whether received messages are ordered correctly for a single consumer
+ * when rollback. This is not valid when there are multiple consumers.
+ *
+ * @param messagesPerRollback number of messages per each rollback occurrence by subscriber.
+ * @return true if all messages are received in correct order after each rollback,
+ * false otherwise.
+ */
+ public boolean checkIfTransactedRollbackPreservesOrder(long messagesPerRollback)
+ throws IOException {
+ if (0 < consumers.size()) {
+ AndesClientOutputParser andesClientOutputParser =
+ new AndesClientOutputParser(consumers.get(0).getConfig()
+ .getFilePathToWriteReceivedMessages());
+ return andesClientOutputParser.checkIfTransactedRollbackPreservesOrder(messagesPerRollback);
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * This method returns number of duplicate received messages for a single consumer. This is not
+ * valid when is comes to multiple consumers.
+ *
+ * @return The duplicate message count.
+ */
+ public long getTotalNumberOfDuplicates()
+ throws IOException {
+ if (0 < consumers.size()) {
+ AndesClientOutputParser andesClientOutputParser =
+ new AndesClientOutputParser(consumers.get(0).getConfig()
+ .getFilePathToWriteReceivedMessages());
+ return andesClientOutputParser.numberDuplicatedMessages();
+ } else {
+ return -1L;
+ }
+ }
+
+ /**
+ * Sets the starting delay when starting publishers or consumers.
+ *
+ * @param startDelay The starting delay
+ */
+ public void setStartDelay(long startDelay) {
+ this.startDelay = startDelay;
+ }
+
+ /**
+ * Gets the all the consumers created by the client.
+ * @return A {@link java.util.List} of
+ * {@link org.wso2.mb.integration.common.clients.AndesJMSConsumer}.
+ */
+ public List getConsumers() {
+ return consumers;
+ }
+
+ /**
+ * Gets the all the publisher created by the client.
+ * @return A {@link java.util.List} of
+ * {@link org.wso2.mb.integration.common.clients.AndesJMSPublisher}.
+ */
+ public List getPublishers() {
+ return publishers;
+ }
+}
diff --git a/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/AndesJMSBase.java b/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/AndesJMSBase.java
new file mode 100644
index 00000000..5b541fd4
--- /dev/null
+++ b/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/AndesJMSBase.java
@@ -0,0 +1,95 @@
+/*
+* Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+*
+* WSO2 Inc. licenses this file to you under the Apache License,
+* Version 2.0 (the "License"); you may not use this file except
+* in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT 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.wso2.mb.integration.common.clients;
+
+import org.wso2.mb.integration.common.clients.configurations.AndesJMSClientConfiguration;
+import org.wso2.mb.integration.common.clients.exceptions.AndesClientException;
+import org.wso2.mb.integration.common.clients.operations.utils.AndesClientConstants;
+
+import javax.jms.JMSException;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+import java.io.IOException;
+import java.util.Properties;
+
+/**
+ * The base class for JMS publishers and consumers. This class creates the initial context which
+ * is required in creating the publishers and consumers.
+ */
+public abstract class AndesJMSBase {
+ /**
+ * The configuration file used in creating the JMS publishers and consumers.
+ */
+ protected final AndesJMSClientConfiguration jmsConfig;
+
+ /**
+ * The initial context used for creating the publishers and consumers.
+ */
+ private InitialContext initialContext;
+
+ /**
+ * Creates the initial context.
+ *
+ * @param config The configuration.
+ * @throws NamingException
+ */
+ protected AndesJMSBase(AndesJMSClientConfiguration config) throws NamingException {
+ this.jmsConfig = config;
+
+ Properties properties = new Properties();
+ properties.put(Context.INITIAL_CONTEXT_FACTORY, AndesClientConstants.ANDES_ICF);
+ properties.put(AndesClientConstants.CF_NAME_PREFIX + AndesClientConstants.CF_NAME, jmsConfig.getConnectionString());
+ properties.put(jmsConfig.getExchangeType().getType() + "." + jmsConfig.getDestinationName(), jmsConfig.getDestinationName());
+
+ initialContext = new InitialContext(properties);
+ }
+
+ /**
+ * Gets the initial context.
+ *
+ * @return The initial context.
+ */
+ public InitialContext getInitialContext() {
+ return initialContext;
+ }
+
+ /**
+ * Starts up the publisher or consumer.
+ *
+ * @throws JMSException
+ * @throws NamingException
+ * @throws IOException
+ */
+ public abstract void startClient()
+ throws JMSException, NamingException, IOException, AndesClientException;
+
+ /**
+ * Stops the publisher or consumer
+ *
+ * @throws JMSException
+ */
+ public abstract void stopClient() throws JMSException, AndesClientException;
+
+ /**
+ * Gets the configuration.
+ *
+ * @return The configuration.
+ */
+ public abstract AndesJMSClientConfiguration getConfig();
+}
diff --git a/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/AndesJMSConsumer.java b/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/AndesJMSConsumer.java
new file mode 100644
index 00000000..6ccec430
--- /dev/null
+++ b/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/AndesJMSConsumer.java
@@ -0,0 +1,635 @@
+/*
+* Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+*
+* WSO2 Inc. licenses this file to you under the Apache License,
+* Version 2.0 (the "License"); you may not use this file except
+* in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT 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.wso2.mb.integration.common.clients;
+
+import org.apache.log4j.Logger;
+import org.wso2.mb.integration.common.clients.configurations.AndesJMSConsumerClientConfiguration;
+import org.wso2.mb.integration.common.clients.exceptions.AndesClientException;
+import org.wso2.mb.integration.common.clients.operations.utils.AndesClientConstants;
+import org.wso2.mb.integration.common.clients.operations.utils.AndesClientUtils;
+import org.wso2.mb.integration.common.clients.operations.utils.ExchangeType;
+import org.wso2.mb.integration.common.clients.operations.utils.JMSDeliveryStatus;
+
+import javax.jms.Connection;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageListener;
+import javax.jms.Queue;
+import javax.jms.QueueConnection;
+import javax.jms.QueueConnectionFactory;
+import javax.jms.QueueReceiver;
+import javax.jms.QueueSession;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.jms.Topic;
+import javax.jms.TopicConnection;
+import javax.jms.TopicConnectionFactory;
+import javax.jms.TopicSession;
+import javax.jms.TopicSubscriber;
+import javax.naming.NamingException;
+import java.io.IOException;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * The JMS message consumer used for creating a consumer, reading messages synchronously and also
+ * asynchronously.
+ */
+public class AndesJMSConsumer extends AndesJMSBase
+ implements Runnable, MessageListener {
+ /**
+ * The logger used in logging information, warnings, errors and etc.
+ */
+ private static Logger log = Logger.getLogger(AndesJMSConsumer.class);
+
+ /**
+ * The configuration for the consumer
+ */
+ private final AndesJMSConsumerClientConfiguration consumerConfig;
+
+ /**
+ * Timestamp for the first message consumed
+ */
+ private long firstMessageConsumedTimestamp;
+
+ /**
+ * Timestamp of the last message consumes
+ */
+ private long lastMessageConsumedTimestamp;
+
+ /**
+ * The amount of messages received by the the consumer
+ */
+ private AtomicLong receivedMessageCount;
+
+ /**
+ * The addition of the time differences between the timestamp at which it got published and the
+ * timestamp at which it got consumed for each message consumed.
+ */
+ private long totalLatency;
+
+ /**
+ * The JMS connection used to create the JMS sessions
+ */
+ private Connection connection;
+
+ /**
+ * The JMS session used to create the JMS receiver
+ */
+ private Session session;
+
+ /**
+ * The receiver used the consume the received messages
+ */
+ private MessageConsumer receiver;
+
+ /**
+ * Creates a new JMS consumer with a given configuration.
+ *
+ * @param config The configuration.
+ * @param createConsumer Creates the connection, session and receiver.
+ * @throws NamingException
+ * @throws JMSException
+ */
+ public AndesJMSConsumer(AndesJMSConsumerClientConfiguration config, boolean createConsumer)
+ throws NamingException, JMSException {
+ super(config);
+ receivedMessageCount = new AtomicLong(0);
+
+ // Sets the configuration
+ this.consumerConfig = config;
+
+ if (createConsumer) {
+ if (ExchangeType.QUEUE == this.consumerConfig.getExchangeType()) {
+ this.createQueueConnection();
+
+ } else if (ExchangeType.TOPIC == this.consumerConfig.getExchangeType()) {
+ this.createTopicConnection();
+ }
+ }
+ }
+
+ /**
+ * Creates a topic connection, session and receiver.
+ *
+ * @throws NamingException
+ * @throws JMSException
+ */
+ private void createTopicConnection() throws NamingException, JMSException {
+ // Creates a topic connection, sessions and receiver
+ TopicConnectionFactory connFactory = (TopicConnectionFactory) super.getInitialContext()
+ .lookup(AndesClientConstants.CF_NAME);
+ TopicConnection topicConnection = connFactory.createTopicConnection();
+ topicConnection.setClientID(this.consumerConfig.getSubscriptionID());
+ topicConnection.start();
+ TopicSession topicSession;
+ // Sets acknowledgement mode
+ if (TopicSession.SESSION_TRANSACTED == this.consumerConfig.getAcknowledgeMode().getType()) {
+ topicSession = topicConnection
+ .createTopicSession(true, this.consumerConfig.getAcknowledgeMode().getType());
+ } else {
+ topicSession = topicConnection
+ .createTopicSession(false, this.consumerConfig.getAcknowledgeMode().getType());
+ }
+
+ Topic topic =
+ (Topic) super.getInitialContext().lookup(this.consumerConfig.getDestinationName());
+
+ connection = topicConnection;
+ session = topicSession;
+ // If topic is durable
+ if (this.consumerConfig.isDurable()) {
+ // If selectors exists
+ if (null != this.consumerConfig.getSelectors()) {
+ receiver = topicSession.createDurableSubscriber(topic, this.consumerConfig
+ .getSubscriptionID(), this.consumerConfig.getSelectors(), false);
+ } else {
+ receiver = topicSession
+ .createDurableSubscriber(topic, this.consumerConfig.getSubscriptionID());
+ }
+ } else {
+ // If selectors exists
+ if (null != this.consumerConfig.getSelectors()) {
+ receiver = topicSession
+ .createSubscriber(topic, this.consumerConfig.getSelectors(), false);
+ } else {
+ receiver = topicSession.createSubscriber(topic);
+ }
+ }
+ }
+
+ /**
+ * Creates a queue connection, session and receiver.
+ *
+ * @throws NamingException
+ * @throws JMSException
+ */
+ private void createQueueConnection() throws NamingException, JMSException {
+ // Creates a queue connection, sessions and receiver
+ QueueConnectionFactory connFactory = (QueueConnectionFactory) super.getInitialContext()
+ .lookup(AndesClientConstants.CF_NAME);
+ QueueConnection queueConnection = connFactory.createQueueConnection();
+ queueConnection.start();
+ QueueSession queueSession;
+
+ // Sets acknowledgement mode
+ if (QueueSession.SESSION_TRANSACTED == this.consumerConfig.getAcknowledgeMode().getType()) {
+ queueSession = queueConnection
+ .createQueueSession(true, this.consumerConfig.getAcknowledgeMode().getType());
+ } else {
+ queueSession = queueConnection
+ .createQueueSession(false, this.consumerConfig.getAcknowledgeMode().getType());
+ }
+
+ Queue queue =
+ (Queue) super.getInitialContext().lookup(this.consumerConfig.getDestinationName());
+ connection = queueConnection;
+ session = queueSession;
+
+ // If selectors exists
+ if (null != this.consumerConfig.getSelectors()) {
+ receiver = queueSession.createReceiver(queue, this.consumerConfig.getSelectors());
+ } else {
+ receiver = queueSession.createReceiver(queue);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void startClient() throws AndesClientException, JMSException {
+ if (null != connection && null != session && null != receiver) {
+ log.info("Starting Consumer");
+ if (this.consumerConfig.isAsync()) {
+ // Use an asynchronous message listener
+ receiver.setMessageListener(this);
+ } else {
+ // Uses a thread to listen to messages
+ Thread consumerThread = new Thread(this);
+ consumerThread.start();
+ }
+ } else {
+ throw new AndesClientException("The connection, session and message receiver is not assigned.");
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void stopClient(){
+ /**
+ * Using a separate thread as stopping the consumer on "onMessage" thread is not allowed.
+ */
+ new Thread(new Runnable() {
+ @Override
+ public void run() {
+ if (null != connection && null != session && null != receiver) {
+ try {
+ log.info("Closing Consumer");
+ if (ExchangeType.TOPIC == consumerConfig.getExchangeType()) {
+ if (null != receiver) {
+ TopicSubscriber topicSubscriber = (TopicSubscriber) receiver;
+ topicSubscriber.close();
+ }
+
+ if (null != session) {
+ TopicSession topicSession = (TopicSession) session;
+ topicSession.close();
+ }
+
+ if (null != connection) {
+ TopicConnection topicConnection = (TopicConnection) connection;
+ topicConnection.close();
+ }
+ } else if (ExchangeType.QUEUE == consumerConfig.getExchangeType()) {
+ if (null != receiver) {
+ QueueReceiver queueReceiver = (QueueReceiver) receiver;
+ queueReceiver.close();
+ }
+
+ if (null != session) {
+ QueueSession queueSession = (QueueSession) session;
+ queueSession.close();
+ }
+
+ if (null != connection) {
+ QueueConnection queueConnection = (QueueConnection) connection;
+ queueConnection.stop();
+ queueConnection.close();
+ }
+ }
+
+ receiver = null;
+ session = null;
+ connection = null;
+
+ log.info("Consumer Closed");
+
+ } catch (JMSException e) {
+ log.error("Error in stopping client.", e);
+ throw new RuntimeException("Error in stopping client.", e);
+ }
+ }
+ }
+ }).start();
+ }
+
+ public void stopClientSync(){
+ if (null != connection && null != session && null != receiver) {
+ try {
+ log.info("Closing Consumer");
+ if (ExchangeType.TOPIC == consumerConfig.getExchangeType()) {
+ if (null != receiver) {
+ TopicSubscriber topicSubscriber = (TopicSubscriber) receiver;
+ topicSubscriber.close();
+ }
+
+ if (null != session) {
+ TopicSession topicSession = (TopicSession) session;
+ topicSession.close();
+ }
+
+ if (null != connection) {
+ TopicConnection topicConnection = (TopicConnection) connection;
+ topicConnection.close();
+ }
+ } else if (ExchangeType.QUEUE == consumerConfig.getExchangeType()) {
+ if (null != receiver) {
+ QueueReceiver queueReceiver = (QueueReceiver) receiver;
+ queueReceiver.close();
+ }
+
+ if (null != session) {
+ QueueSession queueSession = (QueueSession) session;
+ queueSession.close();
+ }
+
+ if (null != connection) {
+ QueueConnection queueConnection = (QueueConnection) connection;
+ queueConnection.stop();
+ queueConnection.close();
+ }
+ }
+
+ receiver = null;
+ session = null;
+ connection = null;
+
+ log.info("Consumer Closed");
+
+ } catch (JMSException e) {
+ log.error("Error in stopping client.", e);
+ throw new RuntimeException("Error in stopping client.", e);
+ }
+ }
+ }
+
+ /**
+ * Un-Subscribes and closes a consumers.
+ *
+ * @param stopClient true if the client needs to stopped after un-subscribing, false otherwise.
+ * @throws JMSException
+ */
+ public void unSubscribe(final boolean stopClient) throws JMSException {
+ /**
+ * Using a separate thread as un-subscribing the consumer on "onMessage" thread is not allowed.
+ */
+ new Thread(new Runnable() {
+ @Override
+ public void run() {
+ if (null != connection && null != session && null != receiver) {
+ try {
+ log.info("Un-subscribing Subscriber");
+ session.unsubscribe(consumerConfig.getSubscriptionID());
+ log.info("Subscriber Un-Subscribed");
+ if (stopClient) {
+ stopClient();
+ }
+
+ } catch (JMSException e) {
+ log.error("Error in removing subscription(un-subscribing).", e);
+ throw new RuntimeException("JMSException : Error in removing subscription(un-subscribing).", e);
+ }
+ } else {
+ AndesClientException andesClientException =
+ new AndesClientException("The connection, session and message receiver is not assigned.");
+ log.error("The connection, session and message receiver is not assigned.", andesClientException);
+ throw new RuntimeException("The connection, session and message receiver is not assigned.", andesClientException);
+ }
+ }
+ }).start();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void run() {
+ try {
+ boolean interrupted = false;
+ while (true) {
+ Message message = this.receiver.receive();
+
+ // We assume message receiving was interrupted if we receive null
+ if (null == message) {
+ interrupted = true;
+ break;
+ } else if ( processReceivedMessage(message)) {
+ break;
+ }
+ }
+ if (!interrupted) {
+ stopClientSync();
+ }
+ } catch (JMSException e) {
+ log.error("Error while receiving messages ", e);
+ throw new RuntimeException("JMSException : Error while listening to messages", e);
+ } catch (IOException e) {
+ log.error("Error while writing message to file", e);
+ throw new RuntimeException("IOException : Error while writing message to file\"", e);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void onMessage(Message message) {
+ try {
+ boolean success = this.processReceivedMessage(message);
+ if(success) {
+ stopClient();
+ }
+ } catch (JMSException e) {
+ log.error("Error while listening to messages", e);
+ throw new RuntimeException("Error while listening to messages", e);
+ } catch (IOException e) {
+ log.error("Error while writing message to file", e);
+ throw new RuntimeException("Error while listening to messages", e);
+ }
+ }
+
+ /**
+ * Processes the received messages. The processing includes the following actions. 1.
+ * Calculation of transactions per second. 2. Calculation of average latency for messages. 3.
+ * Message detail logging 4. Writes messages to a file. 5. Writes statistics to a file. 6.
+ * Closing and un-subscribing of client.
+ *
+ * @param message The {@link javax.jms.Message} to publish.
+ * @return true if client is stopped or un-subscribed, false otherwise.
+ * @throws JMSException
+ * @throws IOException
+ */
+ private boolean processReceivedMessage(Message message)
+ throws JMSException, IOException {
+ if (null != message) {
+ long threadID = Thread.currentThread().getId();
+ // Calculating total latency
+ long currentTimeStamp = System.currentTimeMillis();
+ this.totalLatency = this.totalLatency + (currentTimeStamp - message.getJMSTimestamp());
+ // Setting timestamps for TPS calculation
+ if (0 == this.firstMessageConsumedTimestamp) {
+ this.firstMessageConsumedTimestamp = currentTimeStamp;
+ }
+ this.lastMessageConsumedTimestamp = currentTimeStamp;
+
+ // Incrementing message received count
+ this.receivedMessageCount.incrementAndGet();
+ JMSDeliveryStatus deliveryStatus;
+ // Gets whether the message is original or redelivered
+ if (message.getJMSRedelivered()) {
+ deliveryStatus = JMSDeliveryStatus.REDELIVERED;
+ } else {
+ deliveryStatus = JMSDeliveryStatus.ORIGINAL;
+ }
+ // Logging the received message
+ if (0 == this.receivedMessageCount.get() % this.consumerConfig
+ .getPrintsPerMessageCount()) {
+ log.info("[RECEIVE] ThreadID:" + threadID + " Destination(" + this.consumerConfig
+ .getExchangeType().getType() + "):" +
+ this.consumerConfig.getDestinationName() + " ReceivedMessageCount:" +
+ this.receivedMessageCount + " MessageToReceive:" +
+ this.consumerConfig
+ .getMaximumMessagesToReceived() + " Original/Redelivered:" + deliveryStatus
+ .getStatus());
+
+ }
+ // Writes the statistics
+ if (null != this.consumerConfig.getFilePathToWriteStatistics()) {
+ String statisticsString = Long.toString(currentTimeStamp) + "," + Double
+ .toString(this.getConsumerTPS()) + "," + Double
+ .toString(this.getAverageLatency());
+ AndesClientUtils.writeStatisticsToFile(statisticsString, this.consumerConfig
+ .getFilePathToWriteStatistics());
+ }
+ if (message instanceof TextMessage) {
+ TextMessage textMessage = (TextMessage) message;
+ // Writes the received messages
+ if (null != this.consumerConfig.getFilePathToWriteReceivedMessages()) {
+ AndesClientUtils
+ .writeReceivedMessagesToFile(textMessage.getText(), this.consumerConfig
+ .getFilePathToWriteReceivedMessages());
+ }
+ }
+
+ // Acknowledges messages
+ if (0 == this.receivedMessageCount.get() % this.consumerConfig
+ .getAcknowledgeAfterEachMessageCount()) {
+ if (Session.CLIENT_ACKNOWLEDGE == session.getAcknowledgeMode()) {
+ message.acknowledge();
+ log.info("Acknowledging message : " + message.getJMSMessageID());
+ }
+ }
+
+ if (0 == this.receivedMessageCount.get() % consumerConfig
+ .getCommitAfterEachMessageCount()) {
+ // Committing session
+ session.commit();
+ log.info("Committed session");
+ } else if (0 == this.receivedMessageCount.get() % consumerConfig
+ .getRollbackAfterEachMessageCount()) {
+ // Roll-backing session
+ session.rollback();
+ log.info("Roll-backed session");
+ }
+
+ if (this.receivedMessageCount.get() >= consumerConfig
+ .getUnSubscribeAfterEachMessageCount()) {
+ // Un-Subscribing consumer
+ unSubscribe(true);
+ // Waiting till consumer is un-subscribed so that no messages will be read.
+ AndesClientUtils.sleepForInterval(1000L);
+ return true;
+ } else if (this.receivedMessageCount.get() >= consumerConfig
+ .getMaximumMessagesToReceived()) {
+ return true;
+ }
+
+ // Delaying reading of messages
+ if (0 < consumerConfig.getRunningDelay()) {
+ try {
+ Thread.sleep(consumerConfig.getRunningDelay());
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Gets the received message count for the consumer.
+ *
+ * @return The received message count.
+ */
+ public AtomicLong getReceivedMessageCount() {
+ return this.receivedMessageCount;
+ }
+
+ /**
+ * Gets the consumer transactions per seconds.
+ *
+ * @return The consumer transactions per seconds.
+ */
+ public double getConsumerTPS() {
+ if (0 == this.lastMessageConsumedTimestamp - this.firstMessageConsumedTimestamp) {
+ return this.receivedMessageCount.doubleValue() / (1D / 1000);
+ } else {
+ return this.receivedMessageCount
+ .doubleValue() / (((double) (this.lastMessageConsumedTimestamp - this.firstMessageConsumedTimestamp)) / 1000D);
+ }
+ }
+
+ /**
+ * Gets the average latency for the consumer in receiving messages.
+ *
+ * @return The average latency.
+ */
+ public double getAverageLatency() {
+ if (0 == this.receivedMessageCount.doubleValue()) {
+ log.warn("No messages were received to calculate average latency.");
+ return 0D;
+ } else {
+ return (((double) this.totalLatency) / 1000D) / this.receivedMessageCount.doubleValue();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public AndesJMSConsumerClientConfiguration getConfig() {
+ return this.consumerConfig;
+ }
+
+ /**
+ * Gets the JMS message consuming connection ({@link javax.jms.Connection}).
+ *
+ * @return A {@link javax.jms.Connection}
+ */
+ public Connection getConnection() {
+ return this.connection;
+ }
+
+ /**
+ * Sets the JMS message consuming connection ({@link javax.jms.Connection}).
+ *
+ * @param connection A {@link javax.jms.Connection}.
+ */
+ public void setConnection(Connection connection) {
+ this.connection = connection;
+ }
+
+ /**
+ * Gets the JMS message consuming session ({@link javax.jms.Session}).
+ *
+ * @return A {@link javax.jms.Session}.
+ */
+ public Session getSession() {
+ return this.session;
+ }
+
+ /**
+ * Sets the JMS message consuming session ({@link javax.jms.Session}).
+ *
+ * @param session A {@link javax.jms.Session}.
+ */
+ public void setSession(Session session) {
+ this.session = session;
+ }
+
+ /**
+ * Gets the JMS message consumer ({@link javax.jms.MessageConsumer}).
+ *
+ * @return A {@link javax.jms.MessageConsumer}.
+ */
+ public MessageConsumer getReceiver() {
+ return this.receiver;
+ }
+
+ /**
+ * Sets the JMS message consumer ({@link javax.jms.MessageConsumer}).
+ *
+ * @param receiver A {@link javax.jms.MessageConsumer}.
+ */
+ public void setReceiver(MessageConsumer receiver) {
+ this.receiver = receiver;
+ }
+}
diff --git a/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/AndesJMSPublisher.java b/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/AndesJMSPublisher.java
new file mode 100644
index 00000000..305e8a89
--- /dev/null
+++ b/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/AndesJMSPublisher.java
@@ -0,0 +1,437 @@
+/*
+* Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+*
+* WSO2 Inc. licenses this file to you under the Apache License,
+* Version 2.0 (the "License"); you may not use this file except
+* in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT 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.wso2.mb.integration.common.clients;
+
+import org.apache.log4j.Logger;
+import org.wso2.mb.integration.common.clients.configurations.AndesJMSPublisherClientConfiguration;
+import org.wso2.mb.integration.common.clients.configurations.JMSHeaderProperty;
+import org.wso2.mb.integration.common.clients.configurations.JMSHeaderPropertyType;
+import org.wso2.mb.integration.common.clients.exceptions.AndesClientException;
+import org.wso2.mb.integration.common.clients.operations.utils.AndesClientConstants;
+import org.wso2.mb.integration.common.clients.operations.utils.AndesClientUtils;
+import org.wso2.mb.integration.common.clients.operations.utils.JMSMessageType;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.DeliveryMode;
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.MapMessage;
+import javax.jms.Message;
+import javax.jms.MessageProducer;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.naming.NamingException;
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
+import java.text.MessageFormat;
+import java.util.List;
+
+/**
+ * The JMS message publisher used for creating a publisher and for publishing JMS messages.
+ */
+public class AndesJMSPublisher extends AndesJMSBase implements Runnable {
+ /**
+ * The logger used in logging information, warnings, errors and etc.
+ */
+ private static Logger log = Logger.getLogger(AndesJMSPublisher.class);
+
+ /**
+ * The configuration for the publisher
+ */
+ private AndesJMSPublisherClientConfiguration publisherConfig;
+
+ /**
+ * The amount of messages sent by the publisher
+ */
+ private long sentMessageCount;
+
+ /**
+ * The timestamp at which the first message was published
+ */
+ private long firstMessagePublishTimestamp;
+
+ /**
+ * The timestamp at which the last message was published
+ */
+ private long lastMessagePublishTimestamp;
+
+ /**
+ * The connection which is used to create the JMS session
+ */
+ private Connection connection;
+
+ /**
+ * The session which is used to create the JMS message producer
+ */
+ private Session session;
+
+ /**
+ * The message producer which produces/sends messages
+ */
+ private MessageProducer sender;
+
+ /**
+ * Message content which is needed to be published. The value will depend on the configuration.
+ */
+ private String messageContentFromFile = null;
+
+ /**
+ * Creates a new JMS publisher with a given configuration.
+ *
+ * @param config The configuration
+ * @param createPublisher Creates connection, session and sender.
+ * @throws NamingException
+ * @throws JMSException
+ */
+ public AndesJMSPublisher(AndesJMSPublisherClientConfiguration config, boolean createPublisher)
+ throws NamingException, JMSException {
+ super(config);
+
+ // Sets the configuration
+ this.publisherConfig = config;
+
+ // Creates a JMS connection, sessions and sender
+ if (createPublisher) {
+ ConnectionFactory connFactory = (ConnectionFactory) super.getInitialContext()
+ .lookup(AndesClientConstants.CF_NAME);
+ connection = connFactory.createConnection();
+ connection.start();
+ if(config.isTransactionalSession()) {
+ this.session = connection.createSession(true, 0);
+ } else {
+ this.session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ }
+
+ Destination destination = (Destination) super.getInitialContext()
+ .lookup(this.publisherConfig.getDestinationName());
+ this.sender = this.session.createProducer(destination);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void startClient() throws AndesClientException, IOException {
+ if (null != connection && null != session && null != sender) {
+ //reading message content from file
+ if (null != this.publisherConfig.getReadMessagesFromFilePath()) {
+ this.getMessageContentFromFile();
+ }
+
+ Thread subscriberThread = new Thread(this);
+ subscriberThread.start();
+ } else {
+ throw new AndesClientException("The connection, session and message sender is not assigned.");
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void stopClient() throws JMSException {
+ if (null != connection && null != session && null != sender) {
+ long threadID = Thread.currentThread().getId();
+ log.info("Closing publisher | ThreadID : " + threadID);
+ this.sender.close();
+ this.session.close();
+ this.connection.close();
+ this.sender = null;
+ this.session = null;
+ this.connection = null;
+ log.info("Publisher closed | ThreadID : " + threadID);
+ }
+ }
+
+ /**
+ * Reads message content from a file which is used as the message content to when publishing
+ * messages.
+ *
+ * @throws IOException
+ */
+ public void getMessageContentFromFile() throws IOException {
+ if (null != this.publisherConfig.getReadMessagesFromFilePath()) {
+ BufferedReader br = new BufferedReader(new FileReader(this.publisherConfig
+ .getReadMessagesFromFilePath()));
+ try {
+ StringBuilder sb = new StringBuilder();
+ String line = br.readLine();
+
+ while (line != null) {
+ sb.append(line);
+ sb.append('\n');
+ line = br.readLine();
+ }
+
+ // Remove the last appended next line since there is no next line.
+ sb.replace(sb.length() - 1, sb.length() + 1, "");
+ messageContentFromFile = sb.toString();
+ } finally {
+ br.close();
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void run() {
+ try {
+ Message message = null;
+ long threadID = Thread.currentThread().getId();
+ while (this.sentMessageCount < this.publisherConfig.getNumberOfMessagesToSend()) {
+ // Creating a JMS message
+ if (JMSMessageType.TEXT == this.publisherConfig.getJMSMessageType()) {
+ if (null != this.publisherConfig.getReadMessagesFromFilePath()) {
+ message = this.session.createTextMessage(this.messageContentFromFile);
+ } else {
+ message = this.session.createTextMessage(MessageFormat
+ .format(AndesClientConstants.PUBLISH_MESSAGE_FORMAT, this.sentMessageCount, threadID));
+ }
+ } else if (JMSMessageType.BYTE == this.publisherConfig.getJMSMessageType()) {
+ message = this.session.createBytesMessage();
+ } else if (JMSMessageType.MAP == this.publisherConfig.getJMSMessageType()) {
+ MapMessage mapMessage = this.session.createMapMessage();
+ if (null != this.publisherConfig.getReadMessagesFromFilePath()) {
+ String[] entries = this.messageContentFromFile.split(System.getProperty("line.separator"));
+ for (int i = 0; i < entries.length; i++) {
+ mapMessage.setString("key" + i, entries[i]);
+ }
+ }
+ message = mapMessage;
+ } else if (JMSMessageType.OBJECT == this.publisherConfig.getJMSMessageType()) {
+ message = this.session.createObjectMessage();
+ } else if (JMSMessageType.STREAM == this.publisherConfig.getJMSMessageType()) {
+ message = this.session.createStreamMessage();
+ }
+
+ //set JMS message type
+ String jmsType = publisherConfig.getJMSType();
+ if(message!= null && null != jmsType && !jmsType.isEmpty()) {
+ message.setJMSType(jmsType);
+ }
+
+ //set JMS header properties
+ setMessageProperties(message);
+
+ if (null != message) {
+ this.sender.send(message, DeliveryMode.PERSISTENT, 0, this.publisherConfig
+ .getJMSMessageExpiryTime());
+ // need to commit if transactional
+ if(getConfig().isTransactionalSession()) {
+ session.commit();
+ }
+ if (message instanceof TextMessage && null != this.publisherConfig.getFilePathToWritePublishedMessages()){
+ AndesClientUtils.writePublishedMessagesToFile(((TextMessage) message)
+ .getText(), this.publisherConfig.getFilePathToWritePublishedMessages());
+ }
+
+ this.sentMessageCount++;
+
+ // TPS calculation
+ long currentTimeStamp = System.currentTimeMillis();
+ if (0 == this.firstMessagePublishTimestamp) {
+ this.firstMessagePublishTimestamp = currentTimeStamp;
+ }
+
+ this.lastMessagePublishTimestamp = currentTimeStamp;
+ if (0 == this.sentMessageCount % this.publisherConfig
+ .getPrintsPerMessageCount()) {
+ // Logging the sent message details.
+ if (null != this.publisherConfig.getReadMessagesFromFilePath()) {
+ log.info("[SEND]" + " (FROM FILE) ThreadID:" +
+ threadID + " Destination(" + this.publisherConfig
+ .getExchangeType().getType() + "):" +
+ this.publisherConfig
+ .getDestinationName() + " SentMessageCount:" +
+ this.sentMessageCount + " CountToSend:" +
+ this.publisherConfig.getNumberOfMessagesToSend());
+ } else {
+ log.info("[SEND]" + " (INBUILT MESSAGE) ThreadID:" +
+ threadID + " Destination(" + this.publisherConfig
+ .getExchangeType().getType() + "):" +
+ this.publisherConfig
+ .getDestinationName() + " SentMessageCount:" +
+ this.sentMessageCount + " CountToSend:" +
+ this.publisherConfig.getNumberOfMessagesToSend());
+ }
+ }
+ // Writing statistics
+ if (null != this.publisherConfig.getFilePathToWriteStatistics()) {
+ String statisticsString =
+ ",,,," + Long.toString(currentTimeStamp) + "," + Double
+ .toString(this.getPublisherTPS());
+ AndesClientUtils
+ .writeStatisticsToFile(statisticsString, this.publisherConfig
+ .getFilePathToWriteStatistics());
+ }
+
+ // Delaying the publishing of messages
+ if (0 < this.publisherConfig.getRunningDelay()) {
+ try {
+ Thread.sleep(this.publisherConfig.getRunningDelay());
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+ }
+
+ this.stopClient();
+ } catch (JMSException e) {
+ throw new RuntimeException("Error while publishing messages", e);
+ } catch (IOException e) {
+ throw new RuntimeException("Error while writing statistics", e);
+ }
+ }
+
+ /**
+ * Set JMS Headers to the message according to publisher configuration
+ *
+ * @param message message to set properties
+ */
+ private void setMessageProperties(Message message) throws JMSException {
+
+ List headerPropertyList = publisherConfig.getJMSHeaderProperties();
+
+ for (JMSHeaderProperty jmsHeaderProperty : headerPropertyList) {
+ JMSHeaderPropertyType type = jmsHeaderProperty.getType();
+ String propertyKey = jmsHeaderProperty.getKey();
+ Object propertyValue = jmsHeaderProperty.getValue();
+ switch (type) {
+ case OBJECT:
+ message.setObjectProperty(propertyKey, propertyValue);
+ break;
+ case BYTE:
+ message.setByteProperty(propertyKey, (Byte) propertyValue);
+ break;
+ case BOOLEAN:
+ message.setBooleanProperty(propertyKey, (Boolean) propertyValue);
+ break;
+ case DOUBLE:
+ message.setDoubleProperty(propertyKey, (Double) propertyValue);
+ break;
+ case FLOAT:
+ message.setFloatProperty(propertyKey, (Float) propertyValue);
+ break;
+ case SHORT:
+ message.setShortProperty(propertyKey, (Short) propertyValue);
+ break;
+ case STRING:
+ message.setStringProperty(propertyKey, (String) propertyValue);
+ break;
+ case INTEGER:
+ message.setIntProperty(propertyKey, (Integer) propertyValue);
+ break;
+ case LONG:
+ message.setLongProperty(propertyKey, (Long) propertyValue);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Gets the published message count.
+ *
+ * @return The published message count.
+ */
+ public long getSentMessageCount() {
+ return this.sentMessageCount;
+ }
+
+ /**
+ * Gets the transactions per seconds for publisher.
+ *
+ * @return The transactions per second.
+ */
+ public double getPublisherTPS() {
+ if (0 == this.lastMessagePublishTimestamp - this.firstMessagePublishTimestamp) {
+ return ((double) this.sentMessageCount) / (1D / 1000);
+ } else {
+ return ((double) this.sentMessageCount) / (((double) (this.lastMessagePublishTimestamp - this.firstMessagePublishTimestamp)) / 1000);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public AndesJMSPublisherClientConfiguration getConfig() {
+ return this.publisherConfig;
+ }
+
+ /**
+ * Gets the JMS message sending connection ({@link javax.jms.Connection}).
+ *
+ * @return A {@link javax.jms.Connection}
+ */
+ public Connection getConnection() {
+ return this.connection;
+ }
+
+ /**
+ * Sets the JMS message sending connection ({@link javax.jms.Connection}).
+ *
+ * @param connection A {@link javax.jms.Connection}.
+ */
+ public void setConnection(Connection connection) {
+ this.connection = connection;
+ }
+
+ /**
+ * Gets the JMS message sending session ({@link javax.jms.Session}).
+ *
+ * @return A {@link javax.jms.Session}.
+ */
+ public Session getSession() {
+ return this.session;
+ }
+
+ /**
+ * Sets the JMS message sending session ({@link javax.jms.Session}).
+ *
+ * @param session A {@link javax.jms.Session}.
+ */
+ public void setSession(Session session) {
+ this.session = session;
+ }
+
+ /**
+ * Gets the JMS message producer ({@link javax.jms.MessageProducer}).
+ *
+ * @return A {@link javax.jms.MessageProducer}.
+ */
+ public MessageProducer getSender() {
+ return this.sender;
+ }
+
+ /**
+ * Sets the JMS message producer ({@link javax.jms.MessageProducer}). Suppressing
+ * "UnusedDeclaration" as the client acts as a service.
+ *
+ * @param sender A {@link javax.jms.MessageProducer}.
+ */
+ @SuppressWarnings("UnusedDeclaration")
+ public void setSender(MessageProducer sender) {
+ this.sender = sender;
+ }
+}
diff --git a/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/AndesMQTTClient.java b/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/AndesMQTTClient.java
new file mode 100644
index 00000000..31dac2fa
--- /dev/null
+++ b/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/AndesMQTTClient.java
@@ -0,0 +1,256 @@
+/*
+ * Copyright (c) 2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.wso2.mb.integration.common.clients;
+
+import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
+import org.eclipse.paho.client.mqttv3.MqttException;
+import org.eclipse.paho.client.mqttv3.MqttMessage;
+import org.eclipse.paho.client.mqttv3.persist.MqttDefaultFilePersistence;
+import org.wso2.mb.integration.common.clients.operations.mqtt.callback.CallbackHandler;
+
+import java.io.File;
+import java.util.List;
+
+/**
+ * Basic MQTT client which handles the operations around MQTT clients.
+ * - Handling fields
+ * - Handling message counts
+ *
+ * Each MQTT client with different publish/subscribe mechanism should extend from this.
+ */
+public abstract class AndesMQTTClient implements Runnable {
+
+ /**
+ * The MQTT callback handler which handles message arrival, delivery complete and connection loss requests.
+ */
+ private final CallbackHandler callbackHandler;
+
+ /**
+ * unique identifier for mqtt client - less than or equal to 23 characters
+ */
+ protected final String mqttClientID;
+
+ /**
+ * Connection options that are required to create a connection to a MQTT server
+ */
+ protected final MqttConnectOptions connectionOptions;
+
+ /**
+ * Message broker MQTT URL
+ */
+ protected final String brokerUrl;
+
+ /**
+ * The topic the messages needs to send to / received from
+ */
+ protected final String topic;
+
+ /**
+ * The quality of service to send/receive messages *
+ */
+ protected final QualityOfService qos;
+
+ /**
+ * MQTT retain parameter
+ * When retain enabled with published topic message, it should retained for future subscribers
+ * for the same topic.
+ */
+ protected final boolean retain;
+
+ /**
+ * Store messages until server fetches them.
+ * Need a random value on this path to ensure that the same persistence store is not used by two clients.
+ */
+ protected final MqttDefaultFilePersistence dataStore =
+ new MqttDefaultFilePersistence(System.getProperty("java.io.tmpdir") + File.separator + Math.random());
+
+ /**
+ * Create a mqtt client initializing mqtt options.
+ *
+ * @param configuration MQTT configurations
+ * @param clientID The unique client Id
+ * @param topic Topic to subscribe/publish to
+ * @param qos The quality of service
+ * @param callbackHandler Callback Handler to handle receiving messages/message sending ack
+ */
+ public AndesMQTTClient(MQTTClientConnectionConfiguration configuration, String clientID, String topic,
+ QualityOfService qos, CallbackHandler callbackHandler) {
+
+ //Initializing the variables locally
+ this.brokerUrl = configuration.getBrokerURL();
+ this.mqttClientID = clientID;
+ String password = configuration.getBrokerPassword();
+ String userName = configuration.getBrokerUserName();
+ this.topic = topic;
+ this.qos = qos;
+ this.retain = configuration.isRetain();
+
+ // Construct the connection options object that contains connection parameters
+ // such as cleanSession and LWT
+ connectionOptions = new MqttConnectOptions();
+ connectionOptions.setCleanSession(configuration.isCleanSession());
+
+ if (null != password) {
+ connectionOptions.setPassword(password.toCharArray());
+ }
+ if (null != userName) {
+ connectionOptions.setUserName(userName);
+ }
+
+ // Set callback handler
+ this.callbackHandler = callbackHandler;
+ }
+
+ /**
+ * Publish messages to mqtt server.
+ *
+ * @param payload Data to send
+ * @param noOfMessages Number of message to send
+ * @throws MqttException
+ */
+ protected abstract void publish(byte[] payload, int noOfMessages) throws MqttException;
+
+ /**
+ * Subscribe to the requested topic
+ * The {@link QualityOfService} specified is the maximum level that messages will be sent to the client at.
+ * For instance if QoS {@link QualityOfService#LEAST_ONCE} is specified, any messages originally published at QoS
+ * {@link QualityOfService#EXACTLY_ONCE} will be downgraded to {@link QualityOfService#MOST_ONCE} when delivering
+ * to the client but messages published at {@link QualityOfService#LEAST_ONCE} and {@link
+ * QualityOfService#MOST_ONCE} will be received at the same level they were published at.
+ *
+ * @throws MqttException
+ */
+ public abstract void subscribe() throws MqttException;
+
+ /**
+ * Subscribe to a given topic.
+ *
+ * @param topicName The topic to subscribe to
+ * @throws MqttException
+ */
+ public abstract void subscribe(String topicName) throws MqttException;
+
+ /**
+ * Un-subscribe from the topic.
+ *
+ * @throws MqttException
+ */
+ public abstract void unsubscribe() throws MqttException;
+
+ /**
+ * Un-subscribe from a given topic.
+ *
+ * @param topic The topic to un-subscribe from.
+ * @throws MqttException
+ */
+ public abstract void unsubscribe(String topic) throws MqttException;
+
+ /**
+ * Get the received message count from the callback handler to validate message receiving is successful.
+ *
+ * @return Received message count
+ */
+ public int getReceivedMessageCount() {
+ int messageCount = 0;
+ if (null != callbackHandler) {
+ messageCount = callbackHandler.getReceivedMessageCount();
+ }
+
+ return messageCount;
+ }
+
+ /**
+ * Get the sent message count from the callback handler to validate message sending is successful.
+ *
+ * @return The sent message count.
+ */
+ public int getSentMessageCount() {
+ int messageCount = 0;
+ if (null != callbackHandler) {
+ messageCount = callbackHandler.getSentMessageCount();
+ }
+
+ return messageCount;
+ }
+
+ /**
+ * Shutdown the mqtt client. Call this whenever the system exits, test cases are finished or disconnect hook is
+ * called.
+ *
+ * @throws MqttException
+ */
+ public abstract void disconnect() throws MqttException;
+
+ /**
+ * Connect a mqtt client to the server with given options.
+ *
+ * @throws MqttException
+ */
+ public abstract void connect() throws MqttException;
+
+ /**
+ * Get the mqtt client Id. Use this to print client Id into logs whenever necessary.
+ *
+ * @return MQTT client Id
+ */
+ public String getMqttClientID() {
+ return mqttClientID;
+ }
+
+ /**
+ * Use this to validate if connection to server is still active.
+ *
+ * @return Is MQTT client connected to the server
+ */
+ public abstract boolean isConnected();
+
+ /**
+ * Get the topic name this MQTT client is connected to.
+ *
+ * @return The topic name
+ */
+ public String getTopic() {
+ return topic;
+ }
+
+ /**
+ * Get the MQTT callback handler for the client.
+ *
+ * @return The callback handler
+ */
+ public CallbackHandler getCallbackHandler() {
+ return callbackHandler;
+ }
+
+ /**
+ * Check if the subscriber is subscribed to a topic
+ *
+ * @return Is Subscribed
+ */
+ public abstract boolean isSubscribed();
+
+ /**
+ * Get all the received messages through this client.
+ * Use this if want to validate message content.
+ *
+ * @return Received messages.
+ */
+ public abstract List getReceivedMessages();
+
+}
diff --git a/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/ClientMode.java b/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/ClientMode.java
new file mode 100644
index 00000000..d0cbbcc9
--- /dev/null
+++ b/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/ClientMode.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.wso2.mb.integration.common.clients;
+
+/**
+ * The MQTT client mode to use.
+ */
+public enum ClientMode {
+
+ /**
+ * All the server calls will be synchronous. The control will not be returned until the call is successful.
+ */
+ BLOCKING,
+
+ /**
+ * All the server calls are asynchronous. The control is immediately returned and the server call will be made
+ * asynchronously.
+ */
+ ASYNC
+
+}
diff --git a/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/MQTTClientConnectionConfiguration.java b/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/MQTTClientConnectionConfiguration.java
new file mode 100755
index 00000000..cd16370b
--- /dev/null
+++ b/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/MQTTClientConnectionConfiguration.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.wso2.mb.integration.common.clients;
+
+/**
+ * The configurations that needs to be passed to MQTT client.
+ */
+public class MQTTClientConnectionConfiguration {
+
+ /**
+ * The protocol used by the broker.
+ * tcp, udp .etc
+ */
+ private String brokerProtocol = null;
+
+ /**
+ * Broker host address.
+ * eg :- 127.0.0.1
+ */
+ private String brokerHost = null;
+
+ /**
+ * Broker working port.
+ * eg :- 1883
+ */
+ private String brokerPort = null;
+
+ /**
+ * The password to connect to the broker.
+ */
+ private String brokerPassword = null;
+
+ /**
+ * The username to connect to the broker.
+ */
+ private String brokerUserName = null;
+
+ /**
+ * MQTT retain parameter
+ *
+ * When retain enabled with published topic message, it should retained for future subscribers
+ * for the same topic.
+ */
+ private boolean retain = false;
+
+ /**
+ * MQTT clean session parameter.
+ *
+ * When a client is connected to a broker, and if it has been previously connected and that session information
+ * is available in the broker, clean session = true will discard previous session information.
+ */
+ private boolean cleanSession = false;
+
+ public boolean isCleanSession() {
+ return cleanSession;
+ }
+
+ public void setCleanSession(boolean cleanSession) {
+ this.cleanSession = cleanSession;
+ }
+
+ public boolean isRetain() {
+ return retain;
+ }
+
+ public void setRetain(boolean retain) {
+ this.retain = retain;
+ }
+
+ public String getBrokerProtocol() {
+ return brokerProtocol;
+ }
+
+ public void setBrokerProtocol(String brokerProtocol) {
+ this.brokerProtocol = brokerProtocol;
+ }
+
+ public String getBrokerHost() {
+ return brokerHost;
+ }
+
+ public void setBrokerHost(String brokerHost) {
+ this.brokerHost = brokerHost;
+ }
+
+ public String getBrokerPort() {
+ return brokerPort;
+ }
+
+ public void setBrokerPort(String brokerPort) {
+ this.brokerPort = brokerPort;
+ }
+
+ public String getBrokerPassword() {
+ return brokerPassword;
+ }
+
+ public void setBrokerPassword(String brokerPassword) {
+ this.brokerPassword = brokerPassword;
+ }
+
+ public String getBrokerUserName() {
+ return brokerUserName;
+ }
+
+ public void setBrokerUserName(String brokerUserName) {
+ this.brokerUserName = brokerUserName;
+ }
+
+ /**
+ * Generate the broker URL using the given configurations.
+ *
+ * @return The broker URL
+ */
+ public String getBrokerURL() {
+ return brokerProtocol + "://" + brokerHost + ":" + brokerPort;
+ }
+}
diff --git a/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/MQTTClientEngine.java b/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/MQTTClientEngine.java
new file mode 100755
index 00000000..8e57a70c
--- /dev/null
+++ b/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/MQTTClientEngine.java
@@ -0,0 +1,596 @@
+/*
+ * Copyright (c) 2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.wso2.mb.integration.common.clients;
+
+import org.apache.commons.lang.RandomStringUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.eclipse.paho.client.mqttv3.MqttException;
+import org.eclipse.paho.client.mqttv3.MqttMessage;
+import org.wso2.carbon.automation.engine.context.AutomationContext;
+import org.wso2.mb.integration.common.clients.operations.mqtt.async.MQTTAsyncPublisherClient;
+import org.wso2.mb.integration.common.clients.operations.mqtt.async.MQTTAsyncSubscriberClient;
+import org.wso2.mb.integration.common.clients.operations.mqtt.blocking.MQTTBlockingPublisherClient;
+import org.wso2.mb.integration.common.clients.operations.mqtt.blocking.MQTTBlockingSubscriberClient;
+
+import javax.xml.xpath.XPathExpressionException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Handle all MQTT operations for MQTT tests.
+ * Create a new instance of this per each test case.
+ */
+public class MQTTClientEngine {
+
+ /**
+ * Keeps all the publishers created through the engine
+ */
+ private final List publisherList = new ArrayList();
+
+ /**
+ * Keep all the subscribers created through the engine
+ */
+ private final List subscriberList = new ArrayList();
+
+ /**
+ * Subscriber client thread executor, executes runnable subscribers
+ */
+ private final ExecutorService clientControlSubscriptionThreads = Executors.newFixedThreadPool(10);
+
+ /**
+ * Publisher client thread executor, executes runnable publishers
+ */
+ private final ExecutorService clientControlPublisherThreads = Executors.newFixedThreadPool(10);
+
+ private final Log log = LogFactory.getLog(MQTTClientEngine.class);
+
+ private static final int MILLISECONDS_TO_A_SECOND = 1000;
+
+ /**
+ * The executor service to invoke scheduled jobs
+ */
+ private final ScheduledExecutorService scheduleExecutor = Executors.newScheduledThreadPool(1);
+
+ /**
+ * Schedule which publishes send/receive TPS
+ */
+ private ScheduledFuture tpsPublisherSchedule;
+
+ /**
+ * The received message count there was when the previous TPS calculation happened
+ */
+ private int previousReceivedMessageCount;
+
+ /**
+ * The sent message count there was when the previous TPS calculation happened
+ */
+ private int previousSentMessageCount;
+
+ /**
+ * Initialises the client engine attaching a disconnect hook to close all the opened connection.
+ * Initialises TPS publishing mechanism.
+ */
+ public MQTTClientEngine() {
+ startTPSPublisher();
+ Runtime.getRuntime().addShutdownHook(new Thread() {
+ @Override
+ public void run() {
+ try {
+ shutdown();
+ log.info("All mqtt clients have been disconnected.");
+ } catch (MqttException e) {
+ log.error("Error occurred invoking disconnect for " + this.getName(), e);
+ }
+
+ }
+ });
+ }
+
+ /**
+ * Generate a unique client Id for MQTT clients.
+ * Randomize current timestamp.
+ *
+ * @return A unique Id
+ */
+ public String generateClientID() {
+ String clientId = RandomStringUtils.random(MQTTConstants.CLIENT_ID_LENGTH, String.valueOf(System
+ .currentTimeMillis()));
+ log.info("ClientID generated : " + clientId);
+ return clientId;
+ }
+
+ /**
+ * Create a MQTT subscriber. Use when a subscriber with specific MQTTClientConnectionConfiguration is required.
+ *
+ * @param configuration MQTT configurations for the subscriber
+ * @param topicName Topic to subscribe to
+ * @param qos Quality of Service
+ * @param saveMessages Save receiving messages
+ * @param clientMode Client connection mode
+ * @throws MqttException
+ */
+ public void createSubscriberConnection(MQTTClientConnectionConfiguration configuration,
+ String topicName, QualityOfService qos,
+ boolean saveMessages, ClientMode clientMode) throws MqttException {
+
+ AndesMQTTClient mqttClient;
+
+ if (ClientMode.ASYNC == clientMode) {
+ mqttClient = new MQTTAsyncSubscriberClient(configuration, generateClientID(), topicName, qos, saveMessages);
+ subscriberList.add(mqttClient);
+ clientControlSubscriptionThreads.execute(mqttClient);
+ } else if (ClientMode.BLOCKING == clientMode) {
+ mqttClient = new MQTTBlockingSubscriberClient(configuration, generateClientID(), topicName, qos,
+ saveMessages);
+ subscriberList.add(mqttClient);
+ mqttClient.run();
+ } else {
+ // Using else since only the above two scenarios are handled. If a new client mode is included,
+ // handle it before this
+ throw new MqttException(new Throwable("Unidentified clientMode : " + clientMode));
+ }
+
+
+ waitForSubscribersToSubscribe();
+ }
+
+ /**
+ * Method which can be used to override the auto generated client ID for a specific subscriber.
+ *
+ * @param configuration MQTT configurations for the subscriber
+ * @param topicName Topic to subscribe to
+ * @param qos Quality of Service
+ * @param saveMessages Save receiving messages
+ * @param clientMode Client connection mode
+ * @param clientID Unique identifier for the client hosting the subscription
+ */
+ public void createSubscriberConnection(MQTTClientConnectionConfiguration configuration,
+ String topicName, QualityOfService qos,
+ boolean saveMessages, ClientMode clientMode, String clientID) throws
+ MqttException {
+
+ AndesMQTTClient mqttClient;
+
+ if (ClientMode.ASYNC == clientMode) {
+ mqttClient = new MQTTAsyncSubscriberClient(configuration, clientID, topicName, qos, saveMessages);
+ subscriberList.add(mqttClient);
+ clientControlSubscriptionThreads.execute(mqttClient);
+ } else if (ClientMode.BLOCKING == clientMode) {
+ mqttClient = new MQTTBlockingSubscriberClient(configuration, clientID, topicName, qos,
+ saveMessages);
+ subscriberList.add(mqttClient);
+ mqttClient.run();
+ } else {
+ // Using else since only the above two scenarios are handled. If a new client mode is included,
+ // handle it before this
+ throw new MqttException(new Throwable("Unidentified clientMode : " + clientMode));
+ }
+
+
+ waitForSubscribersToSubscribe();
+ }
+
+ /**
+ * Create a given number of subscribers.
+ *
+ * @param topicName Topic to subscribe to
+ * @param qos Quality of Service
+ * @param noOfSubscribers Number of subscriber connections to create
+ * @param saveMessages Save receiving messages
+ * @param clientMode Client connection mode
+ * @throws MqttException
+ */
+ public void createSubscriberConnection(String topicName, QualityOfService qos, int noOfSubscribers,
+ boolean saveMessages, ClientMode clientMode,
+ AutomationContext automationContext)
+ throws MqttException, XPathExpressionException {
+ MQTTClientConnectionConfiguration configurations = getConfigurations(automationContext);
+ for (int i = 0; i < noOfSubscribers; i++) {
+ createSubscriberConnection(configurations, topicName, qos, saveMessages, clientMode);
+ }
+ }
+
+
+ /**
+ * Create a given number of subscribers.
+ *
+ * @param topicName Topic to subscribe to
+ * @param qos Quality of Service
+ * @param noOfSubscribers Number of subscriber connections to create
+ * @param saveMessages Save receiving messages
+ * @param clientMode Client connection mode
+ * @param configuration Configuration to use
+ * @throws MqttException
+ */
+ public void createSubscriberConnection(String topicName, QualityOfService qos, int noOfSubscribers,
+ boolean saveMessages, ClientMode clientMode,
+ MQTTClientConnectionConfiguration configuration) throws MqttException {
+
+ for (int i = 0; i < noOfSubscribers; i++) {
+ createSubscriberConnection(configuration, topicName, qos, saveMessages, clientMode);
+ }
+ }
+
+
+ /**
+ * Wait until all the subscriber are subscribed to the topics and ready to receive messages.
+ * Before creating publishers, this should be called otherwise while subscribers are being subscribed publishers
+ * will start to publish and those messages will be lost.
+ */
+ private void waitForSubscribersToSubscribe() {
+ while (!isAllSubscribersSubscribed()) {
+ try {
+ TimeUnit.SECONDS.sleep(1L);
+ } catch (InterruptedException e) {
+ log.error("Error waiting until subscribers subscribe to topics.", e);
+ }
+ log.info("Waiting for subscribers to create connection");
+ }
+ }
+
+ /**
+ * Check if all the subscribers are subscribed to the topics and ready to receive messages.
+ *
+ * @return Is all subscribers subscribed to their topics
+ */
+ private boolean isAllSubscribersSubscribed() {
+ boolean subscribed = true;
+ for (AndesMQTTClient subscriberClient : subscriberList) {
+ if (!subscriberClient.isSubscribed()) {
+ subscribed = false;
+ break;
+ }
+ }
+
+ return subscribed;
+ }
+
+ /**
+ * Create a MQTT publisher. Use when a publisher with specific MQTTClientConnectionConfiguration is required.
+ *
+ * @param configuration MQTT MQTT configurations for the publisher
+ * @param topicName Topic to publish to
+ * @param qos Quality of Service
+ * @param payload Payload of the sending message
+ * @param noOfMessages Number of message to send
+ * @param clientMode Client connection mode
+ * @throws MqttException
+ */
+ public void createPublisherConnection(MQTTClientConnectionConfiguration configuration,
+ String topicName, QualityOfService qos, byte[] payload,
+ int noOfMessages, ClientMode clientMode) throws MqttException {
+
+ AndesMQTTClient mqttClient;
+
+ if (ClientMode.ASYNC == clientMode) {
+ mqttClient = new MQTTAsyncPublisherClient(configuration, generateClientID(), topicName, qos, payload,
+ noOfMessages);
+ publisherList.add(mqttClient);
+ clientControlPublisherThreads.execute(mqttClient);
+ } else if (ClientMode.BLOCKING == clientMode) {
+ mqttClient = new MQTTBlockingPublisherClient(configuration, generateClientID(), topicName, qos, payload,
+ noOfMessages);
+ publisherList.add(mqttClient);
+ mqttClient.run();
+ } else {
+ // Using else since only the above two scenarios are handled. If a new client mode is included,
+ // handle it before this
+ throw new MqttException(new Throwable("Unidentified ClientMode : " + clientMode));
+ }
+ }
+
+
+
+ /**
+ * Create a given number of publishers.
+ *
+ * @param topicName Topic to publish to
+ * @param qos Quality of Service
+ * @param payload Payload of the sending message
+ * @param noOfPublishers Number of publisher connections to create
+ * @param noOfMessages Number of message to send
+ * @param clientMode Client connection mode
+ * @throws MqttException
+ */
+ public void createPublisherConnection(String topicName, QualityOfService qos, byte[] payload,
+ int noOfPublishers, int noOfMessages, ClientMode clientMode,
+ AutomationContext automationContext)
+ throws MqttException, XPathExpressionException {
+ createPublisherConnection(topicName, qos, payload, noOfPublishers, noOfMessages, clientMode,
+ getConfigurations(automationContext));
+ }
+
+ /**
+ * Create a given number of publishers.
+ *
+ * @param topicName Topic to publish to
+ * @param qos Quality of Service
+ * @param payload Payload of the sending message
+ * @param noOfPublishers Number of publisher connections to create
+ * @param noOfMessages Number of message to send
+ * @param clientMode Client connection mode
+ * @param configuration Configuration to use.
+ * @throws MqttException
+ */
+ public void createPublisherConnection(String topicName, QualityOfService qos, byte[] payload,
+ int noOfPublishers, int noOfMessages, ClientMode clientMode,
+ MQTTClientConnectionConfiguration configuration) throws MqttException {
+
+ for (int i = 0; i < noOfPublishers; i++) {
+ createPublisherConnection(configuration, topicName, qos, payload, noOfMessages, clientMode);
+ }
+ }
+
+
+ /**
+ * Retrieve default MQTT client configurations. Always retrieve configurations from this unless there is a
+ * specific requirement.
+ *
+ * @return Default MQTTClientConnectionConfigurations
+ */
+ private MQTTClientConnectionConfiguration getDefaultConfigurations() {
+ MQTTClientConnectionConfiguration configuration = new MQTTClientConnectionConfiguration();
+
+ configuration.setBrokerHost(MQTTConstants.BROKER_HOST);
+ configuration.setBrokerProtocol(MQTTConstants.BROKER_PROTOCOL);
+ configuration.setBrokerPort(MQTTConstants.BROKER_PORT);
+ configuration.setBrokerPassword(MQTTConstants.BROKER_PASSWORD);
+ configuration.setBrokerUserName(MQTTConstants.BROKER_USER_NAME);
+ configuration.setCleanSession(true);
+
+ return configuration;
+ }
+
+ /**
+ * Retrieve default MQTT client configurations and change if there are configuration changes in
+ * automation xml.
+ *
+ * @return Default MQTTClientConnectionConfigurations
+ */
+ public MQTTClientConnectionConfiguration getConfigurations(AutomationContext automationContext)
+ throws XPathExpressionException {
+
+ MQTTClientConnectionConfiguration configuration = getDefaultConfigurations();
+
+ String brokerHost = automationContext.getInstance().getHosts().get("default");
+
+ if (!brokerHost.isEmpty()) {
+ configuration.setBrokerHost(brokerHost);
+ }
+
+ if(!automationContext.getInstance().getPorts().get("mqtt").isEmpty()) {
+ configuration.setBrokerPort(automationContext.getInstance().getPorts().get("mqtt"));
+ }
+
+ return configuration;
+ }
+
+
+ /**
+ * Get received messages from all subscriber clients.
+ *
+ * @return Received messages
+ */
+ public List getReceivedMessages() {
+ List receivedMessages = new ArrayList();
+ for (AndesMQTTClient subscriber : subscriberList) {
+ receivedMessages.addAll(subscriber.getReceivedMessages());
+ }
+
+ return receivedMessages;
+ }
+
+ /**
+ * Get received message count from all subscribers.
+ *
+ * @return Received message count
+ */
+ public int getReceivedMessageCount() {
+ int count = 0;
+
+ for (AndesMQTTClient subscriber : subscriberList) {
+ count = count + subscriber.getReceivedMessageCount();
+ }
+
+ return count;
+ }
+
+ /**
+ * Get sent message count from all publishers.
+ *
+ * @return Sent message count
+ */
+ public int getSentMessageCount() {
+ int count = 0;
+
+ for (AndesMQTTClient publisher : publisherList) {
+ count = count + publisher.getSentMessageCount();
+ }
+
+ return count;
+ }
+
+ /**
+ * Get all the subscribers.
+ * Use if needed to directly handle subscribers.
+ *
+ * @return MQTTSubscriberClient list
+ */
+ public List getSubscriberList() {
+ return subscriberList;
+ }
+
+ /**
+ * Get all the publishers.
+ * Use if needed to directly handle publishers.
+ *
+ * @return MQTTPublisherClient list
+ */
+ public List getPublisherList() {
+ return publisherList;
+ }
+
+ /**
+ * Wait for subscribers to receive all the messages and disconnect all clients.
+ * Use in test cases before doing assertions so message send/receive will be completed before assertions.
+ *
+ * @see MQTTClientEngine#waitUntilAllMessageReceived()
+ *
+ * @throws MqttException
+ */
+ public void waitUntilAllMessageReceivedAndShutdownClients() throws MqttException {
+ waitUntilAllMessageReceived();
+ shutdown();
+ }
+
+ /**
+ * Wait for subscribers to receive all the messages that have been sent.
+ * Use in test cases before doing assertions so message send/receive will be completed before assertions
+ * but needs the clients to be connected for further cases.
+ *
+ * Detect all the messages are received by checking message count in each 10 second iterations.
+ * If message count doesn't change in two consecutive rounds it will be decided that all the messages that the
+ * server has sent is received.
+ *
+ * If no messages are received, will lookout for 20 seconds for message and return.
+ */
+ public void waitUntilAllMessageReceived() {
+ int previousMessageCount = 0;
+ int currentMessageCount = -1;
+
+ // Check each 10 second if new messages have been received, if not disconnect clients.
+ // If no message are received this will wait for 20 seconds before shutting down clients.
+ while (currentMessageCount != previousMessageCount) {
+ try {
+ TimeUnit.SECONDS.sleep(10);
+ } catch (InterruptedException e) {
+ log.error("Error waiting for receiving messages.", e);
+ }
+ previousMessageCount = currentMessageCount;
+ currentMessageCount = getReceivedMessageCount();
+ }
+ }
+
+ /**
+ * Wait for subscriber to receive given number of messages and exit.
+ * Use in test cases before doing assertions so message send/receive will be completed before
+ * assertions.
+ *
+ * This method will exit regardless of the number of messages received if maximum wait time
+ * is reached.
+ *
+ * @param expectedNumberOfMessages expected number of messages to be received by subscriber.
+ * @param maxWaitTime maximum wait time in milliseconds before stop waiting for messages.
+ * @throws org.eclipse.paho.client.mqttv3.MqttException
+ */
+ public void waitUntilExpectedNumberOfMessagesReceived(int expectedNumberOfMessages,
+ long maxWaitTime) throws MqttException {
+
+ // max system wait time
+ long maxWaitSystemTime = System.currentTimeMillis() + maxWaitTime;
+
+ // this loop will exit if system time is larger or equal than maximum system wait time.
+ while (System.currentTimeMillis() <= maxWaitSystemTime) {
+ try {
+
+ TimeUnit.MILLISECONDS.sleep(2000L);
+
+ } catch (InterruptedException e) {
+ log.error("Error waiting for receiving messages.", e);
+ }
+
+ // if expected number of messages received by the subscriber it will break the loop.
+ // without waiting further.
+ if (expectedNumberOfMessages <= getReceivedMessageCount()) {
+ log.info("Expected message count received by subscriber.");
+ break;
+ }
+
+ }
+
+ }
+
+ /**
+ * Calculate the TPS for the last (messageCount) messages.
+ *
+ * @param timeDiffMillis Time took in milliseconds to receive (messageCount) messages.
+ * @return Transactions Per Second
+ */
+ private double calculateTPS(long timeDiffMillis, int messageCount) {
+ return ((double) messageCount) / ((double) timeDiffMillis / MILLISECONDS_TO_A_SECOND);
+ }
+
+ /**
+ * Start publishing message send/receive TPS.
+ */
+ private void startTPSPublisher() {
+ // scheduling each second will be too much details, but greater than 10 will be too less details, hence 5
+ final int scheduleTimeInSeconds = 5;
+ tpsPublisherSchedule = scheduleExecutor.scheduleAtFixedRate(new Runnable() {
+ @Override
+ public void run() {
+ int currentReceivedMessageCount = getReceivedMessageCount();
+ int currentSentMessageCount = getSentMessageCount();
+
+ if (currentReceivedMessageCount != previousReceivedMessageCount) {
+ double receiveTPS = calculateTPS(scheduleTimeInSeconds * MILLISECONDS_TO_A_SECOND,
+ currentReceivedMessageCount - previousReceivedMessageCount);
+ log.info("Message Receiving TPS for the last " + scheduleTimeInSeconds + " seconds : " +
+ receiveTPS);
+
+ previousReceivedMessageCount = currentReceivedMessageCount;
+ }
+
+ if (currentSentMessageCount != previousSentMessageCount) {
+ double sentTPS = calculateTPS(scheduleTimeInSeconds * MILLISECONDS_TO_A_SECOND,
+ currentSentMessageCount - previousSentMessageCount);
+ log.info("Message Sending TPS for the last " + scheduleTimeInSeconds + " seconds : " + sentTPS);
+
+ previousSentMessageCount = currentSentMessageCount;
+ }
+ }
+ }, 0, scheduleTimeInSeconds, TimeUnit.SECONDS);
+ }
+
+ /**
+ * Shutdown all the clients.
+ * Invoke when message send/receive is complete or shutdown hook is triggered.
+ *
+ * @throws MqttException
+ */
+ public void shutdown() throws MqttException {
+
+ for (AndesMQTTClient subscriberClient : subscriberList) {
+ subscriberClient.disconnect();
+ }
+
+ for (AndesMQTTClient publisherClient : publisherList) {
+ publisherClient.disconnect();
+ }
+
+ tpsPublisherSchedule.cancel(true);
+ scheduleExecutor.shutdown();
+ }
+}
diff --git a/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/MQTTConstants.java b/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/MQTTConstants.java
new file mode 100755
index 00000000..6d228da7
--- /dev/null
+++ b/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/MQTTConstants.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.wso2.mb.integration.common.clients;
+
+/**
+ * Constants for MQTT tests.
+ */
+public class MQTTConstants {
+
+ public static final String BROKER_PROTOCOL = "tcp";
+ public static final String BROKER_HOST = "localhost";
+ public static final String BROKER_PORT = "1883";
+ public static final String BROKER_PASSWORD = "admin";
+ public static final String BROKER_USER_NAME = "admin";
+
+ public static final byte[] TEMPLATE_PAYLOAD = "hello".getBytes();
+ public static final byte[] EMPTY_PAYLOAD = "".getBytes();
+
+ /**
+ * Maximum length of a MQTT client Id defined by MQTT 3.1 specifications
+ */
+ public static final int CLIENT_ID_LENGTH = 23;
+
+ // Print message send/receive details on each 1000 messages
+ public static final int MESSAGE_PRINT_LIMIT = 1000;
+
+ /***
+ * Timeout for an MQTT client to connect to the broker.
+ */
+ public static final long CLIENT_CONNECT_TIMEOUT = 1000;
+}
diff --git a/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/QualityOfService.java b/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/QualityOfService.java
new file mode 100644
index 00000000..ea8adf24
--- /dev/null
+++ b/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/QualityOfService.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.wso2.mb.integration.common.clients;
+
+/**
+ * The quality of service levels in MQTT.
+ */
+public enum QualityOfService {
+
+ /**
+ * The message is delivered at most once, or it may not be delivered at all. Its delivery across the network is
+ * not acknowledged. The message is not stored. The message could be lost if the client is disconnected,
+ * or if the server fails. QoS0 is the fastest mode of transfer. It is sometimes called "fire and forget".
+ */
+ MOST_ONCE(0),
+
+ /**
+ * The message is always delivered at least once. It might be delivered multiple times if there is a failure
+ * before an acknowledgment is received by the sender. The message must be stored locally at the sender,
+ * until the sender receives confirmation that the message has been published by the receiver. The message is
+ * stored in case the message must be sent again.
+ */
+ LEAST_ONCE(1),
+
+ /**
+ * The message is always delivered exactly once. The message must be stored locally at the sender,
+ * until the sender receives confirmation that the message has been published by the receiver. The message is
+ * stored in case the message must be sent again. QoS2 is the safest, but slowest mode of transfer. A more
+ * sophisticated handshaking and acknowledgement sequence is used than for QoS1 to ensure no duplication of
+ * messages occurs.
+ */
+ EXACTLY_ONCE(2);
+
+ private final int qos;
+
+ /**
+ * Initialize with the given Quality of Service.
+ *
+ * @param qos The quality of service level
+ */
+ private QualityOfService(int qos) {
+ this.qos = qos;
+ }
+
+ /**
+ * Get the corresponding value for the given quality of service.
+ * Retrieve this value whenever quality of service level needs to feed into external libraries.
+ *
+ * @return The integer representation of this quality of service
+ */
+ public int getValue() {
+ return qos;
+ }
+}
\ No newline at end of file
diff --git a/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/configurations/AndesJMSClientConfiguration.java b/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/configurations/AndesJMSClientConfiguration.java
new file mode 100644
index 00000000..ae2cae23
--- /dev/null
+++ b/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/configurations/AndesJMSClientConfiguration.java
@@ -0,0 +1,526 @@
+/*
+* Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+*
+* WSO2 Inc. licenses this file to you under the Apache License,
+* Version 2.0 (the "License"); you may not use this file except
+* in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT 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.wso2.mb.integration.common.clients.configurations;
+
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.commons.configuration.XMLConfiguration;
+import org.wso2.mb.integration.common.clients.operations.utils.AndesClientConstants;
+import org.wso2.mb.integration.common.clients.exceptions.AndesClientConfigurationException;
+import org.wso2.mb.integration.common.clients.operations.utils.ExchangeType;
+
+/**
+ * This class acts as a configuration class for the Andes Client. The class contains configuration
+ * that is common for both JMS publishers and consumer. The configuration mentioned are related to
+ * JMS only.
+ */
+public class AndesJMSClientConfiguration implements Cloneable {
+
+ /**
+ * The destination name to be used when a configuration is not passed to the client.
+ */
+ private static final String TEMP_DESTINATION_NAME = "temporaryDestination";
+
+ /**
+ * The AMQP transport port.
+ */
+ private int port;
+
+ /**
+ * The host name for the AMQP transport.
+ */
+ private String hostName;
+
+ /**
+ * The user name used when creating the AMQP connection string. Publishing/Consuming of JMS will
+ * be done under this username.
+ */
+ private String userName;
+
+ /**
+ * The password used when creating the AMQP connection string.
+ */
+ private String password;
+
+ /**
+ * The connection string used for publishing/consuming jms messages
+ */
+ private String connectionString;
+
+ /**
+ * The exchange type used to describe the destination type
+ */
+ private ExchangeType exchangeType;
+
+ /**
+ * The destination name for which messages are published/consumed
+ */
+ private String destinationName;
+
+ /**
+ * The amount of console logging for a certain message count
+ */
+ private long printsPerMessageCount;
+
+ /**
+ * A delay value which can be used to delay of publishing/consuming jms messages
+ */
+ private long runningDelay;
+
+ /**
+ * The file path to write statistics. Statistics include TPS, latency, etc.
+ */
+ private String filePathToWriteStatistics;
+
+ /**
+ * The query string for the amqp connection string. Used during SSL connections.
+ */
+ private String queryStringForConnection = "";
+
+ /**
+ * The empty constructor which will create a queue related test case.
+ */
+ public AndesJMSClientConfiguration() {
+ this(ExchangeType.QUEUE, TEMP_DESTINATION_NAME);
+ }
+
+ /**
+ * Creates a connection string with the default username, password, hostname, port. Also sets
+ * the exchange type and destination name for publishing/consuming jms messages.
+ *
+ * @param exchangeType The exchange type.
+ * @param destinationName The destination name.
+ */
+ public AndesJMSClientConfiguration(ExchangeType exchangeType, String destinationName) {
+ this(AndesClientConstants.DEFAULT_USERNAME, AndesClientConstants.DEFAULT_PASSWORD,
+ AndesClientConstants.DEFAULT_HOST_NAME, AndesClientConstants.DEFAULT_PORT,
+ exchangeType, destinationName);
+ }
+
+ /**
+ * Creates a connection string with default username, password and a given host name, port. Also
+ * sets exchangeType and destination name used for publishing/consuming jms messages.
+ *
+ * @param hostName The host name used in the AMQP transport connection string.
+ * @param port The port used in the AMQP transport connection string.
+ * @param exchangeType The exchange type used for publishing/consuming jms messages.
+ * @param destinationName The destination name used for publishing/consuming jms messages.
+ */
+ public AndesJMSClientConfiguration(String hostName, int port, ExchangeType exchangeType,
+ String destinationName) {
+ this(AndesClientConstants.DEFAULT_USERNAME, AndesClientConstants.DEFAULT_PASSWORD, hostName,
+ port, exchangeType, destinationName);
+ }
+
+ /**
+ * Creates a connection string with default username, password, hostname and a given port. Also
+ * sets exchangeType and destination name used for publishing/consuming jms messages.
+ *
+ * @param port The port used in the AMQP transport connection string.
+ * @param exchangeType The exchange type used for publishing/consuming jms messages.
+ * @param destinationName The destination name used for publishing/consuming jms messages.
+ */
+ public AndesJMSClientConfiguration(int port, ExchangeType exchangeType,
+ String destinationName) {
+ this(AndesClientConstants.DEFAULT_USERNAME, AndesClientConstants.DEFAULT_PASSWORD,
+ AndesClientConstants.DEFAULT_HOST_NAME, port, exchangeType, destinationName);
+ }
+
+ /**
+ * Creates a connection string with a given username, password, exchange type
+ * and destination name.
+ *
+ * @param userName The username to be used in creating the connection string.
+ * @param password The password to be used in creating the connection string.
+ * @param exchangeType The exchange type.
+ * @param destinationName The destination name.
+ */
+ public AndesJMSClientConfiguration(String userName, String password,ExchangeType exchangeType,
+ String destinationName) {
+ this(userName, password, AndesClientConstants.DEFAULT_HOST_NAME,
+ AndesClientConstants.DEFAULT_PORT, exchangeType, destinationName);
+ }
+
+ /**
+ * Creates a connection string with a given port, username, password, exchange type
+ * and destination name.
+ *
+ * @param userName The username to be used in creating the connection string.
+ * @param password The password to be used in creating the connection string.
+ * @param exchangeType The exchange type.
+ * @param destinationName The destination name.
+ */
+ public AndesJMSClientConfiguration(int port, String userName, String password,ExchangeType exchangeType,
+ String destinationName) {
+ this(userName, password, AndesClientConstants.DEFAULT_HOST_NAME,
+ port, exchangeType, destinationName);
+ }
+
+ /**
+ * Creates a connection string with a given username, password, hostname, port, exchange type
+ * and destination name.
+ *
+ * @param userName The username to be used in creating the connection string.
+ * @param password The password to be used in creating the connection string.
+ * @param hostName The host name to be used in creating the connection string.
+ * @param port The AMQP transport port used in creating the connection string
+ * @param exchangeType The exchange type.
+ * @param destinationName The destination name.
+ */
+ public AndesJMSClientConfiguration(String userName, String password, String hostName,
+ int port, ExchangeType exchangeType,
+ String destinationName) {
+ // Setting values for exchange type and destination name
+ this.exchangeType = exchangeType;
+ this.destinationName = destinationName;
+
+ // Creating connection string
+ this.userName = userName;
+ this.password = password;
+ this.hostName = hostName;
+ this.port = port;
+ this.createConnectionString();
+
+ // Setting default values
+ this.printsPerMessageCount = 1L;
+ this.runningDelay = 0L;
+ }
+
+ /**
+ * Creates a connection string using an xml file.
+ *
+ * @param xmlConfigFilePath The file path for the xml configuration file.
+ * @throws AndesClientConfigurationException
+ */
+ public AndesJMSClientConfiguration(String xmlConfigFilePath)
+ throws AndesClientConfigurationException {
+ try {
+ XMLConfiguration config = new XMLConfiguration(xmlConfigFilePath);
+
+ // Setting values for exchange type and destination name
+ this.exchangeType = ExchangeType.valueOf(config.getString("base.exchangeType", "QUEUE"));
+ this.destinationName = config.getString("base.destinationName", TEMP_DESTINATION_NAME);
+
+ // Creating connection string
+ this.userName =
+ config.getString("base.userName", AndesClientConstants.DEFAULT_USERNAME);
+ this.password =
+ config.getString("base.password", AndesClientConstants.DEFAULT_PASSWORD);
+ this.hostName =
+ config.getString("base.hostName", AndesClientConstants.CARBON_VIRTUAL_HOST_NAME);
+ this.port = config.getInt("base.port", AndesClientConstants.DEFAULT_PORT);
+ this.queryStringForConnection = config.getString("base.queryStringForConnection", "");
+ this.createConnectionString();
+
+ // Setting default values
+ this.printsPerMessageCount = config.getLong("base.printsPerMessageCount", 1L);
+ this.runningDelay = config.getLong("base.runningDelay", 0L);
+ } catch (ConfigurationException e) {
+ throw new AndesClientConfigurationException("Error in reading xml configuration file. Make sure the file exists.", e);
+ } catch (IllegalArgumentException e) {
+ throw new AndesClientConfigurationException("Invalid exchange type used. Use either 'QUEUE' or 'TOPIC'.", e);
+ }
+ }
+
+ /**
+ * Copy constructor for the client.
+ *
+ * @param config The configuration file.
+ */
+ public AndesJMSClientConfiguration(
+ AndesJMSClientConfiguration config) {
+ this.connectionString = config.getConnectionString();
+ this.exchangeType = config.getExchangeType();
+ this.destinationName = config.getDestinationName();
+ this.printsPerMessageCount = config.getPrintsPerMessageCount();
+ this.runningDelay = config.getRunningDelay();
+ }
+
+ /**
+ * Creates an SSL connection string with a given username, password, hostname, port, exchange
+ * type and destination name.
+ *
+ * @param userName The username to be used in creating the connection string.
+ * @param password The password to be used in creating the connection string.
+ * @param hostName The host name to be used in creating the connection string.
+ * @param port The AMQP transport port used in creating the connection string
+ * @param exchangeType The exchange type.
+ * @param destinationName The destination name.
+ * @param sslAlias The ssl alias to use in ssl connection.
+ * @param trustStorePath The file path for trust store to use in ssl connection.
+ * @param trustStorePassword The trust store password to use in ssl connection.
+ * @param keyStorePath The file path for key store to use in ssl connection.
+ * @param keyStorePassword The key store password to use in ssl connection.
+ */
+ public AndesJMSClientConfiguration(String userName, String password, String hostName, int port,
+ ExchangeType exchangeType, String destinationName,
+ String sslAlias,
+ String trustStorePath, String trustStorePassword,
+ String keyStorePath, String keyStorePassword) {
+ // Setting values for exchange type and destination name
+ this.exchangeType = exchangeType;
+ this.destinationName = destinationName;
+
+ // Creating connection string
+ this.userName = userName;
+ this.password = password;
+ this.hostName = hostName;
+ this.port = port;
+ if ((keyStorePath == null) || (keyStorePassword == null)) {
+ this.queryStringForConnection = "?ssl='true'" +
+ "&ssl_cert_alias='" + sslAlias + "'&trust_store='" + trustStorePath +
+ "'&trust_store_password='" + trustStorePassword + "'";
+ } else {
+ this.queryStringForConnection = "?ssl='true'" +
+ "&ssl_cert_alias='" + sslAlias + "'&trust_store='" + trustStorePath +
+ "'&trust_store_password='" +
+ trustStorePassword + "'&key_store='" + keyStorePath +
+ "'&key_store_password='" + keyStorePassword + "'";
+ }
+ this.createConnectionString();
+
+ // Setting default values
+ this.printsPerMessageCount = 1L;
+ this.runningDelay = 0L;
+ }
+
+ /**
+ * Creates an AMQP connection string.
+ */
+ private void createConnectionString() {
+ this.connectionString = "amqp://" + this.userName + ":" + this.password + "@" +
+ AndesClientConstants.CARBON_CLIENT_ID + "/" +
+ AndesClientConstants.CARBON_VIRTUAL_HOST_NAME +
+ "?brokerlist='tcp://" +
+ this.hostName + ":" + this.port + this.queryStringForConnection + "'";
+ }
+
+ /**
+ * Sets user name for the AMQP connection string
+ *
+ * @param userName The user name.
+ */
+ public void setUserName(String userName) {
+ this.userName = userName;
+ this.createConnectionString();
+ }
+
+ /**
+ * Sets password for the AMQP connection string
+ *
+ * @param password The password
+ */
+ public void setPassword(String password) {
+ this.password = password;
+ this.createConnectionString();
+ }
+
+ /**
+ * Sets host name for the AMQP connection string.
+ * Suppressing "UnusedDeclaration" warning as the client can be exported and used.
+ *
+ * @param hostName The host name
+ */
+ @SuppressWarnings("UnusedDeclaration")
+ public void setHostName(String hostName) {
+ this.hostName = hostName;
+ this.createConnectionString();
+ }
+
+ /**
+ * Sets the AMQP connection string port.
+ *
+ * @param port the port.
+ */
+ public void setPort(int port) {
+ this.port = port;
+ this.createConnectionString();
+ }
+
+ /**
+ * Gets the user name used in the AMQP connection string.
+ *
+ * @return The user name.
+ */
+ public String getUserName() {
+ return this.userName;
+ }
+
+ /**
+ * Gets the password used in the AMQP connection string.
+ *
+ * @return The password.
+ */
+ public String getPassword() {
+ return this.password;
+ }
+
+ /**
+ * Gets the host name used in the AMQP connection string.
+ * Suppressing "UnusedDeclaration" warning as the client can be exported and used.
+ *
+ * @return The host name.
+ */
+ @SuppressWarnings("UnusedDeclaration")
+ public String getHostName() {
+ return this.hostName;
+ }
+
+ /**
+ * Gets the port used in the AMQP connection string.
+ *
+ * @return The port name.
+ */
+ public int getPort() {
+ return this.port;
+ }
+
+ /**
+ * Gets the AMQP connection string.
+ *
+ * @return The connection string.
+ */
+ public String getConnectionString() {
+ return connectionString;
+ }
+
+ /**
+ * Sets the AMQP transport connection string.
+ *
+ * @param connectionString The connection string.
+ */
+ public void setConnectionString(String connectionString) {
+ this.connectionString = connectionString;
+ }
+
+ /**
+ * Gets the exchange type used for publishing/consuming jms messages.
+ *
+ * @return The exchange type
+ */
+ public ExchangeType getExchangeType() {
+ return exchangeType;
+ }
+
+ /**
+ * Sets the exchange type used for publishing/consuming jms messages Suppressing
+ * "UnusedDeclaration" as this is a configuration
+ *
+ * @param exchangeType The exchange type
+ */
+ @SuppressWarnings("UnusedDeclaration")
+ public void setExchangeType(ExchangeType exchangeType) {
+ this.exchangeType = exchangeType;
+ }
+
+ /**
+ * Gets the destination name for publishing/consuming jms messages.
+ *
+ * @return The destination name.
+ */
+ public String getDestinationName() {
+ return destinationName;
+ }
+
+ /**
+ * Sets the destination name for publishing/consuming jms messages.
+ *
+ * @param destinationName The destination name
+ */
+ public void setDestinationName(String destinationName) {
+ this.destinationName = destinationName;
+ }
+
+ /**
+ * Gets the number of console logging per message count
+ *
+ * @return The number of console logging per message count
+ */
+ public long getPrintsPerMessageCount() {
+ return this.printsPerMessageCount;
+ }
+
+ /**
+ * Sets the number of console logging per message count
+ *
+ * @param printsPerMessageCount The number of console logging per message count
+ * @throws org.wso2.mb.integration.common.clients.exceptions.AndesClientConfigurationException
+ */
+ public void setPrintsPerMessageCount(long printsPerMessageCount) throws
+ AndesClientConfigurationException {
+ if (0 < printsPerMessageCount) {
+ this.printsPerMessageCount = printsPerMessageCount;
+ } else {
+ throw new AndesClientConfigurationException("Prints per message count cannot be less than one");
+ }
+ }
+
+ /**
+ * Gets the delay used in publishing/consuming messages in milliseconds.
+ *
+ * @return the delay used in publishing/consuming messages in milliseconds.
+ */
+ public long getRunningDelay() {
+ return runningDelay;
+ }
+
+ /**
+ * Sets the delay used in publishing/consuming messages in milliseconds.
+ *
+ * @param runningDelay The delay used in publishing/consuming messages in milliseconds.
+ * @throws org.wso2.mb.integration.common.clients.exceptions.AndesClientConfigurationException
+ */
+ public void setRunningDelay(long runningDelay) throws AndesClientConfigurationException {
+ if (0 <= runningDelay) {
+ this.runningDelay = runningDelay;
+ } else {
+ throw new AndesClientConfigurationException("Running delay cannot be less than 0");
+ }
+ }
+
+ /**
+ * Gets the file path to write statistics such as TPS, Average latency against Timestamp.
+ *
+ * @return The file path used for writing statistics.
+ */
+ public String getFilePathToWriteStatistics() {
+ return filePathToWriteStatistics;
+ }
+
+ /**
+ * Sets the file path to write statistics such as TPS, Average latency against Timestamp
+ * Suppressing "UnusedDeclaration" as this is a configuration
+ *
+ * @param filePathToPrintStatistics The file path used for writing statistics.
+ */
+ @SuppressWarnings("UnusedDeclaration")
+ public void setFilePathToWriteStatistics(String filePathToPrintStatistics) {
+ this.filePathToWriteStatistics = filePathToPrintStatistics;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ return "ConnectionString=" + this.connectionString + "\n" + "ExchangeType=" +
+ this.exchangeType + "\n" + "PrintsPerMessageCount=" + this.printsPerMessageCount
+ +"\n" + "DestinationName=" + this.destinationName +
+ "\n" + "RunningDelay=" + this.runningDelay + "\n";
+ }
+}
diff --git a/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/configurations/AndesJMSConsumerClientConfiguration.java b/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/configurations/AndesJMSConsumerClientConfiguration.java
new file mode 100644
index 00000000..db1cce91
--- /dev/null
+++ b/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/configurations/AndesJMSConsumerClientConfiguration.java
@@ -0,0 +1,551 @@
+/*
+* Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+*
+* WSO2 Inc. licenses this file to you under the Apache License,
+* Version 2.0 (the "License"); you may not use this file except
+* in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT 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.wso2.mb.integration.common.clients.configurations;
+
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.commons.configuration.XMLConfiguration;
+import org.apache.commons.lang.StringUtils;
+import org.apache.log4j.Logger;
+import org.wso2.mb.integration.common.clients.exceptions.AndesClientConfigurationException;
+import org.wso2.mb.integration.common.clients.operations.utils.ExchangeType;
+import org.wso2.mb.integration.common.clients.operations.utils.JMSAcknowledgeMode;
+
+/**
+ * This class represents the Andes client consumer configuration. The class contains properties
+ * related to JMS message consuming.
+ */
+public class AndesJMSConsumerClientConfiguration extends AndesJMSClientConfiguration {
+ /**
+ * The logger used in logging information, warnings, errors and etc.
+ */
+ private static Logger log = Logger.getLogger(AndesJMSConsumerClientConfiguration.class);
+
+ /**
+ * Message count at which the consumer un-subscribes.
+ */
+ private long unSubscribeAfterEachMessageCount = Long.MAX_VALUE;
+
+ /**
+ * Message count at which the session is rolled back.
+ */
+ private long rollbackAfterEachMessageCount = Long.MAX_VALUE;
+
+ /**
+ * Message count at which the session is committed.
+ */
+ private long commitAfterEachMessageCount = Long.MAX_VALUE;
+
+ /**
+ * Message count at which a message is acknowledge.
+ */
+ private long acknowledgeAfterEachMessageCount = Long.MAX_VALUE;
+
+ /**
+ * The file path to write received messages.
+ */
+ private String filePathToWriteReceivedMessages = null;
+
+ /**
+ * Maximum messages to receiver.
+ */
+ private long maximumMessagesToReceived = Long.MAX_VALUE;
+
+ /**
+ * Subscription ID for durable topics.
+ */
+ private String subscriptionID = null;
+
+ /**
+ * Whether the subscriber is durable.
+ */
+ private boolean durable = false;
+
+ /**
+ * The acknowledge mode for messages.
+ */
+ private JMSAcknowledgeMode acknowledgeMode = JMSAcknowledgeMode.AUTO_ACKNOWLEDGE;
+
+ /**
+ * Whether the consumer is asynchronously reading messages. Asynchronous message reading implies
+ * that it uses {@link javax.jms.MessageListener} to listen to receiving messages. Synchronous
+ * message reading will use a while loop inside a thread.
+ */
+ private boolean async = false;
+
+ /**
+ * JMS selectors string for filtering.
+ */
+ private String selectors = null;
+
+ /**
+ * Creates a consumer configuration with default values.
+ */
+ public AndesJMSConsumerClientConfiguration() {
+ super();
+ }
+
+ /**
+ * Creates a consumer with a given exchange type and destination with default connection string.
+ *
+ * @param exchangeType The exchange type.
+ * @param destinationName The destination name.
+ */
+ public AndesJMSConsumerClientConfiguration(
+ ExchangeType exchangeType, String destinationName) {
+ super(exchangeType, destinationName);
+ }
+
+ /**
+ * Creates a consumer with a given host name, port for connection string and exchange type and
+ * destination name.
+ *
+ * @param hostName The host name for connection string.
+ * @param port The port for the connection string.
+ * @param exchangeType The exchange type.
+ * @param destinationName The destination name.
+ */
+ public AndesJMSConsumerClientConfiguration(String hostName, int port,
+ ExchangeType exchangeType,
+ String destinationName) {
+ super(hostName, port, exchangeType, destinationName);
+ }
+
+ /**
+ * Creates a consumer with a given port for connection string and exchange type and
+ * destination name.
+ *
+ * @param port The port for the connection string.
+ * @param exchangeType The exchange type.
+ * @param destinationName The destination name.
+ */
+ public AndesJMSConsumerClientConfiguration( int port,
+ ExchangeType exchangeType,
+ String destinationName) {
+ super(port, exchangeType, destinationName);
+ }
+
+
+ /**
+ * Creates a consumer with a given username, password, for connection
+ * string and exchange type and destination name.
+ *
+ * @param userName The user name for the connection string.
+ * @param password The password for the connection string.
+ * @param exchangeType The exchange type.
+ * @param destinationName The destination name.
+ */
+ public AndesJMSConsumerClientConfiguration(String userName, String password,
+ ExchangeType exchangeType,
+ String destinationName) {
+ super(userName, password, exchangeType, destinationName);
+ }
+
+ /**
+ * Creates a consumer with a given port, username, password, for connection
+ * string and exchange type and destination name.
+ *
+ * @param userName The user name for the connection string.
+ * @param password The password for the connection string.
+ * @param exchangeType The exchange type.
+ * @param destinationName The destination name.
+ */
+ public AndesJMSConsumerClientConfiguration(int port, String userName, String password,
+ ExchangeType exchangeType,
+ String destinationName) {
+ super(port, userName, password, exchangeType, destinationName);
+ }
+
+
+ /**
+ * Creates a consumer with a given user name, password, host name, port for connection
+ * string and exchange type and destination name.
+ *
+ * @param userName The user name for the connection string.
+ * @param password The password for the connection string.
+ * @param hostName The host name for the connection string.
+ * @param port The port for the connection string.
+ * @param exchangeType The exchange type.
+ * @param destinationName The destination name.
+ */
+ public AndesJMSConsumerClientConfiguration(String userName, String password,
+ String hostName, int port,
+ ExchangeType exchangeType,
+ String destinationName) {
+ super(userName, password, hostName, port, exchangeType, destinationName);
+ }
+
+ /**
+ * Creates a configuration for a consumer using an xml file.
+ *
+ * @param xmlConfigFilePath The file path for the xml configuration file path.
+ * @throws AndesClientConfigurationException
+ */
+ public AndesJMSConsumerClientConfiguration(String xmlConfigFilePath)
+ throws AndesClientConfigurationException {
+ super(xmlConfigFilePath);
+ try {
+ XMLConfiguration config = new XMLConfiguration(xmlConfigFilePath);
+
+ this.unSubscribeAfterEachMessageCount = config.getLong("base.consumer.unSubscribeAfterEachMessageCount", Long.MAX_VALUE);
+ this.rollbackAfterEachMessageCount = config.getLong("base.consumer.rollbackAfterEachMessageCount", Long.MAX_VALUE);
+ this.commitAfterEachMessageCount = config.getLong("base.consumer.commitAfterEachMessageCount", Long.MAX_VALUE);
+ this.acknowledgeAfterEachMessageCount = config.getLong("base.consumer.acknowledgeAfterEachMessageCount", Long.MAX_VALUE);
+ this.filePathToWriteReceivedMessages = config.getString("base.consumer.filePathToWriteReceivedMessages", null);
+ this.maximumMessagesToReceived = config.getLong("base.consumer.maximumMessagesToReceived", Long.MAX_VALUE);
+ this.subscriptionID = config.getString("base.consumer.subscriptionID", null);
+ this.durable = config.getBoolean("base.consumer.durable", false);
+ this.async = config.getBoolean("base.consumer.async", true);
+ this.selectors = config.getString("base.consumer.selectors", null);
+ this.acknowledgeMode = JMSAcknowledgeMode.valueOf(config.getString("base.consumer.acknowledgeMode", "AUTO_ACKNOWLEDGE"));
+ } catch (ConfigurationException e) {
+ throw new AndesClientConfigurationException("Error in reading xml configuration file. Make sure the file exists.", e);
+ } catch (IllegalArgumentException e) {
+ throw new AndesClientConfigurationException("Invalid acknowledge mode used. Use a value either of the values : SESSION_TRANSACTED, AUTO_ACKNOWLEDGE, CLIENT_ACKNOWLEDGE, DUPS_OK_ACKNOWLEDGE", e);
+ }
+ }
+
+ /**
+ * The copy constructor for the JMS base class. This will copy all attributes defined in another
+ * configuration only for the base client.
+ *
+ * @param config The configuration to be copied.
+ */
+ public AndesJMSConsumerClientConfiguration(
+ AndesJMSClientConfiguration config) {
+ super(config);
+ }
+
+ /**
+ * Creates a JMS message consumer with a given AMQP transport connection string for SSL and a
+ * given exchange type and destination.
+ *
+ * @param userName The user name for the connection string.
+ * @param password The password for the connection string.
+ * @param hostName The host name for the connection string.
+ * @param port The port for the connection string.
+ * @param exchangeType The exchange type.
+ * @param destinationName The destination name.
+ * @param sslAlias The ssl alias to use in ssl connection.
+ * @param trustStorePath The file path for trust store to use in ssl connection.
+ * @param trustStorePassword The trust store password to use in ssl connection.
+ * @param keyStorePath The file path for key store to use in ssl connection.
+ * @param keyStorePassword The key store password to use in ssl connection.
+ */
+ public AndesJMSConsumerClientConfiguration(String userName, String password, String hostName,
+ int port,
+ ExchangeType exchangeType, String destinationName,
+ String sslAlias, String trustStorePath,
+ String trustStorePassword, String keyStorePath,
+ String keyStorePassword) {
+ super(userName, password, hostName, port, exchangeType, destinationName, sslAlias,
+ trustStorePath, trustStorePassword, keyStorePath, keyStorePassword);
+
+ }
+
+ /**
+ * Gets the message count to un-subscribe the consumer.
+ *
+ * @return The message count to un-subscribe the consumer.
+ */
+ public long getUnSubscribeAfterEachMessageCount() {
+ return unSubscribeAfterEachMessageCount;
+ }
+
+ /**
+ * Sets message count to un-subscribe the consumer.
+ *
+ * @param unSubscribeAfterEachMessageCount The message count to un-subscribe the consumer.
+ * @throws org.wso2.mb.integration.common.clients.exceptions.AndesClientConfigurationException
+ */
+ public void setUnSubscribeAfterEachMessageCount(long unSubscribeAfterEachMessageCount)
+ throws AndesClientConfigurationException {
+ if (0 < unSubscribeAfterEachMessageCount) {
+ this.unSubscribeAfterEachMessageCount = unSubscribeAfterEachMessageCount;
+ } else {
+ throw new AndesClientConfigurationException("Value cannot be less than 0");
+ }
+ }
+
+ /**
+ * Gets the message count at which the session should be rolled-back.
+ *
+ * @return The message count at which the session should be rolled-back.
+ */
+ public long getRollbackAfterEachMessageCount() {
+ return rollbackAfterEachMessageCount;
+ }
+
+ /**
+ * Sets message count at which the session should be rolled-back.
+ *
+ * @param rollbackAfterEachMessageCount The message count at which the session should be
+ * rolled-back.
+ * @throws org.wso2.mb.integration.common.clients.exceptions.AndesClientConfigurationException
+ */
+ public void setRollbackAfterEachMessageCount(long rollbackAfterEachMessageCount)
+ throws AndesClientConfigurationException {
+ if (0 < rollbackAfterEachMessageCount) {
+ this.rollbackAfterEachMessageCount = rollbackAfterEachMessageCount;
+ } else {
+ throw new AndesClientConfigurationException("Value cannot be less than 0");
+ }
+ }
+
+ /**
+ * Gets the message count at which the session should be committed.
+ *
+ * @return The message count at which the session should be committed.
+ */
+ public long getCommitAfterEachMessageCount() {
+ return commitAfterEachMessageCount;
+ }
+
+ /**
+ * Sets the message count at which the session should be committed.
+ *
+ * @param commitAfterEachMessageCount The message count at which the session should be
+ * committed.
+ * @throws org.wso2.mb.integration.common.clients.exceptions.AndesClientConfigurationException
+ */
+ public void setCommitAfterEachMessageCount(long commitAfterEachMessageCount)
+ throws AndesClientConfigurationException {
+ if (0 < commitAfterEachMessageCount) {
+ this.commitAfterEachMessageCount = commitAfterEachMessageCount;
+ } else {
+ throw new AndesClientConfigurationException("Value cannot be less than 0");
+ }
+ }
+
+ /**
+ * Gets the message count at which a message should be acknowledged after.
+ *
+ * @return The the message count at which a message should be acknowledged after.
+ */
+ public long getAcknowledgeAfterEachMessageCount() {
+ return acknowledgeAfterEachMessageCount;
+ }
+
+ /**
+ * Sets the message count at which a message should be acknowledged after.
+ *
+ * @param acknowledgeAfterEachMessageCount The the message count at which a message should be
+ * acknowledged after.
+ * @throws org.wso2.mb.integration.common.clients.exceptions.AndesClientConfigurationException
+ */
+ public void setAcknowledgeAfterEachMessageCount(long acknowledgeAfterEachMessageCount)
+ throws AndesClientConfigurationException {
+ if (0 < acknowledgeAfterEachMessageCount) {
+ this.acknowledgeAfterEachMessageCount = acknowledgeAfterEachMessageCount;
+ } else {
+ throw new AndesClientConfigurationException("Value cannot be less than 0");
+ }
+ }
+
+ /**
+ * Gets the file path where the received messages should be written to,
+ *
+ * @return The file path where the received messages should be written to,
+ */
+ public String getFilePathToWriteReceivedMessages() {
+ return filePathToWriteReceivedMessages;
+ }
+
+ /**
+ * Sets the file path where the received messages should be written to,
+ *
+ * @param filePathToWriteReceivedMessages The file path where the received messages should be
+ * written to,
+ */
+ public void setFilePathToWriteReceivedMessages(String filePathToWriteReceivedMessages) {
+ this.filePathToWriteReceivedMessages = filePathToWriteReceivedMessages;
+ }
+
+ /**
+ * Gets the maximum number of messages to received.
+ *
+ * @return The maximum number of messages to received.
+ */
+ public long getMaximumMessagesToReceived() {
+ return this.maximumMessagesToReceived;
+ }
+
+ /**
+ * Sets the maximum number of messages to received.
+ *
+ * @param maximumMessagesToReceived The maximum number of messages to received.
+ * @throws org.wso2.mb.integration.common.clients.exceptions.AndesClientConfigurationException
+ */
+ public void setMaximumMessagesToReceived(long maximumMessagesToReceived)
+ throws AndesClientConfigurationException {
+ if (0 < maximumMessagesToReceived) {
+ this.maximumMessagesToReceived = maximumMessagesToReceived;
+ } else {
+ throw new AndesClientConfigurationException("The maximum number of messages to receive " +
+ "cannot be less than 1");
+ }
+ }
+
+ /**
+ * Gets the subscription ID.
+ *
+ * @return The subscription ID.
+ */
+ public String getSubscriptionID() {
+ return subscriptionID;
+ }
+
+ /**
+ * Sets the subscription ID
+ *
+ * @param subscriptionID The subscription ID
+ * @throws org.wso2.mb.integration.common.clients.exceptions.AndesClientConfigurationException
+ */
+ public void setSubscriptionID(String subscriptionID) throws AndesClientConfigurationException {
+ if (this.durable) {
+ if (StringUtils.isNotEmpty(subscriptionID)) {
+ this.subscriptionID = subscriptionID;
+ } else {
+ throw new AndesClientConfigurationException("Subscription ID cannot be null or empty " +
+ "for an durable topic");
+ }
+ } else {
+ this.subscriptionID = subscriptionID;
+ log.warn("Setting subscription ID for non-durable topics. Subscription ID is not " +
+ "necessary for non-durable topics or queues");
+ }
+ }
+
+ /**
+ * Checks whether the subscriber/consumer is durable.
+ *
+ * @return true if subscriber/consumer is durable, false otherwise.
+ */
+ public boolean isDurable() {
+ return durable;
+ }
+
+ /**
+ * Sets values for a durable subscription
+ *
+ * @param durable True if subscription is durable, false otherwise.
+ * @param subscriptionID The subscription ID.
+ * @throws org.wso2.mb.integration.common.clients.exceptions.AndesClientConfigurationException
+ */
+ public void setDurable(boolean durable, String subscriptionID) throws
+ AndesClientConfigurationException {
+ if (durable) {
+ if (StringUtils.isNotEmpty(subscriptionID)) {
+ this.subscriptionID = subscriptionID;
+ } else {
+ throw new AndesClientConfigurationException("Subscription ID cannot be null or empty " +
+ "for an durable topic");
+ }
+ }
+
+ this.durable = durable;
+ }
+
+ /**
+ * Gets acknowledge mode for messages.
+ *
+ * @return The acknowledge mode for messages.
+ */
+ public JMSAcknowledgeMode getAcknowledgeMode() {
+ return acknowledgeMode;
+ }
+
+ /**
+ * Sets acknowledge mode for messages.
+ *
+ * @param acknowledgeMode The acknowledge mode for messages.
+ * @throws org.wso2.mb.integration.common.clients.exceptions.AndesClientConfigurationException
+ */
+ public void setAcknowledgeMode(JMSAcknowledgeMode acknowledgeMode)
+ throws AndesClientConfigurationException {
+ this.acknowledgeMode = acknowledgeMode;
+ }
+
+ /**
+ * Checks whether consumer is asynchronously reading messages.
+ *
+ * @return true if messages are read asynchronously, false otherwise. Asynchronously message
+ * reading implies that it uses {@link javax.jms.MessageListener} to listen to receiving
+ * messages.
+ */
+ public boolean isAsync() {
+ return async;
+ }
+
+ /**
+ * Sets the consumer to read message asynchronously. Asynchronously message
+ * reading implies that it uses {@link javax.jms.MessageListener} to listen to receiving
+ * messages.
+ * Suppressing "UnusedDeclaration" as this is a configuration
+ *
+ * @param async true if messages should be read asynchronously, false otherwise.
+ */
+ @SuppressWarnings("UnusedDeclaration")
+ public void setAsync(boolean async) {
+ this.async = async;
+ }
+
+ /**
+ * Gets the selectors query used by the consumer for filtering.
+ *
+ * @return The selectors query used by the consumer for filtering.
+ */
+ public String getSelectors() {
+ return selectors;
+ }
+
+ /**
+ * Sets the selectors query used by the consumer for filtering.
+ *
+ * @param selectors The selectors query used by the consumer for filtering.
+ */
+ public void setSelectors(String selectors) {
+ this.selectors = selectors;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ return super.toString() +
+ "UnSubscribeAfterEachMessageCount=" + this.unSubscribeAfterEachMessageCount + "\n" +
+ "RollbackAfterEachMessageCount=" + this.rollbackAfterEachMessageCount + "\n" +
+ "CommitAfterEachMessageCount=" + this.commitAfterEachMessageCount + "\n" +
+ "AcknowledgeAfterEachMessageCount=" + this.acknowledgeAfterEachMessageCount + "\n" +
+ "FilePathToWriteReceivedMessages=" + this.filePathToWriteReceivedMessages + "\n" +
+ "MaximumMessagesToReceived=" + this.maximumMessagesToReceived + "\n" +
+ "SubscriptionID=" + this.subscriptionID + "\n" +
+ "Durable=" + this.durable + "\n" +
+ "AcknowledgeMode=" + this.acknowledgeMode + "\n" +
+ "Async=" + this.async + "\n" +
+ "Selectors=" + this.selectors + "\n";
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public AndesJMSConsumerClientConfiguration clone() throws CloneNotSupportedException {
+ return (AndesJMSConsumerClientConfiguration) super.clone();
+ }
+}
diff --git a/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/configurations/AndesJMSPublisherClientConfiguration.java b/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/configurations/AndesJMSPublisherClientConfiguration.java
new file mode 100644
index 00000000..1d559b72
--- /dev/null
+++ b/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/configurations/AndesJMSPublisherClientConfiguration.java
@@ -0,0 +1,426 @@
+/*
+* Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+*
+* WSO2 Inc. licenses this file to you under the Apache License,
+* Version 2.0 (the "License"); you may not use this file except
+* in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT 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.wso2.mb.integration.common.clients.configurations;
+
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.commons.configuration.XMLConfiguration;
+import org.wso2.mb.integration.common.clients.exceptions.AndesClientConfigurationException;
+import org.wso2.mb.integration.common.clients.operations.utils.ExchangeType;
+import org.wso2.mb.integration.common.clients.operations.utils.JMSMessageType;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class represents the Andes client publisher configuration. The class contains properties
+ * related to JMS message publishing/sending.
+ */
+public class AndesJMSPublisherClientConfiguration extends AndesJMSClientConfiguration {
+
+ /**
+ * File path to read a string content which would be used to as message content when publishing.
+ */
+ private String readMessagesFromFilePath = null;
+
+ /**
+ * JMS message type. Text will be used as default message type.
+ */
+ private JMSMessageType jmsMessageType = JMSMessageType.TEXT;
+
+ /**
+ * Number of messages to be sent by the publisher.
+ */
+ private long numberOfMessagesToSend = 10L;
+
+ /**
+ * The message expiry time.
+ */
+ private long jmsMessageExpiryTime = 0L;
+
+ /**
+ * File path to write messages that are being published
+ */
+ private String filePathToWritePublishedMessages = null;
+
+ /**
+ * Whether the session needs to be transactional or not.
+ */
+ private boolean transactionalSession;
+
+ /**
+ * List of JMS Header properties to set when publishing message
+ */
+ private List JMSHeaderProperties;
+
+ /**
+ * Holds JMSType property to set for JMS messages published
+ */
+ private String JMSType;
+
+ /**
+ * Creates a connection string with default properties.
+ */
+ public AndesJMSPublisherClientConfiguration() {
+ super();
+ }
+
+ /**
+ * Creates a publisher with a given exchange type and destination with default connection
+ * string.
+ *
+ * @param exchangeType The exchange type.
+ * @param destinationName The destination name.
+ */
+ public AndesJMSPublisherClientConfiguration(
+ ExchangeType exchangeType, String destinationName) {
+ super(exchangeType, destinationName);
+ JMSHeaderProperties = new ArrayList(5);
+ }
+
+ /**
+ * Creates a publisher with a given host name, port for connection string and exchange type and
+ * destination name.
+ *
+ * @param hostName The host name for connection string.
+ * @param port The port for the connection string.
+ * @param exchangeType The exchange type.
+ * @param destinationName The destination name.
+ */
+ public AndesJMSPublisherClientConfiguration(String hostName, int port,
+ ExchangeType exchangeType,
+ String destinationName) {
+ super(hostName, port, exchangeType, destinationName);
+ JMSHeaderProperties = new ArrayList(5);
+ }
+
+ /**
+ * Creates a publisher with a given host name, port for connection string and exchange type and
+ * destination name.
+ *
+ * @param port The port for the connection string.
+ * @param exchangeType The exchange type.
+ * @param destinationName The destination name.
+ */
+ public AndesJMSPublisherClientConfiguration(int port,
+ ExchangeType exchangeType,
+ String destinationName) {
+ super(port, exchangeType, destinationName);
+ JMSHeaderProperties = new ArrayList(5);
+ }
+
+ /**
+ * Creates a publisher with a given username, password, for connection
+ * string and exchange type and destination name.
+ *
+ * @param userName The user name for the connection string.
+ * @param password The password for the connection string.
+ * @param exchangeType The exchange type.
+ * @param destinationName The destination name.
+ */
+ public AndesJMSPublisherClientConfiguration(String userName, String password,
+ ExchangeType exchangeType,
+ String destinationName) {
+ super(userName, password, exchangeType, destinationName);
+ JMSHeaderProperties = new ArrayList(5);
+ }
+
+ /**
+ * Creates a publisher with a given port, username, password, for connection
+ * string and exchange type and destination name.
+ *
+ * @param userName The user name for the connection string.
+ * @param password The password for the connection string.
+ * @param exchangeType The exchange type.
+ * @param destinationName The destination name.
+ */
+ public AndesJMSPublisherClientConfiguration(int port, String userName, String password,
+ ExchangeType exchangeType,
+ String destinationName) {
+ super(port, userName, password, exchangeType, destinationName);
+ JMSHeaderProperties = new ArrayList(5);
+ }
+
+ /**
+ * Creates a publisher with a given user name, password, host name, password for connection
+ * string and exchange type and destination name.
+ *
+ * @param userName The user name for the connection string.
+ * @param password The password for the connection string.
+ * @param hostName The host name for the connection string.
+ * @param port The port for the connection string.
+ * @param exchangeType The exchange type.
+ * @param destinationName The destination name.
+ */
+ public AndesJMSPublisherClientConfiguration(String userName, String password,
+ String hostName, int port,
+ ExchangeType exchangeType,
+ String destinationName) {
+ super(userName, password, hostName, port, exchangeType, destinationName);
+ JMSHeaderProperties = new ArrayList(5);
+ }
+
+ /**
+ * Creates a configuration for a publisher using an xml file.
+ *
+ * @param xmlConfigFilePath The file path for the xml configuration file path.
+ * @throws AndesClientConfigurationException
+ */
+ public AndesJMSPublisherClientConfiguration(String xmlConfigFilePath)
+ throws AndesClientConfigurationException {
+ super(xmlConfigFilePath);
+ try {
+ XMLConfiguration config = new XMLConfiguration(xmlConfigFilePath);
+
+ numberOfMessagesToSend = config.getLong("base.publisher.numberOfMessagesToSend", 10L);
+ jmsMessageExpiryTime = config.getLong("base.publisher.jmsMessageExpiryTime", 0L);
+ readMessagesFromFilePath = config.getString("base.publisher.readMessagesFromFilePath", null);
+ jmsMessageType = JMSMessageType.valueOf(config.getString("base.publisher.jmsMessageType", "TEXT"));
+ filePathToWritePublishedMessages = config.getString("base.publisher.filePathToWritePublishedMessages", null);
+ JMSHeaderProperties = new ArrayList(5);
+ } catch (ConfigurationException e) {
+ throw new AndesClientConfigurationException("Error in reading xml configuration file. Make sure the file exists.", e);
+ } catch (IllegalArgumentException e) {
+ throw new AndesClientConfigurationException("Invalid message type used. Use either 'TEXT', 'BYTE', 'MAP', 'OBJECT' or 'STREAM'.", e);
+ }
+ }
+
+ /**
+ * The copy constructor for the JMS base class. This will copy all attributes defined in another
+ * configuration only for the base client.
+ *
+ * @param config The configuration to be copied.
+ */
+ public AndesJMSPublisherClientConfiguration(
+ AndesJMSClientConfiguration config) {
+ super(config);
+ JMSHeaderProperties = new ArrayList(5);
+ }
+
+ /**
+ * Creates a JMS message publisher with a given AMQP transport connection string for SSL and a
+ * given exchange type and destination.
+ *
+ * @param userName The user name for the connection string.
+ * @param password The password for the connection string.
+ * @param hostName The host name for the connection string.
+ * @param port The port for the connection string.
+ * @param exchangeType The exchange type.
+ * @param destinationName The destination name.
+ * @param sslAlias The ssl alias to use in ssl connection.
+ * @param trustStorePath The file path for trust store to use in ssl connection.
+ * @param trustStorePassword The trust store password to use in ssl connection.
+ * @param keyStorePath The file path for key store to use in ssl connection.
+ * @param keyStorePassword The key store password to use in ssl connection.
+ */
+ public AndesJMSPublisherClientConfiguration(String userName, String password, String hostName,
+ int port,
+ ExchangeType exchangeType, String destinationName,
+ String sslAlias, String trustStorePath,
+ String trustStorePassword, String keyStorePath,
+ String keyStorePassword) {
+ super(userName, password, hostName, port, exchangeType, destinationName, sslAlias,
+ trustStorePath, trustStorePassword, keyStorePath, keyStorePassword);
+ JMSHeaderProperties = new ArrayList(5);
+ }
+
+ /**
+ * Gets the file path to read a string content which would be used to as message content when
+ * publishing.
+ *
+ * @return The file path.
+ */
+ public String getReadMessagesFromFilePath() {
+ return readMessagesFromFilePath;
+ }
+
+ /**
+ * Sets the file path to read a string content which would be used to as message content when
+ * publishing.
+ *
+ * @param readMessagesFromFilePath The file path.
+ * @throws org.wso2.mb.integration.common.clients.exceptions.AndesClientConfigurationException
+ * @throws FileNotFoundException
+ */
+ public void setReadMessagesFromFilePath(String readMessagesFromFilePath)
+ throws AndesClientConfigurationException, FileNotFoundException {
+ File messagesFilePath = new File(readMessagesFromFilePath);
+ if (messagesFilePath.exists() && !messagesFilePath.isDirectory()) {
+ this.readMessagesFromFilePath = readMessagesFromFilePath;
+ } else {
+ throw new FileNotFoundException("File is missing : " + messagesFilePath);
+ }
+ }
+
+ /**
+ * Gets JMS message type.
+ *
+ * @return JMS message type.
+ */
+ public JMSMessageType getJMSMessageType() {
+ return jmsMessageType;
+ }
+
+ /**
+ * Set a header property to the messages published
+ *
+ * @param key key of the header
+ * @param value value of the header
+ * @param type type of the header (Boolean, Integer, Long etc)
+ */
+ public void setJMSHeaderProperty(String key, Object value, JMSHeaderPropertyType type) {
+ JMSHeaderProperties.add(new JMSHeaderProperty(key, value, type));
+ }
+
+ /**
+ * Set JMS Type to be set for publishing messages
+ * @link https://docs.oracle.com/javaee/6/api/javax/jms/Message.html#setJMSType(java.lang.String)
+ *
+ * @param jmsType jmsType to set
+ */
+ public void setJMSType(String jmsType) {
+ this.JMSType = jmsType;
+ }
+
+ /**
+ * Get JMS type
+ *
+ * @return JMS type as a string
+ */
+ public String getJMSType() {
+ return JMSType;
+ }
+
+ /**
+ * Sets JMS message type.
+ *
+ * @param jmsMessageType JMS message type
+ */
+ public void setJMSMessageType(JMSMessageType jmsMessageType) {
+ this.jmsMessageType = jmsMessageType;
+ }
+
+ /**
+ * Gets the number of messages to be sent by the publisher.
+ *
+ * @return The number of messages.
+ */
+ public long getNumberOfMessagesToSend() {
+ return numberOfMessagesToSend;
+ }
+
+ /**
+ * Sets the number of messages to be sent by the publisher
+ *
+ * @param numberOfMessagesToSend The number of messages.
+ * @throws org.wso2.mb.integration.common.clients.exceptions.AndesClientConfigurationException
+ */
+ public void setNumberOfMessagesToSend(long numberOfMessagesToSend)
+ throws AndesClientConfigurationException {
+ if (0 < numberOfMessagesToSend) {
+ this.numberOfMessagesToSend = numberOfMessagesToSend;
+ } else {
+ throw new AndesClientConfigurationException("The number of messages to send cannot be less" +
+ " than 1");
+ }
+ }
+
+ /**
+ * Gets the file path where published messages are written.
+ *
+ * @return The file path.
+ */
+ public String getFilePathToWritePublishedMessages() {
+ return filePathToWritePublishedMessages;
+ }
+
+ /**
+ * Sets the file path to write messages that are being published by the client.
+ * Suppressing "UnusedDeclaration" warning as the client can be exported and used.
+ *
+ * @param filePathToWritePublishedMessages The file path
+ */
+ @SuppressWarnings("UnusedDeclaration")
+ public void setFilePathToWritePublishedMessages(String filePathToWritePublishedMessages) {
+ this.filePathToWritePublishedMessages = filePathToWritePublishedMessages;
+ }
+
+ /**
+ * Gets the messages expiry time.
+ *
+ * @return The message expiry time.
+ */
+ public long getJMSMessageExpiryTime() {
+ return jmsMessageExpiryTime;
+ }
+
+ /**
+ * Sets the message expiry time.
+ *
+ * @param jmsMessageExpiryTime The message expiry time.
+ * @throws org.wso2.mb.integration.common.clients.exceptions.AndesClientConfigurationException
+ */
+ public void setJMSMessageExpiryTime(long jmsMessageExpiryTime) throws
+ AndesClientConfigurationException {
+ if (0 <= jmsMessageExpiryTime) {
+ this.jmsMessageExpiryTime = jmsMessageExpiryTime;
+ } else {
+ throw new AndesClientConfigurationException("Message expiry time cannot be less than 0");
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ return super.toString() +
+ "ReadMessagesFromFilePath=" + this.readMessagesFromFilePath + "\n" +
+ "JmsMessageType=" + this.jmsMessageType + "\n" +
+ "NumberOfMessagesToSend=" + this.numberOfMessagesToSend + "\n" +
+ "JmsMessageExpiryTime=" + this.jmsMessageExpiryTime + "\n";
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public AndesJMSPublisherClientConfiguration clone() throws CloneNotSupportedException {
+ return (AndesJMSPublisherClientConfiguration) super.clone();
+ }
+
+ /**
+ * Whether the session needs to be transactional or not.
+ */
+ public boolean isTransactionalSession() {
+ return transactionalSession;
+ }
+
+ /**
+ * Set the session transactional. This is for publishers
+ * @param transactionalSession true if session needs to be transactional and false otherwise
+ */
+ public void setTransactionalSession(boolean transactionalSession) {
+ this.transactionalSession = transactionalSession;
+ }
+
+ public List getJMSHeaderProperties() {
+ return JMSHeaderProperties;
+ }
+}
diff --git a/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/configurations/JMSHeaderProperty.java b/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/configurations/JMSHeaderProperty.java
new file mode 100644
index 00000000..a25b66f0
--- /dev/null
+++ b/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/configurations/JMSHeaderProperty.java
@@ -0,0 +1,74 @@
+/*
+ *
+ * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.wso2.mb.integration.common.clients.configurations;
+
+/**
+ * This class represents configuration of a JMS Header property. JMS sender reads them and set
+ * when sending a JMS message to the provider
+ */
+public class JMSHeaderProperty {
+
+ private String key;
+
+ private Object value;
+
+ private JMSHeaderPropertyType type;
+
+ /**
+ * Create a new JMSHeaderProperty.
+ *
+ * @param key key of the header to be set to message
+ * @param value value of the header to be set to message
+ * @param type type of the header to be set to message
+ */
+ public JMSHeaderProperty(String key, Object value, JMSHeaderPropertyType type) {
+ this.key = key;
+ this.value = value;
+ this.type = type;
+ }
+
+ /**
+ * Get Key of the header property
+ *
+ * @return key as a string
+ */
+ public String getKey() {
+ return key;
+ }
+
+ /**
+ * Get value of the header property
+ *
+ * @return value as a Object
+ */
+ public Object getValue() {
+ return value;
+ }
+
+ /**
+ * Get property of the header property. Long, String, Integer etc
+ *
+ * @return Property type
+ */
+ public JMSHeaderPropertyType getType() {
+ return type;
+ }
+}
diff --git a/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/configurations/JMSHeaderPropertyType.java b/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/configurations/JMSHeaderPropertyType.java
new file mode 100644
index 00000000..98586f97
--- /dev/null
+++ b/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/configurations/JMSHeaderPropertyType.java
@@ -0,0 +1,46 @@
+/*
+ *
+ * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.wso2.mb.integration.common.clients.configurations;
+
+/**
+ * Keeps the type of the JMS header property. According to JMS spec headers of different types
+ * can be set
+ */
+public enum JMSHeaderPropertyType {
+
+ OBJECT,
+
+ SHORT,
+
+ STRING,
+
+ INTEGER,
+
+ LONG,
+
+ BOOLEAN,
+
+ BYTE,
+
+ DOUBLE,
+
+ FLOAT
+}
diff --git a/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/exceptions/AndesClientConfigurationException.java b/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/exceptions/AndesClientConfigurationException.java
new file mode 100644
index 00000000..de23840d
--- /dev/null
+++ b/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/exceptions/AndesClientConfigurationException.java
@@ -0,0 +1,73 @@
+/*
+* Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+*
+* WSO2 Inc. licenses this file to you under the Apache License,
+* Version 2.0 (the "License"); you may not use this file except
+* in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT 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.wso2.mb.integration.common.clients.exceptions;
+
+/**
+ * Exception class for andes client configuration.
+ */
+public class AndesClientConfigurationException extends Exception {
+
+ /**
+ * Error message for exception
+ */
+ public String errorMessage;
+
+ /**
+ * Creates Andes configuration exception
+ */
+ public AndesClientConfigurationException() {
+ }
+
+ /**
+ * Creates Andes configuration exception with error message
+ *
+ * @param message Error message
+ */
+ public AndesClientConfigurationException(String message) {
+ super(message);
+ errorMessage = message;
+ }
+
+ /**
+ * Creates Andes configuration exception with error message and throwable
+ *
+ * @param message Error message
+ * @param cause The throwable
+ */
+ public AndesClientConfigurationException(String message, Throwable cause) {
+ super(message, cause);
+ errorMessage = message;
+ }
+
+ /**
+ * Creates Andes configuration exception with throwable.
+ *
+ * @param cause The throwable
+ */
+ public AndesClientConfigurationException(Throwable cause) {
+ super(cause);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getMessage() {
+ return errorMessage;
+ }
+}
\ No newline at end of file
diff --git a/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/exceptions/AndesClientException.java b/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/exceptions/AndesClientException.java
new file mode 100644
index 00000000..47350125
--- /dev/null
+++ b/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/exceptions/AndesClientException.java
@@ -0,0 +1,55 @@
+package org.wso2.mb.integration.common.clients.exceptions;
+
+/**
+ * Exception class for andes client.
+ */
+public class AndesClientException extends Exception {
+ /**
+ * Error message for exception
+ */
+ public String errorMessage;
+
+ /**
+ * Creates Andes exception
+ */
+ public AndesClientException() {
+ }
+
+ /**
+ * Creates Andes exception with error message
+ *
+ * @param message Error message
+ */
+ public AndesClientException(String message) {
+ super(message);
+ errorMessage = message;
+ }
+
+ /**
+ * Creates Andes exception with error message and throwable
+ *
+ * @param message Error message
+ * @param cause The throwable
+ */
+ public AndesClientException(String message, Throwable cause) {
+ super(message, cause);
+ errorMessage = message;
+ }
+
+ /**
+ * Creates Andes exception with throwable.
+ *
+ * @param cause The throwable
+ */
+ public AndesClientException(Throwable cause) {
+ super(cause);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getMessage() {
+ return errorMessage;
+ }
+}
diff --git a/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/operations/clients/AndesAdminClient.java b/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/operations/clients/AndesAdminClient.java
new file mode 100644
index 00000000..b021f9d9
--- /dev/null
+++ b/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/operations/clients/AndesAdminClient.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2005-2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.wso2.mb.integration.common.clients.operations.clients;
+
+import org.apache.axis2.AxisFault;
+import org.apache.axis2.client.Options;
+import org.apache.axis2.client.ServiceClient;
+import org.wso2.carbon.andes.stub.AndesAdminServiceBrokerManagerAdminException;
+import org.wso2.carbon.andes.stub.AndesAdminServiceStub;
+import org.wso2.carbon.andes.stub.admin.types.Message;
+import org.wso2.carbon.andes.stub.admin.types.Queue;
+import org.wso2.carbon.andes.stub.admin.types.QueueRolePermission;
+import org.wso2.mb.integration.common.clients.operations.clients.utils.AuthenticateStubUtil;
+
+import java.rmi.RemoteException;
+
+/**
+ * Andes Admin Client is a client which is used to contact the Andes Admin services
+ */
+public class AndesAdminClient {
+ String backendUrl = null;
+ String sessionCookie = null;
+ AndesAdminServiceStub stub = null;
+ public static final String PUBLISHER_ROLE = "publisher";
+
+ /**
+ * Initializes Andes Admin Client
+ *
+ * @param backendUrl the backend url
+ * @param sessionCookie the session cookie string
+ * @throws AxisFault
+ */
+ public AndesAdminClient(String backendUrl, String sessionCookie) throws AxisFault {
+
+ this.backendUrl = backendUrl + "AndesAdminService";
+ this.sessionCookie = sessionCookie;
+ stub = new AndesAdminServiceStub(this.backendUrl);
+ AuthenticateStubUtil.authenticateStub(sessionCookie, stub);
+ }
+
+ /**
+ * Creates a new queue
+ *
+ * @param queue new queue name
+ * @throws AndesAdminServiceBrokerManagerAdminException
+ * @throws RemoteException
+ */
+ public void createQueue(String queue)
+ throws AndesAdminServiceBrokerManagerAdminException, RemoteException {
+ // Add permission to be able to publish
+ QueueRolePermission queueRolePermission = new QueueRolePermission();
+ queueRolePermission.setRoleName(PUBLISHER_ROLE);
+ queueRolePermission.setAllowedToConsume(true);
+ queueRolePermission.setAllowedToPublish(true);
+ stub.addQueueAndAssignPermission(queue, new QueueRolePermission[]{queueRolePermission});
+ }
+
+ /**
+ * Gets messages in a queue
+ *
+ * @param queue the queue name
+ * @param startingIndex starting index of the messages to be returned
+ * @param maximumMessageCount maximum number of messages to return
+ * @return an array of messages
+ * @throws AndesAdminServiceBrokerManagerAdminException
+ * @throws RemoteException
+ */
+ public Message[] browseQueue(String queue, int startingIndex, int maximumMessageCount)
+ throws AndesAdminServiceBrokerManagerAdminException, RemoteException {
+ return stub.browseQueue(queue, startingIndex, maximumMessageCount);
+ }
+
+ /**
+ * Deletes a queue
+ *
+ * @param queue the queue name
+ * @throws AndesAdminServiceBrokerManagerAdminException
+ * @throws RemoteException
+ */
+ public void deleteQueue(String queue)
+ throws AndesAdminServiceBrokerManagerAdminException, RemoteException {
+ stub.deleteQueue(queue);
+ }
+
+ /**
+ * Deletes all messages in a queue
+ *
+ * @param queue the name of the queue
+ * @throws RemoteException
+ */
+ public void purgeQueue(String queue)
+ throws RemoteException, AndesAdminServiceBrokerManagerAdminException {
+ stub.purgeMessagesOfQueue(queue);
+ }
+
+ /**
+ * Get queue object by queue name
+ *
+ * @param name the name of the queue
+ * @return a queue
+ * @throws RemoteException
+ * @throws AndesAdminServiceBrokerManagerAdminException
+ */
+ public Queue getQueueByName(String name)
+ throws RemoteException, AndesAdminServiceBrokerManagerAdminException {
+ return stub.getQueueByName(name);
+ }
+
+ /**
+ * Updating permissions for a queue. Permissions may include publish, consume etc
+ *
+ * @param queueName queue name
+ * @param permissions new permissions
+ * @throws AndesAdminServiceBrokerManagerAdminException
+ * @throws RemoteException
+ */
+ public void updatePermissionForQueue(String queueName, QueueRolePermission permissions)
+ throws AndesAdminServiceBrokerManagerAdminException, RemoteException {
+ stub.updatePermission(queueName, new QueueRolePermission[]{permissions});
+ }
+
+ /**
+ * Adding session cookie to service client options
+ *
+ * @param client the service client
+ * @throws AxisFault
+ */
+ private void configureCookie(ServiceClient client) throws AxisFault {
+ if (sessionCookie != null) {
+ Options option = client.getOptions();
+ option.setManageSession(true);
+ option.setProperty(org.apache.axis2.transport.http.HTTPConstants.COOKIE_STRING,
+ sessionCookie);
+ }
+ }
+
+ /**
+ * Get dead letter channel queue
+ *
+ * @return queue
+ * @throws AndesAdminServiceBrokerManagerAdminException
+ * @throws java.rmi.RemoteException
+ */
+ public Queue getDlcQueue() throws AndesAdminServiceBrokerManagerAdminException,
+ java.rmi.RemoteException {
+ return stub.getDLCQueue();
+ }
+
+}
diff --git a/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/operations/clients/TopicAdminClient.java b/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/operations/clients/TopicAdminClient.java
new file mode 100644
index 00000000..d4268b9f
--- /dev/null
+++ b/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/operations/clients/TopicAdminClient.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2005-2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.wso2.mb.integration.common.clients.operations.clients;
+
+import org.apache.axis2.AxisFault;
+import org.apache.axis2.client.Options;
+import org.apache.axis2.client.ServiceClient;
+import org.wso2.carbon.andes.event.stub.core.TopicNode;
+import org.wso2.carbon.andes.event.stub.core.TopicRolePermission;
+import org.wso2.carbon.andes.event.stub.service.AndesEventAdminServiceEventAdminException;
+import org.wso2.carbon.andes.event.stub.service.AndesEventAdminServiceStub;
+
+import java.rmi.RemoteException;
+
+/**
+ * Topic Admin Client is a client which is used to contact the Topic Admin services
+ */
+public class TopicAdminClient {
+
+ String backendUrl = null;
+ String SessionCookie = null;
+ AndesEventAdminServiceStub stub = null;
+
+ /**
+ * Initializes Topic Admin Client
+ *
+ * @param backendUrl the backend url
+ * @param sessionCookie the session cookie string
+ * @throws AxisFault
+ */
+ public TopicAdminClient(String backendUrl, String sessionCookie) throws AxisFault {
+
+ this.backendUrl = backendUrl + "AndesEventAdminService.AndesEventAdminServiceHttpsSoap12Endpoint";
+ this.SessionCookie = sessionCookie;
+ stub = new AndesEventAdminServiceStub(this.backendUrl);
+ configureCookie(stub._getServiceClient());
+
+ }
+
+ /**
+ * Adds a new topic
+ *
+ * @param newTopicName new topic name
+ * @throws AndesEventAdminServiceEventAdminException
+ * @throws RemoteException
+ */
+ public void addTopic(String newTopicName)
+ throws AndesEventAdminServiceEventAdminException, RemoteException {
+ stub.addTopic(newTopicName);
+ }
+
+ /**
+ * Removes a topic
+ *
+ * @param topicName topic name
+ * @throws AndesEventAdminServiceEventAdminException
+ * @throws RemoteException
+ */
+ public void removeTopic(String topicName)
+ throws AndesEventAdminServiceEventAdminException, RemoteException {
+ stub.removeTopic(topicName);
+ }
+
+ /**
+ * Get topic node by topic name
+ *
+ * @param topicName the topic name
+ * @return a topic node
+ * @throws AndesEventAdminServiceEventAdminException
+ * @throws RemoteException
+ */
+ public TopicNode getTopicByName(String topicName)
+ throws AndesEventAdminServiceEventAdminException, RemoteException {
+ TopicNode[] topicNodes = stub.getAllTopics().getChildren();
+ if (topicNodes != null && topicNodes.length > 0) {
+ for (TopicNode topicNode : topicNodes) {
+ if (topicNode.getTopicName().equalsIgnoreCase(topicName)) {
+ return topicNode;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Updating permissions for a topic. Permissions may include publish, consume etc
+ *
+ * @param topicName topic name
+ * @param permissions new permissions
+ * @throws AndesEventAdminServiceEventAdminException
+ * @throws RemoteException
+ */
+ public void updatePermissionForTopic(String topicName, TopicRolePermission permissions)
+ throws AndesEventAdminServiceEventAdminException, RemoteException {
+ stub.updatePermission(topicName, new TopicRolePermission[]{permissions});
+ }
+
+ /**
+ * Adding session cookie to service client options
+ *
+ * @param client the service client
+ * @throws AxisFault
+ */
+ private void configureCookie(ServiceClient client) throws AxisFault {
+ if (SessionCookie != null) {
+ Options option = client.getOptions();
+ option.setManageSession(true);
+ option.setProperty(org.apache.axis2.transport.http.HTTPConstants.COOKIE_STRING,
+ SessionCookie);
+ }
+ }
+}
diff --git a/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/operations/clients/utils/AuthenticateStubUtil.java b/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/operations/clients/utils/AuthenticateStubUtil.java
new file mode 100644
index 00000000..4423f708
--- /dev/null
+++ b/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/operations/clients/utils/AuthenticateStubUtil.java
@@ -0,0 +1,68 @@
+/*
+* Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+*
+* WSO2 Inc. licenses this file to you under the Apache License,
+* Version 2.0 (the "License"); you may not use this file except
+* in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT 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.wso2.mb.integration.common.clients.operations.clients.utils;
+
+import org.apache.axis2.client.Options;
+import org.apache.axis2.client.ServiceClient;
+import org.apache.axis2.client.Stub;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.wso2.carbon.utils.CarbonUtils;
+
+/**
+ * This class is used to authenticate a web services so that it's stubs can be used.
+ * @see AuthenticateStubUtil
+ * for more other mehtods.
+ */
+public class AuthenticateStubUtil {
+
+ /**
+ * Info logger.
+ */
+ private static final Log log = LogFactory.getLog(AuthenticateStubUtil.class);
+
+ /**
+ * Stub authentication method
+ *
+ * @param stub valid stub
+ * @param sessionCookie session cookie
+ */
+ public static void authenticateStub(String sessionCookie, Stub stub) {
+ long soTimeout = 5 * 60 * 1000; // Three minutes
+
+ ServiceClient client = stub._getServiceClient();
+ Options option = client.getOptions();
+ option.setManageSession(true);
+ option.setTimeOutInMilliSeconds(soTimeout);
+ option.setProperty(org.apache.axis2.transport.http.HTTPConstants.COOKIE_STRING, sessionCookie);
+ if (log.isDebugEnabled()) {
+ log.debug("AuthenticateStub : Stub created with session " + sessionCookie);
+ }
+ }
+
+ /**
+ * Authenticate the given web service stub against the Product user manager. This
+ * will make it possible to use the stub for invoking Product admin services.
+ *
+ * @param stub Axis2 service stub which needs to be authenticated
+ */
+ public static void authenticateStub(String userName, String password, Stub stub) {
+ CarbonUtils.setBasicAccessSecurityHeaders(userName, password, stub._getServiceClient());
+ }
+}
diff --git a/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/operations/mqtt/async/AndesMQTTAsyncClient.java b/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/operations/mqtt/async/AndesMQTTAsyncClient.java
new file mode 100644
index 00000000..27cfcc15
--- /dev/null
+++ b/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/operations/mqtt/async/AndesMQTTAsyncClient.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.wso2.mb.integration.common.clients.operations.mqtt.async;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.eclipse.paho.client.mqttv3.*;
+import org.wso2.mb.integration.common.clients.QualityOfService;
+import org.wso2.mb.integration.common.clients.AndesMQTTClient;
+import org.wso2.mb.integration.common.clients.MQTTClientConnectionConfiguration;
+import org.wso2.mb.integration.common.clients.operations.mqtt.blocking.AndesMQTTBlockingClient;
+import org.wso2.mb.integration.common.clients.operations.mqtt.callback.CallbackHandler;
+
+/**
+ * Asynchronous publish/subscribe MQTT client.
+ *
+ * Each asynchronous publisher/subscriber should extend from this.
+ */
+public abstract class AndesMQTTAsyncClient extends AndesMQTTClient {
+
+ private final static Log log = LogFactory.getLog(AndesMQTTBlockingClient.class);
+
+ // Basic asynchronous mqtt client
+ protected MqttAsyncClient mqttClient;
+
+ /**
+ * Create a mqtt client initializing mqtt options.
+ *
+ * @param configuration MQTT configurations
+ * @param clientID The unique client Id
+ * @param topic Topic to subscribe/publish to
+ * @param qos The quality of service
+ * @param callbackHandler Callback Handler to handle receiving messages/message sending ack
+ * @throws MqttException
+ */
+ public AndesMQTTAsyncClient(MQTTClientConnectionConfiguration configuration, String clientID, String topic,
+ QualityOfService qos, CallbackHandler callbackHandler) throws MqttException {
+ super(configuration, clientID, topic, qos, callbackHandler);
+
+ // Construct MQTT client
+ mqttClient = new MqttAsyncClient(this.brokerUrl, clientID, dataStore);
+
+ // Connect to the MQTT server
+ connect();
+
+ mqttClient.setCallback(callbackHandler);
+ }
+
+ /**
+ * Publish message to broker using mqtt asynchronously.
+ *
+ * @param payload Data to send
+ * @param noOfMessages Number of message to send
+ * @throws MqttException
+ */
+ protected void publish(byte[] payload, int noOfMessages) throws MqttException {
+ log.info("Publishing to topic : " + topic + " on qos : " + qos);
+
+ if (null != payload) {
+
+ // Create and configure message
+ MqttMessage message = new MqttMessage(payload);
+ message.setQos(qos.getValue());
+ message.setRetained(retain);
+
+ for (int i = 0; i < noOfMessages; i++) {
+ // Send message to server, control is either returned or blocked until it has been delivered to the
+ // server depending on the MqttClient type (Blocking/Async)meeting the specified quality of service.
+ mqttClient.publish(topic, message);
+ }
+ }
+ }
+
+ /**
+ * Subscribe to a topic in an asynchronous manner.
+ *
+ * @throws MqttException
+ */
+ public void subscribe() throws MqttException {
+ log.info("Subscribing to topic \"" + topic + "\" qos " + qos);
+ IMqttToken subscriptionToken = mqttClient.subscribe(topic, qos.getValue());
+
+ // Wait until subscription is made. Otherwise test results will be unpredictable
+ subscriptionToken.waitForCompletion();
+
+ //Will need to wait to receive all messages - subscriber closes on disconnect
+ }
+
+ /**
+ * Asynchronously subscribe to a given topic.
+ *
+ * @param topicName The topic to subscribe to
+ * @throws MqttException
+ */
+ @Override
+ public void subscribe(String topicName) throws MqttException {
+ log.info("Subscribing to topic \"" + topicName + "\" qos " + qos);
+ IMqttToken subscriptionToken = mqttClient.subscribe(topicName, qos.getValue());
+
+ // Wait until subscription is made. Otherwise test results will be unpredictable
+ subscriptionToken.waitForCompletion();
+ }
+
+ /**
+ * Un-subscribe from the topic.
+ *
+ * @throws MqttException
+ */
+ public void unsubscribe() throws MqttException {
+ IMqttToken unsubscriptionToken = mqttClient.unsubscribe(topic);
+
+ // Wait until un-subscription is successful. Otherwise test results will be unpredictable.
+ unsubscriptionToken.waitForCompletion();
+ log.info("Subscriber for topic : " + topic + " un-subscribed");
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void unsubscribe(String topic) throws MqttException {
+ IMqttToken unsubscriptionToken = mqttClient.unsubscribe(topic);
+
+ // Wait until un-subscription is successful. Otherwise test results will be unpredictable.
+ unsubscriptionToken.waitForCompletion();
+ log.info("Subscriber for topic : " + topic + " un-subscribed");
+ }
+
+ /**
+ * Shutdown the mqtt client. Call this whenever the system exits, test cases are finished or disconnect hook is
+ * called.
+ *
+ * @throws MqttException
+ */
+ public void disconnect() throws MqttException {
+ if (isConnected()) {
+ IMqttToken disconnectionToken = mqttClient.disconnect();
+
+ // Wait until disconnect is complete
+ disconnectionToken.waitForCompletion();
+ log.info("Client " + mqttClientID + " Disconnected");
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void connect() throws MqttException {
+ if (!isConnected()) {
+ log.info("Connecting to " + brokerUrl + " with client ID " + mqttClientID);
+ IMqttToken connectionToken = mqttClient.connect(connectionOptions);
+
+ // Wait until connection is complete. Otherwise test results will be unpredictable
+ connectionToken.waitForCompletion();
+
+ log.info("Client " + mqttClientID + " Connected");
+ }
+ }
+
+ /**
+ * Use this to validate if connection to server is still active.
+ *
+ * @return Is MQTT client connected to the server
+ */
+ public boolean isConnected() {
+ return mqttClient.isConnected();
+ }
+
+}
diff --git a/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/operations/mqtt/async/MQTTAsyncPublisherClient.java b/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/operations/mqtt/async/MQTTAsyncPublisherClient.java
new file mode 100644
index 00000000..1097616c
--- /dev/null
+++ b/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/operations/mqtt/async/MQTTAsyncPublisherClient.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.wso2.mb.integration.common.clients.operations.mqtt.async;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.eclipse.paho.client.mqttv3.MqttException;
+import org.eclipse.paho.client.mqttv3.MqttMessage;
+import org.wso2.mb.integration.common.clients.QualityOfService;
+import org.wso2.mb.integration.common.clients.MQTTClientConnectionConfiguration;
+import org.wso2.mb.integration.common.clients.operations.mqtt.callback.CallbackHandler;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Asynchronous MQTT publisher client.
+ */
+public class MQTTAsyncPublisherClient extends AndesMQTTAsyncClient {
+
+ /** The payload to send as the message content **/
+ private byte[] messagePayLoad;
+
+ /** The number of messages to send **/
+ private int noOfMessages;
+
+ private static final Log log = LogFactory.getLog(MQTTAsyncPublisherClient.class);
+
+ /**
+ * Initialize publishing to mqtt.
+ *
+ * @param configuration MQTT configurations
+ * @param clientID Unique mqtt client Id
+ * @param topic Topic to publish to
+ * @param qos Quality of service
+ * @param payload Data to send
+ * @param noOfMessages Number of message to send
+ * @throws MqttException
+ */
+ public MQTTAsyncPublisherClient(MQTTClientConnectionConfiguration configuration, String clientID, String topic,
+ QualityOfService qos, byte[] payload, int noOfMessages) throws MqttException {
+ super(configuration, clientID, topic, qos, new CallbackHandler());
+ messagePayLoad = payload;
+ this.noOfMessages = noOfMessages;
+ }
+
+ /**
+ * Start the publisher to publish to mqtt.
+ */
+ @Override
+ public void run() {
+ try {
+ publish(messagePayLoad, noOfMessages);
+ } catch (MqttException e) {
+ log.error("Error publishing messages to " + getTopic() + " from " + getMqttClientID(), e);
+ }
+ }
+
+ /**
+ * Return subscription status as false since this is the publishing client.
+ *
+ * @return False
+ */
+ @Override
+ public boolean isSubscribed() {
+ return false;
+ }
+
+ /**
+ * Return empty as this is the publisher client and does not accept any messages.
+ *
+ * @return empty message list
+ */
+ @Override
+ public List getReceivedMessages() {
+ return Collections.emptyList();
+ }
+}
diff --git a/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/operations/mqtt/async/MQTTAsyncSubscriberClient.java b/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/operations/mqtt/async/MQTTAsyncSubscriberClient.java
new file mode 100644
index 00000000..488e437e
--- /dev/null
+++ b/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/operations/mqtt/async/MQTTAsyncSubscriberClient.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.wso2.mb.integration.common.clients.operations.mqtt.async;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.eclipse.paho.client.mqttv3.MqttException;
+import org.eclipse.paho.client.mqttv3.MqttMessage;
+import org.wso2.mb.integration.common.clients.QualityOfService;
+import org.wso2.mb.integration.common.clients.MQTTClientConnectionConfiguration;
+import org.wso2.mb.integration.common.clients.operations.mqtt.callback.CallbackHandler;
+
+import java.util.List;
+
+/**
+ * Asynchronous MQTT subscriber client.
+ */
+public class MQTTAsyncSubscriberClient extends AndesMQTTAsyncClient {
+
+ private static final Log log = LogFactory.getLog(MQTTAsyncSubscriberClient.class);
+
+ // Listening to the server for message or not
+ private boolean subscribed = false;
+
+ /**
+ * Initialize subscribing to mqtt.
+ *
+ * @param configuration MQTT configurations
+ * @param clientID Unique mqtt client Id
+ * @param topic Topic to subscribe to
+ * @param qos Quality of Service
+ * @param saveMessages Save receiving messages
+ * @throws MqttException
+ */
+ public MQTTAsyncSubscriberClient(MQTTClientConnectionConfiguration configuration, String clientID, String topic,
+ QualityOfService qos, boolean saveMessages) throws MqttException {
+ super(configuration, clientID, topic, qos, new CallbackHandler(saveMessages));
+ }
+
+ /**
+ * Get all the received messages through this client.
+ * Use this if want to validate message content.
+ *
+ * @return Received messages.
+ */
+ public List getReceivedMessages() {
+ return getCallbackHandler().getReceivedMessages();
+ }
+
+
+ /**
+ * Invokes client and subscribes to the given topic.
+ */
+ @Override
+ public void run() {
+ try {
+ subscribe();
+ subscribed = true;
+ } catch (MqttException e) {
+ log.error("Error subscribing to topic " + getTopic() + " from client " + getMqttClientID(), e);
+ }
+ }
+
+
+ /**
+ * Gracefully disconnect the client after un-subscribing to subscribed topic.
+ * Called through ClientEngine disconnect.
+ *
+ * @throws MqttException
+ */
+ @Override
+ public void disconnect() throws MqttException {
+ CallbackHandler callbackHandler = getCallbackHandler();
+ if (isConnected()) {
+ if (null != callbackHandler) {
+ log.info("No of messages received for client " + getMqttClientID() + " : " + callbackHandler
+ .getReceivedMessageCount());
+ }
+
+ unsubscribe();
+ subscribed = false;
+ mqttClient.disconnect();
+ log.info("Client " + getMqttClientID() + " Disconnected");
+ }
+ }
+
+ /**
+ * Check if the subscriber is subscribed to a topic
+ *
+ * @return Is Subscribed
+ */
+ public boolean isSubscribed() {
+ return subscribed;
+ }
+
+}
diff --git a/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/operations/mqtt/blocking/AndesMQTTBlockingClient.java b/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/operations/mqtt/blocking/AndesMQTTBlockingClient.java
new file mode 100644
index 00000000..f2350358
--- /dev/null
+++ b/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/operations/mqtt/blocking/AndesMQTTBlockingClient.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.wso2.mb.integration.common.clients.operations.mqtt.blocking;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.eclipse.paho.client.mqttv3.MqttClient;
+import org.eclipse.paho.client.mqttv3.MqttException;
+import org.eclipse.paho.client.mqttv3.MqttMessage;
+import org.wso2.mb.integration.common.clients.QualityOfService;
+import org.wso2.mb.integration.common.clients.AndesMQTTClient;
+import org.wso2.mb.integration.common.clients.MQTTClientConnectionConfiguration;
+import org.wso2.mb.integration.common.clients.operations.mqtt.callback.CallbackHandler;
+
+/**
+ * Blocking(synchronous) publish/subscribe MQTT client.
+ *
+ * Each blocking publisher/subscriber should extend from this.
+ */
+public abstract class AndesMQTTBlockingClient extends AndesMQTTClient {
+
+ private final static Log log = LogFactory.getLog(AndesMQTTBlockingClient.class);
+
+ protected MqttClient mqttClient;
+
+ /**
+ * Create a mqtt client initializing mqtt options.
+ *
+ * @param configuration MQTT configurations
+ * @param clientID The unique client Id
+ * @param topic Topic to subscribe/publish to
+ * @param qos The quality of service
+ * @param callbackHandler Callback Handler to handle receiving messages/message sending ack
+ * @throws MqttException
+ */
+ public AndesMQTTBlockingClient(MQTTClientConnectionConfiguration configuration, String clientID, String topic,
+ QualityOfService qos, CallbackHandler callbackHandler) throws MqttException {
+ super(configuration, clientID, topic, qos, callbackHandler);
+
+ // Construct MQTT client
+ mqttClient = new MqttClient(this.brokerUrl, clientID, dataStore);
+
+ // Connect to the MQTT server
+ connect();
+
+ mqttClient.setCallback(callbackHandler);
+ }
+
+ /**
+ * Publish message to broker using mqtt synchronously.
+ *
+ * @param payload Data to send
+ * @param noOfMessages Number of message to send
+ * @throws MqttException
+ */
+ protected void publish(byte[] payload, int noOfMessages) throws MqttException {
+ log.info("Publishing to topic : " + topic + " on qos : " + qos);
+
+ if (null != payload) {
+
+ // Create and configure message
+ MqttMessage message = new MqttMessage(payload);
+ message.setQos(qos.getValue());
+ message.setRetained(retain);
+
+ for (int i = 0; i < noOfMessages; i++) {
+ // Send message to server, control is either returned or blocked until it has been delivered to the
+ // server depending on the MqttClient type (Blocking/Async)meeting the specified quality of service.
+ mqttClient.publish(topic, message);
+ }
+ }
+ }
+
+ /**
+ * Subscribe to the requested topic in a synchronous manner.
+ *
+ * @throws MqttException
+ */
+ public void subscribe() throws MqttException {
+ log.info("Subscribing to topic \"" + topic + "\" qos " + qos);
+ mqttClient.subscribe(topic, qos.getValue());
+
+ //Will need to wait to receive all messages - subscriber closes on disconnect
+ }
+
+ /**
+ * Synchronously subscribe to a given topic.
+ *
+ * @param topicName The topic to subscribe to
+ * @throws MqttException
+ */
+ @Override
+ public void subscribe(String topicName) throws MqttException {
+ log.info("Subscribing to topic \"" + topicName + "\" on qos" + qos);
+ mqttClient.subscribe(topicName, qos.getValue());
+ }
+
+ /**
+ * Un-subscribe from the topic.
+ *
+ * @throws MqttException
+ */
+ public void unsubscribe() throws MqttException {
+ mqttClient.unsubscribe(topic);
+ log.info("Subscriber for topic : " + topic + " un-subscribed");
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void unsubscribe(String topic) throws MqttException {
+ mqttClient.unsubscribe(topic);
+ log.info("Subscriber for topic : " + topic + " un-subscribed");
+ }
+
+ /**
+ * Shutdown the mqtt client. Call this whenever the system exits, test cases are finished or disconnect hook is
+ * called.
+ *
+ * @throws MqttException
+ */
+ public void disconnect() throws MqttException {
+ if (isConnected()) {
+ mqttClient.disconnect();
+ log.info("Client " + mqttClientID + " Disconnected");
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void connect() throws MqttException {
+ log.info("Connecting to " + brokerUrl + " with client ID " + mqttClientID);
+ mqttClient.connect(connectionOptions);
+
+ log.info("Client " + mqttClientID + " Connected");
+ }
+
+ /**
+ * Use this to validate if connection to server is still active.
+ *
+ * @return Is MQTT client connected to the server
+ */
+ public boolean isConnected() {
+ return mqttClient.isConnected();
+ }
+
+}
diff --git a/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/operations/mqtt/blocking/MQTTBlockingPublisherClient.java b/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/operations/mqtt/blocking/MQTTBlockingPublisherClient.java
new file mode 100644
index 00000000..b4d29953
--- /dev/null
+++ b/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/operations/mqtt/blocking/MQTTBlockingPublisherClient.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.wso2.mb.integration.common.clients.operations.mqtt.blocking;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.eclipse.paho.client.mqttv3.MqttException;
+import org.eclipse.paho.client.mqttv3.MqttMessage;
+import org.wso2.mb.integration.common.clients.QualityOfService;
+import org.wso2.mb.integration.common.clients.MQTTClientConnectionConfiguration;
+import org.wso2.mb.integration.common.clients.operations.mqtt.callback.CallbackHandler;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Synchronous MQTT publishing client.
+ */
+public class MQTTBlockingPublisherClient extends AndesMQTTBlockingClient {
+
+ // The payload to send as message content
+ private byte[] messagePayLoad;
+
+ // The number of messages to send
+ private int noOfMessages;
+
+ private static final Log log = LogFactory.getLog(MQTTBlockingPublisherClient.class);
+
+ /**
+ * Initialize publishing to mqtt.
+ *
+ * @param configuration MQTT configurations
+ * @param clientID Unique mqtt client Id
+ * @param topic Topic to publish to
+ * @param qos Quality of service
+ * @param payload Data to send
+ * @param noOfMessages Number of message to send
+ * @throws MqttException
+ */
+ public MQTTBlockingPublisherClient(MQTTClientConnectionConfiguration configuration, String clientID, String topic,
+ QualityOfService qos, byte[] payload, int noOfMessages) throws MqttException {
+ super(configuration, clientID, topic, qos, new CallbackHandler());
+ messagePayLoad = payload;
+ this.noOfMessages = noOfMessages;
+ }
+
+ /**
+ * Start the publisher to publish to mqtt.
+ */
+ @Override
+ public void run() {
+ try {
+ publish(messagePayLoad, noOfMessages);
+ } catch (MqttException e) {
+ log.error("Error publishing messages to " + getTopic() + " from " + getMqttClientID(), e);
+ }
+ }
+
+ /**
+ * Return subscription status as false since this is the publishing client.
+ *
+ * @return False
+ */
+ @Override
+ public boolean isSubscribed() {
+ return false;
+ }
+
+ /**
+ * Return empty as this is the publisher client and does not accept any messages.
+ *
+ * @return empty message list
+ */
+ @Override
+ public List getReceivedMessages() {
+ return Collections.emptyList();
+ }
+}
diff --git a/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/operations/mqtt/blocking/MQTTBlockingSubscriberClient.java b/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/operations/mqtt/blocking/MQTTBlockingSubscriberClient.java
new file mode 100644
index 00000000..0fe71c55
--- /dev/null
+++ b/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/operations/mqtt/blocking/MQTTBlockingSubscriberClient.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.wso2.mb.integration.common.clients.operations.mqtt.blocking;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.eclipse.paho.client.mqttv3.MqttException;
+import org.eclipse.paho.client.mqttv3.MqttMessage;
+import org.wso2.mb.integration.common.clients.QualityOfService;
+import org.wso2.mb.integration.common.clients.MQTTClientConnectionConfiguration;
+import org.wso2.mb.integration.common.clients.operations.mqtt.callback.CallbackHandler;
+
+import java.util.List;
+
+/**
+ * Synchronous MQTT subscriber client.
+ */
+public class MQTTBlockingSubscriberClient extends AndesMQTTBlockingClient {
+
+ private static final Log log = LogFactory.getLog(MQTTBlockingSubscriberClient.class);
+
+ // Listening to the server for message or not
+ private boolean subscribed = false;
+
+ /**
+ * Initialize subscribing to mqtt.
+ *
+ * @param configuration MQTT configurations
+ * @param clientID Unique mqtt client Id
+ * @param topic Topic to subscribe to
+ * @param qos Quality of Service
+ * @param saveMessages Save receiving messages
+ * @throws MqttException
+ */
+ public MQTTBlockingSubscriberClient(MQTTClientConnectionConfiguration configuration, String clientID, String topic,
+ QualityOfService qos, boolean saveMessages) throws MqttException {
+ super(configuration, clientID, topic, qos, new CallbackHandler(saveMessages));
+ }
+
+ /**
+ * Get all the received messages through this client.
+ * Use this if want to validate message content.
+ *
+ * @return Received messages.
+ */
+ public List getReceivedMessages() {
+ return getCallbackHandler().getReceivedMessages();
+ }
+
+
+ /**
+ * Invokes client and subscribes to the given topic.
+ */
+ @Override
+ public void run() {
+ try {
+ subscribe();
+ subscribed = true;
+ } catch (MqttException e) {
+ log.error("Error subscribing to topic " + getTopic() + " from client " + getMqttClientID(), e);
+ }
+ }
+
+
+ /**
+ * Gracefully disconnect the client after un-subscribing to subscribed topic.
+ * Called through ClientEngine disconnect.
+ *
+ * @throws MqttException
+ */
+ @Override
+ public void disconnect() throws MqttException {
+ CallbackHandler callbackHandler = getCallbackHandler();
+ if (isConnected()) {
+ if (null != callbackHandler) {
+ log.info("No of messages received for client " + getMqttClientID() + " : " + callbackHandler
+ .getReceivedMessageCount());
+ }
+
+ // Disconnecting forcefully without un-subscribing to prevent a publisher from blocking an un-subscribe
+ // process.
+ mqttClient.disconnect();
+ subscribed = false;
+
+ log.info("Client " + getMqttClientID() + " Disconnected");
+ }
+ }
+
+ /**
+ * Check if the subscriber is subscribed to a topic
+ *
+ * @return Is Subscribed
+ */
+ public boolean isSubscribed() {
+ return subscribed;
+ }
+}
diff --git a/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/operations/mqtt/callback/CallbackHandler.java b/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/operations/mqtt/callback/CallbackHandler.java
new file mode 100755
index 00000000..11e3a413
--- /dev/null
+++ b/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/operations/mqtt/callback/CallbackHandler.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.wso2.mb.integration.common.clients.operations.mqtt.callback;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
+import org.eclipse.paho.client.mqttv3.MqttCallback;
+import org.eclipse.paho.client.mqttv3.MqttMessage;
+import org.wso2.mb.integration.common.clients.MQTTConstants;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Callback handler to handle message arrival, delivery complete and connection lost.
+ * Keeps track of sent/received message counts.
+ */
+public class CallbackHandler implements MqttCallback {
+
+ private final Log log = LogFactory.getLog(CallbackHandler.class);
+
+ private boolean saveMessages = false;
+
+ private final List receivedMessages = new ArrayList();
+ private int receivedMessageCount;
+ private int sentMessageCount;
+
+ /**
+ * Saves the topic name for which the last message received if saveMessages is set to true.
+ */
+ String lastTopicReceived;
+
+ /**
+ * Default constructor. Use this if you do not care about receiving message are saved or not.
+ */
+ public CallbackHandler() {
+
+ }
+
+ /**
+ * Set saveMessages while initializing. Use this if you want to specifically want to save/not save receiving
+ * messages.
+ *
+ * Do not set saveMessages to true if you are expecting a large number of messages.
+ *
+ * @param saveReceivingMessages Save receiving message
+ */
+ public CallbackHandler(boolean saveReceivingMessages) {
+ this.saveMessages = saveReceivingMessages;
+ }
+
+ /**
+ * Extract the received message count for the client.
+ *
+ * @return Received message count
+ */
+ public int getReceivedMessageCount() {
+ return receivedMessageCount;
+ }
+
+ /**
+ * Handle losing connection with the server.
+ * Here we just print it to the test console.
+ *
+ * @param throwable Throwable connection lost
+ */
+ @Override
+ public void connectionLost(Throwable throwable) {
+ log.error("Connection Lost - Client Disconnected", throwable);
+ }
+
+ /**
+ * Handle a receiving message from a server.
+ * The receiving message count will be updated. If save message flag is up, the received message will be saved.
+ *
+ * @param topic Topic message received from
+ * @param mqttMessage The mqtt message received
+ * @throws Exception
+ */
+ @Override
+ public void messageArrived(String topic, MqttMessage mqttMessage) throws Exception {
+ if (null != mqttMessage) {
+ if (saveMessages) {
+ receivedMessages.add(mqttMessage);
+ lastTopicReceived = topic;
+ log.info("Message arrived on " + topic + " : " + mqttMessage.toString());
+ }
+
+ incrementReceivedMessageCount();
+ int receivedMessageCount = getReceivedMessageCount();
+
+ if (receivedMessageCount % MQTTConstants.MESSAGE_PRINT_LIMIT == 0) {
+ log.info(receivedMessageCount + " messages received.");
+ }
+ } else {
+ log.warn("Empty message received by the callback handler on topic " + topic);
+ }
+
+
+ }
+
+ /**
+ * Handle delivery complete ack.
+ *
+ * @param iMqttDeliveryToken Delivery complete token
+ */
+ @Override
+ public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {
+ incrementSentMessageCount();
+
+ int sentMessageCount = getSentMessageCount();
+
+ if (sentMessageCount % MQTTConstants.MESSAGE_PRINT_LIMIT == 0) {
+ log.info(sentMessageCount + " messages received.");
+ }
+ }
+
+ /**
+ * Increment the receiving message count.
+ * Use this instead of just incrementing so if threads are involved this method can be used to handle concurrency
+ * issues.
+ */
+ private void incrementReceivedMessageCount() {
+ receivedMessageCount++;
+ }
+
+ /**
+ * Increment the sent message count.
+ * Use this instead of just incrementing so if threads are involved this method can be used to handle concurrency
+ * issues.
+ */
+ private void incrementSentMessageCount() {
+ sentMessageCount++;
+ }
+
+ /**
+ * Retrieve the received messages. This will return a non empty value only if saveMessages flag is set.
+ *
+ * @return Received messages
+ */
+ public List getReceivedMessages() {
+ return receivedMessages;
+ }
+
+ /**
+ * Get the sent message count.
+ *
+ * @return Sent message count
+ */
+ public int getSentMessageCount() {
+ return sentMessageCount;
+ }
+
+
+ public String getLastTopicReceived() {
+ return lastTopicReceived;
+ }
+}
diff --git a/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/operations/utils/AndesClientConstants.java b/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/operations/utils/AndesClientConstants.java
new file mode 100644
index 00000000..26062d8a
--- /dev/null
+++ b/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/operations/utils/AndesClientConstants.java
@@ -0,0 +1,156 @@
+/*
+* Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+*
+* WSO2 Inc. licenses this file to you under the Apache License,
+* Version 2.0 (the "License"); you may not use this file except
+* in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT 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.wso2.mb.integration.common.clients.operations.utils;
+
+import java.io.File;
+
+/**
+ * This class contains the constants that are being used by the andes client.
+ */
+public class AndesClientConstants {
+ /**
+ * Andes initial context factory.
+ */
+ public static final String ANDES_ICF =
+ "org.wso2.andes.jndi.PropertiesFileInitialContextFactory";
+
+ /**
+ * Connection factory name prefix.
+ */
+ public static final String CF_NAME_PREFIX = "connectionfactory.";
+
+ /**
+ * Andes connection factory name
+ */
+ public static final String CF_NAME = "andesConnectionfactory";
+
+ /**
+ * WSO2 carbon factory name.
+ */
+ public static final String CARBON_VIRTUAL_HOST_NAME = "carbon";
+
+ /**
+ * Carbon client ID.
+ */
+ public static final String CARBON_CLIENT_ID = "carbon";
+
+ /**
+ * Default file path to write received messages by subscriber/consumer
+ */
+ public static final String FILE_PATH_TO_WRITE_RECEIVED_MESSAGES =
+ System.getProperty("project.build.directory") + File.separator + "receivedMessages.txt";
+
+ /**
+ * Default file path to write statistics by subscriber/consumer and publisher Suppressing
+ * "UnusedDeclaration" as this may be used in client configuration
+ */
+ @SuppressWarnings("UnusedDeclaration")
+ public static final String FILE_PATH_TO_WRITE_STATISTICS =
+ System.getProperty("framework.resource.location") + File.separator + "stats.csv";
+
+ /**
+ * Message publishing format
+ */
+ public static final String PUBLISH_MESSAGE_FORMAT = "Sending Message:{0} ThreadID:{1}";
+ // please see usages prior editing
+
+ /**
+ * Default waiting time that is used to check whether the consumer has received messages.
+ */
+ public static final long DEFAULT_RUN_TIME = 10000L;
+
+ /**
+ * Default waiting time that is used to check whether the consumer has received messages.
+ */
+ public static final long DEFAULT_CLUSTER_SYNC_TIME = 1000;
+
+ /**
+ * Admin user name for AMQP connection string
+ */
+ public static final String DEFAULT_USERNAME = "admin";
+
+ /**
+ * Admin password for AMQP connection string
+ */
+ public static final String DEFAULT_PASSWORD = "admin";
+
+ /**
+ * Default host name for AMQP connection string
+ */
+ public static final String DEFAULT_HOST_NAME = "127.0.0.1";
+
+ /**
+ * Default port for AMQP connections string
+ */
+ public static final int DEFAULT_PORT = 5672;
+
+ /**
+ * File path to read message content for publishing
+ */
+ public static final String MESSAGE_CONTENT_INPUT_FILE_PATH_1MB =
+ System.getProperty("framework.resource.location") + File.separator +
+ "MessageContentInput.txt";
+
+ /**
+ * File path to read message content for publishing
+ */
+ public static final String MAP_MESSAGE_CONTENT_INPUT_FILE_PATH =
+ System.getProperty("framework.resource.location") + File.separator +
+ "MapMessageContentInput.txt";
+
+ /**
+ * File path to read message content for publishing
+ */
+ public static final String MESSAGE_CONTENT_INPUT_FILE_PATH_WITHOUT_REPETITIONS_256KB =
+ System.getProperty("framework.resource.location") + File.separator +
+ "MessageContentInputWithoutRepetitions.txt";
+
+ /**
+ * File path creating a file.
+ */
+ public static final String FILE_PATH_FOR_CREATING_A_NEW_FILE =
+ System.getProperty("project.build.directory") + File.separator + "newFile.txt";
+
+ /**
+ * File path for a file of size 1 kb.
+ */
+ public static final String FILE_PATH_FOR_ONE_KB_SAMPLE_FILE =
+ System.getProperty("framework.resource.location") + "sample" + File.separator +
+ "sample_1KB_msg.xml";
+
+ /**
+ * The JMS property which stores routing key.
+ */
+ public static final String JMS_ANDES_ROUTING_KEY_MESSAGE_PROPERTY = "JMS_ANDES_ROUTING_KEY";
+
+ /**
+ * JMS Property allowing to append routing key for messages.
+ */
+ public static final String ANDES_SET_ROUTING_KEY = "AndesSetRoutingKey";
+
+ /**
+ * System property name of andes acknowledgement wait timeout
+ */
+ public static final String ANDES_ACK_WAIT_TIMEOUT_PROPERTY = "AndesAckWaitTimeOut";
+
+ /**
+ * System property name of andes redelivery delay
+ */
+ public static final String ANDES_REDELIVERY_DELAY_PROPERTY = "AndesRedeliveryDelay";
+
+}
diff --git a/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/operations/utils/AndesClientOutputParser.java b/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/operations/utils/AndesClientOutputParser.java
new file mode 100644
index 00000000..40c019eb
--- /dev/null
+++ b/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/operations/utils/AndesClientOutputParser.java
@@ -0,0 +1,382 @@
+/*
+ * Copyright (c) 2005-2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.wso2.mb.integration.common.clients.operations.utils;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.LineIterator;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * This class is used to get Andes Client outputs from parse file. The class provides evaluation
+ * functions for testing purposes.
+ */
+public class AndesClientOutputParser {
+
+ /**
+ * The logger used in logging information, warnings, errors and etc.
+ */
+ private static Log log = LogFactory.getLog(AndesClientOutputParser.class);
+
+ /**
+ * Map that stored received messages. Used to check message duplication.
+ */
+ private Map mapOfReceivedMessages = new HashMap();
+
+ /**
+ * List of received messages.
+ */
+ private List messages = new ArrayList();
+
+ /**
+ * File path to parse received messages
+ */
+ private String filePath = "";
+
+ /**
+ * Creates an output parse for andes with a give file path.
+ *
+ * @param filePath The file path for received messages.
+ * @throws IOException
+ */
+ public AndesClientOutputParser(String filePath) throws IOException {
+ this.filePath = filePath;
+ parseFile();
+ }
+
+ /**
+ * Reads received messages from a file path and store the message ID in necessary data
+ * structures.
+ *
+ * @throws IOException
+ */
+ private void parseFile() throws IOException {
+ try {
+ BufferedReader br = new BufferedReader(new FileReader(filePath));
+ try {
+ String line = br.readLine();
+ while (line != null) {
+ String tempSendMessageString = line.substring(AndesClientConstants.PUBLISH_MESSAGE_FORMAT.indexOf("Sending Message:") + "Sending Message:".length());
+ long messageIdentifier = Long.valueOf(tempSendMessageString.substring(0, tempSendMessageString
+ .indexOf(" ")).replace(",",""));
+ this.addMessage(messageIdentifier);
+ line = br.readLine();
+ }
+ } finally {
+ br.close();
+ }
+ } catch (FileNotFoundException e) {
+ log.error("Error " + filePath + " the file containing received messages couldn't found", e);
+ throw e;
+ } catch (IOException e) {
+ log.error("Error " + filePath + " the file cannot be read", e);
+ throw e;
+ }
+ }
+
+ /**
+ * Gets the map used for message duplication.
+ *
+ * @return A map of duplicated message IDs as key.
+ */
+ public Map getDuplicatedMessages() {
+ Map messagesDuplicated = new HashMap();
+ for (Long messageIdentifier : mapOfReceivedMessages.keySet()) {
+ if (mapOfReceivedMessages.get(messageIdentifier) > 1) {
+ messagesDuplicated.put(messageIdentifier, mapOfReceivedMessages.get(messageIdentifier));
+ }
+ }
+ return messagesDuplicated;
+ }
+
+ /**
+ * Checks if messages are received in the correct order.
+ *
+ * @return true if messages are in order, false otherwise.
+ */
+ public boolean checkIfMessagesAreInOrder() {
+ boolean result = true;
+ for (int count = 0; count < messages.size(); count++) {
+ if (messages.get(count) != (count)) {
+ result = false;
+ log.warn("Message order is broken at message " + messages.get(count));
+ break;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Prints missing message IDs.
+ * Suppressing "UnusedDeclaration" as this could be used for debugging purposes
+ *
+ * @param numberOfSentMessages Number of messages to print.
+ */
+ @SuppressWarnings("UnusedDeclaration")
+ public void printMissingMessages(int numberOfSentMessages) {
+ log.info("Printing Missing Messages");
+ for (long count = 0; count < numberOfSentMessages; count++) {
+ if (mapOfReceivedMessages.get(count) == null) {
+ log.info("Missing message id:" + count + 1 + "\n");
+ }
+ }
+ }
+
+ /**
+ * Prints duplicated message IDs
+ * Suppressing "UnusedDeclaration" as this could be used for debugging purposes
+ */
+ @SuppressWarnings("UnusedDeclaration")
+ public void printDuplicateMessages() {
+ log.info("Printing Duplicated Messages");
+ log.info(this.getDuplicatedMessages());
+ }
+
+ /**
+ * Prints the map that contains received messages.
+ * Suppressing "UnusedDeclaration" as this could be used for debugging purposes
+ */
+ @SuppressWarnings("UnusedDeclaration")
+ public void printMessagesMap() {
+ log.info("Printing Received Messages");
+ log.info(mapOfReceivedMessages);
+ }
+
+ /**
+ * Adds received message IDs to a list and a map.
+ *
+ * @param messageIdentifier Received message ID.
+ */
+ private void addMessage(Long messageIdentifier) {
+ if (mapOfReceivedMessages.get(messageIdentifier) == null) {
+ mapOfReceivedMessages.put(messageIdentifier, 1);
+ } else {
+ int currentCount = mapOfReceivedMessages.get(messageIdentifier);
+ mapOfReceivedMessages.put(messageIdentifier, currentCount + 1);
+ }
+
+ messages.add(messageIdentifier);
+ }
+
+ /**
+ * Prints received message IDs in sorted.
+ * Suppressing "UnusedDeclaration" as this could be used for debugging purposes
+ */
+ @SuppressWarnings("UnusedDeclaration")
+ public void printMessagesSorted() {
+ log.info("Printing Sorted Messages");
+ List cloneOfMessages = new ArrayList();
+ cloneOfMessages.addAll(messages);
+ Collections.sort(cloneOfMessages);
+ log.info(cloneOfMessages);
+ }
+
+ /**
+ * Check whether all the messages are transacted
+ *
+ * @param operationOccurredIndex Index of the operation occurred message
+ * @return transactedResult
+ */
+ public boolean transactedOperations(long operationOccurredIndex) throws FileNotFoundException {
+ boolean result = false;
+ int count = 0;
+ long firstMessageIdentifier = 0;
+ try {
+ BufferedReader br = new BufferedReader(new FileReader(filePath));
+ //Needed try/finally to close the file
+ try {
+ String line = br.readLine();
+ while (line != null) {
+ String tempSendMessageString = line.substring(AndesClientConstants.PUBLISH_MESSAGE_FORMAT.indexOf("Sending Message:") + "Sending Message:".length());
+ long messageIdentifier = Long.parseLong(tempSendMessageString.substring(0, tempSendMessageString.indexOf(" ")));
+ if (count == 0) {
+ firstMessageIdentifier = messageIdentifier;
+ }
+ if (count == (operationOccurredIndex)) {
+ if (messageIdentifier == firstMessageIdentifier) {
+ result = true;
+ }
+ }
+ line = br.readLine();
+ count++;
+ }
+ } catch (IOException e) {
+ log.error("Error while parsing the file containing received messages", e);
+ } finally {
+ try {
+ br.close();
+ } catch (IOException e) {
+ log.error("Error while closing the file containing received messages", e);
+ }
+ }
+
+ } catch (FileNotFoundException e) {
+ log.error("Error " + filePath + " the file containing received messages couldn't found", e);
+ throw e;
+ }
+
+ AndesClientUtils.flushPrintWriters();
+ return result;
+ }
+
+ /**
+ * Check whether all the messages are received in-order when subscriber rollbacks
+ * after certain number of messages.
+ *
+ * @param messagesPerRollback Number of messages received per rollback
+ * @return Result as true if transacted rollback operation has successfully
+ * preserved order of all messages.
+ */
+ public boolean checkIfTransactedRollbackPreservesOrder(long messagesPerRollback)
+ throws FileNotFoundException {
+
+ boolean result = true;
+ int count = 0;
+ Long messageIdentifier;
+
+ int rollbackBatchIteration = 1;
+ boolean isFirstMessageBatch = true;
+ LineIterator iterator = null;
+
+ Map firstMessageBatch = new HashMap();
+ try {
+ iterator = FileUtils.lineIterator(new File(filePath));
+
+ String line = iterator.nextLine();
+ while (iterator.hasNext()) {
+
+ messageIdentifier = getMessageIdentifier(line);
+
+ if (firstMessageBatch.containsValue(messageIdentifier)) {
+ isFirstMessageBatch = false;
+ if (count != messagesPerRollback * rollbackBatchIteration) {
+ log.error("failed to check if rollback messages are received in order" +
+ " to due to first duplicated message count " + count +
+ " not equal to messages per each rollback." +
+ messagesPerRollback + ".");
+ result = false;
+ }
+ rollbackBatchIteration++;
+ }
+
+ if (!isFirstMessageBatch) {
+ for (int i = 0; i < messagesPerRollback; i++) {
+ messageIdentifier = getMessageIdentifier(line);
+ if (null != firstMessageBatch.get(i)) {
+ if (!firstMessageBatch.get(i).equals(messageIdentifier)) {
+ result = false;
+ log.error("Error in line :" + line +
+ ".Rollback operation failed to keep message order.");
+ }
+ }
+ if (iterator.hasNext()) {
+ line = iterator.nextLine();
+ count++;
+ }
+ }
+ } else if (isFirstMessageBatch) {
+ firstMessageBatch.put(count, messageIdentifier);
+ line = iterator.nextLine();
+ count++;
+ }
+ }
+
+ } catch (FileNotFoundException e) {
+ log.error("Error " + filePath + " the file containing received messages couldn't found", e);
+ throw e;
+ } catch (IOException e) {
+ log.error("Error while parsing the file containing received messages", e);
+ } finally {
+ iterator.close();
+ }
+
+ AndesClientUtils.flushPrintWriters();
+ return result;
+ }
+
+
+ /**
+ * This method will return message identifier number extracted from given string line.
+ * sample string line "Sending Message:36 ThreadID:7,335".
+ *
+ * @param line string parameter which contains given line of a text file.
+ * @return messageIdentifier which can identify messages uniquely.
+ */
+ private Long getMessageIdentifier(String line) {
+
+ String tempSendMessageString = line.substring(AndesClientConstants.
+ PUBLISH_MESSAGE_FORMAT.indexOf("Sending Message:") + "Sending Message:".length());
+ Long messageIdentifier = Long.parseLong(tempSendMessageString.
+ substring(0, tempSendMessageString.indexOf(" ")));
+
+ return messageIdentifier;
+ }
+
+
+ /**
+ * Parse the file and get the number of duplicate message IDs.
+ *
+ * @return Duplicated message ID count.
+ */
+ public long numberDuplicatedMessages() {
+ long duplicateCount = 0;
+ List messagesDuplicated = new ArrayList();
+ try {
+ BufferedReader br = new BufferedReader(new FileReader(filePath));
+ //Needed try/finally to close the file
+ try {
+ String line = br.readLine();
+ while (line != null) {
+ String tempSendMessageString = line.substring(AndesClientConstants.PUBLISH_MESSAGE_FORMAT.indexOf("Sending Message:") + "Sending Message:".length());
+ long messageIdentifier = Long.parseLong(tempSendMessageString.substring(0, tempSendMessageString.indexOf(" ")));
+ if (messagesDuplicated.contains(messageIdentifier)) {
+ duplicateCount++;
+ } else {
+ messagesDuplicated.add(messageIdentifier);
+ }
+ line = br.readLine();
+ }
+ } catch (IOException e) {
+ log.error("Error while parsing the file containing received messages", e);
+ } finally {
+
+ try {
+ br.close();
+ } catch (IOException e) {
+ log.error("Error while closing the file containing received messages", e);
+ }
+
+ }
+ } catch (FileNotFoundException e) {
+ log.error("Error " + filePath + " the file containing received messages couldn't found", e);
+ }
+ return duplicateCount;
+ }
+}
diff --git a/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/operations/utils/AndesClientUtils.java b/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/operations/utils/AndesClientUtils.java
new file mode 100644
index 00000000..b83fd177
--- /dev/null
+++ b/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/operations/utils/AndesClientUtils.java
@@ -0,0 +1,363 @@
+/*
+* Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+*
+* WSO2 Inc. licenses this file to you under the Apache License,
+* Version 2.0 (the "License"); you may not use this file except
+* in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT 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.wso2.mb.integration.common.clients.operations.utils;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.log4j.Logger;
+import org.wso2.mb.integration.common.clients.AndesClient;
+
+import javax.jms.JMSException;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * This class provides functionality to evaluate Andes Client consumers and publishers.
+ */
+public class AndesClientUtils {
+ /**
+ * The logger used in logging information, warnings, errors and etc.
+ */
+ private static Logger log = Logger.getLogger(AndesClientUtils.class);
+
+ /**
+ * The print writer to print received messages to a file.
+ */
+ private static PrintWriter receivedMessagePrintWriter;
+
+ /**
+ * The print writer to print statistics such as TPS for consumers and producers and also the
+ * average latency to a file.
+ */
+ private static PrintWriter statisticsPrintWriter;
+
+ /**
+ * The print writer to print messages that are being sent by the publisher.
+ */
+ private static PrintWriter publishedMessagePrintWriter;
+
+ /**
+ * Waits until no messages are received. The waiting is done by using a loop checking whether
+ * any new messages are received than the previous iteration. In each iteration it will wait for
+ * a certain time to make sure that message counter changes until no change is detected in the
+ * message counters.
+ *
+ * @param client The consumer client
+ * @param waitTimeTillMessageCounterChanges The amount of milliseconds to wait for new messages
+ * are received.
+ * @param expectedMessageCount Number of messages expected from the consumer
+ * @throws JMSException
+ */
+ public static void waitForMessagesAndShutdown(AndesClient client,
+ long waitTimeTillMessageCounterChanges, long expectedMessageCount)
+ throws JMSException {
+ long previousMessageCount = 0;
+ long currentMessageCount = -1;
+
+ /**
+ * At each iteration it will check whether the message count has changed than the previous
+ * iteration
+ */
+ while (currentMessageCount != previousMessageCount) {
+ try {
+ // Waits till the consumer client received more messages.
+ TimeUnit.MILLISECONDS.sleep(waitTimeTillMessageCounterChanges);
+ } catch (InterruptedException e) {
+ log.error("Error waiting for receiving messages.", e);
+ }
+ // Updating message counters
+ previousMessageCount = currentMessageCount;
+ currentMessageCount = client.getReceivedMessageCount();
+ }
+
+ log.info("Message count received by consumer : " + Long
+ .toString(client.getReceivedMessageCount()));
+
+ if (expectedMessageCount != currentMessageCount) {
+ // Stopping the consumer client
+ client.stopClient();
+ }
+
+ // Prints print writer contents to files.
+ flushPrintWriters();
+ }
+
+ /**
+ * Waits until no messages are received. The waiting is done by using a loop checking whether
+ * any new messages are received than the previous iteration. In each iteration it will wait for
+ * a certain time to make sure that message counter changes until no change is detected in the
+ * message counters.
+ *
+ * @param client The consumer client
+ * @param waitTimeTillMessageCounterChanges The amount of milliseconds to wait for new messages
+ * are received.
+ * @throws JMSException
+ */
+ public static void waitForMessagesAndShutdown(AndesClient client,
+ long waitTimeTillMessageCounterChanges)
+ throws JMSException {
+ long previousMessageCount = 0;
+ long currentMessageCount = -1;
+
+ /**
+ * At each iteration it will check whether the message count has changed than the previous
+ * iteration
+ */
+ while (currentMessageCount != previousMessageCount) {
+ try {
+ // Waits till the consumer client received more messages.
+ TimeUnit.MILLISECONDS.sleep(waitTimeTillMessageCounterChanges);
+ } catch (InterruptedException e) {
+ log.error("Error waiting for receiving messages.", e);
+ }
+ // Updating message counters
+ previousMessageCount = currentMessageCount;
+ currentMessageCount = client.getReceivedMessageCount();
+ }
+
+ log.info("Message count received by consumer : " + Long
+ .toString(client.getReceivedMessageCount()));
+ // Stopping the consumer client
+ client.stopClient();
+ // Prints print writer contents to files.
+ flushPrintWriters();
+ }
+
+ /**
+ * Shutdown the client gracefully without waiting.
+ *
+ * @param client The client to shutdown
+ * @throws JMSException
+ */
+ public static void shutdownClient(AndesClient client) throws JMSException {
+ client.stopClient();
+ flushPrintWriters();
+ }
+
+ /**
+ * Sleeps for a certain time.
+ *
+ * @param milliseconds Sleep time in milliseconds.
+ */
+ public static void sleepForInterval(long milliseconds) {
+ if (0 < milliseconds) {
+ try {
+ Thread.sleep(milliseconds);
+ } catch (InterruptedException ignore) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+
+ /**
+ * Writes received messages to a file.
+ *
+ * @param content Message content to write.
+ * @param filePath File path where the message content should be written.
+ */
+ public static void writeReceivedMessagesToFile(String content, String filePath)
+ throws IOException {
+ if (receivedMessagePrintWriter == null) {
+ initializeReceivedMessagesPrintWriter(filePath);
+ }
+ receivedMessagePrintWriter.println(content);
+
+ }
+
+ /**
+ * Writes statistics to a file.
+ *
+ * @param content Statistic content.
+ * @param filePath File path where the statistics should be written.
+ */
+ public static void writeStatisticsToFile(String content, String filePath) throws IOException {
+ if (statisticsPrintWriter == null) {
+ initializeStatisticsPrintWriter(filePath);
+ }
+
+ statisticsPrintWriter.println(content);
+
+ }
+
+ /**
+ * Writes published messages to a file.
+ *
+ * @param content Statistic content.
+ * @param filePath File path where the statistics should be written.
+ */
+ public static void writePublishedMessagesToFile(String content, String filePath) throws IOException {
+ if (publishedMessagePrintWriter == null) {
+ initializePublishedPrintWriter(filePath);
+ }
+
+ publishedMessagePrintWriter.println(content);
+ }
+
+ /**
+ * Initialize the message content print writer. This needs to be invoked before each test case.
+ *
+ * @param filePath The file path to write to.
+ */
+ public static void initializeReceivedMessagesPrintWriter(String filePath) throws IOException {
+ if (StringUtils.isNotEmpty(filePath)) {
+ File writerFile = new File(filePath);
+ if (writerFile.exists() || writerFile.createNewFile()) {
+ BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(filePath));
+ receivedMessagePrintWriter = new PrintWriter(bufferedWriter);
+ }
+ }
+ }
+
+ /**
+ * Initialize the statistics print writer. This needs to be invoked before each test case.
+ *
+ * @param filePath The file path to write to.
+ */
+ public static void initializeStatisticsPrintWriter(String filePath) throws IOException {
+ if (StringUtils.isNotEmpty(filePath)) {
+ File writerFile = new File(filePath);
+ if (writerFile.exists() || writerFile.createNewFile()) {
+ BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(filePath));
+ statisticsPrintWriter = new PrintWriter(bufferedWriter);
+ statisticsPrintWriter
+ .println("TIMESTAMP,CONSUMER_TPS,AVERAGE_LATENCY,,TIMESTAMP,PUBLISHER_TPS");
+ }
+ }
+ }
+
+ /**
+ * Initialize the published messages print writer. This needs to be invoked before each test
+ * case.
+ *
+ * @param filePath The file path to write to.
+ */
+ public static void initializePublishedPrintWriter(String filePath) throws IOException {
+ if (StringUtils.isNotEmpty(filePath)) {
+ File writerFile = new File(filePath);
+ if (writerFile.exists() || writerFile.createNewFile()) {
+ BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(filePath));
+ publishedMessagePrintWriter = new PrintWriter(bufferedWriter);
+ }
+ }
+ }
+
+ /**
+ * Prints print writers to file paths.
+ */
+ public static void flushPrintWriters() {
+ if (null != receivedMessagePrintWriter) {
+ receivedMessagePrintWriter.flush();
+ }
+
+ if (null != statisticsPrintWriter) {
+ statisticsPrintWriter.flush();
+ }
+
+ if (null != publishedMessagePrintWriter) {
+ publishedMessagePrintWriter.flush();
+ }
+ }
+
+ /**
+ * Creates a file using a given file and a size.
+ *
+ * @param filePathToRead The file path to read contents from.
+ * @param filePathToCreate The path in which the contents should be written with a given size.
+ * @param sizeInKB The size of the file to be written in kilobytes.
+ */
+ public static void createMockFile(String filePathToRead, String filePathToCreate,
+ int sizeInKB) {
+ String fileContentToBeWritten = "";
+ BufferedReader br = null;
+ try {
+ br = new BufferedReader(new FileReader(filePathToRead));
+ StringBuilder sb = new StringBuilder();
+ String line = br.readLine();
+
+ while (line != null) {
+ sb.append(line);
+ sb.append('\n');
+ line = br.readLine();
+ }
+ fileContentToBeWritten = sb.toString();
+ } catch (FileNotFoundException e) {
+ log.error("File to read sample string to create text file to send is not found", e);
+ } catch (IOException e) {
+ log.error("Error in reading sample file to create text file to send", e);
+ } finally {
+
+ try {
+ if (br != null) {
+ br.close();
+ }
+ } catch (IOException e) {
+ log.error("Error while closing buffered reader", e);
+ }
+
+ }
+
+ //If already exists, deleting the file
+ if (deleteRandomFile(filePathToCreate)) {
+ log.info("File requested to create already exists. Deleted file: " + filePathToCreate);
+ }
+
+ try {
+ File fileToCreate = new File(filePathToCreate);
+
+ boolean createFileSuccess = fileToCreate.createNewFile();
+ if (createFileSuccess) {
+ log.info("Successfully created a file to append content for sending at " + filePathToCreate);
+ }
+
+ BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(filePathToCreate));
+ PrintWriter printWriter = new PrintWriter(bufferedWriter);
+
+ for (int count = 0; count < sizeInKB; count++) {
+ printWriter.append(fileContentToBeWritten);
+ }
+
+ printWriter.flush();
+ printWriter.close();
+ } catch (IOException e) {
+ log.error("Error. File to print received messages is not provided", e);
+ }
+ }
+
+ /**
+ * Deletes a random file.
+ *
+ * @param filePathToDelete The path in which the contents should be written with a given size.
+ */
+ public static boolean deleteRandomFile(String filePathToDelete) {
+ File fileToDelete = new File(filePathToDelete);
+ boolean deleted = false;
+
+ if (fileToDelete.exists()) {
+ if (fileToDelete.delete()) {
+ deleted = true;
+ }
+ }
+ return deleted;
+ }
+}
diff --git a/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/operations/utils/ExchangeType.java b/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/operations/utils/ExchangeType.java
new file mode 100644
index 00000000..c519cf40
--- /dev/null
+++ b/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/operations/utils/ExchangeType.java
@@ -0,0 +1,45 @@
+/*
+* Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+*
+* WSO2 Inc. licenses this file to you under the Apache License,
+* Version 2.0 (the "License"); you may not use this file except
+* in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT 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.wso2.mb.integration.common.clients.operations.utils;
+
+/**
+ * Enumeration for JMS exchange types.
+ */
+public enum ExchangeType {
+ /**
+ * Exchange types
+ */
+ QUEUE("queue"), TOPIC("topic");
+ private String type;
+
+ /**
+ * Initializes enums
+ * @param type The exchange type as string.
+ */
+ ExchangeType(String type) {
+ this.type = type;
+ }
+
+ /**
+ * Gets exchange string.
+ * @return The exchange string.
+ */
+ public String getType() {
+ return type;
+ }
+}
diff --git a/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/operations/utils/JMSAcknowledgeMode.java b/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/operations/utils/JMSAcknowledgeMode.java
new file mode 100644
index 00000000..0fef614d
--- /dev/null
+++ b/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/operations/utils/JMSAcknowledgeMode.java
@@ -0,0 +1,66 @@
+/*
+* Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+*
+* WSO2 Inc. licenses this file to you under the Apache License,
+* Version 2.0 (the "License"); you may not use this file except
+* in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT 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.wso2.mb.integration.common.clients.operations.utils;
+
+/**
+ * Enumeration for acknowledge modes in JMS
+ */
+public enum JMSAcknowledgeMode {
+ /**
+ * @see SESSION_TRANSACTED
+ */
+ SESSION_TRANSACTED(0),
+
+ /**
+ * @see AUTO_ACKNOWLEDGE
+ */
+ AUTO_ACKNOWLEDGE(1),
+
+ /**
+ * @see CLIENT_ACKNOWLEDGE
+ */
+ CLIENT_ACKNOWLEDGE(2),
+
+ /**
+ * @see DUPS_OK_ACKNOWLEDGE
+ */
+ DUPS_OK_ACKNOWLEDGE(3),
+
+ /**
+ * Per message acknowledgement.
+ */
+ PER_MESSAGE_ACKNOWLEDGE(259);
+
+ private int type;
+
+ /**
+ * Initializes acknowledge mode
+ * @param type Acknowledge mode as per JMS
+ */
+ JMSAcknowledgeMode(int type) {
+ this.type = type;
+ }
+
+ /**
+ * Gets acknowledge mode
+ * @return The Acknowledge mode value
+ */
+ public int getType() {
+ return type;
+ }
+}
diff --git a/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/operations/utils/JMSClientHelper.java b/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/operations/utils/JMSClientHelper.java
new file mode 100644
index 00000000..e90f3452
--- /dev/null
+++ b/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/operations/utils/JMSClientHelper.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2005-2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.wso2.mb.integration.common.clients.operations.utils;
+
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+import java.util.Properties;
+
+public class JMSClientHelper {
+ /**
+ * Full qualified class name of the andes initial context factory
+ */
+ public static final String ANDES_INITIAL_CONTEXT_FACTORY = "org.wso2.andes.jndi" +
+ ".PropertiesFileInitialContextFactory";
+
+ /**
+ * Queue connection factory name used
+ */
+ public static final String QUEUE_CONNECTION_FACTORY = "andesQueueConnectionfactory";
+
+ /**
+ * Topic connection factory name used
+ */
+ public static final String TOPIC_CONNECTION_FACTORY = "andesTopicConnectionfactory";
+
+ /**
+ * Create a inital context with the given parameters
+ *
+ * @param username
+ * Username
+ * @param password
+ * Password
+ * @param brokerHost
+ * Hostname or IP address of the broker
+ * @param port
+ * Port used for AMQP transport
+ * @param queueName
+ * Queue name
+ * @return InitialContext
+ * @throws NamingException
+ */
+ public static InitialContext getInitialContextForQueue(String username,
+ String password,
+ String brokerHost,
+ String port,
+ String queueName) throws NamingException {
+
+ Properties contextProperties = new Properties();
+ contextProperties.put(Context.INITIAL_CONTEXT_FACTORY, ANDES_INITIAL_CONTEXT_FACTORY);
+ String connectionString = getBrokerConnectionString(username, password, brokerHost, port);
+ contextProperties.put("connectionfactory." + QUEUE_CONNECTION_FACTORY, connectionString);
+ contextProperties.put("queue." + queueName, queueName);
+
+ return new InitialContext(contextProperties);
+ }
+
+ /**
+ * Create a inital context with the given parameters
+ *
+ * @param username
+ * Username
+ * @param password
+ * Password
+ * @param brokerHost
+ * Hostname or IP address of the broker
+ * @param port
+ * Port used for AMQP transport
+ * @param topicName
+ * Topic name
+ * @return InitialContext
+ * @throws NamingException
+ */
+ public static InitialContext getInitialContextForTopic(String username,
+ String password,
+ String brokerHost,
+ String port,
+ String topicName) throws NamingException {
+
+ Properties contextProperties = new Properties();
+ contextProperties.put(Context.INITIAL_CONTEXT_FACTORY, ANDES_INITIAL_CONTEXT_FACTORY);
+ String connectionString = getBrokerConnectionString(username, password, brokerHost, port);
+ contextProperties.put("connectionfactory." + TOPIC_CONNECTION_FACTORY, connectionString);
+ contextProperties.put("topic." + topicName, topicName);
+
+ return new InitialContext(contextProperties);
+ }
+
+ /**
+ * Generate broker connection string
+ *
+ * @param userName
+ * Username
+ * @param password
+ * Password
+ * @param brokerHost
+ * Hostname of broker (E.g. localhost)
+ * @param port
+ * Port (E.g. 5672)
+ * @return Broker Connection String
+ */
+ private static String getBrokerConnectionString(String userName, String password,
+ String brokerHost, String port) {
+
+ return "amqp://" + userName + ":" + password + "@clientID/carbon?brokerlist='tcp://"
+ + brokerHost + ":" + port + "'";
+ }
+}
diff --git a/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/operations/utils/JMSDeliveryStatus.java b/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/operations/utils/JMSDeliveryStatus.java
new file mode 100644
index 00000000..72c34c37
--- /dev/null
+++ b/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/operations/utils/JMSDeliveryStatus.java
@@ -0,0 +1,28 @@
+package org.wso2.mb.integration.common.clients.operations.utils;
+
+/**
+ *
+ */
+public enum JMSDeliveryStatus {
+ /**
+ * JMS delivery statuses.
+ */
+ ORIGINAL("Original"), REDELIVERED("Redelivered");
+ private String status;
+
+ /**
+ * Initializes JMS delivery status
+ * @param status Delivery status.
+ */
+ JMSDeliveryStatus(String status) {
+ this.status = status;
+ }
+
+ /**
+ * Gets JMS delivery status.
+ * @return Delivery status.
+ */
+ public String getStatus() {
+ return status;
+ }
+}
diff --git a/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/operations/utils/JMSMessageType.java b/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/operations/utils/JMSMessageType.java
new file mode 100644
index 00000000..036d2126
--- /dev/null
+++ b/modules/broker/integration/tests-common/admin-clients/src/main/java/org/wso2/mb/integration/common/clients/operations/utils/JMSMessageType.java
@@ -0,0 +1,47 @@
+/*
+* Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+*
+* WSO2 Inc. licenses this file to you under the Apache License,
+* Version 2.0 (the "License"); you may not use this file except
+* in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT 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.wso2.mb.integration.common.clients.operations.utils;
+
+/**
+ * Enumeration for JMS message types.
+ */
+public enum JMSMessageType {
+ /**
+ * JMS message types.
+ */
+ TEXT("text"), BYTE("byte"), MAP("map"), OBJECT("object"), STREAM("stream");
+ private String type;
+
+ /**
+ * Initializes JMS message type.
+ *
+ * @param type Message type.
+ */
+ JMSMessageType(String type) {
+ this.type = type;
+ }
+
+ /**
+ * Gets JMS message type.
+ *
+ * @return The message type.
+ */
+ public String getType() {
+ return type;
+ }
+}
\ No newline at end of file
diff --git a/modules/broker/integration/tests-common/integration-tests-utils/pom.xml b/modules/broker/integration/tests-common/integration-tests-utils/pom.xml
new file mode 100644
index 00000000..11530796
--- /dev/null
+++ b/modules/broker/integration/tests-common/integration-tests-utils/pom.xml
@@ -0,0 +1,64 @@
+
+
+
+
+ org.wso2.iot
+ wso2iot-broker-integration-tests
+ 1.0.0-SNAPSHOT
+ ../../pom.xml
+
+
+ 4.0.0
+ WSO2 MB - Integration Test Common Utils Module
+ org.wso2.iot.broker.integration.common.utils
+ jar
+
+
+
+ org.wso2.carbon.automation
+ org.wso2.carbon.automation.engine
+ compile
+
+
+ org.wso2.iot
+ org.wso2.iot.broker.integration.common.clients
+ compile
+
+
+ org.wso2.carbon.automationutils
+ org.wso2.carbon.integration.common.utils
+ compile
+
+
+ org.wso2.carbon
+ org.wso2.carbon.authenticator.stub
+ compile
+
+
+ org.wso2.carbon.automation
+ org.wso2.carbon.automation.extensions
+ compile
+
+
+ commons-jxpath
+ commons-jxpath
+ compile
+
+
+ commons-configuration
+ commons-configuration
+ compile
+
+
+ com.google.guava
+ guava
+ compile
+
+
+ org.wso2.andes.wso2
+ andes
+ compile
+
+
+
+
diff --git a/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/backend/ConfigurationEditor.java b/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/backend/ConfigurationEditor.java
new file mode 100644
index 00000000..771f0bd0
--- /dev/null
+++ b/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/backend/ConfigurationEditor.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.wso2.mb.integration.common.utils.backend;
+
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.commons.configuration.XMLConfiguration;
+import org.apache.commons.configuration.tree.xpath.XPathExpressionEngine;
+import org.wso2.andes.configuration.enums.AndesConfiguration;
+import org.wso2.carbon.integration.common.utils.exceptions.AutomationUtilException;
+import org.wso2.carbon.integration.common.utils.mgt.ServerConfigurationManager;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * This class allows a test case to edit the main server configuration (currently broker.xml) and apply it to the
+ * server before execution.
+ */
+public class ConfigurationEditor {
+
+ /**
+ * File name prefix used for the updated configuration file.
+ */
+ public static final String UPDATED_CONFIG_FILE_PREFIX = "updated_";
+
+ /**
+ * Configuration property holder
+ */
+ public XMLConfiguration configuration;
+
+ /**
+ * File path of the original configuration file.
+ */
+ public String originalConfigFilePath;
+
+ /**
+ * File path of the updated configuration file.
+ */
+ public String updatedConfigFilePath;
+
+ public ConfigurationEditor(String originalConfigFilePath) throws ConfigurationException {
+ this.originalConfigFilePath = originalConfigFilePath;
+
+ configuration = new XMLConfiguration(this.originalConfigFilePath);
+
+ // Support XPath queries.
+ configuration.setExpressionEngine(new XPathExpressionEngine());
+
+ configuration.setDelimiterParsingDisabled(true); // If we don't do this,
+ // we can't add a new configuration to the compositeConfiguration by code.
+ }
+
+ /**
+ * Update a property in loaded original configuration
+ * @param property AndesConfiguration property.
+ * @param value New value to be set
+ * @return the set value
+ */
+ public String updateProperty(AndesConfiguration property, String value) {
+ configuration.setProperty(property.get().getKeyInFile(),value);
+ return value;
+ }
+
+ /**
+ * Apply modified configuration and restart server
+ *
+ * @param serverConfigurationManager Server configuration manager object from automation engine.
+ * @return true if the update was successful.
+ * @throws IOException
+ * @throws AutomationUtilException
+ * @throws ConfigurationException
+ */
+ public boolean applyUpdatedConfigurationAndRestartServer(ServerConfigurationManager serverConfigurationManager)
+ throws IOException, AutomationUtilException, ConfigurationException {
+
+ //Rename original configuration file to original_broker.xml
+ String originalConfigFileDirectory = originalConfigFilePath.substring(0,originalConfigFilePath.lastIndexOf(File.separator));
+ String originalConfigFileName = originalConfigFilePath.substring(originalConfigFilePath.lastIndexOf(File.separator));
+
+ updatedConfigFilePath = originalConfigFileDirectory + UPDATED_CONFIG_FILE_PREFIX + originalConfigFileName;
+ configuration.save(updatedConfigFilePath);
+
+ serverConfigurationManager.applyConfiguration(new File(updatedConfigFilePath), new File(originalConfigFilePath), true, true);
+
+ return true;
+ }
+
+}
diff --git a/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/backend/MBIntegrationBaseTest.java b/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/backend/MBIntegrationBaseTest.java
new file mode 100644
index 00000000..27324c91
--- /dev/null
+++ b/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/backend/MBIntegrationBaseTest.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2005-2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.wso2.mb.integration.common.utils.backend;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.wso2.carbon.authenticator.stub.LoginAuthenticationExceptionException;
+import org.wso2.carbon.automation.engine.context.AutomationContext;
+import org.wso2.carbon.automation.engine.context.TestUserMode;
+import org.wso2.carbon.automation.engine.frameworkutils.FrameworkPathUtil;
+import org.wso2.carbon.integration.common.utils.mgt.ServerConfigurationManager;
+import org.xml.sax.SAXException;
+
+import javax.xml.stream.XMLStreamException;
+import javax.xml.xpath.XPathException;
+import javax.xml.xpath.XPathExpressionException;
+import java.io.File;
+import java.io.IOException;
+import java.net.URISyntaxException;
+
+/**
+ * Base class of all MB integration tests
+ */
+public class MBIntegrationBaseTest {
+
+ protected Log log = LogFactory.getLog(MBIntegrationBaseTest.class);
+ protected AutomationContext automationContext;
+ protected String backendURL;
+ protected ServerConfigurationManager serverManager = null;
+
+ /**
+ * Initialize the base test by initializing the automation context.
+ *
+ * @param userMode The testing user mode
+ * @throws XPathExpressionException
+ */
+ protected void init(TestUserMode userMode) throws XPathExpressionException {
+ // org.apache.xerces.dom.ParentNode.nodeListItem which is used in AutomationContext
+ // does not guarantee thread safety.
+ // Hence to allow tests to run in parallel, this initialization should be synchronized
+ synchronized (this.getClass()) {
+ automationContext = new AutomationContext("MB", userMode);
+ backendURL = automationContext.getContextUrls().getBackEndUrl();
+ }
+ }
+
+ /**
+ * Restart the testing MB server in In-Memory H2 database mode by applying In-Memory database configurations
+ * in andes-virtualhosts-H2-mem.xml file.
+ *
+ * @throws Exception
+ */
+ protected void restartServerWithH2MemMode() throws Exception {
+ serverManager = new ServerConfigurationManager(automationContext);
+
+ // Replace the broker.xml with the new configuration and restarts the server.
+ serverManager.applyConfiguration(new File(FrameworkPathUtil.getSystemResourceLocation() + File.separator +
+ "artifacts" + File.separator + "mb" + File.separator + "config" + File.separator +
+ "broker.xml"),
+ new File(ServerConfigurationManager.getCarbonHome() +
+ File.separator + "repository" + File.separator + "conf" + File.separator + "broker.xml"),
+ true, true);
+ }
+
+ /**
+ * Gracefully restart the current server which was deployed by the test suit. This can be used when a large
+ * amount or large size of messages are tested to clean up the server before or after the test.
+ *
+ * @throws Exception
+ */
+ protected void restartServer()
+ throws Exception {
+ serverManager = new ServerConfigurationManager(automationContext);
+ serverManager.restartGracefully();
+ }
+
+ /**
+ * Returns wso2 https server port based on automation.xml configurations
+ * @throws Exception
+ */
+ protected Integer getHttpsServerPort() throws XPathExpressionException {
+ return Integer.parseInt(automationContext.getInstance().getPorts().get("https"));
+
+ }
+
+ /**
+ * Returns AMQP port based on automation.xml configurations
+ * @throws Exception
+ */
+ protected Integer getAMQPPort() throws XPathExpressionException {
+ return Integer.parseInt(automationContext.getInstance().getPorts().get("amqp"));
+
+ }
+
+ /**
+ * Returns AMQP port based on automation.xml configurations
+ * @throws Exception
+ */
+ protected Integer getSecureAMQPPort() throws XPathExpressionException {
+ return Integer.parseInt(automationContext.getInstance().getPorts().get("sslamqp"));
+
+ }
+
+
+ /**
+ * Returns MQTT port based on automation.xml configurations
+ * @throws Exception
+ */
+ protected Integer getMQTTPort() throws XPathExpressionException {
+ return Integer.parseInt(automationContext.getInstance().getPorts().get("mqtt"));
+ }
+
+ /**
+ * Returns JMX RMI Server port based on automation.xml configurations
+ * @throws Exception
+ */
+ protected Integer getJMXServerPort() throws XPathExpressionException {
+ return Integer.parseInt(automationContext.getInstance().getPorts().get("jmxserver"));
+ }
+
+ /**
+ * Returns JMX RMI Registry port based on automation.xml configurations
+ * @throws Exception
+ */
+ protected Integer getRMIRegistryPort() throws XPathExpressionException {
+ return Integer.parseInt(automationContext.getInstance().getPorts().get("rmiregistry"));
+ }
+
+
+}
diff --git a/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/backend/MBIntegrationUiBaseTest.java b/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/backend/MBIntegrationUiBaseTest.java
new file mode 100644
index 00000000..5cc66cb4
--- /dev/null
+++ b/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/backend/MBIntegrationUiBaseTest.java
@@ -0,0 +1,206 @@
+/*
+* Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+*
+* WSO2 Inc. licenses this file to you under the Apache License,
+* Version 2.0 (the "License"); you may not use this file except
+* in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT 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.wso2.mb.integration.common.utils.backend;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebDriver;
+import org.wso2.carbon.automation.engine.context.AutomationContext;
+import org.wso2.carbon.automation.engine.context.TestUserMode;
+import org.wso2.carbon.automation.engine.frameworkutils.FrameworkPathUtil;
+import org.wso2.carbon.automation.extensions.selenium.BrowserManager;
+import org.wso2.carbon.integration.common.utils.LoginLogoutClient;
+import org.wso2.carbon.integration.common.utils.exceptions.AutomationUtilException;
+import org.wso2.carbon.integration.common.utils.mgt.ServerConfigurationManager;
+import org.wso2.mb.integration.common.utils.ui.UIElementMapper;
+import org.wso2.mb.integration.common.utils.ui.pages.login.LoginPage;
+
+import javax.xml.xpath.XPathExpressionException;
+import java.io.File;
+import java.io.IOException;
+import java.net.MalformedURLException;
+
+/**
+ * The following class is the base class for all the UI test cases for MB.
+ */
+public class MBIntegrationUiBaseTest {
+ private static final Log log = LogFactory.getLog(MBIntegrationUiBaseTest.class);
+ protected AutomationContext mbServer;
+ protected String sessionCookie;
+ protected String backendURL;
+ protected ServerConfigurationManager serverManager;
+ protected LoginLogoutClient loginLogoutClient;
+ protected WebDriver driver;
+ /** custom admin role name set with restartServerWithDifferentAdminRoleName() method */
+ protected static final String CUSTOM_ADMIN_ROLE_NAME = "administrator";
+
+ /**
+ * Initializes the automation context, login client, session cookie and the backend url by {@link org.wso2.carbon
+ * .automation.engine.context.TestUserMode#SUPER_TENANT_ADMIN}.
+ *
+ * @throws AutomationUtilException
+ * @throws MalformedURLException
+ * @throws XPathExpressionException
+ */
+ protected void init() throws AutomationUtilException, IOException, XPathExpressionException {
+ mbServer = new AutomationContext("MB", TestUserMode.SUPER_TENANT_ADMIN);
+ loginLogoutClient = new LoginLogoutClient(mbServer);
+ sessionCookie = loginLogoutClient.login();
+ backendURL = mbServer.getContextUrls().getBackEndUrl();
+ this.driver = BrowserManager.getWebDriver();
+ }
+
+ /**
+ * Initializes the automation context, login client, session cookie and the backend url by a {@link org.wso2
+ * .carbon.automation.engine.context.TestUserMode}.
+ *
+ * @param testUserMode The testing user mode.
+ * @throws XPathExpressionException
+ * @throws AutomationUtilException
+ * @throws MalformedURLException
+ */
+ protected void init(TestUserMode testUserMode) throws XPathExpressionException, AutomationUtilException,
+ MalformedURLException {
+ mbServer = new AutomationContext("MB", testUserMode);
+ loginLogoutClient = new LoginLogoutClient(mbServer);
+ sessionCookie = loginLogoutClient.login();
+ backendURL = mbServer.getContextUrls().getBackEndUrl();
+ this.driver = BrowserManager.getWebDriver();
+ }
+
+ /**
+ * Get current test user's Username according to the automation context
+ *
+ * @throws XPathExpressionException
+ */
+ protected String getCurrentUserName() throws XPathExpressionException {
+ return mbServer.getContextTenant().getContextUser().getUserName();
+ }
+
+ /**
+ * Get current test user's password according to the automation context
+ *
+ * @throws XPathExpressionException
+ */
+ protected String getCurrentPassword() throws XPathExpressionException {
+ return mbServer.getContextTenant().getContextUser().getPassword();
+ }
+
+ /**
+ * Return the admin user name of current context tenant
+ * @return admin name as a String
+ * @throws XPathExpressionException
+ */
+ protected String getAdminUserName() throws XPathExpressionException {
+ return mbServer.getContextTenant().getTenantAdmin().getUserName();
+ }
+
+ /**
+ * Get the password of admin user of current context tenant
+ * @return password as a String
+ * @throws XPathExpressionException
+ */
+ protected String getAdminPassword() throws XPathExpressionException {
+ return mbServer.getContextTenant().getTenantAdmin().getPassword();
+ }
+
+ /**
+ * Restart the testing MB server with WSO2 domain name set under user management
+ *
+ * @throws AutomationUtilException
+ * @throws XPathExpressionException
+ * @throws IOException
+ */
+ protected void restartServerWithDomainName() throws AutomationUtilException, XPathExpressionException,
+ IOException {
+ serverManager = new ServerConfigurationManager(mbServer);
+
+ // Replace the user-mgt.xml with the new configuration and restarts the server.
+ serverManager.applyConfiguration(new File(FrameworkPathUtil.getSystemResourceLocation() + File.separator +
+ "artifacts" + File.separator + "mb" + File.separator + "config" + File.separator
+ + "user-mgt.xml"), new File(ServerConfigurationManager.getCarbonHome() +
+ File.separator + "repository" + File.separator + "conf" + File.separator +
+ "user-mgt.xml"), true, true);
+ }
+
+ /**
+ * Restart the server with admin role name set to "administrator" instead of default value admin.
+ *
+ * @throws IOException
+ * @throws AutomationUtilException
+ * @throws XPathExpressionException
+ */
+ protected void restartServerWithDifferentAdminRoleName() throws IOException, AutomationUtilException,
+ XPathExpressionException {
+ serverManager = new ServerConfigurationManager(mbServer);
+
+ // Replace the user-mgt.xml with the new configuration and restarts the server.
+ serverManager.applyConfiguration(new File(FrameworkPathUtil.getSystemResourceLocation() + File.separator +
+ "artifacts" + File.separator + "mb" + File.separator + "config" + File.separator
+ + "user-mgt-admin-role-name.xml"), new File(ServerConfigurationManager.getCarbonHome() +
+ File.separator + "repository" + File.separator + "conf" + File.separator +
+ "user-mgt.xml"), true, true);
+ }
+
+ /**
+ * Restart the server with previous configuration.
+ *
+ * @throws IOException
+ * @throws AutomationUtilException
+ */
+ protected void restartInPreviousConfiguration() throws IOException, AutomationUtilException {
+ serverManager.restoreToLastConfiguration(true);
+ }
+
+ /**
+ * Gets the default login url for management console.
+ * @return The URL.
+ */
+ protected String getLoginURL() throws XPathExpressionException {
+ return mbServer.getContextUrls().getWebAppURLHttps() + "/carbon/admin/login.jsp";
+ }
+
+ /**
+ * Logs out from MB management console
+ *
+ * @return The login page.
+ * @throws IOException
+ */
+ protected LoginPage logout() throws IOException {
+ driver.findElement(By.xpath(UIElementMapper.getInstance().getElement("home.mb.sign.out.xpath"))).click();
+ return new LoginPage(driver);
+ }
+
+ /**
+ * Returns MQTT port based on automation.xml configurations
+ * @throws XPathExpressionException
+ */
+ protected Integer getMQTTPort() throws XPathExpressionException {
+ return Integer.parseInt(mbServer.getInstance().getPorts().get("mqtt"));
+ }
+
+ /**
+ * Returns MQTT port based on automation.xml configurations
+ * @throws XPathExpressionException
+ */
+ protected Integer getAMQPPort() throws XPathExpressionException {
+ return Integer.parseInt(mbServer.getInstance().getPorts().get("amqp"));
+ }
+}
diff --git a/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/UIElementMapper.java b/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/UIElementMapper.java
new file mode 100644
index 00000000..a7dc5b62
--- /dev/null
+++ b/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/UIElementMapper.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2005-2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.wso2.mb.integration.common.utils.ui;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
+
+/**
+ * Read mapper.properties file and load it's uiElements into Properties object.
+ */
+public class UIElementMapper {
+ public static final Properties uiProperties = new Properties();
+ private static UIElementMapper instance;
+
+ static {
+ try {
+ setStream();
+ instance = new UIElementMapper();
+ } catch (IOException ioe){
+ throw new ExceptionInInitializerError("mapper stream not set. Failed to read file");
+ }
+ }
+
+ private UIElementMapper() {
+ }
+
+ public static UIElementMapper getInstance() {
+ return instance;
+ }
+
+ private static Properties setStream() throws IOException {
+ InputStream inputStream = UIElementMapper.class.getResourceAsStream("/mapper.properties");
+ if (inputStream.available() > 0) {
+ uiProperties.load(inputStream);
+ inputStream.close();
+ return uiProperties;
+ }
+ return null;
+ }
+
+ public String getElement(String key) {
+ return uiProperties.getProperty(key);
+ }
+}
diff --git a/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/MBPage.java b/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/MBPage.java
new file mode 100644
index 00000000..1ca92804
--- /dev/null
+++ b/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/MBPage.java
@@ -0,0 +1,83 @@
+/*
+* Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+*
+* WSO2 Inc. licenses this file to you under the Apache License,
+* Version 2.0 (the "License"); you may not use this file except
+* in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT 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.wso2.mb.integration.common.utils.ui.pages;
+
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebDriver;
+import org.wso2.mb.integration.common.utils.ui.UIElementMapper;
+import org.wso2.mb.integration.common.utils.ui.pages.configure.ConfigurePage;
+import org.wso2.mb.integration.common.utils.ui.pages.login.LoginPage;
+import org.wso2.mb.integration.common.utils.ui.pages.monitor.MonitorPage;
+
+import java.io.IOException;
+
+/**
+ * The base class for all the pages. Navigation functions that can be done from any page should
+ * be implemented within this class (to avoid duplication of common functionality throughout
+ * pages).
+ */
+public abstract class MBPage {
+
+ /**
+ * Web driver used by selenium framework to do UI operations pragmatically
+ */
+ protected WebDriver driver;
+
+ /**
+ * Constructor. Takes the reference of web driver instance.
+ *
+ * @param driver The selenium Web Driver
+ */
+ protected MBPage(WebDriver driver) {
+ this.driver = driver;
+ }
+
+ /**
+ * Selects a Configuration tab and returns the configuration tab related page
+ *
+ * @return ConfigurePage The configuration page.
+ * @throws IOException
+ */
+ public ConfigurePage getConfigurePage() throws IOException {
+ driver.findElement(By.id(UIElementMapper.getInstance().getElement("configure.tab.id"))).click();
+ return new ConfigurePage(driver);
+ }
+
+ /**
+ * Selects the Monitor tab and returns the monitor tab related page
+ *
+ * @return MonitorPage The monitoring page.
+ * @throws IOException
+ */
+ public MonitorPage getMonitorPage() throws IOException {
+ driver.findElement(By.id(UIElementMapper.getInstance().getElement("mb.tab.button.monitor.id"))).click();
+ return new MonitorPage(driver);
+ }
+
+ /**
+ * Log out from current account and returns the LoginPage
+ *
+ * @return LoginPage The login page.
+ * @throws IOException
+ */
+ public LoginPage logout() throws IOException {
+ driver.findElement(By.xpath(UIElementMapper.getInstance().getElement("home.mb.sign.out.xpath"))).click();
+ return new LoginPage(driver);
+ }
+}
diff --git a/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/configure/AddNewTenantPage.java b/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/configure/AddNewTenantPage.java
new file mode 100644
index 00000000..c958fa2f
--- /dev/null
+++ b/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/configure/AddNewTenantPage.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2005-2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.wso2.mb.integration.common.utils.ui.pages.configure;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.wso2.mb.integration.common.utils.ui.UIElementMapper;
+
+import java.util.List;
+
+/**
+ * Abstraction of the Add new tenant page of the UI.
+ */
+public class AddNewTenantPage {
+
+ private static final Log log = LogFactory.getLog(AddNewTenantPage.class);
+ private WebDriver driver;
+
+ public AddNewTenantPage(WebDriver driver) {
+ this.driver = driver;
+ // Check that we're on the right page.
+ if (!driver.findElement(By.id(UIElementMapper.getInstance()
+ .getElement("home.dashboard.middle.text"))).getText().contains("Register A New Organization")) {
+ throw new IllegalStateException("Not in add new tenant page.");
+ }
+ }
+
+ /**
+ * Add a new tenant
+ * @param domain domain of the tenant
+ * @param firstName tenant first name
+ * @param lastName tenant last name
+ * @param adminUserName admin users' user name
+ * @param adminPassword admin users' password
+ * @param adminPasswordRepeat admin users' password (if repeat password doesn't match operation
+ * must be unsuccessful)
+ * @param adminEmail admin users' email
+ * @return true if tenant successfully created. false otherwise
+ */
+ public boolean add(final String domain, final String firstName, final String lastName,
+ final String adminUserName, final String adminPassword, final String adminPasswordRepeat, final String adminEmail) {
+ boolean isSuccessful = false;
+
+ // fill the form
+ driver.findElement(By.id(UIElementMapper.getInstance().getElement("add.tenant.domain.field.id"))).sendKeys(domain);
+ //todo implement usage plan select
+// driver.findElement(By.id(UIElementMapper.getInstance().getElement("add.tenant.usage.plan.field.id"))).(usagePlanName);
+ driver.findElement(By.id(UIElementMapper.getInstance().getElement("add.tenant.first.name.field.id"))).sendKeys(firstName);
+ driver.findElement(By.id(UIElementMapper.getInstance().getElement("add.tenant.last.name.field.id"))).sendKeys(lastName);
+ driver.findElement(By.id(UIElementMapper.getInstance().getElement("add.tenant.admin.user.name.field.id"))).sendKeys(adminUserName);
+ driver.findElement(By.id(UIElementMapper.getInstance().getElement("add.tenant.admin.password.field.id"))).sendKeys(adminPassword);
+ driver.findElement(By.id(UIElementMapper.getInstance().getElement("add.tenant.admin.password.repeat.field.id"))).sendKeys(adminPasswordRepeat);
+ driver.findElement(By.id(UIElementMapper.getInstance().getElement("add.tenant.admin.email.field.id"))).sendKeys(adminEmail);
+
+ driver.findElement(By.xpath(UIElementMapper.getInstance().getElement("add.tenant.save.button.xpath"))).click();
+
+ // handle confirmation popup
+ String dialog = driver.getWindowHandle();
+ driver.switchTo().window(dialog);
+
+ if (driver.findElement(By.id(UIElementMapper.getInstance().getElement("mb.popup.dialog.id"))).getText().contains("successful")) {
+ isSuccessful = true; // got success confirmation box
+ }
+
+ // find ok button in popup dialog and click it
+ List buttonList = driver.findElements(By.tagName("button"));
+ for (WebElement okButton : buttonList) {
+ if (okButton.getText().compareToIgnoreCase("ok") == 0) {
+ okButton.click();
+ break;
+ }
+ }
+
+ return isSuccessful;
+ }
+
+}
diff --git a/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/configure/AddRoleStep1Page.java b/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/configure/AddRoleStep1Page.java
new file mode 100644
index 00000000..c9a8308a
--- /dev/null
+++ b/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/configure/AddRoleStep1Page.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2005-2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.wso2.mb.integration.common.utils.ui.pages.configure;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebDriver;
+import org.wso2.mb.integration.common.utils.ui.UIElementMapper;
+
+public class AddRoleStep1Page {
+
+ private static final Log log = LogFactory.getLog(AddRoleStep1Page.class);
+ private WebDriver driver;
+
+ public AddRoleStep1Page(WebDriver driver){
+ this.driver = driver;
+ if (!driver.findElement(By.xpath(UIElementMapper.getInstance().getElement("usr.mgt.add.role.step1.sub.header.xpath")))
+ .getText().contains("Step 1 : Enter role details")) {
+ throw new IllegalStateException("This is not the Add Role step1 page");
+ }
+ }
+
+ public void setDetails(final String roleName) {
+ driver.findElement(By.xpath(UIElementMapper.getInstance().getElement("usr.mgt.add.role.step1.name.field.xpath"))).sendKeys(roleName);
+ }
+
+ public AddRoleStep2Page next() {
+ driver.findElement(By.xpath(UIElementMapper.getInstance().getElement("usr.mgt.add.role.step1.next.button.xpath"))).click();
+ return new AddRoleStep2Page(driver);
+ }
+}
diff --git a/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/configure/AddRoleStep2Page.java b/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/configure/AddRoleStep2Page.java
new file mode 100644
index 00000000..85dd1532
--- /dev/null
+++ b/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/configure/AddRoleStep2Page.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2005-2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.wso2.mb.integration.common.utils.ui.pages.configure;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebDriver;
+import org.wso2.mb.integration.common.utils.ui.UIElementMapper;
+
+import java.util.List;
+
+public class AddRoleStep2Page {
+
+ private static final Log log = LogFactory.getLog(AddRoleStep2Page.class);
+ private WebDriver driver;
+
+ public AddRoleStep2Page(WebDriver driver){
+ this.driver = driver;
+ if (!driver.findElement(By.xpath(UIElementMapper.getInstance().getElement("usr.mgt.add.role.step2.sub.header.xpath")))
+ .getText().contains("Step 2 : Select permissions to add to Role")) {
+ throw new IllegalStateException("This is not the Add Role step2 page");
+ }
+ }
+
+ public void selectPermission(String permissionXpath) {
+ driver.findElement(By.xpath(UIElementMapper.getInstance().getElement(permissionXpath))).click();
+ }
+
+ public AddRoleStep3Page next() {
+ driver.findElement(By.xpath(UIElementMapper.getInstance().getElement("usr.mgt.add.role.step2.next.button.xpath"))).click();
+ return new AddRoleStep3Page(driver);
+ }
+
+}
diff --git a/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/configure/AddRoleStep3Page.java b/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/configure/AddRoleStep3Page.java
new file mode 100644
index 00000000..ff412b7f
--- /dev/null
+++ b/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/configure/AddRoleStep3Page.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2005-2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.wso2.mb.integration.common.utils.ui.pages.configure;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.wso2.mb.integration.common.utils.ui.UIElementMapper;
+
+import java.util.List;
+
+public class AddRoleStep3Page {
+
+ private static final Log log = LogFactory.getLog(AddRoleStep3Page.class);
+ private WebDriver driver;
+
+ public AddRoleStep3Page(WebDriver driver){
+ this.driver = driver;
+ if (!driver.findElement(By.xpath(UIElementMapper.getInstance()
+ .getElement("usr.mgt.add.role.step3.sub.header.xpath"))).getText().contains("Step 3")) {
+ throw new IllegalStateException("This is not the Add Role step3 page");
+ }
+ }
+
+ public boolean finish(){
+ boolean isSuccessful = false;
+ driver.findElement(By.xpath(UIElementMapper.getInstance().getElement("usr.mgt.add.role.step3.finish.button.xpath"))).click();
+ // handle delete confirmation popup
+ String dialog = driver.getWindowHandle();
+ driver = driver.switchTo().window(dialog);
+
+ WebElement e = driver.findElement(By.id("messagebox-info"));
+ if(e.findElement(By.tagName("p")).getText().contains("is added successfully")) {
+ isSuccessful = true;
+ }
+ // find ok button in popup dialog and click it
+ List buttonList = driver.findElements(By.tagName("button"));
+ for (WebElement okButton : buttonList) {
+ if (okButton.getText().compareToIgnoreCase("ok") == 0) {
+ okButton.click();
+ break;
+ }
+ }
+ dialog = driver.getWindowHandle();
+ driver = driver.switchTo().window(dialog);
+ return isSuccessful;
+ }
+
+ public void selectUsers(List userXpathList) {
+ for(String userXpath: userXpathList){
+ driver.findElement(By.xpath(userXpath)).click();
+ }
+ }
+}
diff --git a/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/configure/AddSecondaryUserStorePage.java b/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/configure/AddSecondaryUserStorePage.java
new file mode 100644
index 00000000..4b05bd12
--- /dev/null
+++ b/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/configure/AddSecondaryUserStorePage.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2005-2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.wso2.mb.integration.common.utils.ui.pages.configure;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebDriver;
+import org.wso2.mb.integration.common.utils.ui.UIElementMapper;
+
+import java.io.IOException;
+
+public class AddSecondaryUserStorePage {
+ private static final Log log = LogFactory.getLog(AddSecondaryUserStorePage.class);
+ private WebDriver driver;
+ private UIElementMapper uiElementMapper;
+
+ public AddSecondaryUserStorePage(WebDriver driver) throws IOException {
+ this.driver = driver;
+ this.uiElementMapper = UIElementMapper.getInstance();
+ // Check that we're on the right page.
+ if (!driver.getCurrentUrl().contains("/userstore_config/userstore-config.jsp")) {
+ throw new IllegalStateException("This is not the \"Add Secondary User Store\" page");
+ }
+ }
+}
diff --git a/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/configure/AddUserStep1Page.java b/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/configure/AddUserStep1Page.java
new file mode 100644
index 00000000..72a900c2
--- /dev/null
+++ b/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/configure/AddUserStep1Page.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2005-2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.wso2.mb.integration.common.utils.ui.pages.configure;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebDriver;
+import org.wso2.mb.integration.common.utils.ui.UIElementMapper;
+
+public class AddUserStep1Page {
+ private static final Log log = LogFactory.getLog(AddUserStep1Page.class);
+ private WebDriver driver;
+
+ public AddUserStep1Page(WebDriver driver){
+ this.driver = driver;
+ if (!driver.findElement(By.xpath(UIElementMapper.getInstance()
+ .getElement("usr.mgt.add.user.step1.sub.header.xpath"))).getText().contains("Step 1 : Enter user name")) {
+ throw new IllegalStateException("This is not the add users step1 page");
+ }
+ }
+
+ public void addUserDetails(final String userName, final String password, final String repeatPassword) {
+ driver.findElement(By.xpath(UIElementMapper.getInstance().getElement("usr.mgt.add.user.step1.user.name.field.xpath")))
+ .sendKeys(userName);
+ driver.findElement(By.xpath(UIElementMapper.getInstance().getElement("usr.mgt.add.user.step1.password.field.xpath")))
+ .sendKeys(password);
+ driver.findElement(By.xpath(UIElementMapper.getInstance().getElement("usr.mgt.add.user.step1.password.repeat.field.xpath")))
+ .sendKeys(repeatPassword);
+ }
+
+ public AddUserStep2Page next() {
+ driver.findElement(By.xpath(UIElementMapper.getInstance().getElement("usr.mgt.add.user.step1.next.button.xpath"))).click();
+ return new AddUserStep2Page(driver);
+ }
+}
diff --git a/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/configure/AddUserStep2Page.java b/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/configure/AddUserStep2Page.java
new file mode 100644
index 00000000..349b05de
--- /dev/null
+++ b/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/configure/AddUserStep2Page.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2005-2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.wso2.mb.integration.common.utils.ui.pages.configure;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.wso2.mb.integration.common.utils.ui.UIElementMapper;
+import org.wso2.mb.integration.common.utils.ui.pages.MBPage;
+
+import java.util.List;
+
+/**
+ * UI test class related to the second page of the queue add wizard of Management console
+ */
+public class AddUserStep2Page extends MBPage{
+
+ private static final Log log = LogFactory.getLog(AddUserStep2Page.class);
+
+ /**
+ * Checks whether the current page is the correct add user step 2 page. if not throws a
+ * runtime exception (IllegalStateException)
+ * @param driver WebDriver
+ */
+ public AddUserStep2Page(WebDriver driver) {
+ super(driver);
+ if (!driver.findElement(By.xpath(UIElementMapper.getInstance()
+ .getElement("usr.mgt.add.user.step2.sub.header.xpath"))).getText().contains("Step 2 : Select roles of the user")) {
+ throw new IllegalStateException("This is not the Add User step2 page");
+ }
+ }
+
+ public boolean selectRole(final String role){
+ WebElement tableData = driver.findElement(By.xpath(UIElementMapper.getInstance()
+ .getElement("usr.mgt.add.user.step2.select.roles.td.xpath")));
+ List inputList = tableData.findElements(By.tagName("input"));
+ for(WebElement e: inputList){
+ if((e.getAttribute("type").compareTo("checkbox") == 0) && (e.getAttribute("value").compareTo(role) == 0)) {
+ e.click();
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public boolean finish() {
+ boolean isSuccessful = false;
+ driver.findElement(By.xpath(UIElementMapper.getInstance().getElement("usr.mgt.add.user.step2.finish.button"))).click();
+ String dialog = driver.getWindowHandle();
+ driver = driver.switchTo().window(dialog);
+
+ WebElement e = driver.findElement(By.id("messagebox-info"));
+ if(e.findElement(By.tagName("p")).getText().contains("is added successfully")) {
+ isSuccessful = true;
+ }
+
+ // find ok button in popup dialog and click it
+ List buttonList = driver.findElements(By.tagName("button"));
+ for (WebElement okButton : buttonList) {
+ if (okButton.getText().compareToIgnoreCase("ok") == 0) {
+ okButton.click();
+ break;
+ }
+ }
+ dialog = driver.getWindowHandle();
+ driver = driver.switchTo().window(dialog);
+ return isSuccessful;
+ }
+
+}
diff --git a/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/configure/ConfigurePage.java b/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/configure/ConfigurePage.java
new file mode 100644
index 00000000..62330ea1
--- /dev/null
+++ b/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/configure/ConfigurePage.java
@@ -0,0 +1,79 @@
+/*
+* Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+*
+* WSO2 Inc. licenses this file to you under the Apache License,
+* Version 2.0 (the "License"); you may not use this file except
+* in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT 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.wso2.mb.integration.common.utils.ui.pages.configure;
+
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebDriver;
+import org.wso2.mb.integration.common.utils.ui.UIElementMapper;
+
+import java.io.IOException;
+
+/**
+ * Abstraction of the Configuration tab page of the UI.
+ */
+public class ConfigurePage {
+ private WebDriver driver;
+
+ /**
+ * Initializes configuration page.
+ * @param driver The selenium web driver.
+ * @throws IOException
+ */
+ public ConfigurePage(WebDriver driver) throws IOException {
+ this.driver = driver;
+ // Check that we're on the right page.
+ String attr = driver.findElement(By.id(UIElementMapper.getInstance().getElement("configure.panel.button.id"))).getAttribute("class");
+
+ if (attr.compareTo("menu-panel-buttons selected") != 0) {
+ throw new IllegalStateException("This is not the Configure page");
+ }
+ }
+
+ /**
+ * User store Management store page is selected from UI and returned
+ *
+ * @return The user management store page.
+ * @throws IOException
+ */
+ public UserStoreManagementPage getUserStoreManagementPage() throws IOException {
+ driver.findElement(By.xpath(UIElementMapper.getInstance().getElement("configure.user.store.management.xpath"))).click();
+ return new UserStoreManagementPage(driver);
+ }
+
+ /**
+ * New Tenant creation page link is selected from Configure tab page in UI and AddNewTenantPage
+ * is returned
+ *
+ * @return The tenant adding page.
+ */
+ public AddNewTenantPage getAddNewTenantPage() {
+ driver.findElement(By.xpath(UIElementMapper.getInstance().getElement("configure.multitenancy.add.new.tenant.xpath"))).click();
+ return new AddNewTenantPage(driver);
+ }
+
+ /**
+ * User Management page link is selected from Configure tab page in UI
+ *
+ * @return The user management page to add users and roles.
+ */
+ public UserManagementPage getUserManagementPage() {
+ driver.findElement(By.xpath(UIElementMapper.getInstance().getElement("configure.users.and.roles.button.xpath"))).click();
+ return new UserManagementPage(driver);
+ }
+}
diff --git a/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/configure/TenantHomePage.java b/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/configure/TenantHomePage.java
new file mode 100644
index 00000000..cf88eda8
--- /dev/null
+++ b/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/configure/TenantHomePage.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2005-2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.wso2.mb.integration.common.utils.ui.pages.configure;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebDriver;
+import org.wso2.mb.integration.common.utils.ui.pages.login.LoginPage;
+import org.wso2.mb.integration.common.utils.ui.UIElementMapper;
+
+import java.io.IOException;
+
+/**
+ * This page represents Tenant Home page in MB management console.
+ */
+public class TenantHomePage {
+
+ private static final Log log = LogFactory.getLog(TenantHomePage.class);
+ private WebDriver driver;
+
+ /**
+ * This constructor test whether the web driver is in correct page.
+ * @param driver WebDriver
+ */
+ public TenantHomePage(WebDriver driver){
+ this.driver = driver;
+ // Check that we're on the right page.
+ if (!driver.findElement(By.xpath(UIElementMapper.getInstance()
+ .getElement("mb.tenant.home.page.menu.header.xpath"))).getText().contains("Home")) {
+ throw new IllegalStateException("This is not the tenant home page");
+ }
+ }
+
+ /**
+ * Logout from home page. Login page is returned
+ * @return LoginPage
+ * @throws IOException
+ */
+ public LoginPage logout() throws IOException {
+ driver.findElement(By.xpath(UIElementMapper.getInstance().getElement("mb.tenant.sign.out.xpath"))).click();
+ return new LoginPage(driver);
+ }
+}
diff --git a/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/configure/UserManagementPage.java b/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/configure/UserManagementPage.java
new file mode 100644
index 00000000..0b4838c4
--- /dev/null
+++ b/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/configure/UserManagementPage.java
@@ -0,0 +1,67 @@
+/*
+* Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+*
+* WSO2 Inc. licenses this file to you under the Apache License,
+* Version 2.0 (the "License"); you may not use this file except
+* in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT 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.wso2.mb.integration.common.utils.ui.pages.configure;
+
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebDriver;
+import org.wso2.mb.integration.common.utils.ui.UIElementMapper;
+
+/**
+ * This class represents the user management class.
+ */
+public class UserManagementPage {
+ private WebDriver driver;
+
+ /**
+ * Creates a user management class.
+ *
+ * @param driver The selenium web driver.
+ */
+ public UserManagementPage(WebDriver driver) {
+ this.driver = driver;
+
+ if (!driver.findElement(By.xpath(UIElementMapper.getInstance()
+ .getElement("configure.user.mgt.header.xpath"))).getText().contains("Add Users and Roles")) {
+
+ throw new IllegalStateException("This is not the User Management page");
+ }
+ }
+
+ /**
+ * Gets the first page in creating a new role
+ *
+ * @return The page that appears first when creating a new role
+ */
+ public AddRoleStep1Page getAddRolePage() {
+ driver.findElement(By.xpath(UIElementMapper.getInstance().getElement("configure.usr.mgt.roles.link.xpath")))
+ .click();
+ return new AddRoleStep1Page(driver);
+ }
+
+ /**
+ * Gets the first page in creating a new new
+ *
+ * @return The page that appears first when creating a new user
+ */
+ public AddUserStep1Page getAddNewUserPage() {
+ driver.findElement(By.xpath(UIElementMapper.getInstance().getElement("configure.usr.mgt.users.link.xpath")))
+ .click();
+ return new AddUserStep1Page(driver);
+ }
+}
diff --git a/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/configure/UserStoreManagementPage.java b/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/configure/UserStoreManagementPage.java
new file mode 100644
index 00000000..1dd90e7c
--- /dev/null
+++ b/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/configure/UserStoreManagementPage.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2005-2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.wso2.mb.integration.common.utils.ui.pages.configure;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebDriver;
+import org.wso2.mb.integration.common.utils.ui.pages.configure.AddSecondaryUserStorePage;
+import org.wso2.mb.integration.common.utils.ui.UIElementMapper;
+
+import java.io.IOException;
+
+public class UserStoreManagementPage {
+ private static final Log log = LogFactory.getLog(UserStoreManagementPage.class);
+ private WebDriver driver;
+ private UIElementMapper uiElementMapper;
+
+ public UserStoreManagementPage(WebDriver driver) throws IOException {
+ this.driver = driver;
+ this.uiElementMapper = UIElementMapper.getInstance();
+ // Check that we're on the right page.
+ if (!driver.findElement(By.id(uiElementMapper.getElement("configure.user.store.management.header.id")))
+ .getText().contains("Add New User Store")) {
+ throw new IllegalStateException("This is not the User Store Management page");
+ }
+ }
+
+ public AddSecondaryUserStorePage addSecondaryUserStore() throws IOException {
+ driver.findElement(By.xpath(uiElementMapper.getElement("configure.user.store.management.add.secondary.userstore"))).click();
+ return new AddSecondaryUserStorePage(driver);
+ }
+}
diff --git a/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/login/LoginPage.java b/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/login/LoginPage.java
new file mode 100644
index 00000000..8692735c
--- /dev/null
+++ b/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/login/LoginPage.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2005-2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.wso2.mb.integration.common.utils.ui.pages.login;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.wso2.mb.integration.common.utils.ui.pages.configure.TenantHomePage;
+import org.wso2.mb.integration.common.utils.ui.pages.main.HomePage;
+import org.wso2.mb.integration.common.utils.ui.UIElementMapper;
+
+import java.io.IOException;
+
+/**
+ * Login page class - contains methods to login to wso2 products.
+ */
+public class LoginPage {
+ private static final Log log = LogFactory.getLog(LoginPage.class);
+ private WebDriver driver;
+
+ public LoginPage(WebDriver driver) throws IOException {
+ this.driver = driver;
+ // Check that we're on the right page.
+ if (!(driver.getCurrentUrl().contains("login.jsp"))) {
+ // Alternatively, we could navigate to the login page, perhaps logging out first
+ throw new IllegalStateException("This is not the login page");
+ }
+ }
+
+ /**
+ * Provide facility to log into the products using user credentials
+ *
+ * @param userName login user name
+ * @param password login password
+ * @return reference to Home page
+ * @throws java.io.IOException if mapper.properties file not found
+ */
+ public HomePage loginAs(final String userName, final String password) throws IOException {
+ log.info("Login as " + userName);
+ WebElement userNameField = driver.findElement(By.id(UIElementMapper.getInstance()
+ .getElement("login.username.id")));
+ WebElement passwordField = driver.findElement(By.id(UIElementMapper.getInstance()
+ .getElement("login.password.id")));
+ userNameField.sendKeys(userName);
+ passwordField.sendKeys(password);
+ driver.findElement(By.className(UIElementMapper.getInstance().getElement("login.sign" +
+ ".in.button"))).click();
+ driver.findElement(By.id(UIElementMapper.getInstance().getElement("main.tab.id"))).click();
+ return new HomePage(driver);
+ }
+
+ public TenantHomePage loginAsTenant(final String userName, final String domain, final String password){
+ log.info("Login as " + userName);
+ WebElement userNameField = driver.findElement(By.id(UIElementMapper.getInstance()
+ .getElement("login.username.id")));
+ WebElement passwordField = driver.findElement(By.id(UIElementMapper.getInstance()
+ .getElement("login.password.id")));
+ userNameField.sendKeys(userName + "@" + domain);
+ passwordField.sendKeys(password);
+ driver.findElement(By.className(UIElementMapper.getInstance().getElement("login.sign.in" +
+ ".button"))).click();
+ driver.findElement(By.id(UIElementMapper.getInstance().getElement("main.tab.id"))).click();
+ return new TenantHomePage(driver);
+
+
+ }
+
+}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/main/DLCBrowsePage.java b/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/main/DLCBrowsePage.java
new file mode 100644
index 00000000..a028ec1c
--- /dev/null
+++ b/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/main/DLCBrowsePage.java
@@ -0,0 +1,81 @@
+/*
+* Copyright (c) 2005-2010, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+*
+* WSO2 Inc. licenses this file to you under the Apache License,
+* Version 2.0 (the "License"); you may not use this file except
+* in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT 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.wso2.mb.integration.common.utils.ui.pages.main;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.wso2.mb.integration.common.utils.ui.UIElementMapper;
+
+import java.io.IOException;
+
+/**
+ * This page represents 'Dead Letter Channel -> Browse' page in MB management console.
+ */
+public class DLCBrowsePage {
+ private static final Log log = LogFactory.getLog(DLCBrowsePage.class);
+ private WebDriver driver;
+
+ /**
+ * Retrieve Page consists DeadLetterChannel
+ *
+ * @param driver selenium web driver used to run the test
+ * @throws IOException if mapper.properties file not found
+ */
+ public DLCBrowsePage(WebDriver driver) throws IOException {
+ this.driver = driver;
+ // Check that we're on the right page.
+ if (!driver.findElement(By.xpath(UIElementMapper.getInstance()
+ .getElement("home.dlc.header.xpath"))).getText()
+ .contains("Dead Letter Channel")) {
+ throw new IllegalStateException("This is not the DLC page");
+ }
+ }
+
+ /**
+ * Browse for content of DeadLetter Channel
+ * Retrieve 'Dead Letter Channel -> Browse -> Queue Content' page
+ *
+ * @return Content of DeadLetter Channel
+ * @throws IOException if mapper.properties file not found
+ */
+ public DLCContentPage getDLCContent() throws IOException {
+ driver.findElement(By.xpath(UIElementMapper.getInstance()
+ .getElement("mb.dlc.browse.table.browse.button.xpath"))).click();
+ return new DLCContentPage(driver);
+ }
+
+ /**
+ * Check whether dead letter channel created or not
+ *
+ * @return true when dead letter channel created
+ */
+ public boolean isDLCCreated() {
+ boolean isDLCCreated = false;
+ WebElement queueTable;
+ queueTable = driver.findElement(By.xpath(UIElementMapper.getInstance()
+ .getElement("mb.dlc.browse.table.xpath")));
+ if (queueTable != null) {
+ isDLCCreated = true;
+ }
+ return isDLCCreated;
+ }
+}
diff --git a/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/main/DLCContentPage.java b/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/main/DLCContentPage.java
new file mode 100644
index 00000000..c1ae5957
--- /dev/null
+++ b/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/main/DLCContentPage.java
@@ -0,0 +1,177 @@
+package org.wso2.mb.integration.common.utils.ui.pages.main;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.wso2.mb.integration.common.utils.ui.UIElementMapper;
+
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * This page represents ' Dead Letter Channel -> Browse -> Queue Content' page in MB management console.
+ */
+public class DLCContentPage {
+ private static final Log log = LogFactory.getLog(DLCContentPage.class);
+ private WebDriver driver;
+
+ /**
+ * Retrieve page consists content of DeadLetter Channel
+ *
+ * @param driver selenium web driver used to run the test
+ * @throws IOException if mapper.properties file not found
+ */
+ public DLCContentPage(WebDriver driver) throws IOException {
+ this.driver = driver;
+ // Check that we're on the right page.
+ if (!driver.findElement(By.xpath(UIElementMapper.getInstance()
+ .getElement("mb.dlc.queue.content"))).getText()
+ .contains("Queue Content: DeadLetterChannel")) {
+ throw new IllegalStateException("This is not the DLC Queue Content page");
+ }
+ }
+
+ /**
+ * Test deleting messages of DeadLetter Channel
+ */
+ public String deleteFunction() throws IOException {
+ String deletingMessageID;
+
+ driver.findElement(By.xpath(UIElementMapper.getInstance()
+ .getElement("mb.dlc.browse.table.choose.box.xpath"))).click();
+ deletingMessageID = driver.findElement(By.xpath(UIElementMapper.getInstance()
+ .getElement("mb.dlc.first.message.id"))).getText();
+ driver.findElement(By.xpath(UIElementMapper.getInstance()
+ .getElement("mb.dlc.browse.table.delete.button"))).click();
+ driver.findElement(By.xpath(UIElementMapper.getInstance()
+ .getElement("mb.dlc.browse.function.confirm"))).click();
+ driver.findElement(By.xpath(UIElementMapper.getInstance()
+ .getElement("mb.dlc.browse.function.success"))).click();
+ return deletingMessageID;
+ }
+
+ /**
+ * Delete all the messages in DeadLetter Channel
+ */
+ public void deleteAllDLCMessages() {
+
+ // Get all elements in dlc table
+ WebElement dlcTable = driver.findElement(By.xpath(UIElementMapper.getInstance()
+ .getElement("mb.dlc.browse.content.table")));
+ // Get all the TR elements from the table
+ List allDlcRows = dlcTable.findElements(By.tagName("tr"));
+
+ //A row represents a message in DLC
+ //Therefore comparing the row count with zero is used to see if the message list is empty
+ if (allDlcRows.size() > 0) {
+ log.info("delete all dlc messages");
+ driver.findElement(By.xpath(UIElementMapper.getInstance()
+ .getElement("mb.dlc.browse.table.choose.all.box.xpath")))
+ .click();
+ driver.findElement(By.xpath(UIElementMapper.getInstance().getElement("mb.dlc.browse.table.delete.button")))
+ .click();
+ driver.findElement(By.xpath(UIElementMapper.getInstance().getElement("mb.dlc.browse.function.confirm")))
+ .click();
+ driver.findElement(By.xpath(UIElementMapper.getInstance().getElement("mb.dlc.browse.function.success")))
+ .click();
+ }
+ }
+
+ /**
+ * Test restoring messages of DeadLetter Channel
+ */
+ public String restoreFunction() throws IOException {
+ String restoringMessageID;
+
+ driver.findElement(By.xpath(UIElementMapper.getInstance()
+ .getElement("mb.dlc.browse.table.choose.box.xpath"))).click();
+ restoringMessageID = driver.findElement(By.xpath(UIElementMapper.getInstance()
+ .getElement("mb.dlc.first.message.id"))).getText();
+ driver.findElement(By.xpath(UIElementMapper.getInstance()
+ .getElement("mb.dlc.browse.table.restore.button"))).click();
+ driver.findElement(By.xpath(UIElementMapper.getInstance()
+ .getElement("mb.dlc.browse.function.confirm"))).click();
+ driver.findElement(By.xpath(UIElementMapper.getInstance()
+ .getElement("mb.dlc.browse.function.success"))).click();
+
+ return restoringMessageID;
+ }
+
+ /**
+ * Test rerouting messages of DeadLetter Channel
+ */
+ public String rerouteFunction(String qName) throws IOException {
+ String reroutingMessageID;
+
+ driver.findElement(By.xpath(UIElementMapper.getInstance()
+ .getElement("mb.dlc.browse.table.choose.box.xpath"))).click();
+ reroutingMessageID = driver.findElement(By.xpath(UIElementMapper.getInstance()
+ .getElement("mb.dlc.first.message.id"))).getText();
+ driver.findElement(By.xpath(UIElementMapper.getInstance()
+ .getElement("mb.dlc.browse.table.reroute.button"))).click();
+ //select rerouteTestQueue to reroute message
+ WebElement select = driver.findElement(By.xpath(UIElementMapper.getInstance()
+ .getElement("mb.dlc.browse.table.reroute.queue.select")));
+ List options = select.findElements(By.tagName(UIElementMapper.getInstance()
+ .getElement("mb.dlc.browse.table.reroute.queue.option")));
+ for (WebElement option : options) {
+ if (option.getText().equals(qName)) {
+ option.click();
+ break;
+ }
+ }
+ driver.findElement(By.xpath(UIElementMapper.getInstance()
+ .getElement("mb.dlc.browse.table.reroute.confirm"))).click();
+ driver.findElement(By.xpath(UIElementMapper.getInstance()
+ .getElement("mb.dlc.browse.function.confirm"))).click();
+ driver.findElement(By.xpath(UIElementMapper.getInstance()
+ .getElement("mb.dlc.browse.function.success"))).click();
+ return reroutingMessageID;
+ }
+
+ /**
+ * Test reroute all messages function in DLC when its enabled.
+ *
+ * @param sourceDestination The destination from which the messages needs to be transferred.
+ * @param targetDestination The destination which the messages need to be transferred to.
+ * @throws IOException
+ */
+ public void rerouteAllFunction(String sourceDestination, String targetDestination) throws IOException {
+ driver.findElement(By.xpath(UIElementMapper.getInstance()
+ .getElement("mb.dlc.browse.table.reroute.all.button"))).click();
+
+ // Selection source destination
+ WebElement sourceDestinationDropDown = driver.findElement(By.xpath(UIElementMapper.getInstance()
+ .getElement("mb.dlc.browse.table.reroute.all.source.select")));
+ List sourceDestinationOptions = sourceDestinationDropDown.findElements(By.tagName(UIElementMapper.getInstance()
+ .getElement("mb.dlc.browse.table.reroute.queue.option")));
+ for (WebElement option : sourceDestinationOptions) {
+ if (option.getText().equals(sourceDestination)) {
+ option.click();
+ break;
+ }
+ }
+
+ // Selection target destination
+ WebElement targetDestinationDropDown = driver.findElement(By.xpath(UIElementMapper.getInstance()
+ .getElement("mb.dlc.browse.table.reroute.all.target.select")));
+ List targetDestinationOptions = targetDestinationDropDown.findElements(By.tagName(UIElementMapper.getInstance()
+ .getElement("mb.dlc.browse.table.reroute.queue.option")));
+ for (WebElement option : targetDestinationOptions) {
+ if (option.getText().equals(targetDestination)) {
+ option.click();
+ break;
+ }
+ }
+
+ driver.findElement(By.xpath(UIElementMapper.getInstance()
+ .getElement("mb.dlc.browse.table.reroute.confirm"))).click();
+ driver.findElement(By.xpath(UIElementMapper.getInstance()
+ .getElement("mb.dlc.browse.function.confirm"))).click();
+ driver.findElement(By.xpath(UIElementMapper.getInstance()
+ .getElement("mb.dlc.browse.function.success"))).click();
+ }
+
+}
diff --git a/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/main/HomePage.java b/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/main/HomePage.java
new file mode 100644
index 00000000..0bcc97e5
--- /dev/null
+++ b/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/main/HomePage.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2005-2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.wso2.mb.integration.common.utils.ui.pages.main;
+
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebDriver;
+import org.wso2.mb.integration.common.utils.ui.UIElementMapper;
+import org.wso2.mb.integration.common.utils.ui.pages.MBPage;
+
+import java.io.IOException;
+
+/**
+ * Home page class holds the information of product page you got once login
+ * NOTE: To navigate to a page Don't use direct links to pages. To ensure there is a UI element to navigate to
+ * that page.
+ */
+public class HomePage extends MBPage {
+
+ /**
+ * Checks whether the current page is the home page. if not throws a runtime exception
+ *
+ * @param driver WebDriver
+ */
+ public HomePage(WebDriver driver) {
+ super(driver);
+ // Check that we're on the right page.
+ if (!driver.findElement(By.id(
+ UIElementMapper.getInstance().getElement("home.dashboard.middle.text"))).getText()
+ .contains("Home")) {
+ throw new IllegalStateException("This is not the home page");
+ }
+ }
+
+ /**
+ * Clicks on the dead letter channel browsing page.
+ *
+ * @return A {@link org.wso2.mb.integration.common.utils.ui.pages.main.DLCBrowsePage}
+ * @throws IOException
+ */
+ public DLCBrowsePage getDLCBrowsePage() throws IOException {
+ this.clickOnMenuItem("home.mb.dlc.browse.xpath");
+ return new DLCBrowsePage(driver);
+ }
+
+ /**
+ * Clicks on the queue browsing page.
+ *
+ * @return A {@link org.wso2.mb.integration.common.utils.ui.pages.main.QueuesBrowsePage}
+ * @throws IOException
+ */
+ public QueuesBrowsePage getQueuesBrowsePage() throws IOException {
+ this.clickOnMenuItem("home.mb.queues.browse.xpath");
+ return new QueuesBrowsePage(driver);
+ }
+
+ /**
+ * Clicks on the queue browsing page.
+ *
+ * @return A {@link org.wso2.mb.integration.common.utils.ui.pages.main.QueueSubscriptionsPage}
+ * @throws IOException
+ */
+ public QueueSubscriptionsPage getQueueSubscriptionsPage() throws IOException {
+ this.clickOnMenuItem("home.mb.queues.subscriptions.xpath");
+ return new QueueSubscriptionsPage(driver);
+ }
+
+ /**
+ * Clicks on the queue adding page.
+ *
+ * @return A {@link org.wso2.mb.integration.common.utils.ui.pages.main.QueueAddPage}
+ * @throws IOException
+ */
+ public QueueAddPage getQueueAddPage() throws IOException {
+ this.clickOnMenuItem("home.mb.queues.add.xpath");
+ return new QueueAddPage(driver);
+ }
+
+ /**
+ * Clicks on the topic adding page.
+ *
+ * @return A {@link org.wso2.mb.integration.common.utils.ui.pages.main.TopicAddPage}
+ * @throws IOException
+ */
+ public TopicAddPage getTopicAddPage() throws IOException {
+ this.clickOnMenuItem("home.mb.topics.add.xpath");
+ return new TopicAddPage(driver);
+ }
+
+ /**
+ * Click on the topic browsing page
+ *
+ * @return A {@link org.wso2.mb.integration.common.utils.ui.pages.main.TopicsBrowsePage}
+ * @throws IOException
+ */
+ public TopicsBrowsePage getTopicsBrowsePage() throws IOException {
+ this.clickOnMenuItem("home.mb.topics.browse.xpath");
+ return new TopicsBrowsePage(driver);
+ }
+
+ /**
+ * Clicks on the topic adding page
+ *
+ * @param xPathForTopicMenuItem The xPath of the topic adding page.
+ * @return A {@link org.wso2.mb.integration.common.utils.ui.pages.main.TopicAddPage}
+ */
+ public TopicAddPage getTopicAddPage(String xPathForTopicMenuItem) {
+ this.clickOnMenuItem(xPathForTopicMenuItem);
+ return new TopicAddPage(driver);
+ }
+
+ /**
+ * Click on the topic browsing page
+ *
+ * @param xPathForTopicMenuItem The xPath of the topic browsing page.
+ * @return A {@link org.wso2.mb.integration.common.utils.ui.pages.main.TopicsBrowsePage}
+ * @throws IOException
+ */
+ public TopicsBrowsePage getTopicsBrowsePage(String xPathForTopicMenuItem) throws IOException {
+ this.clickOnMenuItem(xPathForTopicMenuItem);
+ return new TopicsBrowsePage(driver);
+ }
+
+ /**
+ * Click on the topic subscriptions page.
+ *
+ * @return A {@link org.wso2.mb.integration.common.utils.ui.pages.main.TopicSubscriptionsPage}
+ * @throws IOException
+ */
+ public TopicSubscriptionsPage getTopicSubscriptionsPage() throws IOException {
+ this.clickOnMenuItem("home.mb.topic.subscriptions.xpath");
+ return new TopicSubscriptionsPage(driver);
+ }
+
+ /**
+ * Clicks on a menu item with a given xPath
+ *
+ * @param xPathForMenuItem The xPath for the menu item.
+ */
+ private void clickOnMenuItem(String xPathForMenuItem) {
+ driver.findElement(By.xpath(UIElementMapper.getInstance().getElement(xPathForMenuItem)))
+ .click();
+ }
+}
diff --git a/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/main/MessageContentPage.java b/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/main/MessageContentPage.java
new file mode 100644
index 00000000..dcedc9bf
--- /dev/null
+++ b/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/main/MessageContentPage.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.wso2.mb.integration.common.utils.ui.pages.main;
+
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebDriver;
+import org.wso2.mb.integration.common.utils.ui.UIElementMapper;
+
+import java.io.IOException;
+
+/**
+ * This page represents 'Queues-> Browse' page in MB management console.
+ *
+ */
+public class MessageContentPage {
+
+ private WebDriver driver;
+
+ public MessageContentPage(WebDriver driver) throws IOException {
+ this.driver = driver;
+ // Check that we're on the right page.
+ if (!driver.findElement(By.xpath(UIElementMapper.getInstance().getElement("mb.queue.content.page.header.xpath"))).getText().contains("Message Content")) {
+ throw new IllegalStateException("This is not the Message Content page");
+ }
+ }
+
+ /**
+ * Get the message length displayed in the text area.
+ * @return displayed message length
+ */
+ public int getDisplayedMessageLength() {
+ return driver.findElement(By.xpath(UIElementMapper.getInstance().getElement("mb.message.content.textarea.xpath"))).getText().length();
+ }
+
+}
diff --git a/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/main/QueueAddPage.java b/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/main/QueueAddPage.java
new file mode 100644
index 00000000..3506dfb7
--- /dev/null
+++ b/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/main/QueueAddPage.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2005-2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.wso2.mb.integration.common.utils.ui.pages.main;
+
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.wso2.mb.integration.common.utils.ui.UIElementMapper;
+import org.wso2.mb.integration.common.utils.ui.pages.MBPage;
+
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * UI test class related to queue add page of Management console.
+ */
+public class QueueAddPage extends MBPage {
+
+ /**
+ * Checks whether the current page the WebDriver is in is the correct queue add page. if not
+ * throws a runtime exception (IllegalStateException)
+ *
+ * @param driver WebDriver
+ */
+ public QueueAddPage(WebDriver driver) {
+ super(driver);
+ if(!driver.findElement(By.xpath(UIElementMapper.getInstance().
+ getElement("mb.add.queue.page.header.xpath"))).getText().contains("Add Queue")){
+ throw new IllegalStateException("This is not the Add Queue page");
+ }
+ }
+
+ /**
+ * Adds a queue with all without changing privileges for the queue
+ * @param qName queue name
+ * @return true if successful and false otherwise
+ * @throws IOException
+ */
+ public boolean addQueue(final String qName) throws IOException {
+ return addQueue(qName, true);
+ }
+
+ /**
+ * Adds a queue without privileges to any role or not explicitly specified
+ * @param qName queue name
+ * @param withoutPrivileges without privileges set to roles to consume or publish
+ * @return true if successful and false otherwise
+ * @throws IOException
+ */
+ public boolean addQueue(final String qName, boolean withoutPrivileges) throws IOException{
+ boolean isSuccessful = false;
+
+ WebElement qNameField = driver.findElement(By.id(UIElementMapper.getInstance()
+ .getElement("mb.add.queue.page.qname.field.id")));
+ qNameField.sendKeys(qName);
+
+ if(withoutPrivileges) {
+
+ // get permission table
+ WebElement table = driver.findElement(By.xpath(UIElementMapper.getInstance()
+ .getElement("mb.add.queue.page.permission.table")));
+
+ // get role name related publish consume checkboxes list for all the roles
+ List checkBoxList = table.findElements(By.tagName("input"));
+
+ // make all the permissions unchecked
+ for (WebElement element: checkBoxList) {
+ if(element.isSelected()) {
+ element.click(); // uncheck checkbox
+ }
+ }
+ }
+
+ driver.getWindowHandle();
+ driver.findElement(By.xpath(UIElementMapper.getInstance()
+ .getElement("mb.add.queue.page.add.button.xpath"))).click();
+ String dialog = driver.getWindowHandle();
+ driver.switchTo().window(dialog);
+ if(driver.findElement(By.id(UIElementMapper.getInstance()
+ .getElement("mb.popup.dialog.id"))).getText().contains("Queue added successfully")) {
+ isSuccessful =true;
+ }
+ driver.findElement(By.xpath(UIElementMapper.getInstance().getElement("mb.add.queue.page" +
+ ".onqueueadd.okbutton.xpath"))).click();
+
+ return isSuccessful;
+ }
+}
diff --git a/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/main/QueueContentPage.java b/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/main/QueueContentPage.java
new file mode 100644
index 00000000..909443d1
--- /dev/null
+++ b/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/main/QueueContentPage.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2005-2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.wso2.mb.integration.common.utils.ui.pages.main;
+
+import java.io.IOException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebDriver;
+import org.wso2.mb.integration.common.utils.ui.UIElementMapper;
+
+/**
+ * This page represents 'Queues-> Browse' page in MB management console.
+ *
+ */
+public class QueueContentPage {
+
+ private static final Log log = LogFactory.getLog(QueueContentPage.class);
+ private WebDriver driver;
+
+ public QueueContentPage(WebDriver driver) throws IOException {
+ this.driver = driver;
+ // Check that we're on the right page.
+ if (!driver.findElement(By.xpath(UIElementMapper.getInstance().getElement("mb.queue.content.page.header.xpath"))).getText().contains("Queue Content")) {
+ throw new IllegalStateException("This is not the Queue Content page");
+ }
+ }
+
+ /**
+ * Navigate to message content page related to the message on the given row index within the page. (e.g. 1st row)
+ * @param listIndex
+ */
+ public MessageContentPage viewFullMessage(int listIndex) throws IOException {
+
+ String xpath = UIElementMapper.getInstance().getElement("mb.queue.content.page.row.xpath").replaceAll("#REPLACE#",String.valueOf(listIndex));
+
+ driver.findElement(By.xpath(xpath)).click();
+
+ return new MessageContentPage(this.driver);
+ }
+
+}
diff --git a/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/main/QueueSubscriptionsPage.java b/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/main/QueueSubscriptionsPage.java
new file mode 100644
index 00000000..287d1608
--- /dev/null
+++ b/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/main/QueueSubscriptionsPage.java
@@ -0,0 +1,151 @@
+/*
+* Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+*
+* WSO2 Inc. licenses this file to you under the Apache License,
+* Version 2.0 (the "License"); you may not use this file except
+* in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT 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.wso2.mb.integration.common.utils.ui.pages.main;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.ui.Select;
+import org.wso2.mb.integration.common.utils.ui.UIElementMapper;
+import org.wso2.mb.integration.common.utils.ui.pages.MBPage;
+
+/**
+ * UI test class related to queue subscriptions page of Management console.
+ */
+public class QueueSubscriptionsPage extends MBPage{
+
+ private static Log log = LogFactory.getLog(QueueSubscriptionsPage.class);
+
+ /**
+ * Checks whether the current page the WebDriver is in is the correct queue subscriptions page.
+ * if not throws a runtime exception (IllegalStateException)
+ *
+ * @param driver WebDriver
+ */
+ protected QueueSubscriptionsPage(WebDriver driver) {
+ super(driver);
+ if(!driver.findElement(By.xpath(UIElementMapper.getInstance().
+ getElement("mb.queue.manage.subscriptions.page.xpath"))).getText().contains("Queue Subscription List")){
+ throw new IllegalStateException("This is not the Queue Subscriptions page");
+ }
+ }
+
+ /**
+ * Search queue subscriptions according to the search criteria.
+ *
+ * @param queueNamePattern string pattern of the queue name (* for all)
+ * @param identifierPattern string pattern of the identifier (* for all)
+ * @param ownNodeIdIndex index of the node Id in the dropdown the subscriptions belong to
+ * @return number of subscriptions listed under search result
+ */
+ public int searchQueueSubscriptions(String queueNamePattern, String identifierPattern, int ownNodeIdIndex,
+ boolean isNameExactMatch, boolean isIdentifierExactMatch) {
+
+ WebElement queueNamePatternField = driver.findElement(By.name(UIElementMapper.getInstance()
+ .getElement("mb.search.queue.name.pattern.tag.name")));
+ queueNamePatternField.clear();
+ queueNamePatternField.sendKeys(queueNamePattern);
+
+ WebElement queueNameExactMatchField = driver.findElement(
+ By.name(UIElementMapper.getInstance().getElement("mb.search.queue.name.exactmatch.tag.name")));
+ // Set the name exact match check box state based on the test input
+ if (isNameExactMatch != queueNameExactMatchField.isSelected()) {
+ queueNameExactMatchField.click();
+ }
+ WebElement queueIdentifierExactMatchField = driver.findElement(
+ By.name(UIElementMapper.getInstance().getElement("mb.search.queue.identifier.exactmatch.tag.name")));
+ // Set the identifier exact match check box state based on the test input
+ if (isIdentifierExactMatch != queueIdentifierExactMatchField.isSelected()) {
+ queueIdentifierExactMatchField.click();
+ }
+
+ WebElement queueIdentifierPatternField = driver.findElement(By.name(UIElementMapper.getInstance()
+ .getElement("mb.search.queue.identifier.pattern.tag.name")));
+ queueIdentifierPatternField.clear();
+ queueIdentifierPatternField.sendKeys(identifierPattern);
+
+ Select ownNodeIdDropdown = new Select(driver.findElement(By.id(UIElementMapper.getInstance()
+ .getElement("mb.search.queue.own.node.id.element.id"))));
+ ownNodeIdDropdown.selectByIndex(ownNodeIdIndex);
+
+ driver.findElement(By.xpath(UIElementMapper.getInstance()
+ .getElement("mb.search.queue.search.button.xpath"))).click();
+
+ return getSubscriptionCount();
+
+ }
+
+ /**
+ * Gets the number of queue subscriptions.
+ *
+ * @return the number of subscriptions.
+ */
+ public int getSubscriptionCount() {
+ int numberOfSubscribers = 0;
+
+ WebElement subscriptionTable = driver.findElement(By.xpath(UIElementMapper.getInstance()
+ .getElement("mb.subscriptions.queue.table.xpath")));
+ // Checks whether the table exists.
+ if ("table".equals(subscriptionTable.getTagName())) {
+ numberOfSubscribers = subscriptionTable.findElement(By.tagName("tbody")).findElements(By
+ .tagName("tr")).size();
+ }
+ if (numberOfSubscribers == 0) {
+ log.warn("Queue Subscriptions table does not exists.");
+ }
+ return numberOfSubscribers;
+ }
+
+ /**
+ * Close the first subscription out of the subscriptions listed on queue subscriptions page
+ *
+ * @return true if successful and false otherwise
+ */
+ public boolean closeTopSubscription() {
+
+ String deletingMessageID = driver.findElement(By.xpath(UIElementMapper.getInstance()
+ .getElement("mb.queue.subscriptions.table.delete.subid"))).getText();
+
+ driver.findElement(By.xpath(UIElementMapper.getInstance()
+ .getElement("mb.queue.subscriptions.table.delete.button"))).click();
+
+ driver.findElement(By.xpath(UIElementMapper.getInstance()
+ .getElement("mb.queue.subscriptions.close.confirm"))).click();
+ boolean successMessageReceived = driver.findElement(By.xpath(UIElementMapper.getInstance()
+ .getElement("mb.queue.subscription.close.result"))).getText()
+ .contains("Successfully closed subscription");
+
+ driver.findElement(By.xpath(UIElementMapper.getInstance()
+ .getElement("mb.queue.subscription.close.result.confirm"))).click();
+
+ boolean queueSubscriptionSuccessfullyRemoved = false;
+
+ String firstSubscriptionIDAfterDelete = driver.findElement(By.xpath(UIElementMapper.getInstance()
+ .getElement("mb.queue.subscriptions.table.delete.subid"))).getText();
+
+ if(!(firstSubscriptionIDAfterDelete.equals(deletingMessageID)) && successMessageReceived) {
+ queueSubscriptionSuccessfullyRemoved = true;
+ }
+
+ return queueSubscriptionSuccessfullyRemoved;
+
+ }
+}
diff --git a/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/main/QueuesBrowsePage.java b/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/main/QueuesBrowsePage.java
new file mode 100644
index 00000000..f7a0d9e6
--- /dev/null
+++ b/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/main/QueuesBrowsePage.java
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 2005-2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.wso2.mb.integration.common.utils.ui.pages.main;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.wso2.mb.integration.common.utils.ui.UIElementMapper;
+
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * This page represents 'Queue-> Browse' page in MB management console.
+ */
+public class QueuesBrowsePage {
+
+ private WebDriver driver;
+ private static final Log log = LogFactory.getLog(QueuesBrowsePage.class);
+
+ public QueuesBrowsePage(WebDriver driver) throws IOException {
+ this.driver = driver;
+ // Check that we're on the right page.
+ if (!driver.findElement(By.xpath(UIElementMapper.getInstance()
+ .getElement("mb.queue.list.page.header.xpath"))).getText().contains("Queue List")) {
+ throw new IllegalStateException("This is not the Queue List page");
+ }
+ }
+
+ /**
+ * Check whether the queue with the given queue name is present in the UI
+ * @param queueName queue name
+ * @return true if the queue is present, false otherwise
+ */
+ public boolean isQueuePresent(final String queueName) {
+ return getTableRowByQueueName(queueName) != null;
+ }
+
+ /**
+ * Delete queue from the UI delete option
+ * @param queueName queue name
+ * @return true if delete successful, false otherwise
+ */
+ public boolean deleteQueue(final String queueName) {
+
+ boolean isSuccessful = false;
+ WebElement row = getTableRowByQueueName(queueName);
+ if (row == null) {
+ log.warn("unable to find the table row for queue name: " + queueName);
+ return false;
+ }
+
+ List columnList = row.findElements(By.tagName("td"));
+ WebElement deleteButton = columnList.get(5).findElement(By.tagName("a"));
+ deleteButton.click();
+
+ // handle delete confirmation popup
+ String confirmation = driver.getWindowHandle();
+ driver.switchTo().window(confirmation);
+
+ // find yes button in confirmation dialog and click it
+ List confirmationButtonList = driver.findElements(By.tagName("button"));
+ for (WebElement yesButton : confirmationButtonList) {
+ if (yesButton.getText().compareToIgnoreCase("yes") == 0) {
+ yesButton.click();
+ break;
+ }
+ }
+
+ // handle delete dialog popup
+ String dialog = driver.getWindowHandle();
+ driver.switchTo().window(dialog);
+
+ // find ok button in popup dialog and click it
+ List dialogButtonList = driver.findElements(By.tagName("button"));
+ for (WebElement okButton : dialogButtonList) {
+ if (okButton.getText().compareToIgnoreCase("ok") == 0) {
+ okButton.click();
+ isSuccessful = !isQueuePresent(queueName); // if Queue present failure
+ break;
+ }
+ }
+
+ return isSuccessful;
+ }
+
+ /**
+ * Gets message count of a specific queue
+ *
+ * @param queueName name of the queue
+ * @return the number of messages
+ */
+ public int getMessageCount(String queueName) {
+ WebElement row = getTableRowByQueueName(queueName);
+ if (row == null) {
+ log.warn("Unable to find the table row for queue name: " + queueName);
+ }
+
+ if (row != null) {
+ List columnList;
+ columnList = row.findElements(By.tagName("td"));
+ return Integer.parseInt(columnList.get(1).getText());
+ } else {
+ log.warn("Unable to get message count.");
+ return -1;
+ }
+ }
+
+ /**
+ * Navigates the browser to 'Queue Content' page where user can see messages it contains etc.
+ *
+ * @param qName name of the Queue to browse
+ * @return true if the navigate operation is successful, false otherwise
+ */
+ public QueueContentPage browseQueue(final String qName) throws IOException {
+
+ WebElement row = getTableRowByQueueName(qName);
+ if (row == null) {
+ log.warn("unable to find the table row for queue name: " + qName);
+ return null; // can't find the queue.
+ }
+
+ List columnList = row.findElements(By.tagName("td"));
+ WebElement browseButton = columnList.get(2).findElement(By.tagName("a"));
+ if (browseButton != null) {
+ browseButton.click();
+ }
+ return new QueueContentPage(this.driver);
+ }
+
+ /**
+ * Retrieve the Web Element of the given queue name from available queues table in UI
+ * @param queueName queue name
+ * @return Web Element row of the given queue name item in UI, null returned if not found
+ */
+ private WebElement getTableRowByQueueName(final String queueName) {
+
+ // if no queues available return null
+ if (driver.findElement(By.id(UIElementMapper.getInstance()
+ .getElement("mb.queue.list.page.workarea.id"))).getText()
+ .contains("No queues are created")) {
+
+ return null;
+ }
+
+ WebElement queueTable = driver.findElement(By.xpath(UIElementMapper.getInstance()
+ .getElement("mb.queue.list.table.body.xpath")));
+ List rowElementList = queueTable.findElements(By.tagName("tr"));
+
+ // go through table rows and find the queue
+ for (WebElement row : rowElementList) {
+ List columnList = row.findElements(By.tagName("td"));
+ // Assumption: there are six columns. Delete buttons are in the sixth column
+ if ((columnList.size() == 6) && columnList.get(0).getText().equals(queueName)) {
+ return row;
+ }
+ }
+ return null;
+ }
+}
diff --git a/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/main/TopicAddPage.java b/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/main/TopicAddPage.java
new file mode 100644
index 00000000..34eea0ad
--- /dev/null
+++ b/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/main/TopicAddPage.java
@@ -0,0 +1,80 @@
+/*
+* Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+*
+* WSO2 Inc. licenses this file to you under the Apache License,
+* Version 2.0 (the "License"); you may not use this file except
+* in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT 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.wso2.mb.integration.common.utils.ui.pages.main;
+
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.wso2.mb.integration.common.utils.ui.UIElementMapper;
+import org.wso2.mb.integration.common.utils.ui.pages.MBPage;
+
+/**
+ * The class for topic creation page. Provides functions available in the topic creation page.
+ */
+public class TopicAddPage extends MBPage {
+ /**
+ * Constructor. Takes the reference of web driver instance.
+ *
+ * @param driver WebDriver
+ */
+ protected TopicAddPage(WebDriver driver) {
+ super(driver);
+ if (!driver.findElement(By.xpath(UIElementMapper.getInstance().
+ getElement("mb.add.topics.page.header.xpath"))).getText().contains("Add Topic")) {
+ throw new IllegalStateException("This is not the Add Topic page");
+ }
+ }
+
+ /**
+ * Adds a new topic.
+ *
+ * @param topicName The new topic name.
+ * @return true if topic successfully added, false otherwise.
+ */
+ public boolean addTopic(String topicName) {
+ boolean isSuccessful = false;
+
+ // Setting topic name value
+ WebElement topicNameField = driver.findElement(By.id(UIElementMapper.getInstance()
+ .getElement("mb.add.topics.page.topic.name.field.id")));
+ topicNameField.sendKeys(topicName);
+
+ driver.getWindowHandle();
+
+ // Clicking the "Add Topic" button
+ driver.findElement(By.xpath(UIElementMapper.getInstance()
+ .getElement("mb.add.topics.page.add.button.xpath")))
+ .click();
+ String dialog = driver.getWindowHandle();
+ driver.switchTo().window(dialog);
+
+ // Checking if valid message is prompt on the dialog
+ if (driver.findElement(By.id(UIElementMapper.getInstance()
+ .getElement("mb.popup.dialog.id"))).getText().contains("Topic added successfully")) {
+ isSuccessful = true;
+ }
+
+ // Clicking ok button of the dialog
+ driver.findElement(By.xpath(UIElementMapper.getInstance()
+ .getElement("mb.add.topic.page.ontopicadd.okbutton.xpath"))).click();
+
+ return isSuccessful;
+ }
+
+}
diff --git a/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/main/TopicSubscriptionsPage.java b/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/main/TopicSubscriptionsPage.java
new file mode 100644
index 00000000..7e1a2677
--- /dev/null
+++ b/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/main/TopicSubscriptionsPage.java
@@ -0,0 +1,228 @@
+/*
+* Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+*
+* WSO2 Inc. licenses this file to you under the Apache License,
+* Version 2.0 (the "License"); you may not use this file except
+* in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT 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.wso2.mb.integration.common.utils.ui.pages.main;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.ui.Select;
+import org.wso2.mb.integration.common.utils.ui.UIElementMapper;
+import org.wso2.mb.integration.common.utils.ui.pages.MBPage;
+
+import java.util.List;
+
+/**
+ * The class for topic subscriptions. Provides functions available in the topic subscriptions page.
+ */
+public class TopicSubscriptionsPage extends MBPage {
+ private static final Log log = LogFactory.getLog(QueueContentPage.class);
+
+ /**
+ * Constructor. Takes the reference of web driver instance.
+ *
+ * @param driver The selenium Web Driver
+ */
+ protected TopicSubscriptionsPage(WebDriver driver) {
+ super(driver);
+
+ // Check that we're on the right page.
+ if (!driver.findElement(By.xpath(UIElementMapper.getInstance()
+ .getElement("mb.subscriptions.topics.page.header.xpath"))).getText().contains("Topic Subscription List")) {
+ throw new IllegalStateException("This is not the Topic Subscriptions page");
+ }
+ }
+
+ /**
+ * Gets the number of durable active subscriptions.
+ *
+ * @return The number of subscriptions.
+ */
+ public int getDurableActiveSubscriptionsCount() {
+ List tempDurableActiveTables = driver.findElements(By.xpath(UIElementMapper.getInstance()
+ .getElement("mb.subscriptions.topics.page.durable.active.table.xpath")));
+ // Checks whether the table exists.
+ if (0 < tempDurableActiveTables.size()) {
+ return tempDurableActiveTables.get(0).findElement(By.tagName("tbody")).findElements(By.tagName("tr")).size();
+ } else {
+ log.warn("Durable Active Subscriptions table does not exists.");
+ return 0;
+ }
+ }
+
+ /**
+ * Gets the number of durable in-active subscriptions.
+ *
+ * @return The number of subscriptions.
+ */
+ public int getDurableInActiveSubscriptionsCount() {
+ List tempDurableInActiveTables = driver.findElements(By.xpath(UIElementMapper.getInstance()
+ .getElement("mb.subscriptions.topics.page.durable.inactive.table.xpath")));
+ // Checks whether the table exists.
+ if (0 < tempDurableInActiveTables.size()) {
+ return tempDurableInActiveTables.get(0).findElement(By.tagName("tbody")).findElements(By.tagName("tr")).size();
+ } else {
+ log.warn("Durable In-Active Subscriptions table does not exists.");
+ return 0;
+ }
+ }
+
+ /**
+ * Search topic subscriptions according to the search criteria.
+ *
+ * @param queueNamePattern string pattern of the topic name (* for all)
+ * @param identifierPattern string pattern of the identifier (* for all)
+ * @param ownNodeIdIndex index of the node Id in the dropdown the subscriptions belong to
+ * @return number of subscriptions listed under search result
+ */
+ public void searchTopicSubscriptions(String queueNamePattern, String identifierPattern, int
+ ownNodeIdIndex, boolean isNameExactMatch, boolean isIdentifierExactMatch) {
+
+ WebElement queueNamePatternField = driver.findElement(By.name(UIElementMapper.getInstance()
+ .getElement("mb.search.topic.name.pattern.tag.name")));
+ queueNamePatternField.clear();
+ queueNamePatternField.sendKeys(queueNamePattern);
+
+ WebElement queueIdentifierPatternField = driver.findElement(By.name(UIElementMapper.getInstance()
+ .getElement("mb.search.topic.identifier.pattern.tag.name")));
+ queueIdentifierPatternField.clear();
+ queueIdentifierPatternField.sendKeys(identifierPattern);
+
+ WebElement topicNameExactMatchField = driver.findElement(
+ By.name(UIElementMapper.getInstance().getElement("mb.search.topic.name.exactmatch.tag.name")));
+ // Set the name exact match check box state based on the test input
+ if (isNameExactMatch != topicNameExactMatchField.isSelected()) {
+ topicNameExactMatchField.click();
+ }
+ WebElement topicIdentifierExactMatchField = driver.findElement(
+ By.name(UIElementMapper.getInstance().getElement("mb.search.topic.identifier.exactmatch.tag.name")));
+ // Set the identifier exact match check box state based on the test input
+ if (isIdentifierExactMatch != topicIdentifierExactMatchField.isSelected()) {
+ topicIdentifierExactMatchField.click();
+ }
+
+ Select ownNodeIdDropdown = new Select(driver.findElement(By.id(UIElementMapper.getInstance()
+ .getElement("mb.search.topic.own.node.id.element.id"))));
+ ownNodeIdDropdown.selectByIndex(ownNodeIdIndex);
+
+ driver.findElement(By.xpath(UIElementMapper.getInstance()
+ .getElement("mb.search.topic.search.button.xpath"))).click();
+
+ }
+
+ /**
+ * Gets the number of temporary active subscriptions.
+ *
+ * @return The number of subscriptions.
+ */
+ public int getNonDurableSubscriptionsCount() {
+ int numberOfSubscribers = 0;
+ List tempNonDurableActiveTables = driver.findElements(By.xpath(UIElementMapper.getInstance()
+ .getElement("mb.subscriptions.topics.page.temporary.table.xpath")));
+ // Checks whether the table exists.
+ if (0 < tempNonDurableActiveTables.size()) {
+ for (WebElement tempNonDurableActiveTable : tempNonDurableActiveTables) {
+ if ("table".equals(tempNonDurableActiveTable.getTagName())) {
+ numberOfSubscribers = tempNonDurableActiveTable.findElement(By.tagName("tbody")).findElements(By
+ .tagName("tr")).size();
+ }
+ }
+
+ }
+
+ if (numberOfSubscribers == 0) {
+ log.warn("Durable Active Subscriptions table does not exists.");
+ }
+ return numberOfSubscribers;
+ }
+
+ /**
+ * Forcibly close non durable topic subscription. This will delete the first subscription listed
+ * on non durable subscriptions list
+ * @return true if subscription removal is successful, otherwise false
+ */
+ public boolean closeNonDurableTopicSubscription() {
+ String deletingMessageID = driver.findElement(By.xpath(UIElementMapper.getInstance()
+ .getElement("mb.tempTopic.subscriptions.table.delete.subid"))).getText();
+
+ driver.findElement(By.xpath(UIElementMapper.getInstance()
+ .getElement("mb.tempTopic.subscriptions.table.delete.button"))).click();
+
+ driver.findElement(By.xpath(UIElementMapper.getInstance()
+ .getElement("mb.tempTopic.subscriptions.close.confirm"))).click();
+ boolean successMessageReceived = driver.findElement(By.xpath(UIElementMapper.getInstance()
+ .getElement("mb.tempTopic.subscription.close.result"))).getText()
+ .contains("Successfully closed subscription");
+
+ driver.findElement(By.xpath(UIElementMapper.getInstance()
+ .getElement("mb.tempTopic.subscription.close.result.confirm"))).click();
+
+ boolean queueSubscriptionSuccessfullyRemoved = false;
+
+ String firstSubscriptionIDAfterDelete = driver.findElement(By.xpath(UIElementMapper.getInstance()
+ .getElement("mb.tempTopic.subscriptions.table.delete.subid"))).getText();
+
+ if(!(firstSubscriptionIDAfterDelete.equals(deletingMessageID)) && successMessageReceived) {
+ queueSubscriptionSuccessfullyRemoved = true;
+ }
+
+ return queueSubscriptionSuccessfullyRemoved;
+ }
+
+ /**
+ * Forcibly close non durable topic subscription. This will delete the first subscription listed
+ * on non durable subscriptions list. This will also check if subscription has moved to inactive
+ * state when closed
+ * @return true if subscription removal is successful, otherwise false
+ */
+ public boolean closeDurableTopicSubscription() {
+ String deletingMessageID = driver.findElement(By.xpath(UIElementMapper.getInstance()
+ .getElement("mb.durableTopic.subscriptions.table.delete.subid"))).getText();
+
+ driver.findElement(By.xpath(UIElementMapper.getInstance()
+ .getElement("mb.durableTopic.subscriptions.table.delete.button"))).click();
+
+ driver.findElement(By.xpath(UIElementMapper.getInstance()
+ .getElement("mb.durableTopic.subscriptions.close.confirm"))).click();
+ boolean successMessageReceived = driver.findElement(By.xpath(UIElementMapper.getInstance()
+ .getElement("mb.durableTopic.subscription.close.result"))).getText()
+ .contains("Successfully closed subscription");
+
+ driver.findElement(By.xpath(UIElementMapper.getInstance()
+ .getElement("mb.durableTopic.subscription.close.result.confirm"))).click();
+
+ boolean queueSubscriptionSuccessfullyRemoved = false;
+
+ String firstSubscriptionIDAfterDelete = driver.findElement(By.xpath(UIElementMapper.getInstance()
+ .getElement("mb.durableTopic.subscriptions.table.delete.subid"))).getText();
+
+ String firstInactiveSubID = driver.findElement(By.xpath(UIElementMapper.getInstance()
+ .getElement("mb.durableTopic.subscription.close.inactive.subid"))).getText();
+
+ if(!(firstSubscriptionIDAfterDelete.equals(deletingMessageID))
+ && deletingMessageID.equals(firstInactiveSubID)
+ && successMessageReceived) {
+
+ queueSubscriptionSuccessfullyRemoved = true;
+ }
+
+ return queueSubscriptionSuccessfullyRemoved;
+ }
+}
diff --git a/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/main/TopicsBrowsePage.java b/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/main/TopicsBrowsePage.java
new file mode 100644
index 00000000..e4b44c41
--- /dev/null
+++ b/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/main/TopicsBrowsePage.java
@@ -0,0 +1,78 @@
+/*
+* Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+*
+* WSO2 Inc. licenses this file to you under the Apache License,
+* Version 2.0 (the "License"); you may not use this file except
+* in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT 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.wso2.mb.integration.common.utils.ui.pages.main;
+
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.wso2.mb.integration.common.utils.ui.UIElementMapper;
+import org.wso2.mb.integration.common.utils.ui.pages.MBPage;
+
+import java.util.List;
+
+/**
+ * The class for topic content browsing page. Provides functions available in the topic browsing
+ * page.
+ */
+public class TopicsBrowsePage extends MBPage {
+ /**
+ * Constructor. Takes the reference of web driver instance.
+ *
+ * @param driver WebDriver
+ */
+ protected TopicsBrowsePage(WebDriver driver) {
+ super(driver);
+ // Check that we're on the right page.
+ if (!driver.findElement(By.xpath(UIElementMapper.getInstance()
+ .getElement("mb.topic.browse.page.header.xpath")))
+ .getText().contains("Topic List")) {
+ throw new IllegalStateException("This is not the Topic List page");
+ }
+ }
+
+ /**
+ * Validates whether a give topic exists.
+ *
+ * @param topicName The topic name
+ * @return true if topic is available, false otherwise.
+ */
+ public boolean isTopicPresent(String topicName) {
+ boolean isTopicPresent = false;
+
+ // Gets the topic tree element
+ WebElement topicTree = driver.findElement(By.xpath(UIElementMapper.getInstance()
+ .getElement("mb.topic.browse.topictree")));
+
+ // Gets all 'ul' elements.
+ List ulList = topicTree.findElements(By.tagName("ul"));
+ for (WebElement ulNode : ulList) {
+ // Gets all 'li' elements
+ List liList = ulNode.findElements(By.tagName("li"));
+ for (WebElement liNode : liList) {
+ // Gets the element which has the topic name
+ WebElement topicNameNode = liNode.findElement(By.className("treeNode"));
+ if (topicName.equals(topicNameNode.getText())) {
+ isTopicPresent = true;
+ }
+ }
+
+ }
+ return isTopicPresent;
+ }
+}
diff --git a/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/monitor/ApplicationLogsPage.java b/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/monitor/ApplicationLogsPage.java
new file mode 100644
index 00000000..b77406ae
--- /dev/null
+++ b/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/monitor/ApplicationLogsPage.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2005-2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.wso2.mb.integration.common.utils.ui.pages.monitor;
+
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebDriver;
+import org.wso2.mb.integration.common.utils.ui.UIElementMapper;
+
+import java.io.IOException;
+
+public class ApplicationLogsPage {
+ private WebDriver driver;
+
+ public ApplicationLogsPage(WebDriver driver) throws IOException {
+ this.driver = driver;
+ // Check that we're on the right page.
+ if (!driver.findElement(By.xpath(UIElementMapper.getInstance().getElement("mb.page.header.xpath"))).getText().contains("Application Logs")) {
+ throw new IllegalStateException("This is not the Application Logs page");
+ }
+ }
+
+ public MonitorPage getMonitorPage() throws IOException {
+ driver.findElement(By.id(UIElementMapper.getInstance().getElement("mb.tab.button.monitor.id"))).click();
+ return new MonitorPage(driver);
+ }
+}
diff --git a/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/monitor/MonitorPage.java b/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/monitor/MonitorPage.java
new file mode 100644
index 00000000..8e40022b
--- /dev/null
+++ b/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/monitor/MonitorPage.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2005-2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.wso2.mb.integration.common.utils.ui.pages.monitor;
+
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebDriver;
+import org.wso2.mb.integration.common.utils.ui.UIElementMapper;
+
+import java.io.IOException;
+
+public class MonitorPage {
+ private WebDriver driver;
+
+ public MonitorPage(WebDriver driver) throws IOException {
+ this.driver = driver;
+ // Check that we're on the right page.
+ if (!driver.findElement(By.id(UIElementMapper.getInstance().getElement("mb.tab.button.monitor.id"))).getAttribute("class").contains(UIElementMapper.getInstance().getElement("mb.tab.button.selected.class"))) {
+ throw new IllegalStateException("This is not the Monitor page");
+ }
+ }
+
+ public ApplicationLogsPage getApplicationLogsPage() throws IOException {
+ driver.findElement(By.xpath(UIElementMapper.getInstance().getElement("mb.monitor.button.logs.application.button.xpath"))).click();
+ return new ApplicationLogsPage(driver);
+ }
+
+ public SystemLogsPage getSystemLogsPage() throws IOException {
+ driver.findElement(By.xpath(UIElementMapper.getInstance().getElement("mb.monitor.button.logs.system.button.xpath"))).click();
+ return new SystemLogsPage(driver);
+ }
+}
diff --git a/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/monitor/SystemLogsPage.java b/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/monitor/SystemLogsPage.java
new file mode 100644
index 00000000..8a51ec75
--- /dev/null
+++ b/modules/broker/integration/tests-common/integration-tests-utils/src/main/java/org/wso2/mb/integration/common/utils/ui/pages/monitor/SystemLogsPage.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2005-2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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.wso2.mb.integration.common.utils.ui.pages.monitor;
+
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebDriver;
+import org.wso2.mb.integration.common.utils.ui.UIElementMapper;
+
+import java.io.IOException;
+
+public class SystemLogsPage {
+ public SystemLogsPage(WebDriver driver) throws IOException {
+ // Check that we're on the right page.
+ if (!driver.findElement(By.xpath(UIElementMapper.getInstance().getElement("mb.page.header.xpath"))).getText().contains("System Logs")) {
+ throw new IllegalStateException("This is not the System Logs page");
+ }
+ }
+}
diff --git a/modules/broker/integration/tests-common/integration-tests-utils/src/main/resources/mapper.properties b/modules/broker/integration/tests-common/integration-tests-utils/src/main/resources/mapper.properties
new file mode 100644
index 00000000..16e2d127
--- /dev/null
+++ b/modules/broker/integration/tests-common/integration-tests-utils/src/main/resources/mapper.properties
@@ -0,0 +1,214 @@
+#
+# Copyright (c) 2005-2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+#
+# WSO2 Inc. licenses this file to you under the Apache License,
+# Version 2.0 (the "License"); you may not use this file except
+# in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+login.username.id=txtUserName
+login.password.id=txtPassword
+login.header.div=header-div
+login.sign.in.button=button
+
+home.dashboard.middle.text=middle
+home.dlc.header.xpath=//*[@id="middle"]/h2
+home.mb.sign.out.xpath=//*[@id="header-div"]/div[4]/div/ul/li[3]/a
+home.mb.dlc.browse.xpath=//*[@id="menu"]/ul/li[5]/ul/li[6]/ul/li/a
+home.mb.queues.browse.xpath=//*[@id="menu"]/ul/li[5]/ul/li[2]/ul/li[1]/a
+home.mb.topic.browse.xpath=//*[@id="menu"]/ul/li[5]/ul/li[4]/ul/li[1]/a
+home.mb.queues.add.xpath=//*[@id="menu"]/ul/li[5]/ul/li[2]/ul/li[2]/a
+home.mb.topic.add.xpath=//*[@id="menu"]/ul/li[5]/ul/li[4]/ul/li[2]/a
+mb.queue.list.page.header.xpath=//*[@id="middle"]/h2
+mb.topic.list.page.header.xpath=//*[@id="workArea"]/h2
+mb.queue.content.page.header.xpath=//*[@id="middle"]/h2
+#REPLACE tag should be replaced with the row index for below xpath
+mb.queue.content.page.row.xpath = //div[@id='workArea']//tr[#REPLACE#]//form[@action='message_content.jsp']/a
+mb.message.content.page.header.xpath=//*[@id="middle"]/h2
+mb.message.content.textarea.xpath=//table[@id='content-table']/tbody/tr[2]/td[@id='body']/div[@id='middle']/div[@id='workArea']/textarea
+mb.queue.list.page.workarea.id=workArea
+mb.topic.list.page.workarea.xpath=//*[@id="topicTree"]/ul/li
+
+#queue subscriptions
+home.mb.queues.subscriptions.xpath =//*[@id="menu"]/ul/li[5]/ul/li[8]/ul/li[1]/a
+mb.queue.manage.subscriptions.page.xpath=//*[@id="middle"]/h2
+mb.queue.subscriptions.table.delete.subid=//*[@id="workArea"]/table[2]/tbody/tr[1]/td[1]
+mb.queue.subscriptions.table.delete.button=//*[@id="workArea"]/table[2]/tbody/tr[1]/td[11]/a
+mb.queue.subscriptions.close.confirm=/html/body/div[3]/div[2]/button[1]
+mb.queue.subscription.close.result=//*[@id="messagebox-info"]/p
+mb.queue.subscription.close.result.confirm=/html/body/div[3]/div[2]/button
+
+
+mb.add.queue.page.header.xpath=//*[@id="workArea"]/h2
+mb.add.queue.page.qname.field.id=queue
+mb.add.queue.page.add.button.xpath=//*[@id="workArea"]/table/tbody/tr[3]/td/input
+mb.add.queue.page.permission.table=//*[@id="permissionsTable"]/tbody
+mb.add.queue.page.onqueueadd.okbutton.xpath=/html/body/div[3]/div[2]/button
+mb.add.queue.page.onqueueadd.msgdialog.id=dialog
+mb.queue.list.table.body.xpath=//*[@id="workArea"]/table[2]/tbody
+mb.queue.browse.content.table=//*[@id="workArea"]/table[2]/tbody
+home.logged.user.dev=logged-user
+mb.popup.dialog.id=dialog
+
+mb.search.queue.name.pattern.tag.name=queueNamePattern
+mb.search.queue.identifier.pattern.tag.name=identifier
+mb.search.queue.own.node.id.element.id=ownNodeId
+mb.search.queue.search.button.xpath=//*[@id="workArea"]/form/table/tbody/tr[4]/td[1]/input
+
+mb.search.queue.name.exactmatch.tag.name=isQueueExactlyMatch
+mb.search.queue.identifier.exactmatch.tag.name=isIdentifierExactlyMatch
+
+
+mb.search.topic.name.pattern.tag.name=topicNamePattern
+mb.search.topic.identifier.pattern.tag.name=identifier
+mb.search.topic.own.node.id.element.id=ownNodeId
+mb.search.topic.search.button.xpath=//*[@id="workArea"]/form/table/tbody/tr[4]/td[1]/input
+
+mb.search.topic.name.exactmatch.tag.name=isTopicExactlyMatch
+mb.search.topic.identifier.exactmatch.tag.name=isIdentifierExactlyMatch
+
+mb.add.topic.page.header.xpath=//*[@id="workArea"]/h2
+mb.add.topic.page.topic.name.field.id=topic
+mb.add.topic.page.add.button.xpath=//*[@id="workArea"]/table/tbody/tr[3]/td/input
+mb.add.topic.page.ontopicadd.okbutton.xpath=/html/body/div[3]/div[2]/button
+
+
+repository.url.name=_txt_repository_location_url
+main.tab.id=menu-panel-button1
+
+configure.tab.id=menu-panel-button3
+configure.tab.menu.header.id=region1_configure_menu
+configure.user.store.management.add.secondary.userstore=//*[@id="workArea"]/table[1]/tbody/tr/td/a
+configure.user.store.management.xpath=//*[@id="menu"]/ul/li[3]/ul/li[4]/ul/li[1]/a
+configure.user.store.management.header.id=middle
+configure.usr.mgt.roles.header.xpath=//*[@id="middle"]/h2
+configure.usr.mgt.users.header.xpath=//*[@id="middle"]/h2
+configure.panel.button.id=menu-panel-button3
+configure.user.mgt.header.xpath=//*[@id="middle"]/h2
+usr.mgt.roles.add.new.role.button.xpath=//*[@id="workArea"]/table[4]/tbody/tr[1]/td/a
+configure.users.and.roles.button.xpath=//*[@id="menu"]/ul/li[3]/ul/li[2]/ul/li[1]/a
+configure.usr.mgt.roles.link.xpath=//*[@id="internal"]/tbody/tr[2]/td/a
+
+usr.mgt.add.role.step1.sub.header.xpath=//*[@id="workArea"]/h3
+usr.mgt.add.role.step1.next.button.xpath=//*[@id="workArea"]/form/table/tbody/tr[2]/td/input[1]
+usr.mgt.add.role.step1.finish.button.xpath=//*[@id="workArea"]/form/table/tbody/tr[2]/td/input[2]
+usr.mgt.add.role.step1.name.field.xpath=//*[@id="workArea"]/form/table/tbody/tr[1]/td/table/tbody/tr[2]/td[2]/input
+usr.mgt.add.role.step1.cancel.button.xpath=//*[@id="workArea"]/form/table/tbody/tr[2]/td/input[3]
+
+usr.mgt.add.role.step2.sub.header.xpath=//*[@id="workArea"]/h3
+usr.mgt.add.role.step2.next.button.xpath=//*[@id="workArea"]/form/table/tbody/tr/td/input[1]
+usr.mgt.add.role.step2.finish.button.xpath=//*[@id="workArea"]/form/table/tbody/tr/td/input[2]
+usr.mgt.add.role.step2.cancel.button.xpath=//*[@id="workArea"]/form/table/tbody/tr/td/input[3]
+usr.mgt.add.role.step2.login.role.xpath=//*[@id="ygtvcheck11"]/div
+
+usr.mgt.add.role.step3.sub.header.xpath=//*[@id="workArea"]/h3
+usr.mgt.add.role.step3.finish.button.xpath=//*[@id="content-table"]/tbody/tr[3]/td/input[1]
+usr.mgt.add.role.step3.cancel.button.xpath=//*[@id="content-table"]/tbody/tr[3]/td/input[2]
+
+configure.usr.mgt.users.link.xpath=//*[@id="internal"]/tbody/tr[1]/td/a
+usr.mgt.add.new.usr.button.xpath=//*[@id="workArea"]/table[4]/tbody/tr[1]/td/a
+usr.mgt.add.user.step1.sub.header.xpath=//*[@id="workArea"]/h3
+usr.mgt.add.user.step1.user.name.field.xpath=//*[@id="mainTable"]/tbody/tr[2]/td[2]/input
+usr.mgt.add.user.step1.password.field.xpath=//*[@id="passwordRow"]/td[2]/input
+usr.mgt.add.user.step1.password.repeat.field.xpath=//*[@id="retypeRow"]/td[2]/input
+usr.mgt.add.user.step1.next.button.xpath=//*[@id="userAdd"]/tbody/tr[2]/td/input[1]
+
+usr.mgt.add.user.step2.sub.header.xpath=//*[@id="workArea"]/h3
+usr.mgt.add.user.step2.select.roles.td.xpath=//*[@id="edit_users"]/table[1]/tbody/tr/td/table/tbody
+usr.mgt.add.user.step2.finish.button=//*[@id="content-table"]/tbody/tr[3]/td/input[1]
+
+configure.multitenancy.add.new.tenant.xpath=//*[@id="menu"]/ul/li[3]/ul/li[11]/ul/li[1]/a
+add.tenant.domain.field.id=domain
+add.tenant.usage.plan.field.id=usage-plan-name
+add.tenant.first.name.field.id=admin-firstname
+add.tenant.last.name.field.id=admin-lastname
+add.tenant.admin.user.name.field.id=admin
+add.tenant.admin.password.field.id=admin-password
+add.tenant.admin.password.repeat.field.id=admin-password-repeat
+add.tenant.admin.email.field.id=admin-email
+add.tenant.save.button.xpath=//*[@id="buttonRow"]/td/input
+
+mb.tenant.home.page.menu.header.xpath=//*[@id="menu"]/ul/li[1]/a
+mb.tenant.sign.out.xpath=//*[@id="header-div"]/div[4]/div/ul/li[3]/a
+
+mb.tab.button.monitor.id=menu-panel-button2
+mb.tab.button.selected.class=selected
+mb.page.header.xpath=//*[@id="middle"]/h2
+mb.monitor.button.logs.application.button.xpath=/html/body/table/tbody/tr[2]/td[2]/table/tbody/tr[4]/td/div/ul/li[2]/ul/li[3]/a
+mb.monitor.button.logs.system.button.xpath=/html/body/table/tbody/tr[2]/td[2]/table/tbody/tr[4]/td/div/ul/li[2]/ul/li[5]/a
+
+mb.dlc.browse.table.browse.button.xpath=//*[@id="workArea"]/table/tbody/tr/td[3]/a
+mb.dlc.browse.table.xpath=//*[@id="workArea"]/table/tbody
+mb.dlc.queue.content=//*[@id="middle"]/h2
+
+mb.dlc.browse.table.choose.box.xpath=//*[@id="workArea"]/table[3]/tbody/tr[1]/td[1]/input
+mb.dlc.browse.table.choose.all.box.xpath=//*[@id="workArea"]/table[3]/thead/tr/th[1]/input
+mb.dlc.browse.content.table=//*[@id="workArea"]/table[3]/tbody
+mb.dlc.first.message.id=//*[@id="workArea"]/table[3]/tbody/tr[1]/td[3]
+mb.dlc.browse.function.confirm=/html/body/div[3]/div[2]/button[1]
+mb.dlc.browse.function.success=/html/body/div[3]/div[2]/button
+
+mb.dlc.browse.table.delete.button=//*[@id="iconArea"]/table/thead/tr/th[1]/a
+mb.dlc.browse.table.restore.button=//*[@id="iconArea"]/table/thead/tr/th[2]/a
+mb.dlc.browse.table.reroute.queue.select=//*[@id="allQueues"]
+mb.dlc.browse.table.reroute.queue.option=option
+mb.dlc.restored.message.id=//*[@id="workArea"]/table[2]/tbody/tr[1]/td[2]
+mb.dlc.browse.table.reroute.button=//*[@id="iconArea"]/table/thead/tr/th[3]/a
+mb.dlc.browse.table.reroute.confirm=/html/body/div[3]/div[2]/button
+mb.dlc.rerouted.message.id=//*[@id="workArea"]/table[2]/tbody/tr[1]/td[2]
+mb.dlc.rerouted.queue.table=//*[@id="workArea"]/table[2]/tbody
+
+mb.dlc.browse.table.reroute.all.button=//*[@id="iconArea"]/table/thead/tr/th[4]/a
+mb.dlc.browse.table.reroute.all.source.select=//*[@id="sourceDestinations"]
+mb.dlc.browse.table.reroute.all.target.select=//*[@id="targetDestinations"]
+
+
+#Topics
+
+mb.add.topics.page.header.xpath=//*[@id="workArea"]/h2
+mb.add.topics.page.topic.name.field.id=topic
+mb.add.topics.page.add.button.xpath=//*[@id="permissionTable"]/tbody/tr[3]/td/input
+home.mb.topics.add.xpath=//*[@id="menu"]/ul/li[5]/ul/li[4]/ul/li[2]/a
+home.mb.topics.browse.xpath=//*[@id="menu"]/ul/li[5]/ul/li[4]/ul/li[1]/a
+mb.topic.browse.page.header.xpath=//*[@id="workArea"]/h2
+mb.topic.browse.topictree=//*[@id="topicTree"]
+home.mb.topics.add.without.queue.xpath=//*[@id="menu"]/ul/li[5]/ul/li[2]/ul/li[2]/a
+home.mb.topics.browse.without.queue.xpath=//*[@id="menu"]/ul/li[5]/ul/li[2]/ul/li[1]/a
+mb.topic.subscribe.page.header.xpath=//*[@id="workArea"]/h2
+mb.topic.subscribe.page.subscribe.button.xpath=/html/body/table/tbody/tr[2]/td[3]/table/tbody/tr[2]/td/div/div/table/tbody/tr[2]/td/input
+mb.topic.subscribe.page.subscribe.okbutton.xpath=/html/body/div[3]/div[2]/button
+
+#Topic Subscriptions
+mb.subscriptions.topics.page.header.xpath=//*[@id="middle"]/h2
+mb.subscriptions.topics.page.durable.active.table.xpath=//*[@id="workArea"]/h3[3]/preceding-sibling::table[@class='styledLeft']
+mb.subscriptions.topics.page.durable.inactive.table.xpath=//*[@id="workArea"]/h3[3]/following-sibling::table[@class='styledLeft']
+home.mb.topic.subscriptions.xpath=//*[@id="menu"]/ul/li[5]/ul/li[8]/ul/li[2]/a
+
+mb.subscriptions.queue.table.xpath=//*[@id="workArea"]/table[2]
+
+mb.tempTopic.subscriptions.table.delete.subid=//*[@id="workArea"]/table[2]/tbody/tr[1]/td[1]
+mb.tempTopic.subscriptions.table.delete.button=//*[@id="workArea"]/table[2]/tbody/tr[1]/td[5]/a
+mb.tempTopic.subscriptions.close.confirm=/html/body/div[3]/div[2]/button[1]
+mb.tempTopic.subscription.close.result=//*[@id="messagebox-info"]/p
+mb.tempTopic.subscription.close.result.confirm=/html/body/div[3]/div[2]/button
+mb.subscriptions.topics.page.temporary.table.xpath=//*[@id="workArea"]/h3[1]/following-sibling::*[3]
+
+
+
+mb.durableTopic.subscriptions.table.delete.subid=//*[@id="workArea"]/table[2]/tbody/tr[1]/td[2]
+mb.durableTopic.subscriptions.table.delete.button=//*[@id="workArea"]/table[2]/tbody/tr[1]/td[9]/a
+mb.durableTopic.subscriptions.close.confirm=/html/body/div[3]/div[2]/button[1]
+mb.durableTopic.subscription.close.result=//*[@id="messagebox-info"]/p
+mb.durableTopic.subscription.close.result.confirm=/html/body/div[3]/div[2]/button
+
+mb.durableTopic.subscription.close.inactive.subid=//*[@id="workArea"]/table[4]/tbody/tr/td[1]
diff --git a/modules/broker/integration/tests-common/platform-tests-utils/pom.xml b/modules/broker/integration/tests-common/platform-tests-utils/pom.xml
new file mode 100644
index 00000000..0b1de60e
--- /dev/null
+++ b/modules/broker/integration/tests-common/platform-tests-utils/pom.xml
@@ -0,0 +1,49 @@
+
+
+
+
+ org.wso2.mb
+ wso2iot-broker-integration-tests
+ 1.0.0-SNAPSHOT
+ ../../pom.xml
+
+
+ 4.0.0
+ WSO2 MB - platform Test Common Utils Module
+ org.wso2.iot.broker.platform.common.utils
+ jar
+
+
+
+ org.wso2.carbon.automation
+ org.wso2.carbon.automation.test.utils
+ compile
+
+
+ org.wso2.carbon.automation
+ org.wso2.carbon.automation.engine
+ compile
+
+
+ org.wso2.iot
+ org.wso2.iot.broker.integration.common.clients
+ compile
+
+
+ org.wso2.carbon.automationutils
+ org.wso2.carbon.integration.common.utils
+ compile
+
+
+ org.wso2.carbon
+ org.wso2.carbon.authenticator.stub
+ compile
+
+
+ org.wso2.carbon.automation
+ org.wso2.carbon.automation.extensions
+ compile
+
+
+
+
\ No newline at end of file
diff --git a/modules/broker/integration/tests-common/platform-tests-utils/src/main/java/org/wso2/mb/platform/common/utils/DataAccessUtil.java b/modules/broker/integration/tests-common/platform-tests-utils/src/main/java/org/wso2/mb/platform/common/utils/DataAccessUtil.java
new file mode 100644
index 00000000..9eea3f2f
--- /dev/null
+++ b/modules/broker/integration/tests-common/platform-tests-utils/src/main/java/org/wso2/mb/platform/common/utils/DataAccessUtil.java
@@ -0,0 +1,184 @@
+/*
+* Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+*
+* WSO2 Inc. licenses this file to you under the Apache License,
+* Version 2.0 (the "License"); you may not use this file except
+* in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT 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.wso2.mb.platform.common.utils;
+
+import org.wso2.mb.platform.common.utils.exceptions.DataAccessUtilException;
+
+import javax.xml.xpath.XPathExpressionException;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+/**
+ * This class is used for testing database records directly.
+ */
+public class DataAccessUtil {
+
+ /**
+ * Get database connection
+ * @return database connection
+ * @throws SQLException
+ * @throws XPathExpressionException
+ * @throws ClassNotFoundException
+ */
+ private Connection getConnection() throws SQLException, XPathExpressionException,
+ ClassNotFoundException {
+ return RDBMSConnectionManager.getConnection();
+ }
+
+ /**
+ * Get current number of messages in database for a given queue name.
+ * @param queueName queue name
+ * @return number of messages in database
+ * @throws DataAccessUtilException
+ */
+ public long getMessageCountForQueue(String queueName) throws DataAccessUtilException{
+ Connection connection = null;
+ PreparedStatement preparedStatement = null;
+ ResultSet resultSet = null;
+ long count = 0;
+ try {
+ connection = getConnection();
+ long queueId = getQueueId(queueName);
+ preparedStatement = connection.prepareStatement(RDBMSConstants.PS_GET_MESSAGE_COUNT_FOR_QUEUE);
+ preparedStatement.setLong(1, queueId);
+ resultSet = preparedStatement.executeQuery();
+ if (resultSet.next()) {
+ count = resultSet.getLong(RDBMSConstants.MSG_COUNT);
+ }
+ } catch (Exception e) {
+ throw new DataAccessUtilException("Failed to get message count for queue: " + queueName, e);
+ }
+ finally {
+ close(resultSet, "getMessageCountForQueue");
+ close(preparedStatement, "getMessageCountForQueue");
+ close(connection, "getMessageCountForQueue");
+ }
+ return count;
+ }
+
+ /**
+ * Get queue id for a given queue.
+ * @param queueName queue name
+ * @return queue id
+ * @throws DataAccessUtilException
+ */
+ public long getQueueId(String queueName) throws DataAccessUtilException {
+ Connection connection = null;
+ PreparedStatement preparedStatement = null;
+ ResultSet resultSet = null;
+ long count = 0;
+ try {
+ connection = getConnection();
+ preparedStatement = connection.prepareStatement(RDBMSConstants.PS_GET_QUEUE_ID);
+ preparedStatement.setString(1, queueName);
+ resultSet = preparedStatement.executeQuery();
+ if (resultSet.next()) {
+ count = resultSet.getLong(RDBMSConstants.QUEUE_ID);
+ }
+ } catch (Exception e) {
+ throw new DataAccessUtilException("Failed to get queue id for queue: " + queueName, e);
+ } finally {
+ close(resultSet, "getQueueId");
+ close(preparedStatement, "getQueueId");
+ close(connection, "getQueueId");
+ }
+ return count;
+ }
+
+ /**
+ * Get current number of slots for a given queue which are in assigned state.
+ * @param queueName queue name
+ * @return number of slots
+ * @throws DataAccessUtilException
+ */
+ public long getAssignedSlotCountForQueue(String queueName) throws DataAccessUtilException{
+ Connection connection = null;
+ PreparedStatement preparedStatement = null;
+ ResultSet resultSet = null;
+ long count = 0;
+ try {
+ connection = getConnection();
+ preparedStatement = connection.prepareStatement(RDBMSConstants.PS_GET_ASSIGNED_SLOTS_FOR_QUEUE);
+ preparedStatement.setString(1, queueName);
+ resultSet = preparedStatement.executeQuery();
+ if (resultSet.next()) {
+ count = resultSet.getLong(RDBMSConstants.SLOT_COUNT);
+ }
+ } catch (Exception e) {
+ throw new DataAccessUtilException("Failed to get slot count for queue: " + queueName, e);
+ }
+ finally {
+ close(resultSet, "getAssignedSlotCountForQueue");
+ close(preparedStatement, "getAssignedSlotCountForQueue");
+ close(connection, "getAssignedSlotCountForQueue");
+ }
+ return count;
+ }
+
+ /**
+ * closes the result set resources
+ *
+ * @param resultSet ResultSet
+ * @param task task that was done by the closed result set.
+ */
+ protected void close(ResultSet resultSet, String task) throws DataAccessUtilException{
+ if (resultSet != null) {
+ try {
+ resultSet.close();
+ } catch (SQLException e) {
+ throw new DataAccessUtilException("Failed to close result set", e);
+ }
+ }
+ }
+
+ /**
+ * close the prepared statement resource
+ *
+ * @param preparedStatement PreparedStatement
+ * @param task task that was done by the closed prepared statement.
+ */
+ protected void close(PreparedStatement preparedStatement, String task) throws DataAccessUtilException{
+ if (preparedStatement != null) {
+ try {
+ preparedStatement.close();
+ } catch (SQLException e) {
+ throw new DataAccessUtilException("Failed to close prepared statement", e);
+ }
+ }
+ }
+
+ /**
+ * Closes the provided connection. on failure log the error;
+ *
+ * @param connection Connection
+ * @param task task that was done before closing
+ */
+ protected void close(Connection connection, String task) throws DataAccessUtilException{
+ if (connection != null) {
+ try {
+ connection.close();
+ } catch (SQLException e) {
+ throw new DataAccessUtilException("Failed to close database connection", e);
+ }
+ }
+ }
+
+}
diff --git a/modules/broker/integration/tests-common/platform-tests-utils/src/main/java/org/wso2/mb/platform/common/utils/MBPlatformBaseTest.java b/modules/broker/integration/tests-common/platform-tests-utils/src/main/java/org/wso2/mb/platform/common/utils/MBPlatformBaseTest.java
new file mode 100644
index 00000000..1144b8fd
--- /dev/null
+++ b/modules/broker/integration/tests-common/platform-tests-utils/src/main/java/org/wso2/mb/platform/common/utils/MBPlatformBaseTest.java
@@ -0,0 +1,336 @@
+/*
+* Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+*
+* WSO2 Inc. licenses this file to you under the Apache License,
+* Version 2.0 (the "License"); you may not use this file except
+* in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT 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.wso2.mb.platform.common.utils;
+
+import com.google.common.net.HostAndPort;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.wso2.carbon.andes.stub.AndesAdminServiceBrokerManagerAdminException;
+import org.wso2.carbon.authenticator.stub.LoginAuthenticationExceptionException;
+import org.wso2.carbon.automation.engine.context.AutomationContext;
+import org.wso2.carbon.automation.engine.context.TestUserMode;
+import org.wso2.carbon.automation.engine.context.beans.Instance;
+import org.wso2.carbon.integration.common.utils.LoginLogoutClient;
+import org.wso2.carbon.integration.common.utils.exceptions.AutomationUtilException;
+import org.wso2.mb.integration.common.clients.operations.clients.AndesAdminClient;
+import org.wso2.mb.integration.common.clients.operations.clients.TopicAdminClient;
+import org.xml.sax.SAXException;
+
+import javax.xml.stream.XMLStreamException;
+import javax.xml.xpath.XPathExpressionException;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.rmi.RemoteException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Stack;
+
+/**
+ * Base class of all MB integration tests
+ */
+public class MBPlatformBaseTest {
+
+ protected Log log = LogFactory.getLog(MBPlatformBaseTest.class);
+ protected Map contextMap;
+ protected Map andesAdminClients;
+ protected Map topicAdminClients;
+ private Stack stack = null;
+
+ /**
+ * Create automation context objects for every node in config
+ *
+ * @param userMode User mode for which the automation context should use
+ * @throws XPathExpressionException
+ */
+ protected void initCluster(TestUserMode userMode) throws XPathExpressionException {
+ contextMap = new HashMap();
+ AutomationContext automationContext = new AutomationContext("MB_Cluster", userMode);
+ log.info("Cluster instance loading");
+ Map instanceMap = automationContext.getProductGroup().getInstanceMap();
+
+ if (instanceMap != null && instanceMap.size() > 0) {
+ for (Map.Entry entry : instanceMap.entrySet()) {
+ String instanceKey = entry.getKey();
+ contextMap.put(instanceKey, new AutomationContext("MB_Cluster", instanceKey, userMode));
+ log.info(instanceKey);
+ }
+ }
+
+ stack = new Stack();
+
+ }
+
+ /**
+ * Get automation context object with given node key
+ *
+ * @param key The key value for automation context map
+ * @return Respective automation context
+ */
+
+ protected AutomationContext getAutomationContextWithKey(String key) {
+
+ if (contextMap != null && contextMap.size() > 0) {
+ for (Map.Entry entry : contextMap.entrySet()) {
+ if (entry.getKey().equalsIgnoreCase(key)) {
+ return entry.getValue();
+ }
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Get andes admin client for given node
+ *
+ * @param key The key for the map which the andes admin clients are stored
+ * @return An {@link org.wso2.mb.integration.common.clients.operations.clients.AndesAdminClient}.
+ */
+
+ protected AndesAdminClient getAndesAdminClientWithKey(String key) {
+
+ if (andesAdminClients != null && andesAdminClients.size() > 0) {
+ for (Map.Entry entry : andesAdminClients.entrySet()) {
+ if (entry.getKey().equalsIgnoreCase(key)) {
+ return entry.getValue();
+ }
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Get topic admin client for given node.
+ * Suppressing "UnusedDeclaration" warning as this method can be used later in writing test
+ * cases.
+ *
+ * @param key The key for the map which the topic admin clients are stored
+ * @return An {@link org.wso2.mb.integration.common.clients.operations.clients.TopicAdminClient}.
+ */
+ @SuppressWarnings("UnusedDeclaration")
+ protected TopicAdminClient getTopicAdminClientWithKey(String key) {
+
+ if (topicAdminClients != null && topicAdminClients.size() > 0) {
+ for (Map.Entry entry : topicAdminClients.entrySet()) {
+ if (entry.getKey().equalsIgnoreCase(key)) {
+ return entry.getValue();
+ }
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Login and provide session cookie for node
+ *
+ * @param context The automation context to be used.
+ * @return The session cookie of the login user
+ * @throws IOException
+ * @throws XPathExpressionException
+ * @throws URISyntaxException
+ * @throws SAXException
+ * @throws XMLStreamException
+ * @throws LoginAuthenticationExceptionException
+ */
+ protected String login(AutomationContext context)
+ throws IOException, XPathExpressionException, URISyntaxException, SAXException,
+ XMLStreamException, LoginAuthenticationExceptionException, AutomationUtilException {
+ LoginLogoutClient loginLogoutClient = new LoginLogoutClient(context);
+ return loginLogoutClient.login();
+ }
+
+ /**
+ * Make MB instances in random mode to support pick a random instance for test cases
+ */
+ protected void makeMBInstancesRandom() {
+
+ Object[] keys = contextMap.keySet().toArray();
+
+ List