EL container integration; support for contextual objects; removal of deprecated Spring 2.0 functionality; Java 5 code style

This commit is contained in:
Juergen Hoeller
2008-11-20 02:10:53 +00:00
parent 369821dd66
commit 347f34c68a
281 changed files with 6120 additions and 9903 deletions

View File

@@ -1,179 +0,0 @@
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.jms.listener.serversession;
import javax.jms.JMSException;
import javax.jms.ServerSession;
import javax.jms.Session;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.task.TaskExecutor;
import org.springframework.jms.support.JmsUtils;
import org.springframework.scheduling.timer.TimerTaskExecutor;
/**
* Abstract base class for ServerSessionFactory implementations
* that pool ServerSessionFactory instances.
*
* <p>Provides a factory method that creates a poolable ServerSession
* (to be added as new instance to a pool), a callback method invoked
* when a ServerSession finished an execution of its listener (to return
* an instance to the pool), and a method to destroy a ServerSession instance
* (after removing an instance from the pool).
*
* @author Juergen Hoeller
* @since 2.0
* @deprecated as of Spring 2.5, in favor of DefaultMessageListenerContainer
* and JmsMessageEndpointManager. To be removed in Spring 3.0.
* @see org.springframework.jms.listener.serversession.CommonsPoolServerSessionFactory
*/
public abstract class AbstractPoolingServerSessionFactory implements ServerSessionFactory {
protected final Log logger = LogFactory.getLog(getClass());
private TaskExecutor taskExecutor;
private int maxSize;
/**
* Specify the TaskExecutor to use for executing ServerSessions
* (and consequently, the underlying MessageListener).
* <p>Default is a {@link org.springframework.scheduling.timer.TimerTaskExecutor}
* for each pooled ServerSession, using one Thread per pooled JMS Session.
* Alternatives are a shared TimerTaskExecutor, sharing a single Thread
* for the execution of all ServerSessions, or a TaskExecutor
* implementation backed by a thread pool.
*/
public void setTaskExecutor(TaskExecutor taskExecutor) {
this.taskExecutor = taskExecutor;
}
/**
* Return the TaskExecutor to use for executing ServerSessions.
*/
protected TaskExecutor getTaskExecutor() {
return this.taskExecutor;
}
/**
* Set the maximum size of the pool.
*/
public void setMaxSize(int maxSize) {
this.maxSize = maxSize;
}
/**
* Return the maximum size of the pool.
*/
public int getMaxSize() {
return this.maxSize;
}
/**
* Create a new poolable ServerSession.
* To be called when a new instance should be added to the pool.
* @param sessionManager the listener session manager to create the
* poolable ServerSession for
* @return the new poolable ServerSession
* @throws JMSException if creation failed
*/
protected final ServerSession createServerSession(ListenerSessionManager sessionManager) throws JMSException {
return new PoolableServerSession(sessionManager);
}
/**
* Destroy the given poolable ServerSession.
* To be called when an instance got removed from the pool.
* @param serverSession the poolable ServerSession to destroy
*/
protected final void destroyServerSession(ServerSession serverSession) {
if (serverSession != null) {
((PoolableServerSession) serverSession).close();
}
}
/**
* Template method called by a ServerSession if it finished
* execution of its listener and is ready to go back into the pool.
* <p>Subclasses should implement the actual returning of the instance
* to the pool.
* @param serverSession the ServerSession that finished its execution
* @param sessionManager the session manager that the ServerSession belongs to
*/
protected abstract void serverSessionFinished(
ServerSession serverSession, ListenerSessionManager sessionManager);
/**
* ServerSession implementation designed to be pooled.
* Creates a new JMS Session on instantiation, reuses it
* for all executions, and closes it on <code>close</code>.
* <p>Creates a TimerTaskExecutor (using a single Thread) per
* ServerSession, unless given a specific TaskExecutor to use.
*/
private class PoolableServerSession implements ServerSession {
private final ListenerSessionManager sessionManager;
private final Session session;
private TaskExecutor taskExecutor;
private TimerTaskExecutor internalExecutor;
public PoolableServerSession(final ListenerSessionManager sessionManager) throws JMSException {
this.sessionManager = sessionManager;
this.session = sessionManager.createListenerSession();
this.taskExecutor = getTaskExecutor();
if (this.taskExecutor == null) {
this.internalExecutor = new TimerTaskExecutor();
this.internalExecutor.afterPropertiesSet();
this.taskExecutor = this.internalExecutor;
}
}
public Session getSession() {
return this.session;
}
public void start() {
this.taskExecutor.execute(new Runnable() {
public void run() {
try {
sessionManager.executeListenerSession(session);
}
finally {
serverSessionFinished(PoolableServerSession.this, sessionManager);
}
}
});
}
public void close() {
if (this.internalExecutor != null) {
this.internalExecutor.destroy();
}
JmsUtils.closeSession(this.session);
}
}
}

