Establishing a JMS connection

In order to send and receive any messages in JMS, an application requires a handle to a JMS provider.

Connecting to a JMS provider

A JMS client connects to a JMS provider through administrative objects. These administrative objects can be injected into the application if the developer uses annotations or they can be retrieved by navigating to the Java Native Directory Interface in a Java EE application server or by directly looking up the name and programming in the JMS API.

Inside a Java EE application server, the connection details of the administrative objects are established through external configuration. The JMS specification does not explicitly define how the administration objects are set up. Java EE application servers allow applications to set up administrative objects through XML files. Most products, including GlassFish, have a separate web-based administration console where operations can set up connection factories and connection pools.. In the Java EE specification, this is the role of the Deployer and Administrator (see Online Chapter, Moving Java EE.next to the Cloud).

JMS defines two administrative objects: javax.jms.ConnectionFactory and javax.jms.Destination.

Connection factories

The connection factory is the provider object that creates a connection to the JMS provider and a destination address in order to send a message. The interface responsible for supplying connections is called javax.jms.ConnectionFactory. The connection factory is rather similar to javax.sql.DataSource in the JDBC specification. DataSource provides a database connection to a relational database. ConnectionFactory provides a connection to the messaging system conduit.

Here is the interface definition:

package javax.jms;
public interface ConnectionFactory {
    Connection createConnection()
    throws JMSException;

    Connection createConnection(
        String userName, String password) 
    throws JMSException;

    /* Since JMS 2.0 */
    JMSContext createContext();

    JMSContext createContext(
        String userName, String password);    

    JMSContext createContext(
        String userName, String password, int sessionMode);    

    JMSContext createContext(int sessionMode);      
}

In the JMS 1.1 standard, the connection factory provides access to the javax.jms.Connection object, which is the connection that represents either a queue (P2P) or topic (pub-sub).

