AMQ-517 - adding activemq-cpp project to support integration of c++ stomp and openwire projects.

git-svn-id: https://svn.apache.org/repos/asf/incubator/activemq/trunk@418749 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Nathan Christopher Mittler 2006-07-03 11:51:36 +00:00
parent 7a853a45bf
commit be47d4066c
339 changed files with 36125 additions and 0 deletions

142
activemq-cpp/makefile Normal file
View File

@ -0,0 +1,142 @@
SRCDIR = src
MAKESUPPORT_HOME = $(PWD)
OFILES = \
$(OUTDIR)/main/activemq/exceptions/ActiveMQException.o \
\
$(OUTDIR)/main/activemq/support/InitDirector.o \
\
$(OUTDIR)/main/activemq/transport/IOTransport.o \
$(OUTDIR)/main/activemq/transport/TcpTransport.o \
$(OUTDIR)/main/activemq/transport/ResponseCorrelator.o \
$(OUTDIR)/main/activemq/transport/TransportFactoryMap.o \
$(OUTDIR)/main/activemq/transport/IOTransportFactory.o \
$(OUTDIR)/main/activemq/transport/TcpTransportFactory.o \
\
$(OUTDIR)/main/activemq/connector/ConnectorFactoryMap.o \
\
$(OUTDIR)/main/activemq/connector/stomp/StompConnector.o \
$(OUTDIR)/main/activemq/connector/stomp/StompConnectorFactory.o \
$(OUTDIR)/main/activemq/connector/stomp/StompCommandReader.o \
$(OUTDIR)/main/activemq/connector/stomp/StompCommandWriter.o \
$(OUTDIR)/main/activemq/connector/stomp/StompSessionManager.o \
\
$(OUTDIR)/main/activemq/connector/stomp/commands/CommandConstants.o \
\
$(OUTDIR)/main/activemq/connector/stomp/marshal/Marshaler.o \
\
$(OUTDIR)/main/activemq/core/ActiveMQConnectionFactory.o \
$(OUTDIR)/main/activemq/core/ActiveMQConnection.o \
$(OUTDIR)/main/activemq/core/ActiveMQSession.o \
$(OUTDIR)/main/activemq/core/ActiveMQProducer.o \
$(OUTDIR)/main/activemq/core/ActiveMQConsumer.o \
$(OUTDIR)/main/activemq/core/ActiveMQTransaction.o \
\
$(OUTDIR)/main/activemq/io/EndianReader.o \
$(OUTDIR)/main/activemq/io/EndianWriter.o \
$(OUTDIR)/main/activemq/io/BufferedInputStream.o \
$(OUTDIR)/main/activemq/io/BufferedOutputStream.o \
$(OUTDIR)/main/activemq/io/ByteArrayInputStream.o \
$(OUTDIR)/main/activemq/io/ByteArrayOutputStream.o \
\
$(OUTDIR)/main/activemq/logger/SimpleLogger.o \
$(OUTDIR)/main/activemq/logger/LogWriter.o \
$(OUTDIR)/main/activemq/logger/LogManager.o \
$(OUTDIR)/main/activemq/logger/LoggerHierarchy.o \
\
$(OUTDIR)/main/activemq/network/ServerSocket.o \
$(OUTDIR)/main/activemq/network/TcpSocket.o \
$(OUTDIR)/main/activemq/network/BufferedSocket.o \
$(OUTDIR)/main/activemq/network/SocketFactory.o \
$(OUTDIR)/main/activemq/network/SocketInputStream.o \
$(OUTDIR)/main/activemq/network/SocketOutputStream.o\
\
$(OUTDIR)/main/activemq/util/Guid.o \
$(OUTDIR)/main/activemq/util/StringTokenizer.o \
\
$(OUTDIR)/main/activemq/concurrent/Thread.o \
$(OUTDIR)/main/activemq/concurrent/Mutex.o \
$(OUTDIR)/main/activemq/concurrent/ThreadPool.o \
$(OUTDIR)/main/activemq/concurrent/PooledThread.o
OTESTFILES = \
$(OUTDIR)/test/main.o \
\
$(OUTDIR)/test/activemq/core/ActiveMQConnectionFactoryTest.o \
$(OUTDIR)/test/activemq/core/ActiveMQConnectionTest.o \
$(OUTDIR)/test/activemq/core/ActiveMQSessionTest.o \
\
$(OUTDIR)/test/activemq/concurrent/MutexTest.o \
$(OUTDIR)/test/activemq/concurrent/ThreadPoolTest.o \
$(OUTDIR)/test/activemq/concurrent/ThreadTest.o \
\
$(OUTDIR)/test/activemq/connector/stomp/StompConnectorTest.o \
$(OUTDIR)/test/activemq/connector/stomp/StompFrameTest.o \
$(OUTDIR)/test/activemq/connector/stomp/StompCommandReaderTest.o \
$(OUTDIR)/test/activemq/connector/stomp/StompCommandWriterTest.o \
$(OUTDIR)/test/activemq/connector/stomp/StompSessionManagerTest.o \
\
$(OUTDIR)/test/activemq/connector/stomp/commands/CommandConstantsTest.o \
$(OUTDIR)/test/activemq/connector/stomp/commands/AbortCommandTest.o \
$(OUTDIR)/test/activemq/connector/stomp/commands/AckCommandTest.o \
$(OUTDIR)/test/activemq/connector/stomp/commands/BeginCommandTest.o \
$(OUTDIR)/test/activemq/connector/stomp/commands/CommitCommandTest.o \
$(OUTDIR)/test/activemq/connector/stomp/commands/ConnectCommandTest.o \
$(OUTDIR)/test/activemq/connector/stomp/commands/ConnectedCommandTest.o \
$(OUTDIR)/test/activemq/connector/stomp/commands/DisconnectCommandTest.o \
$(OUTDIR)/test/activemq/connector/stomp/commands/ErrorCommandTest.o \
$(OUTDIR)/test/activemq/connector/stomp/commands/ReceiptCommandTest.o \
$(OUTDIR)/test/activemq/connector/stomp/commands/SubscribeCommandTest.o \
$(OUTDIR)/test/activemq/connector/stomp/commands/UnsubscribeCommandTest.o \
$(OUTDIR)/test/activemq/connector/stomp/commands/MessageCommandTest.o \
$(OUTDIR)/test/activemq/connector/stomp/commands/BytesMessageCommandTest.o \
$(OUTDIR)/test/activemq/connector/stomp/commands/TextMessageCommandTest.o \
\
$(OUTDIR)/test/activemq/connector/stomp/marshal/MarshalerTest.o \
\
$(OUTDIR)/test/activemq/connector/ConnectorFactoryMapRegistrarTest.o \
$(OUTDIR)/test/activemq/connector/ConnectorFactoryMapTest.o \
\
$(OUTDIR)/test/activemq/exceptions/ActiveMQExceptionTest.o \
\
$(OUTDIR)/test/activemq/io/BufferedInputStreamTest.o \
$(OUTDIR)/test/activemq/io/BufferedOutputStreamTest.o \
$(OUTDIR)/test/activemq/io/ByteArrayInputStreamTest.o \
$(OUTDIR)/test/activemq/io/ByteArrayOutputStreamTest.o \
$(OUTDIR)/test/activemq/io/EndianReaderTest.o \
$(OUTDIR)/test/activemq/io/EndianWriterTest.o \
\
$(OUTDIR)/test/activemq/logger/LoggerTest.o \
\
$(OUTDIR)/test/activemq/network/SocketFactoryTest.o \
$(OUTDIR)/test/activemq/network/SocketTest.o \
\
$(OUTDIR)/test/activemq/transport/DummyTransportFactory.o \
$(OUTDIR)/test/activemq/transport/IOTransportTest.o \
$(OUTDIR)/test/activemq/transport/ResponseCorrelatorTest.o \
$(OUTDIR)/test/activemq/transport/TransportFactoryMapTest.o \
$(OUTDIR)/test/activemq/transport/TransportFactoryMapRegistrarTest.o \
\
$(OUTDIR)/test/activemq/util/GuidTest.o \
$(OUTDIR)/test/activemq/util/IntegerTest.o \
$(OUTDIR)/test/activemq/util/LongTest.o \
$(OUTDIR)/test/activemq/util/BooleanTest.o \
$(OUTDIR)/test/activemq/util/QueueTest.o \
$(OUTDIR)/test/activemq/util/StringTokenizerTest.o
OINTEGRATIONFILES = \
$(OUTDIR)/test-integration/main.o \
\
$(OUTDIR)/test-integration/integration/simple/SimpleTester.o \
$(OUTDIR)/test-integration/integration/transactional/TransactionTester.o \
$(OUTDIR)/test-integration/integration/common/AbstractTester.o \
$(OUTDIR)/test-integration/integration/common/IntegrationCommon.o
LIBFILE = $(OUTDIR)/activemq.a
TESTEXE = $(OUTDIR)/activemqTest
INTEGRATIONEXE = $(OUTDIR)/activemqIntegrationTests
DEFINES =
include $(MAKESUPPORT_HOME)/makefile.cfg

View File

@ -0,0 +1,18 @@
#
# Compiler specific configuration
#
OUTDIR = out
LIBRARY_NAME = activemq-cpp
LIBFILE = $(OUTDIR)/lib$(LIBRARY_NAME).a
#
# GCC/G++ debug for Linux
#
CC = g++ -frtti -g -pthread -DDEBUG -D_DEBUG -D_REENTRANT
LD = g++ -g -frtti -pthread
CCFLAGS = -Wall
LDFLAGS = -L$(OUTDIR) -l$(LIBRARY_NAME) -lcppunit -ldl -luuid
ARFLAGS =

View File

@ -0,0 +1,19 @@
#
# Compiler specific configuration
#
OUTDIR = out
LIBRARY_NAME = activemq-cpp
LIBFILE = $(OUTDIR)/lib$(LIBRARY_NAME).a
#
# GCC/G++ release for Linux
#
CC = g++ -frtti -pthread -O3 -DNDEBUG -D_REENTRANT
LD = g++ -frtti -pthread
CCFLAGS = -Wall
LDFLAGS = -L$(OUTDIR) -l$(LIBRARY_NAME) -lcppunit -ldl -luuid
OUTDIR = out
ARFLAGS =

View File

@ -0,0 +1,16 @@
#
# Compiler specific configuration
#
LIBFILE = $(OUTDIR)/libactivemq-cpp.a
#
# GCC/G++ debug for Linux
#
CC = g++ -fexceptions -frtti -O0 -g3 -DDEBUG -D_DEBUG -D_REENTRANT -D_WIN32 -DWINVER=0x0502 -DWIN32_LEAN_AND_MEAN
LD = g++ -g3 -frtti
CCFLAGS = -Wall
LDFLAGS = -L$(OUTDIR) -lactivemq -lcppunit -lws2_32 -lrpcrt4
OUTDIR = out
ARFLAGS =

View File

@ -0,0 +1,17 @@
#
# Compiler specific configuration
#
LIBFILE = $(OUTDIR)/libactivemq-cpp.a
#
# GCC/G++ release for Linux
#
CC = g++ -fexceptions -frtti -O3 -DNDEBUG -D_REENTRANT -D__WIN32 -DWIN32_LEAN_AND_MEAN
LD = g++ -frtti
CCFLAGS = -Wall
LDFLAGS = -L$(OUTDIR) -lactivemq -lcppunit -lws2_32 -lrpcrt4
OUTDIR = out
ARFLAGS =

179
activemq-cpp/makefile.cfg Normal file
View File

@ -0,0 +1,179 @@
CURRENT = $(PWD)
# --- select compiler for structure
# ----------------------------------------------------------
include $(MAKESUPPORT_HOME)/makefile-$(OSTYPE)-$(CONFIG).cfg
# --- set generic commmands
# ----------------------------------------------------------
MV = mv
RM = rm -f
RMR = rm -rf
CP = cp -p
LN = ln -s
LS = ls
CAT = cat
MD = mkdir
AR = ar -r
PURIFY = purify
ECHO = echo
TOUCH = touch
CD = cd
STRIP = strip
# --- set default targets and their handling procedures
# ----------------------------------------------------------
.SILENT:
.KEEP_STATE:
.SUFFIXES:
.SUFFIXES: .cpp .CC
.INIT:
$(ECHO) " -<>- Compiling "$(CURRENT)
.DONE:
$(ECHO) " -<>- Done"
.FAILED:
$(ECHO) " *** Compilation of $(CURRENT) Failed"
$(OUTDIR)/main/%.o: $(SRCDIR)/main/%.cpp
$(ECHO) " - "$(CC) "'"$<"'"
$(CC) -o $@ $(DEFINES) $(CCFLAGS) -I$(SRCDIR)/main \
$(LOCAL_INCLUDE) -c $<
$(OUTDIR)/test/%.o: $(SRCDIR)/test/%.cpp
$(ECHO) " - "$(CC) "'"$<"'"
$(CC) -o $@ $(DEFINES) $(CCFLAGS) -I$(SRCDIR)/main -I$(SRCDIR)/test \
$(LOCAL_INCLUDE) -c $<
$(OUTDIR)/test-integration/%.o: $(SRCDIR)/test-integration/%.cpp
$(ECHO) " - "$(CC) "'"$<"'"
$(CC) -o $@ $(DEFINES) $(CCFLAGS) -I$(SRCDIR)/main -I$(SRCDIR)/test-integration \
$(LOCAL_INCLUDE) -c $<
# --- set generic targets and their handling procedures
# ----------------------------------------------------------
lib: \
prepare \
$(OFILES) \
$(LIBFILE) \
done
test: \
prepare_test \
$(OTESTFILES) \
$(TESTEXE) \
done
integration: \
prepare_integration \
$(OINTEGRATIONFILES) \
$(INTEGRATIONEXE) \
done
all: lib test integration
default: all
$(LIBFILE): $(OFILES) $(DEPLIBS)
$(ECHO) " - Creating static library file "$@
$(AR) $(ARFLAGS) $@ $(OFILES)
$(TESTEXE): $(OTESTFILES)
$(LD) -o $@ $(OTESTFILES) $(LDFLAGS)
$(ECHO) 'Finished building target: $@'
$(INTEGRATIONEXE): $(OINTEGRATIONFILES)
$(LD) -o $@ $(OINTEGRATIONFILES) $(LDFLAGS)
$(ECHO) 'Finished building target: $@'
clean:
$(ECHO) " - Cleaning up local directory "$(CURRENT)
$(ECHO) " - Removing object files"
$(RM) $(OFILES)
$(ECHO) " - Removing file "$(LIBFILE)
$(RM) -rf $(OUTDIR)
$(RM) $(LIBFILE)
$(RM) *~ *%
$(RM) #*
$(RM) core
$(RM) a.out
prepare:
if test ! -d $(OUTDIR) ; \
then \
$(MD) $(OUTDIR); \
$(MD) $(OUTDIR)/main; \
$(MD) $(OUTDIR)/main/activemq; \
$(MD) $(OUTDIR)/main/activemq/exceptions; \
$(MD) $(OUTDIR)/main/activemq/commands; \
$(MD) $(OUTDIR)/main/activemq/connector; \
$(MD) $(OUTDIR)/main/activemq/connector/stomp; \
$(MD) $(OUTDIR)/main/activemq/connector/stomp/commands; \
$(MD) $(OUTDIR)/main/activemq/connector/stomp/marshal; \
$(MD) $(OUTDIR)/main/activemq/core; \
$(MD) $(OUTDIR)/main/activemq/io; \
$(MD) $(OUTDIR)/main/activemq/logger; \
$(MD) $(OUTDIR)/main/activemq/network; \
$(MD) $(OUTDIR)/main/activemq/util; \
$(MD) $(OUTDIR)/main/activemq/support; \
$(MD) $(OUTDIR)/main/activemq/concurrent; \
$(MD) $(OUTDIR)/main/activemq/transport; \
fi
prepare_test:
if test ! -d $(OUTDIR) ; \
then \
$(MD) $(OUTDIR); \
fi
if test ! -d $(OUTDIR)/test ; \
then \
$(MD) $(OUTDIR)/test; \
$(MD) $(OUTDIR)/test/activemq; \
$(MD) $(OUTDIR)/test/activemq/exceptions; \
$(MD) $(OUTDIR)/test/activemq/commands; \
$(MD) $(OUTDIR)/test/activemq/connector; \
$(MD) $(OUTDIR)/test/activemq/connector/stomp; \
$(MD) $(OUTDIR)/test/activemq/connector/stomp/commands; \
$(MD) $(OUTDIR)/test/activemq/connector/stomp/marshal; \
$(MD) $(OUTDIR)/test/activemq/core; \
$(MD) $(OUTDIR)/test/activemq/io; \
$(MD) $(OUTDIR)/test/activemq/logger; \
$(MD) $(OUTDIR)/test/activemq/network; \
$(MD) $(OUTDIR)/test/activemq/util; \
$(MD) $(OUTDIR)/test/activemq/concurrent; \
$(MD) $(OUTDIR)/test/activemq/transport; \
fi
prepare_integration:
if test ! -d $(OUTDIR) ; \
then \
$(MD) $(OUTDIR); \
fi
if test ! -d $(OUTDIR)/test-integration ; \
then \
$(MD) $(OUTDIR)/test-integration; \
$(MD) $(OUTDIR)/test-integration/integration; \
$(MD) $(OUTDIR)/test-integration/integration/common; \
$(MD) $(OUTDIR)/test-integration/integration/simple; \
$(MD) $(OUTDIR)/test-integration/integration/transactional; \
$(MD) $(OUTDIR)/test-integration/integration/durable; \
fi
done:
$(ECHO) "Done."

228
activemq-cpp/pom.xml Normal file
View File

@ -0,0 +1,228 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>activemq</groupId>
<name>ActiveMQ :: CPP :: Parent</name>
<artifactId>activemq-cpp-parent</artifactId>
<packaging>pom</packaging>
<!-- these should be deleted when using a parent pom-->
<version>1.0-SNAPSHOT</version>
<build>
<pluginManagement>
<plugins>
<plugin>
<!-- configure the Mojo native plugin -->
<groupId>org.codehaus.mojo</groupId>
<artifactId>native-maven-plugin</artifactId>
<version>1.0-alpha-1-SNAPSHOT</version>
<extensions>true</extensions>
<!-- Make child POMs inherit this configuration -->
<inherited>true</inherited>
<configuration>
<!-- All compiler flags are determined by the profile -->
<compilerProvider>${compiler.provider}</compilerProvider>
<envFactoryName>${env.factory.name}</envFactoryName>
<compilerStartOptions>
<compilerStartOption>${compiler.options}</compilerStartOption>
</compilerStartOptions>
<linkerExecutable>${linker.executable}</linkerExecutable>
<linkerStartOptions>
<linkerStartOption>${linker.options}</linkerStartOption>
</linkerStartOptions>
<!-- Define the sources for the library build -->
<sources>
<!-- Standard include directories -->
<source><directory>../src/main</directory></source>
<source><directory>../src/test</directory></source>
<source>
<directory>../src/main/activemq/concurrent</directory>
<fileNames>
<fileName>Mutex.cpp</fileName>
<fileName>PooledThread.cpp</fileName>
<fileName>Thread.cpp</fileName>
<fileName>ThreadPool.cpp</fileName>
</fileNames>
</source>
<source>
<directory>../src/main/activemq/connector</directory>
<fileNames>
<fileName>ConnectorFactoryMap.cpp</fileName>
</fileNames>
</source>
<source>
<directory>../src/main/activemq/connector/stomp</directory>
<fileNames>
<fileName>StompCommandReader.cpp</fileName>
<fileName>StompCommandWriter.cpp</fileName>
<fileName>StompConnector.cpp</fileName>
<fileName>StompConnectorFactory.cpp</fileName>
<fileName>StompSessionManager.cpp</fileName>
</fileNames>
</source>
<source>
<directory>../src/main/activemq/connector/stomp/commands</directory>
<fileNames>
<fileName>CommandConstants.cpp</fileName>
</fileNames>
</source>
<source>
<directory>../src/main/activemq/connector/stomp/marshal</directory>
<fileNames>
<fileName>Marshaler.cpp</fileName>
</fileNames>
</source>
<source>
<directory>../src/main/activemq/core</directory>
<fileNames>
<fileName>ActiveMQConnection.cpp</fileName>
<fileName>ActiveMQConnectionFactory.cpp</fileName>
<fileName>ActiveMQConsumer.cpp</fileName>
<fileName>ActiveMQProducer.cpp</fileName>
<fileName>ActiveMQSession.cpp</fileName>
<fileName>ActiveMQTransaction.cpp</fileName>
</fileNames>
</source>
<source>
<directory>../src/main/activemq/exceptions</directory>
<fileNames>
<fileName>ActiveMQException.cpp</fileName>
</fileNames>
</source>
<source>
<directory>../src/main/activemq/io</directory>
<fileNames>
<fileName>BufferedInputStream.cpp</fileName>
<fileName>BufferedOutputStream.cpp</fileName>
<fileName>ByteArrayInputStream.cpp</fileName>
<fileName>ByteArrayOutputStream.cpp</fileName>
<fileName>EndianReader.cpp</fileName>
<fileName>EndianWriter.cpp</fileName>
</fileNames>
</source>
<source>
<directory>../src/main/activemq/logger</directory>
<fileNames>
<fileName>Logger.cpp</fileName>
<fileName>LoggerHierarchy.cpp</fileName>
<fileName>LogManager.cpp</fileName>
<fileName>LogWriter.cpp</fileName>
<fileName>SimpleLogger.cpp</fileName>
</fileNames>
</source>
<source>
<directory>../src/main/activemq/network</directory>
<fileNames>
<fileName>BufferedSocket.cpp</fileName>
<fileName>ServerSocket.cpp</fileName>
<fileName>SocketFactory.cpp</fileName>
<fileName>SocketInputStream.cpp</fileName>
<fileName>SocketOutputStream.cpp</fileName>
<fileName>TcpSocket.cpp</fileName>
</fileNames>
</source>
<source>
<directory>../src/main/activemq/support</directory>
<fileNames>
<fileName>InitDirector.cpp</fileName>
</fileNames>
</source>
<source>
<directory>../src/main/activemq/transport</directory>
<fileNames>
<fileName>IOTransport.cpp</fileName>
<fileName>IOTransportFactory.cpp</fileName>
<fileName>ResponseCorrelator.cpp</fileName>
<fileName>TcpTransport.cpp</fileName>
<fileName>TcpTransportFactory.cpp</fileName>
<fileName>TransportFactoryMap.cpp</fileName>
</fileNames>
</source>
<source>
<directory>../src/main/activemq/util</directory>
<fileNames>
<fileName>Guid.cpp</fileName>
<fileName>StringTokenizer.cpp</fileName>
</fileNames>
</source>
</sources>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
<profiles>
<!-- Default profile for Windows: MSVC compiler -->
<profile>
<id>win32-msvc</id>
<activation>
<os>
<family>windows</family>
</os>
</activation>
<modules>
<module>win32-msvc</module>
</modules>
</profile>
<!-- Profile for building on windows (cygwin) with gcc -->
<profile>
<id>win32-gcc</id>
<modules>
<module>win32-gcc</module>
</modules>
</profile>
<!-- Profile for building on *nix with the default compiler -->
<profile>
<id>unix</id>
<activation>
<os>
<family>unix</family>
</os>
</activation>
<modules>
<module>unix</module>
</modules>
</profile>
</profiles>
<!-- Repos for using the mojo native plugin -->
<repositories>
<repository>
<id>Maven Snapshots</id>
<url>http://snapshots.maven.codehaus.org/maven2/</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
<releases>
<enabled>true</enabled>
</releases>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>Maven Snapshots</id>
<url>http://snapshots.maven.codehaus.org/maven2/</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
<releases>
<enabled>true</enabled>
</releases>
</pluginRepository>
</pluginRepositories>
</project>

109
activemq-cpp/readme.txt Normal file
View File

@ -0,0 +1,109 @@
--------------------------------------------------------------------------
ActiveMQ CPP Library - Version 0.0.1
--------------------------------------------------------------------------
This library provides a JMS like interface to an ActiveMQ broker in c++.
Currently the Library only supports the Stomp protocol, future versions
will contain support for openwire.
UNIT Tests
--------------------------------------------------------------------------
The package contains a complete set of cppunit tests. In order for you
to build an run the tests, you will need to download and install the
cppunit suite.
http://cppunit.sourceforge.net/cppunit-wiki
or on Fedora type
yum install cppunit*
Make sure that the path to the installed cpp unit library and includes is
visible in your current shell before you try building the tets.
Integration Tests
--------------------------------------------------------------------------
The library also contains a set of tests that are run against a real AMQ
broker. Running these without a broker will result in failed tests.
The tests currently hardcode the broker url to be tcp://127.0.0.1:61613,
you can change this by changing the declaration in IntegrationCommon.cpp
in the test-integration src tree.
Notes for Windows users
--------------------------------------------------------------------------
The builds support using the GNU compiler on Windows, we used the MinGW
package. There is an issues still outstanding with this in that the sockets
break for no reason when built this way. We therefore suggest that you
stick with using the MSVC compiler when on windows.
There are a couple or things that you will need to setup to ensure that the
MSVC compile succeeds.
* You need to download and install the Platform SDK if you don't have it
installed already.
* Ensure that the path to you MSVC install is set in the PATH env variable.
you can tests this buy typing cl.exe at the command line, if you get an
error complaining that its not found, then setup you PATH correctly.
* Set the INCLUDE env variable to include the path to your MSVC includes,
and the platform SDK includes.
i.e. INCLUDE = D:\Program Files\Microsoft Visual Studio 8\VC\include;D:\Program Files\Microsoft Platform SDK\Include
* Set the LIB env variable to include the path to your MSVC libs, and the
Platform SDK libs.
i.e. LIB = D:\Program Files\Microsoft Visual Studio 8\VC\lib;D:\Program Files\Microsoft Platform SDK\Lib
Maven Builds
--------------------------------------------------------------------------
The pacakge currently supports building the library only using maven.
The Mojo Native plugin (from the MOJO maven plugins site) is required.
http://mojo.codehaus.org/maven-native/native-maven-plugin/introduction.html
On the windows platform is was necessay to download the source for this
plugin and build it locally, this shouldn't be necessary on non-windows
platforms, but if you have problems, try that first.
You can get the latest source via subversion:
svn co https://svn.codehaus.org/mojo/trunk/mojo/maven-native
Once you have downloaded the source, install the plugin into your local
repository via: mvn install
Using Maven with activemq-cpp
* type mvn package
This will build the library using the default target for the platform
you are on, which is release, and the gnu compiler for unix platforms, or
the MSVC compiler on windows platforms.
Makefile Builds
--------------------------------------------------------------------------
The Makefile provided requires some env variable to be set
OSTYPE: This is the OS you are on and is reflected in the names of the
makefiles. Currently your choices are Linux or Windows, both use
the GNU compiler.
CONFIG: This is the build Mode you want to execute, i.e. debug or release.
MAKESUPPORT_HOME: Path to the folder where the Makefiles are stored.
There are three targets available in the Makefile, lib, test, and integration
whose output is fairly obvious.
Using the Makefile:
* type make to build all targets: lib, tests and integration
* type make < Target Name > to build only the target you need.
* type make clean to remove all of the object, library, and executable files.

View File

@ -0,0 +1,62 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#ifndef _ACTIVEMQ_CONCURRENT_CONCURRENT_H_
#define _ACTIVEMQ_CONCURRENT_CONCURRENT_H_
#include <activemq/concurrent/Lock.h>
namespace activemq{
namespace concurrent{
/**
* The synchronized macro defines a mechanism for snycronizing
* a scetion of code. The macro must be passed an object that
* implements the Syncronizable interface.
*
* The macro works by creating a for loop that will loop exactly
* once, creating a Lock object that is scoped to the loop. Once
* the loop conpletes and exits the Lock object goes out of scope
* releasing the lock on object W. For added safety the if else
* is used because not all compiles restrict the lifetime of
* loop variables to the loop, they will however restrict them
* to the scope of the else.
*
* The macro would be used as follows.
*
* <Syncronizable> X;
*
* somefunction()
* {
* syncronized(X)
* {
* // Do something that needs syncronizing.
* }
* }
*/
#define WAIT_INFINITE 0xFFFFFFFF
#define synchronized(W) \
if(false){} \
else \
for(activemq::concurrent::Lock lock_W(W); \
lock_W.isLocked(); lock_W.unlock())
}}
#endif /*_ACTIVEMQ_CONCURRENT_CONCURRENT_H_*/

View File

@ -0,0 +1,124 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#ifndef ACTIVEMQ_CONCURRENT_LOCK_H
#define ACTIVEMQ_CONCURRENT_LOCK_H
// Includes.
#include <activemq/concurrent/Synchronizable.h>
namespace activemq{
namespace concurrent{
/**
* A wrapper class around a given synchronization mechanism that
* provides automatic release upon destruction.
* @author Nathan Mittler
*/
class Lock
{
private: // Data
/**
* Flag to indicate whether or not this object has locked the
* sync object.
*/
bool locked;
/**
* The synchronizable object to lock/unlock.
*/
Synchronizable* syncObject;
public: // Interface
/**
* Constructor - initializes the object member and locks
* the object if desired.
* @param object The sync object to control
* @param intiallyLocked If true, the object will automatically
* be locked.
*/
Lock( Synchronizable* object, const bool intiallyLocked = true )
{
try{
syncObject = object;
locked = false;
if( intiallyLocked )
{
lock();
}
}
AMQ_CATCH_RETHROW( exceptions::ActiveMQException )
AMQ_CATCHALL_THROW( exceptions::ActiveMQException )
}
/**
* Destructor - Unlocks the object if it is locked.
*/
virtual ~Lock()
{
try{
if( locked )
{
syncObject->unlock();
}
}
AMQ_CATCH_RETHROW( exceptions::ActiveMQException )
AMQ_CATCHALL_THROW( exceptions::ActiveMQException )
}
/**
* Locks the object.
*/
void lock()
{
try{
syncObject->lock();
locked = true;
}
AMQ_CATCH_RETHROW( exceptions::ActiveMQException )
AMQ_CATCHALL_THROW( exceptions::ActiveMQException )
}
/**
* Unlocks the object.
*/
void unlock()
{
try{
if(locked)
{
syncObject->unlock();
locked = false;
}
}
AMQ_CATCH_RETHROW( exceptions::ActiveMQException )
AMQ_CATCHALL_THROW( exceptions::ActiveMQException )
}
/**
* Indicates whether or not the object is locked.
* @return true if the object is locked, otherwise false.
*/
bool isLocked() const{ return locked; }
};
}}
#endif // ACTIVEMQ_CONCURRENT_LOCK_H

View File

@ -0,0 +1,21 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#include <activemq/concurrent/Mutex.h>
using namespace activemq::concurrent;
////////////////////////////////////////////////////////////////////////////////

View File

@ -0,0 +1,358 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#ifndef ACTIVEMQ_CONCURRENT_MUTEX_H
#define ACTIVEMQ_CONCURRENT_MUTEX_H
// Includes.
#include <activemq/concurrent/Synchronizable.h>
#include <activemq/concurrent/Concurrent.h>
#include <activemq/concurrent/Thread.h>
#include <list>
#if (defined(__unix__) || defined(unix) || defined(MACOSX)) && !defined(USG)
#ifndef unix
#define unix
#endif
#include <pthread.h>
#include <sys/time.h>
#endif
#if defined(WIN32) || defined(__CYGWIN__) && !defined unix
#include <windows.h>
#if ( !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0400)
#if ( !defined(WINVER) || WINVER < 0x0400)
#pragma message ("Unsupported platform, Windows NT 4.0 or later required")
#endif
#endif
#endif
#include <assert.h>
namespace activemq{
namespace concurrent{
/**
* Creates a pthread_mutex_t object. The object is created
* such that successive locks from the same thread is allowed
* and will be successful.
* @see pthread_mutex_t
*/
class Mutex : public Synchronizable
{
private: // Data
/**
* The mutex object.
*/
#ifdef unix
pthread_mutex_t mutex;
std::list<pthread_cond_t*> eventQ;
#else
CRITICAL_SECTION mutex;
std::list<HANDLE> eventQ;
#endif
// Lock Status Members
int lock_count;
unsigned long lock_owner;
public:
/**
* Constructor - creates and initializes the mutex.
*/
Mutex()
{
#ifdef unix
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutex_init(&mutex, &attr);
pthread_mutexattr_destroy(&attr);
#else
InitializeCriticalSection(&mutex);
#endif
lock_owner = 0;
lock_count = 0;
}
/**
* Destructor - destroys the mutex object.
*/
virtual ~Mutex()
{
// Unlock the mutex.
unlock();
#ifdef unix
pthread_mutex_destroy(&mutex);
#else
DeleteCriticalSection(&mutex);
#endif
}
/**
* Locks the object.
*/
virtual void lock() throw( exceptions::ActiveMQException )
{
if(isLockOwner())
{
lock_count++;
}
else
{
#ifdef unix
pthread_mutex_lock(&mutex);
#else
EnterCriticalSection(&mutex);
#endif
lock_count = 1;
lock_owner = Thread::getId();
}
}
/**
* Unlocks the object.
*/
virtual void unlock() throw( exceptions::ActiveMQException )
{
if(lock_owner == 0)
{
return;
}
if(!isLockOwner())
{
throw exceptions::ActiveMQException(
__FILE__, __LINE__,
"Mutex::unlock - Failed, not Lock Owner!" );
}
lock_count--;
if(lock_count == 0)
{
lock_owner = 0;
#ifdef unix
pthread_mutex_unlock(&mutex);
#else
LeaveCriticalSection(&mutex);
#endif
}
}
/**
* Waits on a signal from this object, which is generated
* by a call to Notify.
*/
virtual void wait() throw( exceptions::ActiveMQException )
{
// Delegate to the timed version
wait( WAIT_INFINITE );
}
/**
* Waits on a signal from this object, which is generated
* by a call to Notify. Must have this object locked before
* calling. This wait will timeout after the specified time
* interval.
*/
virtual void wait( unsigned long millisecs )
throw( exceptions::ActiveMQException )
{
if(!isLockOwner())
{
throw exceptions::ActiveMQException(
__FILE__, __LINE__,
"Mutex::wait - Failed, not Lock Owner!");
}
// Save the current owner and Lock count as we are going to
// unlock and release for someone else to lock on potentially.
// When we come back and re-lock we want to restore to the
// state we were in before.
unsigned long lock_owner = this->lock_owner;
int lock_count = this->lock_count;
this->lock_count = 0;
this->lock_owner = 0;
#ifdef unix
// Create this threads wait event
pthread_cond_t waitEvent;
pthread_cond_init(&waitEvent, NULL);
// Store the event in the queue so that a notify can
// call it and wake up the thread.
eventQ.push_back(&waitEvent);
int returnValue = 0;
if(millisecs != WAIT_INFINITE)
{
timeval now = {};
gettimeofday(&now, NULL);
timespec wait = {};
wait.tv_sec = now.tv_sec + (millisecs / 1000);
wait.tv_nsec = (now.tv_usec * 1000) + ((millisecs % 1000) * 1000000);
if(wait.tv_nsec > 1000000000)
{
wait.tv_sec++;
wait.tv_nsec -= 1000000000;
}
returnValue = pthread_cond_timedwait(&waitEvent, &mutex, &wait);
}
else
{
returnValue = pthread_cond_wait(&waitEvent, &mutex);
}
// If the wait did not succeed for any reason, remove it
// from the queue.
if( returnValue != 0 ){
std::list<pthread_cond_t*>::iterator iter = eventQ.begin();
for( ; iter != eventQ.end(); ++iter ){
if( *iter == &waitEvent ){
eventQ.erase(iter);
break;
}
}
}
// Destroy our wait event now, the notify method will have removed it
// from the event queue.
pthread_cond_destroy(&waitEvent);
#else
// Create the event to wait on
HANDLE waitEvent = CreateEvent( NULL, false, false, NULL );
if(waitEvent == NULL)
{
throw exceptions::ActiveMQException(
__FILE__, __LINE__,
"Mutex::Mutex - Failed Creating Event." );
}
eventQ.push_back( waitEvent );
// Release the Lock
LeaveCriticalSection( &mutex );
// Wait for a signal
WaitForSingleObject( waitEvent, millisecs );
// Reaquire the Lock
EnterCriticalSection( &mutex );
// Clean up the event, the notif methods will have
// already poped it from the queue.
CloseHandle( waitEvent );
#endif
// restore the owner
this->lock_owner = lock_owner;
this->lock_count = lock_count;
}
/**
* Signals a waiter on this object that it can now wake
* up and continue.
*/
virtual void notify() throw( exceptions::ActiveMQException )
{
if( !isLockOwner() )
{
throw exceptions::ActiveMQException(
__FILE__, __LINE__,
"Mutex::Notify - Failed, not Lock Owner!" );
}
if( !eventQ.empty() )
{
#ifdef unix
pthread_cond_signal( eventQ.front() );
eventQ.pop_front();
#else
SetEvent( eventQ.front() );
eventQ.pop_front();
#endif
}
}
/**
* Signals the waiters on this object that it can now wake
* up and continue.
*/
virtual void notifyAll() throw( exceptions::ActiveMQException )
{
if(!isLockOwner())
{
throw exceptions::ActiveMQException(
__FILE__, __LINE__,
"Mutex::NotifyAll - Failed, not Lock Owner!" );
}
#ifdef unix
while(!eventQ.empty())
{
pthread_cond_signal( eventQ.front() );
eventQ.pop_front();
}
#else
while(!eventQ.empty())
{
SetEvent( eventQ.front() );
eventQ.pop_front();
}
#endif
}
private:
/**
* Check if the calling thread is the Lock Owner
*/
bool isLockOwner()
{
return lock_owner == Thread::getId();
}
};
}}
#endif // ACTIVEMQ_CONCURRENT_MUTEX_H

View File

@ -0,0 +1,161 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#include <activemq/concurrent/PooledThread.h>
#include <activemq/concurrent/ThreadPool.h>
#include <activemq/concurrent/TaskListener.h>
#include <activemq/exceptions/IllegalArgumentException.h>
#include <iostream>
using namespace activemq;
using namespace activemq::concurrent;
////////////////////////////////////////////////////////////////////////////////
LOGCMS_INITIALIZE(logger, PooledThread, "com.activemq.concurrent.PooledThread");
////////////////////////////////////////////////////////////////////////////////
PooledThread::PooledThread(ThreadPool* pool)
{
if(pool == NULL)
{
throw exceptions::IllegalArgumentException( __FILE__, __LINE__,
"PooledThread::PooledThread");
}
busy = false;
done = false;
listener = NULL;
// Store our Pool.
this->pool = pool;
}
////////////////////////////////////////////////////////////////////////////////
PooledThread::~PooledThread()
{
}
////////////////////////////////////////////////////////////////////////////////
void PooledThread::run(void)
{
ThreadPool::Task task;
try
{
while(!done)
{
//LOGCMS_DEBUG(logger, "PooledThread::run - Entering deQ");
// Blocks until there something to be done
task = pool->deQueueTask();
//LOGCMS_DEBUG(logger, "PooledThread::run - Exited deQ");
// Check if the Done Flag is set, in case it happened while we
// were waiting for a task
if(done)
{
break;
}
// If we got here and the runnable was null then something
// bad must have happened. Throw an Exception and bail.
if(!task.first)
{
throw exceptions::ActiveMQException( __FILE__, __LINE__,
"PooledThread::run - Retrieive NULL task from Pool.");
}
// Got some work to do, so set flag to busy
busy = true;
// Inform a listener that we are going to start
if(listener)
{
/*LOGCMS_DEBUG(logger,
"PooledThread::run - Inform Listener we are starting");*/
listener->onTaskStarted(this);
}
// Perform the work
task.first->run();
/*LOGCMS_DEBUG(logger,
"PooledThread::run - Inform Task Listener we are done");*/
// Notify the Task listener that we are done
task.second->onTaskComplete(task.first);
// Inform a listener that we are going to stop and wait
// for a new task
if(listener)
{
/*LOGCMS_DEBUG(logger,
"PooledThread::run - Inform Listener we are done");*/
listener->onTaskCompleted(this);
}
// Set flag to inactive, we will wait for work
busy = false;
}
}
catch(exceptions::ActiveMQException& ex)
{
ex.setMark( __FILE__, __LINE__ );
// Notify the Task owner
if(task.first && task.second)
{
task.second->onTaskException(task.first, ex);
}
busy = false;
// Notify the PooledThreadListener
if(listener)
{
listener->onTaskException(this, ex);
}
}
catch(...)
{
exceptions::ActiveMQException ex(
__FILE__, __LINE__,
"PooledThread::run - Caught Unknown Exception");
// Notify the Task owner
if(task.first && task.second)
{
task.second->onTaskException(task.first, ex);
}
busy = false;
// Notify the PooledThreadListener
if(listener)
{
listener->onTaskException(this, ex);
}
}
}
////////////////////////////////////////////////////////////////////////////////
void PooledThread::stop(void) throw ( cms::CMSException )
{
done = true;
}

View File

@ -0,0 +1,105 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#ifndef _ACTIVEMQ_CONCURRENT_POOLEDTHREAD_H_
#define _ACTIVEMQ_CONCURRENT_POOLEDTHREAD_H_
#include <activemq/concurrent/Thread.h>
#include <activemq/concurrent/Runnable.h>
#include <activemq/concurrent/PooledThreadListener.h>
#include <activemq/logger/LoggerDefines.h>
#include <cms/Stoppable.h>
#include <cms/CMSException.h>
namespace activemq{
namespace concurrent{
class ThreadPool;
class PooledThread : public Thread, public cms::Stoppable
{
private:
// Is this thread currently processing something
bool busy;
// Boolean flag indicating thread should stop
bool done;
// Listener for Task related events
PooledThreadListener* listener;
// The thread pool this Pooled Thread is Servicing
ThreadPool* pool;
// Logger Init
LOGCMS_DECLARE(logger);
public:
/**
* Constructor
*/
PooledThread(ThreadPool* pool);
/**
* Destructor
*/
virtual ~PooledThread(void);
/**
* Run Method for this object waits for something to be
* enqueued on the ThreadPool and then grabs it and calls
* its run method.
*/
virtual void run(void);
/**
* Stops the Thread, thread will complete its task if currently
* running one, and then die. Does not block.
*/
virtual void stop(void) throw ( cms::CMSException );
/**
* Checks to see if the thread is busy, if busy it means
* that this thread has taken a task from the ThreadPool's
* queue and is processing it.
*/
virtual bool isBusy(void) { return busy; }
/**
* Adds a listener to this <code>PooledThread</code> to be
* notified when this thread starts and completes a task.
*/
virtual void setPooledThreadListener(PooledThreadListener* listener)
{
this->listener = listener;
}
/**
* Removes a listener for this <code>PooledThread</code> to be
* notified when this thread starts and completes a task.
*/
virtual PooledThreadListener* getPooledThreadListener(void)
{
return this->listener;
}
};
}}
#endif /*_ACTIVEMQ_CONCURRENT_POOLEDTHREAD_H_*/

View File

@ -0,0 +1,66 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#ifndef _ACTIVEMQ_CONCURRENT_POOLEDTHREADLISTENER_H_
#define _ACTIVEMQ_CONCURRENT_POOLEDTHREADLISTENER_H_
#include <activemq/exceptions/ActiveMQException.h>
namespace activemq{
namespace concurrent{
//forward declare
class PooledThread;
class PooledThreadListener
{
public:
/**
* Destructor
*/
virtual ~PooledThreadListener(void) {}
/**
* Called by a pooled thread when it is about to begin
* executing a new task.
* @param Pointer to the Pooled Thread that is making this call
*/
virtual void onTaskStarted(PooledThread* thread) = 0;
/**
* Called by a pooled thread when it has completed a task
* and is going back to waiting for another task to run
* @param Pointer the the Pooled Thread that is making this call.
*/
virtual void onTaskCompleted(PooledThread* thread) = 0;
/**
* Called by a pooled thread when it has encountered an exception
* while running a user task, after receiving this notification
* the callee should assume that the PooledThread is now no longer
* running.
* @param Pointer to the Pooled Thread that is making this call
* @param The Exception that occured.
*/
virtual void onTaskException(PooledThread* thread,
exceptions::ActiveMQException& ex) = 0;
};
}}
#endif /*_ACTIVEMQ_CONCURRENT_POOLEDTHREADLISTENER_H_*/

View File

@ -0,0 +1,41 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#ifndef ACTIVEMQ_CONCURRENT_RUNNABLE_H_
#define ACTIVEMQ_CONCURRENT_RUNNABLE_H_
namespace activemq{
namespace concurrent{
/**
* Interface for a runnable object - defines a task
* that can be run by a thread.
*/
class Runnable{
public:
virtual ~Runnable(){}
/**
* Run method - called by the Thread class in the context
* of the thread.
*/
virtual void run() = 0;
};
}}
#endif /*ACTIVEMQ_CONCURRENT_RUNNABLE_H_*/

View File

@ -0,0 +1,87 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#ifndef ACTIVEMQ_CONCURRENT_SYNCHRONIZABLE_H
#define ACTIVEMQ_CONCURRENT_SYNCHRONIZABLE_H
#include <activemq/exceptions/ActiveMQException.h>
namespace activemq{
namespace concurrent{
/**
* The interface for all synchronizable objects (that is, objects
* that can be locked and unlocked).
*/
class Synchronizable
{
public: // Abstract Interface
virtual ~Synchronizable(){}
/**
* Locks the object.
* @throws ActiveMQException
*/
virtual void lock() throw(exceptions::ActiveMQException) = 0;
/**
* Unlocks the object.
* @throws ActiveMQException
*/
virtual void unlock() throw(exceptions::ActiveMQException) = 0;
/**
* Waits on a signal from this object, which is generated
* by a call to Notify. Must have this object locked before
* calling.
* @throws ActiveMQException
*/
virtual void wait() throw(exceptions::ActiveMQException) = 0;
/**
* Waits on a signal from this object, which is generated
* by a call to Notify. Must have this object locked before
* calling. This wait will timeout after the specified time
* interval.
* @param time in millisecsonds to wait, or WAIT_INIFINITE
* @throws ActiveMQException
*/
virtual void wait(unsigned long millisecs)
throw(exceptions::ActiveMQException) = 0;
/**
* Signals a waiter on this object that it can now wake
* up and continue. Must have this object locked before
* calling.
* @throws ActiveMQException
*/
virtual void notify() throw(exceptions::ActiveMQException) = 0;
/**
* Signals the waiters on this object that it can now wake
* up and continue. Must have this object locked before
* calling.
* @throws ActiveMQException
*/
virtual void notifyAll() throw(exceptions::ActiveMQException) = 0;
};
}}
#endif /*ACTIVEMQ_CONCURRENT_SYNCHRONIZABLE_H*/

View File

@ -0,0 +1,56 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#ifndef _ACTIVEMQ_CONCURRENT_TASKLISTENER_H_
#define _ACTIVEMQ_CONCURRENT_TASKLISTENER_H_
#include <activemq/concurrent/Runnable.h>
#include <activemq/exceptions/ActiveMQException.h>
namespace activemq{
namespace concurrent{
class TaskListener
{
public:
/**
* Destructor
*/
virtual ~TaskListener() {}
/**
* Called when a queued task has completed, the task that
* finished is passed along for user consumption
* @param Runnable Pointer to the task that finished
*/
virtual void onTaskComplete(Runnable* task) = 0;
/**
* Called when a queued task has thrown an exception while
* being run. The Callee should assume that this was an
* unrecoverable exeption and that this task is now defunct.
* @param Runnable Pointer to the task
* @param The ActiveMQException that was thrown.
*/
virtual void onTaskException(Runnable* task,
exceptions::ActiveMQException& ex) = 0;
};
}}
#endif /*_ACTIVEMQ_CONCURRENT_TASKLISTENER_H_*/

View File

@ -0,0 +1,173 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#include "Thread.h"
#include <errno.h>
#ifdef unix
#include <errno.h> // EINTR
extern int errno;
#else
#include <process.h> // _endthreadex
#endif
#include <activemq/exceptions/ActiveMQException.h>
using namespace activemq;
using namespace activemq::concurrent;
#ifdef unix
static struct ThreadStaticInitializer {
// Thread Attribute member
pthread_attr_t threadAttribute;
// Static Initializer:
ThreadStaticInitializer() {
pthread_attr_init (&threadAttribute);
pthread_attr_setdetachstate (&threadAttribute, PTHREAD_CREATE_JOINABLE);
}
} threadStaticInitializer;
#endif
////////////////////////////////////////////////////////////////////////////////
Thread::Thread()
{
task = this;
started = false;
joined = false;
}
////////////////////////////////////////////////////////////////////////////////
Thread::Thread( Runnable* task )
{
this->task = task;
started = false;
joined = false;
}
////////////////////////////////////////////////////////////////////////////////
Thread::~Thread()
{
}
////////////////////////////////////////////////////////////////////////////////
void Thread::start() throw ( exceptions::ActiveMQException )
{
if (this->started) {
throw exceptions::ActiveMQException( __FILE__, __LINE__,
"Thread already started");
}
#ifdef unix
pthread_attr_init (&attributes);
pthread_attr_setdetachstate (&attributes, PTHREAD_CREATE_JOINABLE);
int err = pthread_create (
&this->threadHandle,
&attributes,
runCallback,
this);
if (err != 0) {
throw exceptions::ActiveMQException( __FILE__, __LINE__,
"Coud not start thread");
}
#else
unsigned int threadId = 0;
this->threadHandle =
(HANDLE)_beginthreadex(NULL, 0, runCallback, this, 0, &threadId);
if (this->threadHandle == NULL) {
throw exceptions::ActiveMQException( __FILE__, __LINE__,
"Coud not start thread");
}
#endif
// Mark the thread as started.
started = true;
}
////////////////////////////////////////////////////////////////////////////////
void Thread::join() throw( exceptions::ActiveMQException )
{
if (!this->started) {
throw exceptions::ActiveMQException( __FILE__, __LINE__,
"Thread::join() called without having called Thread::start()");
}
if (!this->joined) {
#ifdef unix
pthread_join(this->threadHandle, NULL);
#else
WaitForSingleObject (this->threadHandle, INFINITE);
#endif
}
this->joined = true;
}
////////////////////////////////////////////////////////////////////////////////
void Thread::sleep(int millisecs)
{
#ifdef unix
struct timespec rec, rem;
rec.tv_sec = millisecs / 1000;
rec.tv_nsec = (millisecs % 1000) * 1000000;
while( nanosleep( &rec, &rem ) == -1 ){
if( errno != EINTR ){
break;
}
}
#else
Sleep (millisecs);
#endif
}
////////////////////////////////////////////////////////////////////////////////
unsigned long Thread::getId(void)
{
#ifdef unix
return (long)(pthread_self());
#else
return GetCurrentThreadId();
#endif
}
////////////////////////////////////////////////////////////////////////////////
#ifdef unix
void*
#else
unsigned int WINAPI
#endif
Thread::runCallback (void* param)
{
// Get the instance.
Thread* thread = (Thread*)param;
// Invoke run on the task.
thread->task->run();
#ifdef unix
return NULL;
#else
// Return 0 if no exception was threwn. Otherwise -1.
_endthreadex(0); // Needed when using threads and CRT in Windows. Otherwise memleak can appear.
return 0;
#endif
}

View File

@ -0,0 +1,131 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#ifndef ACTIVEMQ_CONCURRENT_THREAD_H
#define ACTIVEMQ_CONCURRENT_THREAD_H
#include <activemq/exceptions/ActiveMQException.h>
#include <activemq/concurrent/Runnable.h>
#include <stdexcept>
#include <assert.h>
#if (defined(__unix__) || defined(unix) || defined(MACOSX)) && !defined(USG)
#ifndef unix
#define unix
#endif
#include <pthread.h>
#else
#include <windows.h>
#endif
namespace activemq{
namespace concurrent{
/**
* Basic thread class - mimics the Java Thread. Derived classes may
* implement the run method, or this class can be used as is with
* a provided Runnable delegate.
*/
class Thread : public Runnable
{
private:
/**
* The task to be run by this thread, defaults to
* this thread object.
*/
Runnable* task;
#ifdef unix
pthread_attr_t attributes;
pthread_t threadHandle ;
#else
HANDLE threadHandle ;
#endif
/**
* Started state of this thread.
*/
bool started;
/**
* Indicates whether the thread has already been
* joined.
*/
bool joined;
public:
Thread();
Thread( Runnable* task );
virtual ~Thread();
/**
* Creates a system thread and starts it in a joinable mode.
* Upon creation, the
* run() method of either this object or the provided Runnable
* object will be invoked in the context of this thread.
* @exception runtime_error is thrown if the system could
* not start the thread.
*/
virtual void start() throw (exceptions::ActiveMQException);
/**
* Wait til the thread exits. This is when the run()
* method has returned or has thrown an exception.
* If an exception was thrown in the run() method,
* join() will return the thrown exception. Otherwise
* (if run() returned normally), join() will
* return NULL.
*/
virtual void join() throw (exceptions::ActiveMQException);
/**
* Default implementation of the run method - does nothing.
*/
virtual void run(){};
public:
/**
* Halts execution of the calling thread for a specified no of millisec.
*
* Note that this method is a static method that applies to the
* calling thread and not to the thread object.
*/
static void sleep(int millisecs);
/**
* Obtains the Thread Id of the current thread
* @return Thread Id
*/
static unsigned long getId(void);
private:
// Internal thread handling
#ifdef unix
static void* runCallback (void* param);
#else
static unsigned int WINAPI runCallback (void* param);
#endif
} ;
}}
#endif /*ACTIVEMQ_CONCURRENT_THREAD_H*/

View File

@ -0,0 +1,344 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#include <activemq/concurrent/ThreadPool.h>
#include <activemq/concurrent/Concurrent.h>
#include <activemq/exceptions/IllegalArgumentException.h>
#ifdef min
#undef min
#endif
#include <algorithm>
#include <iostream>
using namespace std;
using namespace activemq;
using namespace activemq::concurrent;
////////////////////////////////////////////////////////////////////////////////
LOGCMS_INITIALIZE(logger, ThreadPool, "com.activemq.concurrent.ThreadPool");
LOGCMS_INITIALIZE(marker, ThreadPool, "com.activemq.concurrent.ThreadPool.Marker");
////////////////////////////////////////////////////////////////////////////////
ThreadPool ThreadPool::instance;
////////////////////////////////////////////////////////////////////////////////
ThreadPool::ThreadPool(void)
{
maxThreads = DEFAULT_MAX_POOL_SIZE;
blockSize = DEFAULT_MAX_BLOCK_SIZE;
freeThreads = 0;
shutdown = false;
}
////////////////////////////////////////////////////////////////////////////////
ThreadPool::~ThreadPool(void)
{
try
{
std::vector<PooledThread*>::iterator itr = pool.begin();
// Stop all the threads
for(; itr != pool.end(); ++itr)
{
(*itr)->stop();
}
// Set the shutdown flag so that the DeQueue methods all quit
// when we interrupt them.
shutdown = true;
synchronized(&queue)
{
// Signal the Queue so that all waiters are notified
queue.notifyAll();
}
// Wait for everyone to die
for(itr = pool.begin(); itr != pool.end(); ++itr)
{
(*itr)->join();
}
}
AMQ_CATCH_RETHROW( exceptions::ActiveMQException )
AMQ_CATCHALL_THROW( exceptions::ActiveMQException )
}
////////////////////////////////////////////////////////////////////////////////
void ThreadPool::queueTask(ThreadPool::Task task)
throw ( exceptions::ActiveMQException )
{
try
{
if(!task.first || !task.second)
{
throw exceptions::IllegalArgumentException( __FILE__, __LINE__,
"ThreadPool::QueueTask - Invalid args for Task");
}
//LOGCMS_DEBUG(logger, "ThreadPool::QueueTask - syncing on queue");
synchronized(&queue)
{
//LOGCMS_DEBUG(logger, "ThreadPool::QueueTask - sync'd, synching pool");
// If there's nobody open to do work, then create some more
// threads to handle the work.
if(freeThreads == 0)
{
AllocateThreads(blockSize);
}
//LOGCMS_DEBUG(logger, "ThreadPool::QueueTask - pushing task");
// queue the new work.
queue.push(task);
//LOGCMS_DEBUG(logger, "ThreadPool::QueueTask - calling notify");
// Inform waiters that we put some work on the queue.
queue.notify();
}
}
AMQ_CATCH_RETHROW( exceptions::ActiveMQException )
AMQ_CATCHALL_THROW( exceptions::ActiveMQException )
}
////////////////////////////////////////////////////////////////////////////////
ThreadPool::Task ThreadPool::deQueueTask(void)
throw ( exceptions::ActiveMQException )
{
try
{
//LOGCMS_DEBUG(logger, "ThreadPool::DeQueueTask - syncing on queue");
synchronized(&queue)
{
/*LOGCMS_DEBUG(logger,
"ThreadPool::DeQueueTask - sync'd checking queue empty");*/
// Wait for work, wait in a while loop since another thread could
// be waiting for a lock and get the work before we get woken up
// from our wait.
while(queue.empty() && !shutdown)
{
//LOGCMS_DEBUG(logger, "ThreadPool::DeQueueTask - Q empty, waiting");
queue.wait();
//LOGCMS_DEBUG(logger, "ThreadPool::DeQueueTask - done waiting");
}
// Don't give more work if we are closing down
if(shutdown)
{
return Task();
}
// check size again.
if(queue.empty())
{
throw exceptions::ActiveMQException( __FILE__, __LINE__,
"ThreadPool::DeQueueUserWorkItem - Empty Taskn, not in shutdown.");
}
//LOGCMS_DEBUG(logger, "ThreadPool::DeQueueTask - popping task");
// not empty so get the new work to do
return queue.pop();
}
return Task();
}
AMQ_CATCH_RETHROW( exceptions::ActiveMQException )
AMQ_CATCHALL_THROW( exceptions::ActiveMQException )
}
////////////////////////////////////////////////////////////////////////////////
void ThreadPool::reserve(unsigned long size)
{
try{
synchronized(&poolLock)
{
if(size < pool.size() || pool.size() == maxThreads)
{
return;
}
// How many do we reserve
unsigned long allocCount = size - pool.size();
// Allocate the new Threads
AllocateThreads(allocCount);
}
}
AMQ_CATCH_RETHROW( exceptions::ActiveMQException )
AMQ_CATCHALL_THROW( exceptions::ActiveMQException )
}
////////////////////////////////////////////////////////////////////////////////
void ThreadPool::setMaxThreads(unsigned long maxThreads)
{
try
{
synchronized(&poolLock)
{
if(maxThreads == 0)
{
// Caller tried to do something stupid, ignore them.
return;
}
this->maxThreads = maxThreads;
}
}
AMQ_CATCH_RETHROW( exceptions::ActiveMQException )
AMQ_CATCHALL_THROW( exceptions::ActiveMQException )
}
////////////////////////////////////////////////////////////////////////////////
void ThreadPool::setBlockSize(unsigned long blockSize)
{
try
{
if(blockSize <= 0)
{
// User tried something dumb, protect them from themselves
return;
}
synchronized(&poolLock)
{
this->blockSize = blockSize;
}
}
AMQ_CATCH_RETHROW( exceptions::ActiveMQException )
AMQ_CATCHALL_THROW( exceptions::ActiveMQException )
}
////////////////////////////////////////////////////////////////////////////////
void ThreadPool::AllocateThreads(unsigned long count)
{
try
{
if(pool.size() >= maxThreads)
{
return;
}
synchronized(&poolLock)
{
// Take the min of alloc size of maxThreads since we don't
// want anybody sneaking eaxtra threads in, greedy bastards.
count = std::min(count, maxThreads - pool.size());
// Each time we create a thread we increment the free Threads
// counter, but before we call start so that the Thread doesn't
// get ahead of us.
for(unsigned long i = 0; i < count; ++i)
{
pool.push_back(new PooledThread(this));
pool.back()->setPooledThreadListener(this);
freeThreads++;
pool.back()->start();
}
}
}
AMQ_CATCH_RETHROW( exceptions::ActiveMQException )
AMQ_CATCHALL_THROW( exceptions::ActiveMQException )
}
////////////////////////////////////////////////////////////////////////////////
void ThreadPool::onTaskStarted(PooledThread* thread)
{
try
{
synchronized(&poolLock)
{
freeThreads--;
// Now that this callback has decremented the free threads coutner
// let check if there is any outstanding work to be done and no
// threads to handle it. This could happen if the QueueTask
// method was called successively without any of the PooledThreads
// having a chance to wake up and service the queue. This would
// cause the number of Task to exceed the number of free threads
// once the Threads got a chance to wake up and service the queue
if(freeThreads == 0 && !queue.empty())
{
// Allocate a new block of threads
AllocateThreads(blockSize);
}
}
//LOGCMS_DEBUG(logger, "ThreadPool::onTaskStarted:");
}
AMQ_CATCH_RETHROW( exceptions::ActiveMQException )
AMQ_CATCHALL_THROW( exceptions::ActiveMQException )
}
////////////////////////////////////////////////////////////////////////////////
void ThreadPool::onTaskCompleted(PooledThread* thread)
{
try
{
synchronized(&poolLock)
{
freeThreads++;
}
//LOGCMS_DEBUG(logger, "ThreadPool::onTaskCompleted: ");
}
AMQ_CATCH_RETHROW( exceptions::ActiveMQException )
AMQ_CATCHALL_THROW( exceptions::ActiveMQException )
}
////////////////////////////////////////////////////////////////////////////////
void ThreadPool::onTaskException(
PooledThread* thread,
exceptions::ActiveMQException& ex)
{
//LOGCMS_DEBUG(logger, "ThreadPool::onTaskException: ");
try
{
synchronized(&poolLock)
{
// Delete the thread that had the exception and start a new
// one to take its place.
freeThreads--;
std::vector<PooledThread*>::iterator itr =
std::find(pool.begin(), pool.end(), thread);
if(itr != pool.end())
{
pool.erase(itr);
}
// Bye-Bye Thread Object
delete thread;
// Now allocate a replacement
AllocateThreads(1);
}
}
AMQ_CATCH_RETHROW( exceptions::ActiveMQException )
AMQ_CATCHALL_THROW( exceptions::ActiveMQException )
}

View File

@ -0,0 +1,239 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#ifndef _ACTIVEMQ_CONCURRENT_THREADPOOL_H_
#define _ACTIVEMQ_CONCURRENT_THREADPOOL_H_
#include <activemq/concurrent/Runnable.h>
#include <activemq/concurrent/PooledThread.h>
#include <activemq/concurrent/PooledThreadListener.h>
#include <activemq/concurrent/TaskListener.h>
#include <activemq/concurrent/Mutex.h>
#include <activemq/util/Queue.h>
#include <activemq/logger/LoggerDefines.h>
#include <vector>
namespace activemq{
namespace concurrent{
/**
* Defines a Thread Pool object that implements the functionality
* of pooling threads to perform user tasks. The Thread Poll has
* max size that it will grow to. The thread pool allocates threads
* in blocks. When there are no waiting worker threads and a task
* is queued then a new batch is allocated. The user can specify
* the size of the blocks, otherwise a default value is used.
* <P>
* When the user queues a task they must also queue a listner to
* be notified when the task has completed, this provides the user
* with a mechanism to know when a task object can be freed.
* <P>
* To have the Thread Pool perform a task, the user enqueue's an
* object that implements the <code>Runnable</code> insterface and
* one of the worker threads will executing it in its thread context.
*/
class ThreadPool : public PooledThreadListener
{
public:
// Constants
static const size_t DEFAULT_MAX_POOL_SIZE = 10;
static const size_t DEFAULT_MAX_BLOCK_SIZE = 3;
// Types
typedef std::pair<Runnable*, TaskListener*> Task;
private:
// Vector of threads that this object has created for its pool.
std::vector< PooledThread* > pool;
// Queue of Task that are in need of completion
util::Queue<Task> queue;
// Max number of Threads this Pool can contian
unsigned long maxThreads;
// Max number of tasks that can be allocated at a time
unsigned long blockSize;
// boolean flag use to indocate that this object is shutting down.
bool shutdown;
// Count of threads that are currently free to perfom some work.
unsigned long freeThreads;
// Mutex for locking operations that affect the pool.
Mutex poolLock;
// Logger Init
LOGCMS_DECLARE(logger);
LOGCMS_DECLARE(marker);
private: // Statics
// The singleton instance of this class
static ThreadPool instance;
public:
/**
* Constructor
*/
ThreadPool(void);
/**
* Destructor
*/
virtual ~ThreadPool(void);
/**
* Queue a task to be completed by one of the Pooled Threads.
* tasks are serviced as soon as a <code>PooledThread</code>
* is available to run it.
* @param object that derives from Runnable
* @throws ActiveMQException
*/
virtual void queueTask(Task task)
throw ( exceptions::ActiveMQException );
/**
* DeQueue a task to be completed by one of the Pooled Threads.
* A caller of this method will block until there is something
* in the tasks queue, therefore care must be taken when calling
* this function. Normally clients of ThreadPool don't use
* this, only the <code>PooledThread</code> objects owned by
* this ThreadPool.
* @return object that derives from Runnable
* @throws ActiveMQException
*/
virtual Task deQueueTask(void)
throw ( exceptions::ActiveMQException );
/**
* Returns the current number of Threads in the Pool, this is
* how many there are now, not how many are active or the max
* number that might exist.
* @return integer number of threads in existance.
*/
virtual unsigned long getPoolSize(void) const { return pool.size(); }
/**
* Returns the current backlog of items in the tasks queue, this
* is how much work is still waiting to get done.
* @return number of outstanding tasks.
*/
virtual unsigned long getBacklog(void) const { return queue.size(); }
/**
* Ensures that there is at least the specified number of Threads
* allocated to the pool. If the size is greater than the MAX
* number of threads in the pool, then only MAX threads are
* reservved. If the size is smaller than the number of threads
* currently in the pool, than nothing is done.
* @param number of threads to reserve.
*/
virtual void reserve(unsigned long size);
/**
* Get the Max Number of Threads this Pool can contain
* @return max size
*/
virtual unsigned long getMaxThreads(void) const { return maxThreads; }
/**
* Sets the Max number of threads this pool can contian.
* if this value is smaller than the current size of the
* pool nothing is done.
*/
virtual void setMaxThreads(unsigned long maxThreads);
/**
* Gets the Max number of threads that can be allocated at a time
* when new threads are needed.
* @return max Thread Block Size
*/
virtual unsigned long getBlockSize(void) const { return blockSize; }
/**
* Sets the Max number of Threads that can be allocated at a time
* when the Thread Pool determines that more Threads are needed.
* @param Max Thread Block Size
*/
virtual void setBlockSize(unsigned long blockSize);
/**
* Returns the current number of available threads in the pool, threads
* that are performing a user task are considered unavailable. This value
* could change immeadiately after calling as Threads could finish right
* after and be available again. This is informational only.
* @return totoal free threads
*/
virtual unsigned long getFreeThreadCount(void) const { return freeThreads; }
public: // PooledThreadListener Callbacks
/**
* Called by a pooled thread when it is about to begin
* executing a new task. This will decrement the available
* threads counter so that this object knows when there are
* no more free threads and must create new ones.
* @param Pointer to the Pooled Thread that is making this call
*/
virtual void onTaskStarted(PooledThread* thread);
/**
* Called by a pooled thread when it has completed a task
* and is going back to waiting for another task to run,
* this will increment the free threads counter.
* @param Pointer the the Pooled Thread that is making this call.
*/
virtual void onTaskCompleted(PooledThread* thread);
/**
* Called by a pooled thread when it has encountered an exception
* while running a user task, after receiving this notification
* the callee should assume that the PooledThread is now no longer
* running.
* @param Pointer to the Pooled Thread that is making this call
* @param The Exception that occured.
*/
virtual void onTaskException(PooledThread* thread,
exceptions::ActiveMQException& ex);
public: // Statics
/**
* Return the one and only Thread Pool instance.
* @return The Thread Pool Pointer
*/
static ThreadPool* getInstance(void) { return &instance; }
private:
/**
* Allocates the requested ammount of Threads, won't exceed
* <code>maxThreads</code>.
* @param the number of threads to create
*/
void AllocateThreads(unsigned long count);
};
}}
#endif /*_ACTIVEMQ_CONCURRENT_THREADPOOL_H_*/

View File

@ -0,0 +1,317 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#ifndef _ACTIVEMQ_CONNECTOR_CONNECTOR_H_
#define _ACTIVEMQ_CONNECTOR_CONNECTOR_H_
#include <list>
#include <cms/Startable.h>
#include <cms/Closeable.h>
#include <cms/MessageListener.h>
#include <cms/ExceptionListener.h>
#include <cms/Topic.h>
#include <cms/Queue.h>
#include <cms/TemporaryTopic.h>
#include <cms/TemporaryQueue.h>
#include <cms/Session.h>
#include <cms/BytesMessage.h>
#include <cms/TextMessage.h>
#include <cms/MapMessage.h>
#include <activemq/exceptions/InvalidStateException.h>
#include <activemq/transport/Transport.h>
#include <activemq/connector/SessionInfo.h>
#include <activemq/connector/ConsumerInfo.h>
#include <activemq/connector/ProducerInfo.h>
#include <activemq/connector/TransactionInfo.h>
#include <activemq/connector/ConsumerMessageListener.h>
#include <activemq/connector/ConnectorException.h>
namespace activemq{
namespace connector{
// Forward declarations.
class Connector
:
public cms::Startable,
public cms::Closeable
{
public: // Connector Types
enum AckType
{
DeliveredAck = 0, // Message delivered but not consumed
PoisonAck = 1, // Message could not be processed due to
// poison pill but discard anyway
ConsumedAck = 2 // Message consumed, discard
};
public:
virtual ~Connector(void) {};
/**
* Gets the Client Id for this connection, if this
* connection has been closed, then this method returns ""
* @return Client Id String
*/
virtual std::string getClientId(void) const = 0;
/**
* Gets a reference to the Transport that this connection
* is using.
* @param reference to a transport
* @throws InvalidStateException if the Transport is not set
*/
virtual transport::Transport& getTransport(void) const
throw (exceptions::InvalidStateException ) = 0;
/**
* Creates a Session Info object for this connector
* @param Acknowledgement Mode of the Session
* @returns Session Info Object
* @throws ConnectorException
*/
virtual SessionInfo* createSession(
cms::Session::AcknowledgeMode ackMode)
throw( ConnectorException ) = 0;
/**
* Create a Consumer for the given Session
* @param Destination to Subscribe to.
* @param Session Information.
* @return Consumer Information
* @throws ConnectorException
*/
virtual ConsumerInfo* createConsumer(
cms::Destination* destination,
SessionInfo* session,
const std::string& selector = "")
throw ( ConnectorException ) = 0;
/**
* Create a Durable Consumer for the given Session
* @param Topic to Subscribe to.
* @param Session Information.
* @param name of the Durable Topic
* @param Selector
* @param if set, inhibits the delivery of messages
* published by its own connection
* @return Consumer Information
* @throws ConnectorException
*/
virtual ConsumerInfo* createDurableConsumer(
cms::Topic* topic,
SessionInfo* session,
const std::string& name,
const std::string& selector = "",
bool noLocal = false)
throw ( ConnectorException ) = 0;
/**
* Create a Consumer for the given Session
* @param Destination to Subscribe to.
* @param Session Information.
* @return Producer Information
* @throws ConnectorException
*/
virtual ProducerInfo* createProducer(
cms::Destination* destination,
SessionInfo* session)
throw ( ConnectorException ) = 0;
/**
* Creates a Topic given a name and session info
* @param Topic Name
* @param Session Information
* @return a newly created Topic Object
* @throws ConnectorException
*/
virtual cms::Topic* createTopic(const std::string& name,
SessionInfo* session)
throw ( ConnectorException ) = 0;
/**
* Creates a Queue given a name and session info
* @param Queue Name
* @param Session Information
* @return a newly created Queue Object
* @throws ConnectorException
*/
virtual cms::Queue* createQueue(const std::string& name,
SessionInfo* session)
throw ( ConnectorException ) = 0;
/**
* Creates a Temporary Topic given a name and session info
* @param Temporary Topic Name
* @param Session Information
* @return a newly created Temporary Topic Object
* @throws ConnectorException
*/
virtual cms::TemporaryTopic* createTemporaryTopic(
SessionInfo* session)
throw ( ConnectorException ) = 0;
/**
* Creates a Temporary Queue given a name and session info
* @param Temporary Queue Name
* @param Session Information
* @return a newly created Temporary Queue Object
* @throws ConnectorException
*/
virtual cms::TemporaryQueue* createTemporaryQueue(
SessionInfo* session)
throw ( ConnectorException ) = 0;
/**
* Sends a Message
* @param The Message to send.
* @param Producer Info for the sender of this message
* @throws ConnectorException
*/
virtual void send(cms::Message* message, ProducerInfo* producerInfo)
throw ( ConnectorException ) = 0;
/**
* Sends a set of Messages
* @param List of Messages to send.
* @param Producer Info for the sender of this message
* @throws ConnectorException
*/
virtual void send(std::list<cms::Message*>& messages,
ProducerInfo* producerInfo)
throw ( ConnectorException ) = 0;
/**
* Acknowledges a Message
* @param An ActiveMQMessage to Ack.
* @throws ConnectorException
*/
virtual void acknowledge(const SessionInfo* session,
const cms::Message* message,
AckType ackType = ConsumedAck)
throw ( ConnectorException ) = 0;
/**
* Starts a new Transaction.
* @param Session Information
* @throws ConnectorException
*/
virtual TransactionInfo* startTransaction(
SessionInfo* session)
throw ( ConnectorException ) = 0;
/**
* Commits a Transaction.
* @param The Transaction information
* @param Session Information
* @throws ConnectorException
*/
virtual void commit(TransactionInfo* transaction,
SessionInfo* session)
throw ( ConnectorException ) = 0;
/**
* Rolls back a Transaction.
* @param The Transaction information
* @param Session Information
* @throws ConnectorException
*/
virtual void rollback(TransactionInfo* transaction,
SessionInfo* session)
throw ( ConnectorException ) = 0;
/**
* Creates a new Message.
* @param Session Information
* @param Transaction Info for this Message
* @throws ConnectorException
*/
virtual cms::Message* createMessage(
SessionInfo* session,
TransactionInfo* transaction)
throw ( ConnectorException ) = 0;
/**
* Creates a new BytesMessage.
* @param Session Information
* @param Transaction Info for this Message
* @throws ConnectorException
*/
virtual cms::BytesMessage* createBytesMessage(
SessionInfo* session,
TransactionInfo* transaction)
throw ( ConnectorException ) = 0;
/**
* Creates a new TextMessage.
* @param Session Information
* @param Transaction Info for this Message
* @throws ConnectorException
*/
virtual cms::TextMessage* createTextMessage(
SessionInfo* session,
TransactionInfo* transaction)
throw ( ConnectorException ) = 0;
/**
* Creates a new MapMessage.
* @param Session Information
* @param Transaction Info for this Message
* @throws ConnectorException
*/
virtual cms::MapMessage* createMapMessage(
SessionInfo* session,
TransactionInfo* transaction)
throw ( ConnectorException ) = 0;
/**
* Unsubscribe from a givenDurable Subscription
* @param name of the Subscription
* @throws ConnectorException
*/
virtual void unsubscribe(const std::string& name)
throw ( ConnectorException ) = 0;
/**
* Destroys the given connector resource.
* @param resource the resource to be destroyed.
* @throws ConnectorException
*/
virtual void destroyResource( ConnectorResource* resource )
throw ( ConnectorException ) = 0;
/**
* Sets the listener of consumer messages.
* @param listener the observer.
*/
virtual void setConsumerMessageListener(
ConsumerMessageListener* listener) = 0;
/**
* Sets the Listner of exceptions for this connector
* @param ExceptionListener the observer.
*/
virtual void setExceptionListener(
cms::ExceptionListener* listener) = 0;
};
}}
#endif /*_ACTIVEMQ_CONNECTOR_CONNECTOR_H_*/

View File

@ -0,0 +1,64 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#ifndef CONNECTOREXCEPTION_H_
#define CONNECTOREXCEPTION_H_
#include <activemq/exceptions/ActiveMQException.h>
namespace activemq{
namespace connector{
/*
* Signals that an Connector exception of some sort has occurred.
*/
class ConnectorException : public exceptions::ActiveMQException
{
public:
ConnectorException() {}
ConnectorException( const exceptions::ActiveMQException& ex ){
*(ActiveMQException*)this = ex;
}
ConnectorException( const ConnectorException& ex ){
*(exceptions::ActiveMQException*)this = ex;
}
ConnectorException(const char* file, const int lineNumber,
const char* msg, ...)
{
va_list vargs ;
va_start(vargs, msg) ;
buildMessage(msg, vargs) ;
// Set the first mark for this exception.
setMark( file, lineNumber );
}
/**
* Clones this exception. This is useful for cases where you need
* to preserve the type of the original exception as well as the message.
* All subclasses should override.
*/
virtual exceptions::ActiveMQException* clone() const{
return new ConnectorException( *this );
}
virtual ~ConnectorException() {}
};
}}
#endif /*CONNECTOREXCEPTION_H_*/

View File

@ -0,0 +1,48 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#ifndef CONNECTORFACTORY_H_
#define CONNECTORFACTORY_H_
#include <activemq/util/Properties.h>
#include <activemq/transport/Transport.h>
#include <activemq/connector/Connector.h>
namespace activemq{
namespace connector{
/**
* Interface class for all Connector Factory Classes
*/
class ConnectorFactory
{
public:
virtual ~ConnectorFactory(void) {};
/**
* Creates a connector
* @param The Properties that the new connector is configured with
*/
virtual Connector* createConnector(
const activemq::util::Properties& properties,
activemq::transport::Transport* transport) = 0;
};
}}
#endif /*CONNECTORFACTORY_H_*/

View File

@ -0,0 +1,74 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#include <activemq/connector/ConnectorFactoryMap.h>
using namespace activemq;
using namespace activemq::connector;
////////////////////////////////////////////////////////////////////////////////
ConnectorFactoryMap* ConnectorFactoryMap::getInstance(void)
{
// Static instance of this Map, create here so that one will
// always exist, the one and only Connector Map.
static ConnectorFactoryMap instance;
return &instance;
}
////////////////////////////////////////////////////////////////////////////////
void ConnectorFactoryMap::registerConnectorFactory(const std::string& name,
ConnectorFactory* factory)
{
factoryMap[name] = factory;
}
////////////////////////////////////////////////////////////////////////////////
void ConnectorFactoryMap::unregisterConnectorFactory(const std::string& name)
{
factoryMap.erase(name);
}
////////////////////////////////////////////////////////////////////////////////
ConnectorFactory* ConnectorFactoryMap::lookup(const std::string& name)
{
std::map<std::string, ConnectorFactory*>::const_iterator itr =
factoryMap.find(name);
if(itr != factoryMap.end())
{
return itr->second;
}
// Didn't find it, return nothing, not a single thing.
return NULL;
}
////////////////////////////////////////////////////////////////////////////////
std::size_t ConnectorFactoryMap::getFactoryNames(
std::vector<std::string>& factoryList)
{
std::map<std::string, ConnectorFactory*>::const_iterator itr =
factoryMap.begin();
for(; itr != factoryMap.end(); ++itr)
{
factoryList.insert(factoryList.end(), itr->first);
}
return factoryMap.size();
}

View File

@ -0,0 +1,93 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#ifndef CONNECTORFACTORYMAP_H_
#define CONNECTORFACTORYMAP_H_
#include <map>
#include <vector>
#include <string>
#include <activemq/exceptions/ActiveMQException.h>
#include <activemq/connector/ConnectorFactory.h>
namespace activemq{
namespace connector{
/**
* Lookup Map for Connector Factories. Use the Connector name to
* find the associated factory. This class does not take ownership
* of the stored factories, they must be deallocated somewhere.
*/
class ConnectorFactoryMap
{
public:
/**
* Gets a singleton instance of this class.
*/
static ConnectorFactoryMap* getInstance(void);
/**
* Registers a new Connector Factory with this map
* @param name to associate the factory with
* @param factory to store.
*/
void registerConnectorFactory(const std::string& name,
ConnectorFactory* factory);
/**
* Unregisters a Connector Factory with this map
* @param name of the factory to remove
*/
void unregisterConnectorFactory(const std::string& name);
/**
* Lookup the named factory in the Map
* @param the factory name to lookup
* @return the factory assciated with the name, or NULL
*/
ConnectorFactory* lookup(const std::string& name);
/**
* Fetch a list of factory names that this Map contains
* @param vector object to receive the list
* @returns count of factories.
*/
std::size_t getFactoryNames(std::vector<std::string>& factoryList);
private:
// Hidden Contrustor, prevents instantiation
ConnectorFactoryMap() {};
// Hidden Destructor.
virtual ~ConnectorFactoryMap() {};
// Hidden Copy Constructore
ConnectorFactoryMap(const ConnectorFactoryMap& factoryMap);
// Hidden Assignment operator
ConnectorFactoryMap operator=(const ConnectorFactoryMap& factoryMap);
// Map of Factories
std::map<std::string, ConnectorFactory*> factoryMap;
};
}}
#endif /*CONNECTORFACTORYMAP_H_*/

View File

@ -0,0 +1,90 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#ifndef CONNECTORFACTORYMAPREGISTRAR_H_
#define CONNECTORFACTORYMAPREGISTRAR_H_
#include <string>
#include <activemq/connector/ConnectorFactoryMap.h>
namespace activemq{
namespace connector{
/**
* Registers the passed in factory into the factory map, this class
* can manage the lifetime of the registered factory (default behaviour).
*/
class ConnectorFactoryMapRegistrar
{
public:
/**
* Constructor for this class
* @param name of the factory to register
* @param the factory
* @param boolean indicating if this object manages the lifetime of
* the factory that is being registered.
*/
ConnectorFactoryMapRegistrar( const std::string& name,
ConnectorFactory* factory,
bool manageLifetime = true )
{
// Register it in the map.
ConnectorFactoryMap::getInstance()->
registerConnectorFactory(name, factory);
// Store for later deletion
this->factory = factory;
this->manageLifetime = manageLifetime;
this->name = name;
}
virtual ~ConnectorFactoryMapRegistrar(void)
{
try
{
// UnRegister it in the map.
ConnectorFactoryMap::getInstance()->
unregisterConnectorFactory(name);
if(manageLifetime)
{
delete factory;
}
}
catch(...) {}
}
/**
* get a reference to the factory that this class is holding
* @return reference to a factory class
*/
virtual ConnectorFactory& getFactory(void) {
return *factory;
}
private:
std::string name;
ConnectorFactory* factory;
bool manageLifetime;
};
}}
#endif /*CONNECTORFACTORYMAPREGISTRAR_H_*/

View File

@ -0,0 +1,25 @@
#ifndef ACTIVEMQ_CONNECTOR_CONNECTORRESOURCE_H_
#define ACTIVEMQ_CONNECTOR_CONNECTORRESOURCE_H_
namespace activemq{
namespace connector{
/**
* An object who's lifetime is determined by
* the connector that created it. All ConnectorResources
* should be given back to the connector rather than
* deleting explicitly.
*/
class ConnectorResource
{
public:
/**
* Destructor
*/
virtual ~ConnectorResource() {}
};
}}
#endif /*ACTIVEMQ_CONNECTOR_CONNECTORRESOURCE_H_*/

View File

@ -0,0 +1,89 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#ifndef _ACTIVEMQ_CONNECTOR_CONSUMERINFO_H_
#define _ACTIVEMQ_CONNECTOR_CONSUMERINFO_H_
#include <activemq/connector/ConnectorResource.h>
#include <activemq/connector/SessionInfo.h>
#include <cms/Destination.h>
#include <string>
namespace activemq{
namespace connector{
class ConsumerInfo : public ConnectorResource
{
public:
/**
* Destructor
*/
virtual ~ConsumerInfo(void) {}
/**
* Gets this message consumer's message selector expression.
* @return This Consumer's selector expression or "".
*/
virtual const std::string& getMessageSelector(void) const = 0;
/**
* Sets this message consumer's message selector expression.
* @param This Consumer's selector expression or "".
*/
virtual void setMessageSelector( const std::string& selector ) = 0;
/**
* Gets the ID that is assigned to this consumer
* @return value of the Consumer Id.
*/
virtual unsigned int getConsumerId(void) const = 0;
/**
* Sets the ID that is assigned to this consumer
* @return string value of the Consumer Id.
*/
virtual void setConsumerId( const unsigned int id ) = 0;
/**
* Gets the Destination that this Consumer is subscribed on
* @return Destination
*/
virtual const cms::Destination& getDestination(void) const = 0;
/**
* Sets the destination that this Consumer is listening on
* @param Destination
*/
virtual void setDestination( const cms::Destination& destination ) = 0;
/**
* Gets the Session Info that this consumer is attached too
* @return SessionnInfo pointer
*/
virtual const SessionInfo* getSessionInfo(void) const = 0;
/**
* Gets the Session Info that this consumer is attached too
* @return SessionnInfo pointer
*/
virtual void setSessionInfo( const SessionInfo* session ) = 0;
};
}}
#endif /*_ACTIVEMQ_CONNECTOR_CONSUMERINFO_H_*/

View File

@ -0,0 +1,46 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#ifndef _ACTIVEMQ_CONNECTOR_CONSUMERMESSAGELISTENER_H_
#define _ACTIVEMQ_CONNECTOR_CONSUMERMESSAGELISTENER_H_
#include <activemq/connector/ConsumerInfo.h>
#include <activemq/core/ActiveMQMessage.h>
namespace activemq{
namespace connector{
/**
* An observer of messages that are targeted at a
* particular consumer.
*/
class ConsumerMessageListener{
public:
virtual ~ConsumerMessageListener(){}
/**
* Called to dispatch a message to a particular consumer.
* @param consumer the target consumer of the dispatch.
* @param msg the message to be dispatched.
*/
virtual void onConsumerMessage( ConsumerInfo* consumer,
core::ActiveMQMessage* msg ) = 0;
};
}}
#endif /*_ACTIVEMQ_CONNECTOR_CONSUMERMESSAGELISTENER_H_*/

View File

@ -0,0 +1,75 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#ifndef _ACTIVEMQ_CONNECTOR_PRODUCERINFO_H_
#define _ACTIVEMQ_CONNECTOR_PRODUCERINFO_H_
#include <cms/Destination.h>
#include <activemq/connector/ConnectorResource.h>
#include <activemq/connector/SessionInfo.h>
namespace activemq{
namespace connector{
class ProducerInfo : public ConnectorResource
{
public:
virtual ~ProducerInfo(void) {}
/**
* Retrieves the default destination that this producer
* sends its messages to.
* @return Destionation, owned by this object
*/
virtual const cms::Destination& getDestination(void) const = 0;
/**
* Sets the Default Destination for this Producer
* @param reference to a destination, copied internally
*/
virtual void setDestination( const cms::Destination& dest ) = 0;
/**
* Gets the ID that is assigned to this Producer
* @return value of the Producer Id.
*/
virtual unsigned int getProducerId(void) const = 0;
/**
* Sets the ID that is assigned to this Producer
* @return string value of the Producer Id.
*/
virtual void setProducerId( const unsigned int id ) = 0;
/**
* Gets the Session Info that this consumer is attached too
* @return SessionnInfo pointer
*/
virtual const SessionInfo* getSessionInfo(void) const = 0;
/**
* Gets the Session Info that this consumer is attached too
* @return SessionnInfo pointer
*/
virtual void setSessionInfo( const SessionInfo* session ) = 0;
};
}}
#endif /*_ACTIVEMQ_CONNECTOR_PRODUCERINFO_H_*/

View File

@ -0,0 +1,93 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#ifndef _ACTIVEMQ_CONNECTOR_SESSIONINFO_H_
#define _ACTIVEMQ_CONNECTOR_SESSIONINFO_H_
#include <activemq/connector/ConnectorResource.h>
#include <activemq/connector/TransactionInfo.h>
#include <cms/Session.h>
namespace activemq{
namespace connector{
class SessionInfo : public ConnectorResource
{
public:
/**
* Destructor
*/
virtual ~SessionInfo(void) {}
/**
* Gets the Connection Id of the Connection that this consumer is
* using to receive its messages.
* @return string value of the connection id
*/
virtual const std::string& getConnectionId(void) const = 0;
/**
* Sets the Connection Id of the Connection that this consumer is
* using to receive its messages.
* @param string value of the connection id
*/
virtual void setConnectionId( const std::string& id ) = 0;
/**
* Gets the Sessions Id value
* @return id for this session
*/
virtual unsigned int getSessionId(void) const = 0;
/**
* Sets the Session Id for this Session
* @param integral id value for this session
*/
virtual void setSessionId( const unsigned int id ) = 0;
/**
* Sets the Ack Mode of this Session Info object
* @param Ack Mode
*/
virtual void setAckMode(cms::Session::AcknowledgeMode ackMode) = 0;
/**
* Gets the Ack Mode of this Session
* @return Ack Mode
*/
virtual cms::Session::AcknowledgeMode getAckMode(void) const = 0;
/**
* Gets the currently active transaction info, if this session is
* transacted, returns NULL when not transacted. You must call
* getAckMode and see if the session is transacted.
* @return Transaction Id of current Transaction
*/
virtual const TransactionInfo* getTransactionInfo(void) const = 0;
/**
* Sets the current transaction info for this session, this is nit
* used when the session is not transacted.
* @param Transaction Id
*/
virtual void setTransactionInfo( const TransactionInfo* transaction ) = 0;
};
}}
#endif /*_ACTIVEMQ_CONNECTOR_SESSIONINFO_H_*/

View File

@ -0,0 +1,64 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#ifndef _ACTIVEMQ_CONNECTOR_TRANSACTIONINFO_H_
#define _ACTIVEMQ_CONNECTOR_TRANSACTIONINFO_H_
#include <activemq/connector/ConnectorResource.h>
namespace activemq{
namespace connector{
class SessionInfo;
class TransactionInfo : public ConnectorResource
{
public:
/**
* Destructor
*/
virtual ~TransactionInfo(void) {}
/**
* Gets the Transction Id
* @return unsigned int Id
*/
virtual unsigned int getTransactionId(void) const = 0;
/**
* Sets the Transction Id
* @param unsigned int Id
*/
virtual void setTransactionId( const unsigned int id ) = 0;
/**
* Gets the Session Info that this transaction is attached too
* @return SessionnInfo pointer
*/
virtual const SessionInfo* getSessionInfo(void) const = 0;
/**
* Gets the Session Info that this transaction is attached too
* @return SessionnInfo pointer
*/
virtual void setSessionInfo( const SessionInfo* session ) = 0;
};
}}
#endif /*_ACTIVEMQ_CONNECTOR_TRANSACTIONINFO_H_*/

View File

@ -0,0 +1,50 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#ifndef _ACTIVEMQ_CONNECTOR_STOMP_STOMPCOMMANDLISTENER_H_
#define _ACTIVEMQ_CONNECTOR_STOMP_STOMPCOMMANDLISTENER_H_
#include <activemq/connector/stomp/commands/StompCommand.h>
#include <activemq/connector/stomp/StompConnectorException.h>
namespace activemq{
namespace connector{
namespace stomp{
/**
* Interface class for object that with to register with the Stomp
* Connector in order to process a Command that was received.
*/
class StompCommandListener
{
public:
virtual ~StompCommandListener(void) {}
/**
* Process the Stomp Command
* @param command to process
* @throw ConnterException
*/
virtual void onStompCommand( commands::StompCommand* command )
throw ( StompConnectorException ) = 0;
};
}}}
#endif /*_ACTIVEMQ_CONNECTOR_STOMP_STOMPCOMMANDLISTENER_H_*/

View File

@ -0,0 +1,325 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#include "StompCommandReader.h"
#include <activemq/connector/stomp/commands/CommandConstants.h>
#include <activemq/concurrent/Thread.h>
using namespace std;
using namespace activemq;
using namespace activemq::concurrent;
using namespace activemq::connector;
using namespace activemq::connector::stomp;
using namespace activemq::transport;
using namespace activemq::io;
using namespace activemq::exceptions;
////////////////////////////////////////////////////////////////////////////////
StompCommandReader::StompCommandReader(void)
{
inputStream = NULL;
}
////////////////////////////////////////////////////////////////////////////////
StompCommandReader::StompCommandReader(InputStream* is)
{
inputStream = is;
}
////////////////////////////////////////////////////////////////////////////////
Command* StompCommandReader::readCommand(void)
throw (CommandIOException)
{
try
{
// Create a new Frame for reading to.
StompFrame* frame = new StompFrame();
// Read the command into the frame.
readStompCommand( *frame );
// Read the headers.
readStompHeaders( *frame );
// Read the body.
readStompBody( *frame );
// Return the Command, caller must delete it.
return marshaler.marshal( frame );
}
AMQ_CATCH_RETHROW( CommandIOException )
AMQ_CATCH_EXCEPTION_CONVERT( ActiveMQException, CommandIOException )
AMQ_CATCHALL_THROW( CommandIOException )
}
////////////////////////////////////////////////////////////////////////////////
void StompCommandReader::readStompCommand( StompFrame& frame )
throw ( StompConnectorException )
{
// Read the command;
int numChars = readStompHeaderLine();
if( numChars <= 0 )
{
throw StompConnectorException(
__FILE__, __LINE__,
"StompCommandReader::readStompCommand: "
"Error on Read of Command Header" );
}
// Set the command in the frame - copy the memory.
frame.setCommand( reinterpret_cast<char*>(&buffer[0]) );
// Clean up the mess.
buffer.clear();
}
////////////////////////////////////////////////////////////////////////////////
void StompCommandReader::readStompHeaders( StompFrame& frame )
throw (StompConnectorException)
{
// Read the command;
bool endOfHeaders = false;
while( !endOfHeaders )
{
// Clean up the mess.
buffer.clear();
// Read in the next header line.
int numChars = readStompHeaderLine();
if( numChars == 0 )
{
// should never get here
throw StompConnectorException(
__FILE__, __LINE__,
"StompCommandReader::readStompHeaders: no characters read" );
}
// Check for an empty line to demark the end of the header section.
// if its not the end then we have a header to process, so parse it.
if( numChars == 1 && buffer[0] == '\0' )
{
endOfHeaders = true;
}
else
{
// Search through this line to separate the key/value pair.
for( size_t ix = 0; ix < buffer.size(); ++ix )
{
// If found the key/value separator...
if( buffer[ix] == ':' )
{
// Null-terminate the key.
buffer[ix] = '\0';
const char* key = reinterpret_cast<char*>(&buffer[0]);
const char* value = reinterpret_cast<char*>(&buffer[ix+1]);
// Assign the header key/value pair.
frame.getProperties().setProperty(key, value);
// Break out of the for loop.
break;
}
}
}
}
// Clean up the mess.
buffer.clear();
}
////////////////////////////////////////////////////////////////////////////////
int StompCommandReader::readStompHeaderLine(void)
throw (StompConnectorException)
{
int count = 0;
while( true )
{
// Read the next char from the stream.
buffer.push_back( inputStream->read() );
// Increment the position pointer.
count++;
// If we reached the line terminator, return the total number
// of characters read.
if( buffer[count-1] == '\n' )
{
// Overwrite the line feed with a null character.
buffer[count-1] = '\0';
return count;
}
}
// If we get here something bad must have happened.
throw StompConnectorException(
__FILE__, __LINE__,
"StompCommandReader::readStompHeaderLine: "
"Unrecoverable, error condition");
}
////////////////////////////////////////////////////////////////////////////////
void StompCommandReader::readStompBody( StompFrame& frame )
throw ( StompConnectorException )
{
unsigned long content_length = 0;
if(frame.getProperties().hasProperty(
commands::CommandConstants::toString(
commands::CommandConstants::HEADER_CONTENTLENGTH)))
{
char* stopped_string = NULL;
string length =
frame.getProperties().getProperty(
commands::CommandConstants::toString(
commands::CommandConstants::HEADER_CONTENTLENGTH));
content_length = strtoul(
length.c_str(),
&stopped_string,
10);
}
if(content_length != 0)
{
// For this case its assumed that content length indicates how
// much to read. We reserve space in the buffer for it to
// minimize the number of reallocs that might occur. We are
// assuming that content length doesn't count the trailing null
// that indicates the end of frame. The reserve won't do anything
// if the buffer already has that much capacity. The resize call
// basically sets the end iterator to the correct location since
// this is a char vector and we already reserve enough space.
// Resize doesn't realloc the vector smaller if content_length
// is less than capacity of the buffer, it just move the end
// iterator. Reserve adds the benefit that the mem is set to
// zero. Over time as larger messages come in thsi will cause
// us to adapt to that size so that future messages that are
// around that size won't alloc any new memory.
buffer.reserve( content_length );
buffer.resize( content_length );
// Read the Content Length now
read( &buffer[0], content_length );
// Content Length read, now pop the end terminator off (\0\n).
if(inputStream->read() != '\0' ||
inputStream->read() != '\n')
{
throw StompConnectorException(
__FILE__, __LINE__,
"StompCommandReader::readStompBody: "
"Read Content Length, and no trailing null");
}
}
else
{
// Content length was either zero, or not set, so we read until the
// first null is encounted.
while( true )
{
char byte = inputStream->read();
buffer.push_back(byte);
content_length++;
if(byte != '\0')
{
continue;
}
// We read up to the first NULL, now lets pop off the required
// newline to complete the packet.
if(inputStream->read() != '\n')
{
throw StompConnectorException(
__FILE__, __LINE__,
"StompCommandReader::readStompBody: "
"Read Body, and no trailing newline");
}
break; // Read null and newline we are done.
}
}
if( content_length != 0 )
{
char* cpyBody = new char[content_length];
memcpy(cpyBody, &buffer[0], content_length);
// Set the body contents in the frame - copy the memory
frame.setBody( cpyBody, content_length );
}
// Clean up the mess.
buffer.clear();
}
////////////////////////////////////////////////////////////////////////////////
int StompCommandReader::read(unsigned char* buffer, int count)
throw(io::IOException)
{
if( inputStream == NULL )
{
throw IOException(
__FILE__, __LINE__,
"StompCommandReader::read(char*,int) - input stream is NULL" );
}
int head = 0;
// We call the read(buffer, size) version asking for one
// byte, if this returns zero, then there wasn't anything
// on the stream to read, so we try again after a short
// pause in hopes that some more data will show up.
while( true )
{
head += inputStream->read(&buffer[head], count - head);
if(head == count)
{
return count;
}
// Got here, so we wait a bit and try again.
Thread::sleep( 10 );
}
}
////////////////////////////////////////////////////////////////////////////////
unsigned char StompCommandReader::readByte(void) throw(io::IOException)
{
if( inputStream == NULL )
{
throw IOException(
__FILE__, __LINE__,
"StompCommandReader::read(char*,int) - input stream is NULL" );
}
unsigned char c = 0;
inputStream->read(&c, 1);
return c;
}

View File

@ -0,0 +1,146 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#ifndef _ACTIVEMQ_CONNECTOR_STOMP_STOMPCOMMANDREADER_H_
#define _ACTIVEMQ_CONNECTOR_STOMP_STOMPCOMMANDREADER_H_
#include <activemq/transport/CommandReader.h>
#include <activemq/io/InputStream.h>
#include <activemq/transport/CommandIOException.h>
#include <activemq/transport/Command.h>
#include <activemq/connector/stomp/StompFrame.h>
#include <activemq/connector/stomp/StompConnectorException.h>
#include <activemq/connector/stomp/marshal/Marshaler.h>
namespace activemq{
namespace connector{
namespace stomp{
class StompCommandReader : public transport::CommandReader
{
private:
/**
* The target input stream.
*/
io::InputStream* inputStream;
/**
* Vector Object used to buffer data
*/
std::vector<unsigned char> buffer;
/**
* Marshaler of Stomp Commands
*/
marshal::Marshaler marshaler;
public:
/**
* Deafult Constructor
*/
StompCommandReader( void );
/**
* Constructor.
* @param is the target input stream.
*/
StompCommandReader( io::InputStream* is );
/**
* Destructor
*/
virtual ~StompCommandReader(void) {}
/**
* Reads a command from the given input stream.
* @return The next command available on the stream.
* @throws CommandIOException if a problem occurs during the read.
*/
virtual transport::Command* readCommand( void )
throw ( transport::CommandIOException );
/**
* Sets the target input stream.
* @param Target Input Stream
*/
virtual void setInputStream(io::InputStream* is){
inputStream = is;
}
/**
* Gets the target input stream.
* @return Target Input Stream
*/
virtual io::InputStream* getInputStream( void ){
return inputStream;
}
/**
* Attempts to read an array of bytes from the stream.
* @param buffer The target byte buffer.
* @param count The number of bytes to read.
* @return The number of bytes read.
* @throws IOException thrown if an error occurs.
*/
virtual int read(unsigned char* buffer, int count)
throw( io::IOException );
/**
* Attempts to read a byte from the input stream
* @return The byte.
* @throws IOException thrown if an error occurs.
*/
virtual unsigned char readByte(void) throw( io::IOException );
private:
/**
* Read the Stomp Command from the Frame
* @param reference to a Stomp Frame
* @throws StompConnectorException
*/
void readStompCommand( StompFrame& frame )
throw ( StompConnectorException );
/**
* Read all the Stomp Headers for the incoming Frame
* @param Frame to place data into
* @throws StompConnectorException
*/
void readStompHeaders( StompFrame& frame )
throw ( StompConnectorException );
/**
* Reads a Stomp Header line and stores it in the buffer object
* @return number of bytes read, zero if there was a problem.
* @throws StompConnectorException
*/
int readStompHeaderLine( void ) throw ( StompConnectorException );
/**
* Reads the Stomp Body from the Wire and store it in the frame.
* @param Stomp Frame to place data in
*/
void readStompBody( StompFrame& frame )
throw ( StompConnectorException );
};
}}}
#endif /*_ACTIVEMQ_CONNECTOR_STOMP_STOMPCOMMANDREADER_H_*/

View File

@ -0,0 +1,137 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#include "StompCommandWriter.h"
#include <activemq/connector/stomp/StompFrame.h>
#include <activemq/connector/stomp/commands/CommandConstants.h>
using namespace std;
using namespace activemq;
using namespace activemq::connector;
using namespace activemq::connector::stomp;
using namespace activemq::connector::stomp::commands;
using namespace activemq::transport;
using namespace activemq::io;
using namespace activemq::exceptions;
////////////////////////////////////////////////////////////////////////////////
StompCommandWriter::StompCommandWriter(void)
{
outputStream = NULL;
}
////////////////////////////////////////////////////////////////////////////////
StompCommandWriter::StompCommandWriter(OutputStream* os)
{
outputStream = os;
}
////////////////////////////////////////////////////////////////////////////////
void StompCommandWriter::writeCommand( const Command* command )
throw ( transport::CommandIOException )
{
try
{
if( outputStream == NULL )
{
throw CommandIOException(
__FILE__, __LINE__,
"StompCommandWriter::writeCommand - "
"output stream is NULL" );
}
const StompFrame& frame = marshaler.marshal( command );
// Write the command.
const string& cmdString = frame.getCommand();
write( cmdString.c_str(), cmdString.length() );
writeByte( '\n' );
// Write all the headers.
vector< pair<string,string> > headers = frame.getProperties().toArray();
for( unsigned int ix=0; ix < headers.size(); ++ix )
{
string& name = headers[ix].first;
string& value = headers[ix].second;
write( name.c_str(), name.length() );
writeByte( ':' );
write( value.c_str(), value.length() );
writeByte( '\n' );
}
// Finish the header section with a form feed.
writeByte( '\n' );
// Write the body.
const char* body = frame.getBody();
if( body != NULL )
{
write( body, frame.getBodyLength() );
}
if( ( frame.getBodyLength() == 0 ) ||
( frame.getProperties().getProperty(
CommandConstants::toString(
CommandConstants::HEADER_CONTENTLENGTH ), "" ) != "" ) )
{
writeByte( '\0' );
}
writeByte( '\n' );
// Flush the stream.
outputStream->flush();
}
AMQ_CATCH_RETHROW( CommandIOException )
AMQ_CATCH_EXCEPTION_CONVERT( ActiveMQException, CommandIOException )
AMQ_CATCHALL_THROW( CommandIOException )
}
////////////////////////////////////////////////////////////////////////////////
void StompCommandWriter::write(const unsigned char* buffer, int count)
throw(IOException)
{
if( outputStream == NULL )
{
throw IOException(
__FILE__, __LINE__,
"StompCommandWriter::write(char*,int) - input stream is NULL" );
}
outputStream->write( buffer, count );
}
////////////////////////////////////////////////////////////////////////////////
void StompCommandWriter::writeByte(unsigned char v) throw(IOException)
{
if( outputStream == NULL )
{
throw IOException(
__FILE__, __LINE__,
"StompCommandWriter::write(char) - input stream is NULL" );
}
outputStream->write( v );
}
////////////////////////////////////////////////////////////////////////////////
void StompCommandWriter::write(const char* buffer, int count)
throw(io::IOException)
{
write(reinterpret_cast<const unsigned char*>(buffer), count);
}

View File

@ -0,0 +1,118 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#ifndef _ACTIVEMQ_CONNECTOR_STOMP_STOMPCOMMANDWRITER_H_
#define _ACTIVEMQ_CONNECTOR_STOMP_STOMPCOMMANDWRITER_H_
#include <activemq/transport/CommandWriter.h>
#include <activemq/io/InputStream.h>
#include <activemq/transport/CommandIOException.h>
#include <activemq/connector/stomp/StompConnectorException.h>
#include <activemq/transport/Command.h>
#include <activemq/io/OutputStream.h>
#include <activemq/connector/stomp/marshal/Marshaler.h>
namespace activemq{
namespace connector{
namespace stomp{
class StompCommandWriter : public transport::CommandWriter
{
private:
/**
* Target output stream.
*/
io::OutputStream* outputStream;
/**
* Marshaler of Stomp Commands
*/
marshal::Marshaler marshaler;
public:
/**
* Default Constructor
*/
StompCommandWriter(void);
/**
* Constructor.
* @param os the target output stream.
*/
StompCommandWriter( io::OutputStream* os );
/**
* Destructor
*/
virtual ~StompCommandWriter(void) {}
/**
* Sets the target output stream.
*/
virtual void setOutputStream(io::OutputStream* os){
outputStream = os;
}
/**
* Gets the target output stream.
*/
virtual io::OutputStream* getOutputStream(void){
return outputStream;
}
/**
* Writes a command to the given output stream.
* @param command the command to write.
* @param os the target stream for the write.
* @throws CommandIOException if a problem occurs during the write.
*/
virtual void writeCommand( const transport::Command* command )
throw ( transport::CommandIOException );
/**
* Writes a byte array to the output stream.
* @param buffer a byte array
* @param count the number of bytes in the array to write.
* @throws IOException thrown if an error occurs.
*/
virtual void write(const unsigned char* buffer, int count)
throw( io::IOException );
/**
* Writes a byte to the output stream.
* @param v The value to be written.
* @throws IOException thrown if an error occurs.
*/
virtual void writeByte(unsigned char v) throw( io::IOException );
private:
/**
* Writes a char array to the output stream.
* @param buffer a char array
* @param count the number of bytes in the array to write.
* @throws IOException thrown if an error occurs.
*/
virtual void write(const char* buffer, int count)
throw( io::IOException );
};
}}}
#endif /*_ACTIVEMQ_CONNECTOR_STOMP_STOMPCOMMANDWRITER_H_*/

View File

@ -0,0 +1,795 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#include <activemq/connector/stomp/StompConnector.h>
#include <activemq/concurrent/Concurrent.h>
#include <activemq/transport/BrokerError.h>
#include <activemq/transport/Transport.h>
#include <activemq/transport/ExceptionResponse.h>
#include <activemq/connector/stomp/StompTopic.h>
#include <activemq/connector/stomp/StompQueue.h>
#include <activemq/connector/stomp/commands/ConnectCommand.h>
#include <activemq/connector/stomp/commands/ErrorCommand.h>
#include <activemq/connector/stomp/commands/BeginCommand.h>
#include <activemq/connector/stomp/commands/AbortCommand.h>
#include <activemq/connector/stomp/commands/AckCommand.h>
#include <activemq/connector/stomp/commands/CommitCommand.h>
#include <activemq/connector/stomp/commands/MessageCommand.h>
#include <activemq/connector/stomp/commands/BytesMessageCommand.h>
#include <activemq/connector/stomp/commands/TextMessageCommand.h>
#include <activemq/connector/stomp/commands/ConnectedCommand.h>
#include <activemq/connector/stomp/commands/DisconnectCommand.h>
#include <activemq/exceptions/UnsupportedOperationException.h>
#include <activemq/connector/stomp/StompProducerInfo.h>
#include <activemq/connector/stomp/StompTransactionInfo.h>
#include <activemq/util/Integer.h>
using namespace std;
using namespace activemq;
using namespace activemq::connector;
using namespace activemq::util;
using namespace activemq::transport;
using namespace activemq::exceptions;
using namespace activemq::connector::stomp;
using namespace activemq::connector::stomp::commands;
////////////////////////////////////////////////////////////////////////////////
StompConnector::StompConnector( Transport* transport,
const util::Properties& properties )
throw ( IllegalArgumentException )
{
if(transport == NULL)
{
throw IllegalArgumentException(
__FILE__, __LINE__,
"StompConnector::StompConnector - Transport cannot be NULL");
}
this->transport = transport;
this->state = DISCONNECTED;
this->exceptionListener = NULL;
this->messageListener = NULL;
this->sessionManager = NULL;
this->nextProducerId = 0;
this->nextTransactionId = 0;
this->properties.copy( &properties );
// Observe the transport for events.
this->transport->setCommandListener( this );
this->transport->setTransportExceptionListener( this );
// Setup the reader and writer in the transport.
this->transport->setCommandReader( &reader );
this->transport->setCommandWriter( &writer );
// Register ourself for those commands that we process
addCmdListener( CommandConstants::ERROR_CMD, this );
}
////////////////////////////////////////////////////////////////////////////////
StompConnector::~StompConnector(void)
{
try
{
close();
delete sessionManager;
}
AMQ_CATCH_NOTHROW( ActiveMQException )
AMQ_CATCHALL_NOTHROW( )
}
////////////////////////////////////////////////////////////////////////////////
unsigned int StompConnector::getNextProducerId(void)
{
synchronized(&mutex)
{
return nextProducerId++;
}
return 0;
}
////////////////////////////////////////////////////////////////////////////////
unsigned int StompConnector::getNextTransactionId(void)
{
synchronized(&mutex)
{
return nextTransactionId++;
}
return 0;
}
////////////////////////////////////////////////////////////////////////////////
void StompConnector::enforceConnected( void ) throw ( ConnectorException )
{
if( state != CONNECTED )
{
throw StompConnectorException(
__FILE__, __LINE__,
"StompConnector::enforceConnected - Not Connected!" );
}
}
////////////////////////////////////////////////////////////////////////////////
void StompConnector::addCmdListener(
commands::CommandConstants::CommandId commandId,
StompCommandListener* listener )
{
cmdListenerMap.insert( make_pair( commandId, listener ) );
}
////////////////////////////////////////////////////////////////////////////////
void StompConnector::removeCmdListener(
commands::CommandConstants::CommandId commandId )
{
cmdListenerMap.erase(commandId);
}
////////////////////////////////////////////////////////////////////////////////
void StompConnector::start(void) throw( cms::CMSException )
{
try
{
synchronized( &mutex )
{
if( state == CONNECTED )
{
throw ActiveMQException(
__FILE__, __LINE__,
"StompConnector::start - already started" );
}
// Start the transport - this establishes the socket.
transport->start();
// Send the connect message to the broker.
connect();
}
}
AMQ_CATCH_RETHROW( ActiveMQException )
AMQ_CATCHALL_THROW( ActiveMQException );
}
////////////////////////////////////////////////////////////////////////////////
void StompConnector::close(void) throw( cms::CMSException ){
try
{
synchronized( &mutex )
{
if( state == this->CONNECTED )
{
// Send the disconnect message to the broker.
disconnect();
// Close the transport.
transport->close();
}
}
}
AMQ_CATCH_RETHROW( ActiveMQException )
AMQ_CATCHALL_THROW( ActiveMQException );
}
////////////////////////////////////////////////////////////////////////////////
void StompConnector::connect(void)
{
try
{
// Mark this connector as started.
state = this->CONNECTING;
// Send the connect command to the broker
ConnectCommand cmd;
// Encode User Name and Password and Client ID
string login = getLogin();
if( login.length() > 0 ){
cmd.setLogin( login );
}
string password = getPassword();
if( password.length() > 0 ){
cmd.setPassword( password );
}
string clientId = getClientId();
if( clientId.length() > 0 ){
cmd.setClientId( clientId );
}
Response* response = transport->request( &cmd );
if( dynamic_cast< ExceptionResponse* >( response ) != NULL )
{
throw StompConnectorException(
__FILE__, __LINE__,
"StompConnector::connect - Failed on Connect Request" );
}
ConnectedCommand* connected =
dynamic_cast< ConnectedCommand* >( response );
if( connected == NULL )
{
throw StompConnectorException(
__FILE__, __LINE__,
"StompConnector::connect - "
"Response not a connected response" );
}
// Connected so we now create the SessionManager
sessionManager = new StompSessionManager(
connected->getSessionId(), transport );
// Give our message listener to the session manager it will
// notify all the interested clients
sessionManager->setConsumerMessageListener( messageListener );
// Add the Session Manager as the Command Listener for
// Message commands so that it can route them to the
// correct consumers.
addCmdListener( CommandConstants::MESSAGE, sessionManager );
// In Stomp, the client Id is the same as the session id that is
// returned in the Connected response
properties.setProperty(
commands::CommandConstants::toString(
commands::CommandConstants::HEADER_CLIENT_ID ),
connected->getSessionId() );
// Tag us in the Connected State now.
state = CONNECTED;
// Clean up
delete response;
}
AMQ_CATCH_RETHROW( BrokerError )
AMQ_CATCH_RETHROW( ActiveMQException )
AMQ_CATCHALL_THROW( ActiveMQException )
}
////////////////////////////////////////////////////////////////////////////////
void StompConnector::disconnect(void)
{
try
{
// Mark state as no longer connected.
state = this->DISCONNECTED;
// Send the disconnect command to the broker.
DisconnectCommand cmd;
transport->oneway( &cmd );
}
AMQ_CATCH_RETHROW( ActiveMQException )
AMQ_CATCHALL_THROW( ActiveMQException );
}
////////////////////////////////////////////////////////////////////////////////
SessionInfo* StompConnector::createSession(
cms::Session::AcknowledgeMode ackMode)
throw( ConnectorException )
{
try
{
enforceConnected();
return sessionManager->createSession( ackMode );
}
AMQ_CATCH_RETHROW( ConnectorException )
AMQ_CATCHALL_THROW( ConnectorException );
}
////////////////////////////////////////////////////////////////////////////////
ConsumerInfo* StompConnector::createConsumer(
cms::Destination* destination,
SessionInfo* session,
const std::string& selector)
throw ( ConnectorException )
{
try
{
enforceConnected();
return sessionManager->createConsumer(
destination, session, selector );
}
AMQ_CATCH_RETHROW( ConnectorException )
AMQ_CATCHALL_THROW( ConnectorException );
}
////////////////////////////////////////////////////////////////////////////////
ConsumerInfo* StompConnector::createDurableConsumer(
cms::Topic* topic,
SessionInfo* session,
const std::string& name,
const std::string& selector,
bool noLocal)
throw ( ConnectorException )
{
try
{
enforceConnected();
return sessionManager->createDurableConsumer(
topic, session, name, selector, noLocal );
}
AMQ_CATCH_RETHROW( ConnectorException )
AMQ_CATCHALL_THROW( ConnectorException );
}
////////////////////////////////////////////////////////////////////////////////
ProducerInfo* StompConnector::createProducer(
cms::Destination* destination,
SessionInfo* session)
throw ( ConnectorException )
{
try
{
enforceConnected();
ProducerInfo* producer = new StompProducerInfo();
producer->setDestination( *destination );
producer->setProducerId( getNextProducerId() );
producer->setSessionInfo( session );
return producer;
}
AMQ_CATCH_RETHROW( ConnectorException )
AMQ_CATCHALL_THROW( ConnectorException );
}
////////////////////////////////////////////////////////////////////////////////
cms::Topic* StompConnector::createTopic(const std::string& name,
SessionInfo* session)
throw ( ConnectorException )
{
try
{
enforceConnected();
return new StompTopic(name);
}
AMQ_CATCH_RETHROW( ConnectorException )
AMQ_CATCHALL_THROW( ConnectorException );
}
////////////////////////////////////////////////////////////////////////////////
cms::Queue* StompConnector::createQueue(const std::string& name,
SessionInfo* session)
throw ( ConnectorException )
{
try
{
enforceConnected();
return new StompQueue(name);
}
AMQ_CATCH_RETHROW( ConnectorException )
AMQ_CATCHALL_THROW( ConnectorException );
}
////////////////////////////////////////////////////////////////////////////////
cms::TemporaryTopic* StompConnector::createTemporaryTopic(
SessionInfo* session)
throw ( ConnectorException )
{
try
{
throw UnsupportedOperationException(
__FILE__, __LINE__,
"StompConnector::createTemporaryTopic - No Stomp Support");
}
AMQ_CATCH_RETHROW( ConnectorException )
AMQ_CATCHALL_THROW( ConnectorException );
}
////////////////////////////////////////////////////////////////////////////////
cms::TemporaryQueue* StompConnector::createTemporaryQueue(
SessionInfo* session)
throw ( ConnectorException )
{
try
{
throw UnsupportedOperationException(
__FILE__, __LINE__,
"StompConnector::createTemporaryQueue - No Stomp Support");
}
AMQ_CATCH_RETHROW( ConnectorException )
AMQ_CATCHALL_THROW( ConnectorException );
}
////////////////////////////////////////////////////////////////////////////////
void StompConnector::send(cms::Message* message,
ProducerInfo* producerInfo)
throw ( ConnectorException )
{
try
{
enforceConnected();
const SessionInfo* session = producerInfo->getSessionInfo();
Command* command = dynamic_cast< transport::Command* >( message );
if( command == NULL )
{
throw StompConnectorException(
__FILE__, __LINE__,
"StompConnector::send - "
"Message is not a valid stomp type.");
}
if( session->getAckMode() == cms::Session::Transactional )
{
StompCommand* stompCommand =
dynamic_cast< StompCommand* >( message );
if( stompCommand == NULL )
{
throw StompConnectorException(
__FILE__, __LINE__,
"StompConnector::send - "
"Message is not a valid stomp type.");
}
stompCommand->setTransactionId(
Integer::toString(
session->getTransactionInfo()->getTransactionId() ) );
}
// Send it
transport->oneway( command );
}
AMQ_CATCH_RETHROW( ConnectorException )
AMQ_CATCHALL_THROW( ConnectorException );
}
////////////////////////////////////////////////////////////////////////////////
void StompConnector::send(std::list<cms::Message*>& messages,
ProducerInfo* producerInfo)
throw ( ConnectorException )
{
try
{
enforceConnected();
list<cms::Message*>::const_iterator itr = messages.begin();
for(; itr != messages.end(); ++itr)
{
this->send(*itr, producerInfo);
}
}
AMQ_CATCH_RETHROW( ConnectorException )
AMQ_CATCHALL_THROW( ConnectorException );
}
////////////////////////////////////////////////////////////////////////////////
void StompConnector::acknowledge( const SessionInfo* session,
const cms::Message* message,
AckType ackType = ConsumedAck )
throw ( ConnectorException )
{
try
{
enforceConnected();
// Auto to Stomp means don't do anything, so we drop it here
// for client acknowledge we have to send and ack.
if( session->getAckMode() == cms::Session::ClientAcknowledge )
{
AckCommand cmd;
if( message->getCMSMessageId() == NULL )
{
throw StompConnectorException(
__FILE__, __LINE__,
"StompConnector::send - "
"Message has no Message Id, cannot ack.");
}
cmd.setMessageId( message->getCMSMessageId() );
if( session->getAckMode() == cms::Session::Transactional )
{
cmd.setTransactionId(
Integer::toString(
session->getTransactionInfo()->getTransactionId() ) );
}
transport->oneway( &cmd );
}
}
AMQ_CATCH_RETHROW( ConnectorException )
AMQ_CATCHALL_THROW( ConnectorException );
}
////////////////////////////////////////////////////////////////////////////////
TransactionInfo* StompConnector::startTransaction(
SessionInfo* session)
throw ( ConnectorException )
{
try
{
enforceConnected();
TransactionInfo* transaction = new StompTransactionInfo();
transaction->setTransactionId( getNextTransactionId() );
session->setTransactionInfo( transaction );
BeginCommand cmd;
cmd.setTransactionId(
Integer::toString( transaction->getTransactionId() ) );
transport->oneway( &cmd );
return transaction;
}
AMQ_CATCH_RETHROW( ConnectorException )
AMQ_CATCHALL_THROW( ConnectorException );
}
////////////////////////////////////////////////////////////////////////////////
void StompConnector::commit(TransactionInfo* transaction,
SessionInfo* session)
throw ( ConnectorException )
{
try
{
enforceConnected();
CommitCommand cmd;
cmd.setTransactionId(
Integer::toString( transaction->getTransactionId() ) );
transport->oneway( &cmd );
}
AMQ_CATCH_RETHROW( ConnectorException )
AMQ_CATCHALL_THROW( ConnectorException );
}
////////////////////////////////////////////////////////////////////////////////
void StompConnector::rollback(TransactionInfo* transaction,
SessionInfo* session)
throw ( ConnectorException )
{
try
{
enforceConnected();
AbortCommand cmd;
cmd.setTransactionId(
Integer::toString( transaction->getTransactionId() ) );
transport->oneway( &cmd );
}
AMQ_CATCH_RETHROW( ConnectorException )
AMQ_CATCHALL_THROW( ConnectorException );
}
////////////////////////////////////////////////////////////////////////////////
cms::Message* StompConnector::createMessage(
SessionInfo* session,
TransactionInfo* transaction)
throw ( ConnectorException )
{
try
{
enforceConnected();
MessageCommand* cmd = new MessageCommand();
if( transaction != NULL )
{
cmd->setTransactionId(
Integer::toString( transaction->getTransactionId() ) );
}
return cmd;
}
AMQ_CATCH_RETHROW( ConnectorException )
AMQ_CATCHALL_THROW( ConnectorException );
}
////////////////////////////////////////////////////////////////////////////////
cms::BytesMessage* StompConnector::createBytesMessage(
SessionInfo* session,
TransactionInfo* transaction)
throw ( ConnectorException )
{
try
{
enforceConnected();
BytesMessageCommand* cmd = new BytesMessageCommand();
if( transaction != NULL )
{
cmd->setTransactionId(
Integer::toString( transaction->getTransactionId() ) );
}
return cmd;
}
AMQ_CATCH_RETHROW( ConnectorException )
AMQ_CATCHALL_THROW( ConnectorException );
}
////////////////////////////////////////////////////////////////////////////////
cms::TextMessage* StompConnector::createTextMessage(
SessionInfo* session,
TransactionInfo* transaction)
throw ( ConnectorException )
{
try
{
enforceConnected();
TextMessageCommand* cmd = new TextMessageCommand;
if( transaction != NULL )
{
cmd->setTransactionId(
Integer::toString( transaction->getTransactionId() ) );
}
return cmd;
}
AMQ_CATCH_RETHROW( ConnectorException )
AMQ_CATCHALL_THROW( ConnectorException );
}
////////////////////////////////////////////////////////////////////////////////
cms::MapMessage* StompConnector::createMapMessage(
SessionInfo* session,
TransactionInfo* transaction)
throw ( ConnectorException )
{
try
{
throw UnsupportedOperationException(
__FILE__, __LINE__,
"StompConnector::createTemporaryQueue - No Stomp Support");
}
AMQ_CATCH_RETHROW( ConnectorException )
AMQ_CATCHALL_THROW( ConnectorException );
}
////////////////////////////////////////////////////////////////////////////////
void StompConnector::unsubscribe(const std::string& name)
throw ( ConnectorException )
{
try
{
throw UnsupportedOperationException(
__FILE__, __LINE__,
"StompConnector::createTemporaryQueue - No Stomp Support");
}
AMQ_CATCH_RETHROW( ConnectorException )
AMQ_CATCHALL_THROW( ConnectorException );
}
////////////////////////////////////////////////////////////////////////////////
void StompConnector::destroyResource( ConnectorResource* resource )
throw ( ConnectorException )
{
try
{
ConsumerInfo* consumer =
dynamic_cast<ConsumerInfo*>(resource);
SessionInfo* session =
dynamic_cast<SessionInfo*>(resource);
if( consumer != NULL)
{
sessionManager->removeConsumer( consumer );
}
else if( session != NULL)
{
sessionManager->removeSession( session );
}
// No matter what we end it here.
delete resource;
}
AMQ_CATCH_RETHROW( ConnectorException )
AMQ_CATCHALL_THROW( ConnectorException );
}
////////////////////////////////////////////////////////////////////////////////
void StompConnector::onCommand( transport::Command* command )
{
try
{
StompCommand* stompCommand = dynamic_cast< StompCommand* >(command);
if(stompCommand == NULL)
{
fire( ConnectorException(
__FILE__, __LINE__,
"StompConnector::onCommand - Recieved an unknown Command") );
}
CmdListenerMap::iterator itr =
cmdListenerMap.find( stompCommand->getStompCommandId() );
if( itr == cmdListenerMap.end() )
{
fire( ConnectorException(
__FILE__, __LINE__,
"StompConnector::onCommand - "
"Recieved command with no listener") );
// This isn't going an farther, so delete it.
delete command;
return; // we are done
}
// Hand off
itr->second->onStompCommand( stompCommand );
}
AMQ_CATCH_RETHROW( ConnectorException )
AMQ_CATCHALL_THROW( ConnectorException );
}
////////////////////////////////////////////////////////////////////////////////
void StompConnector::onTransportException(
transport::Transport* source,
const exceptions::ActiveMQException& ex )
{
try
{
// Inform the user.
fire( ex );
// Close down.
close();
}
AMQ_CATCH_RETHROW( ConnectorException )
AMQ_CATCHALL_THROW( ConnectorException );
}
////////////////////////////////////////////////////////////////////////////////
void StompConnector::onStompCommand( commands::StompCommand* command )
throw ( StompConnectorException )
{
try
{
ErrorCommand* error =
dynamic_cast<ErrorCommand*>(command);
if(error != NULL)
{
fire( StompConnectorException(
__FILE__, __LINE__,
(string( "StompConnector::onStompCommand - " ) +
error->getErrorMessage() ).c_str() ) );
// Shutdown
close();
}
}
AMQ_CATCH_RETHROW( StompConnectorException )
AMQ_CATCHALL_THROW( StompConnectorException );
}

View File

@ -0,0 +1,533 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#ifndef ACTIVEMQ_CONNECTOR_STOMP_STOMPCONNECTOR_H_
#define ACTIVEMQ_CONNECTOR_STOMP_STOMPCONNECTOR_H_
#include <activemq/connector/Connector.h>
#include <activemq/transport/Transport.h>
#include <activemq/transport/CommandListener.h>
#include <activemq/transport/TransportExceptionListener.h>
#include <activemq/concurrent/Mutex.h>
#include <activemq/util/Properties.h>
#include <activemq/connector/stomp/StompCommandReader.h>
#include <activemq/connector/stomp/StompCommandWriter.h>
#include <activemq/connector/stomp/StompCommandListener.h>
#include <activemq/connector/stomp/StompSessionManager.h>
#include <activemq/connector/stomp/commands/CommandConstants.h>
#include <activemq/exceptions/IllegalArgumentException.h>
namespace activemq{
namespace connector{
namespace stomp{
/**
* The connector implementation for the STOMP protocol.
*/
class StompConnector
:
public Connector,
public transport::CommandListener,
public transport::TransportExceptionListener,
public StompCommandListener
{
private:
// Flags the state we are in for connection to broker.
enum connectionState
{
DISCONNECTED,
CONNECTING,
CONNECTED
};
// Maps Command Ids to listener that are interested
typedef std::map< commands::CommandConstants::CommandId,
StompCommandListener*> CmdListenerMap;
private:
/**
* The transport for sending/receiving commands on the wire.
*/
transport::Transport* transport;
/**
* Flag to indicate the start state of the connector.
*/
connectionState state;
/**
* Sync object.
*/
concurrent::Mutex mutex;
/**
* Observer of messages directed at a particular
* consumer.
*/
ConsumerMessageListener* messageListener;
/**
* Observer of connector exceptions.
*/
cms::ExceptionListener* exceptionListener;
/**
* This Connector's Command Reader
*/
StompCommandReader reader;
/**
* This Connector's Command Writer
*/
StompCommandWriter writer;
/**
* Map to hold StompCommandListeners
*/
CmdListenerMap cmdListenerMap;
/**
* Session Manager object that will be allocated when we connect
*/
StompSessionManager* sessionManager;
/**
* Next avaliable Producer Id
*/
unsigned int nextProducerId;
/**
* Next avaliable Transaction Id
*/
unsigned int nextTransactionId;
/**
* Properties for the connector.
*/
util::SimpleProperties properties;
private:
/**
* Sends the connect message to the broker and
* waits for the response.
*/
void connect(void);
/**
* Sends a oneway disconnect message to the broker.
*/
void disconnect(void);
/**
* Fires a consumer message to the observer.
*/
void fire( ConsumerInfo* consumer, core::ActiveMQMessage* msg ){
try{
if( messageListener != NULL ){
messageListener->onConsumerMessage(
consumer,
msg );
}
}catch( ... ){/* do nothing*/}
}
/**
* Fires an exception event to the observing object.
*/
void fire( const exceptions::ActiveMQException& ex ){
try{
if( exceptionListener != NULL ){
exceptionListener->onException( ex );
}
}catch( ... ){/* do nothing*/}
}
public:
/**
* Constructor for the stomp connector.
* @param transport the transport object for sending/receiving
* commands on the wire.
* @param props properties for configuring the connector.
*/
StompConnector( transport::Transport* transport,
const util::Properties& properties )
throw ( exceptions::IllegalArgumentException );
virtual ~StompConnector(void);
/**
* Starts the service.
* @throws CMSException
*/
virtual void start(void) throw( cms::CMSException );
/**
* Closes this object and deallocates the appropriate resources.
* @throws CMSException
*/
virtual void close(void) throw( cms::CMSException );
/**
* Gets the Client Id for this connection, if this
* connection has been closed, then this method returns ""
* @return Client Id String
*/
virtual std::string getClientId(void) const {
return properties.getProperty(
commands::CommandConstants::toString(
commands::CommandConstants::HEADER_CLIENT_ID ), "" );
}
virtual std::string getLogin(void) const {
return properties.getProperty(
commands::CommandConstants::toString(
commands::CommandConstants::HEADER_LOGIN ), "" );
}
virtual std::string getPassword(void) const {
return properties.getProperty(
commands::CommandConstants::toString(
commands::CommandConstants::HEADER_PASSWORD ), "" );
}
/**
* Gets a reference to the Transport that this connection
* is using.
* @param reference to a transport
* @throws InvalidStateException if the Transport is not set
*/
virtual transport::Transport& getTransport(void) const
throw (exceptions::InvalidStateException ) {
if( transport == NULL ) {
throw exceptions::InvalidStateException(
__FILE__, __LINE__,
"StompConnector::getTransport - "
"Invalid State, No Transport.");
}
return *transport;
}
/**
* Creates a Session Info object for this connector
* @param Acknowledgement Mode of the Session
* @returns Session Info Object
* @throws ConnectorException
*/
virtual SessionInfo* createSession(
cms::Session::AcknowledgeMode ackMode)
throw( ConnectorException );
/**
* Create a Consumer for the given Session
* @param Destination to Subscribe to.
* @param Session Information.
* @return Consumer Information
* @throws ConnectorException
*/
virtual ConsumerInfo* createConsumer(
cms::Destination* destination,
SessionInfo* session,
const std::string& selector = "")
throw ( ConnectorException );
/**
* Create a Durable Consumer for the given Session
* @param Topic to Subscribe to.
* @param Session Information.
* @param name of the Durable Topic
* @param Selector
* @param if set, inhibits the delivery of messages
* published by its own connection
* @return Consumer Information
* @throws ConnectorException
*/
virtual ConsumerInfo* createDurableConsumer(
cms::Topic* topic,
SessionInfo* session,
const std::string& name,
const std::string& selector = "",
bool noLocal = false)
throw ( ConnectorException );
/**
* Create a Consumer for the given Session
* @param Destination to Subscribe to.
* @param Session Information.
* @return Producer Information
* @throws ConnectorException
*/
virtual ProducerInfo* createProducer(
cms::Destination* destination,
SessionInfo* session)
throw ( ConnectorException );
/**
* Creates a Topic given a name and session info
* @param Topic Name
* @param Session Information
* @return a newly created Topic Object
* @throws ConnectorException
*/
virtual cms::Topic* createTopic( const std::string& name,
SessionInfo* session )
throw ( ConnectorException );
/**
* Creates a Queue given a name and session info
* @param Queue Name
* @param Session Information
* @return a newly created Queue Object
* @throws ConnectorException
*/
virtual cms::Queue* createQueue( const std::string& name,
SessionInfo* session )
throw ( ConnectorException );
/**
* Creates a Temporary Topic given a name and session info
* @param Temporary Topic Name
* @param Session Information
* @return a newly created Temporary Topic Object
* @throws ConnectorException
*/
virtual cms::TemporaryTopic* createTemporaryTopic(
SessionInfo* session)
throw ( ConnectorException );
/**
* Creates a Temporary Queue given a name and session info
* @param Temporary Queue Name
* @param Session Information
* @return a newly created Temporary Queue Object
* @throws ConnectorException
*/
virtual cms::TemporaryQueue* createTemporaryQueue(
SessionInfo* session)
throw ( ConnectorException );
/**
* Sends a Message
* @param The Message to send.
* @param Producer Info for the sender of this message
* @throws ConnectorException
*/
virtual void send( cms::Message* message, ProducerInfo* producerInfo )
throw ( ConnectorException );
/**
* Sends a set of Messages
* @param List of Messages to send.
* @param Producer Info for the sender of this message
* @throws ConnectorException
*/
virtual void send( std::list<cms::Message*>& messages,
ProducerInfo* producerInfo )
throw ( ConnectorException );
/**
* Acknowledges a Message
* @param An ActiveMQMessage to Ack.
* @throws ConnectorException
*/
virtual void acknowledge( const SessionInfo* session,
const cms::Message* message,
AckType ackType)
throw ( ConnectorException );
/**
* Starts a new Transaction.
* @param Session Information
* @throws ConnectorException
*/
virtual TransactionInfo* startTransaction(
SessionInfo* session)
throw ( ConnectorException );
/**
* Commits a Transaction.
* @param The Transaction information
* @param Session Information
* @throws ConnectorException
*/
virtual void commit(TransactionInfo* transaction,
SessionInfo* session)
throw ( ConnectorException );
/**
* Rolls back a Transaction.
* @param The Transaction information
* @param Session Information
* @throws ConnectorException
*/
virtual void rollback(TransactionInfo* transaction,
SessionInfo* session)
throw ( ConnectorException );
/**
* Creates a new Message.
* @param Session Information
* @param Transaction Info for this Message
* @throws ConnectorException
*/
virtual cms::Message* createMessage(
SessionInfo* session,
TransactionInfo* transaction)
throw ( ConnectorException );
/**
* Creates a new BytesMessage.
* @param Session Information
* @param Transaction Info for this Message
* @throws ConnectorException
*/
virtual cms::BytesMessage* createBytesMessage(
SessionInfo* session,
TransactionInfo* transaction)
throw ( ConnectorException );
/**
* Creates a new TextMessage.
* @param Session Information
* @param Transaction Info for this Message
* @throws ConnectorException
*/
virtual cms::TextMessage* createTextMessage(
SessionInfo* session,
TransactionInfo* transaction)
throw ( ConnectorException );
/**
* Creates a new MapMessage.
* @param Session Information
* @param Transaction Info for this Message
* @throws ConnectorException
*/
virtual cms::MapMessage* createMapMessage(
SessionInfo* session,
TransactionInfo* transaction)
throw ( ConnectorException );
/**
* Unsubscribe from a givenDurable Subscription
* @param name of the Subscription
* @throws ConnectorException
*/
virtual void unsubscribe( const std::string& name )
throw ( ConnectorException );
/**
* Destroys the given connector resource.
* @param resource the resource to be destroyed.
* @throws ConnectorException
*/
virtual void destroyResource( ConnectorResource* resource )
throw ( ConnectorException );
/**
* Sets the listener of consumer messages.
* @param listener the observer.
*/
virtual void setConsumerMessageListener(
ConsumerMessageListener* listener)
{
this->messageListener = listener;
if(sessionManager != NULL)
{
sessionManager->setConsumerMessageListener( listener );
}
}
/**
* Sets the Listner of exceptions for this connector
* @param ExceptionListener the observer.
*/
virtual void setExceptionListener(
cms::ExceptionListener* listener)
{
this->exceptionListener = listener;
}
public: // transport::CommandListener
/**
* Event handler for the receipt of a non-response command from the
* transport.
* @param command the received command object.
*/
virtual void onCommand( transport::Command* command );
public: // TransportExceptionListener
/**
* Event handler for an exception from a command transport.
* @param source The source of the exception
* @param ex The exception.
*/
virtual void onTransportException(
transport::Transport* source,
const exceptions::ActiveMQException& ex );
public: // StompCommandListener
/**
* Process the Stomp Command
* @param command to process
* @throw ConnterException
*/
virtual void onStompCommand( commands::StompCommand* command )
throw ( StompConnectorException );
public:
/**
* Registers a Command Listener using the CommandId specified
* if there is already a listener for that command it will be
* removed.
* @param CommandId to process
* @param pointer to the listener to call
*/
virtual void addCmdListener(
commands::CommandConstants::CommandId commandId,
StompCommandListener* listener );
/**
* UnRegisters a Command Listener using the CommandId specified
* @param CommandId of the listener to remove.
*/
virtual void removeCmdListener(
commands::CommandConstants::CommandId commandId );
private:
unsigned int getNextProducerId( void );
unsigned int getNextTransactionId( void );
// Check for Connected State and Throw an exception if not.
void enforceConnected( void ) throw ( ConnectorException );
};
}}}
#endif /*ACTIVEMQ_CONNECTOR_STOMP_STOMPCONNECTOR_H_*/

View File

@ -0,0 +1,65 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#ifndef ACTIVEMQ_CONNECTOR_STOMP_STOMPCONNECTOREXCEPTION_H_
#define ACTIVEMQ_CONNECTOR_STOMP_STOMPCONNECTOREXCEPTION_H_
#include <activemq/connector/ConnectorException.h>
namespace activemq{
namespace connector{
namespace stomp{
/*
* Signals that an Connector exception of some sort has occurred.
*/
class StompConnectorException : public connector::ConnectorException
{
public:
StompConnectorException() {}
StompConnectorException( const exceptions::ActiveMQException& ex ){
*(ActiveMQException*)this = ex;
}
StompConnectorException( const StompConnectorException& ex ){
*(exceptions::ActiveMQException*)this = ex;
}
StompConnectorException(const char* file, const int lineNumber,
const char* msg, ...)
{
va_list vargs ;
va_start(vargs, msg) ;
buildMessage(msg, vargs) ;
// Set the first mark for this exception.
setMark( file, lineNumber );
}
/**
* Clones this exception. This is useful for cases where you need
* to preserve the type of the original exception as well as the message.
* All subclasses should override.
*/
virtual exceptions::ActiveMQException* clone() const{
return new StompConnectorException( *this );
}
virtual ~StompConnectorException() {}
};
}}}
#endif /*ACTIVEMQ_CONNECTOR_STOMP_STOMPCONNECTOREXCEPTION_H_*/

View File

@ -0,0 +1,49 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#include <activemq/connector/stomp/StompConnectorFactory.h>
#include <activemq/connector/stomp/StompConnector.h>
#include <activemq/connector/Connector.h>
#include <activemq/transport/Transport.h>
using namespace activemq;
using namespace activemq::util;
using namespace activemq::transport;
using namespace activemq::connector;
using namespace activemq::connector::stomp;
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
Connector* StompConnectorFactory::createConnector(
const activemq::util::Properties& properties,
activemq::transport::Transport* transport)
{
return dynamic_cast<Connector*>(
new StompConnector(transport, properties));
}
////////////////////////////////////////////////////////////////////////////////
ConnectorFactory& StompConnectorFactory::getInstance(void)
{
// Create a static instance of the registrar and return a reference to
// its internal instance of this class.
static ConnectorFactoryMapRegistrar registrar(
"stomp", new StompConnectorFactory());
return registrar.getFactory();
}

View File

@ -0,0 +1,54 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#ifndef ACTIVEMQ_CONNECTOR_STOMP_STOMPCONNECTORFACTORY_H_
#define ACTIVEMQ_CONNECTOR_STOMP_STOMPCONNECTORFACTORY_H_
#include <activemq/connector/ConnectorFactory.h>
#include <activemq/connector/ConnectorFactoryMapRegistrar.h>
namespace activemq{
namespace connector{
namespace stomp{
class StompConnectorFactory : public connector::ConnectorFactory
{
private:
public:
virtual ~StompConnectorFactory(void) {}
/**
* Creates a StompConnector
* @param The Properties that the new connector is configured with
*/
virtual Connector* createConnector(
const activemq::util::Properties& properties,
activemq::transport::Transport* transport);
/**
* Returns an instance of this Factory by reference
* @return StompConnectorFactory reference
*/
static ConnectorFactory& getInstance(void);
};
}}}
#endif /*ACTIVEMQ_CONNECTOR_STOMP_STOMPCONNECTORFACTORY_H_*/

View File

@ -0,0 +1,118 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#ifndef _ACTIVEMQ_CONNECTOR_STOMP_STOMPCONSUMERINFO_H_
#define _ACTIVEMQ_CONNECTOR_STOMP_STOMPCONSUMERINFO_H_
namespace activemq{
namespace connector{
namespace stomp{
class StompConsumerInfo : public ConsumerInfo
{
private:
// Message Selector for this Consumer
std::string selector;
// Consumer Id
unsigned int consumerId;
// Destination
cms::Destination* destination;
// Session Info - We do not own this
const SessionInfo* session;
public:
StompConsumerInfo(void) {
selector = "";
consumerId = 0;
destination = NULL;
}
virtual ~StompConsumerInfo(void) { delete destination; }
/**
* Gets this message consumer's message selector expression.
* @return This Consumer's selector expression or "".
*/
virtual const std::string& getMessageSelector(void) const {
return selector;
}
/**
* Sets this message consumer's message selector expression.
* @param This Consumer's selector expression or "".
*/
virtual void setMessageSelector( const std::string& selector ) {
this->selector = selector;
}
/**
* Gets the ID that is assigned to this consumer
* @return value of the Consumer Id.
*/
virtual unsigned int getConsumerId(void) const {
return consumerId;
}
/**
* Sets the ID that is assigned to this consumer
* @return string value of the Consumer Id.
*/
virtual void setConsumerId( const unsigned int id ) {
this->consumerId = id;
}
/**
* Gets the Destination that this Consumer is subscribed on
* @return Destination
*/
virtual const cms::Destination& getDestination(void) const {
return *destination;
}
/**
* Sets the destination that this Consumer is listening on
* @param Destination
*/
virtual void setDestination( const cms::Destination& destination ) {
this->destination = destination.clone();
}
/**
* Gets the Session Info that this consumer is attached too
* @return SessionnInfo pointer
*/
virtual const SessionInfo* getSessionInfo(void) const {
return session;
}
/**
* Gets the Session Info that this consumer is attached too
* @return SessionnInfo pointer
*/
virtual void setSessionInfo( const SessionInfo* session ) {
this->session = session;
}
};
}}}
#endif /*_ACTIVEMQ_CONNECTOR_STOMP_STOMPCONSUMERINFO_H_*/

View File

@ -0,0 +1,106 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#ifndef _ACTIVEMQ_CONNECTOR_STOMP_STOMPDESTINATION_H_
#define _ACTIVEMQ_CONNECTOR_STOMP_STOMPDESTINATION_H_
#include <string>
#include <cms/Destination.h>
namespace activemq{
namespace connector{
namespace stomp{
/**
* Templatized Destination Class that bundles all the common aspects
* of a Stomp Destination into one class. The template arguement is
* one of Topic, Queue, TemporaryTopic, or TemporaryQueue.
*/
template <typename T>
class StompDestination : public T
{
private:
// Destination type
cms::Destination::DestinationType destType;
// Name of the Destination
std::string name;
public:
StompDestination(void) {}
StompDestination( const std::string& name,
cms::Destination::DestinationType type )
{
this->name = name;
this->destType = type;
}
virtual ~StompDestination(void) {}
/**
* Retrieves the name of this destination, plus the stomp
* destination decorator
* @return name
*/
virtual std::string toProviderString(void) const {
return getPrefix() + name;
}
/**
* Retrieve the Destination Type for this Destination
* @return The Destination Type
*/
virtual cms::Destination::DestinationType getDestinationType(void) const {
return destType;
}
/**
* Converts the Destination Name into a String minus the
* stomp decorator
* @return string name
*/
virtual std::string toString(void) const {
return name;
}
/**
* Copies the contents of the given Destinastion object to this one.
* @param source The source Destination object.
*/
virtual void copy( const cms::Destination& source ) {
this->destType = source.getDestinationType();
this->name = source.toString();
}
protected:
/**
* Retrieves the proper Stomp Prefix for the specified type
* of Destination
* @return string prefix
*/
virtual std::string getPrefix(void) const = 0;
};
}}}
#endif /*_ACTIVEMQ_CONNECTOR_STOMP_STOMPDESTINATION_H_*/

View File

@ -0,0 +1,127 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#ifndef ACTIVEMQ_CONNECTOR_STOMP_STOMPFRAMEWRAPPER_H_
#define ACTIVEMQ_CONNECTOR_STOMP_STOMPFRAMEWRAPPER_H_
#include <string>
#include <map>
#include <activemq/util/SimpleProperties.h>
namespace activemq{
namespace connector{
namespace stomp{
/**
* A Stomp-level message frame that encloses all messages
* to and from the broker.
*/
class StompFrame{
public:
/**
* Default constructor.
*/
StompFrame(void){
body = NULL;
bodyLength = 0;
}
/**
* Destruction - frees the memory pool.
*/
virtual ~StompFrame(void) { delete body; }
/**
* Clonse this message exactly, returns a new instance that the
* caller is required to delete.
* @return new copy of this message
*/
virtual StompFrame* clone(void) const {
StompFrame* frame = new StompFrame();
frame->command = command;
frame->properties = properties;
char* cpyBody = new char[bodyLength];
memcpy(cpyBody, body, bodyLength);
frame->setBody(cpyBody, bodyLength);
return frame;
}
/**
* Sets the command for this stomp frame.
* @param command The command to be set.
*/
void setCommand( const std::string& cmd ){
this->command = cmd;
}
/**
* Accessor for this frame's command field.
*/
const std::string& getCommand(void) const{
return command;
}
/**
* Gets access to the header properties for this frame.
*/
util::Properties& getProperties(void){ return properties; }
const util::Properties& getProperties(void) const {
return properties;
}
/**
* Accessor for the body data of this frame.
* @return char pointer to body data
*/
const char* getBody(void) const{
return body;
}
/**
* Return the number of bytes contained in this frames body
* @return Body bytes length.
*/
int getBodyLength(void) const{ return bodyLength; }
/**
* Sets the body data of this frame as a byte sequence.
* @param bytes The byte buffer to be set in the body.
* @param numBytes The number of bytes in the buffer.
*/
void setBody( const char* bytes, const int numBytes ){
body = bytes;
bodyLength = numBytes;
}
private:
// String Name of this command.
std::string command;
// Properties of the Stomp Message
util::SimpleProperties properties;
// Byte data of Body.
const char* body;
int bodyLength;
};
}}}
#endif /*ACTIVEMQ_CONNECTOR_STOMP_STOMPFRAMEWRAPPER_H_*/

View File

@ -0,0 +1,99 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#ifndef _ACTIVEMQ_CONNECTOR_STOMP_STOMPPRODUCERINFO_H_
#define _ACTIVEMQ_CONNECTOR_STOMP_STOMPPRODUCERINFO_H_
#include <activemq/connector/ProducerInfo.h>
#include <cms/Destination.h>
namespace activemq{
namespace connector{
namespace stomp{
class StompProducerInfo : public ProducerInfo
{
private:
// Producer Id
unsigned int producerId;
// Default Destination
cms::Destination* dest;
// Session that this producer is attached to - we do not own this
const SessionInfo* session;
public:
StompProducerInfo(void) { dest = NULL; }
virtual ~StompProducerInfo(void) { delete dest; }
/**
* Retrieves the default destination that this producer
* sends its messages to.
* @return Destionation, owned by this object
*/
virtual const cms::Destination& getDestination(void) const {
return *dest;
}
/**
* Sets the Default Destination for this Producer
* @param reference to a destination, copied internally
*/
virtual void setDestination( const cms::Destination& dest ) {
this->dest = dest.clone();
}
/**
* Gets the ID that is assigned to this Producer
* @return value of the Producer Id.
*/
virtual unsigned int getProducerId(void) const {
return producerId;
}
/**
* Sets the ID that is assigned to this Producer
* @return string value of the Producer Id.
*/
virtual void setProducerId( const unsigned int id ) {
this->producerId = id;
}
/**
* Gets the Session Info that this consumer is attached too
* @return SessionnInfo pointer
*/
virtual const SessionInfo* getSessionInfo(void) const {
return session;
}
/**
* Gets the Session Info that this consumer is attached too
* @return SessionnInfo pointer
*/
virtual void setSessionInfo( const SessionInfo* session ) {
this->session = session;
}
};
}}}
#endif /*_ACTIVEMQ_CONNECTOR_STOMP_STOMPPRODUCERINFO_H_*/

View File

@ -0,0 +1,74 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#ifndef _ACTIVEMQ_CONNECTOR_STOMP_STOMPQUEUE_H_
#define _ACTIVEMQ_CONNECTOR_STOMP_STOMPQUEUE_H_
#include <activemq/connector/stomp/StompDestination.h>
#include <activemq/connector/stomp/commands/CommandConstants.h>
#include <cms/Queue.h>
namespace activemq{
namespace connector{
namespace stomp{
class StompQueue : public StompDestination<cms::Queue>
{
public:
StompQueue(void) : StompDestination< cms::Queue >() {}
StompQueue(const std::string& name) :
StompDestination< cms::Queue >( name, cms::Destination::QUEUE )
{}
virtual ~StompQueue(void) {}
/**
* Gets the name of this queue.
* @return The queue name.
*/
virtual std::string getQueueName(void) const
throw( cms::CMSException ) {
return toString();
}
/**
* Creates a new instance of this destination type that is a
* copy of this one, and returns it.
* @returns cloned copy of this object
*/
virtual cms::Destination* clone(void) const {
return new StompQueue( toString() );
}
protected:
/**
* Retrieves the proper Stomp Prefix for the specified type
* of Destination
* @return string prefix
*/
virtual std::string getPrefix(void) const {
return commands::CommandConstants::queuePrefix;
}
};
}}}
#endif /*_ACTIVEMQ_CONNECTOR_STOMP_STOMPQUEUE_H_*/

View File

@ -0,0 +1,31 @@
#ifndef ACTIVEMQ_CONNECTOR_STOMP_STOMPSELECTOR_H_
#define ACTIVEMQ_CONNECTOR_STOMP_STOMPSELECTOR_H_
#include <cms/Message.h>
#include <string>
namespace activemq{
namespace connector{
namespace stomp{
/**
* Since the stomp protocol doesn't have a consumer-based selector
* mechanism, we have to do the selector logic on the client
* side. This class provides the selector algorithm that is
* needed to determine if a given message is to be selected for
* a given consumer's selector string.
*/
class StompSelector{
public:
static bool isSelected( const std::string& selector,
cms::Message* msg )
{
return true;
}
};
}}}
#endif /*ACTIVEMQ_CONNECTOR_STOMP_STOMPSELECTOR_H_*/

View File

@ -0,0 +1,134 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#ifndef _ACTIVEMQ_CONNECTOR_STOMP_STOMPSESSIONINFO_H_
#define _ACTIVEMQ_CONNECTOR_STOMP_STOMPSESSIONINFO_H_
#include <activemq/connector/SessionInfo.h>
#include <cms/Session.h>
#include <string>
namespace activemq{
namespace connector{
namespace stomp{
class StompSessionInfo : public connector::SessionInfo
{
private:
// Acknowledge Mode of this Session
cms::Session::AcknowledgeMode ackMode;
// The id of the connection to the broker
// (given to us by the broker)
std::string connectionId;
// The unique session id
unsigned int sessionId;
// Info for this sessions current transaction
const TransactionInfo* transaction;
public:
/**
* Constructor
*/
StompSessionInfo(void)
{
sessionId = 0;
ackMode = cms::Session::AutoAcknowledge;
}
/**
* Destructor
*/
virtual ~StompSessionInfo(void) {}
/**
* Gets the Connection Id of the Connection that this consumer is
* using to receive its messages.
* @return string value of the connection id
*/
virtual const std::string& getConnectionId(void) const{
return connectionId;
}
/**
* Sets the Connection Id of the Connection that this consumer is
* using to receive its messages.
* @param string value of the connection id
*/
virtual void setConnectionId( const std::string& id ){
connectionId = id;
}
/**
* Gets the Sessions Id value
* @return id for this session
*/
virtual unsigned int getSessionId(void) const {
return sessionId;
}
/**
* Sets the Session Id for this Session
* @param integral id value for this session
*/
virtual void setSessionId( const unsigned int id ) {
this->sessionId = id;
}
/**
* Sets the Ack Mode of this Session Info object
* @param Ack Mode
*/
virtual void setAckMode(cms::Session::AcknowledgeMode ackMode) {
this->ackMode = ackMode;
}
/**
* Gets the Ack Mode of this Session
* @return Ack Mode
*/
virtual cms::Session::AcknowledgeMode getAckMode(void) const {
return ackMode;
}
/**
* Gets the currently active transaction info, if this session is
* transacted, returns NULL when not transacted. You must call
* getAckMode and see if the session is transacted.
* @return Transaction Id of current Transaction
*/
virtual const TransactionInfo* getTransactionInfo(void) const {
return transaction;
}
/**
* Sets the current transaction info for this session, this is nit
* used when the session is not transacted.
* @param Transaction Id
*/
virtual void setTransactionInfo( const TransactionInfo* transaction ) {
this->transaction = transaction;
}
};
}}}
#endif /*_ACTIVEMQ_CONNECTOR_STOMP_STOMPSESSIONINFO_H_*/

View File

@ -0,0 +1,326 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#include "StompSessionManager.h"
#include <activemq/core/ActiveMQMessage.h>
#include <activemq/concurrent/Concurrent.h>
#include <activemq/connector/stomp/StompSessionInfo.h>
#include <activemq/connector/stomp/StompConsumerInfo.h>
#include <activemq/connector/stomp/commands/SubscribeCommand.h>
#include <activemq/connector/stomp/commands/UnsubscribeCommand.h>
#include <activemq/connector/stomp/StompSelector.h>
using namespace std;
using namespace activemq;
using namespace activemq::core;
using namespace activemq::exceptions;
using namespace activemq::transport;
using namespace activemq::connector;
using namespace activemq::connector::stomp;
using namespace activemq::connector::stomp::commands;
////////////////////////////////////////////////////////////////////////////////
StompSessionManager::StompSessionManager( const std::string& connectionId,
Transport* transport )
{
if( transport == NULL )
{
throw NullPointerException(
__FILE__, __LINE__,
"StompSessionManager::StompSessionManager" );
}
this->transport = transport;
this->connectionId = connectionId;
this->nextSessionId = 0;
this->nextConsumerId = 0;
this->messageListener = NULL;
}
////////////////////////////////////////////////////////////////////////////////
StompSessionManager::~StompSessionManager(void)
{
// NOTE - I am not cleaning out the ConsumerInfo objects in the
// map becaise it is really the job of the consumer ot remove itself
// when it is destructed. If it doesn't then we would have problems,
// but if it does, but it's deleted after this object then we would
// still have problems.
}
////////////////////////////////////////////////////////////////////////////////
unsigned int StompSessionManager::getNextSessionId(void)
{
synchronized(&mutex)
{
return nextSessionId++;
}
return 0;
}
////////////////////////////////////////////////////////////////////////////////
unsigned int StompSessionManager::getNextConsumerId(void)
{
synchronized(&mutex)
{
return nextConsumerId++;
}
return 0;
}
////////////////////////////////////////////////////////////////////////////////
connector::SessionInfo* StompSessionManager::createSession(
cms::Session::AcknowledgeMode ackMode)
throw ( exceptions::ActiveMQException )
{
try
{
SessionInfo* session = new StompSessionInfo();
// Init data
session->setAckMode(ackMode);
session->setConnectionId( connectionId );
session->setSessionId( getNextSessionId() );
return session;
}
AMQ_CATCH_RETHROW( ActiveMQException )
AMQ_CATCHALL_THROW( ActiveMQException )
}
////////////////////////////////////////////////////////////////////////////////
void StompSessionManager::removeSession(
connector::SessionInfo* session )
throw ( exceptions::ActiveMQException )
{
// NO-op
}
////////////////////////////////////////////////////////////////////////////////
connector::ConsumerInfo* StompSessionManager::createConsumer(
cms::Destination* destination,
SessionInfo* session,
const std::string& selector)
throw( ConnectorException )
{
try
{
// Delegate to the createDurableConsumer method, just pas the
// appropriate params so that a regular consumer is created on
// the broker side.
return createDurableConsumer(
destination, session, "", selector, false );
}
AMQ_CATCH_RETHROW( ConnectorException )
AMQ_CATCHALL_THROW( ConnectorException )
}
////////////////////////////////////////////////////////////////////////////////
connector::ConsumerInfo* StompSessionManager::createDurableConsumer(
cms::Destination* destination,
SessionInfo* session,
const std::string& name,
const std::string& selector,
bool noLocal )
throw ( ConnectorException )
{
try
{
synchronized(&mutex)
{
// Find the right mapping to consumers
ConsumerMap& consumerMap =
destinationMap[ destination->toString() ];
// We only need to send a sub request if there are no active
// consumers on this destination.
if( consumerMap.empty() )
{
// Send the request to the Broker
SubscribeCommand cmd;
if( session->getAckMode() == cms::Session::ClientAcknowledge )
{
cmd.setAckMode( CommandConstants::ACK_CLIENT );
}
cmd.setDestination( destination->toProviderString() );
cmd.setNoLocal( noLocal );
if( name != "" )
{
cmd.setSubscriptionName( name );
}
// The Selector is set on the first subscribe on this dest,
// and if another consumer is created on this destination
// that specifies a selector it will be ignored. While
// this is not ideal, is the only way to handle the fact
// that activemq stomp doesn't support multiple sessions.
if( selector != "" )
{
cmd.setMessageSelector( selector );
}
// Fire the message
transport->oneway( &cmd );
}
// Initialize a new Consumer info Message
ConsumerInfo* consumer = new StompConsumerInfo();
consumer->setConsumerId( getNextConsumerId() );
consumer->setDestination( *destination );
consumer->setMessageSelector( selector );
consumer->setSessionInfo( session );
// Store this consumer for later message dispatching.
consumerMap.insert(
make_pair( consumer->getConsumerId(), consumer ) );
return consumer;
}
return NULL;
}
AMQ_CATCH_RETHROW( ConnectorException )
AMQ_CATCHALL_THROW( ConnectorException )
}
////////////////////////////////////////////////////////////////////////////////
void StompSessionManager::removeConsumer(
connector::ConsumerInfo* consumer)
throw( ConnectorException )
{
try
{
synchronized(&mutex)
{
DestinationMap::iterator itr =
destinationMap.find( consumer->getDestination().toString() );
if( itr == destinationMap.end() )
{
// Already removed from the map
return;
}
ConsumerMap& consumers = itr->second;
// Remove from the map.
consumers.erase( consumer->getConsumerId() );
// If there are no more on this destination then we unsubscribe
if( consumers.empty() )
{
UnsubscribeCommand cmd;
cmd.setDestination(
consumer->getDestination().toProviderString() );
// Send the message
transport->oneway( &cmd );
}
}
}
AMQ_CATCH_RETHROW( ConnectorException )
AMQ_CATCHALL_THROW( ConnectorException )
}
////////////////////////////////////////////////////////////////////////////////
void StompSessionManager::onStompCommand( commands::StompCommand* command )
throw ( StompConnectorException )
{
try
{
cms::Message* message = dynamic_cast< cms::Message*>( command );
if( message == NULL )
{
throw StompConnectorException(
__FILE__, __LINE__,
"StompSessionManager::onStompCommand - Invalid Command" );
}
if( messageListener == NULL )
{
throw StompConnectorException(
__FILE__, __LINE__,
"StompSessionManager::onStompCommand - "
"No Message Listener Registered." );
}
synchronized(&mutex)
{
DestinationMap::iterator itr =
destinationMap.find( message->getCMSDestination().toString() );
if( itr == destinationMap.end() )
{
throw StompConnectorException(
__FILE__, __LINE__,
"StompSessionManager::onStompCommand - "
"Received a Message that doesn't have a listener" );
}
// If we only have 1 consumer, we don't need to clone the original
// message.
if(itr->second.size() == 1)
{
ConsumerInfo* consumerInfo = itr->second.begin()->second;
if( StompSelector::isSelected(
consumerInfo->getMessageSelector(),
message ) )
{
ActiveMQMessage* msg =
dynamic_cast< ActiveMQMessage* >( message );
messageListener->onConsumerMessage( consumerInfo, msg );
}
return;
}
// We have more than one consumer of this message - we have to
// clone the message for each consumer so they don't destroy each other's
// message.
ConsumerMap::iterator c_itr = itr->second.begin();
for(; c_itr != itr->second.end(); ++c_itr )
{
ConsumerInfo* consumerInfo = c_itr->second;
if( StompSelector::isSelected(
consumerInfo->getMessageSelector(),
message ) )
{
ActiveMQMessage* msg =
dynamic_cast< ActiveMQMessage* >( message->clone() );
messageListener->onConsumerMessage( consumerInfo, msg );
}
}
// We got here which means that we sent copies, so remove
// the original.
delete command;
}
}
AMQ_CATCH_RETHROW( StompConnectorException )
AMQ_CATCH_EXCEPTION_CONVERT( ActiveMQException, StompConnectorException )
AMQ_CATCHALL_THROW( StompConnectorException )
}

View File

@ -0,0 +1,185 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#ifndef _ACTIVEMQ_CONNECTOR_STOMP_STOMPSESSIONMANAGER_H_
#define _ACTIVEMQ_CONNECTOR_STOMP_STOMPSESSIONMANAGER_H_
#include <activemq/connector/SessionInfo.h>
#include <activemq/connector/ConsumerInfo.h>
#include <activemq/transport/Transport.h>
#include <activemq/concurrent/Mutex.h>
#include <activemq/connector/ConnectorException.h>
#include <activemq/connector/stomp/StompCommandListener.h>
#include <activemq/connector/ConsumerMessageListener.h>
namespace activemq{
namespace connector{
namespace stomp{
/**
* The Stomp Session Manager is responsible for managing multiple
* Client Sessions. The management involves routing messages to
* sessions. If more than one ActiveMQConsumer is created that is
* listening to the same Topic or Queue, then the messages that are
* received must be delivered to each of those sessions, and copied
* so that a transactional session can manage the lifetime of the
* message.
*/
class StompSessionManager : public StompCommandListener
{
private:
// Map Types
typedef std::map<unsigned int, ConsumerInfo*> ConsumerMap;
typedef std::map<std::string, ConsumerMap> DestinationMap;
private:
// Next id to be used for a Session Id
unsigned int nextSessionId;
// Next id to be used for a Consumer Id
unsigned int nextConsumerId;
// Mutex to protect ids.
concurrent::Mutex mutex;
// Mapping of a Session to all the consumer's
DestinationMap destinationMap;
// Transport that we use to find a transport for sending
// commands
transport::Transport* transport;
// Consumer Message listener, we notify this whenever we receive
// a new StompMessage type command.
ConsumerMessageListener* messageListener;
// The global connection id
std::string connectionId;
public:
StompSessionManager( const std::string& connectionId,
transport::Transport* transport );
virtual ~StompSessionManager(void);
/**
* Creates a new Session and returns a SessionInfo object whose
* lifetime is the property of the caller.
* @param the ackMode of the session.
* @return new SessionInfo object
*/
virtual connector::SessionInfo* createSession(
cms::Session::AcknowledgeMode ackMode)
throw ( exceptions::ActiveMQException );
/**
* removes the specified Session from the Manager, all data that
* is associated with session consumers is now lost. The session
* is not deleted here, it is the owner's responsibility.
* @param the session info for the session to remove.
*/
virtual void removeSession( connector::SessionInfo* session )
throw ( exceptions::ActiveMQException );
/**
* Creates a new consumer to the specified session, will subscribe
* to the destination if another consumer hasn't already been
* subbed to that destination. The returned consumer is the
* owned by the caller and not deleted by this class.
* @param destination to subscribe to
* @param session to associate with
* @param selector string
* @return new ConsumerInfo object.
*/
virtual connector::ConsumerInfo* createConsumer(
cms::Destination* destination,
SessionInfo* session,
const std::string& selector)
throw( ConnectorException );
/**
* Creates a new durable consumer to the specified session, will
* subscribe to the destination if another consumer hasn't already
* been subbed to that destination. The returned consumer is the
* owned by the caller and not deleted by this class.
* @param Topic to subscribe to
* @param session to associate with
* @param Subscription Name
* @param selector string
* @param Should we be notified of messages we send.
* @return new ConsumerInfo object.
*/
virtual connector::ConsumerInfo* createDurableConsumer(
cms::Destination* destination,
SessionInfo* session,
const std::string& name,
const std::string& selector,
bool noLocal )
throw ( ConnectorException );
/**
* Removes the Consumer from the session, will unsubscrive if the
* consumer is the only one listeneing on this destination. The
* Consumer is not deleted, just unassociated from the Manager
* caller is responsible for managing the lifetime.
* @param the ConsumerInfo for the consumer to remove
* @throws ConnectorException
*/
virtual void removeConsumer( connector::ConsumerInfo* consumer )
throw( ConnectorException );
/**
* Sets the listener of consumer messages.
* @param listener the observer.
*/
virtual void setConsumerMessageListener(
ConsumerMessageListener* listener )
{
this->messageListener = listener;
}
public: // StompCommand Listener
/**
* Process the Stomp Command
* @param command to process
* @throw ConnterException
*/
virtual void onStompCommand( commands::StompCommand* command )
throw ( StompConnectorException );
protected:
/**
* Gets the Next Session Id
* @return unique session id
*/
virtual unsigned int getNextSessionId(void);
/**
* Gets the Next Session Id
* @return unique session id
*/
virtual unsigned int getNextConsumerId(void);
};
}}}
#endif /*_ACTIVEMQ_CONNECTOR_STOMP_STOMPSESSIONMANAGER_H_*/

View File

@ -0,0 +1,74 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#ifndef _ACTIVEMQ_CONNECTOR_STOMP_STOMPTOPIC_H_
#define _ACTIVEMQ_CONNECTOR_STOMP_STOMPTOPIC_H_
#include <activemq/connector/stomp/StompDestination.h>
#include <activemq/connector/stomp/commands/CommandConstants.h>
#include <cms/Topic.h>
namespace activemq{
namespace connector{
namespace stomp{
class StompTopic : public StompDestination<cms::Topic>
{
public:
StompTopic(void) : StompDestination<cms::Topic>() {}
StompTopic(const std::string& name) :
StompDestination< cms::Topic >( name, cms::Destination::TOPIC )
{}
virtual ~StompTopic(void) {}
/**
* Gets the name of this queue.
* @return The queue name.
*/
virtual std::string getTopicName(void) const
throw( cms::CMSException ) {
return toString();
}
/**
* Creates a new instance of this destination type that is a
* copy of this one, and returns it.
* @returns cloned copy of this object
*/
virtual cms::Destination* clone(void) const {
return new StompTopic( toString() );
}
protected:
/**
* Retrieves the proper Stomp Prefix for the specified type
* of Destination
* @return string prefix
*/
virtual std::string getPrefix(void) const {
return commands::CommandConstants::topicPrefix;
}
};
}}}
#endif /*_ACTIVEMQ_CONNECTOR_STOMP_STOMPTOPIC_H_*/

View File

@ -0,0 +1,88 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#ifndef ACTIVEMQ_CONNECTOR_STOMPTRANSACTIONINFO_H_
#define ACTIVEMQ_CONNECTOR_STOMPTRANSACTIONINFO_H_
#include <activemq/connector/TransactionInfo.h>
#include <activemq/connector/SessionInfo.h>
namespace activemq{
namespace connector{
namespace stomp{
class StompTransactionInfo : public connector::TransactionInfo
{
private:
// Transaction Id
unsigned int transactionId;
// Session Info - We do not own this
const SessionInfo* session;
public:
/**
* TransactionInfo Constructor
*/
StompTransactionInfo(void) {
transactionId = 0;
session = NULL;
}
/**
* Destructor
*/
virtual ~StompTransactionInfo(void) {}
/**
* Gets the Transction Id
* @return unsigned int Id
*/
virtual unsigned int getTransactionId(void) const {
return transactionId;
}
/**
* Sets the Transction Id
* @param unsigned int Id
*/
virtual void setTransactionId( const unsigned int id ) {
this->transactionId = id;
}
/**
* Gets the Session Info that this Transction is attached too
* @return SessionnInfo pointer
*/
virtual const SessionInfo* getSessionInfo(void) const {
return session;
}
/**
* Gets the Session Info that this Transction is attached too
* @return SessionnInfo pointer
*/
virtual void setSessionInfo( const SessionInfo* session ) {
this->session = session;
}
};
}}}
#endif /*ACTIVEMQ_CONNECTOR_STOMPTRANSACTIONINFO_H_*/

View File

@ -0,0 +1,85 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#ifndef _ACTIVEMQ_CONNECTOR_STOMP_COMMANDS_ABORTCOMMAND_H_
#define _ACTIVEMQ_CONNECTOR_STOMP_COMMANDS_ABORTCOMMAND_H_
#include <activemq/connector/stomp/commands/AbstractCommand.h>
#include <activemq/connector/stomp/commands/CommandConstants.h>
#include <activemq/transport/Command.h>
namespace activemq{
namespace connector{
namespace stomp{
namespace commands{
/**
* Represents the Stomp Abort Command which rolls back a
* transaction in progress.
*/
class AbortCommand : public AbstractCommand< transport::Command >
{
public:
AbortCommand(void) :
AbstractCommand<transport::Command>() {
initialize( getFrame() );
}
AbortCommand( StompFrame* frame ) :
AbstractCommand<transport::Command>(frame) {
validate( getFrame() );
}
virtual ~AbortCommand(void) {}
protected:
/**
* Inheritors are required to override this method to init the
* frame with data appropriate for the command type.
* @param Frame to init
*/
virtual void initialize( StompFrame& frame )
{
frame.setCommand( CommandConstants::toString(
CommandConstants::ABORT ) );
}
/**
* Inheritors are required to override this method to validate
* the passed stomp frame before it is marshalled or unmarshaled
* @param Frame to validate
* @returns true if frame is valid
*/
virtual bool validate( const StompFrame& frame ) const
{
if((frame.getCommand() ==
CommandConstants::toString( CommandConstants::ABORT ) ) &&
(frame.getProperties().hasProperty(
CommandConstants::toString(
CommandConstants::HEADER_TRANSACTIONID ) ) ) )
{
return true;
}
return false;
}
};
}}}}
#endif /*_ACTIVEMQ_CONNECTOR_STOMP_COMMANDS_ABORTCOMMAND_H_*/

View File

@ -0,0 +1,280 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#ifndef ACTIVEMQ_CONNECTOR_STOMP_COMMANDS_ABSTRACTCOMMAND_H_
#define ACTIVEMQ_CONNECTOR_STOMP_COMMANDS_ABSTRACTCOMMAND_H_
#include <activemq/connector/stomp/StompFrame.h>
#include <activemq/connector/stomp/commands/StompCommand.h>
#include <activemq/exceptions/NullPointerException.h>
#include <activemq/util/Integer.h>
#include <activemq/util/Long.h>
namespace activemq{
namespace connector{
namespace stomp{
namespace commands{
/**
* Interface for all Stomp commands. Commands wrap
* around a stomp frame and provide their own marshalling
* to and from frames. Stomp frame objects are dumb and have
* a generic interface that becomes cumbersome to use directly.
* Commands help to abstract the stomp frame by providing a
* more user-friendly interface to the frame content.
*/
template<typename T>
class AbstractCommand
:
public StompCommand,
public T
{
protected:
// Frame that contains the actual message
StompFrame* frame;
protected:
StompFrame& getFrame(void) {
if( frame == NULL ){
throw exceptions::NullPointerException(
__FILE__, __LINE__,
"AbstractCommand::getFrame - Frame not initialized");
}
return *frame;
}
const StompFrame& getFrame(void) const {
if( frame == NULL ){
throw exceptions::NullPointerException(
__FILE__, __LINE__,
"AbstractCommand::getFrame - Frame not initialized");
}
return *frame;
}
void destroyFrame(void)
{
if( frame != NULL ){
delete frame;
frame = NULL;
}
}
const char* getPropertyValue( const std::string& name ) const{
return getFrame().getProperties().getProperty( name );
}
const std::string getPropertyValue(
const std::string& name,
const std::string& defReturn ) const {
return getFrame().getProperties().getProperty(
name, defReturn );
}
void setPropertyValue( const std::string& name, const std::string& value ){
getFrame().getProperties().setProperty( name, value );
}
/**
* Inheritors are required to override this method to init the
* frame with data appropriate for the command type.
* @param Frame to init
*/
virtual void initialize( StompFrame& frame ) = 0;
/**
* Inheritors are required to override this method to validate
* the passed stomp frame before it is marshalled or unmarshaled
* @param Frame to validate
* @returns true if frame is valid
*/
virtual bool validate( const StompFrame& frame ) const = 0;
public:
AbstractCommand(void){
frame = new StompFrame;
}
AbstractCommand(StompFrame* frame){
this->frame = frame;
}
virtual ~AbstractCommand(void){
destroyFrame();
}
/**
* Sets the Command Id of this Message
* @param Command Id
*/
virtual void setCommandId( const unsigned int id ){
setPropertyValue(
CommandConstants::toString(
CommandConstants::HEADER_REQUESTID),
util::Integer::toString( id ) );
}
/**
* Gets the Command Id of this Message
* @return Command Id
*/
virtual unsigned int getCommandId(void) const {
return util::Integer::parseInt(
getPropertyValue(
CommandConstants::toString(
CommandConstants::HEADER_REQUESTID ),
"0" ) );
}
/**
* Set if this Message requires a Response
* @param true if response is required
*/
virtual void setResponseRequired( const bool required ) {
}
/**
* Is a Response required for this Command
* @return true if a response is required.
*/
virtual bool isResponseRequired(void) const {
return frame->getProperties().hasProperty(
CommandConstants::toString(
CommandConstants::HEADER_REQUESTID) );
}
/**
* Gets the Correlation Id that is associated with this message
* @return the Correlation Id
*/
virtual unsigned int getCorrelationId(void) const {
return util::Integer::parseInt(
getPropertyValue(
CommandConstants::toString(
CommandConstants::HEADER_RESPONSEID ),
"0" ) );
}
/**
* Sets the Correlation Id if this Command
* @param Id
*/
virtual void setCorrelationId( const unsigned int corrId ) {
setPropertyValue(
CommandConstants::toString(
CommandConstants::HEADER_RESPONSEID),
util::Integer::toString( corrId ) );
}
/**
* Get the Transaction Id of this Command
* @return the Id of the Transaction
*/
virtual const char* getTransactionId(void) const{
return getPropertyValue(
CommandConstants::toString(
CommandConstants::HEADER_TRANSACTIONID) );
}
/**
* Set the Transaction Id of this Command
* @param the Id of the Transaction
*/
virtual void setTransactionId( const std::string& id ){
setPropertyValue(
CommandConstants::toString(
CommandConstants::HEADER_TRANSACTIONID),
id );
}
/**
* Retrieve the Stomp Command Id for this message.
* @return Stomp CommandId enum
*/
virtual CommandConstants::CommandId getStompCommandId(void) const {
return CommandConstants::toCommandId(
getFrame().getCommand() );
}
/**
* Marshals the command to a stomp frame.
* @returns the stomp frame representation of this
* command.
* @throws MarshalException if the command is not
* in a state that can be marshaled.
*/
virtual const StompFrame& marshal(void) const
throw (marshal::MarshalException)
{
if( frame == NULL || !validate( *frame ) ){
throw marshal::MarshalException(
__FILE__, __LINE__,
"AbstractCommand::marshal() - frame invalid" );
}
return getFrame();
}
protected:
/**
* Fetch the number of bytes in the Stomp Frame Body
* @return number of bytes
*/
virtual unsigned long getNumBytes(void) const{
return getFrame().getBodyLength();
}
/**
* Returns a char array of bytes that are contained in the message
* @param pointer to array of bytes.
*/
virtual const char* getBytes(void) const{
return getFrame().getBody();
}
/**
* Set the bytes that are to be sent in the body of this message
* the content length flag indicates if the Content Length header
* should be set.
* @param bytes to store
* @param number of bytes to pull from the bytes buffer
* @param true if the content length header should be set
*/
virtual void setBytes( const char* bytes,
const unsigned long numBytes,
const bool setContentLength = true )
{
char* copy = new char[numBytes];
memcpy( copy, bytes, numBytes );
getFrame().setBody( copy, numBytes );
if( setContentLength )
{
setPropertyValue(
CommandConstants::toString(
CommandConstants::HEADER_CONTENTLENGTH),
util::Long::toString( numBytes ) );
}
}
};
}}}}
#endif /*ACTIVEMQ_CONNECTOR_STOMP_COMMANDS_ABSTRACTCOMMAND_H_*/

View File

@ -0,0 +1,113 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#ifndef _ACTIVEMQ_CONNCETOR_STOMP_COMMANDS_ACKCOMMAND_H_
#define _ACTIVEMQ_CONNCETOR_STOMP_COMMANDS_ACKCOMMAND_H_
#include <activemq/connector/stomp/commands/AbstractCommand.h>
#include <activemq/connector/stomp/commands/CommandConstants.h>
#include <activemq/transport/Command.h>
namespace activemq{
namespace connector{
namespace stomp{
namespace commands{
/**
* Stomp Command that Represents Acknowledgement of a message
* receive. The Ack Command has one required attribute, message
* Id. For each message sent to the client from the broker, the
* message will not be considered consumed until an Ack is sent.
* Optionally a Transaction Id can be set that indicates that the
* message acknowledgement should be part of a named transaction.
*/
class AckCommand : public AbstractCommand< transport::Command >
{
public:
AckCommand(void) :
AbstractCommand<transport::Command>() {
initialize( getFrame() );
}
AckCommand( StompFrame* frame ) :
AbstractCommand<transport::Command>(frame) {
validate( getFrame() );
}
virtual ~AckCommand(void) {}
/**
* Get the Message Id of this Command
* @return the Id of the Message
*/
virtual const char* getMessageId(void) const{
return getPropertyValue(
CommandConstants::toString(
CommandConstants::HEADER_MESSAGEID) );
}
/**
* Set the Message Id that this Ack is associated with
* @param the Message Id
*/
virtual void setMessageId(const std::string& messageId){
setPropertyValue(
CommandConstants::toString(
CommandConstants::HEADER_MESSAGEID),
messageId );
}
protected:
/**
* Inheritors are required to override this method to init the
* frame with data appropriate for the command type.
* @param Frame to init
*/
virtual void initialize( StompFrame& frame )
{
frame.setCommand( CommandConstants::toString(
CommandConstants::ACK ) );
}
/**
* Inheritors are required to override this method to validate
* the passed stomp frame before it is marshalled or unmarshaled
* @param Frame to validate
* @returns true if frame is valid
*/
virtual bool validate( const StompFrame& frame ) const
{
if((frame.getCommand() ==
CommandConstants::toString( CommandConstants::ACK )) &&
(frame.getProperties().hasProperty(
CommandConstants::toString(
CommandConstants::HEADER_TRANSACTIONID ) ) &&
(frame.getProperties().hasProperty(
CommandConstants::toString(
CommandConstants::HEADER_MESSAGEID ) ) ) ) );
{
return true;
}
return false;
}
};
}}}}
#endif /*_ACTIVEMQ_CONNCETOR_STOMP_COMMANDS_ACKCOMMAND_H_*/

View File

@ -0,0 +1,90 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#ifndef _ACTIVEMQ_CONNECTOR_STOMP_COMMANDS_BEGINCOMMAND_H_
#define _ACTIVEMQ_CONNECTOR_STOMP_COMMANDS_BEGINCOMMAND_H_
#include <activemq/connector/stomp/commands/AbstractCommand.h>
#include <activemq/connector/stomp/commands/CommandConstants.h>
#include <activemq/transport/Command.h>
namespace activemq{
namespace connector{
namespace stomp{
namespace commands{
/**
* Begins a Transaction. Transactions in this case apply to
* sending and acknowledging -- any messages sent or acknowledged
* during a transaction will be handled atomically based on the
* transaction.
*
* A transaction Identifier is required and this id will be used
* for all sends, commits, aborts, or acks.
*/
class BeginCommand : public AbstractCommand< transport::Command >
{
public:
BeginCommand(void) :
AbstractCommand<transport::Command>() {
initialize( getFrame() );
}
BeginCommand( StompFrame* frame ) :
AbstractCommand<transport::Command>(frame) {
validate( getFrame() );
}
virtual ~BeginCommand(void) {}
protected:
/**
* Inheritors are required to override this method to init the
* frame with data appropriate for the command type.
* @param Frame to init
*/
virtual void initialize( StompFrame& frame )
{
frame.setCommand( CommandConstants::toString(
CommandConstants::BEGIN ) );
}
/**
* Inheritors are required to override this method to validate
* the passed stomp frame before it is marshalled or unmarshaled
* @param Frame to validate
* @returns true if frame is valid
*/
virtual bool validate( const StompFrame& frame ) const
{
if((frame.getCommand() ==
CommandConstants::toString( CommandConstants::BEGIN )) &&
(frame.getProperties().hasProperty(
CommandConstants::toString(
CommandConstants::HEADER_TRANSACTIONID ) ) ) )
{
return true;
}
return false;
}
};
}}}}
#endif /*_ACTIVEMQ_CONNECTOR_STOMP_COMMANDS_BEGINCOMMAND_H_*/

View File

@ -0,0 +1,96 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#ifndef _ACTIVEMQ_CONNECTOR_STOMP_COMMANDS_BYTESMESSAGECOMMAND_H_
#define _ACTIVEMQ_CONNECTOR_STOMP_COMMANDS_BYTESMESSAGECOMMAND_H_
#include <cms/BytesMessage.h>
#include <activemq/connector/stomp/commands/StompMessage.h>
#include <activemq/connector/stomp/commands/CommandConstants.h>
namespace activemq{
namespace connector{
namespace stomp{
namespace commands{
/**
* Implements the interface for a cms::BytesMessage. Uses the template
* class StompMessage to implement all cms::Message type functionality
* and implements the BytesMessage interface here.
*/
class BytesMessageCommand : public StompMessage< cms::BytesMessage >
{
public:
BytesMessageCommand(void) :
StompMessage< cms::BytesMessage >() {
initialize( getFrame() );
}
BytesMessageCommand( StompFrame* frame ) :
StompMessage< cms::BytesMessage >(frame) {
validate( getFrame() );
}
virtual ~BytesMessageCommand(void) {}
/**
* Clonse this message exactly, returns a new instance that the
* caller is required to delete.
* @return new copy of this message
*/
virtual cms::Message* clone(void) const {
StompFrame* frame = getFrame().clone();
return new BytesMessageCommand( frame );
}
/**
* sets the bytes given to the message body.
* @param Byte Buffer to copy
* @param Number of bytes in Buffer to copy
* @throws CMSException
*/
virtual void setBodyBytes( const unsigned char* buffer,
const unsigned long numBytes )
throw( cms::CMSException ) {
this->setBytes(
reinterpret_cast<const char*>( buffer ), numBytes );
}
/**
* Gets the bytes that are contained in this message, user should
* copy this data into a user allocated buffer. Call
* <code>getBodyLength</code> to determine the number of bytes
* to expect.
* @return const pointer to a byte buffer
*/
virtual const unsigned char* getBodyBytes(void) const {
return reinterpret_cast<const unsigned char*>( this->getBytes() );
}
/**
* Returns the number of bytes contained in the body of this message.
* @return number of bytes.
*/
virtual unsigned long getBodyLength(void) const {
return this->getNumBytes();
}
};
}}}}
#endif /*_ACTIVEMQ_CONNECTOR_STOMP_COMMANDS_BYTESMESSAGECOMMAND_H_*/

View File

@ -0,0 +1,144 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#include "CommandConstants.h"
#include <stdio.h>
#include <activemq/connector/stomp/StompTopic.h>
#include <activemq/connector/stomp/StompQueue.h>
using namespace std;
using namespace activemq;
using namespace activemq::exceptions;
using namespace activemq::connector::stomp;
using namespace activemq::connector::stomp::commands;
////////////////////////////////////////////////////////////////////////////////
const char* CommandConstants::queuePrefix = "/queue/";
const char* CommandConstants::topicPrefix = "/topic/";
////////////////////////////////////////////////////////////////////////////////
string CommandConstants::StaticInitializer::stompHeaders[NUM_STOMP_HEADERS];
string CommandConstants::StaticInitializer::commands[NUM_COMMANDS];
string CommandConstants::StaticInitializer::ackModes[NUM_ACK_MODES];
string CommandConstants::StaticInitializer::msgTypes[NUM_MSG_TYPES];
map<std::string, CommandConstants::StompHeader> CommandConstants::StaticInitializer::stompHeaderMap;
map<std::string, CommandConstants::CommandId> CommandConstants::StaticInitializer::commandMap;
map<std::string, CommandConstants::AckMode> CommandConstants::StaticInitializer::ackModeMap;
map<std::string, CommandConstants::MessageType> CommandConstants::StaticInitializer::msgTypeMap;
CommandConstants::StaticInitializer CommandConstants::staticInits;
////////////////////////////////////////////////////////////////////////////////
CommandConstants::StaticInitializer::StaticInitializer(){
stompHeaders[HEADER_DESTINATION] = "destination";
stompHeaders[HEADER_TRANSACTIONID] = "transaction";
stompHeaders[HEADER_CONTENTLENGTH] = "content-length";
stompHeaders[HEADER_SESSIONID] = "session";
stompHeaders[HEADER_RECEIPTID] = "receipt-id";
stompHeaders[HEADER_RECEIPT_REQUIRED] = "receipt";
stompHeaders[HEADER_MESSAGEID] = "message-id";
stompHeaders[HEADER_ACK] = "ack";
stompHeaders[HEADER_LOGIN] = "login";
stompHeaders[HEADER_PASSWORD] = "passcode";
stompHeaders[HEADER_CLIENT_ID] = "client-id";
stompHeaders[HEADER_MESSAGE] = "message";
stompHeaders[HEADER_CORRELATIONID] = "correlation-id";
stompHeaders[HEADER_REQUESTID] = "request-id";
stompHeaders[HEADER_RESPONSEID] = "response-id";
stompHeaders[HEADER_EXPIRES] = "expires";
stompHeaders[HEADER_PERSISTANT] = "persistent";
stompHeaders[HEADER_PRIORITY] = "priority";
stompHeaders[HEADER_REPLYTO] = "reply-to";
stompHeaders[HEADER_TYPE] = "type";
stompHeaders[HEADER_AMQMSGTYPE] = "amq-msg-type";
stompHeaders[HEADER_JMSXGROUPID] = "JMSXGroupID";
stompHeaders[HEADER_JMSXGROUPSEQNO] = "JMSXGroupSeq";
stompHeaders[HEADER_SELECTOR] = "selector";
stompHeaders[HEADER_DISPATCH_ASYNC] = "activemq.dispatchAsync";
stompHeaders[HEADER_EXCLUSIVE] = "activemq.exclusive";
stompHeaders[HEADER_MAXPENDINGMSGLIMIT] = "activemq.maximumPendingMessageLimit";
stompHeaders[HEADER_NOLOCAL] = "activemq.noLocal";
stompHeaders[HEADER_PREFETCHSIZE] = "activemq.prefetchSize";
stompHeaders[HEADER_PRIORITY] = "activemq.priority";
stompHeaders[HEADER_RETROACTIVE] = "activemq.retroactive";
stompHeaders[HEADER_SUBSCRIPTIONNAME] = "activemq.subscriptionName";
stompHeaders[HEADER_TIMESTAMP] = "timestamp";
stompHeaders[HEADER_REDELIVERED] = "redelivered";
stompHeaders[HEADER_REDELIVERYCOUNT] = "redelivery_count";
stompHeaders[HEADER_SELECTOR] = "selector";
stompHeaders[HEADER_ID] = "id";
stompHeaders[HEADER_SUBSCRIPTION] = "subscription";
commands[CONNECT] = "CONNECT";
commands[CONNECTED] = "CONNECTED";
commands[DISCONNECT] = "DISCONNECT";
commands[SUBSCRIBE] = "SUBSCRIBE";
commands[UNSUBSCRIBE] = "UNSUBSCRIBE";
commands[MESSAGE] = "MESSAGE";
commands[SEND] = "SEND";
commands[BEGIN] = "BEGIN";
commands[COMMIT] = "COMMIT";
commands[ABORT] = "ABORT";
commands[ACK] = "ACK";
commands[ERROR_CMD] = "ERROR";
commands[RECEIPT] = "RECEIPT";
ackModes[ACK_CLIENT] = "client";
ackModes[ACK_AUTO] = "auto";
msgTypes[TEXT] = "text";
msgTypes[BYTES] = "bytes";
for( int ix=0; ix<NUM_STOMP_HEADERS; ++ix ){
stompHeaderMap[stompHeaders[ix]] = (StompHeader)ix;
}
for( int ix=0; ix<NUM_COMMANDS; ++ix ){
commandMap[commands[ix]] = (CommandId)ix;
}
for( int ix=0; ix<NUM_ACK_MODES; ++ix ){
ackModeMap[ackModes[ix]] = (AckMode)ix;
}
for( int ix=0; ix<NUM_MSG_TYPES; ++ix ){
msgTypeMap[msgTypes[ix]] = (MessageType)ix;
}
}
////////////////////////////////////////////////////////////////////////////////
cms::Destination* CommandConstants::toDestination( const std::string& dest )
throw ( exceptions::IllegalArgumentException )
{
int qpos = dest.find(queuePrefix);
int tpos = dest.find(topicPrefix);
if(tpos == 0)
{
return new StompTopic(dest.substr(strlen(topicPrefix)));
}
else if(qpos == 0)
{
return new StompQueue(dest.substr(strlen(queuePrefix)));
}
else
{
throw IllegalArgumentException(
__FILE__, __LINE__,
"CommandConstants::toDestionation - Not a valid Stomp Dest");
}
}

View File

@ -0,0 +1,193 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#ifndef ACTIVEMQ_CONNECTOR_STOMP_COMMANDS_COMMANDCONSTANTS_H_
#define ACTIVEMQ_CONNECTOR_STOMP_COMMANDS_COMMANDCONSTANTS_H_
#include <cms/Destination.h>
#include <activemq/exceptions/IllegalArgumentException.h>
#include <string>
#include <map>
namespace activemq{
namespace connector{
namespace stomp{
namespace commands{
class CommandConstants{
public:
enum CommandId{
CONNECT,
CONNECTED,
DISCONNECT,
SUBSCRIBE,
UNSUBSCRIBE,
MESSAGE,
SEND,
BEGIN,
COMMIT,
ABORT,
ACK,
ERROR_CMD,
RECEIPT,
NUM_COMMANDS
};
enum StompHeader{
HEADER_DESTINATION,
HEADER_TRANSACTIONID,
HEADER_CONTENTLENGTH,
HEADER_SESSIONID,
HEADER_RECEIPT_REQUIRED,
HEADER_RECEIPTID,
HEADER_MESSAGEID,
HEADER_ACK,
HEADER_LOGIN,
HEADER_PASSWORD,
HEADER_CLIENT_ID,
HEADER_MESSAGE,
HEADER_CORRELATIONID,
HEADER_REQUESTID,
HEADER_RESPONSEID,
HEADER_EXPIRES,
HEADER_PERSISTANT,
HEADER_REPLYTO,
HEADER_TYPE,
HEADER_AMQMSGTYPE,
HEADER_JMSXGROUPID,
HEADER_JMSXGROUPSEQNO,
HEADER_DISPATCH_ASYNC,
HEADER_EXCLUSIVE,
HEADER_MAXPENDINGMSGLIMIT,
HEADER_NOLOCAL,
HEADER_PREFETCHSIZE,
HEADER_PRIORITY,
HEADER_RETROACTIVE,
HEADER_SUBSCRIPTIONNAME,
HEADER_TIMESTAMP,
HEADER_REDELIVERED,
HEADER_REDELIVERYCOUNT,
HEADER_SELECTOR,
HEADER_ID,
HEADER_SUBSCRIPTION,
NUM_STOMP_HEADERS
};
enum AckMode{
ACK_CLIENT,
ACK_AUTO,
NUM_ACK_MODES
};
enum MessageType
{
TEXT,
BYTES,
NUM_MSG_TYPES
};
static const char* queuePrefix;
static const char* topicPrefix;
static const std::string& toString( const CommandId cmd ){
return StaticInitializer::commands[cmd];
}
static CommandId toCommandId( const std::string& cmd ){
std::map<std::string, CommandId>::iterator iter =
StaticInitializer::commandMap.find(cmd);
if( iter == StaticInitializer::commandMap.end() ){
return NUM_COMMANDS;
}
return iter->second;
}
static std::string toString( const StompHeader header ){
return StaticInitializer::stompHeaders[header];
}
static StompHeader toStompHeader( const std::string& header ){
std::map<std::string, StompHeader>::iterator iter =
StaticInitializer::stompHeaderMap.find(header);
if( iter == StaticInitializer::stompHeaderMap.end() ){
return NUM_STOMP_HEADERS;
}
return iter->second;
}
static std::string toString( const AckMode mode ){
return StaticInitializer::ackModes[mode];
}
static AckMode toAckMode( const std::string& mode ){
std::map<std::string, AckMode>::iterator iter =
StaticInitializer::ackModeMap.find(mode);
if( iter == StaticInitializer::ackModeMap.end() ){
return NUM_ACK_MODES;
}
return iter->second;
}
static std::string toString( const MessageType type ){
return StaticInitializer::msgTypes[type];
}
static MessageType toMessageType( const std::string& type ){
std::map<std::string, MessageType>::iterator iter =
StaticInitializer::msgTypeMap.find(type);
if( iter == StaticInitializer::msgTypeMap.end() ){
return NUM_MSG_TYPES;
}
return iter->second;
}
static cms::Destination* toDestination( const std::string& dest )
throw ( exceptions::IllegalArgumentException );
class StaticInitializer{
public:
StaticInitializer();
virtual ~StaticInitializer(){}
static std::string stompHeaders[NUM_STOMP_HEADERS];
static std::string commands[NUM_COMMANDS];
static std::string ackModes[NUM_ACK_MODES];
static std::string msgTypes[NUM_MSG_TYPES];
static std::map<std::string, StompHeader> stompHeaderMap;
static std::map<std::string, CommandId> commandMap;
static std::map<std::string, AckMode> ackModeMap;
static std::map<std::string, MessageType> msgTypeMap;
};
private:
static StaticInitializer staticInits;
};
}}}}
#endif /*ACTIVEMQ_CONNECTOR_STOMP_COMMANDS_COMMANDCONSTANTS_H_*/

View File

@ -0,0 +1,85 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#ifndef _ACTIVEMQ_CONNECTOR_STOMP_COMMANDS_COMMITCOMMAND_H_
#define _ACTIVEMQ_CONNECTOR_STOMP_COMMANDS_COMMITCOMMAND_H_
#include <activemq/connector/stomp/commands/AbstractCommand.h>
#include <activemq/connector/stomp/commands/CommandConstants.h>
#include <activemq/transport/Command.h>
#include <string>
namespace activemq{
namespace connector{
namespace stomp{
namespace commands{
/**
* Commits a Transaction.
*/
class CommitCommand : public AbstractCommand< transport::Command >
{
public:
CommitCommand(void) :
AbstractCommand<transport::Command>() {
initialize( getFrame() );
}
CommitCommand( StompFrame* frame ) :
AbstractCommand<transport::Command>(frame) {
validate( getFrame() );
}
virtual ~CommitCommand(void) {}
protected:
/**
* Inheritors are required to override this method to init the
* frame with data appropriate for the command type.
* @param Frame to init
*/
virtual void initialize( StompFrame& frame )
{
frame.setCommand( CommandConstants::toString(
CommandConstants::COMMIT ) );
}
/**
* Inheritors are required to override this method to validate
* the passed stomp frame before it is marshalled or unmarshaled
* @param Frame to validate
* @returns true if frame is valid
*/
virtual bool validate( const StompFrame& frame ) const
{
if((frame.getCommand() ==
CommandConstants::toString( CommandConstants::COMMIT )) &&
(frame.getProperties().hasProperty(
CommandConstants::toString(
CommandConstants::HEADER_TRANSACTIONID ) ) ) )
{
return true;
}
return false;
}
};
}}}}
#endif /*_ACTIVEMQ_CONNECTOR_STOMP_COMMANDS_COMMITCOMMAND_H_*/

View File

@ -0,0 +1,144 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#ifndef ACTIVEMQ_CONNECTOR_STOMP_COMMANDS_CONNECTCOMMAND_H_
#define ACTIVEMQ_CONNECTOR_STOMP_COMMANDS_CONNECTCOMMAND_H_
#include <activemq/connector/stomp/commands/AbstractCommand.h>
#include <activemq/connector/stomp/commands/CommandConstants.h>
#include <activemq/transport/Command.h>
namespace activemq{
namespace connector{
namespace stomp{
namespace commands{
/**
* Message sent to the broker to connect.
*/
class ConnectCommand : public AbstractCommand< transport::Command >
{
public:
ConnectCommand(void) :
AbstractCommand<transport::Command>() {
initialize( getFrame() );
}
ConnectCommand( StompFrame* frame ) :
AbstractCommand<transport::Command>(frame) {
validate( getFrame() );
}
virtual ~ConnectCommand(void) {};
/**
* Get the login
* @return char* to login, can be ""
*/
virtual const char* getLogin(void) const {
return getPropertyValue(
CommandConstants::toString(
CommandConstants::HEADER_LOGIN) );
}
/**
* Set the login
* @param password string value
*/
virtual void setLogin( const std::string& login ){
setPropertyValue(
CommandConstants::toString(
CommandConstants::HEADER_LOGIN) ,
login );
}
/**
* Get the password
* @return char* to password, can be ""
*/
virtual const char* getPassword(void) const{
return getPropertyValue(
CommandConstants::toString(
CommandConstants::HEADER_PASSWORD) );
}
/**
* Set the password
* @param passwrod string value
*/
virtual void setPassword( const std::string& password ){
setPropertyValue(
CommandConstants::toString(
CommandConstants::HEADER_PASSWORD) ,
password );
}
/**
* Get the Client Id
* @return char* to client Id, can be ""
*/
virtual const char* getClientId(void) const{
return getPropertyValue(
CommandConstants::toString(
CommandConstants::HEADER_CLIENT_ID) );
}
/**
* Set the Client Id
* @param client id string value
*/
virtual void setClientId( const std::string& clientId ){
setPropertyValue(
CommandConstants::toString(
CommandConstants::HEADER_CLIENT_ID) ,
clientId );
}
protected:
/**
* Inheritors are required to override this method to init the
* frame with data appropriate for the command type.
* @param Frame to init
*/
virtual void initialize( StompFrame& frame )
{
frame.setCommand( CommandConstants::toString(
CommandConstants::CONNECT ) );
}
/**
* Inheritors are required to override this method to validate
* the passed stomp frame before it is marshalled or unmarshaled
* @param Frame to validate
* @returns true if frame is valid
*/
virtual bool validate( const StompFrame& frame ) const
{
if(frame.getCommand() ==
CommandConstants::toString( CommandConstants::CONNECT ) )
{
return true;
}
return false;
}
};
}}}}
#endif /*ACTIVEMQ_CONNECTOR_STOMP_COMMANDS_CONNECTCOMMAND_H_*/

View File

@ -0,0 +1,101 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#ifndef ACTIVEMQ_COMMAND_STOMP_COMMANDS_CONNECTEDCOMMAND_H_
#define ACTIVEMQ_COMMAND_STOMP_COMMANDS_CONNECTEDCOMMAND_H_
#include <activemq/connector/stomp/commands/AbstractCommand.h>
#include <activemq/connector/stomp/commands/CommandConstants.h>
#include <activemq/transport/Response.h>
namespace activemq{
namespace connector{
namespace stomp{
namespace commands{
/**
* The stomp command returned from the broker indicating
* a connection has been established.
*/
class ConnectedCommand : public AbstractCommand< transport::Response >
{
public:
ConnectedCommand(void) :
AbstractCommand< transport::Response >() {
initialize( getFrame() );
}
ConnectedCommand( StompFrame* frame ) :
AbstractCommand< transport::Response >( frame ) {
validate( getFrame() );
}
virtual ~ConnectedCommand(void) {}
/**
* Get the Session Id
*/
virtual const char* getSessionId() const {
return getPropertyValue(
CommandConstants::toString(
CommandConstants::HEADER_SESSIONID) );
}
/**
* Set the Session Id
*/
virtual void setSessionId( const std::string& session ) {
setPropertyValue(
CommandConstants::toString(
CommandConstants::HEADER_SESSIONID),
session );
}
protected:
/**
* Inheritors are required to override this method to init the
* frame with data appropriate for the command type.
* @param Frame to init
*/
virtual void initialize( StompFrame& frame )
{
frame.setCommand( CommandConstants::toString(
CommandConstants::CONNECTED ) );
}
/**
* Inheritors are required to override this method to validate
* the passed stomp frame before it is marshalled or unmarshaled
* @param Frame to validate
* @returns true if frame is valid
*/
virtual bool validate( const StompFrame& frame ) const
{
if(frame.getCommand() ==
CommandConstants::toString( CommandConstants::CONNECTED ) )
{
return true;
}
return false;
}
};
}}}}
#endif /*ACTIVEMQ_COMMAND_STOMP_COMMANDS_CONNECTEDCOMMAND_H_*/

View File

@ -0,0 +1,84 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#ifndef ACTIVEMQ_CONNECTOR_STOMP_COMMANDS_DISCONNECTCOMMAND_H_
#define ACTIVEMQ_CONNECTOR_STOMP_COMMANDS_DISCONNECTCOMMAND_H_
#include <activemq/connector/stomp/commands/AbstractCommand.h>
#include <activemq/connector/stomp/commands/CommandConstants.h>
#include <activemq/transport/Command.h>
namespace activemq{
namespace connector{
namespace stomp{
namespace commands{
/**
* Sent to the broker to disconnect gracefully before closing
* the transport.
*/
class DisconnectCommand : public AbstractCommand< transport::Command >
{
public:
DisconnectCommand(void) :
AbstractCommand<transport::Command>() {
initialize( getFrame() );
}
DisconnectCommand( StompFrame* frame ) :
AbstractCommand<transport::Command>(frame) {
validate( getFrame() );
}
virtual ~DisconnectCommand(void){};
protected:
/**
* Inheritors are required to override this method to init the
* frame with data appropriate for the command type.
* @param Frame to init
*/
virtual void initialize( StompFrame& frame )
{
frame.setCommand( CommandConstants::toString(
CommandConstants::DISCONNECT ) );
}
/**
* Inheritors are required to override this method to validate
* the passed stomp frame before it is marshalled or unmarshaled
* @param Frame to validate
* @returns true if frame is valid
*/
virtual bool validate( const StompFrame& frame ) const
{
if(frame.getCommand() ==
CommandConstants::toString( CommandConstants::DISCONNECT ) )
{
return true;
}
return false;
}
};
}}}}
#endif /*ACTIVEMQ_CONNECTOR_STOMP_COMMANDS_DISCONNECTCOMMAND_H_*/

View File

@ -0,0 +1,120 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#ifndef ACTIVEMQ_CONNECTOR_STOMP_COMMANDS_ERRORCOMMAND_H_
#define ACTIVEMQ_CONNECTOR_STOMP_COMMANDS_ERRORCOMMAND_H_
#include <activemq/connector/stomp/commands/AbstractCommand.h>
#include <activemq/connector/stomp/commands/CommandConstants.h>
#include <activemq/transport/Command.h>
namespace activemq{
namespace connector{
namespace stomp{
namespace commands{
/**
* Message sent from the broker when an error
* occurs.
*/
class ErrorCommand : public AbstractCommand< transport::Command >
{
public:
ErrorCommand(void) :
AbstractCommand<transport::Command>() {
initialize( getFrame() );
}
ErrorCommand( StompFrame* frame ) :
AbstractCommand<transport::Command>(frame) {
validate( getFrame() );
}
virtual ~ErrorCommand(void) {};
/**
* Get the error message
*/
virtual const char* getErrorMessage(void) const {
return getPropertyValue(
CommandConstants::toString(
CommandConstants::HEADER_MESSAGE) );
}
/**
* Set the error message
*/
virtual void setErrorMessage( const std::string& title ) {
setPropertyValue(
CommandConstants::toString(
CommandConstants::HEADER_MESSAGE),
title );
}
/**
* Set the Text associated with this Error
* @param Error Message
*/
virtual void setErrorDetails( const std::string& text ) {
setBytes( text.c_str(), text.length() + 1 );
}
/**
* Get the Text associated with this Error
* @return Error Message
*/
virtual const char* getErrorDetails(void) const {
return getBytes();
}
protected:
/**
* Inheritors are required to override this method to init the
* frame with data appropriate for the command type.
* @param Frame to init
*/
virtual void initialize( StompFrame& frame )
{
frame.setCommand( CommandConstants::toString(
CommandConstants::ERROR_CMD ) );
}
/**
* Inheritors are required to override this method to validate
* the passed stomp frame before it is marshalled or unmarshaled
* @param Frame to validate
* @returns true if frame is valid
*/
virtual bool validate( const StompFrame& frame ) const
{
if((frame.getCommand() ==
CommandConstants::toString( CommandConstants::ERROR_CMD ) ) &&
(frame.getProperties().hasProperty(
CommandConstants::toString(
CommandConstants::HEADER_MESSAGE ) ) ) )
{
return true;
}
return false;
}
};
}}}}
#endif /*ACTIVEMQ_CONNECTOR_STOMP_COMMANDS_ERRORCOMMAND_H_*/

View File

@ -0,0 +1,63 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#ifndef ACTIVEMQ_CONNECTOR_STOMP_COMMANDS_MESSAGECOMMAND_H_
#define ACTIVEMQ_CONNECTOR_STOMP_COMMANDS_MESSAGECOMMAND_H_
#include <cms/Message.h>
#include <activemq/connector/stomp/commands/StompMessage.h>
#include <activemq/connector/stomp/commands/CommandConstants.h>
namespace activemq{
namespace connector{
namespace stomp{
namespace commands{
/**
* Message command which represents a ActiveMQMessage with no body
* can be sent or recieved.
*/
class MessageCommand : public StompMessage< cms::Message >
{
public:
MessageCommand(void) :
StompMessage< cms::Message >() {
initialize( getFrame() );
}
MessageCommand( StompFrame* frame ) :
StompMessage< cms::Message >( frame ) {
validate( getFrame() );
}
virtual ~MessageCommand(void) {}
/**
* Clonse this message exactly, returns a new instance that the
* caller is required to delete.
* @return new copy of this message
*/
virtual cms::Message* clone(void) const {
StompFrame* frame = getFrame().clone();
return new MessageCommand( frame );
}
};
}}}}
#endif /*ACTIVEMQ_CONNECTOR_STOMP_COMMANDS_MESSAGECOMMAND_H_*/

View File

@ -0,0 +1,104 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#ifndef _ACTIVEMQ_CONNECTOR_STOMP_COMMANDS_RECEIPTCOMMAND_H_
#define _ACTIVEMQ_CONNECTOR_STOMP_COMMANDS_RECEIPTCOMMAND_H_
#include <activemq/connector/stomp/commands/AbstractCommand.h>
#include <activemq/connector/stomp/commands/CommandConstants.h>
#include <activemq/transport/Response.h>
namespace activemq{
namespace connector{
namespace stomp{
namespace commands{
/**
* Message sent from the Broker when a receipt is requested
* for messages that are sent.
*/
class ReceiptCommand : public AbstractCommand< transport::Response >
{
public:
ReceiptCommand(void) :
AbstractCommand<transport::Response>() {
initialize( getFrame() );
}
ReceiptCommand( StompFrame* frame ) :
AbstractCommand<transport::Response>(frame) {
validate( getFrame() );
}
virtual ~ReceiptCommand(void) {}
/**
* Get the receipt id
*/
virtual const char* getReceiptId(void) const{
return getPropertyValue(
CommandConstants::toString(
CommandConstants::HEADER_RECEIPTID) );
}
/**
* Set the receipt id
*/
virtual void setReceiptId( const std::string& id ){
setPropertyValue(
CommandConstants::toString(
CommandConstants::HEADER_RECEIPTID),
id );
}
protected:
/**
* Inheritors are required to override this method to init the
* frame with data appropriate for the command type.
* @param Frame to init
*/
virtual void initialize( StompFrame& frame )
{
frame.setCommand( CommandConstants::toString(
CommandConstants::RECEIPT ) );
}
/**
* Inheritors are required to override this method to validate
* the passed stomp frame before it is marshalled or unmarshaled
* @param Frame to validate
* @returns true if frame is valid
*/
virtual bool validate( const StompFrame& frame ) const
{
if((frame.getCommand() ==
CommandConstants::toString( CommandConstants::RECEIPT )) &&
(frame.getProperties().hasProperty(
CommandConstants::toString(
CommandConstants::HEADER_RECEIPTID ) ) ) )
{
return true;
}
return false;
}
};
}}}}
#endif /*_ACTIVEMQ_CONNECTOR_STOMP_COMMANDS_RECEIPTCOMMAND_H_*/

View File

@ -0,0 +1,111 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#ifndef _ACTIVEMQ_CONNECTOR_STOMP_COMMANDS_STOMPCOMMAND_H_
#define _ACTIVEMQ_CONNECTOR_STOMP_COMMANDS_STOMPCOMMAND_H_
#include <activemq/connector/stomp/commands/CommandConstants.h>
#include <activemq/connector/stomp/marshal/Marshalable.h>
#include <activemq/connector/stomp/marshal/MarshalException.h>
namespace activemq{
namespace connector{
namespace stomp{
namespace commands{
class StompCommand : public marshal::Marshalable
{
protected:
/**
* Inheritors are required to override this method to init the
* frame with data appropriate for the command type.
* @param Frame to init
*/
virtual void initialize( StompFrame& frame ) = 0;
/**
* Inheritors are required to override this method to validate
* the passed stomp frame before it is marshalled or unmarshaled
* @param Frame to validate
* @returns true if frame is valid
*/
virtual bool validate( const StompFrame& frame ) const = 0;
public:
virtual ~StompCommand(void) {}
/**
* Sets the Command Id of this Message
* @param Command Id
*/
virtual void setCommandId( const unsigned int id ) = 0;
/**
* Gets the Command Id of this Message
* @return Command Id
*/
virtual unsigned int getCommandId(void) const = 0;
/**
* Set if this Message requires a Response
* @param true if response is required
*/
virtual void setResponseRequired( const bool required ) = 0;
/**
* Is a Response required for this Command
* @return true if a response is required.
*/
virtual bool isResponseRequired(void) const = 0;
/**
* Gets the Correlation Id that is associated with this message
* @return the Correlation Id
*/
virtual unsigned int getCorrelationId(void) const = 0;
/**
* Sets the Correlation Id if this Command
* @param Id
*/
virtual void setCorrelationId( const unsigned int corrId ) = 0;
/**
* Get the Transaction Id of this Command
* @return the Id of the Transaction
*/
virtual const char* getTransactionId(void) const = 0;
/**
* Set the Transaction Id of this Command
* @param the Id of the Transaction
*/
virtual void setTransactionId( const std::string& id ) = 0;
/**
* Retrieve the Stomp Command Id for this message.
* @return Stomp CommandId enum
*/
virtual CommandConstants::CommandId getStompCommandId(void) const = 0;
};
}}}}
#endif /*_ACTIVEMQ_CONNECTOR_STOMP_COMMANDS_STOMPCOMMAND_H_*/

View File

@ -0,0 +1,400 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#ifndef _ACTIVEMQ_CONNECTOR_STOMP_COMMANDS_STOMPMESSAGE_H_
#define _ACTIVEMQ_CONNECTOR_STOMP_COMMANDS_STOMPMESSAGE_H_
#include <activemq/core/ActiveMQMessage.h>
#include <activemq/core/ActiveMQAckHandler.h>
#include <activemq/connector/stomp/commands/AbstractCommand.h>
#include <activemq/transport/Command.h>
#include <activemq/connector/stomp/StompTopic.h>
#include <activemq/util/Long.h>
#include <activemq/util/Integer.h>
#include <activemq/util/Boolean.h>
#include <string>
namespace activemq{
namespace connector{
namespace stomp{
namespace commands{
/**
* Base class for Stomp Commands that represent the Active MQ message
* types. This class is templated and expects the Template type to be
* a cms::Message type, Message, TextMessage etc. This class will
* implement all the general cms:Message methods
*
* This class implement AbsractCommand<StompCommnd> and the
* ActiveMQMessage interface.
*/
template<typename T>
class StompMessage :
public AbstractCommand< transport::Command >,
public T,
public core::ActiveMQMessage
{
private:
// Core API defined Acknowedge Handler.
core::ActiveMQAckHandler* ackHandler;
// Cached Destination
cms::Destination* dest;
public:
StompMessage(void) :
AbstractCommand< transport::Command >(),
ackHandler( NULL ) { dest = new StompTopic(); }
StompMessage( StompFrame* frame ) :
AbstractCommand< transport::Command >( frame ),
ackHandler( NULL )
{
dest = CommandConstants::toDestination(
getPropertyValue(
CommandConstants::toString(
CommandConstants::HEADER_DESTINATION ), "" ) );
}
virtual ~StompMessage(void) { delete dest; }
/**
* Gets the properties map for this command.
* @return Reference to a Properties object
*/
virtual util::Properties& getProperties(void){
return getFrame().getProperties();
}
virtual const util::Properties& getProperties(void) const{
return getFrame().getProperties();
}
/**
* Get the Correlation Id for this message
* @return string representation of the correlation Id
*/
virtual const char* getCMSCorrelationId(void) const {
return getPropertyValue(
CommandConstants::toString(
CommandConstants::HEADER_CORRELATIONID ) );
}
/**
* Sets the Correlation Id used by this message
* @param String representing the correlation id.
*/
virtual void setCMSCorrelationId(const std::string& correlationId) {
setPropertyValue(
CommandConstants::toString(
CommandConstants::HEADER_CORRELATIONID ) ,
correlationId );
}
/**
* Acknowledges all consumed messages of the session
* of this consumed message.
*/
virtual void acknowledge(void) const throw( cms::CMSException ) {
if(ackHandler != NULL) ackHandler->acknowledgeMessage(this);
}
/**
* Sets the DeliveryMode for this message
* @return DeliveryMode enumerated value.
*/
virtual cms::Message::DeliveryMode getCMSDeliveryMode(void) const {
if(!getFrame().getProperties().hasProperty(
CommandConstants::toString(
CommandConstants::HEADER_PERSISTANT ) ) ) {
return cms::Message::PERSISTANT;
}
return (cms::Message::DeliveryMode)(
util::Integer::parseInt( getPropertyValue(
CommandConstants::toString(
CommandConstants::HEADER_PERSISTANT ) ) ) );
}
/**
* Sets the DeliveryMode for this message
* @param DeliveryMode enumerated value.
*/
virtual void setCMSDeliveryMode(cms::Message::DeliveryMode mode) {
setPropertyValue(
CommandConstants::toString(
CommandConstants::HEADER_PERSISTANT ) ,
util::Integer::toString((int)mode) );
}
/**
* Gets the Destination for this Message
* @return Destination object
*/
virtual const cms::Destination& getCMSDestination(void) const{
return *dest;
}
/**
* Sets the Destination for this message
* @param Destination Object
*/
virtual void setCMSDestination(const cms::Destination& destination) {
dest->copy( destination );
setPropertyValue(
CommandConstants::toString(
CommandConstants::HEADER_DESTINATION ),
dest->toProviderString() );
}
/**
* Gets the Expiration Time for this Message
* @return time value
*/
virtual long getCMSExpiration(void) const {
return util::Long::parseLong( getPropertyValue(
CommandConstants::toString(
CommandConstants::HEADER_EXPIRES ), "0" ) );
}
/**
* Sets the Expiration Time for this message
* @param time value
*/
virtual void setCMSExpiration(long expireTime) {
setPropertyValue(
CommandConstants::toString(
CommandConstants::HEADER_EXPIRES) ,
util::Long::toString( expireTime ) );
}
/**
* Gets the CMS Message Id for this Message
* @return time value
*/
virtual const char* getCMSMessageId(void) const {
return getPropertyValue(
CommandConstants::toString(
CommandConstants::HEADER_MESSAGEID ) );
}
/**
* Sets the CMS Message Id for this message
* @param time value
*/
virtual void setCMSMessageId(const std::string& id) {
setPropertyValue(
CommandConstants::toString(
CommandConstants::HEADER_MESSAGEID ),
id );
}
/**
* Gets the Priority Value for this Message
* @return priority value
*/
virtual int getCMSPriority(void) const {
return util::Integer::parseInt( getPropertyValue(
CommandConstants::toString(
CommandConstants::HEADER_PRIORITY ), "0" ) );
}
/**
* Sets the Priority Value for this message
* @param priority value
*/
virtual void setCMSPriority(int priority) {
setPropertyValue(
CommandConstants::toString(
CommandConstants::HEADER_PRIORITY),
util::Integer::toString( priority ) );
}
/**
* Gets the Redelivered Flag for this Message
* @return redelivered value
*/
virtual bool getCMSRedelivered(void) const {
return util::Boolean::parseBoolean( getPropertyValue(
CommandConstants::toString(
CommandConstants::HEADER_REDELIVERED ),
"false" ) );
}
/**
* Sets the Redelivered Flag for this message
* @param redelivered value
*/
virtual void setCMSRedelivered(bool redelivered) {
setPropertyValue(
CommandConstants::toString(
CommandConstants::HEADER_REDELIVERED ),
util::Boolean::toString( redelivered ) );
}
/**
* Gets the CMS Reply To Address for this Message
* @return Reply To Value
*/
virtual const char* getCMSReplyTo(void) const {
return getPropertyValue(
CommandConstants::toString(
CommandConstants::HEADER_REPLYTO ) );
}
/**
* Sets the CMS Reply To Address for this message
* @param Reply To value
*/
virtual void setCMSReplyTo(const std::string& id) {
setPropertyValue(
CommandConstants::toString(
CommandConstants::HEADER_REPLYTO ),
id );
}
/**
* Gets the Time Stamp for this Message
* @return time stamp value
*/
virtual long getCMSTimeStamp(void) const {
return util::Long::parseLong( getPropertyValue(
CommandConstants::toString(
CommandConstants::HEADER_TIMESTAMP ), "0" ) );
}
/**
* Sets the Time Stamp for this message
* @param time stamp value
*/
virtual void setCMSTimeStamp(long timeStamp) {
setPropertyValue(
CommandConstants::toString(
CommandConstants::HEADER_TIMESTAMP ),
util::Long::toString( timeStamp ) );
}
/**
* Gets the CMS Message Type for this Message
* @return type value
*/
virtual const char* getCMSMessageType(void) const {
return getPropertyValue(
CommandConstants::toString(
CommandConstants::HEADER_TYPE ) );
}
/**
* Sets the CMS Message Type for this message
* @param type value
*/
virtual void setCMSMessageType(const std::string& type) {
setPropertyValue(
CommandConstants::toString(
CommandConstants::HEADER_TYPE ),
type );
}
public: // ActiveMQMessage
/**
* Sets the Acknowledgement Handler that this Message will use
* when the Acknowledge method is called.
* @param ActiveMQAckHandler
*/
virtual void setAckHandler(core::ActiveMQAckHandler* handler) {
this->ackHandler = handler;
}
/**
* Gets the number of times this message has been redelivered.
* @return redelivery count
*/
virtual int getRedeliveryCount(void) const {
return util::Integer::parseInt( getPropertyValue(
CommandConstants::toString(
CommandConstants::HEADER_REDELIVERYCOUNT ),
"0" ) );
}
/**
* Sets the count of the number of times this message has been
* redelivered
* @param redelivery count
*/
virtual void setRedeliveryCount(int count) {
setPropertyValue(
CommandConstants::toString(
CommandConstants::HEADER_REDELIVERYCOUNT ),
util::Integer::toString( count ) );
}
protected:
/**
* Inheritors are required to override this method to init the
* frame with data appropriate for the command type.
* @param Frame to init
*/
virtual void initialize( StompFrame& frame )
{
frame.setCommand( CommandConstants::toString(
CommandConstants::SEND ) );
}
/**
* Inheritors are required to override this method to validate
* the passed stomp frame before it is marshalled or unmarshaled
* @param Frame to validate
* @returns true if frame is valid
*/
virtual bool validate( const StompFrame& frame ) const
{
if(frame.getCommand() ==
CommandConstants::toString( CommandConstants::SEND ) )
{
if(frame.getProperties().hasProperty(
CommandConstants::toString(
CommandConstants::HEADER_DESTINATION ) ) )
{
return true;
}
}
else if( frame.getCommand() ==
CommandConstants::toString( CommandConstants::MESSAGE ) )
{
if(frame.getProperties().hasProperty(
CommandConstants::toString(
CommandConstants::HEADER_DESTINATION ) ) &&
frame.getProperties().hasProperty(
CommandConstants::toString(
CommandConstants::HEADER_MESSAGEID ) ) )
{
return true;
}
}
return false;
}
};
}}}}
#endif /*_ACTIVEMQ_CONNECTOR_STOMP_COMMANDS_STOMPMESSAGE_H_*/

View File

@ -0,0 +1,205 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#ifndef ACTIVEMQ_CONNECTOR_STOMP_COMMANDS_SUBSCRIBECOMMAND_H_
#define ACTIVEMQ_CONNECTOR_STOMP_COMMANDS_SUBSCRIBECOMMAND_H_
#include <activemq/connector/stomp/commands/AbstractCommand.h>
#include <activemq/connector/stomp/commands/CommandConstants.h>
#include <activemq/transport/Command.h>
#include <activemq/util/Boolean.h>
namespace activemq{
namespace connector{
namespace stomp{
namespace commands{
/**
* Command sent to the broker to subscribe to a topic
* or queue.
*/
class SubscribeCommand : public AbstractCommand< transport::Command >
{
public:
SubscribeCommand(void) :
AbstractCommand<transport::Command>() {
initialize( getFrame() );
}
SubscribeCommand( StompFrame* frame ) :
AbstractCommand< transport::Command >( frame ) {
validate( getFrame() );
}
virtual ~SubscribeCommand(void) {}
/**
* Get the destination
* @returns the destination Name String
*/
virtual const char* getDestination(void) const{
return getPropertyValue(
CommandConstants::toString(
CommandConstants::HEADER_DESTINATION) );
}
/**
* Set the destination
* @param the destination Name String
*/
virtual void setDestination( const std::string& dest ){
setPropertyValue(
CommandConstants::toString(
CommandConstants::HEADER_DESTINATION),
dest );
}
/**
* Set the Ack Mode of this Subscription
* @param mode setting.
*/
virtual void setAckMode( const CommandConstants::AckMode mode ){
setPropertyValue(
CommandConstants::toString(
CommandConstants::HEADER_ACK),
CommandConstants::toString( mode ) );
}
/**
* Get the Ack Mode of this Subscription
* @return mode setting.
*/
virtual CommandConstants::AckMode getAckMode(void) const{
return CommandConstants::toAckMode(
getPropertyValue(
CommandConstants::toString(
CommandConstants::HEADER_ACK) ) );
}
/**
* Sets the Message Selector that is associated with this
* subscribe request
* @param selector string
*/
virtual void setMessageSelector( const std::string& selector ) {
setPropertyValue(
CommandConstants::toString(
CommandConstants::HEADER_SELECTOR),
selector );
}
/**
* Gets the Message Selector that is associated with this
* subscribe request
* @returns the selector string
*/
virtual const char* getMessageSelector(void) const{
return getPropertyValue(
CommandConstants::toString(
CommandConstants::HEADER_SELECTOR) );
}
/**
* Sets the Subscription Name that is associated with this
* subscribe request
* @param Subscription Name
*/
virtual void setSubscriptionName( const std::string& name ) {
setPropertyValue(
CommandConstants::toString(
CommandConstants::HEADER_SUBSCRIPTIONNAME),
name );
}
/**
* Gets the Subscription Name that is associated with this
* subscribe request
* @returns the Subscription Name
*/
virtual const char* getSubscriptionName(void) const{
return getPropertyValue(
CommandConstants::toString(
CommandConstants::HEADER_SUBSCRIPTIONNAME) );
}
/**
* Gets hether or not locally sent messages should be ignored for
* subscriptions. Set to true to filter out locally sent messages
* @return NoLocal value
*/
virtual bool getNoLocal(void) const {
return util::Boolean::parseBoolean( getPropertyValue(
CommandConstants::toString(
CommandConstants::HEADER_NOLOCAL ),
"false" ) );
}
/**
* Gets hether or not locally sent messages should be ignored for
* subscriptions. Set to true to filter out locally sent messages
* @param NoLocal value
*/
virtual void setNoLocal( bool noLocal ) {
setPropertyValue(
CommandConstants::toString(
CommandConstants::HEADER_NOLOCAL ),
util::Boolean::toString( noLocal ) );
}
protected:
/**
* Inheritors are required to override this method to init the
* frame with data appropriate for the command type.
* @param Frame to init
*/
virtual void initialize( StompFrame& frame )
{
frame.setCommand( CommandConstants::toString(
CommandConstants::SUBSCRIBE ) );
setPropertyValue(
CommandConstants::toString(
CommandConstants::HEADER_ACK),
CommandConstants::toString(
CommandConstants::ACK_AUTO ) );
}
/**
* Inheritors are required to override this method to validate
* the passed stomp frame before it is marshalled or unmarshaled
* @param Frame to validate
* @returns true if frame is valid
*/
virtual bool validate( const StompFrame& frame ) const
{
if((frame.getCommand() ==
CommandConstants::toString( CommandConstants::SUBSCRIBE )) &&
(frame.getProperties().hasProperty(
CommandConstants::toString(
CommandConstants::HEADER_DESTINATION ) ) ) )
{
return true;
}
return false;
}
};
}}}}
#endif /*ACTIVEMQ_CONNECTOR_STOMP_COMMANDS_SUBSCRIBECOMMAND_H_*/

View File

@ -0,0 +1,75 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#ifndef _ACTIVEMQ_CONNECTOR_STOMP_COMMANDS_TEXTMESSAGECOMMAND_H_
#define _ACTIVEMQ_CONNECTOR_STOMP_COMMANDS_TEXTMESSAGECOMMAND_H_
#include <cms/TextMessage.h>
#include <activemq/connector/stomp/commands/StompMessage.h>
#include <activemq/connector/stomp/commands/CommandConstants.h>
namespace activemq{
namespace connector{
namespace stomp{
namespace commands{
class TextMessageCommand : public StompMessage< cms::TextMessage >
{
public:
TextMessageCommand(void) :
StompMessage< cms::TextMessage >() {
initialize( getFrame() );
}
TextMessageCommand( StompFrame* frame ) :
StompMessage< cms::TextMessage >( frame ) {
validate( getFrame() );
}
virtual ~TextMessageCommand(void) {}
/**
* Clonse this message exactly, returns a new instance that the
* caller is required to delete.
* @return new copy of this message
*/
virtual cms::Message* clone(void) const {
StompFrame* frame = getFrame().clone();
return new TextMessageCommand( frame );
}
/**
* Gets the message character buffer.
* @return The message character buffer.
*/
virtual const char* getText(void) const throw( cms::CMSException ) {
return getBytes();
}
/**
* Sets the message contents.
* @param msg The message buffer.
*/
virtual void setText( const char* msg ) throw( cms::CMSException ) {
setBytes( msg, strlen(msg) + 1, false );
}
};
}}}}
#endif /*_ACTIVEMQ_CONNECTOR_STOMP_COMMANDS_TEXTMESSAGECOMMAND_H_*/

View File

@ -0,0 +1,104 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#ifndef ACTIVEMQ_CONNECTOR_STOMP_COMMANDS_UNSUBSCRIBECOMMAND_H_
#define ACTIVEMQ_CONNECTOR_STOMP_COMMANDS_UNSUBSCRIBECOMMAND_H_
#include <activemq/connector/stomp/commands/AbstractCommand.h>
#include <activemq/connector/stomp/commands/CommandConstants.h>
#include <activemq/transport/Command.h>
namespace activemq{
namespace connector{
namespace stomp{
namespace commands{
/**
* Command sent to the broker to unsubscribe to a
* topic or queue.
*/
class UnsubscribeCommand : public AbstractCommand< transport::Command >
{
public:
UnsubscribeCommand(void) :
AbstractCommand< transport::Command >() {
initialize( getFrame() );
}
UnsubscribeCommand( StompFrame* frame ) :
AbstractCommand< transport::Command >( frame ) {
validate( getFrame() );
}
virtual ~UnsubscribeCommand(void) {};
/**
* Get the destination
*/
virtual const char* getDestination(void) const{
return getPropertyValue(
CommandConstants::toString(
CommandConstants::HEADER_DESTINATION) );
}
/**
* Set the destination
*/
virtual void setDestination( const std::string& dest ){
setPropertyValue(
CommandConstants::toString(
CommandConstants::HEADER_DESTINATION) ,
dest );
}
protected:
/**
* Inheritors are required to override this method to init the
* frame with data appropriate for the command type.
* @param Frame to init
*/
virtual void initialize( StompFrame& frame )
{
frame.setCommand( CommandConstants::toString(
CommandConstants::UNSUBSCRIBE ) );
}
/**
* Inheritors are required to override this method to validate
* the passed stomp frame before it is marshalled or unmarshaled
* @param Frame to validate
* @returns true if frame is valid
*/
virtual bool validate( const StompFrame& frame ) const
{
if((frame.getCommand() ==
CommandConstants::toString( CommandConstants::UNSUBSCRIBE )) &&
(frame.getProperties().hasProperty(
CommandConstants::toString(
CommandConstants::HEADER_DESTINATION ) ) ) )
{
return true;
}
return false;
}
};
}}}}
#endif /*ACTIVEMQ_CONNECTOR_STOMP_COMMANDS_UNSUBSCRIBECOMMAND_H_*/

View File

@ -0,0 +1,66 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#ifndef ACTIVEMQ_CONNECTOR_STOMP_MARSHALL_MARSHALEXCEPTION_H_
#define ACTIVEMQ_CONNECTOR_STOMP_MARSHALL_MARSHALEXCEPTION_H_
#include <activemq/exceptions/ActiveMQException.h>
namespace activemq{
namespace connector{
namespace stomp{
namespace marshal{
/*
* Signals that an problem occurred during marshalling.
*/
class MarshalException : public exceptions::ActiveMQException
{
public:
MarshalException() {}
MarshalException( const exceptions::ActiveMQException& ex ){
*(ActiveMQException*)this = ex;
}
MarshalException( const MarshalException& ex ){
*(exceptions::ActiveMQException*)this = ex;
}
MarshalException(const char* file, const int lineNumber,
const char* msg, ...)
{
va_list vargs ;
va_start(vargs, msg) ;
buildMessage(msg, vargs) ;
// Set the first mark for this exception.
setMark( file, lineNumber );
}
/**
* Clones this exception. This is useful for cases where you need
* to preserve the type of the original exception as well as the message.
* All subclasses should override.
*/
virtual exceptions::ActiveMQException* clone() const{
return new MarshalException( *this );
}
virtual ~MarshalException() {}
};
}}}}
#endif /*ACTIVEMQ_CONNECTOR_STOMP_MARSHAL_MARSHALLEXCEPTION_H_*/

View File

@ -0,0 +1,49 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#ifndef _ACTIVEMQ_CONNECTOR_STOMP_MARSHAL_MARSHALABLE_H_
#define _ACTIVEMQ_CONNECTOR_STOMP_MARSHAL_MARSHALABLE_H_
#include <activemq/connector/stomp/StompFrame.h>
#include <activemq/connector/stomp/marshal/MarshalException.h>
namespace activemq{
namespace connector{
namespace stomp{
namespace marshal{
class Marshalable
{
public:
virtual ~Marshalable(void) {}
/**
* Marshals the command to a stomp frame.
* @returns the stomp frame representation of this
* command.
* @throws MarshalException if the command is not
* in a state that can be marshalled.
*/
virtual const StompFrame& marshal(void) const
throw ( marshal::MarshalException ) = 0;
};
}}}}
#endif /*_ACTIVEMQ_CONNECTOR_STOMP_MARSHAL_MARSHALABLE_H_*/

View File

@ -0,0 +1,115 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#include <activemq/connector/stomp/marshal/Marshaler.h>
#include <activemq/transport/Command.h>
#include <activemq/connector/stomp/marshal/MarshalException.h>
#include <activemq/connector/stomp/commands/CommandConstants.h>
#include <activemq/connector/stomp/commands/AbstractCommand.h>
#include <activemq/connector/stomp/StompFrame.h>
// Commands we can receive
#include <activemq/connector/stomp/commands/ConnectedCommand.h>
#include <activemq/connector/stomp/commands/ReceiptCommand.h>
#include <activemq/connector/stomp/commands/ErrorCommand.h>
// Message Commands we can receive
#include <activemq/connector/stomp/commands/MessageCommand.h>
#include <activemq/connector/stomp/commands/BytesMessageCommand.h>
#include <activemq/connector/stomp/commands/TextMessageCommand.h>
using namespace activemq;
using namespace activemq::exceptions;
using namespace activemq::transport;
using namespace activemq::connector::stomp;
using namespace activemq::connector::stomp::commands;
using namespace activemq::connector::stomp::marshal;
////////////////////////////////////////////////////////////////////////////////
transport::Command* Marshaler::marshal( StompFrame* frame )
throw ( MarshalException )
{
try
{
CommandConstants::CommandId commandId =
CommandConstants::toCommandId(frame->getCommand().c_str());
transport::Command* command = NULL;
if(commandId == CommandConstants::CONNECTED){
command = new ConnectedCommand( frame );
}
else if(commandId == CommandConstants::ERROR_CMD){
command = new ErrorCommand( frame );
}
else if(commandId == CommandConstants::RECEIPT){
command = new ReceiptCommand( frame );
}
else if(commandId == CommandConstants::MESSAGE){
if( !frame->getProperties().hasProperty(
CommandConstants::toString(
CommandConstants::HEADER_CONTENTLENGTH ) ) )
{
command = new TextMessageCommand( frame );
}
else
{
command = new BytesMessageCommand( frame );
}
}
// We either got a command or a response, but if we got neither
// then complain, something went wrong.
if(command == NULL)
{
throw MarshalException(
__FILE__, __LINE__,
"Marshaler::marshal - No Command Created from frame");
}
return command;
}
AMQ_CATCH_RETHROW( MarshalException )
AMQ_CATCH_EXCEPTION_CONVERT( ActiveMQException, MarshalException )
AMQ_CATCHALL_THROW( MarshalException )
}
////////////////////////////////////////////////////////////////////////////////
const StompFrame& Marshaler::marshal( const transport::Command* command )
throw ( MarshalException )
{
try
{
const Marshalable* marshalable =
dynamic_cast<const Marshalable*>(command);
// Easy, just get the frame from the command
if(marshalable != NULL)
{
return marshalable->marshal();
}
else
{
throw MarshalException(
__FILE__, __LINE__,
"Marshaler::marshal - Invalid Command Type!");
}
}
AMQ_CATCH_RETHROW( MarshalException )
AMQ_CATCH_EXCEPTION_CONVERT( ActiveMQException, MarshalException )
AMQ_CATCHALL_THROW( MarshalException )
}

View File

@ -0,0 +1,67 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#ifndef ACTIVEMQ_CONNECTOR_STOMP_MARSHALER_H_
#define ACTIVEMQ_CONNECTOR_STOMP_MARSHALER_H_
#include <activemq/transport/Command.h>
#include <activemq/connector/stomp/StompFrame.h>
#include <activemq/connector/stomp/marshal/MarshalException.h>
namespace activemq{
namespace connector{
namespace stomp{
namespace marshal{
/**
* Interface for all marshallers between Commands and
* stomp frames.
*/
class Marshaler
{
public:
Marshaler(void) {}
virtual ~Marshaler(void) {}
/**
* Marshall a Stomp Frame to a Stomp Command, the frame is now
* owned by this Command, caller should not use the frame again.
* @param Frame to Marshall
* @return Newly Marshaled Stomp Message
* @throws MarshalException
*/
virtual transport::Command* marshal( StompFrame* frame )
throw ( MarshalException );
/**
* Marshal a Stomp Command to a Stom Frame, if the command that
* is past is not castable to a Stomp Command an Exception will
* be thrown
* @param The Stomp Command to Marshal
* @return newly Marshaled Stomp Frame
* @throws MarshalException
*/
virtual const StompFrame& marshal(
const transport::Command* command )
throw ( MarshalException );
};
}}}}
#endif /*ACTIVEMQ_CONNECTOR_STOMP_MARSHALER_H_*/

View File

@ -0,0 +1,49 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#ifndef _ACTIVEMQ_CORE_ACTIVEMQACKHANDLER_H_
#define _ACTIVEMQ_CORE_ACTIVEMQACKHANDLER_H_
#include <cms/CMSException.h>
namespace activemq{
namespace core{
class ActiveMQMessage;
/**
* Interface class that is used to give CMS Messages an interface to
* Ack themselves with.
*/
class ActiveMQAckHandler
{
public:
virtual ~ActiveMQAckHandler(void) {};
/**
* Method called to acknowledge the message passed
* @param Message to Acknowlegde
* @throw CMSException
*/
virtual void acknowledgeMessage( const ActiveMQMessage* message )
throw ( cms::CMSException ) = 0;
};
}}
#endif /*_ACTIVEMQ_CORE_ACTIVEMQACKHANDLER_H_*/

View File

@ -0,0 +1,201 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#include "ActiveMQConnection.h"
#include <cms/Session.h>
#include <activemq/core/ActiveMQSession.h>
#include <activemq/core/ActiveMQConsumer.h>
#include <activemq/exceptions/NullPointerException.h>
using namespace cms;
using namespace activemq;
using namespace activemq::core;
using namespace activemq::connector;
using namespace activemq::exceptions;
using namespace std;
////////////////////////////////////////////////////////////////////////////////
ActiveMQConnection::ActiveMQConnection(ActiveMQConnectionData* connectionData)
{
this->connectionData = connectionData;
this->started = false;
this->exceptionListener = NULL;
// We want to be the sink for all messages from the Connector
connectionData->getConnector()->setConsumerMessageListener( this );
}
////////////////////////////////////////////////////////////////////////////////
ActiveMQConnection::~ActiveMQConnection(void)
{
try
{
close();
}
AMQ_CATCH_NOTHROW( ActiveMQException )
AMQ_CATCHALL_NOTHROW( )
}
////////////////////////////////////////////////////////////////////////////////
cms::Session* ActiveMQConnection::createSession(void)
throw ( cms::CMSException )
{
try
{
return this->createSession( Session::AutoAcknowledge );
}
AMQ_CATCH_RETHROW( ActiveMQException )
AMQ_CATCHALL_THROW( ActiveMQException )
}
////////////////////////////////////////////////////////////////////////////////
cms::Session* ActiveMQConnection::createSession(
cms::Session::AcknowledgeMode ackMode )
throw ( cms::CMSException )
{
try
{
return new ActiveMQSession(
connectionData->getConnector()->createSession( ackMode ),
connectionData->getProperties(),
this );
}
AMQ_CATCH_RETHROW( ActiveMQException )
AMQ_CATCHALL_THROW( ActiveMQException )
}
////////////////////////////////////////////////////////////////////////////////
std::string ActiveMQConnection::getClientId(void) const
{
return connectionData->getConnector()->getClientId();
}
////////////////////////////////////////////////////////////////////////////////
void ActiveMQConnection::close(void) throw ( cms::CMSException )
{
try
{
// Once current deliveries are done this stops the delivery
// of any new messages.
started = false;
// Destroy the connection data
delete connectionData;
connectionData = NULL;
}
AMQ_CATCH_RETHROW( ActiveMQException )
AMQ_CATCHALL_THROW( ActiveMQException )
}
////////////////////////////////////////////////////////////////////////////////
void ActiveMQConnection::start(void) throw ( cms::CMSException )
{
// This starts or restarts the delivery of all incomming messages
// messages delivered while this connection is stopped are dropped
// and not acknowledged.
started = true;
}
////////////////////////////////////////////////////////////////////////////////
void ActiveMQConnection::stop(void) throw ( cms::CMSException )
{
// Once current deliveries are done this stops the delivery of any
// new messages.
started = false;
}
////////////////////////////////////////////////////////////////////////////////
void ActiveMQConnection::addMessageListener( const unsigned int consumerId,
ActiveMQMessageListener* listener )
{
// Place in Map
synchronized(&mutex)
{
consumers[consumerId] = listener;
}
}
////////////////////////////////////////////////////////////////////////////////
void ActiveMQConnection::removeMessageListener( const unsigned int consumerId )
{
// Remove from Map
synchronized(&mutex)
{
consumers.erase( consumerId );
}
}
////////////////////////////////////////////////////////////////////////////////
void ActiveMQConnection::onConsumerMessage( connector::ConsumerInfo* consumer,
core::ActiveMQMessage* message )
{
try
{
if( connectionData == NULL)
{
NullPointerException ex(
__FILE__, __LINE__,
"ActiveMQConnection::onConsumerMessage - "
"Connection Data Null, could be closed." );
fire( ex );
return;
}
// When not started we drop incomming messages
if( !started )
{
// Indicate to Broker that we received the message, but it
// was not consumed.
connectionData->getConnector()->acknowledge(
consumer->getSessionInfo(),
(Message*)message,
Connector::DeliveredAck );
// Delete the message here
delete message;
return;
}
// Started, so lock map and dispatch the message.
synchronized(&mutex)
{
if(consumers.find(consumer->getConsumerId()) != consumers.end())
{
consumers[consumer->getConsumerId()]->
onActiveMQMessage( message );
}
}
}
catch( exceptions::ActiveMQException& ex )
{
ex.setMark( __FILE__, __LINE__ );
fire( ex );
}
catch( ... )
{
exceptions::ActiveMQException ex(
__FILE__, __LINE__,
"IOTransport::run - caught unknown exception" );
fire( ex );
}
}

View File

@ -0,0 +1,179 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#ifndef _ACTIVEMQ_CORE_ACTIVEMQCONNECTION_H_
#define _ACTIVEMQ_CORE_ACTIVEMQCONNECTION_H_
#include <cms/Connection.h>
#include <cms/ExceptionListener.h>
#include <activemq/concurrent/Mutex.h>
#include <activemq/core/ActiveMQConnectionData.h>
#include <activemq/core/ActiveMQMessageListener.h>
#include <activemq/core/ActiveMQMessage.h>
#include <activemq/connector/ConsumerMessageListener.h>
#include <activemq/util/Properties.h>
#include <map>
#include <string>
namespace activemq{
namespace core{
class cms::Session;
class ActiveMQConsumer;
class ActiveMQConnection :
public cms::Connection,
public connector::ConsumerMessageListener
{
private:
// the registered exception listener
cms::ExceptionListener* exceptionListener;
// All the data that is used to connect this Connection
ActiveMQConnectionData* connectionData;
// Indicates if this Connection is started
bool started;
// Map of Consumer Ids to ActiveMQMessageListeners
std::map<unsigned int, ActiveMQMessageListener*> consumers;
// Mutex to lock the Consumers Map
concurrent::Mutex mutex;
public:
/**
* Constructor
*/
ActiveMQConnection(ActiveMQConnectionData* connectionData);
/**
* Destructor
*/
virtual ~ActiveMQConnection(void);
public: // Connection Interface Methods
/**
* Creates a new Session to work for this Connection
*/
virtual cms::Session* createSession(void) throw ( cms::CMSException );
/**
* Creates a new Session to work for this Connection using the
* specified acknowledgment mode
* @param the Acknowledgement Mode to use.
*/
virtual cms::Session* createSession(cms::Session::AcknowledgeMode ackMode)
throw ( cms::CMSException );
/**
* Get the Client Id for this session
* @return string version of Client Id
*/
virtual std::string getClientId(void) const;
/**
* Retrieves the Connection Data object for this object.
* @return pointer to a connection data object.
*/
virtual ActiveMQConnectionData* getConnectionData(void){
return connectionData;
}
/**
* Gets the registered Exception Listener for this connection
* @return pointer to an exception listnener or NULL
*/
virtual cms::ExceptionListener* getExceptionListener(void) const{
return exceptionListener; };
/**
* Sets the registed Exception Listener for this connection
* @param pointer to and <code>ExceptionListener</code>
*/
virtual void setExceptionListener(cms::ExceptionListener* listener){
exceptionListener = listener; };
/**
* Close the currently open connection
* @throws CMSException
*/
virtual void close(void) throw ( cms::CMSException );
/**
* Starts or (restarts) a connections delivery of incoming messages
* @throws CMSException
*/
virtual void start(void) throw ( cms::CMSException );
/**
* Stop the flow of incoming messages
* @throws CMSException
*/
virtual void stop(void) throw ( cms::CMSException );
public: // ActiveMQConnection Methods
/**
* Adds the ActiveMQMessageListener to the Mapping of Consumer Id's
* to listeners, all message to that id will be routed to the given
* listener
* @param Consumer Id String
* @param ActiveMQMessageListener Pointer
*/
virtual void addMessageListener(const unsigned int consumerId,
ActiveMQMessageListener* listener);
/**
* Remove the Listener for the specified Consumer Id
* @param Consumer Id string
*/
virtual void removeMessageListener(const unsigned int consumerId);
private:
/**
* Notify the excpetion listener
*/
void fire( exceptions::ActiveMQException& ex )
{
if( exceptionListener != NULL )
{
try
{
exceptionListener->onException( ex );
}
catch(...){}
}
}
/**
* Called to dispatch a message to a particular consumer.
* @param consumer the target consumer of the dispatch.
* @param msg the message to be dispatched.
*/
virtual void onConsumerMessage( connector::ConsumerInfo* consumer,
core::ActiveMQMessage* message );
};
}}
#endif /*ACTIVEMQCONNECTION_H_*/

View File

@ -0,0 +1,120 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#ifndef _ACTIVEMQ_CORE_ACTIVEMQCONNECTIONDATA_H_
#define _ACTIVEMQ_CORE_ACTIVEMQCONNECTIONDATA_H_
#include <activemq/connector/Connector.h>
#include <activemq/transport/Transport.h>
#include <activemq/exceptions/IllegalArgumentException.h>
#include <activemq/util/Properties.h>
namespace activemq{
namespace core{
/**
* Container of the Data that is needed when creating a new connection
* object. Each ActiveMQConnection owns one of these objects. This
* object knows how to clean up the Connection Dependencies correctly
*/
class ActiveMQConnectionData
{
private:
// Connector Object
connector::Connector* connector;
// Transport we are using
transport::Transport* transport;
// Properties used to configure this connection.
util::Properties* properties;
public:
/**
* Creates a new Connection Data object, passing it the data that
* it will manage for the parent connection object.
* @param A connector instance
* @param A Socket instance
* @param A Transport instance
* @throw IllegalArgumentException if an element is NULL
*/
ActiveMQConnectionData( connector::Connector* connector,
transport::Transport* transport,
util::Properties* properties )
{
if( connector == NULL ||
transport == NULL ||
properties == NULL )
{
throw exceptions::IllegalArgumentException(
__FILE__, __LINE__,
"ActiveMQConnectionData::ActiveMQConnectionData - "
"Required Parameter was NULL.");
}
this->connector = connector;
this->transport = transport;
this->properties = properties;
}
virtual ~ActiveMQConnectionData(void)
{
try
{
connector->close();
delete connector;
transport->close();
delete transport;
delete properties;
}
AMQ_CATCH_NOTHROW( exceptions::ActiveMQException )
AMQ_CATCHALL_NOTHROW( )
}
/**
* Get the Connector that this Connection Data object holds
* @return Connector Pointer
*/
virtual connector::Connector* getConnector(void){
return connector;
}
/**
* Get the Connector that this Connection Data object holds
* @return Connector Pointer
*/
virtual transport::Transport* getTransport(void){
return transport;
}
/**
* Gets a reference to the properties that were used to configure
* this Connection.
* @return Properties object reference.
*/
virtual const util::Properties& getProperties(void) const {
return *properties;
}
};
}}
#endif /*_ACTIVEMQ_CORE_ACTIVEMQCONNECTIONDATA_H_*/

View File

@ -0,0 +1,245 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#include "ActiveMQConnectionFactory.h"
#include <activemq/util/Guid.h>
#include <activemq/util/SimpleProperties.h>
#include <activemq/util/StringTokenizer.h>
#include <activemq/connector/ConnectorFactoryMap.h>
#include <activemq/network/SocketFactory.h>
#include <activemq/transport/TransportFactoryMap.h>
#include <activemq/network/Socket.h>
#include <activemq/exceptions/NullPointerException.h>
#include <activemq/core/ActiveMQConnection.h>
#include <activemq/util/StringTokenizer.h>
#include <activemq/support/LibraryInit.h>
using namespace std;
using namespace activemq;
using namespace activemq::core;
using namespace activemq::util;
using namespace activemq::connector;
using namespace activemq::exceptions;
using namespace activemq::network;
using namespace activemq::transport;
////////////////////////////////////////////////////////////////////////////////
ActiveMQConnectionFactory::ActiveMQConnectionFactory(void)
{
brokerURL = "tcp://localhost:61616";
this->username = "";
this->password = "";
this->clientId = "";
}
////////////////////////////////////////////////////////////////////////////////
ActiveMQConnectionFactory::ActiveMQConnectionFactory(const std::string& url,
const std::string& username,
const std::string& password,
const std::string& clientId)
{
brokerURL = url;
this->username = username;
this->password = password;
this->clientId = clientId;
}
////////////////////////////////////////////////////////////////////////////////
cms::Connection* ActiveMQConnectionFactory::createConnection(void)
throw ( cms::CMSException )
{
return createConnection(username, password);
}
////////////////////////////////////////////////////////////////////////////////
cms::Connection* ActiveMQConnectionFactory::createConnection(
const std::string& username,
const std::string& password,
const std::string& clientId )
throw ( cms::CMSException )
{
// Declared here so that they can be deleted in the catch block
SimpleProperties* properties = NULL;
Transport* transport = NULL;
Connector* connector = NULL;
ActiveMQConnectionData* connectionData = NULL;
ActiveMQConnection* connection = NULL;
this->username = username;
this->password = password;
this->clientId = clientId;
try
{
properties = new SimpleProperties;
// if no Client Id specified, create one
if( this->clientId == "" )
{
this->clientId = Guid::createGUIDString();
}
// Store login data in the properties
properties->setProperty( "username", this->username );
properties->setProperty( "password", this->password );
properties->setProperty( "clientId", this->clientId );
// Parse out the properties from the URI
parseURL( brokerURL, *properties );
// Create the Transport that the Connector will use.
string factoryName =
properties->getProperty( "transport", "tcp" );
TransportFactory* factory =
TransportFactoryMap::getInstance().lookup( factoryName );
if( factory == NULL ){
throw ActiveMQException(
__FILE__, __LINE__,
"ActiveMQConnectionFactory::createConnection - "
"unknown transport factory");
}
// Create the transport.
transport = factory->createTransport( *properties );
if( transport == NULL ){
throw ActiveMQException(
__FILE__, __LINE__,
"ActiveMQConnectionFactory::createConnection - "
"failed creating new Transport");
}
// What wire format are we using, defaults to Stomp
std::string wireFormat =
properties->getProperty( "wireFormat", "stomp" );
// Now try and find a factory to create the Connector
ConnectorFactory* connectorfactory =
ConnectorFactoryMap::getInstance()->lookup( wireFormat );
if( connectorfactory == NULL )
{
throw NullPointerException(
__FILE__, __LINE__,
"ActiveMQConnectionFactory::createConnection - "
"Connector for Wire Format not registered in Map");
}
// Create the Connector.
connector = connectorfactory->createConnector( *properties, transport );
if(connector == NULL)
{
throw NullPointerException(
__FILE__, __LINE__,
"ActiveMQConnectionFactory::createConnection - "
"Failed to Create the Connector");
}
// Start the Connector
connector->start();
// Create Holder and store the data for the Connection
connectionData = new ActiveMQConnectionData(
connector, transport, properties );
// Create and Return the new connection object.
connection = new ActiveMQConnection( connectionData );
return connection;
}
catch( exceptions::ActiveMQException& ex )
{
ex.setMark( __FILE__, __LINE__ );
delete connection;
delete connector;
delete transport;
delete properties;
throw ex;
}
catch( ... )
{
exceptions::ActiveMQException ex(
__FILE__, __LINE__,
"ActiveMQConnectionFactory::create - "
"caught unknown exception" );
delete connection;
delete connector;
delete transport;
delete properties;
throw ex;
}
}
////////////////////////////////////////////////////////////////////////////////
void ActiveMQConnectionFactory::parseURL(const std::string& URI,
Properties& properties)
throw ( exceptions::IllegalArgumentException )
{
try
{
StringTokenizer tokenizer(URI, ":/");
std::vector<std::string> tokens;
// Require that there be three tokens at the least, these are
// transport, url, port.
if(tokenizer.countTokens() < 3)
{
throw exceptions::IllegalArgumentException(
__FILE__, __LINE__,
(string("ActiveMQConnectionFactory::parseURL - "
"Marlformed URI: ") + URI).c_str());
}
// First element should be the Transport Type, following that is the
// URL and any params.
properties.setProperty( "transport", tokenizer.nextToken() );
// Parse URL and Port as one item, optional params follow the ?
// and then each param set is delimited with & we extract first
// three chars as they are the left over ://
properties.setProperty( "uri", tokenizer.nextToken("&?").substr(3) );
// Now get all the optional parameters and store them as properties
int count = tokenizer.toArray(tokens);
for(int i = 0; i < count; ++i)
{
tokenizer.reset(tokens[i], "=");
if(tokenizer.countTokens() != 2)
{
throw exceptions::IllegalArgumentException(
__FILE__, __LINE__,
(string("ActiveMQConnectionFactory::parseURL - "
"Marlformed Parameter = ") + tokens[i]).c_str());
}
// Store this param as a property
properties.setProperty(tokenizer.nextToken(), tokenizer.nextToken());
}
}
AMQ_CATCH_RETHROW( IllegalArgumentException )
AMQ_CATCH_EXCEPTION_CONVERT( ActiveMQException, IllegalArgumentException )
AMQ_CATCHALL_THROW( IllegalArgumentException )
}

View File

@ -0,0 +1,178 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#ifndef _ACTIVEMQ_CORE_ACTIVEMQCONNECTIONFACTORY_H_
#define _ACTIVEMQ_CORE_ACTIVEMQCONNECTIONFACTORY_H_
#include <cms/ConnectionFactory.h>
#include <cms/Connection.h>
#include <activemq/exceptions/IllegalArgumentException.h>
namespace activemq{
namespace core{
class util::Properties;
class ActiveMQConnectionFactory : public cms::ConnectionFactory
{
private:
// The user name this factory will use to connect
std::string username;
// The password this factory will use to connect
std::string password;
// The client id to assign to the connection created
std::string clientId;
// The URL of the Broker, the default is:
// "tcp://localhost:61616"
std::string brokerURL;
public:
/**
* Constructor
*/
ActiveMQConnectionFactory(void);
/**
* Constructor
* @param the URL of the Broker we are connecting to.
* @param username to authenticate with, defaults to ""
* @param password to authenticate with, defaults to ""
* @param client Id to assign to connection, defaults to ""
*/
ActiveMQConnectionFactory(const std::string& url,
const std::string& username = "",
const std::string& password = "",
const std::string& clientId = "");
/**
* Destructor
*/
virtual ~ActiveMQConnectionFactory(void) {}
/**
* Creates a connection with the default user identity. The
* connection is created in stopped mode. No messages will be
* delivered until the Connection.start method is explicitly
* called.
* @throws CMSException
*/
virtual cms::Connection* createConnection(void) throw ( cms::CMSException );
/**
* Creates a connection with the specified user identity. The
* connection is created in stopped mode. No messages will be
* delivered until the Connection.start method is explicitly called.
* @throw CMSException.
*/
virtual cms::Connection* createConnection(const std::string& username,
const std::string& password,
const std::string& clientId = "")
throw ( cms::CMSException );
/**
* Sets the username that should be used when creating a new connection
* @param username string
*/
virtual void setUsername(const std::string& username){
this->username = username;
}
/**
* Gets the username that this factory will use when creating a new
* connection instance.
* @return username string, "" for default credentials
*/
virtual const std::string& getUsername(void) const {
return username;
}
/**
* Sets the password that should be used when creating a new connection
* @param password string
*/
virtual void setPassword(const std::string& password){
this->password = password;
}
/**
* Gets the password that this factory will use when creating a new
* connection instance.
* @return password string, "" for default credentials
*/
virtual const std::string& getPassword(void) const {
return password;
}
/**
* Sets the Broker URL that should be used when creating a new
* connection instance
* @param brokerURL string
*/
virtual void setBrokerURL(const std::string& brokerURL){
this->brokerURL = brokerURL;
}
/**
* Gets the Broker URL that this factory will use when creating a new
* connection instance.
* @return brokerURL string
*/
virtual const std::string& getBrokerURL(void) const {
return brokerURL;
}
/**
* Sets the Client Id that should be used when creating a new
* connection instance
* @param clientId string
*/
virtual void setClientId(const std::string& clientId){
this->clientId = clientId;
}
/**
* Gets the Client Id that this factory will use when creating a new
* connection instance.
* @return clientId string
*/
virtual const std::string& getClientId(void) const {
return clientId;
}
protected:
/**
* Parses the properties out of the provided Broker URI and sets
* them in the passed Properties Object.
* @param a Broker URI to parse
* @param a Properties object to set the parsed values in
* @throws IllegalArgumentException if the passed URI is invalid
*/
virtual void parseURL(const std::string& URI,
util::Properties& properties)
throw ( exceptions::IllegalArgumentException );
};
}}
#endif /*_ACTIVEMQ_CORE_ACTIVEMQCONNECTIONFACTORY_H_*/

View File

@ -0,0 +1,443 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#include "ActiveMQConsumer.h"
#include <activemq/exceptions/NullPointerException.h>
#include <activemq/core/ActiveMQSession.h>
#include <activemq/core/ActiveMQMessage.h>
#include <cms/ExceptionListener.h>
using namespace std;
using namespace cms;
using namespace activemq;
using namespace activemq::core;
using namespace activemq::exceptions;
using namespace activemq::concurrent;
////////////////////////////////////////////////////////////////////////////////
ActiveMQConsumer::ActiveMQConsumer(connector::ConsumerInfo* consumerInfo,
ActiveMQSession* session)
{
if(session == NULL || consumerInfo == NULL)
{
throw NullPointerException(
__FILE__, __LINE__,
"ActiveMQConsumer::ActiveMQConsumer - Init with NULL Session");
}
// Init Producer Data
this->session = session;
this->consumerInfo = consumerInfo;
this->listenerThread = NULL;
this->listener = NULL;
this->shutdown = false;
}
////////////////////////////////////////////////////////////////////////////////
ActiveMQConsumer::~ActiveMQConsumer(void)
{
try
{
// Dispose of the Consumer Info, this should stop us from getting
// any more messages.
session->onDestroySessionResource(this);
// Stop the asynchronous message processin thread if it's
// running.
stopThread();
// Purge all the pending messages
purgeMessages();
}
AMQ_CATCH_NOTHROW( ActiveMQException )
AMQ_CATCHALL_NOTHROW( )
}
////////////////////////////////////////////////////////////////////////////////
std::string ActiveMQConsumer::getMessageSelector(void) const
throw ( cms::CMSException )
{
try
{
// Fetch the Selector
return consumerInfo->getMessageSelector();
}
AMQ_CATCH_RETHROW( ActiveMQException )
AMQ_CATCHALL_THROW( ActiveMQException )
}
////////////////////////////////////////////////////////////////////////////////
cms::Message* ActiveMQConsumer::receive(void) throw ( cms::CMSException )
{
try
{
synchronized(&msgQueue)
{
// Check for empty in case of spurious wakeup, or race to
// queue lock.
while(!shutdown && msgQueue.empty())
{
msgQueue.wait();
}
// This will only happen when this object is being
// destroyed in another thread context - kind of
// scary.
if( shutdown ){
throw ActiveMQException( __FILE__, __LINE__,
"Consumer is being destroyed in another thread" );
}
// Fetch the Message then copy it so it can be handed off
// to the user.
cms::Message* message = msgQueue.pop();
cms::Message* result = message->clone();
// The Message is cleaned up here if the Session is not
// transacted, otherwise we let the transaction clean up
// this message as it will have already been ack'd and
// stored for later redelivery.
destroyMessage( message );
return result;
}
return NULL;
}
AMQ_CATCH_RETHROW( ActiveMQException )
AMQ_CATCHALL_THROW( ActiveMQException )
}
////////////////////////////////////////////////////////////////////////////////
cms::Message* ActiveMQConsumer::receive(int millisecs)
throw ( cms::CMSException )
{
try
{
synchronized(&msgQueue)
{
// Check for empty, and wait if its not
if( msgQueue.empty() ){
msgQueue.wait(millisecs);
// if its still empty...bail
if( msgQueue.empty() ) {
return NULL;
}
}
// Fetch the Message then copy it so it can be handed off
// to the user.
cms::Message* message = msgQueue.pop();
cms::Message* result = message->clone();
// The Message is cleaned up here if the Session is not
// transacted, otherwise we let the transaction clean up
// this message as it will have already been ack'd and
// stored for later redelivery.
destroyMessage( message );
return result;
}
return NULL;
}
AMQ_CATCH_RETHROW( ActiveMQException )
AMQ_CATCHALL_THROW( ActiveMQException )
}
////////////////////////////////////////////////////////////////////////////////
cms::Message* ActiveMQConsumer::receiveNoWait(void)
throw ( cms::CMSException )
{
try
{
synchronized(&msgQueue)
{
if(!msgQueue.empty())
{
// Fetch the Message then copy it so it can be handed off
// to the user.
cms::Message* message = msgQueue.pop();
cms::Message* result = message->clone();
// The Message is cleaned up here if the Session is not
// transacted, otherwise we let the transaction clean up
// this message as it will have already been ack'd and
// stored for later redelivery.
destroyMessage( message );
return result;
}
}
return NULL;
}
AMQ_CATCH_RETHROW( ActiveMQException )
AMQ_CATCHALL_THROW( ActiveMQException )
}
////////////////////////////////////////////////////////////////////////////////
void ActiveMQConsumer::setMessageListener(cms::MessageListener* listener)
{
try
{
synchronized(&listenerLock)
{
this->listener = listener;
}
// Start the thread if it isn't already running.
// If it is already running, this method will wake the thread up
// to notify it that there is a message listener, so that it may
// get rid of backed up messages.
startThread();
}
AMQ_CATCH_RETHROW( ActiveMQException )
AMQ_CATCHALL_THROW( ActiveMQException )
}
////////////////////////////////////////////////////////////////////////////////
void ActiveMQConsumer::acknowledgeMessage( const ActiveMQMessage* message )
throw ( cms::CMSException )
{
try
{
// Delegate the Ack to the Session, we cast away copnstness since
// in a transactional session we might need to redeliver this
// message and update its data.
session->acknowledge(this, const_cast< ActiveMQMessage*>( message ) );
}
AMQ_CATCH_RETHROW( ActiveMQException )
AMQ_CATCHALL_THROW( ActiveMQException )
}
////////////////////////////////////////////////////////////////////////////////
void ActiveMQConsumer::run(void)
{
try
{
while(!shutdown)
{
Message* message = NULL;
synchronized(&msgQueue)
{
// Gaurd against spurious wakeup or race to sync lock
// also if the listner has been unregistered we don't
// have anyone to notify, so we wait till a new one is
// registered, and then we will deliver the backlog
while(msgQueue.empty() || listener == NULL)
{
if( shutdown )
{
break;
}
msgQueue.wait();
}
// don't want to process messages if we are shutting down.
if(shutdown)
{
return;
}
// Dispatch the message
message = msgQueue.pop();
}
// Notify the listener
notifyListener( message );
// The Message is cleaned up here if the Session is not
// transacted, otherwise we let the transaction clean up
// this message as it will have already been ack'd and
// stored for later redelivery.
destroyMessage( message );
}
}
catch( ... )
{
cms::ExceptionListener* listener = session->getExceptionListener();
if(listener != NULL)
{
listener->onException( ActiveMQException(
__FILE__, __LINE__,
"ActiveMQConsumer::run - "
"MessageListener threw an unknown Exception, recovering..."));
}
}
}
////////////////////////////////////////////////////////////////////////////////
void ActiveMQConsumer::dispatch(ActiveMQMessage* message)
throw ( cms::CMSException )
{
try
{
// If the Session is in ClientAcknowledge mode, then we set the
// handler in the message to this object and send it out. Otherwise
// we ack it here for all the other Modes.
if(session->getAcknowledgeMode() == Session::ClientAcknowledge)
{
// Register ourself so that we can handle the Message's
// acknowledge method.
message->setAckHandler(this);
}
else
{
session->acknowledge(this, message);
}
// No listener, so we queue it
synchronized(&msgQueue)
{
msgQueue.push( dynamic_cast< cms::Message* >( message ) );
msgQueue.notifyAll();
}
}
AMQ_CATCH_RETHROW( ActiveMQException )
AMQ_CATCHALL_THROW( ActiveMQException )
}
////////////////////////////////////////////////////////////////////////////////
void ActiveMQConsumer::purgeMessages(void)
{
try
{
synchronized(&msgQueue)
{
while(!msgQueue.empty())
{
// destroy these messages if this is not a transacted
// session, if it is then the tranasction will clean
// the messages up.
destroyMessage( msgQueue.pop() );
}
}
}
AMQ_CATCH_RETHROW( ActiveMQException )
AMQ_CATCHALL_THROW( ActiveMQException )
}
////////////////////////////////////////////////////////////////////////////////
void ActiveMQConsumer::onActiveMQMessage( ActiveMQMessage* message )
throw ( ActiveMQException )
{
try
{
if( message == NULL )
{
throw ActiveMQException(
__FILE__, __LINE__,
"ActiveMQConsumer::onActiveMQMessage - Passed a Null Message");
}
this->dispatch( message );
}
AMQ_CATCH_RETHROW( ActiveMQException )
AMQ_CATCHALL_THROW( ActiveMQException )
}
////////////////////////////////////////////////////////////////////////////////
void ActiveMQConsumer::notifyListener( Message* message ){
try
{
MessageListener* listener = NULL;
synchronized(&listenerLock)
{
listener = getMessageListener();
}
if(listener != NULL)
{
listener->onMessage(*message);
}
}
AMQ_CATCH_RETHROW( ActiveMQException )
AMQ_CATCHALL_THROW( ActiveMQException )
}
////////////////////////////////////////////////////////////////////////////////
void ActiveMQConsumer::destroyMessage( Message* message ){
try
{
/**
* Only destroy the message if the session is NOT transacted. If
* it is, the session will take care of it.
*/
if( message != NULL && !session->isTransacted() )
{
delete message;
}
}
AMQ_CATCH_RETHROW( ActiveMQException )
AMQ_CATCHALL_THROW( ActiveMQException )
}
////////////////////////////////////////////////////////////////////////////////
void ActiveMQConsumer::startThread(){
try
{
// Start the thread, if it's not already started.
if(listenerThread == NULL)
{
listenerThread = new Thread(this);
listenerThread->start();
}
// notify the Queue so that any pending messages get delivered
synchronized(&msgQueue)
{
msgQueue.notifyAll();
}
}
AMQ_CATCH_RETHROW( ActiveMQException )
AMQ_CATCHALL_THROW( ActiveMQException )
}
////////////////////////////////////////////////////////////////////////////////
void ActiveMQConsumer::stopThread(){
try
{
shutdown = true;
// if the thread is running signal it to quit and then
// wait for run to return so thread can die
if(listenerThread != NULL)
{
synchronized( &msgQueue )
{
// Force a wakeup if run is in a wait.
msgQueue.notifyAll();
}
// Wait for it to die and then delete it.
listenerThread->join();
delete listenerThread;
listenerThread = NULL;
}
}
AMQ_CATCH_RETHROW( ActiveMQException )
AMQ_CATCHALL_THROW( ActiveMQException )
}

View File

@ -0,0 +1,227 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#ifndef _ACTIVEMQ_CORE_ACTIVEMQCONSUMER_H_
#define _ACTIVEMQ_CORE_ACTIVEMQCONSUMER_H_
#include <cms/MessageConsumer.h>
#include <cms/MessageListener.h>
#include <cms/Message.h>
#include <cms/CMSException.h>
#include <activemq/connector/ConsumerInfo.h>
#include <activemq/util/Queue.h>
#include <activemq/core/ActiveMQAckHandler.h>
#include <activemq/core/ActiveMQMessageListener.h>
#include <activemq/core/ActiveMQSessionResource.h>
#include <activemq/concurrent/Runnable.h>
#include <activemq/concurrent/Mutex.h>
namespace activemq{
namespace core{
class ActiveMQSession;
class ActiveMQConsumer :
public cms::MessageConsumer,
public ActiveMQAckHandler,
public concurrent::Runnable,
public ActiveMQMessageListener,
public ActiveMQSessionResource
{
private:
// The session that owns this Consumer
ActiveMQSession* session;
// The Consumer info for this Consumer
connector::ConsumerInfo* consumerInfo;
// The Message Listener for this Consumer
cms::MessageListener* listener;
// Lock to protect us from dispatching to a dead listener
concurrent::Mutex listenerLock;
// Message Queue
util::Queue<cms::Message*> msgQueue;
// Thread to notif a listener if one is added
concurrent::Thread* listenerThread;
// Boolean to indicate that the listener Thread is shutting
// down and the run method should return.
bool shutdown;
public:
/**
* Constructor
*/
ActiveMQConsumer(connector::ConsumerInfo* consumerInfo,
ActiveMQSession* session);
/**
* Destructor
*/
virtual ~ActiveMQConsumer(void);
public: // Interface Implementation
/**
* Synchronously Receive a Message
* @return new message
* @throws CMSException
*/
virtual cms::Message* receive(void) throw ( cms::CMSException );
/**
* Synchronously Receive a Message, time out after defined interval.
* Returns null if nothing read.
* @return new message
* @throws CMSException
*/
virtual cms::Message* receive(int millisecs) throw ( cms::CMSException );
/**
* Receive a Message, does not wait if there isn't a new message
* to read, returns NULL if nothing read.
* @return new message
* @throws CMSException
*/
virtual cms::Message* receiveNoWait(void) throw ( cms::CMSException );
/**
* Sets the MessageListener that this class will send notifs on
* @param MessageListener interface pointer
*/
virtual void setMessageListener(cms::MessageListener* listener);
/**
* Gets the MessageListener that this class will send notifs on
* @param MessageListener interface pointer
*/
virtual cms::MessageListener* getMessageListener(void) const {
return this->listener;
}
/**
* Gets this message consumer's message selector expression.
* @return This Consumer's selector expression or "".
* @throws cms::CMSException
*/
virtual std::string getMessageSelector(void) const
throw ( cms::CMSException );
/**
* Method called to acknowledge the message passed
* @param Message to Acknowlegde
* @throw CMSException
*/
virtual void acknowledgeMessage( const ActiveMQMessage* message )
throw ( cms::CMSException );
/**
* Run method that is called from the Thread class when this object
* is registered with a Thread and started. This function reads from
* the message queue and dispatches calls to the MessageConsumer that
* is registered with this class.
*
* It is a error for a MessageListener to throw an exception in their
* onMessage method, but if it does happen this function will get any
* registered exception listener from the session and notify it.
*/
virtual void run(void);
public: // ActiveMQMessageListener Methods
/**
* Called asynchronously when a new message is received, the message
* that is passed is now the property of the callee, and the caller
* will disavowe all knowledge of the message, i.e Callee must delete.
* @param Message object pointer
*/
virtual void onActiveMQMessage( ActiveMQMessage* message )
throw ( exceptions::ActiveMQException );
public: // ActiveMQSessionResource
/**
* Retrieve the Connector resource that is associated with
* this Session resource.
* @return pointer to a Connector Resource, can be NULL
*/
virtual connector::ConnectorResource* getConnectorResource(void) {
return consumerInfo;
}
public: // ActiveMQConsumer Methods
/**
* Called to dispatch a message to this consumer, this is usually
* called from the context of another thread. This will enqueue a
* message on the Consumers Queue, or notify a listener if one is
* currently registered.
* @param cms::Message pointer to the message to dispatch
* @throw cms::CMSException
*/
virtual void dispatch(ActiveMQMessage* message)
throw ( cms::CMSException );
/**
* Get the Consumer information for this consumer
* @return Pointer to a Consumer Info Object
*/
virtual connector::ConsumerInfo* getConsumerInfo(void) {
return consumerInfo;
}
protected:
/**
* Purges all messages currently in the queue. This can be as a
* result of a rollback, or of the consumer being shutdown.
*/
virtual void purgeMessages(void);
/**
* Destroys the message if the session is transacted, otherwise
* does nothing.
*/
virtual void destroyMessage( cms::Message* message );
/**
* Notifies the listener of a message.
*/
void notifyListener( cms::Message* message );
/**
* Starts the message processing thread to receive messages
* asynchronously. This thread is started when setMessageListener
* is invoked, which means that the caller is choosing to use this
* consumer asynchronously instead of synchronously (receive).
*/
void startThread();
/**
* Stops the asynchronous message processing thread if it's started.
*/
void stopThread();
};
}}
#endif /*_ACTIVEMQ_CORE_ACTIVEMQCONSUMER_H_*/

View File

@ -0,0 +1,68 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#ifndef _ACTIVEMQ_CORE_ACTIVEMQMESSAGE_H_
#define _ACTIVEMQ_CORE_ACTIVEMQMESSAGE_H_
#include <cms/Message.h>
namespace activemq{
namespace core{
class ActiveMQAckHandler;
/**
* Interface for all ActiveMQ Messages that will pass through the core
* API layer. This interface defines a method that the API uses to set
* an Acknowledgement handler that will be called by the message when
* a user calls the <code>acknowledge</code> method of the Message
* interface. This is only done when the Session that this message
* passes through is in Client Acknowledge mode.
*/
class ActiveMQMessage
{
public:
/**
* Destructor
*/
virtual ~ActiveMQMessage(void) {}
/**
* Sets the Acknowledgement Handler that this Message will use
* when the Acknowledge method is called.
* @param ActiveMQAckHandler
*/
virtual void setAckHandler(ActiveMQAckHandler* handler) = 0;
/**
* Gets the number of times this message has been redelivered.
* @return redelivery count
*/
virtual int getRedeliveryCount(void) const = 0;
/**
* Sets the count of the number of times this message has been
* redelivered
* @param redelivery count
*/
virtual void setRedeliveryCount(int count) = 0;
};
}}
#endif /*_ACTIVEMQ_CORE_ACTIVEMQMESSAGE_H_*/

View File

@ -0,0 +1,47 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#ifndef _ACTIVEMQ_CORE_ACTIVEMQMESSAGELISTENER_H_
#define _ACTIVEMQ_CORE_ACTIVEMQMESSAGELISTENER_H_
#include <activemq/exceptions/ActiveMQException.h>
namespace activemq{
namespace core{
class ActiveMQMessage;
class ActiveMQMessageListener
{
public:
virtual ~ActiveMQMessageListener(void) {}
/**
* Called asynchronously when a new message is received, the message
* that is passed is now the property of the callee, and the caller
* will disavowe all knowledge of the message, i.e Callee must delete.
* @param Message object pointer
*/
virtual void onActiveMQMessage( ActiveMQMessage* message )
throw ( exceptions::ActiveMQException ) = 0;
};
}}
#endif /*_ACTIVEMQ_CORE_ACTIVEMQMESSAGELISTENER_H_*/

View File

@ -0,0 +1,91 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#include "ActiveMQProducer.h"
#include <activemq/core/ActiveMQSession.h>
#include <activemq/exceptions/NullPointerException.h>
using namespace std;
using namespace activemq;
using namespace activemq::core;
using namespace activemq::connector;
using namespace activemq::exceptions;
////////////////////////////////////////////////////////////////////////////////
ActiveMQProducer::ActiveMQProducer(connector::ProducerInfo* producerInfo,
ActiveMQSession* session)
{
if(session == NULL || producerInfo == NULL)
{
throw NullPointerException(
__FILE__, __LINE__,
"ActiveMQProducer::ActiveMQProducer - Init with NULL Session");
}
// Init Producer Data
this->session = session;
this->producerInfo = producerInfo;
// Default the Delivery options
deliveryMode = cms::Message::PERSISTANT;
disableMsgId = false;
disableTimestamps = false;
priority = 4;
timeToLive = 0;
}
////////////////////////////////////////////////////////////////////////////////
ActiveMQProducer::~ActiveMQProducer(void)
{
try
{
// Dispose of the ProducerInfo
session->onDestroySessionResource(this);
}
AMQ_CATCH_NOTHROW( ActiveMQException )
AMQ_CATCHALL_NOTHROW( )
}
////////////////////////////////////////////////////////////////////////////////
void ActiveMQProducer::send(cms::Message& message)
throw ( cms::CMSException )
{
try
{
send(producerInfo->getDestination(), message);
}
AMQ_CATCH_RETHROW( ActiveMQException )
AMQ_CATCHALL_THROW( ActiveMQException )
}
////////////////////////////////////////////////////////////////////////////////
void ActiveMQProducer::send(const cms::Destination& destination,
cms::Message& message) throw ( cms::CMSException )
{
try
{
// configure the message
message.setCMSDestination(destination);
message.setCMSDeliveryMode(deliveryMode);
message.setCMSPriority(priority);
message.setCMSExpiration(timeToLive);
session->send(&message, this);
}
AMQ_CATCH_RETHROW( ActiveMQException )
AMQ_CATCHALL_THROW( ActiveMQException )
}

View File

@ -0,0 +1,191 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#ifndef _ACTIVEMQ_CORE_ACTIVEMQPRODUCER_H_
#define _ACTIVEMQ_CORE_ACTIVEMQPRODUCER_H_
#include <cms/MessageProducer.h>
#include <cms/Message.h>
#include <cms/Destination.h>
#include <activemq/core/ActiveMQSessionResource.h>
#include <activemq/connector/ProducerInfo.h>
namespace activemq{
namespace core{
class ActiveMQSession;
class ActiveMQProducer : public cms::MessageProducer,
public ActiveMQSessionResource
{
private:
// Delivery Mode of this Producer
cms::Message::DeliveryMode deliveryMode;
// Disable the Message Id
bool disableMsgId;
// Disable sending timestamps
bool disableTimestamps;
// Priority Level to send at
int priority;
// Time to live setting for message
int timeToLive;
// Session that this producer sends to.
ActiveMQSession* session;
// This Producers protocal specific info object
connector::ProducerInfo* producerInfo;
public:
/**
* Constructor
*/
ActiveMQProducer( connector::ProducerInfo* producerInfo,
ActiveMQSession* session );
/**
* Destructor
*/
virtual ~ActiveMQProducer(void);
/**
* Sends the message to the default producer destination.
* @param a Message Object Pointer
* @throws CMSException
*/
virtual void send( cms::Message& message ) throw ( cms::CMSException );
/**
* Sends the message to the designated destination.
* @param a Message Object Pointer
* @throws CMSException
*/
virtual void send( const cms::Destination& destination,
cms::Message& message) throw ( cms::CMSException );
/**
* Sets the delivery mode for this Producer
* @param The DeliveryMode
*/
virtual void setDeliveryMode(cms::Message::DeliveryMode mode) {
deliveryMode = mode;
}
/**
* Gets the delivery mode for this Producer
* @return The DeliveryMode
*/
virtual cms::Message::DeliveryMode getDeliveryMode(void) const {
return deliveryMode;
}
/**
* Sets if Message Ids are disbled for this Producer
* @param boolean indicating enable / disable (true / false)
*/
virtual void setDisableMessageId( bool value ) {
disableMsgId = value;
}
/**
* Sets if Message Ids are disbled for this Producer
* @param boolean indicating enable / disable (true / false)
*/
virtual bool getDisableMessageId(void) const {
return disableMsgId;
}
/**
* Sets if Message Time Stamps are disbled for this Producer
* @param boolean indicating enable / disable (true / false)
*/
virtual void setDisableMessageTimeStamp( bool value ) {
disableTimestamps = value;
}
/**
* Sets if Message Time Stamps are disbled for this Producer
* @param boolean indicating enable / disable (true / false)
*/
virtual bool getDisableMessageTimeStamp(void) const {
return disableTimestamps;
}
/**
* Sets the Priority that this Producers sends messages at
* @param int value for Priority level
*/
virtual void setPriority( int priority ) {
this->priority = priority;
}
/**
* Gets the Priority level that this producer sends messages at
* @return int based priority level
*/
virtual int getPriority(void) const {
return priority;
}
/**
* Sets the Time to Live that this Producers sends messages with
* @param int value for time to live
*/
virtual void setTimeToLive( int time ) {
timeToLive = time;
}
/**
* Gets the Time to Live that this producer sends messages with
* @return int based Time to Live
*/
virtual int getTimeToLive(void) const {
return timeToLive;
}
public: // ActiveMQSessionResource
/**
* Retrieve the Connector resource that is associated with
* this Session resource.
* @return pointer to a Connector Resource, can be NULL
*/
virtual connector::ConnectorResource* getConnectorResource(void) {
return producerInfo;
}
public:
/**
* Retrives this object ProducerInfo pointer
* @return ProducerInfo pointer
*/
virtual connector::ProducerInfo* getProducerInfo(void){
return producerInfo;
}
};
}}
#endif /*_ACTIVEMQ_CORE_ACTIVEMQPRODUCER_H_*/

View File

@ -0,0 +1,545 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#include "ActiveMQSession.h"
#include <activemq/exceptions/InvalidStateException.h>
#include <activemq/exceptions/NullPointerException.h>
#include <activemq/core/ActiveMQConnection.h>
#include <activemq/core/ActiveMQTransaction.h>
#include <activemq/core/ActiveMQConsumer.h>
#include <activemq/core/ActiveMQMessage.h>
#include <activemq/core/ActiveMQProducer.h>
#include <activemq/connector/TransactionInfo.h>
using namespace std;
using namespace cms;
using namespace activemq;
using namespace activemq::core;
using namespace activemq::util;
using namespace activemq::connector;
using namespace activemq::exceptions;
////////////////////////////////////////////////////////////////////////////////
ActiveMQSession::ActiveMQSession( SessionInfo* sessionInfo,
const Properties& properties,
ActiveMQConnection* connection)
{
if(sessionInfo == NULL || connection == NULL)
{
throw NullPointerException(
__FILE__, __LINE__,
"ActiveMQSession::ActiveMQSession - Init with NULL data");
}
this->sessionInfo = sessionInfo;
this->transaction = NULL;
this->connection = connection;
this->closed = false;
// Create a Transaction object only if the session is transactional
if(isTransacted())
{
transaction =
new ActiveMQTransaction(connection, this, properties );
}
}
////////////////////////////////////////////////////////////////////////////////
ActiveMQSession::~ActiveMQSession(void)
{
try
{
// Destroy this session's resources
close();
}
AMQ_CATCH_NOTHROW( ActiveMQException )
AMQ_CATCHALL_NOTHROW( )
}
////////////////////////////////////////////////////////////////////////////////
void ActiveMQSession::close(void) throw ( cms::CMSException )
{
if(closed)
{
return;
}
try
{
// Destry the Transaction
delete transaction;
// Destroy this sessions resources
connection->getConnectionData()->
getConnector()->destroyResource(sessionInfo);
// mark as done
closed = true;
}
AMQ_CATCH_NOTHROW( ActiveMQException )
AMQ_CATCHALL_NOTHROW( )
}
////////////////////////////////////////////////////////////////////////////////
void ActiveMQSession::commit(void) throw ( cms::CMSException )
{
try
{
if(closed || !isTransacted())
{
throw InvalidStateException(
__FILE__, __LINE__,
"ActiveMQSession::commit - This Session Can't Commit");
}
// Commit the Transaction
transaction->commit();
}
AMQ_CATCH_NOTHROW( ActiveMQException )
AMQ_CATCHALL_NOTHROW( )
}
////////////////////////////////////////////////////////////////////////////////
void ActiveMQSession::rollback(void) throw ( cms::CMSException )
{
try
{
if(closed || !isTransacted())
{
throw InvalidStateException(
__FILE__, __LINE__,
"ActiveMQSession::rollback - This Session Can't Rollback");
}
// Rollback the Transaction
transaction->rollback();
}
AMQ_CATCH_NOTHROW( ActiveMQException )
AMQ_CATCHALL_NOTHROW( )
}
////////////////////////////////////////////////////////////////////////////////
cms::MessageConsumer* ActiveMQSession::createConsumer(
cms::Destination& destination)
throw ( cms::CMSException )
{
try
{
if(closed)
{
throw InvalidStateException(
__FILE__, __LINE__,
"ActiveMQSession::createConsumer - Session Already Closed");
}
return createConsumer(destination, "");
}
AMQ_CATCH_RETHROW( ActiveMQException )
AMQ_CATCHALL_THROW( ActiveMQException )
}
////////////////////////////////////////////////////////////////////////////////
cms::MessageConsumer* ActiveMQSession::createConsumer(
cms::Destination& destination,
const std::string& selector)
throw ( cms::CMSException )
{
try
{
if(closed)
{
throw InvalidStateException(
__FILE__, __LINE__,
"ActiveMQSession::createConsumer - Session Already Closed");
}
ActiveMQConsumer* consumer = new ActiveMQConsumer(
connection->getConnectionData()->getConnector()->
createConsumer(&destination, sessionInfo, selector), this);
connection->addMessageListener(
consumer->getConsumerInfo()->getConsumerId(), consumer );
return consumer;
}
AMQ_CATCH_RETHROW( ActiveMQException )
AMQ_CATCHALL_THROW( ActiveMQException )
}
////////////////////////////////////////////////////////////////////////////////
cms::MessageConsumer* ActiveMQSession::createDurableConsumer(
cms::Topic& destination,
const std::string& name,
const std::string& selector,
bool noLocal )
throw ( cms::CMSException )
{
try
{
if(closed)
{
throw InvalidStateException(
__FILE__, __LINE__,
"ActiveMQSession::createProducer - Session Already Closed");
}
ActiveMQConsumer* consumer = new ActiveMQConsumer(
connection->getConnectionData()->getConnector()->
createDurableConsumer( &destination, sessionInfo, name, selector, noLocal ), this);
connection->addMessageListener(
consumer->getConsumerInfo()->getConsumerId(), consumer );
return consumer;
}
AMQ_CATCH_RETHROW( ActiveMQException )
AMQ_CATCHALL_THROW( ActiveMQException )
}
////////////////////////////////////////////////////////////////////////////////
cms::MessageProducer* ActiveMQSession::createProducer(
cms::Destination& destination)
throw ( cms::CMSException )
{
try
{
if(closed)
{
throw InvalidStateException(
__FILE__, __LINE__,
"ActiveMQSession::createProducer - Session Already Closed");
}
return new ActiveMQProducer(
connection->getConnectionData()->getConnector()->
createProducer(&destination, sessionInfo), this);
}
AMQ_CATCH_RETHROW( ActiveMQException )
AMQ_CATCHALL_THROW( ActiveMQException )
}
////////////////////////////////////////////////////////////////////////////////
cms::Queue* ActiveMQSession::createQueue(const std::string& queueName)
throw ( cms::CMSException )
{
try
{
if(closed)
{
throw InvalidStateException(
__FILE__, __LINE__,
"ActiveMQSession::createQueue - Session Already Closed");
}
return connection->getConnectionData()->
getConnector()->createQueue(queueName, sessionInfo);
}
AMQ_CATCH_RETHROW( ActiveMQException )
AMQ_CATCHALL_THROW( ActiveMQException )
}
////////////////////////////////////////////////////////////////////////////////
cms::Topic* ActiveMQSession::createTopic(const std::string& topicName)
throw ( cms::CMSException )
{
try
{
if(closed)
{
throw InvalidStateException(
__FILE__, __LINE__,
"ActiveMQSession::createTopic - Session Already Closed");
}
return connection->getConnectionData()->
getConnector()->createTopic(topicName, sessionInfo);
}
AMQ_CATCH_RETHROW( ActiveMQException )
AMQ_CATCHALL_THROW( ActiveMQException )
}
////////////////////////////////////////////////////////////////////////////////
cms::TemporaryQueue* ActiveMQSession::createTemporaryQueue(void)
throw ( cms::CMSException )
{
try
{
if(closed)
{
throw InvalidStateException(
__FILE__, __LINE__,
"ActiveMQSession::createTemporaryQueue - Session Already Closed");
}
return connection->getConnectionData()->
getConnector()->createTemporaryQueue(sessionInfo);
}
AMQ_CATCH_RETHROW( ActiveMQException )
AMQ_CATCHALL_THROW( ActiveMQException )
}
////////////////////////////////////////////////////////////////////////////////
cms::TemporaryTopic* ActiveMQSession::createTemporaryTopic(void)
throw ( cms::CMSException )
{
try
{
if(closed)
{
throw InvalidStateException(
__FILE__, __LINE__,
"ActiveMQSession::createTemporaryTopic - Session Already Closed");
}
return connection->getConnectionData()->
getConnector()->createTemporaryTopic(sessionInfo);
}
AMQ_CATCH_RETHROW( ActiveMQException )
AMQ_CATCHALL_THROW( ActiveMQException )
}
////////////////////////////////////////////////////////////////////////////////
cms::Message* ActiveMQSession::createMessage(void)
throw ( cms::CMSException )
{
try
{
if(closed)
{
throw InvalidStateException(
__FILE__, __LINE__,
"ActiveMQSession::createMessage - Session Already Closed");
}
return connection->getConnectionData()->
getConnector()->createMessage( sessionInfo, transaction );
}
AMQ_CATCH_RETHROW( ActiveMQException )
AMQ_CATCHALL_THROW( ActiveMQException )
}
////////////////////////////////////////////////////////////////////////////////
cms::BytesMessage* ActiveMQSession::createBytesMessage(void)
throw ( cms::CMSException)
{
try
{
if(closed)
{
throw InvalidStateException(
__FILE__, __LINE__,
"ActiveMQSession::createBytesMessage - Session Already Closed");
}
return connection->getConnectionData()->
getConnector()->createBytesMessage( sessionInfo, transaction );
}
AMQ_CATCH_RETHROW( ActiveMQException )
AMQ_CATCHALL_THROW( ActiveMQException )
}
////////////////////////////////////////////////////////////////////////////////
cms::BytesMessage* ActiveMQSession::createBytesMessage(
const unsigned char* bytes,
unsigned long bytesSize)
throw ( cms::CMSException)
{
try
{
BytesMessage* msg = createBytesMessage();
msg->setBodyBytes(bytes, bytesSize);
return msg;
}
AMQ_CATCH_RETHROW( ActiveMQException )
AMQ_CATCHALL_THROW( ActiveMQException )
}
////////////////////////////////////////////////////////////////////////////////
cms::TextMessage* ActiveMQSession::createTextMessage(void)
throw ( cms::CMSException )
{
try
{
if(closed)
{
throw InvalidStateException(
__FILE__, __LINE__,
"ActiveMQSession::createTextMessage - Session Already Closed");
}
return connection->getConnectionData()->
getConnector()->createTextMessage( sessionInfo, transaction );
}
AMQ_CATCH_RETHROW( ActiveMQException )
AMQ_CATCHALL_THROW( ActiveMQException )
}
////////////////////////////////////////////////////////////////////////////////
cms::TextMessage* ActiveMQSession::createTextMessage(const std::string& text)
throw ( cms::CMSException )
{
try
{
TextMessage* msg = createTextMessage();
msg->setText(text.c_str());
return msg;
}
AMQ_CATCH_RETHROW( ActiveMQException )
AMQ_CATCHALL_THROW( ActiveMQException )
}
////////////////////////////////////////////////////////////////////////////////
cms::MapMessage* ActiveMQSession::createMapMessage(void)
throw ( cms::CMSException )
{
try
{
if(closed)
{
throw InvalidStateException(
__FILE__, __LINE__,
"ActiveMQSession::createMapMessage - Session Already Closed");
}
return connection->
getConnectionData()->
getConnector()->createMapMessage( sessionInfo, transaction );
}
AMQ_CATCH_RETHROW( ActiveMQException )
AMQ_CATCHALL_THROW( ActiveMQException )
}
////////////////////////////////////////////////////////////////////////////////
cms::Session::AcknowledgeMode ActiveMQSession::getAcknowledgeMode(void) const
{
return sessionInfo != NULL ?
sessionInfo->getAckMode() : Session::AutoAcknowledge;
}
////////////////////////////////////////////////////////////////////////////////
bool ActiveMQSession::isTransacted(void) const
{
return sessionInfo != NULL ?
sessionInfo->getAckMode() == Session::Transactional : false;
}
////////////////////////////////////////////////////////////////////////////////
void ActiveMQSession::acknowledge(ActiveMQConsumer* consumer,
ActiveMQMessage* message)
throw ( cms::CMSException )
{
try
{
if( closed )
{
throw InvalidStateException(
__FILE__, __LINE__,
"ActiveMQSession::acknowledgeMessage - Session Already Closed");
}
// Stores the Message and its consumer in the tranasction, if the
// session is a transactional one.
if(isTransacted())
{
transaction->addToTransaction( message, consumer );
}
// Delegate to connector to ack this message.
return connection->getConnectionData()->
getConnector()->acknowledge(
sessionInfo, dynamic_cast< cms::Message* >( message ) );
}
AMQ_CATCH_RETHROW( ActiveMQException )
AMQ_CATCHALL_THROW( ActiveMQException )
}
////////////////////////////////////////////////////////////////////////////////
void ActiveMQSession::send(cms::Message* message, ActiveMQProducer* producer)
throw ( cms::CMSException )
{
try
{
if(closed)
{
throw InvalidStateException(
__FILE__, __LINE__,
"ActiveMQSession::onProducerClose - Session Already Closed");
}
// Send via the connection
connection->getConnectionData()->
getConnector()->send( message, producer->getProducerInfo() );
}
AMQ_CATCH_RETHROW( ActiveMQException )
AMQ_CATCHALL_THROW( ActiveMQException )
}
////////////////////////////////////////////////////////////////////////////////
void ActiveMQSession::onDestroySessionResource(
ActiveMQSessionResource* resource )
throw ( cms::CMSException )
{
try
{
if(closed)
{
throw InvalidStateException(
__FILE__, __LINE__,
"ActiveMQSession::onProducerClose - Session Already Closed");
}
ActiveMQConsumer* consumer =
dynamic_cast< ActiveMQConsumer*>( resource );
if( consumer != NULL )
{
// Remove this Consumer from the Connection
connection->removeMessageListener(
consumer->getConsumerInfo()->getConsumerId());
// Remove this consumer from the Transaction if we are
// transactional
if( transaction != NULL )
{
transaction->removeFromTransaction(consumer);
}
}
// Free its resources.
connection->getConnectionData()->
getConnector()->destroyResource( resource->getConnectorResource() );
}
AMQ_CATCH_RETHROW( ActiveMQException )
AMQ_CATCHALL_THROW( ActiveMQException )
}
////////////////////////////////////////////////////////////////////////////////
cms::ExceptionListener* ActiveMQSession::getExceptionListener(void)
{
if(connection != NULL)
{
return connection->getExceptionListener();
}
return NULL;
}

View File

@ -0,0 +1,271 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#ifndef _ACTIVEMQ_CORE_ACTIVEMQSESSION_H_
#define _ACTIVEMQ_CORE_ACTIVEMQSESSION_H_
#include <cms/Session.h>
#include <cms/ExceptionListener.h>
#include <activemq/connector/SessionInfo.h>
#include <activemq/core/ActiveMQSessionResource.h>
namespace activemq{
namespace core{
class ActiveMQTransaction;
class ActiveMQConnection;
class ActiveMQConsumer;
class ActiveMQMessage;
class ActiveMQProducer;
class ActiveMQConsumer;
class ActiveMQSession : public cms::Session
{
private:
// SessionInfo for this Session
connector::SessionInfo* sessionInfo;
// Transaction Management object
ActiveMQTransaction* transaction;
// Connection
ActiveMQConnection* connection;
// Bool to indicate if this session was closed.
bool closed;
public:
/**
* Constructor
*/
ActiveMQSession( connector::SessionInfo* sessionInfo,
const util::Properties& properties,
ActiveMQConnection* connection);
/**
* Destructor
*/
virtual ~ActiveMQSession(void);
public: // Implements Mehtods
/**
* Closes the Session
* @throw CMSException
*/
virtual void close(void) throw ( cms::CMSException );
/**
* Commits all messages done in this transaction and releases any
* locks currently held.
* @throws CMSException
*/
virtual void commit(void) throw ( cms::CMSException );
/**
* Rollsback all messages done in this transaction and releases any
* locks currently held.
* @throws CMSException
*/
virtual void rollback(void) throw ( cms::CMSException );
/**
* Creates a MessageConsumer for the specified destination.
* @param the Destination that this consumer receiving messages for.
* @throws CMSException
*/
virtual cms::MessageConsumer* createConsumer(cms::Destination& destination)
throw ( cms::CMSException );
/**
* Creates a MessageConsumer for the specified destination, using a
* message selector.
* @param the Destination that this consumer receiving messages for.
* @throws CMSException
*/
virtual cms::MessageConsumer* createConsumer(cms::Destination& destination,
const std::string& selector)
throw ( cms::CMSException );
/**
* Creates a durable subscriber to the specified topic, using a
* message selector
* @param the topic to subscribe to
* @param name used to identify the subscription
* @param only messages matching the selector are received
* @throws CMSException
*/
virtual cms::MessageConsumer* createDurableConsumer(
cms::Topic& destination,
const std::string& name,
const std::string& selector,
bool noLocal = false)
throw ( cms::CMSException );
/**
* Creates a MessageProducer to send messages to the specified
* destination.
* @param the Destination to publish on
* @throws CMSException
*/
virtual cms::MessageProducer* createProducer(cms::Destination& destination)
throw ( cms::CMSException );
/**
* Creates a queue identity given a Queue name.
* @param the name of the new Queue
* @throws CMSException
*/
virtual cms::Queue* createQueue(const std::string& queueName)
throw ( cms::CMSException );
/**
* Creates a topic identity given a Queue name.
* @param the name of the new Topic
* @throws CMSException
*/
virtual cms::Topic* createTopic(const std::string& topicName)
throw ( cms::CMSException );
/**
* Creates a TemporaryQueue object.
* @throws CMSException
*/
virtual cms::TemporaryQueue* createTemporaryQueue(void)
throw ( cms::CMSException );
/**
* Creates a TemporaryTopic object.
* @throws CMSException
*/
virtual cms::TemporaryTopic* createTemporaryTopic(void)
throw ( cms::CMSException );
/**
* Creates a new Message
* @throws CMSException
*/
virtual cms::Message* createMessage(void)
throw ( cms::CMSException );
/**
* Creates a BytesMessage
* @throws CMSException
*/
virtual cms::BytesMessage* createBytesMessage(void)
throw ( cms::CMSException);
/**
* Creates a BytesMessage and sets the paylod to the passed value
* @param an array of bytes to set in the message
* @param the size of the bytes array, or number of bytes to use
* @throws CMSException
*/
virtual cms::BytesMessage* createBytesMessage(const unsigned char* bytes,
unsigned long bytesSize)
throw ( cms::CMSException);
/**
* Creates a new TextMessage
* @throws CMSException
*/
virtual cms::TextMessage* createTextMessage(void)
throw ( cms::CMSException );
/**
* Creates a new TextMessage and set the text to the value given
* @param the initial text for the message
* @throws CMSException
*/
virtual cms::TextMessage* createTextMessage(const std::string& text)
throw ( cms::CMSException );
/**
* Creates a new TextMessage
* @throws CMSException
*/
virtual cms::MapMessage* createMapMessage(void)
throw ( cms::CMSException );
/**
* Returns the acknowledgement mode of the session.
* @return the Sessions Acknowledge Mode
*/
virtual cms::Session::AcknowledgeMode getAcknowledgeMode(void) const;
/**
* Gets if the Sessions is a Transacted Session
* @return transacted true - false.
*/
virtual bool isTransacted(void) const;
public: // ActiveMQSession specific Methods
/**
* Sends a message from the Producer specified
* @param cms::Message pointer
* @param Producer Information
* @throws CMSException
*/
virtual void send(cms::Message* message, ActiveMQProducer* producer)
throw ( cms::CMSException );
/**
* When a ActiveMQ core object is closed or destroyed it should call
* back and let the session know that it is going away, this allows
* the session to clean up any associated resources. This method
* destroy's the data that is associated with a Producer object
* @param The Producer that is being destoryed
* @throw CMSException
*/
virtual void onDestroySessionResource( ActiveMQSessionResource* resource )
throw ( cms::CMSException );
/**
* Called to acknowledge the receipt of a message.
* @param The consumer that received the message
* @param The Message to acknowledge.
* @throws CMSException
*/
virtual void acknowledge(ActiveMQConsumer* consumer,
ActiveMQMessage* message)
throw ( cms::CMSException);
/**
* This method gets any registered exception listener of this sessions
* connection and returns it. Mainly intended for use by the objects
* that this session creates so that they can notify the client of
* exceptions that occur in the context of another thread.
* @returns cms::ExceptionListener pointer or NULL
*/
virtual cms::ExceptionListener* getExceptionListener(void);
/**
* Gets the Session Information object for this session, if the
* session is closed than this returns null
* @return SessionInfo Pointer
*/
virtual connector::SessionInfo* getSessionInfo(void) {
return sessionInfo;
}
};
}}
#endif /*_ACTIVEMQ_CORE_ACTIVEMQSESSION_H_*/

View File

@ -0,0 +1,42 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#ifndef _ACTIVEMQ_CORE_ACTIVEMQSESSIONRESOURCE_H_
#define _ACTIVEMQ_CORE_ACTIVEMQSESSIONRESOURCE_H_
#include <activemq/connector/ConnectorResource.h>
namespace activemq{
namespace core{
class ActiveMQSessionResource
{
public:
virtual ~ActiveMQSessionResource(void) {}
/**
* Retrieve the Connector resource that is associated with
* this Session resource.
* @return pointer to a Connector Resource, can be NULL
*/
virtual connector::ConnectorResource* getConnectorResource(void) = 0;
};
}}
#endif /*_ACTIVEMQ_CORE_ACTIVEMQSESSIONRESOURCE_H_*/

View File

@ -0,0 +1,343 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#include "ActiveMQTransaction.h"
#include <activemq/exceptions/NullPointerException.h>
#include <activemq/core/ActiveMQSession.h>
#include <activemq/core/ActiveMQConnection.h>
#include <activemq/core/ActiveMQConsumer.h>
#include <activemq/core/ActiveMQMessage.h>
#include <activemq/util/Integer.h>
#include <activemq/concurrent/ThreadPool.h>
using namespace std;
using namespace cms;
using namespace activemq;
using namespace activemq::core;
using namespace activemq::util;
using namespace activemq::connector;
using namespace activemq::concurrent;
using namespace activemq::exceptions;
////////////////////////////////////////////////////////////////////////////////
ActiveMQTransaction::ActiveMQTransaction( ActiveMQConnection* connection,
ActiveMQSession* session,
const Properties& properties )
{
try
{
if(connection == NULL || session == NULL)
{
throw NullPointerException(
__FILE__, __LINE__,
"ActiveMQTransaction::ActiveMQTransaction - "
"Initialized with a NULL connection data");
}
// Store State Data
this->connection = connection;
this->session = session;
this->taskCount = 0;
// convert from property Strings to int.
redeliveryDelay = Integer::parseInt(
properties.getProperty("transaction.redeliveryDelay", "25") );
maxRedeliveries = Integer::parseInt(
properties.getProperty("transaction.maxRedeliveryCount", "5") );
// Start a new Transaction
transactionInfo = connection->getConnectionData()->
getConnector()->startTransaction( session->getSessionInfo() );
}
AMQ_CATCH_RETHROW( ActiveMQException )
AMQ_CATCHALL_THROW( ActiveMQException )
}
////////////////////////////////////////////////////////////////////////////////
ActiveMQTransaction::~ActiveMQTransaction(void)
{
try
{
// Inform the connector we are rolling back before we close so that
// the provider knows we didn't complete this transaction
connection->getConnectionData()->getConnector()->
rollback(transactionInfo, session->getSessionInfo());
// Clean up
clearTransaction();
// Must allow all the tasks to complete before we destruct otherwise
// the callbacks will cause an exception.
synchronized(&tasksDone)
{
while(taskCount != 0)
{
tasksDone.wait(1000);
// TODO - Log Here to get some indication if we are stuck
}
}
}
AMQ_CATCH_NOTHROW( ActiveMQException )
AMQ_CATCHALL_NOTHROW( )
}
////////////////////////////////////////////////////////////////////////////////
void ActiveMQTransaction::clearTransaction(void)
{
try
{
if(transactionInfo != NULL)
{
// Dispose of the ProducerInfo
connection->getConnectionData()->
getConnector()->destroyResource(transactionInfo);
}
synchronized(&rollbackLock)
{
// If there are any messages that are being transacted, then
// they die once and for all here.
RollbackMap::iterator itr = rollbackMap.begin();
for(; itr != rollbackMap.end(); ++itr)
{
MessageList::iterator msgItr = itr->second.begin();
for(; msgItr != itr->second.end(); ++msgItr)
{
delete *msgItr;
}
}
rollbackMap.clear();
}
}
AMQ_CATCH_RETHROW( ActiveMQException )
AMQ_CATCHALL_THROW( ActiveMQException )
}
////////////////////////////////////////////////////////////////////////////////
void ActiveMQTransaction::addToTransaction( ActiveMQMessage* message,
ActiveMQMessageListener* listener )
{
synchronized(&rollbackLock)
{
// Store in the Multi Map
rollbackMap[listener].push_back(message);
}
}
////////////////////////////////////////////////////////////////////////////////
void ActiveMQTransaction::removeFromTransaction(
ActiveMQMessageListener* listener )
{
try
{
// Delete all the messages, then remove the consumer's entry from
// the Rollback Map.
synchronized(&rollbackLock)
{
RollbackMap::iterator rb_itr = rollbackMap.find( listener );
if( rb_itr == rollbackMap.end() )
{
return;
}
MessageList::iterator itr = rb_itr->second.begin();
for(; itr != rollbackMap[listener].end(); ++itr)
{
delete *itr;
}
// Erase the entry from the map
rollbackMap.erase(listener);
}
}
AMQ_CATCH_RETHROW( ActiveMQException )
AMQ_CATCHALL_THROW( ActiveMQException )
}
////////////////////////////////////////////////////////////////////////////////
void ActiveMQTransaction::commit(void) throw ( exceptions::ActiveMQException )
{
try
{
if(this->transactionInfo == NULL)
{
throw InvalidStateException(
__FILE__, __LINE__,
"ActiveMQTransaction::begin - "
"Commit called before transaction was started.");
}
// Commit the current Transaction
connection->getConnectionData()->getConnector()->
commit( transactionInfo, session->getSessionInfo() );
// Clean out the Transaction
clearTransaction();
// Start a new Transaction
transactionInfo = connection->getConnectionData()->
getConnector()->startTransaction( session->getSessionInfo() );
}
AMQ_CATCH_RETHROW( ActiveMQException )
AMQ_CATCHALL_THROW( ActiveMQException )
}
////////////////////////////////////////////////////////////////////////////////
void ActiveMQTransaction::rollback(void) throw ( exceptions::ActiveMQException )
{
try
{
if(this->transactionInfo == NULL)
{
throw InvalidStateException(
__FILE__, __LINE__,
"ActiveMQTransaction::rollback - "
"Rollback called before transaction was started.");
}
// Rollback the Transaction
connection->getConnectionData()->getConnector()->
rollback( transactionInfo, session->getSessionInfo() );
// Dispose of the ProducerInfo
connection->getConnectionData()->
getConnector()->destroyResource(transactionInfo);
// Start a new Transaction
transactionInfo = connection->getConnectionData()->
getConnector()->startTransaction( session->getSessionInfo() );
// Create a task for each consumer and copy its message list out
// to the Rollback task so we can clear the list for new messages
// that might come in next.
// NOTE - This could be turned into a Thread so that the connection
// doesn't have to wait on this method to complete an release its
// mutex so it can dispatch new messages. That would however requre
// copying the whole map over to the thread.
synchronized(&rollbackLock)
{
RollbackMap::iterator itr = rollbackMap.begin();
for(; itr != rollbackMap.end(); ++itr)
{
ThreadPool::getInstance()->queueTask(make_pair(
new RollbackTask( itr->first,
connection,
session,
itr->second,
maxRedeliveries,
redeliveryDelay) , this));
// Count the tasks started.
taskCount++;
}
// Clear the map. Ownership of the messages is now handed off
// to the rollback tasks.
rollbackMap.clear();
}
}
AMQ_CATCH_RETHROW( ActiveMQException )
AMQ_CATCHALL_THROW( ActiveMQException )
}
////////////////////////////////////////////////////////////////////////////////
void ActiveMQTransaction::onTaskComplete( Runnable* task )
{
try
{
// Delete the task
delete task;
taskCount--;
if(taskCount == 0)
{
synchronized(&tasksDone)
{
tasksDone.notifyAll();
}
}
}
AMQ_CATCH_NOTHROW( ActiveMQException )
AMQ_CATCHALL_NOTHROW( )
}
////////////////////////////////////////////////////////////////////////////////
void ActiveMQTransaction::onTaskException( Runnable* task,
exceptions::ActiveMQException& ex )
{
try
{
// Delegate
onTaskComplete(task);
// Route the Error
ExceptionListener* listener = connection->getExceptionListener();
if(listener != NULL)
{
listener->onException( ex );
}
}
AMQ_CATCH_NOTHROW( ActiveMQException )
AMQ_CATCHALL_NOTHROW( )
}
////////////////////////////////////////////////////////////////////////////////
void ActiveMQTransaction::RollbackTask::run(void)
{
try
{
MessageList::iterator itr = messages.begin();
for(; itr != messages.end(); ++itr)
{
(*itr)->setRedeliveryCount((*itr)->getRedeliveryCount() + 1);
// Redeliver Messages at some point in the future
Thread::sleep(redeliveryDelay);
if((*itr)->getRedeliveryCount() >= maxRedeliveries)
{
// Poison Ack the Message, we give up processing this one
connection->getConnectionData()->getConnector()->
acknowledge(
session->getSessionInfo(),
dynamic_cast< Message* >(*itr),
Connector::PoisonAck );
// Won't redeliver this so we kill it here.
delete *itr;
return;
}
listener->onActiveMQMessage(*itr);
}
}
AMQ_CATCH_RETHROW( ActiveMQException )
AMQ_CATCHALL_THROW( ActiveMQException )
}

View File

@ -0,0 +1,283 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#ifndef _ACTIVEMQ_CORE_ACTIVEMQTRANSACTION_H_
#define _ACTIVEMQ_CORE_ACTIVEMQTRANSACTION_H_
#include <map>
#include <list>
#include <cms/Message.h>
#include <cms/CMSException.h>
#include <activemq/concurrent/Mutex.h>
#include <activemq/concurrent/TaskListener.h>
#include <activemq/concurrent/Runnable.h>
#include <activemq/connector/TransactionInfo.h>
#include <activemq/exceptions/InvalidStateException.h>
#include <activemq/exceptions/IllegalArgumentException.h>
#include <activemq/util/Properties.h>
#include <activemq/core/ActiveMQSessionResource.h>
namespace activemq{
namespace core{
class ActiveMQConnection;
class ActiveMQSession;
class ActiveMQMessage;
class ActiveMQMessageListener;
/**
* Transaction Management class, hold messages that are to be redelivered
* upon a request to rollback. The Tranasction represents an always
* running transaction, when it is committed or rolled back it silently
* creates a new transaction for the next set of messages. The only
* way to permanently end this tranaction is to delete it.
*
* Configuration options
*
* transaction.redeliveryDelay
* Wait time between the redelivery of each message
*
* transaction.maxRedeliveryCount
* Max number of times a message can be redelivered, if the session is
* rolled back more than this many time, the message is dropped.
*/
class ActiveMQTransaction : public concurrent::TaskListener,
public connector::TransactionInfo,
public ActiveMQSessionResource
{
private:
// List type for holding messages
typedef std::list< ActiveMQMessage* > MessageList;
// Mapping of MessageListener Ids to Lists of Messages that are
// redelivered on a Rollback
typedef std::map< ActiveMQMessageListener*, MessageList > RollbackMap;
private:
// Connection this Transaction is associated with
ActiveMQConnection* connection;
// Session this Transaction is associated with
ActiveMQSession* session;
// Transaction Info for the current Transaction
connector::TransactionInfo* transactionInfo;
// Map of ActiveMQMessageListener to Messages to Rollback
RollbackMap rollbackMap;
// Lock object to protect the rollback Map
concurrent::Mutex rollbackLock;
// Max number of redeliveries before we quit
int maxRedeliveries;
// Wait time between sends of message on a rollback
int redeliveryDelay;
// Mutex that is signaled when all tasks complete.
concurrent::Mutex tasksDone;
// Count of Tasks that are outstanding
int taskCount;
public:
/**
* Constructor
*/
ActiveMQTransaction( ActiveMQConnection* connection,
ActiveMQSession* session,
const util::Properties& properties );
/**
* Destructor
*/
virtual ~ActiveMQTransaction(void);
/**
* Adds the Message as a part of the Transaction for the specified
* ActiveMQConsumer.
* @param ActiveMQMessage
* @param ActiveMQMessageListener
*/
virtual void addToTransaction( ActiveMQMessage* message,
ActiveMQMessageListener* listener );
/**
* Removes the ActiveMQMessageListener and all of its transacted
* messages from the Transaction, this is usually only done when
* a ActiveMQMessageListener is destroyed.
* @param consumer who is to be removed.
*/
virtual void removeFromTransaction( ActiveMQMessageListener* listener );
/**
* Commit the current Transaction
* @throw CMSException
*/
virtual void commit(void) throw ( exceptions::ActiveMQException );
/**
* Rollback the current Transaction
* @throw CMSException
*/
virtual void rollback(void) throw ( exceptions::ActiveMQException );
/**
* Get the Transaction Information object for the current
* Transaction, returns NULL if no transaction is running
* @return TransactionInfo
*/
virtual connector::TransactionInfo* getTransactionInfo(void) const {
return transactionInfo;
}
public: // TransactionInfo Interface
/**
* Gets the Transction Id
* @return unsigned int Id
*/
virtual unsigned int getTransactionId(void) const {
return transactionInfo->getTransactionId();
}
/**
* Sets the Transction Id
* @param unsigned int Id
*/
virtual void setTransactionId( const unsigned int id ) {
transactionInfo->setTransactionId( id );
}
/**
* Gets the Session Info that this transaction is attached too
* @return SessionnInfo pointer
*/
virtual const connector::SessionInfo* getSessionInfo(void) const {
return transactionInfo->getSessionInfo();
}
/**
* Gets the Session Info that this transaction is attached too
* @return SessionnInfo pointer
*/
virtual void setSessionInfo( const connector::SessionInfo* session ) {
transactionInfo->setSessionInfo( session );
}
protected: // Task Listener Interface
/**
* Called when a queued task has completed, the task that
* finished is passed along for user consumption. The task is
* deleted and the count of outstanding tasks is reduced.
* @param Runnable Pointer to the task that finished
*/
virtual void onTaskComplete( concurrent::Runnable* task );
/**
* Called when a queued task has thrown an exception while
* being run. The Callee should assume that this was an
* unrecoverable exeption and that this task is now defunct.
* Deletes the Task and notifies the connection that the
* exception has occurred. Reduce the outstanding task count.
* @param Runnable Pointer to the task
* @param The ActiveMQException that was thrown.
*/
virtual void onTaskException( concurrent::Runnable* task,
exceptions::ActiveMQException& ex );
public: // ActiveMQSessionResource
/**
* Retrieve the Connector resource that is associated with
* this Session resource.
* @return pointer to a Connector Resource, can be NULL
*/
virtual connector::ConnectorResource* getConnectorResource(void) {
return transactionInfo;
}
protected:
/**
* Clean out all Messages from the Rollback Map, deleting the
* messages as it goes. Destroys the Transaction Info object as
* well.
* @throw ActiveMQException
*/
virtual void clearTransaction(void);
private:
// Internal class that is used to redeliver one consumers worth
// of messages from this transaction.
class RollbackTask : public concurrent::Runnable
{
private:
// Wait time before redelivery in millisecs
int redeliveryDelay;
// Max number of time to redeliver this message
int maxRedeliveries;
// Messages to Redeliver
MessageList messages;
// Consumer we are redelivering to
ActiveMQMessageListener* listener;
// Connection to use for sending message acks
ActiveMQConnection* connection;
// Session for this Transaction
ActiveMQSession* session;
public:
RollbackTask( ActiveMQMessageListener* listener,
ActiveMQConnection* connection,
ActiveMQSession* session,
MessageList& messages,
int maxRedeliveries,
int redeliveryDelay ){
// Store State Data.
this->messages = messages;
this->listener = listener;
this->redeliveryDelay = redeliveryDelay;
this->maxRedeliveries = maxRedeliveries;
this->session = session;
this->connection = connection;
}
// Dispatches the Messages to the Consumer.
virtual void run(void);
};
};
}}
#endif /*_ACTIVEMQ_CORE_ACTIVEMQTRANSACTION_H_*/

View File

@ -0,0 +1,70 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#include <stdio.h>
#include "ActiveMQException.h"
#include <activemq/logger/LoggerDefines.h>
using namespace activemq;
using namespace activemq::exceptions;
using namespace std;
////////////////////////////////////////////////////////////////////////////////
void ActiveMQException::buildMessage(const char* format, va_list& vargs)
{
// Allocate buffer with a guess of it's size
int size = 128;
// Format string
while( true ){
// Allocate a buffer of the specified size.
char* buffer = new char[size];
int written = vsnprintf(buffer, size, format, vargs);
if (written > -1 && written < size-1) {
// Guessed size was enough. Assign the string.
message.assign (buffer, written);
break;
}
// Our buffer wasn't big enough - destroy the old buffer,
// double the size and try again.
delete [] buffer;
size *= 2;
}
activemq::logger::SimpleLogger logger("com.yadda1");
logger.log( message );
}
////////////////////////////////////////////////////////////////////////////////
void ActiveMQException::setMark( const char* file, const int lineNumber ){
// Add this mark to the end of the stack trace.
stackTrace.push_back( std::make_pair( (std::string)file, (int)lineNumber ) );
ostringstream stream;
stream << "\tFILE: " << stackTrace[stackTrace.size()-1].first;
stream << ", LINE: " << stackTrace[stackTrace.size()-1].second;
activemq::logger::SimpleLogger logger("com.yadda2");
logger.log( stream.str() );
}

View File

@ -0,0 +1,178 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#ifndef ACTIVEMQ_EXCEPTIONS_ACTIVEMQEXCEPTION_H
#define ACTIVEMQ_EXCEPTIONS_ACTIVEMQEXCEPTION_H
#include <cms/CMSException.h>
#include <activemq/exceptions/ExceptionDefines.h>
#include <stdarg.h>
#include <sstream>
namespace activemq{
namespace exceptions{
/*
* Base class for all exceptions.
*/
class ActiveMQException : public cms::CMSException
{
private:
/**
* The cause of this exception.
*/
std::string message;
/**
* The stack trace.
*/
std::vector< std::pair< std::string, int> > stackTrace;
public:
/**
* Default Constructor
*/
ActiveMQException(void) {}
/**
* Copy Constructor
*/
ActiveMQException( const ActiveMQException& ex ){
*this = ex;
}
/**
* Constructor - Initializes the file name and line number where
* this message occured. Sets the message to report, using an
* optional list of arguments to parse into the message
* @param file name where exception occurs
* @param line number where the exception occurred.
* @param message to report
* @param list of primitives that are formatted into the message
*/
ActiveMQException(const char* file, const int lineNumber,
const char* msg, ...)
{
va_list vargs ;
va_start(vargs, msg) ;
buildMessage(msg, vargs) ;
// Set the first mark for this exception.
setMark( file, lineNumber );
}
/**
* Destructor
*/
virtual ~ActiveMQException(){}
/**
* Gets the message for this exception.
*/
virtual const char* getMessage() const{ return message.c_str(); }
/**
* Sets the cause for this exception.
* @param msg the format string for the msg.
*/
virtual void setMessage( const char* msg, ... ){
va_list vargs ;
va_start(vargs, msg) ;
buildMessage(msg, vargs) ;
}
/**
* Adds a file/line number to the stack trace.
* @param file The name of the file calling this method (use __FILE__).
* @param lineNumber The line number in the calling file (use __LINE__).
*/
virtual void setMark( const char* file, const int lineNumber );
/**
* Clones this exception. This is useful for cases where you need
* to preserve the type of the original exception as well as the message.
* All subclasses should override.
*/
virtual ActiveMQException* clone() const{
return new ActiveMQException( *this );
}
/**
* Provides the stack trace for every point where
* this exception was caught, marked, and rethrown. The first
* item in the returned vector is the first point where the mark
* was set (e.g. where the exception was created).
* @return the stack trace.
*/
virtual std::vector< std::pair< std::string, int> > getStackTrace() const{
return stackTrace;
}
/**
* Prints the stack trace to std::err
*/
virtual void printStackTrace() const{
printStackTrace( std::cerr );
}
/**
* Prints the stack trace to the given output stream.
* @param stream the target output stream.
*/
virtual void printStackTrace( std::ostream& stream ) const{
stream << getStackTraceString();
}
/**
* Gets the stack trace as one contiguous string.
*/
virtual std::string getStackTraceString() const{
// Create the output stream.
std::ostringstream stream;
// Write the message and each stack entry.
stream << message << std::endl;
for( unsigned int ix=0; ix<stackTrace.size(); ++ix ){
stream << "\tFILE: " << stackTrace[ix].first;
stream << ", LINE: " << stackTrace[ix].second;
stream << std::endl;
}
// Return the string from the output stream.
return stream.str();
}
/**
* Assignment operator.
*/
virtual ActiveMQException& operator =( const ActiveMQException& ex ){
this->message = ex.message;
this->stackTrace = ex.stackTrace;
return *this;
}
protected:
virtual void buildMessage(const char* format, va_list& vargs);
};
}}
#endif /*ACTIVEMQ_EXCEPTIONS_ACTIVEMQEXCEPTION_H*/

View File

@ -0,0 +1,78 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#ifndef _ACTIVEMQ_EXCEPTIONS_EXCEPTIONDEFINES_H_
#define _ACTIVEMQ_EXCEPTIONS_EXCEPTIONDEFINES_H_
/**
* Macro for catching and rethrowing an exception of
* a given type.
* @param type The type of the exception to throw
* (e.g. ActiveMQException ).
*/
#define AMQ_CATCH_RETHROW( type ) \
catch( type& ex ){ \
ex.setMark( __FILE__, __LINE__ ); \
throw ex; \
}
/**
* Macro for catching an exception of one type and then rethrowing
* as another type.
* @param sourceType the type of the exception to be caught.
* @param targetType the type of the exception to be thrown.
*/
#define AMQ_CATCH_EXCEPTION_CONVERT( sourceType, targetType ) \
catch( sourceType& ex ){ \
targetType target( ex ); \
target.setMark( __FILE__, __LINE__ ); \
throw target; \
}
/**
* A catch-all that throws a known exception.
* @param type the type of exception to be thrown.
*/
#define AMQ_CATCHALL_THROW( type ) \
catch( ... ){ \
type ex( __FILE__, __LINE__, \
"caught unknown exception" ); \
throw ex; \
}
/**
* A catch-all that does not throw an exception, one use would
* be to catch any exception in a destructor and mark it, but not
* throw so that cleanup would continue as normal.
*/
#define AMQ_CATCHALL_NOTHROW( ) \
catch( ... ){ \
exceptions::ActiveMQException ex( __FILE__, __LINE__, \
"caught unknown exception, not rethrowing" ); \
}
/**
* Macro for catching and rethrowing an exception of
* a given type.
* @param type The type of the exception to throw
* (e.g. ActiveMQException ).
*/
#define AMQ_CATCH_NOTHROW( type ) \
catch( type& ex ){ \
ex.setMark( __FILE__, __LINE__ ); \
}
#endif /*_ACTIVEMQ_EXCEPTIONS_EXCEPTIONDEFINES_H_*/

View File

@ -0,0 +1,90 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#ifndef ACTIVEMQ_EXCEPTIONS_ILLEGALARGUMENTEXCEPTION_H_
#define ACTIVEMQ_EXCEPTIONS_ILLEGALARGUMENTEXCEPTION_H_
#include <activemq/exceptions/ActiveMQException.h>
namespace activemq{
namespace exceptions{
/*
* Thrown when an illegal argument was passed into a method.
*/
class IllegalArgumentException : public ActiveMQException
{
public:
/**
* Default Constructor
*/
IllegalArgumentException(){};
/**
* Conversion Constructor from some other ActiveMQException
* @param An exception that should become this type of Exception
*/
IllegalArgumentException( const ActiveMQException& ex ){
*(ActiveMQException*)this = ex;
}
/**
* Copy Constructor
*/
IllegalArgumentException( const IllegalArgumentException& ex ){
*(ActiveMQException*)this = ex;
}
/**
* Constructor - Initializes the file name and line number where
* this message occured. Sets the message to report, using an
* optional list of arguments to parse into the message
* @param file name where exception occurs
* @param line number where the exception occurred.
* @param message to report
* @param list of primitives that are formatted into the message
*/
IllegalArgumentException(const char* file, const int lineNumber,
const char* msg, ...)
{
va_list vargs ;
va_start(vargs, msg) ;
buildMessage(msg, vargs) ;
// Set the first mark for this exception.
setMark( file, lineNumber );
}
/**
* Clones this exception. This is useful for cases where you need
* to preserve the type of the original exception as well as the message.
* All subclasses should override.
*/
virtual ActiveMQException* clone() const{
return new IllegalArgumentException( *this );
}
/**
* Destructor
*/
virtual ~IllegalArgumentException(){}
};
}}
#endif /*ACTIVEMQ_EXCEPTIONS_ILLEGALARGUMENTEXCEPTION_H_*/

View File

@ -0,0 +1,92 @@
/*
* Copyright 2006 The Apache Software Foundation or its licensors, as
* applicable.
*
* 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.
*/
#ifndef ACTIVEMQ_EXCEPTIONS_ILLEGALMONITORSTATEEXCEPTION_H_
#define ACTIVEMQ_EXCEPTIONS_ILLEGALMONITORSTATEEXCEPTION_H_
#include <activemq/exceptions/ActiveMQException.h>
namespace activemq{
namespace exceptions{
/*
* Thrown when an error occurs from calling a method from syncronizable
* and the caller doesn't hold a lock on the object.
*/
class IllegalMonitorStateException : public ActiveMQException
{
public:
/**
* Default Constructor
*/
IllegalMonitorStateException(void) {};
/**
* Conversion Constructor from some other ActiveMQException
* @param An exception that should become this type of Exception
*/
IllegalMonitorStateException(const ActiveMQException& ex){
*(ActiveMQException*)this = ex;
}
/**
* Copy Constructor
*/
IllegalMonitorStateException(const IllegalMonitorStateException& ex){
*(ActiveMQException*)this = ex;
}
/**
* Constructor - Initializes the file name and line number where
* this message occured. Sets the message to report, using an
* optional list of arguments to parse into the message
* @param file name where exception occurs
* @param line number where the exception occurred.
* @param message to report
* @param list of primitives that are formatted into the message
*/
IllegalMonitorStateException(const char* file,
const int lineNumber,
const char* msg, ...)
{
va_list vargs;
va_start(vargs, msg);
buildMessage(msg, vargs);
// Set the first mark for this exception.
setMark(file, lineNumber);
}
/**
* Clones this exception. This is useful for cases where you need
* to preserve the type of the original exception as well as the message.
* All subclasses should override.
*/
virtual ActiveMQException* clone(void) const{
return new IllegalMonitorStateException(*this);
}
/**
* Destructor
*/
virtual ~IllegalMonitorStateException(void) {}
};
}}
#endif /*ACTIVEMQ_EXCEPTIONS_ILLEGALMONITORSTATEEXCEPTION_H_*/

Some files were not shown because too many files have changed in this diff Show More