The Spring Framework

org.springframework.jms.listener
Class AbstractMessageListenerContainer

java.lang.Object
  extended by org.springframework.jms.support.JmsAccessor
      extended by org.springframework.jms.support.destination.JmsDestinationAccessor
          extended by org.springframework.jms.listener.AbstractMessageListenerContainer
All Implemented Interfaces:
DisposableBean, InitializingBean, Lifecycle
Direct Known Subclasses:
DefaultMessageListenerContainer, ServerSessionMessageListenerContainer, SimpleMessageListenerContainer

public abstract class AbstractMessageListenerContainer
extends JmsDestinationAccessor
implements DisposableBean, Lifecycle

Abstract base class for message listener containers. Can either host a standard JMS MessageListener or a Spring-specific SessionAwareMessageListener.

Usually holds a single JMS Connection that all listeners are supposed to be registered on, which is the standard JMS way of managing listeners. Can alternatively also be used with a fresh Connection per listener, for J2EE-style XA-aware JMS messaging. The actual registration process is up to concrete subclasses.

NOTE: The default behavior of this message listener container is to never propagate an exception thrown by a message listener up to the JMS provider. Instead, it will log any such exception at the error level. This means that from the perspective of the attendant JMS provider no such listener will ever fail.

The listener container offers the following message acknowledgment options:

The exact behavior might vary according to the concrete listener container and JMS provider used.

Note that there is a corner case when using "sessionTransacted", where the listener might have returned successfully but the server died before acknowledging the message. As a consequence, a message might get redelivered even after successful processing - potentially leading to duplicate processing of the message. This violates "exactly-once" semantics, at least potentially.

There are two solutions to the duplicate processing problem:

Note that XA transaction coordination adds significant runtime overhead, so it might be feasible to avoid it unless absolutely necessary.

Recommendations:

Since:
2.0
Author:
Juergen Hoeller
See Also:
setMessageListener(java.lang.Object), MessageListener, SessionAwareMessageListener, handleListenerException(java.lang.Throwable), DefaultMessageListenerContainer, SimpleMessageListenerContainer, ServerSessionMessageListenerContainer

Nested Class Summary
protected static class AbstractMessageListenerContainer.SharedConnectionNotInitializedException
          Exception that indicates that the initial setup of this listener container's shared JMS Connection failed.
 
Field Summary
 
Fields inherited from class org.springframework.jms.support.JmsAccessor
logger
 
Constructor Summary
AbstractMessageListenerContainer()
           
 
Method Summary
 void afterPropertiesSet()
          Validate configuration and call initialize().
protected  void checkMessageListener(Object messageListener)
          Check the given message listener, throwing an exception if it does not correspond to a supported listener type.
protected  void commitIfNecessary(Session session, Message message)
          Perform a commit or message acknowledgement, as appropriate.
protected  Connection createConnection()
          Create a JMS Connection via this template's ConnectionFactory.
protected  Session createSession(Connection con)
          Create a JMS Session for the given Connection.
 void destroy()
          Calls shutdown when the BeanFactory destroys the message listener container instance.
protected abstract  void destroyListener()
          Destroy the registered listener.
protected  void doExecuteListener(Session session, Message message)
          Execute the specified listener, committing or rolling back the transaction afterwards (if necessary).
protected  void doInvokeListener(MessageListener listener, Message message)
          Invoke the specified listener as standard JMS MessageListener.
protected  void doInvokeListener(SessionAwareMessageListener listener, Session session, Message message)
          Invoke the specified listener as Spring SessionAwareMessageListener, exposing a new JMS Session (potentially with its own transaction) to the listener if demanded.
protected  void doRescheduleTask(Object task)
          Reschedule the given task object immediately.
protected  void doStart()
          Start the shared Connection, if any, and notify all listener tasks.
protected  void doStop()
          Notify all listener tasks and stop the shared Connection, if any.
