View Javadoc

1   /*
2    * $Id: ExpiryMonitor.java 19191 2010-08-25 21:05:23Z tcarlson $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
5    *
6    * The software in this package is published under the terms of the CPAL v1.0
7    * license, a copy of which has been included with this distribution in the
8    * LICENSE.txt file.
9    */
10  
11  package org.mule.util.monitor;
12  
13  import org.mule.api.lifecycle.Disposable;
14  import org.mule.config.i18n.CoreMessages;
15  import org.mule.util.concurrent.DaemonThreadFactory;
16  
17  import java.util.Iterator;
18  import java.util.Map;
19  
20  import edu.emory.mathcs.backport.java.util.concurrent.ConcurrentHashMap;
21  import edu.emory.mathcs.backport.java.util.concurrent.ScheduledThreadPoolExecutor;
22  import edu.emory.mathcs.backport.java.util.concurrent.TimeUnit;
23  
24  import org.apache.commons.logging.Log;
25  import org.apache.commons.logging.LogFactory;
26  
27  /**
28   * <code>ExpiryMonitor</code> can monitor objects beased on an expiry time and can
29   * invoke a callback method once the object time has expired. If the object does
30   * expire it is removed from this monitor.
31   */
32  public class ExpiryMonitor implements Runnable, Disposable
33  {
34      /**
35       * logger used by this class
36       */
37      protected static final Log logger = LogFactory.getLog(ExpiryMonitor.class);
38  
39      protected ScheduledThreadPoolExecutor scheduler;
40  
41      private Map monitors;
42  
43      private int monitorFrequency;
44  
45      private String name;
46      
47      private ClassLoader contextClassLoader;
48  
49      public ExpiryMonitor(String name)
50      {
51          this(name, 1000);
52      }
53  
54      public ExpiryMonitor(String name, int monitorFrequency)
55      {
56          this.name = name;
57          this.monitorFrequency = monitorFrequency;
58          init();
59      }
60  
61      public ExpiryMonitor(String name, int monitorFrequency, ClassLoader contextClassLoader)
62      {
63          this.name = name;
64          this.monitorFrequency = monitorFrequency;
65          this.contextClassLoader = contextClassLoader;
66          init();
67      }
68      
69      public ExpiryMonitor(String name, int monitorFrequency, ScheduledThreadPoolExecutor scheduler)
70      {
71          this.name = name;
72          this.monitorFrequency = monitorFrequency;
73          this.scheduler = scheduler;
74          init();
75      }
76  
77      protected void init()
78      {
79          if (monitorFrequency <= 0)
80          {
81              throw new IllegalArgumentException(CoreMessages.propertyHasInvalidValue("monitorFrequency",
82                      new Integer(monitorFrequency)).toString());
83          }
84          monitors = new ConcurrentHashMap();
85          if (scheduler == null)
86          {
87              this.scheduler = new ScheduledThreadPoolExecutor(1);
88              scheduler.setThreadFactory(new DaemonThreadFactory(name + "-Monitor", contextClassLoader));
89              scheduler.scheduleWithFixedDelay(this, 0, monitorFrequency,
90                      TimeUnit.MILLISECONDS);
91          }
92      }
93  
94      /**
95       * Adds an expirable object to monitor. If the Object is already being monitored
96       * it will be reset and the millisecond timeout will be ignored
97       *
98       * @param value     the expiry value
99       * @param timeUnit  The time unit of the Expiry value
100      * @param expirable the objec that will expire
101      */
102     public void addExpirable(long value, TimeUnit timeUnit, Expirable expirable)
103     {
104         if (isRegistered(expirable))
105         {
106             resetExpirable(expirable);
107         }
108         else
109         {
110             if (logger.isDebugEnabled())
111             {
112                 logger.debug("Adding new expirable: " + expirable);
113             }
114             monitors.put(expirable, new ExpirableHolder(timeUnit.toNanos(value), expirable));
115         }
116     }
117 
118     public boolean isRegistered(Expirable expirable)
119     {
120         return (monitors.get(expirable) != null);
121     }
122 
123     public void removeExpirable(Expirable expirable)
124     {
125         if (logger.isDebugEnabled())
126         {
127             logger.debug("Removing expirable: " + expirable);
128         }
129         monitors.remove(expirable);
130     }
131 
132     public void resetExpirable(Expirable expirable)
133     {
134         ExpirableHolder eh = (ExpirableHolder) monitors.get(expirable);
135         if (eh != null)
136         {
137             eh.reset();
138             if (logger.isDebugEnabled())
139             {
140                 logger.debug("Reset expirable: " + expirable);
141             }
142         }
143     }
144 
145     /**
146      * The action to be performed by this timer task.
147      */
148     public void run()
149     {
150         ExpirableHolder holder;
151         for (Iterator iterator = monitors.values().iterator(); iterator.hasNext();)
152         {
153             holder = (ExpirableHolder) iterator.next();
154             if (holder.isExpired())
155             {
156                 removeExpirable(holder.getExpirable());
157                 holder.getExpirable().expired();
158             }
159         }
160     }
161 
162     public void dispose()
163     {
164         logger.info("disposing monitor");
165         scheduler.shutdown();
166         ExpirableHolder holder;
167         for (Iterator iterator = monitors.values().iterator(); iterator.hasNext();)
168         {
169             holder = (ExpirableHolder) iterator.next();
170             removeExpirable(holder.getExpirable());
171             try
172             {
173                 holder.getExpirable().expired();
174             }
175             catch (Exception e)
176             {
177                 // TODO MULE-863: What should we really do?
178                 logger.debug(e.getMessage());
179             }
180         }
181     }
182 
183     private static class ExpirableHolder
184     {
185 
186         private long nanoseconds;
187         private Expirable expirable;
188         private long created;
189 
190         public ExpirableHolder(long nanoseconds, Expirable expirable)
191         {
192             this.nanoseconds = nanoseconds;
193             this.expirable = expirable;
194             created = System.nanoTime();
195         }
196 
197         public long getNanoSeconds()
198         {
199             return nanoseconds;
200         }
201 
202         public Expirable getExpirable()
203         {
204             return expirable;
205         }
206 
207         public boolean isExpired()
208         {
209             return (System.nanoTime() - nanoseconds) > created;
210         }
211 
212         public void reset()
213         {
214             created = System.nanoTime();
215         }
216     }
217 }