View File

@@ -1,274 +0,0 @@
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.jms.listener.serversession;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import javax.jms.JMSException;
import javax.jms.ServerSession;
import org.apache.commons.pool.ObjectPool;
import org.apache.commons.pool.PoolableObjectFactory;
import org.apache.commons.pool.impl.GenericObjectPool;
/**
* {@link ServerSessionFactory} implementation that holds JMS
* <code>ServerSessions</code> in a configurable Jakarta Commons Pool.
*
* <p>By default, an instance of <code>GenericObjectPool</code> is created.
* Subclasses may change the type of <code>ObjectPool</code> used by
* overriding the <code>createObjectPool</code> method.
*
* <p>Provides many configuration properties mirroring those of the Commons Pool
* <code>GenericObjectPool</code> class; these properties are passed to the
* <code>GenericObjectPool</code> during construction. If creating a subclass of this
* class to change the <code>ObjectPool</code> implementation type, pass in the values
* of configuration properties that are relevant to your chosen implementation.
*
* @author Juergen Hoeller
* @since 2.0
* @deprecated as of Spring 2.5, in favor of DefaultMessageListenerContainer
* and JmsMessageEndpointManager. To be removed in Spring 3.0.
* @see GenericObjectPool
* @see #createObjectPool
* @see #setMaxSize
* @see #setMaxIdle
* @see #setMinIdle
* @see #setMaxWait
*/
public class CommonsPoolServerSessionFactory extends AbstractPoolingServerSessionFactory {
private int maxIdle = GenericObjectPool.DEFAULT_MAX_IDLE;
private int minIdle = GenericObjectPool.DEFAULT_MIN_IDLE;
private long maxWait = GenericObjectPool.DEFAULT_MAX_WAIT;
private long timeBetweenEvictionRunsMillis = GenericObjectPool.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS;
private long minEvictableIdleTimeMillis = GenericObjectPool.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
private final Map serverSessionPools = Collections.synchronizedMap(new HashMap(1));
/**
* Create a CommonsPoolServerSessionFactory with default settings.
* Default maximum size of the pool is 8.
* @see #setMaxSize
* @see GenericObjectPool#setMaxActive
*/
public CommonsPoolServerSessionFactory() {
setMaxSize(GenericObjectPool.DEFAULT_MAX_ACTIVE);
}
/**
* Set the maximum number of idle ServerSessions in the pool.
* Default is 8.
* @see GenericObjectPool#setMaxIdle
*/
public void setMaxIdle(int maxIdle) {
this.maxIdle = maxIdle;
}
/**
* Return the maximum number of idle ServerSessions in the pool.
*/
public int getMaxIdle() {
return this.maxIdle;
}
/**
* Set the minimum number of idle ServerSessions in the pool.
* Default is 0.
* @see GenericObjectPool#setMinIdle
*/
public void setMinIdle(int minIdle) {
this.minIdle = minIdle;
}
/**
* Return the minimum number of idle ServerSessions in the pool.
*/
public int getMinIdle() {
return this.minIdle;
}
/**
* Set the maximum waiting time for fetching an ServerSession from the pool.
* Default is -1, waiting forever.
* @see GenericObjectPool#setMaxWait
*/
public void setMaxWait(long maxWait) {
this.maxWait = maxWait;
}
/**
* Return the maximum waiting time for fetching a ServerSession from the pool.
*/
public long getMaxWait() {
return this.maxWait;
}
/**
* Set the time between eviction runs that check idle ServerSessions
* whether they have been idle for too long or have become invalid.
* Default is -1, not performing any eviction.
* @see GenericObjectPool#setTimeBetweenEvictionRunsMillis
*/
public void setTimeBetweenEvictionRunsMillis(long timeBetweenEvictionRunsMillis) {
this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
}
/**
* Return the time between eviction runs that check idle ServerSessions.
*/
public long getTimeBetweenEvictionRunsMillis() {
return this.timeBetweenEvictionRunsMillis;
}
/**
* Set the minimum time that an idle ServerSession can sit in the pool
* before it becomes subject to eviction. Default is 1800000 (30 minutes).
* <p>Note that eviction runs need to be performed to take this
* setting into effect.
* @see #setTimeBetweenEvictionRunsMillis
* @see GenericObjectPool#setMinEvictableIdleTimeMillis
*/
public void setMinEvictableIdleTimeMillis(long minEvictableIdleTimeMillis) {
this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
}
/**
* Return the minimum time that an idle ServerSession can sit in the pool.
*/
public long getMinEvictableIdleTimeMillis() {
return this.minEvictableIdleTimeMillis;
}
/**
* Returns a ServerSession from the pool, creating a new pool for the given
* session manager if necessary.
* @see #createObjectPool
*/
public ServerSession getServerSession(ListenerSessionManager sessionManager) throws JMSException {
ObjectPool pool = null;
synchronized (this.serverSessionPools) {
pool = (ObjectPool) this.serverSessionPools.get(sessionManager);
if (pool == null) {
if (logger.isInfoEnabled()) {
logger.info("Creating Commons ServerSession pool for: " + sessionManager);
}
pool = createObjectPool(sessionManager);
this.serverSessionPools.put(sessionManager, pool);
}
}
try {
return (ServerSession) pool.borrowObject();
}
catch (Exception ex) {
JMSException jmsEx = new JMSException("Failed to borrow ServerSession from pool");
jmsEx.setLinkedException(ex);
throw jmsEx;
}
}
/**
* Subclasses can override this if they want to return a specific Commons pool.
* They should apply any configuration properties to the pool here.
* <p>Default is a GenericObjectPool instance with the given pool size.
* @param sessionManager the session manager to use for
* creating and executing new listener sessions
* @return an empty Commons <code>ObjectPool</code>.
* @see org.apache.commons.pool.impl.GenericObjectPool
* @see #setMaxSize
*/
protected ObjectPool createObjectPool(ListenerSessionManager sessionManager) {
GenericObjectPool pool = new GenericObjectPool(createPoolableObjectFactory(sessionManager));
pool.setMaxActive(getMaxSize());
pool.setMaxIdle(getMaxIdle());
pool.setMinIdle(getMinIdle());
pool.setMaxWait(getMaxWait());
pool.setTimeBetweenEvictionRunsMillis(getTimeBetweenEvictionRunsMillis());
pool.setMinEvictableIdleTimeMillis(getMinEvictableIdleTimeMillis());
return pool;
}
/**
* Create a Commons PoolableObjectFactory adapter for the given session manager.
* Calls <code>createServerSession</code> and <code>destroyServerSession</code>
* as defined by the AbstractPoolingServerSessionFactory class.
* @param sessionManager the session manager to use for
* creating and executing new listener sessions
* @return the Commons PoolableObjectFactory
* @see #createServerSession
* @see #destroyServerSession
*/
protected PoolableObjectFactory createPoolableObjectFactory(final ListenerSessionManager sessionManager) {
return new PoolableObjectFactory() {
public Object makeObject() throws JMSException {
return createServerSession(sessionManager);
}
public void destroyObject(Object obj) {
destroyServerSession((ServerSession) obj);
}
public boolean validateObject(Object obj) {
return true;
}
public void activateObject(Object obj) {
}
public void passivateObject(Object obj) {
}
};
}
/**
* Returns the given ServerSession, which just finished an execution
* of its listener, back to the pool.
*/
protected void serverSessionFinished(ServerSession serverSession, ListenerSessionManager sessionManager) {
ObjectPool pool = (ObjectPool) this.serverSessionPools.get(sessionManager);
if (pool == null) {
throw new IllegalStateException("No pool found for session manager [" + sessionManager + "]");
}
try {
pool.returnObject(serverSession);
}
catch (Exception ex) {
logger.error("Failed to return ServerSession to pool", ex);
}
}
/**
* Closes and removes the pool for the given session manager.
*/
public void close(ListenerSessionManager sessionManager) {
ObjectPool pool = (ObjectPool) this.serverSessionPools.remove(sessionManager);
if (pool != null) {
try {
pool.close();
}
catch (Exception ex) {
logger.error("Failed to close ServerSession pool", ex);
}
}
}
}