protected  void establishSharedConnection()
          Establish a shared Connection for this message listener container.
protected  void executeListener(Session session, Message message)
          Execute the specified listener, committing or rolling back the transaction afterwards (if necessary).
protected  String getClientId()
          Return the JMS client ID for the shared Connection created and used by this messager listener container, if any.
protected  Destination getDestination()
          Return the destination to receive messages from.
protected  String getDestinationName()
          Return the name of the destination to receive messages from.
protected  String getDurableSubscriptionName()
          Return the name of a durable subscription to create, if any.
protected  ExceptionListener getExceptionListener()
          Return the JMS ExceptionListener to notify in case of a JMSException thrown by the registered message listener or the invocation infrastructure, if any.
protected  Object getMessageListener()
          Return the message listener object to register.
protected  String getMessageSelector()
          Return the JMS message selector expression (or null if none).
protected  Connection getSharedConnection()
          Return the shared JMS Connection maintained by this message listener container.
protected  void handleListenerException(Throwable ex)
          Handle the given exception that arose during listener execution.
 void initialize()
          Initialize this message listener container.
protected  void invokeExceptionListener(JMSException ex)
          Invoke the registered JMS ExceptionListener, if any.
protected  void invokeListener(Session session, Message message)
          Invoke the specified listener: either as standard JMS MessageListener or (preferably) as Spring SessionAwareMessageListener.
 boolean isActive()
          Return whether this listener container is currently active, that is, whether it has been set up but not shut down yet.
protected  boolean isClientAcknowledge(Session session)
          Return whether the Session is in client acknowledge mode.
protected  boolean isExposeListenerSession()
          Return whether to expose the listener JMS Session to a registered SessionAwareMessageListener.
 boolean isRunning()
          Return whether this listener container is currently running, that is, whether it has been started and not stopped yet.
protected  boolean isSubscriptionDurable()
          Return whether to make the subscription durable.
protected  void prepareSharedConnection(Connection connection)
          Prepare the given Connection, which is about to be registered as shared Connection for this message listener container.
protected  void refreshSharedConnection()
          Refresh the shared Connection that this listener container holds.
protected abstract  void registerListener()
          Register the specified listener on the underlying JMS Connection.
protected  boolean rescheduleTaskIfNecessary(Object task)
          Take the given task object and reschedule it, either immediately if this listener container is currently running, or later once this listener container has been restarted.
protected  void rollbackOnExceptionIfNecessary(Session session, Throwable ex)
          Perform a rollback, handling rollback exceptions properly.
 void setAutoStartup(boolean autoStartup)
          Set whether to automatically start the listener after initialization.
 void setClientId(String clientId)
          Specify a JMS client id for a shared Connection created and used by this messager listener container.
 void setDestination(Destination destination)
          Set the destination to receive messages from.
 void setDestinationName(String destinationName)
          Set the name of the destination to receive messages from.
 void setDurableSubscriptionName(String durableSubscriptionName)
          Set the name of a durable subscription to create.
 void setExceptionListener(ExceptionListener exceptionListener)
          Set the JMS ExceptionListener to notify in case of a JMSException thrown by the registered message listener or the invocation infrastructure.
 void setExposeListenerSession(boolean exposeListenerSession)
          Set whether to expose the listener JMS Session to a registered SessionAwareMessageListener.
 void setMessageListener(Object messageListener)
          Set the message listener implementation to register.
 void setMessageSelector(String messageSelector)
          Set the JMS message selector expression (or null if none).
 void setSubscriptionDurable(boolean subscriptionDurable)
          Set whether to make the subscription durable.
protected abstract  boolean sharedConnectionEnabled()
          Return whether a shared JMS Connection should be maintained by this listener container base class.
 void shutdown()
          Shut down the registered listeners and close this listener container.
 void start()
          Start this listener container.
protected  void startSharedConnection()
          Start the shared Connection.
 void stop()
          Stop this listener container.
