001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jboss.resource.connectionmanager;
023:
024: import java.security.AccessController;
025: import java.security.PrivilegedAction;
026: import java.util.ArrayList;
027:
028: import java.util.Collection;
029: import java.util.Iterator;
030: import org.jboss.logging.Logger;
031:
032: /**
033: * IdleRemover
034: *
035: * @author <a href="mailto:d_jencks@users.sourceforge.net">David Jencks</a>
036: * @author <a href="mailto:adrian@jboss.com">Adrian Brock</a>
037: * @version $Revision: 57189 $
038: */
039: public class IdleRemover {
040: private final Logger log = Logger.getLogger(getClass());
041:
042: private final Collection pools = new ArrayList();
043:
044: private long interval = Long.MAX_VALUE;
045:
046: private long next = Long.MAX_VALUE;//important initialization!
047:
048: private static final IdleRemover remover = new IdleRemover();
049:
050: public static void registerPool(InternalManagedConnectionPool mcp,
051: long interval) {
052: remover.internalRegisterPool(mcp, interval);
053: }
054:
055: public static void unregisterPool(InternalManagedConnectionPool mcp) {
056: remover.internalUnregisterPool(mcp);
057: }
058:
059: /**
060: * For testing
061: */
062: public static void waitForBackgroundThread() {
063: synchronized (remover.pools) {
064: return;
065: }
066: }
067:
068: private IdleRemover() {
069: AccessController.doPrivileged(new PrivilegedAction() {
070: public Object run() {
071: Runnable runnable = new IdleRemoverRunnable();
072: Thread removerThread = new Thread(runnable,
073: "IdleRemover");
074: removerThread.setDaemon(true);
075: removerThread.start();
076: return null;
077: }
078: });
079: }
080:
081: private void internalRegisterPool(
082: InternalManagedConnectionPool mcp, long interval) {
083: log
084: .debug("internalRegisterPool: registering pool with interval "
085: + interval + " old interval: " + this .interval);
086: synchronized (pools) {
087: pools.add(mcp);
088: if (interval > 1 && interval / 2 < this .interval) {
089: this .interval = interval / 2;
090: long maybeNext = System.currentTimeMillis()
091: + this .interval;
092: if (next > maybeNext && maybeNext > 0) {
093: next = maybeNext;
094: log
095: .debug("internalRegisterPool: about to notify thread: old next: "
096: + next + ", new next: " + maybeNext);
097: pools.notify();
098: }
099: }
100: }
101: }
102:
103: private void internalUnregisterPool(
104: InternalManagedConnectionPool mcp) {
105: synchronized (pools) {
106: pools.remove(mcp);
107: if (pools.size() == 0) {
108: log
109: .debug("internalUnregisterPool: setting interval to Long.MAX_VALUE");
110: interval = Long.MAX_VALUE;
111: }
112: }
113: }
114:
115: /**
116: * Change the context classloader to be where the idle remover was loaded from.<p>
117: *
118: * This avoids holding a reference to the caller's classloader which may be undeployed.
119: */
120: private void setupContextClassLoader() {
121: // Could be null if loaded from system classloader
122: final ClassLoader cl = IdleRemover.class.getClassLoader();
123: if (cl == null)
124: return;
125:
126: SecurityManager sm = System.getSecurityManager();
127: if (sm == null)
128: Thread.currentThread().setContextClassLoader(cl);
129:
130: AccessController.doPrivileged(new PrivilegedAction() {
131: public Object run() {
132: Thread.currentThread().setContextClassLoader(cl);
133: return null;
134: }
135: });
136: }
137:
138: /**
139: * Idle Remover background thread
140: */
141: private class IdleRemoverRunnable implements Runnable {
142: public void run() {
143: setupContextClassLoader();
144:
145: synchronized (pools) {
146: while (true) {
147: try {
148: pools.wait(interval);
149: log
150: .debug("run: IdleRemover notifying pools, interval: "
151: + interval);
152: for (Iterator i = pools.iterator(); i.hasNext();)
153: ((InternalManagedConnectionPool) i.next())
154: .removeTimedOut();
155: next = System.currentTimeMillis() + interval;
156: if (next < 0)
157: next = Long.MAX_VALUE;
158:
159: } catch (InterruptedException ie) {
160: log
161: .info("run: IdleRemover has been interrupted, returning");
162: return;
163: } catch (RuntimeException e) {
164: log
165: .warn(
166: "run: IdleRemover ignored unexpected runtime exception",
167: e);
168: } catch (Error e) {
169: log
170: .warn(
171: "run: IdleRemover ignored unexpected error",
172: e);
173: }
174: }
175: }
176: }
177: }
178: }
|