View File

@@ -1,58 +0,0 @@
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.jms.listener.serversession;
import javax.jms.JMSException;
import javax.jms.Session;
/**
* SPI interface for creating and executing JMS Sessions,
* pre-populated with a specific MessageListener.
* Implemented by ServerSessionMessageListenerContainer,
* accessed by ServerSessionFactory implementations.
*
* <p>Effectively, an instance that implements this interface
* represents a message listener container for a specific
* listener and destination.
*
* @author Juergen Hoeller
* @since 2.0
* @deprecated as of Spring 2.5, in favor of DefaultMessageListenerContainer
* and JmsMessageEndpointManager. To be removed in Spring 3.0.
* @see ServerSessionFactory
* @see ServerSessionMessageListenerContainer
*/
public interface ListenerSessionManager {
/**
* Create a new JMS Session, pre-populated with this manager's
* MessageListener.
* @return the new JMS Session
* @throws JMSException if Session creation failed
* @see javax.jms.Session#setMessageListener(javax.jms.MessageListener)
*/
Session createListenerSession() throws JMSException;
/**
* Execute the given JMS Session, triggering its MessageListener
* with pre-loaded messages.
* @param session the JMS Session to invoke
* @see javax.jms.Session#run()
*/
void executeListenerSession(Session session);
}

