/*
* 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);
}
}
}