View Javadoc

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