View File

@@ -1,63 +0,0 @@
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.jms.listener.serversession;
import javax.jms.JMSException;
import javax.jms.ServerSession;
import org.springframework.jms.listener.serversession.ListenerSessionManager;
/**
* SPI interface to be implemented by components that manage
* JMS ServerSessions. Usually, but not necessarily, an implementation
* of this interface will hold a pool of ServerSessions.
*
* <p>The passed-in ListenerSessionManager has to be used for creating
* and executing JMS Sessions. This session manager is responsible for
* registering a MessageListener with all Sessions that it creates.
* Consequently, the ServerSessionFactory implementation has to
* concentrate on the actual lifecycle (e.g. pooling) of JMS Sessions,
* but is not concerned about Session creation or execution.
*
* @author Juergen Hoeller
* @since 2.0
* @deprecated as of Spring 2.5, in favor of DefaultMessageListenerContainer
* and JmsMessageEndpointManager. To be removed in Spring 3.0.
* @see org.springframework.jms.listener.serversession.ListenerSessionManager
* @see org.springframework.jms.listener.serversession.ServerSessionMessageListenerContainer
*/
public interface ServerSessionFactory {
/**
* Retrieve a JMS ServerSession for the given session manager.
* @param sessionManager the session manager to use for
* creating and executing new listener sessions
* (implicitly indicating the target listener to invoke)
* @return the JMS ServerSession
* @throws JMSException if retrieval failed
*/
ServerSession getServerSession(ListenerSessionManager sessionManager) throws JMSException;
/**
* Close all ServerSessions for the given session manager.
* @param sessionManager the session manager used for
* creating and executing new listener sessions
* (implicitly indicating the target listener)
*/
void close(ListenerSessionManager sessionManager);
}

View File

