The Hermes Messaging Model
In the core of HermesJMS is a helper library for JMS that uses the configuration XML to create and manage JMS connections, sessions, producers and consumers. It basically does all the boring JMS work and hides it all behind a simple facade - the Hermes interface
. The GUI is then built using this framework and each Hermes bean is represented by the session nodes in the browser tree.
Each Hermes bean has a thread local JMS session. The connection can either be shared across all threads or you can have one connection per thread. The default connection policy is a shared conection for all threads using that bean instance however not al JMS providers support multiple sessions per connection - ORACLE for example.
Each time a Hermes bean is used the connection and session are opened appropriately. After a user action is performed the Hermes bean should have its close method called however it can be used again as its resources will be reacquired as needed.
The model does not claim to be a generic JMS messaging model but rather one that has evolved with HermesJMS and suits the interactive style of operations found in a GUI. In particular using a thread local works well as an action always occurs on a single thread.
Accessing a Hermes Bean
From Java this is done via a custom JNDI provider. The provider is configured with the location of your hermes-config.xml file. Each session configured in the browser tree can now be located:
Properties props = new Properties() ;
props.put(Context.INITIAL_CONTEXT_FACTORY, HermesInitialContextFactory.class.getName()) ;
props.put(Context.PROVIDER_URL, "hermes.xml") ;
props.put("hermes.loader", JAXBHermesLoader.class.getName()) ;
Context ctx = new InitialContext(props) ;
Hermes hermes = (Hermes) ctx.lookup("EMS") ;
For code running in the UI the currently loaded configuration XML has its context hanging off the HermesBrowser top level singleton frame. As the context changes due to configuration changes made in the UI, it is best you lookup the Hermes bean as needed and not cache it. Here is a python example:
ctx = HermesBrowser.getBrowser().getContext()
hermes = ctx.lookup("EMS")
Accessing Queues and Topics
Any statically configured (ie. in the browser tree) topics, queues and durable subscriptions are available from the getDestinations method that returns an iterator of DestinationConfig
objects.
If the configuration does not use JNDI (i.e. the connection factory class is instantiated from directly) then calls to createQueue and createTopic delegate to calls of the same name on the JMS session. If JNDI is used however then the parameters to the create calls are used as lookups in the JNDI context to locate bound destinations. This may sound unusual but it lets the UI code be decoupled from how connection factoris, queues and topics are located.
The Hermes Way
If you are always using JNDI then a more straightforward approach is to lookup destinations in JNDI directly. You can get the context that the connection factory the Hermes you are using was found via:
hermes = browser.getContext().lookup("JBM")
ctx = hermes.createContext()
queue = ctx.lookup("queue/A")
ctx.close()
The configured contexts, i.e. those in the browser tree, are available via the browser toplevel frame:
ctx = browser.createContext("JBM")
queue = ctx.lookup("queue/A")
ctx.close()
The JMS Way
There is nothing to stop you ignoring the whole Hermes framework and revert to traditional JMS:
ctx = browser.createContext("JBM")
connectionFactory = ctx.lookup("ConnectionFactory")
queue = ctx.lookup("queue/A")
connection = connectionFactory.createConnection()
session = connection.createSession(true, Session.TRANSACTED)
# message away...
connection.close()
ctx.close()
Transaction Control
The session inside the Hermes bean is always transacted. A typical action should look like:
ctx = HermesBrowser.getBrowser().getContext()
hermes = ctx.lookup("EMS")
# do some work
hermes.commit() # or rollback
hermes.close()
If you do not intend to use the Hermes bean again anytime soon then it must be closed to release the JMS resources. The next time it is used the connection and session will be opened for you as needed.