JMS rules
Overview
Table B.4. JMS rules
JMS_001: Do Not Use A Vendor Specific Class
If you want your code to be vendor independent, you should not use vendor specific classes. You should only use classes from the javax.jms package.
WRONG
QueueConnectionFactory queueConnectionFactory = new progress.message.jclient.QueueConnectionFactory();
JMS_002: Do Not Hard Code An Initial Context Factory
Don't hard code the initial context factory class name when connecting to the server. It is better to store the initial context factory class name in an external configuration file that is read when the connection must be created..
WRONG
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY,
"weblogic.jndi.WLInitialContextFactory");
InitialContext ctx = new InitialContext(env);
JMS_003: Do Not Hard Code A Provider URL
Don't hard code the provider URL when connecting to the server. It is better store the provider URL in an external configuration file that is read when the connection must be created.
WRONG
Hashtable env = new Hashtable();
env.put(Context.PROVIDER_URL, "t3:);
InitialContext ctx = new InitialContext(env);
JMS_004: Do Not Hard Code A Connection Factory Name For JNDI Lookup
Don't hard code the connection factory name for a JNDI lookup. It is better to store the connection factory name in an external configuration file that is read when the JNDI lookup must take place.
WRONG
InitialContext ctx = new InitialContext(env);
QueueConnectionFactory qconFactory = (QueueConnectionFactory) ctx.lookup("jms/FooQueueConnectionFactory");
JMS_005: Do Not Hard Code A Destination Name For JNDI Lookup
Don't hard code the destination name for a JNDI lookup. It is better to store the destination name in an external configuration file that is read when the JNDI lookup must take place.
WRONG
InitialContext ctx = new InitialContext(env);
Queue queue = (Queue) ctx.lookup("jms/FooQueue");
JMS_006: Use JNDI Lookups To Get A Connection Factory Or Destination
Never instantiate connection factories or destinations yourself. This would be an automatic violation of rule
WRONG
QueueConnectionFactory queueConnectionFactory = new progress.message.jclient.QueueConnectionFactory();
JMS_007: Close A Resource When It's No Longer Needed
All JMS resources (Connection, Session, Producer, Consumer) must be closed when they are no longer used.
Always close you resources in a finally clause of a try block. See rule
WRONG
private void doWrongClose(QueueConnectionFactory qconFactory, InitialContext ctx) throws JMSException, NamingException {
QueueConnection qcon = null;
QueueSession qsession = null;
QueueSender qsender = null;
qcon = qconFactory.createQueueConnection();
Queue queue = (Queue) ctx.lookup("jms/FooQueue");
qsession = qcon.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
qsender = qsession.createSender(queue);
}
RIGHT
private void doRightClose(QueueConnectionFactory qconFactory, InitialContext ctx) throws JMSException, NamingException {
QueueConnection qcon = null;
QueueSession qsession = null;
QueueSender qsender = null;
try {
qcon = qconFactory.createQueueConnection();
Queue queue = (Queue) ctx.lookup("jms/FooQueue");
qsession = qcon.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
qsender = qsession.createSender(queue);
} finally {
if (qsender != null) {
qsender.close();
}
if (qsession != null) {
qsession.close();
}
if (qcon != null) {
qcon.close();
}
}
}
JMS_008: Always Close Resources In The Correct Order
The JMS resources must be closed in the correct order:
- Producer or Consumer
- Session
- Connection
See rule [JAC_O68: 3. 4. Java Coding Conventions Rules#JAC_068
JMS_009: Do Not Produce A Message In A Transaction And Rely On It To Be Consumed Before The End Of The Transaction
Sending messages in a transaction is possible. It is important to realize that these messages will not be seen by consumers until the transaction is committed. This means that it is impossible to process replies on the sent messages within the original transaction.
JMS_010: Do Not Rely On JMS To Deliver Message In The Same Order As They Were Sent
When using different JMS sessions for producing and consuming messages, JMS doesn???t guarantee that messages are delivered to the consumer in the same order as they were produced.
If an application wants to consume messages in the same order as they were produced, a sequence number could be attached to each message. Instead of putting them on a JMS destination, they could be stored in a database table. The consumer could then read the messages from the table and sort them by the sequence number, in order to process them in the initial order.
JMS_011: Start A Producer Connection After Start A Consumer
If you start a connection before starting the consumer, then the messages have to wait in the JMS server. This is an unnecessary overhead, so first start consumers and then start the producer connection.
JMS_012: Use A separate Transactional Session For transactional Messages And A Non-transactional Session For Non-transactional Messages
If you want to send 100 messages, and only 10 of them in a transaction, it is better to use a transactional session to send the transactional messages and a non-transactional session to send the non-transactional messages.
JMS_013: Set An Optimal Message Time To Live
Choose an optimal value for the time to live property of a message, to avoid unnecessary memory overhead. By default a message never expires.
JMS_014: Choose A Correct Message Type
The message size depends on the type of message you choose which in turn has an impact on the performance.
JMS_015: Do Not Receive Messages Asynchronously In A Web Component, A Session Bean Or An Entity Bean
Web, session or entity components should only consume messages synchronously using the MessageConsumer???s receive methods, because they are driven by synchronous request-reply protocols, not asynchronous messages.
JMS_016: Do Not Use JMS Sessions In A Multi-threaded Context
JMS sessions were designed for single-threaded use. This is also true for all object created by the session, like producers and consumers.
If a client desires to have one thread producing messages while another thread asynchronously consumes messages at the same time, the client should use a separate session for its producing thread.
It is also forbidden to attempt to combine both synchronous and asynchronous message receiving in the same session. Either the session is dedicated to the thread of control used for delivery to message listeners or it is dedicated to a thread of control initiated by client code.
It is allowed however, to combine producing and consuming messages in the same thread.