|
The Spring Framework | |||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | |||||||||
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |
java.lang.Object org.springframework.jms.support.JmsAccessor org.springframework.jms.support.destination.JmsDestinationAccessor org.springframework.jms.listener.AbstractMessageListenerContainer
public abstract class AbstractMessageListenerContainer
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:
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:
DefaultMessageListenerContainer
, through
specifying a "transactionManager" (typically a
JtaTransactionManager
, with
a corresponding XA-aware JMS ConnectionFactory
passed in as
"connectionFactory").
Recommendations:
JtaTransactionManager
as "transactionManager"
for a full XA-aware JMS provider - typically when running on a J2EE server,
but also for other environments with a JTA transaction manager present.
This will give full "exactly-once" guarantees without custom duplicate
message checks, at the price of additional runtime processing overhead.
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 |
---|
public AbstractMessageListenerContainer()
Method Detail |
---|
public void setClientId(String clientId)
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.
Connection.setClientID(java.lang.String)
,
JmsAccessor.setConnectionFactory(javax.jms.ConnectionFactory)
protected String getClientId()
public void setDestination(Destination destination)
Alternatively, specify a "destinationName", to be dynamically
resolved via the DestinationResolver
.
setDestinationName(String)
protected Destination getDestination()
null
if the configured destination is not an actual
Destination
type; c.f. when the destination is a String
)public void setDestinationName(String destinationName)
The specified name will be dynamically resolved via the configured
destination resolver
.
Alternatively, specify a JMS Destination
object as "destination".
destinationName
- the desired destination (can be null
)setDestination(javax.jms.Destination)
protected String getDestinationName()
null
if the configured destination is not a
String
type; c.f. when
it is an actual Destination
)public void setMessageSelector(String messageSelector)
null
if none).
Default is none.
See the JMS specification for a detailed definition of selector expressions.
protected String getMessageSelector()
null
if none).
public void setMessageListener(Object messageListener)
MessageListener
object
or a Spring SessionAwareMessageListener
object.
IllegalArgumentException
- if the supplied listener is not a
MessageListener
or a SessionAwareMessageListener
MessageListener
,
SessionAwareMessageListener
protected void checkMessageListener(Object messageListener)
By default, only a standard JMS MessageListener
object or a
Spring SessionAwareMessageListener
object will be accepted.
messageListener
- the message listener object to check
IllegalArgumentException
- if the supplied listener is not a
MessageListener
or a SessionAwareMessageListener
MessageListener
,
SessionAwareMessageListener
protected Object getMessageListener()
public void setSubscriptionDurable(boolean subscriptionDurable)
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).
setDurableSubscriptionName(java.lang.String)
protected boolean isSubscriptionDurable()
public void setDurableSubscriptionName(String durableSubscriptionName)
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.
setSubscriptionDurable(boolean)
,
setClientId(java.lang.String)
,
setMessageListener(java.lang.Object)
protected String getDurableSubscriptionName()
public void setExceptionListener(ExceptionListener exceptionListener)
protected ExceptionListener getExceptionListener()
public void setExposeListenerSession(boolean exposeListenerSession)
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.
SessionAwareMessageListener
protected boolean isExposeListenerSession()
Session
to a
registered SessionAwareMessageListener
.
public void setAutoStartup(boolean autoStartup)
Default is "true"; set this to "false" to allow for manual startup.
public void afterPropertiesSet()
initialize()
.
afterPropertiesSet
in interface InitializingBean
afterPropertiesSet
in class JmsAccessor
initialize()
public void initialize() throws JmsException
Creates a JMS Connection, registers the
given listener object
,
and starts the Connection
(if "autoStartup"
hasn't been turned off).
JmsException
- if startup failedprotected void establishSharedConnection() throws JMSException
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.
JMSException
- if thrown by JMS API methodsrefreshSharedConnection()
protected final void refreshSharedConnection() throws JMSException
Called on startup and also after an infrastructure exception that occured during listener setup and/or execution.
JMSException
- if thrown by JMS API methodsprotected void prepareSharedConnection(Connection connection) throws JMSException
The default implementation sets the specified client id, if any. Subclasses can override this to apply further settings.
connection
- the Connection to prepare
JMSException
- if the preparation efforts failedsetClientId(java.lang.String)
protected final Connection getSharedConnection()
IllegalStateException
- if this listener container does not maintain a
shared Connection, or if the Connection hasn't been initialized yetsharedConnectionEnabled()
public void destroy()
shutdown
when the BeanFactory destroys
the message listener container instance.
destroy
in interface DisposableBean
shutdown()
public void shutdown() throws JmsException
JmsException
- if shutdown faileddestroyListener()
public final boolean isActive()
public void start() throws JmsException
start
in interface Lifecycle
JmsException
- if starting faileddoStart()
protected void doStart() throws JMSException
JMSException
- if thrown by JMS API methodsstartSharedConnection()
protected void startSharedConnection() throws JMSException
JMSException
- if thrown by JMS API methodsConnection.start()
public void stop() throws JmsException
stop
in interface Lifecycle
JmsException
- if stopping faileddoStop()
protected void doStop() throws JMSException
JMSException
- if thrown by JMS API methodsstopSharedConnection()
protected void stopSharedConnection() throws JMSException
JMSException
- if thrown by JMS API methodsConnection.start()
public final boolean isRunning()
isRunning
in interface Lifecycle
protected final void waitWhileNotRunning()
To be called by asynchronous tasks that want to block while the listener container is in stopped state.
protected final boolean rescheduleTaskIfNecessary(Object task)
If this listener container has already been shut down, the task will not get rescheduled at all.
task
- the task object to reschedule
doRescheduleTask(java.lang.Object)
protected void doRescheduleTask(Object task)
rescheduleTaskIfNecessary
.
This implementation throws an UnsupportedOperationException.
task
- the task object to reschedulerescheduleTaskIfNecessary(java.lang.Object)
protected void executeListener(Session session, Message message)
session
- the JMS Session to operate onmessage
- the received JMS MessageinvokeListener(javax.jms.Session, javax.jms.Message)
,
commitIfNecessary(javax.jms.Session, javax.jms.Message)
,
rollbackOnExceptionIfNecessary(javax.jms.Session, java.lang.Throwable)
,
handleListenerException(java.lang.Throwable)
protected void doExecuteListener(Session session, Message message) throws JMSException
session
- the JMS Session to operate onmessage
- the received JMS Message
JMSException
- if thrown by JMS API methodsinvokeListener(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)
protected void invokeListener(Session session, Message message) throws JMSException
session
- the JMS Session to operate onmessage
- the received JMS Message
JMSException
- if thrown by JMS API methodssetMessageListener(java.lang.Object)
protected void doInvokeListener(SessionAwareMessageListener listener, Session session, Message message) throws JMSException
listener
- the Spring SessionAwareMessageListener to invokesession
- the JMS Session to operate onmessage
- the received JMS Message
JMSException
- if thrown by JMS API methodsSessionAwareMessageListener
,
setExposeListenerSession(boolean)
protected void doInvokeListener(MessageListener listener, Message message) throws JMSException
Default implementation performs a plain invocation of the
onMessage
method.
listener
- the JMS MessageListener to invokemessage
- the received JMS Message
JMSException
- if thrown by JMS API methodsMessageListener.onMessage(javax.jms.Message)
protected void commitIfNecessary(Session session, Message message) throws JMSException
session
- the JMS Session to commitmessage
- the Message to acknowledge
JMSException
- in case of commit failureprotected void rollbackOnExceptionIfNecessary(Session session, Throwable ex) throws JMSException
session
- the JMS Session to rollbackex
- the thrown application exception or error
JMSException
- in case of a rollback errorprotected void handleListenerException(Throwable ex)
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.
ex
- the exception to handleprotected void invokeExceptionListener(JMSException ex)
ex
- the exception that arose during JMS processingsetExceptionListener(javax.jms.ExceptionListener)
protected abstract boolean sharedConnectionEnabled()
getSharedConnection()
protected abstract void registerListener() throws JMSException
Subclasses need to implement this method for their specific listener management process.
JMSException
- if registration failedgetMessageListener()
,
getSharedConnection()
protected abstract void destroyListener() throws JMSException
Subclasses need to implement this method for their specific listener management process.
JMSException
- if destruction failedprotected Connection createConnection() throws JMSException
This implementation uses JMS 1.1 API.
JMSException
- if thrown by JMS API methodsprotected Session createSession(Connection con) throws JMSException
This implementation uses JMS 1.1 API.
con
- the JMS Connection to create a Session for
JMSException
- if thrown by JMS API methodsprotected boolean isClientAcknowledge(Session session) throws JMSException
This implementation uses JMS 1.1 API.
session
- the JMS Session to check
JMSException
- if thrown by JMS API methods
|
The Spring Framework | |||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | |||||||||
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |