| Dynamic-JMS Overview |
|
|
|
Dynamic-JMS is the first project that makes JMS applications dynamic in the OSGi environment. In plain Java Applications, updating JMS components and configurations requires restarting the application. Using Dynamic-JMS, you can update connection settings, upgrade broker clients, or simply switch brokers at runtime without having to restart the application. Dynamic-JMS is robust and was tested against different runtime update scenarios both synchronous and synchronous. Why use JMS dynamically?Using JMS dynamically in the OSGi environment will allow you to:
The problem of using JMS dynamically?JMS Components (like Connections, Message Producers, Message Consumers, etc.) are not dynamic in nature, as such, they don't support updates at runtime. How Dynamic-JMS helps?Making JMS components dynamic transparently to the application, while still ensuring that JMS components continue their activities normally after updates is a difficult task. Dynamic-JMS comes into help by handling this task, and makes it simple for developer to dynamize JMS components of their OSGi-based applications using standard OSGi facilities like OSGi services and bundle updates. How Dynamic-JMS works?The main component of Dynamic-JMS is the Dynamic JMS Connection Factory. This factory accepts a JMS Connection Factory as a parameter, and when you want to update the connection factory of your application, you invoke the update method of the dynamic connection factory passing it the new connection factory with updated settings, the new connection factory can be a connection factory with a different connection connection string, a factory created by a newer version of the messaging broker client library, or a connection factory of a completely different messaging broker. Actually, Dynamic-JMS handles the interaction with the dynamic connection factory for you. All you need to do to use Dynamic-JMS is registering your connection factory as an OSGi service. You will give your factory a name through service properties. Dynamic-JMS in return will register a dynamic connection factory as an OSGi service with same name but with a very high rank, so your application will use the dynamic connection factory instead. Once you want to update the connection factory, you will register the new connection factory as an OSGi service that has the same name but with a higher rank. Dynamic-JMS will locate your factory and pass it to the dynamic factory in order to be used instead of the old one. If you deregister the new factory, the dynamic factory will get back to using the old connection factory. Example ApplicationThe Example Application consists of four application bundles:
Message Consumer Bundle uses the Dynamic Connection Factory created by Dynamic-JMS which encapsulates the connection factories created by the two connection bundles. The Consumer Bundle creates a message consumer which receives messages from ActiveMQ isntance 2 since the connection factory that uses it has the highest rank. If ActiveMQ Connection 2 Bundle is uninstalled, then the message consumer will be listening to messages from ActiveMQ Connection 1 instance since it's the only connection factory which is left. Example Application + Source Code: dynamic-jms-example.zipBelow is the code that registers the first Connection Factor that points to the first ActiveMQ instance. We will not present the code for the second connection factory since it's quite the same.
void registerConnectionFactory(BundleContext bundleContext) {
ConnectionFactory connectionFactory =
new ActiveMQConnectionFactory("tcp://localhost:12341");
bundleContext.registerService(ConnectionFactory.class.getName(),
connectionFactory, getConnectionFactoryServiceProperties());
}
protected Dictionary getConnectionFactoryServiceProperties() {
Dictionary result = new Hashtable();
result.put(Constants.SERVICE_RANKING, 1);
result.put(CONNECTION_FACTORY_NAME, "exampleConnection");
result.put(CONNECTION_FACTORY_ID, "exampleConnection.activeMq1");
return result;
}
public static final String CONNECTION_FACTORY_NAME =
"org.dynamicjava.osgi.dynamic_jms:connectionFactoryName";
public static final String CONNECTION_FACTORY_ID =
"org.dynamicjava.osgi.dynamic_jms:connectionFactoryId";
After we register the Connection Factory, Dynamic-JMS will find it and create a Dynamic Connection Factory that encapsulates it and provides the dynamic connection factory as an OSGi service. Below is the code that consumes the dynamic connection factory from the consumer bundle.
protected ConnectionFactory retrieveDynamicConnectionFactory(
BundleContext bundleContext) throws InvalidSyntaxException {
ServiceReference[] serviceRefs = bundleContext.getServiceReferences(
ConnectionFactory.class.getName(),
String.format("(&(%s=%s)(%s=%s))",
CONNECTION_FACTORY_NAME, "exampleConnection",
IS_DYNAMIC_FACTORY, "true"));
return (ConnectionFactory)bundleContext.getService(serviceRefs[0]);
}
public static final String CONNECTION_FACTORY_NAME =
"org.dynamicjava.osgi.dynamic_jms:connectionFactoryName";
public static final String CONNECTION_FACTORY_ID =
"org.dynamicjava.osgi.dynamic_jms:connectionFactoryId";
public static final String IS_DYNAMIC_FACTORY =
"org.dynamicjava.osgi.dynamic_jms:isDynamicFactory";
The rest of the code is a typical JMS code, though components work dynamically. From the code snippets you can see that the only thing that differed is the way we consume the connection factory, instead of consuming it directly, we consume a dynamic connection factory, that encapsulates our connection factory, as an OSGi service. |