@@ -1,256 +0,0 @@
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.jms.listener.serversession;
import javax.jms.Connection;
import javax.jms.ConnectionConsumer;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.ServerSession;
import javax.jms.ServerSessionPool;
import javax.jms.Session;
import javax.jms.Topic;
import org.springframework.jms.listener.AbstractMessageListenerContainer;
import org.springframework.jms.support.JmsUtils;
/**
* Message listener container that builds on the {@link javax.jms.ServerSessionPool}
* SPI, creating JMS ServerSession instances through a pluggable
* {@link ServerSessionFactory}.
*
* <p><b>NOTE:</b> This class requires a JMS 1.1+ provider, because it builds on the
* domain-independent API. <b>Use the {@link ServerSessionMessageListenerContainer102}
* subclass for a JMS 1.0.2 provider, e.g. when running on a J2EE 1.3 server.</b>
*
* <p>The default ServerSessionFactory is a {@link SimpleServerSessionFactory},
* which will create a new ServerSession for each listener execution.
* Consider specifying a {@link CommonsPoolServerSessionFactory} to reuse JMS
* Sessions and/or to limit the number of concurrent ServerSession executions.
*
* <p>See the {@link AbstractMessageListenerContainer} javadoc for details
* on acknowledge modes and other configuration options.
*
* <p><b>This is an 'advanced' (special-purpose) message listener container.</b>
* For a simpler message listener container, in particular when using
* a JMS provider without ServerSessionPool support, consider using
* {@link org.springframework.jms.listener.SimpleMessageListenerContainer}.
* For a general one-stop shop that is nevertheless very flexible, consider
* {@link org.springframework.jms.listener.DefaultMessageListenerContainer}.
*
* @author Juergen Hoeller
* @since 2.0
* @deprecated as of Spring 2.5, in favor of DefaultMessageListenerContainer
* and JmsMessageEndpointManager. To be removed in Spring 3.0.
* @see org.springframework.jms.listener.SimpleMessageListenerContainer
* @see org.springframework.jms.listener.endpoint.JmsMessageEndpointManager
*/
public class ServerSessionMessageListenerContainer extends AbstractMessageListenerContainer
implements ListenerSessionManager {
private ServerSessionFactory serverSessionFactory = new SimpleServerSessionFactory();
private int maxMessagesPerTask = 1;
private ConnectionConsumer consumer;
/**
* Set the Spring ServerSessionFactory to use.
* <p>Default is a plain SimpleServerSessionFactory.
* Consider using a CommonsPoolServerSessionFactory to reuse JMS Sessions
* and/or to limit the number of concurrent ServerSession executions.
* @see SimpleServerSessionFactory
* @see CommonsPoolServerSessionFactory
*/
public void setServerSessionFactory(ServerSessionFactory serverSessionFactory) {
this.serverSessionFactory =
(serverSessionFactory != null ? serverSessionFactory : new SimpleServerSessionFactory());
}
/**
* Return the Spring ServerSessionFactory to use.
*/
protected ServerSessionFactory getServerSessionFactory() {
return this.serverSessionFactory;
}
/**
* Set the maximum number of messages to load into a JMS Session.
* Default is 1.
* <p>See the corresponding JMS <code>createConnectionConsumer</code>
* argument for details.
* @see javax.jms.Connection#createConnectionConsumer
*/
public void setMaxMessagesPerTask(int maxMessagesPerTask) {
this.maxMessagesPerTask = maxMessagesPerTask;
}
/**
* Return the maximum number of messages to load into a JMS Session.
*/
protected int getMaxMessagesPerTask() {
return this.maxMessagesPerTask;
}
//-------------------------------------------------------------------------
// Implementation of AbstractMessageListenerContainer's template methods
//-------------------------------------------------------------------------
/**
* Always use a shared JMS Connection.
*/
protected final boolean sharedConnectionEnabled() {
return true;
}
/**
* Creates a JMS ServerSessionPool for the specified listener and registers
* it with a JMS ConnectionConsumer for the specified destination.
* @see #createServerSessionPool
* @see #createConsumer
*/
protected void doInitialize() throws JMSException {
establishSharedConnection();
Connection con = getSharedConnection();
Destination destination = getDestination();
if (destination == null) {
Session session = createSession(con);
try {
destination = resolveDestinationName(session, getDestinationName());
}
finally {
JmsUtils.closeSession(session);
}
}
ServerSessionPool pool = createServerSessionPool();
this.consumer = createConsumer(con, destination, pool);
}
/**
* Create a JMS ServerSessionPool for the specified message listener,
* via this container's ServerSessionFactory.
* <p>This message listener container implements the ListenerSessionManager
* interface, hence can be passed to the ServerSessionFactory itself.
* @return the ServerSessionPool
* @throws JMSException if creation of the ServerSessionPool failed
* @see #setServerSessionFactory
* @see ServerSessionFactory#getServerSession(ListenerSessionManager)
*/
protected ServerSessionPool createServerSessionPool() throws JMSException {
return new ServerSessionPool() {
public ServerSession getServerSession() throws JMSException {
logger.debug("JMS ConnectionConsumer requests ServerSession");
return getServerSessionFactory().getServerSession(ServerSessionMessageListenerContainer.this);
}
};
}
/**
* Return the JMS ConnectionConsumer used by this message listener container.
* Available after initialization.
*/
protected final ConnectionConsumer getConsumer() {
return this.consumer;
}
/**
* Close the JMS ServerSessionPool for the specified message listener,
* via this container's ServerSessionFactory, and subsequently also
* this container's JMS ConnectionConsumer.
* <p>This message listener container implements the ListenerSessionManager
* interface, hence can be passed to the ServerSessionFactory itself.
* @see #setServerSessionFactory
* @see ServerSessionFactory#getServerSession(ListenerSessionManager)
*/
protected void doShutdown() throws JMSException {
logger.debug("Closing ServerSessionFactory");
getServerSessionFactory().close(this);
logger.debug("Closing JMS ConnectionConsumer");
this.consumer.close();
}
//-------------------------------------------------------------------------
// Implementation of the ListenerSessionManager interface
//-------------------------------------------------------------------------
/**
* Create a JMS Session with the specified listener registered.
* Listener execution is delegated to the <code>executeListener</code> method.
* <p>Default implementation simply calls <code>setMessageListener</code>
* on a newly created JMS Session, according to the JMS specification's
* ServerSessionPool section.
* @return the JMS Session
* @throws JMSException if thrown by JMS API methods
* @see #executeListener
*/
public Session createListenerSession() throws JMSException {
final Session session = createSession(getSharedConnection());
session.setMessageListener(new MessageListener() {
public void onMessage(Message message) {
executeListener(session, message);
}
});
return session;
}
/**
* Execute the given JMS Session, triggering invocation
* of its listener.
* <p>Default implementation simply calls <code>run()</code>
* on the JMS Session, according to the JMS specification's
* ServerSessionPool section.
* @param session the JMS Session to execute
*/
public void executeListenerSession(Session session) {
session.run();
}
//-------------------------------------------------------------------------
// JMS 1.1 factory methods, potentially overridden for JMS 1.0.2
//-------------------------------------------------------------------------
/**
* Create a JMS ConnectionConsumer for the given Connection.
* <p>This implementation uses JMS 1.1 API.
* @param con the JMS Connection to create a Session for
* @param destination the JMS Destination to listen to
* @param pool the ServerSessionpool to use
* @return the new JMS Session
* @throws JMSException if thrown by JMS API methods
*/
protected ConnectionConsumer createConsumer(Connection con, Destination destination, ServerSessionPool pool)
throws JMSException {
if (isSubscriptionDurable() && destination instanceof Topic) {
return con.createDurableConnectionConsumer(
(Topic) destination, getDurableSubscriptionName(), getMessageSelector(), pool, getMaxMessagesPerTask());
}
else {
return con.createConnectionConsumer(destination, getMessageSelector(), pool, getMaxMessagesPerTask());
}
}
}

