activemq-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From tab...@apache.org
Subject [2/2] git commit: https://issues.apache.org/jira/browse/AMQCPP-519
Date Mon, 14 Oct 2013 21:36:27 GMT
https://issues.apache.org/jira/browse/AMQCPP-519

Implements the basic discovery transport framework and allows for
addition of agents via DiscoveryAgentRegistry

Project: http://git-wip-us.apache.org/repos/asf/activemq-cpp/repo
Commit: http://git-wip-us.apache.org/repos/asf/activemq-cpp/commit/ba624ea9
Tree: http://git-wip-us.apache.org/repos/asf/activemq-cpp/tree/ba624ea9
Diff: http://git-wip-us.apache.org/repos/asf/activemq-cpp/diff/ba624ea9

Branch: refs/heads/trunk
Commit: ba624ea97d6c1013e0167de7404b56e1f8d46330
Parents: e78c283
Author: Timothy Bish <tabish121@gmai.com>
Authored: Mon Oct 14 17:36:17 2013 -0400
Committer: Timothy Bish <tabish121@gmai.com>
Committed: Mon Oct 14 17:36:17 2013 -0400

----------------------------------------------------------------------
 activemq-cpp/src/main/Makefile.am               |  16 ++
 .../src/main/activemq/library/ActiveMQCPP.cpp   |   8 +-
 .../src/main/activemq/transport/Transport.h     |   3 +-
 .../main/activemq/transport/TransportRegistry.h |   6 -
 .../discovery/DiscoveredBrokerData.cpp          |  35 +++
 .../transport/discovery/DiscoveredBrokerData.h  | 123 +++++++++
 .../transport/discovery/DiscoveryAgent.cpp      |  26 ++
 .../transport/discovery/DiscoveryAgent.h        |  76 ++++++
 .../discovery/DiscoveryAgentFactory.cpp         |  26 ++
 .../transport/discovery/DiscoveryAgentFactory.h |  61 +++++
 .../discovery/DiscoveryAgentRegistry.cpp        | 114 ++++++++
 .../discovery/DiscoveryAgentRegistry.h          | 130 +++++++++
 .../transport/discovery/DiscoveryListener.cpp   |  26 ++
 .../transport/discovery/DiscoveryListener.h     |  54 ++++
 .../transport/discovery/DiscoveryTransport.cpp  | 232 ++++++++++++++++
 .../transport/discovery/DiscoveryTransport.h    | 107 ++++++++
 .../discovery/DiscoveryTransportFactory.cpp     | 104 +++++++
 .../discovery/DiscoveryTransportFactory.h       |  53 ++++
 .../failover/FailoverTransportFactory.cpp       |   1 -
 .../failover/FailoverTransportFactory.h         |  11 -
 .../transport/tcp/TcpTransportFactory.h         |   7 +-
 .../src/main/activemq/util/ServiceStopper.cpp   |  18 +-
 .../src/main/activemq/util/Suspendable.cpp      |  26 ++
 .../src/main/activemq/util/Suspendable.h        |  56 ++++
 .../src/main/activemq/util/URISupport.cpp       |  86 ++++++
 .../src/main/activemq/util/URISupport.h         |  89 +++++-
 activemq-cpp/src/main/decaf/util/Properties.cpp | 270 +++++++++----------
 activemq-cpp/src/main/decaf/util/Properties.h   |  34 +--
 activemq-cpp/src/test/Makefile.am               |   4 +
 .../discovery/DiscoveryAgentRegistryTest.cpp    |  87 ++++++
 .../discovery/DiscoveryAgentRegistryTest.h      |  45 ++++
 .../discovery/DiscoveryTransportFactoryTest.cpp | 113 ++++++++
 .../discovery/DiscoveryTransportFactoryTest.h   |  47 ++++
 .../src/test/activemq/util/URISupportTest.cpp   |  43 +++
 .../src/test/activemq/util/URISupportTest.h     |   4 +
 activemq-cpp/src/test/testRegistry.cpp          |   5 +
 36 files changed, 1955 insertions(+), 191 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/activemq-cpp/blob/ba624ea9/activemq-cpp/src/main/Makefile.am
----------------------------------------------------------------------
diff --git a/activemq-cpp/src/main/Makefile.am b/activemq-cpp/src/main/Makefile.am
index d6ad66e..0861789 100644
--- a/activemq-cpp/src/main/Makefile.am
+++ b/activemq-cpp/src/main/Makefile.am
@@ -155,6 +155,13 @@ cc_sources = \
     activemq/transport/TransportFilter.cpp \
     activemq/transport/TransportRegistry.cpp \
     activemq/transport/correlator/ResponseCorrelator.cpp \
+    activemq/transport/discovery/DiscoveredBrokerData.cpp \
+    activemq/transport/discovery/DiscoveryAgent.cpp \
+    activemq/transport/discovery/DiscoveryAgentFactory.cpp \
+    activemq/transport/discovery/DiscoveryAgentRegistry.cpp \
+    activemq/transport/discovery/DiscoveryListener.cpp \
+    activemq/transport/discovery/DiscoveryTransport.cpp \
+    activemq/transport/discovery/DiscoveryTransportFactory.cpp \
     activemq/transport/failover/BackupTransport.cpp \
     activemq/transport/failover/BackupTransportPool.cpp \
     activemq/transport/failover/CloseTransportsTask.cpp \
@@ -191,6 +198,7 @@ cc_sources = \
     activemq/util/ServiceListener.cpp \
     activemq/util/ServiceStopper.cpp \
     activemq/util/ServiceSupport.cpp \
+    activemq/util/Suspendable.cpp \
     activemq/util/URISupport.cpp \
     activemq/util/Usage.cpp \
     activemq/wireformat/MarshalAware.cpp \
@@ -803,6 +811,13 @@ h_sources = \
     activemq/transport/TransportListener.h \
     activemq/transport/TransportRegistry.h \
     activemq/transport/correlator/ResponseCorrelator.h \
+    activemq/transport/discovery/DiscoveredBrokerData.h \
+    activemq/transport/discovery/DiscoveryAgent.h \
+    activemq/transport/discovery/DiscoveryAgentFactory.h \
+    activemq/transport/discovery/DiscoveryAgentRegistry.h \
+    activemq/transport/discovery/DiscoveryListener.h \
+    activemq/transport/discovery/DiscoveryTransport.h \
+    activemq/transport/discovery/DiscoveryTransportFactory.h \
     activemq/transport/failover/BackupTransport.h \
     activemq/transport/failover/BackupTransportPool.h \
     activemq/transport/failover/CloseTransportsTask.h \
@@ -840,6 +855,7 @@ h_sources = \
     activemq/util/ServiceListener.h \
     activemq/util/ServiceStopper.h \
     activemq/util/ServiceSupport.h \
+    activemq/util/Suspendable.h \
     activemq/util/URISupport.h \
     activemq/util/Usage.h \
     activemq/wireformat/MarshalAware.h \

http://git-wip-us.apache.org/repos/asf/activemq-cpp/blob/ba624ea9/activemq-cpp/src/main/activemq/library/ActiveMQCPP.cpp
----------------------------------------------------------------------
diff --git a/activemq-cpp/src/main/activemq/library/ActiveMQCPP.cpp b/activemq-cpp/src/main/activemq/library/ActiveMQCPP.cpp
index 44581a8..df77048 100644
--- a/activemq-cpp/src/main/activemq/library/ActiveMQCPP.cpp
+++ b/activemq-cpp/src/main/activemq/library/ActiveMQCPP.cpp
@@ -20,6 +20,7 @@
 #include <decaf/lang/Runtime.h>
 #include <activemq/wireformat/WireFormatRegistry.h>
 #include <activemq/transport/TransportRegistry.h>
+#include <activemq/transport/discovery/DiscoveryAgentRegistry.h>
 
 #include <activemq/util/IdGenerator.h>
 
@@ -38,6 +39,7 @@ using namespace activemq::transport;
 using namespace activemq::transport::tcp;
 using namespace activemq::transport::mock;
 using namespace activemq::transport::failover;
