1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package org.apache.commons.pool.impl; 19 20 import java.security.AccessController; 21 import java.security.PrivilegedAction; 22 import java.util.Timer; 23 import java.util.TimerTask; 24 25 /** 26 * <p> 27 * Provides a shared idle object eviction timer for all pools. This class wraps 28 * the standard {@link Timer} and keeps track of how many pools are using it. 29 * If no pools are using the timer, it is canceled. This prevents a thread 30 * being left running which, in application server environments, can lead to 31 * memory leads and/or prevent applications from shutting down or reloading 32 * cleanly. 33 * </p> 34 * <p> 35 * This class has package scope to prevent its inclusion in the pool public API. 36 * The class declaration below should *not* be changed to public. 37 * </p> 38 */ 39 class EvictionTimer { 40 41 /** Timer instance */ 42 private static Timer _timer; //@GuardedBy("this") 43 44 /** Static usage count tracker */ 45 private static int _usageCount; //@GuardedBy("this") 46 47 /** Prevent instantiation */ 48 private EvictionTimer() { 49 // Hide the default constuctor 50 } 51 52 /** 53 * Add the specified eviction task to the timer. Tasks that are added with a 54 * call to this method *must* call {@link #cancel(TimerTask)} to cancel the 55 * task to prevent memory and/or thread leaks in application server 56 * environments. 57 * @param task Task to be scheduled 58 * @param delay Delay in milliseconds before task is executed 59 * @param period Time in milliseconds between executions 60 */ 61 static synchronized void schedule(TimerTask task, long delay, long period) { 62 if (null == _timer) { 63 // Force the new Timer thread to be created with a context class 64 // loader set to the class loader that loaded this library 65 ClassLoader ccl = (ClassLoader) AccessController.doPrivileged( 66 new PrivilegedGetTccl()); 67 try { 68 AccessController.doPrivileged(new PrivilegedSetTccl( 69 EvictionTimer.class.getClassLoader())); 70 _timer = new Timer(true); 71 } finally { 72 AccessController.doPrivileged(new PrivilegedSetTccl(ccl)); 73 } 74 } 75 _usageCount++; 76 _timer.schedule(task, delay, period); 77 } 78 79 /** 80 * Remove the specified eviction task from the timer. 81 * @param task Task to be scheduled 82 */ 83 static synchronized void cancel(TimerTask task) { 84 task.cancel(); 85 _usageCount--; 86 if (_usageCount == 0) { 87 _timer.cancel(); 88 _timer = null; 89 } 90 } 91 92 /** 93 * {@link PrivilegedAction} used to get the ContextClassLoader 94 */ 95 private static class PrivilegedGetTccl implements PrivilegedAction { 96 97 /** 98 * {@inheritDoc} 99 */ 100 public Object run() { 101 return Thread.currentThread().getContextClassLoader(); 102 } 103 } 104 105 /** 106 * {@link PrivilegedAction} used to set the ContextClassLoader 107 */ 108 private static class PrivilegedSetTccl implements PrivilegedAction { 109 110 /** ClassLoader */ 111 private final ClassLoader cl; 112 113 /** 114 * Create a new PrivilegedSetTccl using the given classloader 115 * @param cl ClassLoader to use 116 */ 117 PrivilegedSetTccl(ClassLoader cl) { 118 this.cl = cl; 119 } 120 121 /** 122 * {@inheritDoc} 123 */ 124 public Object run() { 125 Thread.currentThread().setContextClassLoader(cl); 126 return null; 127 } 128 } 129 130 }