View File

@@ -1,101 +0,0 @@
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.jms.listener.serversession;
import javax.jms.Connection;
import javax.jms.ConnectionConsumer;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Queue;
import javax.jms.QueueConnection;
import javax.jms.QueueConnectionFactory;
import javax.jms.ServerSessionPool;
import javax.jms.Session;
import javax.jms.Topic;
import javax.jms.TopicConnection;
import javax.jms.TopicConnectionFactory;
/**
* A subclass of {@link ServerSessionMessageListenerContainer} for the JMS 1.0.2 specification,
* not relying on JMS 1.1 methods like ServerSessionMessageListenerContainer itself.
*
* <p>This class can be used for JMS 1.0.2 providers, offering the same facility as
* ServerSessionMessageListenerContainer does for JMS 1.1 providers.
*
* @author Juergen Hoeller
* @since 2.0
* @deprecated as of Spring 2.5, in favor of DefaultMessageListenerContainer
* and JmsMessageEndpointManager. To be removed in Spring 3.0.
*/
public class ServerSessionMessageListenerContainer102 extends ServerSessionMessageListenerContainer {
/**
* This implementation overrides the superclass method to use JMS 1.0.2 API.
*/
protected Connection createConnection() throws JMSException {
if (isPubSubDomain()) {
return ((TopicConnectionFactory) getConnectionFactory()).createTopicConnection();
}
else {
return ((QueueConnectionFactory) getConnectionFactory()).createQueueConnection();
}
}
/**
* This implementation overrides the superclass method to use JMS 1.0.2 API.
*/
protected ConnectionConsumer createConsumer(Connection con, Destination destination, ServerSessionPool pool)
throws JMSException {
if (isPubSubDomain()) {
if (isSubscriptionDurable()) {
return ((TopicConnection) con).createDurableConnectionConsumer(
(Topic) destination, getDurableSubscriptionName(), getMessageSelector(), pool, getMaxMessagesPerTask());
}
else {
return ((TopicConnection) con).createConnectionConsumer(
(Topic) destination, getMessageSelector(), pool, getMaxMessagesPerTask());
}
}
else {
return ((QueueConnection) con).createConnectionConsumer(
(Queue) destination, getMessageSelector(), pool, getMaxMessagesPerTask());
}
}
/**
* This implementation overrides the superclass method to use JMS 1.0.2 API.
*/
protected Session createSession(Connection con) throws JMSException {
if (isPubSubDomain()) {
return ((TopicConnection) con).createTopicSession(isSessionTransacted(), getSessionAcknowledgeMode());
}
else {
return ((QueueConnection) con).createQueueSession(isSessionTransacted(), getSessionAcknowledgeMode());
}
}
/**
* This implementation overrides the superclass method to avoid using
* JMS 1.1's Session <code>getAcknowledgeMode()</code> method.
* The best we can do here is to check the setting on the listener container.
*/
protected boolean isClientAcknowledge(Session session) throws JMSException {
return (getSessionAcknowledgeMode() == Session.CLIENT_ACKNOWLEDGE);
}
}