+using namespace activemq::transport::discovery;
 using namespace activemq::wireformat;
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -79,6 +81,7 @@ void ActiveMQCPP::shutdownLibrary() {
 
     WireFormatRegistry::shutdown();
     TransportRegistry::shutdown();
+    DiscoveryAgentRegistry::shutdown();
 
     // Now it should be safe to shutdown Decaf.
     decaf::lang::Runtime::shutdownRuntime();
@@ -99,11 +102,14 @@ void ActiveMQCPP::registerWireFormats() {
 void ActiveMQCPP::registerTransports() {
 
     // Each of the internally implemented Transports is registered here
-    // with the Transport Registry
     TransportRegistry::initialize();
 
     TransportRegistry::getInstance().registerFactory("tcp", new TcpTransportFactory());
     TransportRegistry::getInstance().registerFactory("ssl", new SslTransportFactory());
     TransportRegistry::getInstance().registerFactory("mock", new MockTransportFactory());
     TransportRegistry::getInstance().registerFactory("failover", new FailoverTransportFactory());
+
+    // Each discovery agent implemented in this library must be registered here.
+    DiscoveryAgentRegistry::initialize();
+
 }

http://git-wip-us.apache.org/repos/asf/activemq-cpp/blob/ba624ea9/activemq-cpp/src/main/activemq/transport/Transport.h
----------------------------------------------------------------------
diff --git a/activemq-cpp/src/main/activemq/transport/Transport.h b/activemq-cpp/src/main/activemq/transport/Transport.h
index aae0904..deb7213 100644
--- a/activemq-cpp/src/main/activemq/transport/Transport.h
+++ b/activemq-cpp/src/main/activemq/transport/Transport.h
@@ -27,6 +27,7 @@
 #include <decaf/lang/Pointer.h>
 #include <decaf/lang/exceptions/UnsupportedOperationException.h>
 #include <activemq/util/Config.h>
+#include <activemq/util/Service.h>
 #include <activemq/transport/ResponseCallback.h>
 #include <activemq/transport/FutureResponse.h>
 #include <activemq/commands/Command.h>
@@ -56,7 +57,7 @@ namespace transport{
      * object when created so that they can turn the built in Commands to /
      * from the required wire format encoding.
      */
-    class AMQCPP_API Transport: public decaf::io::Closeable {
+    class AMQCPP_API Transport : public activemq::util::Service, public decaf::io::Closeable {
     public:
 
         virtual ~Transport();

http://git-wip-us.apache.org/repos/asf/activemq-cpp/blob/ba624ea9/activemq-cpp/src/main/activemq/transport/TransportRegistry.h
----------------------------------------------------------------------
diff --git a/activemq-cpp/src/main/activemq/transport/TransportRegistry.h b/activemq-cpp/src/main/activemq/transport/TransportRegistry.h
index 4c97fe9..00ba4ce 100644
--- a/activemq-cpp/src/main/activemq/transport/TransportRegistry.h
+++ b/activemq-cpp/src/main/activemq/transport/TransportRegistry.h
@@ -49,13 +49,8 @@ namespace transport {
 
     private:
 
-        // Hidden Constructor, prevents instantiation
         TransportRegistry();
-
-        // Hidden Copy Constructor
         TransportRegistry(const TransportRegistry& registry);
-
-        // Hidden Assignment operator
         TransportRegistry& operator=(const TransportRegistry& registry);
 
     public:
@@ -115,7 +110,6 @@ namespace transport {
         std::vector<std::string> getTransportNames() const;
 
     public:
-        // Static methods
 
         /**
          * Gets the single instance of the TransportRegistry

http://git-wip-us.apache.org/repos/asf/activemq-cpp/blob/ba624ea9/activemq-cpp/src/main/activemq/transport/discovery/DiscoveredBrokerData.cpp
----------------------------------------------------------------------
diff --git a/activemq-cpp/src/main/activemq/transport/discovery/DiscoveredBrokerData.cpp b/activemq-cpp/src/main/activemq/transport/discovery/DiscoveredBrokerData.cpp
new file mode 100644
index 0000000..56ff924
--- /dev/null
+++ b/activemq-cpp/src/main/activemq/transport/discovery/DiscoveredBrokerData.cpp
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "DiscoveredBrokerData.h"
+
+using namespace activemq;
+using namespace activemq::commands;
+using namespace activemq::transport;
+using namespace activemq::transport::discovery;
+
+////////////////////////////////////////////////////////////////////////////////
+DiscoveredBrokerData::DiscoveredBrokerData() : DiscoveryEvent(),
+                                               lastHeartBeatTime(0),
+                                               nextRecoveryTime(0),
+                                               failureCount(0),
+                                               failed(false) {
+}
+
+////////////////////////////////////////////////////////////////////////////////
+DiscoveredBrokerData::~DiscoveredBrokerData() {
+}

http://git-wip-us.apache.org/repos/asf/activemq-cpp/blob/ba624ea9/activemq-cpp/src/main/activemq/transport/discovery/DiscoveredBrokerData.h
----------------------------------------------------------------------
diff --git a/activemq-cpp/src/main/activemq/transport/discovery/DiscoveredBrokerData.h b/activemq-cpp/src/main/activemq/transport/discovery/DiscoveredBrokerData.h
new file mode 100644
index 0000000..4af93ad
--- /dev/null
+++ b/activemq-cpp/src/main/activemq/transport/discovery/DiscoveredBrokerData.h
@@ -0,0 +1,123 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _ACTIVEMQ_TRANSPORT_DISCOVERY_DISCOVEREDBROKERDATA_H_
+#define _ACTIVEMQ_TRANSPORT_DISCOVERY_DISCOVEREDBROKERDATA_H_
+
+#include <activemq/commands/DiscoveryEvent.h>
+
+namespace activemq {
+namespace transport {
+namespace discovery {
+
+    /**
+     * Enhanced DiscoveryEvent object used to store additional data about discovered
+     * broker services.
+     *
+     * @since 3.9.0
+     */
+    class DiscoveredBrokerData : public activemq::commands::DiscoveryEvent {
+    private:
+
+        long long lastHeartBeatTime;
+        long long nextRecoveryTime;
+        int failureCount;
+        bool failed;
+
+    public:
+
+        DiscoveredBrokerData();
+        virtual ~DiscoveredBrokerData();
+
+        /**
+         * Gets the time of the last heart best from this Broker
+         *
+         * @returns the time of the last received heart beat event from this Broker
+         */
+        long long getLastHeartBeatTime() const {
+            return this->lastHeartBeatTime;
+        }
+
+        /**
+         * Sets the time of the last received heart beat event from this Broker.
+         *
+         * @param lastHeartBeatTime
+         *      Time since last heart beat was received.
+         */
+        void setLastHeartBeatTime(long long lastHeartBeatTime) {
+            this->lastHeartBeatTime = lastHeartBeatTime;
+        }
+
+        /**
+         * @returns true is this service has been marked as failed.
+         */
+        bool isFailed() const {
+            return failed;
+        }
+
+        /**
+         * Marks this service as failed.
+         *
+         * @param failed
+         *      Set to true to mark this broker as failed.
+         */
+        void setFailed(bool failed) {
+            this->failed = failed;
+        }
+
+        /**
+         * Gets the number of times that there was a failure contacting this broker.
+         *
+         * @returns count of the number of failures of this service.
+         */
+        int getFailureCount() const {
+            return failureCount;
+        }
+
+        /**
+         * Sets the number of failures that are recorded for this service.
+         *
+         * @param failureCount
+         *      The new value of the failure count for this service.
+         */
+        void setFailureCount(int failureCount) {
+            this->failureCount = failureCount;
+        }
+
+        /**
+         * Gets the set time for the next recovery attempt on this service.
+         *
+         * @returns the next set time that this service can have a recovery attempt.
+         */
+        long long getNextRecoveryTime() const {
+            return nextRecoveryTime;
+        }
+
+        /**
+         * Sets the next recovery time value for this service.
+         *
+         * @param recoveryTime
+         *      The next time a recovery of this service should be attempted.
+         */
+        void setNextRecoveryTime(long long nextRecoveryTime) {
+            this->nextRecoveryTime = nextRecoveryTime;
+        }
+    };
+
+}}}
+
+#endif /* _ACTIVEMQ_TRANSPORT_DISCOVERY_DISCOVEREDBROKERDATA_H_ */

http://git-wip-us.apache.org/repos/asf/activemq-cpp/blob/ba624ea9/activemq-cpp/src/main/activemq/transport/discovery/DiscoveryAgent.cpp
----------------------------------------------------------------------
diff --git a/activemq-cpp/src/main/activemq/transport/discovery/DiscoveryAgent.cpp b/activemq-cpp/src/main/activemq/transport/discovery/DiscoveryAgent.cpp
new file mode 100644
index 0000000..d356690
--- /dev/null
+++ b/activemq-cpp/src/main/activemq/transport/discovery/DiscoveryAgent.cpp
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "DiscoveryAgent.h"
+
+using namespace activemq;
+using namespace activemq::transport;
+using namespace activemq::transport::discovery;
+
+////////////////////////////////////////////////////////////////////////////////
+DiscoveryAgent::~DiscoveryAgent() {
+}

http://git-wip-us.apache.org/repos/asf/activemq-cpp/blob/ba624ea9/activemq-cpp/src/main/activemq/transport/discovery/DiscoveryAgent.h
----------------------------------------------------------------------
diff --git a/activemq-cpp/src/main/activemq/transport/discovery/DiscoveryAgent.h b/activemq-cpp/src/main/activemq/transport/discovery/DiscoveryAgent.h
new file mode 100644
index 0000000..d4a43e8
--- /dev/null
+++ b/activemq-cpp/src/main/activemq/transport/discovery/DiscoveryAgent.h
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _ACTIVEMQ_TRANSPORT_DISCOVERY_DISCOVERYAGENT_H_
+#define _ACTIVEMQ_TRANSPORT_DISCOVERY_DISCOVERYAGENT_H_
+
+#include <activemq/util/Config.h>
+#include <activemq/util/Service.h>
+#include <decaf/net/URI.h>
+#include <decaf/util/Properties.h>
+
+#include <activemq/commands/DiscoveryEvent.h>
+
+namespace activemq {
+namespace transport {
+namespace discovery {
+
+    class DiscoveryListener;
+
+    class AMQCPP_API DiscoveryAgent : public activemq::util::Service {
+    public:
+
+        virtual ~DiscoveryAgent();
+
+        /**
+         * Sets the discovery listener which will be notified on the add or remove of
+         * a discovered service.
+         *
+         * @param listener
+         *      Pointer to a listener instance that will be notified, or null to reset.
+         */
+        virtual void setDiscoveryListener(DiscoveryListener* listener) = 0;
+
+        /**
+         * Register a service with this DiscoveryAgent.  If the agent supports advertisement
+         * then the new service will be broadcast.
+         *
+         * @param service
+         *      The service to register and advertise.
+         *
+         * @throws IOException if an error occurs.
+         */
+        virtual void registerService(const std::string& name) = 0;
+
+        /**
+         * A process actively using a service may see it go down before the DiscoveryAgent
+         * notices the service's failure.  That process can use this method to notify the
+         * DiscoveryAgent of the failure so that other listeners of this DiscoveryAgent can
+         * also be made aware of the failure.
+         *
+         * @paran event
+         *      A DiscoveryEvent that contains information on the failed service.
+         *
+         * @throws IOException if an error occurs processing the failure event.
+         */
+        virtual void serviceFailed(const activemq::commands::DiscoveryEvent& event) = 0;
+
+    };
+
+}}}
+
+#endif /* _ACTIVEMQ_TRANSPORT_DISCOVERY_DISCOVERYAGENT_H_ */

http://git-wip-us.apache.org/repos/asf/activemq-cpp/blob/ba624ea9/activemq-cpp/src/main/activemq/transport/discovery/DiscoveryAgentFactory.cpp
----------------------------------------------------------------------
diff --git a/activemq-cpp/src/main/activemq/transport/discovery/DiscoveryAgentFactory.cpp b/activemq-cpp/src/main/activemq/transport/discovery/DiscoveryAgentFactory.cpp
new file mode 100644
index 0000000..ccef7d5
--- /dev/null
+++ b/activemq-cpp/src/main/activemq/transport/discovery/DiscoveryAgentFactory.cpp
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "DiscoveryAgentFactory.h"
+
+using namespace activemq;
+using namespace activemq::transport;
+using namespace activemq::transport::discovery;
+
+////////////////////////////////////////////////////////////////////////////////
+DiscoveryAgentFactory::~DiscoveryAgentFactory() {
+}

http://git-wip-us.apache.org/repos/asf/activemq-cpp/blob/ba624ea9/activemq-cpp/src/main/activemq/transport/discovery/DiscoveryAgentFactory.h
----------------------------------------------------------------------
diff --git a/activemq-cpp/src/main/activemq/transport/discovery/DiscoveryAgentFactory.h b/activemq-cpp/src/main/activemq/transport/discovery/DiscoveryAgentFactory.h
new file mode 100644
index 0000000..96700be
--- /dev/null
+++ b/activemq-cpp/src/main/activemq/transport/discovery/DiscoveryAgentFactory.h
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _ACTIVEMQ_TRANSPORT_DISCOVERY_DISCOVERYAGENTFACTORY_H_
+#define _ACTIVEMQ_TRANSPORT_DISCOVERY_DISCOVERYAGENTFACTORY_H_
+
+#include <activemq/util/Config.h>
+
+#include <decaf/lang/Pointer.h>
+#include <decaf/net/URI.h>
+
+#include <activemq/transport/discovery/DiscoveryAgent.h>
+
+namespace activemq {
+namespace transport {
+namespace discovery {
+
+    /**
+     * Factory class for creating discovery agents.  All agents are required to
+     * provide a factory class that can be registered in the DiscoveryAgentRegistry.
+     *
+     * @since 3.9.0
+     */
+    class DiscoveryAgentFactory {
+    public:
+
+        virtual ~DiscoveryAgentFactory();
+
+        /**
+         * Creates and returns a new DiscoveryAgentFactory instance that can be used to
+         * create the agent referred to in the given URI.  The factory should apply all
+         * configuration options to the agent prior to returning it.
+         *
+         * @param agentURI
+         *      The URI that defines the agent to create along with it configuration options.
+         *
+         * @returns a new DiscoveryAgent instance for the given URI.
+         *
+         * @throws IOException if an error occurs creating the given agent.
+         */
+        virtual decaf::lang::Pointer<DiscoveryAgent> createAgent(const decaf::net::URI& agentURI) = 0;
+
+    };
+
+}}}
+
+#endif /* _ACTIVEMQ_TRANSPORT_DISCOVERY_DISCOVERYAGENTFACTORY_H_ */

http://git-wip-us.apache.org/repos/asf/activemq-cpp/blob/ba624ea9/activemq-cpp/src/main/activemq/transport/discovery/DiscoveryAgentRegistry.cpp
----------------------------------------------------------------------
diff --git a/activemq-cpp/src/main/activemq/transport/discovery/DiscoveryAgentRegistry.cpp b/activemq-cpp/src/main/activemq/transport/discovery/DiscoveryAgentRegistry.cpp
new file mode 100644
index 0000000..17bb845
--- /dev/null
+++ b/activemq-cpp/src/main/activemq/transport/discovery/DiscoveryAgentRegistry.cpp
@@ -0,0 +1,114 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "DiscoveryAgentRegistry.h"
+
+#include <activemq/exceptions/ActiveMQException.h>
+#include <activemq/transport/discovery/DiscoveryAgentFactory.h>
+
+using namespace std;
+using namespace activemq;
+using namespace activemq::exceptions;
+using namespace activemq::transport;
+using namespace activemq::transport::discovery;
+using namespace decaf;
+using namespace decaf::util;
+using namespace decaf::lang;
+using namespace decaf::lang::exceptions;
+
+////////////////////////////////////////////////////////////////////////////////
+namespace {
+    DiscoveryAgentRegistry* theOnlyInstance;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+DiscoveryAgentRegistry::DiscoveryAgentRegistry() : registry() {
+}
+
+////////////////////////////////////////////////////////////////////////////////
+DiscoveryAgentRegistry::~DiscoveryAgentRegistry() {
+    try {
+        this->unregisterAllFactories();
+    }
+    AMQ_CATCHALL_NOTHROW()
+}
+
+////////////////////////////////////////////////////////////////////////////////
+DiscoveryAgentFactory* DiscoveryAgentRegistry::findFactory(const std::string& name) const {
+
+    if (!this->registry.containsKey(name)) {
+        throw NoSuchElementException(__FILE__, __LINE__,
+            "No Matching Factory Registered for format := %s", name.c_str());
+    }
+
+    return this->registry.get(name);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+void DiscoveryAgentRegistry::registerFactory(const std::string& name, DiscoveryAgentFactory* factory) {
+
+    if (name == "") {
+        throw IllegalArgumentException(__FILE__, __LINE__, "DiscoveryAgentFactory name cannot be the empty string");
+    }
+
+    if (factory == NULL) {
+        throw NullPointerException(__FILE__, __LINE__, "Supplied DiscoveryAgentFactory pointer was NULL");
+    }
+
+    this->registry.put(name, factory);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+void DiscoveryAgentRegistry::unregisterFactory(const std::string& name) {
+    if (this->registry.containsKey(name)) {
+        delete this->registry.get(name);
+        this->registry.remove(name);
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+void DiscoveryAgentRegistry::unregisterAllFactories() {
+
+    Pointer<Iterator<DiscoveryAgentFactory*> > iterator(this->registry.values().iterator());
+    while (iterator->hasNext()) {
+        delete iterator->next();
+    }
+
+    this->registry.clear();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+std::vector<std::string> DiscoveryAgentRegistry::getAgentNames() const {
+    return this->registry.keySet().toArray();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+DiscoveryAgentRegistry& DiscoveryAgentRegistry::getInstance() {
+    return *theOnlyInstance;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+void DiscoveryAgentRegistry::initialize() {
+    theOnlyInstance = new DiscoveryAgentRegistry();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+void DiscoveryAgentRegistry::shutdown() {
+    theOnlyInstance->unregisterAllFactories();
+    delete theOnlyInstance;
+    theOnlyInstance = NULL;
+}

http://git-wip-us.apache.org/repos/asf/activemq-cpp/blob/ba624ea9/activemq-cpp/src/main/activemq/transport/discovery/DiscoveryAgentRegistry.h
----------------------------------------------------------------------
diff --git a/activemq-cpp/src/main/activemq/transport/discovery/DiscoveryAgentRegistry.h b/activemq-cpp/src/main/activemq/transport/discovery/DiscoveryAgentRegistry.h
new file mode 100644
index 0000000..b16be73
--- /dev/null
+++ b/activemq-cpp/src/main/activemq/transport/discovery/DiscoveryAgentRegistry.h
@@ -0,0 +1,130 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _ACTIVEMQ_TRANSPORT_DISCOVERY_DISCOVERYAGENTREGISTRY_H_
+#define _ACTIVEMQ_TRANSPORT_DISCOVERY_DISCOVERYAGENTREGISTRY_H_
+
+#include <activemq/util/Config.h>
+
+#include <string>
+#include <vector>
+
+#include <decaf/util/StlMap.h>
+
+namespace activemq {
+namespace library {
+    class ActiveMQCPP;
+}
+namespace transport {
+namespace discovery {
+
+    class DiscoveryAgentFactory;
+
+    /**
+     * Registry of all Discovery Agent Factories that are available to the client
+     * at runtime.  New Agents must have a factory registered here before an attempt
+     * to create a DiscoveryTansport which uses that agent.
+     *
+     * @since 3.9.0
+     */
+    class AMQCPP_API DiscoveryAgentRegistry {
+    private:
+
+        decaf::util::StlMap<std::string, DiscoveryAgentFactory*> registry;
+
+    private:
+
+        DiscoveryAgentRegistry();
+        DiscoveryAgentRegistry(const DiscoveryAgentRegistry& registry);
+        DiscoveryAgentRegistry& operator=(const DiscoveryAgentRegistry& registry);
+
+    public:
+
+        virtual ~DiscoveryAgentRegistry();
+
+        /**
+         * Gets a Registered DiscoveryAgentFactory from the Registry and returns it
+         * if there is not a registered format factory with the given name an exception
+         * is thrown.
+         *
+         * @param name
+         *        The name of the Factory to find in the Registry.
+         *
+         * @returns the Factory registered under the given name.
+         *
+         * @throws NoSuchElementException if no factory is registered with that name.
+         */
+        DiscoveryAgentFactory* findFactory(const std::string& name) const;
+
+        /**
+         * Registers a new DiscoveryAgentFactory with this Registry.  If a Factory with the
+         * given name is already registered it is overwritten with the new one.  Once a
+         * factory is added to the Registry its lifetime is controlled by the Registry, it
+         * will be deleted once the Registry has been deleted.
+         *
+         * @param name
+         *        The name of the new Factory to register.
+         * @param factory
+         *        The new Factory to add to the Registry.
+         *
+         * @throws IllegalArgumentException is name is the empty string.
+         * @throws NullPointerException if the Factory is Null.
+         */
+        void registerFactory(const std::string& name, DiscoveryAgentFactory* factory);
+
+        /**
+         * Unregisters the Factory with the given name and deletes that instance of the
+         * Factory.
+         *
+         * @param name
+         *        Name of the Factory to unregister and destroy
+         */
+        void unregisterFactory(const std::string& name);
+
+        /**
+         * Removes all Factories and deletes the instances of the Factory objects.
+         */
+        void unregisterAllFactories();
+
+        /**
+         * Retrieves a list of the names of all the Registered Agents in this
+         * Registry.
+         *
+         * @returns stl vector of strings with all the Agent names registered.
+         */
+        std::vector<std::string> getAgentNames() const;
+
+    public:
+
+        /**
+         * Gets the single instance of the TransportRegistry
+         * @return reference to the single instance of this Registry
+         */
+        static DiscoveryAgentRegistry& getInstance();
+
+    private:
+
+        static void initialize();
+        static void shutdown();
+
+        friend class activemq::library::ActiveMQCPP;
+
+    };
+
+}}}
+
+#endif /* _ACTIVEMQ_TRANSPORT_DISCOVERY_DISCOVERYAGENTREGISTRY_H_ */

http://git-wip-us.apache.org/repos/asf/activemq-cpp/blob/ba624ea9/activemq-cpp/src/main/activemq/transport/discovery/DiscoveryListener.cpp
----------------------------------------------------------------------
diff --git a/activemq-cpp/src/main/activemq/transport/discovery/DiscoveryListener.cpp b/activemq-cpp/src/main/activemq/transport/discovery/DiscoveryListener.cpp
new file mode 100644
index 0000000..a260fe7
--- /dev/null
+++ b/activemq-cpp/src/main/activemq/transport/discovery/DiscoveryListener.cpp
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "DiscoveryListener.h"
+
+using namespace activemq;
+using namespace activemq::transport;
+using namespace activemq::transport::discovery;
+
+////////////////////////////////////////////////////////////////////////////////
+DiscoveryListener::~DiscoveryListener() {
+}

http://git-wip-us.apache.org/repos/asf/activemq-cpp/blob/ba624ea9/activemq-cpp/src/main/activemq/transport/discovery/DiscoveryListener.h
----------------------------------------------------------------------
diff --git a/activemq-cpp/src/main/activemq/transport/discovery/DiscoveryListener.h b/activemq-cpp/src/main/activemq/transport/discovery/DiscoveryListener.h
new file mode 100644
index 0000000..87b06ea
--- /dev/null
+++ b/activemq-cpp/src/main/activemq/transport/discovery/DiscoveryListener.h
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _ACTIVEMQ_TRANSPORT_DISCOVERY_DISCOVERYLISTENER_H_
+#define _ACTIVEMQ_TRANSPORT_DISCOVERY_DISCOVERYLISTENER_H_
+
+#include <activemq/util/Config.h>
+
+#include <activemq/commands/DiscoveryEvent.h>
+
+namespace activemq {
+namespace transport {
+namespace discovery {
+
+    class AMQCPP_API DiscoveryListener {
+    public:
+
+        virtual ~DiscoveryListener();
+
+        /**
+         * Called when an discovery agent becomes aware of a new service.
+         *
+         * @param event
+         *      A DiscoveryEvent that contains information on the newly discovered service.
+         */
+        virtual void onServiceAdd(const activemq::commands::DiscoveryEvent& event) = 0;
+
+        /**
+         * Called when an discovery agent determines that a service is no longer available.
+         *
+         * @param event
+         *      A DiscoveryEvent that contains information on the removed service.
+         */
+        virtual void onServiceRemove(const activemq::commands::DiscoveryEvent& event) = 0;
+
+    };
+
+}}}
+
+#endif /* _ACTIVEMQ_TRANSPORT_DISCOVERY_DISCOVERYLISTENER_H_ */

http://git-wip-us.apache.org/repos/asf/activemq-cpp/blob/ba624ea9/activemq-cpp/src/main/activemq/transport/discovery/DiscoveryTransport.cpp
----------------------------------------------------------------------
diff --git a/activemq-cpp/src/main/activemq/transport/discovery/DiscoveryTransport.cpp b/activemq-cpp/src/main/activemq/transport/discovery/DiscoveryTransport.cpp
new file mode 100644
index 0000000..03fef90
--- /dev/null
+++ b/activemq-cpp/src/main/activemq/transport/discovery/DiscoveryTransport.cpp
@@ -0,0 +1,232 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "DiscoveryTransport.h"
+
+#include <activemq/util/URISupport.h>
+#include <activemq/util/Suspendable.h>
+#include <activemq/exceptions/ActiveMQException.h>
+
+#include <decaf/util/HashMap.h>
+#include <decaf/util/StlMap.h>
+#include <decaf/util/Properties.h>
+#include <decaf/util/concurrent/Mutex.h>
+#include <decaf/net/URISyntaxException.h>
+#include <decaf/lang/exceptions/NullPointerException.h>
+
+using namespace decaf;
+using namespace decaf::util;
+using namespace decaf::util::concurrent;
+using namespace decaf::io;
+using namespace decaf::net;
+using namespace decaf::lang;
+using namespace decaf::lang::exceptions;
+using namespace activemq;
+using namespace activemq::commands;
+using namespace activemq::exceptions;
+using namespace activemq::util;
+using namespace activemq::transport;
+using namespace activemq::transport::discovery;
+
+////////////////////////////////////////////////////////////////////////////////
+const std::string DiscoveryTransport::DISCOVERED_OPTION_PREFIX = "discovered.";
+
+////////////////////////////////////////////////////////////////////////////////
+namespace activemq {
+namespace transport {
+namespace discovery {
+
+    class DiscoveryTransportData {
+    public:
+
+        Pointer<CompositeTransport> next;
+        Pointer<DiscoveryAgent> agent;
+        StlMap<std::string, URI> serviceURIs;
+        Properties parameters;
+        Mutex lock;
+
+    private:
+
+        DiscoveryTransportData(const DiscoveryTransportData&);
+        DiscoveryTransportData& operator= (const DiscoveryTransportData&);
+
+    public:
+
+        DiscoveryTransportData() : next(), agent(), serviceURIs(), parameters(), lock() {}
+    };
+
+}}}
+
+////////////////////////////////////////////////////////////////////////////////
+DiscoveryTransport::DiscoveryTransport(Pointer<CompositeTransport> next) :
+    TransportFilter(next), impl(new DiscoveryTransportData) {
+}
+
+////////////////////////////////////////////////////////////////////////////////
+DiscoveryTransport::~DiscoveryTransport() {
+    try {
+        this->close();
+    }
+    AMQ_CATCHALL_NOTHROW()
+    try {
+        delete this->impl;
+    }
+    AMQ_CATCHALL_NOTHROW()
+}
+
+////////////////////////////////////////////////////////////////////////////////
+void DiscoveryTransport::start() {
+    if (this->impl->agent == NULL) {
+        throw IllegalStateException(__FILE__, __LINE__, "discoveryAgent not configured");
+    }
+
+    // lets pass into the agent the broker name and connection details
+    this->impl->agent->setDiscoveryListener(this);
+    this->impl->agent->start();
+
+    TransportFilter::start();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+void DiscoveryTransport::stop() {
+
+    try {
+        IOException error;
+        bool hasException = false;
+
+        try {
+            this->impl->agent->stop();
+        } catch (IOException& ex) {
+            error = ex;
+            error.setMark(__FILE__, __LINE__);
+            hasException = true;
+        }
+
+        try {
+            TransportFilter::stop();
+        } catch (IOException& ex) {
+            if (!hasException) {
+                error = ex;
+                error.setMark(__FILE__, __LINE__);
+                hasException = true;
+            }
+        }
+
+        if (hasException) {
+            throw error;
+        }
+    }
+    AMQ_CATCH_RETHROW(IOException)
+    AMQ_CATCH_EXCEPTION_CONVERT(Exception, IOException)
+    AMQ_CATCHALL_THROW(IOException)
+}
+
+////////////////////////////////////////////////////////////////////////////////
+void DiscoveryTransport::doClose() {
+    try {
+        this->impl->next.reset(NULL);
+    }
+    AMQ_CATCH_RETHROW(IOException)
+    AMQ_CATCH_EXCEPTION_CONVERT(Exception, IOException)
+    AMQ_CATCHALL_THROW(IOException)
+}
+
+////////////////////////////////////////////////////////////////////////////////
+void DiscoveryTransport::setDiscoveryAgent(decaf::lang::Pointer<DiscoveryAgent> agent) {
+    if (agent == NULL) {
+        throw NullPointerException(__FILE__, __LINE__, "DiscoveryAgent required to be non-null");
+    }
+
+    this->impl->agent = agent;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+Pointer<DiscoveryAgent> DiscoveryTransport::getDiscoveryAgent() const {
+    return this->impl->agent;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+void DiscoveryTransport::setParameters(const Properties& properties) {
+    this->impl->parameters = properties;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+Properties DiscoveryTransport::getParameters() const {
+    return this->impl->parameters;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+void DiscoveryTransport::onServiceAdd(const DiscoveryEvent& event) {
+    std::string url = event.getServiceName();
+    if (!url.empty()) {
+        try {
+            URI uri(url);
+            uri = URISupport::applyParameters(uri, this->impl->parameters, DISCOVERED_OPTION_PREFIX);
+            synchronized(&this->impl->lock) {
+                this->impl->serviceURIs.put(event.getServiceName(), uri);
+            }
+            LinkedList<URI> uris;
+            uris.add(uri);
+            this->impl->next->addURI(false, uris);
+        } catch (URISyntaxException& e) {
+        }
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+void DiscoveryTransport::onServiceRemove(const DiscoveryEvent& event) {
+    try {
+        URI uri;
+        synchronized(&this->impl->lock) {
+            uri = this->impl->serviceURIs.get(event.getServiceName());
+        }
+        LinkedList<URI> uris;
+        uris.add(uri);
+        this->impl->next->removeURI(false, uris);
+    } catch (NoSuchElementException& e) {}
+}
+
+////////////////////////////////////////////////////////////////////////////////
+void DiscoveryTransport::transportInterrupted() {
+
+    Pointer<Suspendable> suspendable;
+    try {
+        suspendable = this->impl->next.dynamicCast<Suspendable>();
+        suspendable->resume();
+    } catch (ClassCastException& e) {
+        // Not a Suspendable instance.
+    } catch (Exception& e) {
+        // Failed to Resume
+    }
+
+    TransportFilter::transportInterrupted();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+void DiscoveryTransport::transportResumed() {
+    Pointer<Suspendable> suspendable;
+    try {
+        suspendable = this->impl->next.dynamicCast<Suspendable>();
+        suspendable->suspend();
+    } catch (ClassCastException& e) {
+        // Not a Suspendable instance.
+    } catch (Exception& e) {
+        // Failed to Suspend
+    }
+
+    TransportFilter::transportResumed();
+}

http://git-wip-us.apache.org/repos/asf/activemq-cpp/blob/ba624ea9/activemq-cpp/src/main/activemq/transport/discovery/DiscoveryTransport.h
----------------------------------------------------------------------
diff --git a/activemq-cpp/src/main/activemq/transport/discovery/DiscoveryTransport.h b/activemq-cpp/src/main/activemq/transport/discovery/DiscoveryTransport.h
new file mode 100644
index 0000000..2bc9cc4
--- /dev/null
+++ b/activemq-cpp/src/main/activemq/transport/discovery/DiscoveryTransport.h
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _ACTIVEMQ_TRANSPORT_DISCOVERY_DISCOVERYTRANSPORT_H_
+#define _ACTIVEMQ_TRANSPORT_DISCOVERY_DISCOVERYTRANSPORT_H_
+
+#include <activemq/util/Config.h>
+#include <activemq/transport/CompositeTransport.h>
+#include <activemq/transport/TransportFilter.h>
+#include <activemq/transport/discovery/DiscoveryListener.h>
+#include <activemq/transport/discovery/DiscoveryAgent.h>
+#include <decaf/net/URI.h>
+#include <decaf/util/Properties.h>
+
+namespace activemq {
+namespace transport {
+namespace discovery {
+
+    class DiscoveryTransportData;
+
+    class AMQCPP_API DiscoveryTransport : public TransportFilter, public DiscoveryListener {
+    public:
+
+        static const std::string DISCOVERED_OPTION_PREFIX;
+
+    private:
+
+        DiscoveryTransport(const DiscoveryTransport&);
+        DiscoveryTransport& operator=(const DiscoveryTransport&);
+
+    private:
+
+        DiscoveryTransportData* impl;
+
+    public:
+
+        DiscoveryTransport(Pointer<CompositeTransport> next);
+
+        virtual ~DiscoveryTransport();
+
+        virtual void start();
+
+        virtual void stop();
+
+        /**
+         * Sets the Discovery Agent that this transport will use to discover new Brokers.
+         *
+         * @param agent
+         *      The Discovery Agent to use in this transport.
+         */
+        void setDiscoveryAgent(decaf::lang::Pointer<DiscoveryAgent> agent);
+
+        /**
+         * Returns the currently configured Discovery Agent
+         *
+         * @returns the pointer to the currently configured agent or NULL if not set.
+         */
+        Pointer<DiscoveryAgent> getDiscoveryAgent() const;
+
+        /**
+         * Sets the properties that are used for configuration of discovered brokers.
+         *
+         * @param properties
+         *      The supplied properties to use to configure new services.
+         */
+        void setParameters(const decaf::util::Properties& properties);
+
+        /**
+         * Gets the currently set parameters that are applied to newly discovered services URIs.
+         *
+         * @returns the currently set Properties to apply to new service URIs.
+         */
+        decaf::util::Properties getParameters() const;
+
+    public:
+
+        virtual void onServiceAdd(const activemq::commands::DiscoveryEvent& event);
+
+        virtual void onServiceRemove(const activemq::commands::DiscoveryEvent& event);
+
+        virtual void transportInterrupted();
+
+        virtual void transportResumed();
+
+    protected:
+
+        virtual void doClose();
+
+    };
+
+}}}
+
+#endif /* _ACTIVEMQ_TRANSPORT_DISCOVERY_DISCOVERYTRANSPORT_H_ */

http://git-wip-us.apache.org/repos/asf/activemq-cpp/blob/ba624ea9/activemq-cpp/src/main/activemq/transport/discovery/DiscoveryTransportFactory.cpp
----------------------------------------------------------------------
diff --git a/activemq-cpp/src/main/activemq/transport/discovery/DiscoveryTransportFactory.cpp b/activemq-cpp/src/main/activemq/transport/discovery/DiscoveryTransportFactory.cpp
new file mode 100644
index 0000000..0006b59
--- /dev/null
+++ b/activemq-cpp/src/main/activemq/transport/discovery/DiscoveryTransportFactory.cpp
@@ -0,0 +1,104 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "DiscoveryTransportFactory.h"
+
+#include <activemq/transport/discovery/DiscoveryTransport.h>
+#include <activemq/transport/discovery/DiscoveryAgentFactory.h>
+#include <activemq/transport/discovery/DiscoveryAgentRegistry.h>
+#include <activemq/transport/failover/FailoverTransport.h>
+#include <activemq/transport/correlator/ResponseCorrelator.h>
+#include <activemq/util/CompositeData.h>
+#include <activemq/util/URISupport.h>
+#include <activemq/exceptions/ActiveMQException.h>
+
+#include <decaf/lang/Boolean.h>
+#include <decaf/lang/Integer.h>
+#include <decaf/lang/Long.h>
+
+using namespace decaf;
+using namespace decaf::util;
+using namespace decaf::lang;
+using namespace activemq;
+using namespace activemq::exceptions;
+using namespace activemq::util;
+using namespace activemq::transport;
+using namespace activemq::transport::discovery;
+using namespace activemq::transport::failover;
+using namespace activemq::transport::correlator;
+
+////////////////////////////////////////////////////////////////////////////////
+DiscoveryTransportFactory::~DiscoveryTransportFactory() {
+}
+
+///////////////////////////////////////////////////////////////////////////////
+Pointer<Transport> DiscoveryTransportFactory::create(const decaf::net::URI& location) {
+
+    try {
+
+        // Create the initial Transport, then wrap it in the normal Filters
+        Pointer<Transport> transport(doCreateTransport(location));
+
+        // Create the Transport for response correlator
+        transport.reset(new ResponseCorrelator(transport));
+
+        return transport;
+    }
+    AMQ_CATCH_RETHROW(ActiveMQException)
+    AMQ_CATCH_EXCEPTION_CONVERT(Exception, ActiveMQException)
+    AMQ_CATCHALL_THROW(ActiveMQException)
+}
+
+///////////////////////////////////////////////////////////////////////////////
+Pointer<Transport> DiscoveryTransportFactory::createComposite(const decaf::net::URI& location) {
+    try {
+        return doCreateTransport(location);
+    }
+    AMQ_CATCH_RETHROW(ActiveMQException)
+    AMQ_CATCH_EXCEPTION_CONVERT(Exception, ActiveMQException)
+    AMQ_CATCHALL_THROW(ActiveMQException)
+}
+
+///////////////////////////////////////////////////////////////////////////////
+Pointer<Transport> DiscoveryTransportFactory::doCreateTransport(const decaf::net::URI& location) {
+
+    try {
+        CompositeData composite = URISupport::parseComposite(location);
+
+        // TODO create using factory and pass in params.
+        Pointer<CompositeTransport> failover(new FailoverTransport());
+
+        Pointer<DiscoveryTransport> transport(new DiscoveryTransport(failover));
+
+        // TODO set all discovery options on the transport.
+
+        URI agentURI = composite.getComponents().get(0);
+
+        DiscoveryAgentFactory* agentFactory =
+            DiscoveryAgentRegistry::getInstance().findFactory(agentURI.getScheme());
+
+        // TODO error?
+
+        Pointer<DiscoveryAgent> agent = agentFactory->createAgent(agentURI);
+        transport->setDiscoveryAgent(agent);
+
+        return transport;
+    }
+    AMQ_CATCH_RETHROW(ActiveMQException)
+    AMQ_CATCH_EXCEPTION_CONVERT(Exception, ActiveMQException)
+    AMQ_CATCHALL_THROW(ActiveMQException)
+}

http://git-wip-us.apache.org/repos/asf/activemq-cpp/blob/ba624ea9/activemq-cpp/src/main/activemq/transport/discovery/DiscoveryTransportFactory.h
----------------------------------------------------------------------
diff --git a/activemq-cpp/src/main/activemq/transport/discovery/DiscoveryTransportFactory.h b/activemq-cpp/src/main/activemq/transport/discovery/DiscoveryTransportFactory.h
new file mode 100644
index 0000000..3faec6e
--- /dev/null
+++ b/activemq-cpp/src/main/activemq/transport/discovery/DiscoveryTransportFactory.h
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _ACTIVEMQ_TRANSPORT_DISCOVERY_DISCOVERYTRANSPORTFACTORY_H_
+#define _ACTIVEMQ_TRANSPORT_DISCOVERY_DISCOVERYTRANSPORTFACTORY_H_
+
+#include <activemq/util/Config.h>
+#include <activemq/transport/AbstractTransportFactory.h>
+#include <activemq/transport/Transport.h>
+#include <decaf/net/URI.h>
+#include <decaf/util/Properties.h>
+
+namespace activemq {
+namespace transport {
+namespace discovery {
+
+    /**
+     * Creates an instance of a DiscoveryTransport.
+     *
+     * @since 3.9
+     */
+    class AMQCPP_API DiscoveryTransportFactory : public AbstractTransportFactory {
+    public:
+
+        virtual ~DiscoveryTransportFactory();
+
+        virtual Pointer<Transport> create(const decaf::net::URI& location);
+
+        virtual Pointer<Transport> createComposite(const decaf::net::URI& location);
+
+    protected:
+
+        virtual Pointer<Transport> doCreateTransport(const decaf::net::URI& location);
+
+    };
+
+}}}
+
+#endif /* _ACTIVEMQ_TRANSPORT_DISCOVERY_DISCOVERYTRANSPORTFACTORY_H_ */

http://git-wip-us.apache.org/repos/asf/activemq-cpp/blob/ba624ea9/activemq-cpp/src/main/activemq/transport/failover/FailoverTransportFactory.cpp
----------------------------------------------------------------------
diff --git a/activemq-cpp/src/main/activemq/transport/failover/FailoverTransportFactory.cpp b/activemq-cpp/src/main/activemq/transport/failover/FailoverTransportFactory.cpp
index d6c7dba..3ae9434 100644
--- a/activemq-cpp/src/main/activemq/transport/failover/FailoverTransportFactory.cpp
+++ b/activemq-cpp/src/main/activemq/transport/failover/FailoverTransportFactory.cpp
@@ -25,7 +25,6 @@
 #include <decaf/lang/Boolean.h>
 #include <decaf/lang/Integer.h>
 #include <decaf/lang/Long.h>
-#include <memory>
 
 using namespace activemq;
 using namespace activemq::util;

http://git-wip-us.apache.org/repos/asf/activemq-cpp/blob/ba624ea9/activemq-cpp/src/main/activemq/transport/failover/FailoverTransportFactory.h
----------------------------------------------------------------------
diff --git a/activemq-cpp/src/main/activemq/transport/failover/FailoverTransportFactory.h b/activemq-cpp/src/main/activemq/transport/failover/FailoverTransportFactory.h
index 866bc4d..832af14 100644
--- a/activemq-cpp/src/main/activemq/transport/failover/FailoverTransportFactory.h
+++ b/activemq-cpp/src/main/activemq/transport/failover/FailoverTransportFactory.h
@@ -22,7 +22,6 @@
 
 #include <activemq/transport/AbstractTransportFactory.h>
 #include <activemq/transport/Transport.h>
-#include <activemq/exceptions/ActiveMQException.h>
 #include <activemq/wireformat/WireFormat.h>
 #include <decaf/net/URI.h>
 #include <decaf/util/Properties.h>
@@ -49,16 +48,6 @@ namespace failover {
 
     protected:
 
-        /**
-         * Creates a slimed down Transport instance which can be used in composite
-         * transport instances.
-         *
-         * @param location - URI location to connect to.
-         * @param properties - Properties to apply to the transport.
-         *
-         * @return Pointer to a new FailoverTransport instance.
-         * @throws ActiveMQexception if an error occurs
-         */
         virtual Pointer<Transport> doCreateComposite(const decaf::net::URI& location,
                                                      const decaf::util::Properties& properties);
 

http://git-wip-us.apache.org/repos/asf/activemq-cpp/blob/ba624ea9/activemq-cpp/src/main/activemq/transport/tcp/TcpTransportFactory.h
----------------------------------------------------------------------
diff --git a/activemq-cpp/src/main/activemq/transport/tcp/TcpTransportFactory.h b/activemq-cpp/src/main/activemq/transport/tcp/TcpTransportFactory.h
index d3dee17..1d35a14 100644
--- a/activemq-cpp/src/main/activemq/transport/tcp/TcpTransportFactory.h
+++ b/activemq-cpp/src/main/activemq/transport/tcp/TcpTransportFactory.h
@@ -20,11 +20,10 @@
 
 #include <activemq/util/Config.h>
 #include <activemq/transport/AbstractTransportFactory.h>
-#include <activemq/exceptions/ActiveMQException.h>
 
-namespace activemq{
-namespace transport{
-namespace tcp{
+namespace activemq {
+namespace transport {
+namespace tcp {
 
     using decaf::lang::Pointer;
 

http://git-wip-us.apache.org/repos/asf/activemq-cpp/blob/ba624ea9/activemq-cpp/src/main/activemq/util/ServiceStopper.cpp
----------------------------------------------------------------------
diff --git a/activemq-cpp/src/main/activemq/util/ServiceStopper.cpp b/activemq-cpp/src/main/activemq/util/ServiceStopper.cpp
index dcb935f..5fd2cab 100644
--- a/activemq-cpp/src/main/activemq/util/ServiceStopper.cpp
+++ b/activemq-cpp/src/main/activemq/util/ServiceStopper.cpp
@@ -27,28 +27,26 @@ using namespace decaf;
 using namespace decaf::lang;
 
 ////////////////////////////////////////////////////////////////////////////////
-ServiceStopper::ServiceStopper() : firstException(), hasException(false) {
-}
+ServiceStopper::ServiceStopper() : firstException(), hasException(false) {}
 
 ////////////////////////////////////////////////////////////////////////////////
-ServiceStopper::~ServiceStopper() {
-}
+ServiceStopper::~ServiceStopper() {}
 
 ////////////////////////////////////////////////////////////////////////////////
 void ServiceStopper::stop(Service* service) {
 
-    if(service == NULL) {
+    if (service == NULL) {
         return;
     }
 
     try {
         service->stop();
-    } catch(Exception& ex) {
+    } catch (Exception& ex) {
         this->onException(service, ex);
-    } catch(std::exception& stdex) {
+    } catch (std::exception& stdex) {
         ActiveMQException wrapper(__FILE__, __LINE__, stdex.what());
         this->onException(service, wrapper);
-    } catch(...) {
+    } catch (...) {
         ActiveMQException wrapper(__FILE__, __LINE__, "Caught Unknown Exception");
         this->onException(service, wrapper);
     }
@@ -56,14 +54,14 @@ void ServiceStopper::stop(Service* service) {
 
 ////////////////////////////////////////////////////////////////////////////////
 void ServiceStopper::throwFirstException() {
-    if(this->hasException) {
+    if (this->hasException) {
         throw this->firstException;
     }
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 void ServiceStopper::onException(Service* service AMQCPP_UNUSED, Exception& ex) {
-    if(!this->hasException) {
+    if (!this->hasException) {
         this->firstException = ex;
         this->hasException = true;
     }

http://git-wip-us.apache.org/repos/asf/activemq-cpp/blob/ba624ea9/activemq-cpp/src/main/activemq/util/Suspendable.cpp
----------------------------------------------------------------------
diff --git a/activemq-cpp/src/main/activemq/util/Suspendable.cpp b/activemq-cpp/src/main/activemq/util/Suspendable.cpp
new file mode 100644
index 0000000..11fc2d3
--- /dev/null
+++ b/activemq-cpp/src/main/activemq/util/Suspendable.cpp
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Suspendable.h"
+
+using namespace activemq;
+using namespace activemq::util;
+
+////////////////////////////////////////////////////////////////////////////////
+Suspendable::~Suspendable() {
+}
+

http://git-wip-us.apache.org/repos/asf/activemq-cpp/blob/ba624ea9/activemq-cpp/src/main/activemq/util/Suspendable.h
----------------------------------------------------------------------
diff --git a/activemq-cpp/src/main/activemq/util/Suspendable.h b/activemq-cpp/src/main/activemq/util/Suspendable.h
new file mode 100644
index 0000000..3a218ba
--- /dev/null
+++ b/activemq-cpp/src/main/activemq/util/Suspendable.h
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _ACTIVEMQ_UTIL_SUSPENDABLE_H_
+#define _ACTIVEMQ_UTIL_SUSPENDABLE_H_
+
+#include <activemq/util/Config.h>
+
+namespace activemq {
+namespace util {
+
+    /**
+     * Interface for any resouce that support a suspend / resume style of operation.
+     *
+     * @since 3.9.0
+     */
+    class AMQCPP_API Suspendable {
+    public:
+
+        virtual ~Suspendable();
+
+        /**
+         * Suspend the given resource, all activity within the resource should halt and
+         * enter a waiting state.  When a call to resume is made this resource should then
+         * resume normal operation.
+         *
+         * @throws Exception if an error occurs while the resource is being suspended.
+         */
+        virtual void suspend() = 0;
+
+        /**
+         * Resumes normal operation of this resource after it has been suspended.
+         *
+         * @throws Exception if an error occurs while the resource is being resumed.
+         */
+        virtual void resume() = 0;
+
+    };
+
+}}
+
+#endif /* _ACTIVEMQ_UTIL_SUSPENDABLE_H_ */

http://git-wip-us.apache.org/repos/asf/activemq-cpp/blob/ba624ea9/activemq-cpp/src/main/activemq/util/URISupport.cpp
----------------------------------------------------------------------
diff --git a/activemq-cpp/src/main/activemq/util/URISupport.cpp b/activemq-cpp/src/main/activemq/util/URISupport.cpp
index a2c7e87..5ca0bf8 100644
--- a/activemq-cpp/src/main/activemq/util/URISupport.cpp
+++ b/activemq-cpp/src/main/activemq/util/URISupport.cpp
@@ -35,6 +35,16 @@ using namespace decaf::lang;
 using namespace decaf::lang::exceptions;
 
 ////////////////////////////////////////////////////////////////////////////////
+bool URISupport::isCompositeURI(const URI& uri) {
+    std::string ssp = stripPrefix(uri.getRawSchemeSpecificPart(), "//");
+
+    if (ssp.find_first_of('(') == 0 && checkParenthesis(ssp)) {
+        return true;
+    }
+    return false;
+}
+
+////////////////////////////////////////////////////////////////////////////////
 void URISupport::parseURL(const std::string& URI, decaf::util::Properties& properties) {
 
     try {
@@ -348,3 +358,79 @@ std::string URISupport::stripPrefix(const std::string& value, const std::string&
 
     return value;
 }
+
+////////////////////////////////////////////////////////////////////////////////
+URI URISupport::stripScheme(const URI& uri) {
+    return URI(stripPrefix(uri.getSchemeSpecificPart(), "//"));
+}
+
+////////////////////////////////////////////////////////////////////////////////
+Properties URISupport::parseParameters(const URI& uri) {
+    if (!isCompositeURI(uri)) {
+        return uri.getQuery().empty() ? Properties() : parseQuery(stripPrefix(uri.getQuery(), "?"));
+    } else {
+        return URISupport::parseComposite(uri).getParameters();
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+URI URISupport::applyParameters(const URI& uri, const Properties& queryParameters) {
+    return applyParameters(uri, queryParameters, "");
+}
+
+////////////////////////////////////////////////////////////////////////////////
+URI URISupport::applyParameters(const URI& uri, const Properties& queryParameters, const std::string& optionPrefix) {
+    URI result;
+
+    if (!queryParameters.isEmpty()) {
+
+        std::string newQuery = uri.getRawQuery();
+
+        std::vector<std::string> keys = queryParameters.propertyNames();
+        std::vector<std::string>::iterator iter = keys.begin();
+
+        for (; iter != keys.end(); ++iter) {
+            std::string option = *iter;
+            if (option.find(optionPrefix) == 0) {
+                if (newQuery.length() != 0) {
+                    newQuery.append("&");
+                }
+
+                std::string newKey = option;
+                if (!optionPrefix.empty()) {
+                    newKey = option.substr(optionPrefix.length());
+                }
+
+                newQuery.append(newKey).append("=").append(queryParameters.getProperty(option));
+            }
+        }
+
+        result = createURIWithQuery(uri, newQuery);
+    }
+
+    return result;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+URI URISupport::createURIWithQuery(const URI& uri, const std::string& query) {
+    std::string schemeSpecificPart = uri.getRawSchemeSpecificPart();
+
+    // strip existing query if any
+    std::size_t questionMark = schemeSpecificPart.find_last_of("?");
+
+    // make sure question mark is not within parentheses
+    std::size_t lastParend = schemeSpecificPart.find_last_of(")");
+    if (lastParend != std::string::npos && questionMark < lastParend) {
+        questionMark = std::string::npos;
+    }
+
+    if (questionMark != std::string::npos) {
+        schemeSpecificPart = schemeSpecificPart.substr(0, questionMark);
+    }
+
+    if (!query.empty()) {
+        schemeSpecificPart += "?" + query;
+    }
+
+    return URI(uri.getScheme(), schemeSpecificPart, uri.getFragment());
+}

http://git-wip-us.apache.org/repos/asf/activemq-cpp/blob/ba624ea9/activemq-cpp/src/main/activemq/util/URISupport.h
----------------------------------------------------------------------
diff --git a/activemq-cpp/src/main/activemq/util/URISupport.h b/activemq-cpp/src/main/activemq/util/URISupport.h
index 5e607cb..d1ccf8f 100644
--- a/activemq-cpp/src/main/activemq/util/URISupport.h
+++ b/activemq-cpp/src/main/activemq/util/URISupport.h
@@ -31,6 +31,16 @@ namespace util {
     public:
 
         /**
+         * Examine a URI and determine if it is a Composite type or not.
+         *
+         * @param uri
+         *      The URI that is to be examined.
+         *
+         * @return true if the given URI is a Composite type.
+         */
+        static bool isCompositeURI(const decaf::net::URI& uri);
+
+        /**
          * Parses the properties out of the provided Broker URI and sets
          * them in the passed Properties Object.
          * @param URI a Broker URI to parse
@@ -90,7 +100,73 @@ namespace util {
          */
         static std::string createQueryString(const Properties& options);
 
-    private:
+        /**
+         * Given a URI parse and extract any URI query options and return them as a Key / Value mapping.
+         *
+         * This method differs from the {@link parseQuery} method in that it handles composite URI
+         * types and will extract the URI options from the outermost composite URI.
+         *
+         * @param uri
+         *      The URI whose query should be extracted and processed.
+         *
+         * @return A Mapping of the URI options.
+         *
+         * @throws URISyntaxException if the passed in URI contains invalid elements.
+         */
+        static decaf::util::Properties parseParameters(const decaf::net::URI& uri);
+
+        /**
+         * Given a Key / Value mapping create and append a URI query value that represents the
+         * mapped entries, return the newly updated URI that contains the value of the given URI
+         * and the appended query value.
+         *
+         * @param uri
+         *      The source URI that will have the Map entries appended as a URI query value.
+         * @param queryParameters
+         *      The Key / Value mapping that will be transformed into a URI query string.
+         *
+         * @return A new URI value that combines the given URI and the constructed query string.
+         *
+         * @throws URISyntaxException if an invalid URI is created during this operation.
+         */
+        static decaf::net::URI applyParameters(const decaf::net::URI& uri, const decaf::util::Properties& queryParameters);
+
+        /**
+         * Given a Key / Value mapping create and append a URI query value that represents the mapped
+         * entries, return the newly updated URI that contains the value of the given URI and the
+         * appended query value.  Each entry in the query string is prefixed by the supplied
+         * optionPrefix string.
+         *
+         * @param uri
+         *      The source URI that will have the Map entries appended as a URI query value.
+         * @param queryParameters
+         *      The Key / Value mapping that will be transformed into a URI query string.
+         * @param optionPrefix
+         *      A string value that when not null or empty is used to prefix each query option key.
+         *
+         * @return A new URI value that combines the given URI and the constructed query string.
+         *
+         * @throws URISyntaxException if an invalid URI is created during this operation.
+         */
+        static decaf::net::URI applyParameters(const decaf::net::URI& uri,
+                                               const decaf::util::Properties& queryParameters,
+                                               const std::string& optionPrefix);
+
+        /**
+         * Creates a URI with the given query, removing an previous query value from the given URI.
+         *
+         * @param uri
+         *      The source URI whose existing query is replaced with the newly supplied one.
+         * @param query
+         *      The new URI query string that should be appended to the given URI.
+         *
+         * @return a new URI that is a combination of the original URI and the given query string.
+         *
+         * @throws URISyntaxException
+         */
+        static decaf::net::URI createURIWithQuery(const decaf::net::URI& uri, const std::string& query);
+
+    public:  // Utility methods used by this class.
 
         /**
          * Perform a parse on the given composite URI, placing the results in the passed
@@ -113,6 +189,17 @@ namespace util {
         static decaf::util::LinkedList<std::string> splitComponents(const std::string& str);
 
         /**
+         * Strip a URI of its scheme element.
+         *
+         * @param uri
+         *      The URI whose scheme value should be stripped.
+         *
+         * @return The stripped URI value.
+         * @throws URISyntaxException
+         */
+        static decaf::net::URI stripScheme(const decaf::net::URI& uri);
+
+        /**
          * Given a string value and a prefix value, return a new string that has the prefix
          * removed if it was part of the passed in string, otherwise just return the passed
          * in string


Mime
View raw message