View Javadoc

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 }