001: /*
002: * Copyright 2002-2005 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.springframework.jms.listener.serversession;
018:
019: import java.util.Collections;
020: import java.util.HashMap;
021: import java.util.Iterator;
022: import java.util.Map;
023:
024: import javax.jms.JMSException;
025: import javax.jms.ServerSession;
026:
027: import org.apache.commons.pool.ObjectPool;
028: import org.apache.commons.pool.PoolableObjectFactory;
029: import org.apache.commons.pool.impl.GenericObjectPool;
030:
031: import org.springframework.jms.listener.serversession.ListenerSessionManager;
032:
033: /**
034: * ServerSessionFactory implementation that holds ServerSessions
035: * in a configurable Jakarta Commons Pool.
036: *
037: * <p>By default, an instance of <code>GenericObjectPool</code> is created.
038: * Subclasses may change the type of <code>ObjectPool</code> used by
039: * overriding the <code>createObjectPool</code> method.
040: *
041: * <p>Provides many configuration properties mirroring those of the Commons Pool
042: * <code>GenericObjectPool</code> class; these properties are passed to the
043: * <code>GenericObjectPool</code> during construction. If creating a subclass of this
044: * class to change the <code>ObjectPool</code> implementation type, pass in the values
045: * of configuration properties that are relevant to your chosen implementation.
046: *
047: * @author Juergen Hoeller
048: * @since 2.0
049: * @see GenericObjectPool
050: * @see #createObjectPool
051: * @see #setMaxSize
052: * @see #setMaxIdle
053: * @see #setMinIdle
054: * @see #setMaxWait
055: */
056: public class CommonsPoolServerSessionFactory extends
057: AbstractPoolingServerSessionFactory {
058:
059: private int maxIdle = GenericObjectPool.DEFAULT_MAX_IDLE;
060:
061: private int minIdle = GenericObjectPool.DEFAULT_MIN_IDLE;
062:
063: private long maxWait = GenericObjectPool.DEFAULT_MAX_WAIT;
064:
065: private long timeBetweenEvictionRunsMillis = GenericObjectPool.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS;
066:
067: private long minEvictableIdleTimeMillis = GenericObjectPool.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
068:
069: private final Map serverSessionPools = Collections
070: .synchronizedMap(new HashMap(1));
071:
072: /**
073: * Create a CommonsPoolServerSessionFactory with default settings.
074: * Default maximum size of the pool is 8.
075: * @see #setMaxSize
076: * @see GenericObjectPool#setMaxActive
077: */
078: public CommonsPoolServerSessionFactory() {
079: setMaxSize(GenericObjectPool.DEFAULT_MAX_ACTIVE);
080: }
081:
082: /**
083: * Set the maximum number of idle ServerSessions in the pool.
084: * Default is 8.
085: * @see GenericObjectPool#setMaxIdle
086: */
087: public void setMaxIdle(int maxIdle) {
088: this .maxIdle = maxIdle;
089: }
090:
091: /**
092: * Return the maximum number of idle ServerSessions in the pool.
093: */
094: public int getMaxIdle() {
095: return maxIdle;
096: }
097:
098: /**
099: * Set the minimum number of idle ServerSessions in the pool.
100: * Default is 0.
101: * @see GenericObjectPool#setMinIdle
102: */
103: public void setMinIdle(int minIdle) {
104: this .minIdle = minIdle;
105: }
106:
107: /**
108: * Return the minimum number of idle ServerSessions in the pool.
109: */
110: public int getMinIdle() {
111: return minIdle;
112: }
113:
114: /**
115: * Set the maximum waiting time for fetching an ServerSession from the pool.
116: * Default is -1, waiting forever.
117: * @see GenericObjectPool#setMaxWait
118: */
119: public void setMaxWait(long maxWait) {
120: this .maxWait = maxWait;
121: }
122:
123: /**
124: * Return the maximum waiting time for fetching a ServerSession from the pool.
125: */
126: public long getMaxWait() {
127: return maxWait;
128: }
129:
130: /**
131: * Set the time between eviction runs that check idle ServerSessions
132: * whether they have been idle for too long or have become invalid.
133: * Default is -1, not performing any eviction.
134: * @see GenericObjectPool#setTimeBetweenEvictionRunsMillis
135: */
136: public void setTimeBetweenEvictionRunsMillis(
137: long timeBetweenEvictionRunsMillis) {
138: this .timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
139: }
140:
141: /**
142: * Return the time between eviction runs that check idle ServerSessions.
143: */
144: public long getTimeBetweenEvictionRunsMillis() {
145: return timeBetweenEvictionRunsMillis;
146: }
147:
148: /**
149: * Set the minimum time that an idle ServerSession can sit in the pool
150: * before it becomes subject to eviction. Default is 1800000 (30 minutes).
151: * <p>Note that eviction runs need to be performed to take this
152: * setting into effect.
153: * @see #setTimeBetweenEvictionRunsMillis
154: * @see GenericObjectPool#setMinEvictableIdleTimeMillis
155: */
156: public void setMinEvictableIdleTimeMillis(
157: long minEvictableIdleTimeMillis) {
158: this .minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
159: }
160:
161: /**
162: * Return the minimum time that an idle ServerSession can sit in the pool.
163: */
164: public long getMinEvictableIdleTimeMillis() {
165: return minEvictableIdleTimeMillis;
166: }
167:
168: /**
169: * Returns a ServerSession from the pool, creating a new pool for the given
170: * session manager if necessary.
171: * @see #createObjectPool
172: */
173: public ServerSession getServerSession(
174: ListenerSessionManager sessionManager) throws JMSException {
175: ObjectPool pool = null;
176: synchronized (this .serverSessionPools) {
177: pool = (ObjectPool) this .serverSessionPools
178: .get(sessionManager);
179: if (pool == null) {
180: if (logger.isInfoEnabled()) {
181: logger
182: .info("Creating Commons ServerSession pool for: "
183: + sessionManager);
184: }
185: pool = createObjectPool(sessionManager);
186: this .serverSessionPools.put(sessionManager, pool);
187: }
188: }
189: try {
190: return (ServerSession) pool.borrowObject();
191: } catch (Exception ex) {
192: JMSException jmsEx = new JMSException(
193: "Failed to borrow ServerSession from pool");
194: jmsEx.setLinkedException(ex);
195: throw jmsEx;
196: }
197: }
198:
199: /**
200: * Subclasses can override this if they want to return a specific Commons pool.
201: * They should apply any configuration properties to the pool here.
202: * <p>Default is a GenericObjectPool instance with the given pool size.
203: * @param sessionManager the session manager to use for
204: * creating and executing new listener sessions
205: * @return an empty Commons <code>ObjectPool</code>.
206: * @see org.apache.commons.pool.impl.GenericObjectPool
207: * @see #setMaxSize
208: */
209: protected ObjectPool createObjectPool(
210: ListenerSessionManager sessionManager) {
211: GenericObjectPool pool = new GenericObjectPool(
212: createPoolableObjectFactory(sessionManager));
213: pool.setMaxActive(getMaxSize());
214: pool.setMaxIdle(getMaxIdle());
215: pool.setMinIdle(getMinIdle());
216: pool.setMaxWait(getMaxWait());
217: pool
218: .setTimeBetweenEvictionRunsMillis(getTimeBetweenEvictionRunsMillis());
219: pool
220: .setMinEvictableIdleTimeMillis(getMinEvictableIdleTimeMillis());
221: return pool;
222: }
223:
224: /**
225: * Create a Commons PoolableObjectFactory adapter for the given session manager.
226: * Calls <code>createServerSession</code> and <code>destroyServerSession</code>
227: * as defined by the AbstractPoolingServerSessionFactory class.
228: * @param sessionManager the session manager to use for
229: * creating and executing new listener sessions
230: * @return the Commons PoolableObjectFactory
231: * @see #createServerSession
232: * @see #destroyServerSession
233: */
234: protected PoolableObjectFactory createPoolableObjectFactory(
235: final ListenerSessionManager sessionManager) {
236: return new PoolableObjectFactory() {
237: public Object makeObject() throws JMSException {
238: return createServerSession(sessionManager);
239: }
240:
241: public void destroyObject(Object obj) {
242: destroyServerSession((ServerSession) obj);
243: }
244:
245: public boolean validateObject(Object obj) {
246: return true;
247: }
248:
249: public void activateObject(Object obj) {
250: }
251:
252: public void passivateObject(Object obj) {
253: }
254: };
255: }
256:
257: /**
258: * Returns the given ServerSession, which just finished an execution
259: * of its listener, back to the pool.
260: */
261: protected void serverSessionFinished(ServerSession serverSession,
262: ListenerSessionManager sessionManager) {
263: ObjectPool pool = (ObjectPool) this .serverSessionPools
264: .get(sessionManager);
265: try {
266: pool.returnObject(serverSession);
267: } catch (Exception ex) {
268: logger.error("Failed to return ServerSession to pool", ex);
269: }
270: }
271:
272: /**
273: * Closes all pools held by this ServerSessionFactory.
274: */
275: public void close(ListenerSessionManager sessionManager) {
276: synchronized (this .serverSessionPools) {
277: for (Iterator it = this .serverSessionPools.values()
278: .iterator(); it.hasNext();) {
279: ObjectPool pool = (ObjectPool) it.next();
280: try {
281: pool.close();
282: } catch (Exception ex) {
283: logger.error("Failed to close ServerSession pool",
284: ex);
285: }
286: }
287: }
288: }
289:
290: }
|