View Javadoc

1   /*
2    * $Id: ExpiryMonitor.java 12269 2008-07-10 04:19:03Z dfeist $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSource, Inc.  All rights reserved.  http://www.mulesource.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 edu.emory.mathcs.backport.java.util.concurrent.helpers.Utils;
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      public ExpiryMonitor(String name)
48      {
49          this(name, 1000);
50      }
51  
52      public ExpiryMonitor(String name, int monitorFrequency)
53      {
54          this.name = name;
55          this.monitorFrequency = monitorFrequency;
56          init();
57      }
58  
59      public ExpiryMonitor(String name, int monitorFrequency, ScheduledThreadPoolExecutor scheduler)
60      {
61          this.name = name;
62          this.monitorFrequency = monitorFrequency;
63          this.scheduler = scheduler;
64          init();
65      }
66  
67      protected void init()
68      {
69          if (monitorFrequency <= 0)
70          {
71              throw new IllegalArgumentException(CoreMessages.propertyHasInvalidValue("monitorFrequency",
72                      new Integer(monitorFrequency)).toString());
73          }
74          monitors = new ConcurrentHashMap();
75          if (scheduler == null)
76          {
77              this.scheduler = new ScheduledThreadPoolExecutor(1);
78              scheduler.setThreadFactory(new DaemonThreadFactory(name + "-Monitor"));
79              scheduler.scheduleWithFixedDelay(this, 0, monitorFrequency,
80                      TimeUnit.MILLISECONDS);
81          }
82      }
83  
84      /**
85       * Adds an expirable object to monitor. If the Object is already being monitored
86       * it will be reset and the millisecond timeout will be ignored
87       *
88       * @param value     the expiry value
89       * @param timeUnit  The time unit of the Expiry value
90       * @param expirable the objec that will expire
91       */
92      public void addExpirable(long value, TimeUnit timeUnit, Expirable expirable)
93      {
94          if (isRegistered(expirable))
95          {
96              resetExpirable(expirable);
97          }
98          else
99          {
100             if (logger.isDebugEnabled())
101             {
102                 logger.debug("Adding new expirable: " + expirable);
103             }
104             monitors.put(expirable, new ExpirableHolder(timeUnit.toNanos(value), expirable));
105         }
106     }
107 
108     public boolean isRegistered(Expirable expirable)
109     {
110         return (monitors.get(expirable) != null);
111     }
112 
113     public void removeExpirable(Expirable expirable)
114     {
115         if (logger.isDebugEnabled())
116         {
117             logger.debug("Removing expirable: " + expirable);
118         }
119         monitors.remove(expirable);
120     }
121 
122     public void resetExpirable(Expirable expirable)
123     {
124         ExpirableHolder eh = (ExpirableHolder) monitors.get(expirable);
125         if (eh != null)
126         {
127             eh.reset();
128             if (logger.isDebugEnabled())
129             {
130                 logger.debug("Reset expirable: " + expirable);
131             }
132         }
133     }
134 
135     /**
136      * The action to be performed by this timer task.
137      */
138     public void run()
139     {
140         ExpirableHolder holder;
141         for (Iterator iterator = monitors.values().iterator(); iterator.hasNext();)
142         {
143             holder = (ExpirableHolder) iterator.next();
144             if (holder.isExpired())
145             {
146                 removeExpirable(holder.getExpirable());
147                 holder.getExpirable().expired();
148             }
149         }
150     }
151 
152     public void dispose()
153     {
154         logger.info("disposing monitor");
155         scheduler.shutdown();
156         ExpirableHolder holder;
157         for (Iterator iterator = monitors.values().iterator(); iterator.hasNext();)
158         {
159             holder = (ExpirableHolder) iterator.next();
160             removeExpirable(holder.getExpirable());
161             try
162             {
163                 holder.getExpirable().expired();
164             }
165             catch (Exception e)
166             {
167                 // TODO MULE-863: What should we really do?
168                 logger.debug(e.getMessage());
169             }
170         }
171     }
172 
173     private static class ExpirableHolder
174     {
175 
176         private long nanoseconds;
177         private Expirable expirable;
178         private long created;
179 
180         public ExpirableHolder(long nanoseconds, Expirable expirable)
181         {
182             this.nanoseconds = nanoseconds;
183             this.expirable = expirable;
184             created = Utils.nanoTime();
185         }
186 
187         public long getNanoSeconds()
188         {
189             return nanoseconds;
190         }
191 
192         public Expirable getExpirable()
193         {
194             return expirable;
195         }
196 
197         public boolean isExpired()
198         {
199             return (Utils.nanoTime() - nanoseconds) > created;
200         }
201 
202         public void reset()
203         {
204             created = Utils.nanoTime();
205         }
206     }
207 }