ActiveMQ User Reference
I've been working with ActiveMQ now for over 1.5 years and as I learn more about this great open source product, I jot down what I have learned in this reference. I hope you find it useful and that it can help you successfully deploy ActiveMQ. Click here to download the pdf.
A Monitoring Framework For ActiveMQ
I am currently working on a monitoring framework for ActiveMQ that I call "AMon". It essentially allows you to define your Monitor components (I refer to them as Monlets) and inject them into the message broker. AMon is heavily dependent on Camel and the Java implementation of the UEL (JUEL) to make things easier for the Monlet developer. Also looking into designing a SNMP Agent and MIB for ActiveMQ and allow the Monlets to generate traps. I hope to have AMon ready by 2Q09. Here's a snippet from the user guide that I am working on.
AMon is a monitoring framework that is specifically designed for the ActiveMQ message broker. On its own, AMon does not do the actual monitoring of an ActiveMQ message broker. What AMon provides is a framework that facilitates the rapid development and deployment of one or more monitor components (Monlets). These Monlets, which are deployed directly onto an ActiveMQ message broker, do the actual monitoring of the message broker.
A Monlet is an end-user defined component that comprises one or more conditional statements and the actions that are invoked if and when those conditions test positive. In general, the conditions test the runtime or operational state of those objects that comprise the ActiveMQ message broker.
Unlike ActiveMQ’s advisory system, AMon gives the Monlets direct access to the message broker’s object hierarchies. The broker comprises many objects and properties; therefore, there are also many conditions that can be defined. Here are just a couple of examples of the types of Monlets and the objects that they can monitor.
1. Resource Monlet – one that tests whether a particular resource (memory, queue, etc) has reached a certain threshold and fires off an email or JMS message to another process if that threshold is reached.
2. Audit Monlet – one that tests whether a message that is being routed through the broker meets some sort of condition (e.g., includes some user-defined property that has been assigned a particular value) and if the condition is met the contents of the message can be dumped to an audit log.
AMon also allows Monlets to test conditions associated with the broker’s hosting Java Virtual Machine (JVM). For example, a Monlet can test whether the number of active threads within the JVM or its memory heap size has reached a certain threshold.
AMon maintains a clean separation between the Monlets and the broker objects that they are monitoring. This separation is provided by a combination of the following:
1. Event messages that are published by the AMon core component or engine
2. AMon’s default monitoring expression language (MEL)
3. The Apache Camel integration framework’s routing Domain Specific Language (DSL).
The above items combine to make developing Monlets relatively easy and allows the AMon system to be extensible and flexible.
Sunday, December 28, 2008
Saturday, December 27, 2008
Using LDAP-based JNDI To Access ActiveMQ's JMS Administrable Objects
The primary benefit of using a LDAP DS is that all information, especially information pertaining to ActiveMQ administered objects, can be centrally and securely stored and managed. This is especially attractive for large enterprise class environments that employ many JMS clients.
Java objects are stored in the LDAP DS according to rfc2713.
The following ActiveMQ administered objects are stored in the DS as javax.naming.Reference objects.
org.apache.activemq.ActiveMQConnectionFactory
org.apache.activemq.command.ActiveMQTopic
org.apache.activemq.command.ActiveMQQueue
The following is an example LDAP Interchange Format (LDIF) file for an ActiveMQConnectionFactory object.
The first thing your Java code must do is acquire and configure an instance of this package’s Context interface implementation (i.e., LdapCtx), which it will do so via LdapCtxFactory. The following sections describe three different methods for doing this.
Method 1 - Environment Properties Hashtable
With this method, your Java code specifies the fully qualified class name of the LdapCtxFactory through an entry in an environment property Hashtable, which represents the resulting Context’s environment. The following code snippet illustrates this.
Hashtable env = new Hashtable(); env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory");
Using the same Hashtable, your code must then specify the URL for the target LDAP directory server along with the proper security credentials (username and password). These will all be used to establish a connection to that target directory service.
env.put(Context.PROVIDER_URL,"ldap://ldap.wiz.com:389/ou=adminobjects,o=amq,dc=example,dc=com"); env.put(Context.SECURITY_PRINCIPAL, "uid=admin,ou=system");
env.put(Context.SECURITY_CREDENTIALS, "secret");
Notice how the PROVIDER_URL property must contain the distinguished name (DN) that pertains to the root of the directory information tree (DIT) that is used for storing the ActiveMQ administered objects. Now that your environment properties have all been properly set, your code can create an instance of the Context as this code snippet illustrates.
Context ctx = new InitialContext(env);
Remember that the object doing the actual Context implementation is LdapCtx.
Method 2 - The jndi.properties File
1. You specify the service provider and its environment properties through the jndi.properties file.
2. The configuration burden is shifted from the developer to whoever launches the application.
3.Modifications to the configuration will not require corresponding modifications to the application’s source code.
Here is an example jndi.properties file.
#
# This file must be placed in the JMS client’s CLASSPATH
#
# The 'java.naming.factory.initial' property tells the JVM what JNDI context
# factory (or local JNDI provider) it should use for the application. In this
# case, we're telling it to use the AmqInitialContextFactory object
# as the context factory.
java.naming.factory.initial = com.sun.jndi.ldap.LdapCtxFactory java.naming.provider.url=ldap://192.168.1.148:10389/ou=adminobjects,o=amq,dc=example,dc=com java.naming.security.credentials=secret
java.naming.security.principal=uid=admin,ou=system
The JMS client will then create the Context with one simple statement as this snippet illustrates.
Context ctx = new InitialContext();
Unlike the previous method, this method does not have to specify an environment Hashtable, because the default property values are automatically picked up from the jndi.properties file.
NOTE: The jndi.properties file must be located in the JMS client’s class path.
More information on the jndi.properties file can be found at this URL. http://java.sun.com/products/jndi/tutorial/beyond/env/source.html
Method 3 - System Properties
You can also use ‘system properties’ as yet a third method; for example.
$ java -Djava.naming.factory.initial=\ com.sun.jndi.ldap.LdapCtxFactory -Djava.naming.provider.url=\ ldap:// 192.168.1.148:10389/ou=adminobjects,o=ActiveMQ2,dc=example,dc=com\ -Djava.naming.security.credentials=secret \ -Djava.naming.security.principal=uid=admin,ou=system \ YourJMSApplication
As when using the jndi.properties file, the JMS client would then create the Context with one simple statement as this snippet illustrates.
Context ctx = new InitialContext();
JNDI Operations
Now that your JMS client has acquired a Context, it can perform JNDI operations (lookup, bind, rebind, unbind, etc.) against the corresponding LDAP DS. Your JMS client doesn’t have to concern itself with transforming the ActiveMQ administered objects to and from Reference objects. Recall that the Reference object is one of only a handful of object types that can be stored in the DS. The following code snippets, which assume you’re using the jndi.properties or system properties methods, illustrate how relatively simple it is to perform some of the JNDI operations
/** Bind an ActiveMQConnectionFactory object to the DS. **/
import javax.naming.InitialContext;
import javax.naming.Context;
import org.apache.activemq.ActiveMQConnectionFactory;
public class JndiBind {
public static void main(String[] args) throws Exception {
new JndiBind().init();
}
public void init() throws Exception {
try {
Context ctx = new InitialContext();
// Create an ActiveMQ connection factory, give it some
// URL and save it in the directory.
ActiveMQConnectionFactory factory1 = new ActiveMQConnectionFactory();
factory1.setBrokerURL("tcp://localhost:61683");
ctx.bind("cn=factory3", factory1);
}
catch(Exception e){
e.printStackTrace();
}
}
}
Lookup an ActiveMQConnectionFactory object from the DS. Note how in this example we’re casting the ActiveMQConnectionFactory that is returned from the lookup to a JMS ConnectionFactory. This helps isolate the code from the JMS provider.
This post describes how to use the JNDI to store and retrieve ActiveMQ’s JMS administered objects (i.e., connection factory and destination) to and from a LDAP directory server (DS) like Apache Directory Server.
The primary benefit of using a LDAP DS is that all information, especially information pertaining to ActiveMQ administered objects, can be centrally and securely stored and managed. This is especially attractive for large enterprise class environments that employ many JMS clients.
Java objects are stored in the LDAP DS according to rfc2713.
The following ActiveMQ administered objects are stored in the DS as javax.naming.Reference objects.
org.apache.activemq.ActiveMQConnectionFactory
org.apache.activemq.command.ActiveMQTopic
org.apache.activemq.command.ActiveMQQueue
The following is an example LDAP Interchange Format (LDIF) file for an ActiveMQConnectionFactory object.
dn: cn=factory2,ou=adminobjects,o=amq,dc=example,dc=com
objectClass: javaNamingReference
objectClass: javaObject
objectClass: javaContainer
objectClass: top
cn: factory2
javaclassname: org.apache.activemq.ActiveMQConnectionFactory
javafactory: org.apache.activemq.jndi.JNDIReferenceFactory
javareferenceaddress: #0#blobTransferPolicy.uploadUrl#http://localhost:8080/uploads/
javareferenceaddress: #1#brokerURL#tcp://localhost:61670
javareferenceaddress: #2#objectMessageSerializationDefered#false
javareferenceaddress: #4#redeliveryPolicy.initialRedeliveryDelay#1000
javareferenceaddress: #3#prefetchPolicy.queuePrefetch#1000
The first thing your Java code must do is acquire and configure an instance of this package’s Context interface implementation (i.e., LdapCtx), which it will do so via LdapCtxFactory. The following sections describe three different methods for doing this.
Method 1 - Environment Properties Hashtable
With this method, your Java code specifies the fully qualified class name of the LdapCtxFactory through an entry in an environment property Hashtable, which represents the resulting Context’s environment. The following code snippet illustrates this.
Hashtable env = new Hashtable(); env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory");
Using the same Hashtable, your code must then specify the URL for the target LDAP directory server along with the proper security credentials (username and password). These will all be used to establish a connection to that target directory service.
env.put(Context.PROVIDER_URL,"ldap://ldap.wiz.com:389/ou=adminobjects,o=amq,dc=example,dc=com"); env.put(Context.SECURITY_PRINCIPAL, "uid=admin,ou=system");
env.put(Context.SECURITY_CREDENTIALS, "secret");
Notice how the PROVIDER_URL property must contain the distinguished name (DN) that pertains to the root of the directory information tree (DIT) that is used for storing the ActiveMQ administered objects. Now that your environment properties have all been properly set, your code can create an instance of the Context as this code snippet illustrates.
Context ctx = new InitialContext(env);
Remember that the object doing the actual Context implementation is LdapCtx.
Method 2 - The jndi.properties File
Another method for acquiring an instance of the Context is to use the jndi.properties file. With this approach:
1. You specify the service provider and its environment properties through the jndi.properties file.
2. The configuration burden is shifted from the developer to whoever launches the application.
3.Modifications to the configuration will not require corresponding modifications to the application’s source code.
Here is an example jndi.properties file.
#
# This file must be placed in the JMS client’s CLASSPATH
#
# The 'java.naming.factory.initial' property tells the JVM what JNDI context
# factory (or local JNDI provider) it should use for the application. In this
# case, we're telling it to use the AmqInitialContextFactory object
# as the context factory.
java.naming.factory.initial = com.sun.jndi.ldap.LdapCtxFactory java.naming.provider.url=ldap://192.168.1.148:10389/ou=adminobjects,o=amq,dc=example,dc=com java.naming.security.credentials=secret
java.naming.security.principal=uid=admin,ou=system
The JMS client will then create the Context with one simple statement as this snippet illustrates.
Context ctx = new InitialContext();
Unlike the previous method, this method does not have to specify an environment Hashtable, because the default property values are automatically picked up from the jndi.properties file.
NOTE: The jndi.properties file must be located in the JMS client’s class path.
More information on the jndi.properties file can be found at this URL. http://java.sun.com/products/jndi/tutorial/beyond/env/source.html
Method 3 - System Properties
You can also use ‘system properties’ as yet a third method; for example.
$ java -Djava.naming.factory.initial=\ com.sun.jndi.ldap.LdapCtxFactory -Djava.naming.provider.url=\ ldap:// 192.168.1.148:10389/ou=adminobjects,o=ActiveMQ2,dc=example,dc=com\ -Djava.naming.security.credentials=secret \ -Djava.naming.security.principal=uid=admin,ou=system \ YourJMSApplication
As when using the jndi.properties file, the JMS client would then create the Context with one simple statement as this snippet illustrates.
Context ctx = new InitialContext();
JNDI Operations
Now that your JMS client has acquired a Context, it can perform JNDI operations (lookup, bind, rebind, unbind, etc.) against the corresponding LDAP DS. Your JMS client doesn’t have to concern itself with transforming the ActiveMQ administered objects to and from Reference objects. Recall that the Reference object is one of only a handful of object types that can be stored in the DS. The following code snippets, which assume you’re using the jndi.properties or system properties methods, illustrate how relatively simple it is to perform some of the JNDI operations
/** Bind an ActiveMQConnectionFactory object to the DS. **/
import javax.naming.InitialContext;
import javax.naming.Context;
import org.apache.activemq.ActiveMQConnectionFactory;
public class JndiBind {
public static void main(String[] args) throws Exception {
new JndiBind().init();
}
public void init() throws Exception {
try {
Context ctx = new InitialContext();
// Create an ActiveMQ connection factory, give it some
// URL and save it in the directory.
ActiveMQConnectionFactory factory1 = new ActiveMQConnectionFactory();
factory1.setBrokerURL("tcp://localhost:61683");
ctx.bind("cn=factory3", factory1);
}
catch(Exception e){
e.printStackTrace();
}
}
}
Lookup an ActiveMQConnectionFactory object from the DS. Note how in this example we’re casting the ActiveMQConnectionFactory that is returned from the lookup to a JMS ConnectionFactory. This helps isolate the code from the JMS provider.
import javax.naming.InitialContext;
import javax.naming.Context;
import javax.jms.ConnectionFactory;
public class JndiLookup {
public static void main(String[] args) throws Exception {
new JndiLookup().init();
}
public void init() throws Exception {
try {
Context ctx = new InitialContext();
ConnectionFactory factory2 = (ConnectionFactory)ctx.lookup("cn=factory2");
}
catch(Exception e){
e.printStackTrace();
}
}
}
Subscribe to:
Comments (Atom)