protected  void stopSharedConnection()
          Stop the shared Connection.
protected  void waitWhileNotRunning()
          Wait while this listener container is not running.
 
Methods inherited from class org.springframework.jms.support.destination.JmsDestinationAccessor
getDestinationResolver, isPubSubDomain, resolveDestinationName, setDestinationResolver, setPubSubDomain
 
Methods inherited from class org.springframework.jms.support.JmsAccessor
convertJmsAccessException, getConnectionFactory, getSessionAcknowledgeMode, isSessionTransacted, setConnectionFactory, setSessionAcknowledgeMode, setSessionAcknowledgeModeName, setSessionTransacted
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Constructor Detail

AbstractMessageListenerContainer

public AbstractMessageListenerContainer()
Method Detail

setClientId

public void setClientId(String clientId)
Specify a JMS client id for a shared Connection created and used by this messager listener container.

Note that client ids need to be unique among all active Connections of the underlying JMS provider. Furthermore, a client id can only be assigned if the original ConnectionFactory hasn't already assigned one.

See Also:
Connection.setClientID(java.lang.String), JmsAccessor.setConnectionFactory(javax.jms.ConnectionFactory)

getClientId

protected String getClientId()
Return the JMS client ID for the shared Connection created and used by this messager listener container, if any.


setDestination

public void setDestination(Destination destination)
Set the destination to receive messages from.

Alternatively, specify a "destinationName", to be dynamically resolved via the DestinationResolver.

See Also:
setDestinationName(String)

getDestination

protected Destination getDestination()
Return the destination to receive messages from.

Returns:
the destination to receive messages from (will be null if the configured destination is not an actual Destination type; c.f. when the destination is a String)

setDestinationName

public void setDestinationName(String destinationName)
Set the name of the destination to receive messages from.

The specified name will be dynamically resolved via the configured destination resolver.

Alternatively, specify a JMS Destination object as "destination".

Parameters:
destinationName - the desired destination (can be null)
See Also:
setDestination(javax.jms.Destination)

getDestinationName

protected String getDestinationName()
Return the name of the destination to receive messages from.

Returns:
the name of the destination to receive messages from (will be null if the configured destination is not a String type; c.f. when it is an actual Destination)

setMessageSelector

public void setMessageSelector(String messageSelector)
Set the JMS message selector expression (or null if none). Default is none.

See the JMS specification for a detailed definition of selector expressions.


getMessageSelector

protected String getMessageSelector()
Return the JMS message selector expression (or null if none).


setMessageListener

public void setMessageListener(Object messageListener)
Set the message listener implementation to register. This can be either a standard JMS MessageListener object or a Spring SessionAwareMessageListener object.

Throws:
IllegalArgumentException - if the supplied listener is not a MessageListener or a SessionAwareMessageListener
See Also:
MessageListener, SessionAwareMessageListener

checkMessageListener

protected void checkMessageListener(Object messageListener)
Check the given message listener, throwing an exception if it does not correspond to a supported listener type.

By default, only a standard JMS MessageListener object or a Spring SessionAwareMessageListener object will be accepted.

Parameters:
messageListener - the message listener object to check
Throws:
IllegalArgumentException - if the supplied listener is not a MessageListener or a SessionAwareMessageListener
See Also:
MessageListener, SessionAwareMessageListener

getMessageListener

protected Object getMessageListener()
Return the message listener object to register.


setSubscriptionDurable

public void setSubscriptionDurable(boolean subscriptionDurable)
Set whether to make the subscription durable. The durable subscription name to be used can be specified through the "durableSubscriptionName" property.

Default is "false". Set this to "true" to register a durable subscription, typically in combination with a "durableSubscriptionName" value (unless your message listener class name is good enough as subscription name).

Only makes sense when listening to a topic (pub-sub domain).

See Also:
setDurableSubscriptionName(java.lang.String)

isSubscriptionDurable