View File

@@ -1,138 +0,0 @@
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.jms.listener.serversession;
import javax.jms.JMSException;
import javax.jms.ServerSession;
import javax.jms.Session;
import org.springframework.core.task.SimpleAsyncTaskExecutor;
import org.springframework.core.task.TaskExecutor;
import org.springframework.jms.support.JmsUtils;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
/**
* The simplest possible implementation of the ServerSessionFactory SPI:
* creating a new ServerSession with a new JMS Session every time.
* This is the default used by ServerSessionMessageListenerContainer.
*
* <p>The execution of a ServerSession (and its MessageListener) gets delegated
* to a TaskExecutor. By default, a SimpleAsyncTaskExecutor will be used,
* creating a new Thread for every execution attempt. Alternatives are a
* TimerTaskExecutor, sharing a single Thread for the execution of all
* ServerSessions, or a TaskExecutor implementation backed by a thread pool.
*
* <p>To reuse JMS Sessions and/or to limit the number of concurrent
* ServerSession executions, consider using a pooling ServerSessionFactory:
* for example, CommonsPoolServerSessionFactory.
*
* @author Juergen Hoeller
* @since 2.0
* @deprecated as of Spring 2.5, in favor of DefaultMessageListenerContainer
* and JmsMessageEndpointManager. To be removed in Spring 3.0.
* @see org.springframework.core.task.TaskExecutor
* @see org.springframework.core.task.SimpleAsyncTaskExecutor
* @see org.springframework.scheduling.timer.TimerTaskExecutor
* @see CommonsPoolServerSessionFactory
* @see ServerSessionMessageListenerContainer
*/
public class SimpleServerSessionFactory implements ServerSessionFactory {
/**
* Default thread name prefix: "SimpleServerSessionFactory-".
*/
public static final String DEFAULT_THREAD_NAME_PREFIX =
ClassUtils.getShortName(SimpleServerSessionFactory.class) + "-";
private TaskExecutor taskExecutor = new SimpleAsyncTaskExecutor(DEFAULT_THREAD_NAME_PREFIX);
/**
* Specify the TaskExecutor to use for executing ServerSessions
* (and consequently, the underlying MessageListener).
* <p>Default is a SimpleAsyncTaskExecutor, creating a new Thread for
* every execution attempt. Alternatives are a TimerTaskExecutor,
* sharing a single Thread for the execution of all ServerSessions,
* or a TaskExecutor implementation backed by a thread pool.
* @see org.springframework.core.task.SimpleAsyncTaskExecutor
* @see org.springframework.scheduling.timer.TimerTaskExecutor
*/
public void setTaskExecutor(TaskExecutor taskExecutor) {
Assert.notNull(taskExecutor, "taskExecutor is required");
this.taskExecutor = taskExecutor;
}
/**
* Return the TaskExecutor to use for executing ServerSessions.
*/
protected TaskExecutor getTaskExecutor() {
return taskExecutor;
}
/**
* Creates a new SimpleServerSession with a new JMS Session
* for every call.
*/
public ServerSession getServerSession(ListenerSessionManager sessionManager) throws JMSException {
return new SimpleServerSession(sessionManager);
}
/**
* This implementation is empty, as there is no state held for
* each ListenerSessionManager.
*/
public void close(ListenerSessionManager sessionManager) {
}
/**
* ServerSession implementation that simply creates a new
* JMS Session and executes it via the specified TaskExecutor.
*/
private class SimpleServerSession implements ServerSession {
private final ListenerSessionManager sessionManager;
private final Session session;
public SimpleServerSession(ListenerSessionManager sessionManager) throws JMSException {
this.sessionManager = sessionManager;
this.session = sessionManager.createListenerSession();
}
public Session getSession() {
return session;
}
public void start() {
getTaskExecutor().execute(new Runnable() {
public void run() {
try {
sessionManager.executeListenerSession(session);
}
finally {
JmsUtils.closeSession(session);
}
}
});
}
}
}