Since Java EE 7 and JMS 2.0, connections to the messaging systems are now preferred through the new overloaded methods on createContext(), which returns javax.jms.JMSContext. The other methods are overloaded variations of them. The createContext( method creates or retrieves a default JMS connection for the application server, which is really only useful for testing. The other take a combination of the login credentials and optionally accept a connection mode. See the later section on JMSContexts for the modes.

It is worth noting that javax.jms.Connection are now compatible with Java SE 7 try-resource syntax as they extend java.lang.AutoCloseable.

Default connection factory

JMS 2.0 defines a default connection factory for Java EE full-provide application servers which your application can use, which means all Java EE 7 applications have definite access to a JMS connection. The object is called JNDI (java:comp/jmsDefaultConnectionFactory). Your application can always assume the default connection factory is there and use it. Retrieving the default connection factory is as simple as injecting the @Inject annotation on the JMSContext object.

This is a code snippet that injects JMSConnectionFactory into a bean:

@Inject
@JMSConnectionFactory("java:comp/defaultJMSConnectionFactory")
private JMSContext context;

Message destinations

The message destination is the abstraction over the conduit that connect the Java application to the messaging system. A message destination has provider address to identify its location in the messaging system. The address allows other endpoint to send message over the channel. A JMS destination is called a queue for point-to-point communications, otherwise it is called topic for the pub-sub model.

In JMS, this representation is the marker interface javax.jms.Destination, which happens to be a super interface of javax.jms.Queue and javax.jms.Topic.

Here is a condensed definition of these interfaces:

package javax.jms;

public interface Destination { }

public interface Queue extends Destination {
    String getQueueName() throws JMSException;
    String toString();
}

public interface Topic extends Destination {
    String getTopicName() throws JMSException;
    String toString();
}

Message destinations were introduced in JMS 1.1 in order to unify the two messaging models.

JMSContext

javax.jms.JMSContext is the main interface in the simplified JMS 2.0 specification. The intention of this new interface was to merge the two different ways of configuring and administrating JMS clients in the previous specifications.

In the earlier specification, there were a lot of different objects involved in order to make a connection to the JMS provider, create a message destination, create a message, and send the message on the connection.

For new applications with JMS 2.0, a developer simply injects JMSContext into their code, especially if it runs inside a supporting Java EE 7 application server.

The Java interface JMSContext defines a number of important methods:

Method

Description

createContext( int deliveryMode ): JMSContext

Creates a new JMSContext using the same connection as this one and creates a new JMS session with the requested session mode.

In a Java EE application server environment, and where JMSContext is injected into the application class, this call is prohibited and results in IllegalStateRuntimeException.

createProducer(): JMSProducer

Creates a new JMSProducer, which can be used to configure and send messages.

getClientID()

Gets the client identifier for JMSContext connection.

setClientID()

Sets the client identifier for JMSContext connection. Calling this method is prohibited inside a Java EE or EJB application server. If the application invokes this message in such an environment, javax.jms.InvalidClientIDEXception results.

start()

Starts (or restarts) the delivery of incoming messages by the JMS connection. A call to start on a connection that has already started is ignored.

In a Java EE application server environment, and where JMSContext is injected into the application class, this call is prohibited and results in IllegalStateRuntimeException.

stop()

Temporarily stops the delivery of incoming messages by the JMS connection.

In a Java EE application server environment, and where JMSContext is injected into the application class, this call is prohibited and results in IllegalStateRuntimeException.

close()

Closes the JMSContext and the underlying producers and consumers. Temporary destinations are also deleted. This method may well block the calling application until any incomplete asynchronous send operations are completed.

createBytesMessage(): BytesMessage

Creates a BytesMessage object in order to send a message containing a stream of uninterrupted bytes.

createMapMessage(): MapMessage

Creates a MapMessage object in order to send a message containing name-value pairs.

createMessage(): Message

Creates a Message object in order to send only header information.

createObjectMessage(): ObjectMessage

Creates an ObjectMessage in order to send a serializable Java object.

createStreamMessage(): StreamMessage

Creates a StreamMesage in order to send a message defining a stream of primitive values.

createTextMessage(): TextMessage

Creates a TextMessage in order to send java.lang.String messages.

createTextMessage(String text): TextMessage

Creates a TextMessage in order to send java.lang.String messages.

getTransacted(): boolean

Gets the Boolean flag if this JMSContext is transacted or not.

getSessionMode(): int

Gets the session mode constant for this JMSContext.

commit()

Commits all messages done in this transaction and releases any locks currently held.

This call is prohibited for container-managed connections. Doing so will cause IllegalStateRuntimeException to be raised.

rollback()

Rolls back any messages done in this transaction and releases any locks currently held by this JMSContext.

This call is prohibited for container-managed connections. Doing so will cause IllegalStateRuntimeException to be raised.

recover()

Stops message delivery in JMSContext session and restarts message delivery with the oldest unacknowledged message. The delivery will then continue in serial order.

This call is prohibited for container-managed connections. Doing so will cause IllegalStateRuntimeException to be raised.

createConsumer( Destination destination ): JMSConsumer

Creates a JMSConsumer for the specified destination using the supplied message selector.

createDurableConsumer( Topic topic, String topicName ): JMSConsumer

Creates an unshared durable subscription on the specified topic and creates a consumer in that durable subscription.

createSharedDurableConsumer( Topic topic, String topicName ): JMSConsumer

Creates a shared durable subscription on the specified topic and creates a consumer in that durable subscription.

createSharedDurableConsumer( Topic topic, String topicName ): JMSConsumer

Creates a shared non-durable subscription on the specified topic and creates a consumer in that non-durable subscription.

createBrowser(Queue queueName): QueueBrowser

Creates a QueueBrowser object in order to peek at the messages on the specified queue.

createTemporaryQueue(): QueueBrowser

Creates a TemporaryQueue object that will only live for the lifetime of the JMSContext.

createTemporaryTopic(): TemporaryTopic

Creates a TemporaryTopic object that will only live for the lifetime of the JMSContext.

unsubscribe(String topicName)

Unsubscribes a durable subscription that has been created by a client.

acknowledge()

Acknowledges all messages consumed by JMSContext session.

The JMSContext interface also declares static constants, which are useful for controlling message acknowledgement behavior in the downstream system. These are called delivery modes:

Constant Name

Description

AUTO_ACKNOWLEDGE

Specifies the session and automatically acknowledges a client's receipt of a message either when the session has returned from an invocation of a call or when the message listener has been invoked and the handler successfully returns.

An alias of the Session.AUTO_KNOWLEDGE.

CLIENT_ACKNOWLEDGE

Specifies session that the client controls when messages have been acknowledged. This session mode is designed for a message listener that reads lots of messages in a batch mode (unacknowledged) and then later returns the acknowledgement for each processed message.

An alias of Session.CLIENT_KNOWLEDGE.

DUPS_OK_ACKNOWLEDGE

Specifies the session to lazily acknowledge the delivery of messages, which might result in the delivery of duplicate message, especially if the JMS provider fails (crashes or is forcefully shutdown). The consumer must be aware of the possibility of incoming duplicate messages. This mode affords lower overheads by minimizing the requirement for eager automatic acknowledgements.

An alias of Session.DUP_OKS_ACKNOWLEDGE.

SESSION_TRANSACTED

Specifies the session to deliver and consume messages in a local transaction, which will subsequently either be committed or rolled back by the message listener explicitly.

An alias of Session.SESSION_TRANSACTED.

The JMSContext is a very useful instance in a server-side application because it allows the developer to rely on annotations. The best way to get a JMSContext is to inject it into the application logic. Inside a Java EE environment, there are restrictions on calling certain methods that would interfere with the application server that can cause undefined behavior. An exception is thrown if you attempt to call commit(), rollback(), or recover() on a message destination. If these calls were allowed, then they could be detrimental to the operation of the Java EE server, because suddenly the application could take ownership over internal managed resources when it is not supposed to.

On the client side, the developer must create or retrieve a JMSContext manually. Java EE 7 does not define standalone behavior. Perhaps this is a weakness of the current JMS 2.0 specification. It should be possible to inject a JMSContext in a Java SE application by using a standalone CDI container such as JBoss Weld.

Tip

JMSContext in a Java EE server

JMSContext behaves differently inside an application running on a Java EE server in comparison to a Java SE environment. Inside a Java EE application server or EJB server, the JMSContext can be injected into the application. For an application running under the web profile server with a JMS provider extension, the JMSContext can also be injected into the application. The benefit of having only one object is obviously beneficial to dependency injection. The application server takes care of creating, opening or closing the context.

Retrieving a JMSContext

There are two ways to retrieve a JMSContext:

  • A developer can create a JMSContext from ConnectionFactory by simply calling the createContext() method. This allows a Java SE application to only have one object to get a JMS connection. Once the application is finished with the context, simply call close().
  • The second way requires a Java EE application server or container, and the developer uses the CDI annotation @javax.annotation.Inject to inject the JMSContext into the class.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.188.152.136