protected boolean isSubscriptionDurable()
Return whether to make the subscription durable.


setDurableSubscriptionName

public void setDurableSubscriptionName(String durableSubscriptionName)
Set the name of a durable subscription to create. To be applied in case of a topic (pub-sub domain) with subscription durability activated.

The durable subscription name needs to be unique within this client's JMS client id. Default is the class name of the specified message listener.

Note: Only 1 concurrent consumer (which is the default of this message listener container) is allowed for each durable subscription.

See Also:
setSubscriptionDurable(boolean), setClientId(java.lang.String), setMessageListener(java.lang.Object)

getDurableSubscriptionName

protected String getDurableSubscriptionName()
Return the name of a durable subscription to create, if any.


setExceptionListener

public void setExceptionListener(ExceptionListener exceptionListener)
Set the JMS ExceptionListener to notify in case of a JMSException thrown by the registered message listener or the invocation infrastructure.


getExceptionListener

protected ExceptionListener getExceptionListener()
Return the JMS ExceptionListener to notify in case of a JMSException thrown by the registered message listener or the invocation infrastructure, if any.


setExposeListenerSession

public void setExposeListenerSession(boolean exposeListenerSession)
Set whether to expose the listener JMS Session to a registered SessionAwareMessageListener. Default is "true", reusing the listener's Session.

Turn this off to expose a fresh JMS Session fetched from the same underlying JMS Connection instead, which might be necessary on some JMS providers.

See Also:
SessionAwareMessageListener

isExposeListenerSession

protected boolean isExposeListenerSession()
Return whether to expose the listener JMS Session to a registered SessionAwareMessageListener.


setAutoStartup

public void setAutoStartup(boolean autoStartup)
Set whether to automatically start the listener after initialization.

Default is "true"; set this to "false" to allow for manual startup.


afterPropertiesSet

public void afterPropertiesSet()
Validate configuration and call initialize().

Specified by:
afterPropertiesSet in interface InitializingBean
Overrides:
afterPropertiesSet in class JmsAccessor
See Also:
initialize()

initialize

public void initialize()
                throws JmsException
Initialize this message listener container.