View File

@@ -1,8 +0,0 @@
<html>
<body>
This package contains the ServerSessionMessageListenerContainer implementation,
based on the standard JMS ServerSessionPool API.
</body>
</html>

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2007 the original author or authors.
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,7 +17,7 @@
package org.springframework.jms.support.destination;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Queue;
@@ -25,7 +25,6 @@ import javax.jms.Session;
import javax.jms.Topic;
import javax.naming.NamingException;
import org.springframework.core.CollectionFactory;
import org.springframework.jndi.JndiLocatorSupport;
import org.springframework.util.Assert;
@@ -61,7 +60,7 @@ public class JndiDestinationResolver extends JndiLocatorSupport implements Cachi
private DestinationResolver dynamicDestinationResolver = new DynamicDestinationResolver();
private final Map destinationCache = CollectionFactory.createConcurrentMapIfPossible(16);
private final Map<String, Destination> destinationCache = new ConcurrentHashMap<String, Destination>();
/**
@@ -103,7 +102,7 @@ public class JndiDestinationResolver extends JndiLocatorSupport implements Cachi
throws JMSException {
Assert.notNull(destinationName, "Destination name must not be null");
Destination dest = (Destination) this.destinationCache.get(destinationName);
Destination dest = this.destinationCache.get(destinationName);
if (dest != null) {
validateDestination(dest, destinationName, pubSubDomain);
}