Creates a JMS Connection, registers the given listener object, and starts the Connection (if "autoStartup" hasn't been turned off).

Throws:
JmsException - if startup failed

establishSharedConnection

protected void establishSharedConnection()
                                  throws JMSException
Establish a shared Connection for this message listener container.

The default implementation delegates to refreshSharedConnection, which does one immediate attempt and throws an exception if it fails. Can be overridden to have a recovery proces in place, retrying until a Connection can be successfully established.

Throws:
JMSException - if thrown by JMS API methods
See Also:
refreshSharedConnection()

refreshSharedConnection

protected final void refreshSharedConnection()
                                      throws JMSException
Refresh the shared Connection that this listener container holds.

Called on startup and also after an infrastructure exception that occured during listener setup and/or execution.

Throws:
JMSException - if thrown by JMS API methods

prepareSharedConnection

protected void prepareSharedConnection(Connection connection)
                                throws JMSException
Prepare the given Connection, which is about to be registered as shared Connection for this message listener container.

The default implementation sets the specified client id, if any. Subclasses can override this to apply further settings.

Parameters:
connection - the Connection to prepare
Throws:
JMSException - if the preparation efforts failed
See Also:
setClientId(java.lang.String)

getSharedConnection

protected final Connection getSharedConnection()
Return the shared JMS Connection maintained by this message listener container. Available after initialization.

Throws:
IllegalStateException - if this listener container does not maintain a shared Connection, or if the Connection hasn't been initialized yet
See Also:
sharedConnectionEnabled()

destroy

public void destroy()
Calls shutdown when the BeanFactory destroys the message listener container instance.

Specified by:
destroy in interface DisposableBean
See Also:
shutdown()

shutdown

public void shutdown()
              throws JmsException
Shut down the registered listeners and close this listener container.

Throws:
JmsException - if shutdown failed
See Also:
destroyListener()

isActive

public final boolean isActive()
Return whether this listener container is currently active, that is, whether it has been set up but not shut down yet.


start

public void start()
           throws JmsException
Start this listener container.

Specified by:
start in interface Lifecycle
Throws:
JmsException - if starting failed
See Also:
doStart()

doStart

protected void doStart()
                throws JMSException
Start the shared Connection, if any, and notify all listener tasks.

Throws:
JMSException - if thrown by JMS API methods
See Also:
startSharedConnection()

startSharedConnection

protected void startSharedConnection()
                              throws JMSException
Start the shared Connection.

Throws:
JMSException - if thrown by JMS API methods
See Also:
Connection.start()

stop

public void stop()
          throws JmsException
Stop this listener container.

Specified by:
stop in interface Lifecycle
Throws:
JmsException - if stopping failed
See Also:
doStop()

doStop

protected void doStop()
               throws JMSException
Notify all listener tasks and stop the shared Connection, if any.

Throws:
JMSException - if thrown by JMS API methods
See Also:
stopSharedConnection()

stopSharedConnection

protected void stopSharedConnection()
                             throws JMSException
Stop the shared Connection.

Throws:
JMSException - if thrown by JMS API methods
See Also:
Connection.start()

isRunning

public final boolean isRunning()
Return whether this listener container is currently running, that is, whether it has been started and not stopped yet.

Specified by:
isRunning in interface Lifecycle

waitWhileNotRunning

protected final void waitWhileNotRunning()
Wait while this listener container is not running.

To be called by asynchronous tasks that want to block while the listener container is in stopped state.


rescheduleTaskIfNecessary

protected final boolean rescheduleTaskIfNecessary(Object task)
Take the given task object and reschedule it, either immediately if this listener container is currently running, or later once this listener container has been restarted.

If this listener container has already been shut down, the task will not get rescheduled at all.

Parameters:
task - the task object to reschedule
Returns:
whether the task has been rescheduled (either immediately or for a restart of this container)
See Also:
doRescheduleTask(java.lang.Object)

doRescheduleTask

protected void doRescheduleTask(Object task)
Reschedule the given task object immediately. To be implemented by subclasses if they ever call rescheduleTaskIfNecessary.

This implementation throws an UnsupportedOperationException.

Parameters:
task - the task object to reschedule
See Also:
rescheduleTaskIfNecessary(java.lang.Object)

executeListener

protected void executeListener(Session session,
                               Message message)
Execute the specified listener, committing or rolling back the transaction afterwards (if necessary).

Parameters:
session - the JMS Session to operate on
message - the received JMS Message
See Also:
invokeListener(javax.jms.Session, javax.jms.Message), commitIfNecessary(javax.jms.Session, javax.jms.Message), rollbackOnExceptionIfNecessary(javax.jms.Session, java.lang.Throwable), handleListenerException(java.lang.Throwable)

doExecuteListener

protected void doExecuteListener(Session session,
                                 Message message)
                          throws JMSException
Execute the specified listener, committing or rolling back the transaction afterwards (if necessary).

Parameters:
session - the JMS Session to operate on
message - the received JMS Message
Throws:
JMSException - if thrown by JMS API methods
See Also:
invokeListener(javax.jms.Session, javax.jms.Message), commitIfNecessary(javax.jms.Session, javax.jms.Message), rollbackOnExceptionIfNecessary(javax.jms.Session, java.lang.Throwable), JmsAccessor.convertJmsAccessException(javax.jms.JMSException)

invokeListener

protected void invokeListener(Session session,
                              Message message)
                       throws JMSException
Invoke the specified listener: either as standard JMS MessageListener or (preferably) as Spring SessionAwareMessageListener.

Parameters:
session - the JMS Session to operate on
message - the received JMS Message
Throws:
JMSException - if thrown by JMS API methods
See Also:
setMessageListener(java.lang.Object)

doInvokeListener

protected void doInvokeListener(SessionAwareMessageListener listener,
                                Session session,
                                Message message)
                         throws JMSException
Invoke the specified listener as Spring SessionAwareMessageListener, exposing a new JMS Session (potentially with its own transaction) to the listener if demanded.

Parameters:
listener - the Spring SessionAwareMessageListener to invoke
session - the JMS Session to operate on
message - the received JMS Message
Throws:
JMSException - if thrown by JMS API methods
See Also:
SessionAwareMessageListener, setExposeListenerSession(boolean)

doInvokeListener

protected void doInvokeListener(MessageListener listener,
                                Message message)
                         throws JMSException
Invoke the specified listener as standard JMS MessageListener.

Default implementation performs a plain invocation of the onMessage method.

Parameters:
listener - the JMS MessageListener to invoke
message - the received JMS Message
Throws:
JMSException - if thrown by JMS API methods
See Also:
MessageListener.onMessage(javax.jms.Message)

commitIfNecessary

protected void commitIfNecessary(Session session,
                                 Message message)
                          throws JMSException
Perform a commit or message acknowledgement, as appropriate.

Parameters:
session - the JMS Session to commit
message - the Message to acknowledge
Throws:
JMSException - in case of commit failure

rollbackOnExceptionIfNecessary

protected void rollbackOnExceptionIfNecessary(Session session,
                                              Throwable ex)
                                       throws JMSException
Perform a rollback, handling rollback exceptions properly.

Parameters:
session - the JMS Session to rollback
ex - the thrown application exception or error
Throws:
JMSException - in case of a rollback error

handleListenerException

protected void handleListenerException(Throwable ex)
Handle the given exception that arose during listener execution.

The default implementation logs the exception at error level, not propagating it to the JMS provider - assuming that all handling of acknowledgement and/or transactions is done by this listener container. This can be overridden in subclasses.

Parameters:
ex - the exception to handle

invokeExceptionListener

protected void invokeExceptionListener(JMSException ex)
Invoke the registered JMS ExceptionListener, if any.

Parameters:
ex - the exception that arose during JMS processing
See Also:
setExceptionListener(javax.jms.ExceptionListener)

sharedConnectionEnabled

protected abstract boolean sharedConnectionEnabled()
Return whether a shared JMS Connection should be maintained by this listener container base class.

See Also:
getSharedConnection()

registerListener

protected abstract void registerListener()
                                  throws JMSException
Register the specified listener on the underlying JMS Connection.

Subclasses need to implement this method for their specific listener management process.

Throws:
JMSException - if registration failed
See Also:
getMessageListener(), getSharedConnection()

destroyListener

protected abstract void destroyListener()
                                 throws JMSException
Destroy the registered listener. The JMS Connection will automatically be closed afterwards

Subclasses need to implement this method for their specific listener management process.

Throws:
JMSException - if destruction failed

createConnection

protected Connection createConnection()
                               throws JMSException
Create a JMS Connection via this template's ConnectionFactory.

This implementation uses JMS 1.1 API.

Returns:
the new JMS Connection
Throws:
JMSException - if thrown by JMS API methods

createSession

protected Session createSession(Connection con)
                         throws JMSException
Create a JMS Session for the given Connection.

This implementation uses JMS 1.1 API.

Parameters:
con - the JMS Connection to create a Session for
Returns:
the new JMS Session
Throws:
JMSException - if thrown by JMS API methods

isClientAcknowledge

protected boolean isClientAcknowledge(Session session)
                               throws JMSException
Return whether the Session is in client acknowledge mode.

This implementation uses JMS 1.1 API.

Parameters:
session - the JMS Session to check
Throws:
JMSException - if thrown by JMS API methods

The Spring Framework

Copyright © 2002-2006 The Spring Framework.