View Javadoc
1   package org.apache.commons.jcs3.auxiliary;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.util.concurrent.atomic.AtomicBoolean;
23  import java.util.concurrent.locks.Condition;
24  import java.util.concurrent.locks.Lock;
25  import java.util.concurrent.locks.ReentrantLock;
26  
27  import org.apache.commons.jcs3.log.Log;
28  import org.apache.commons.jcs3.log.LogManager;
29  
30  /**
31   * Used to monitor and repair any failed connection for the lateral cache service. By default the
32   * monitor operates in a failure driven mode. That is, it goes into a wait state until there is an
33   * error. Upon the notification of a connection error, the monitor changes to operate in a time
34   * driven mode. That is, it attempts to recover the connections on a periodic basis. When all failed
35   * connections are restored, it changes back to the failure driven mode.
36   */
37  public abstract class AbstractAuxiliaryCacheMonitor extends Thread
38  {
39      /** The logger */
40      protected final Log log = LogManager.getLog( this.getClass() );
41  
42      /** How long to wait between runs */
43      protected static long idlePeriod = 20 * 1000;
44  
45      /**
46       * Must make sure AbstractAuxiliaryCacheMonitor is started before any error can be detected!
47       */
48      protected AtomicBoolean allright = new AtomicBoolean(true);
49  
50      /**
51       * shutdown flag
52       */
53      private final AtomicBoolean shutdown = new AtomicBoolean(false);
54  
55      /** Synchronization helper lock */
56      private final Lock lock = new ReentrantLock();
57  
58      /** Synchronization helper condition */
59      private final Condition trigger = lock.newCondition();
60  
61      /**
62       * Constructor
63       *
64       * @param name the thread name
65       */
66      public AbstractAuxiliaryCacheMonitor(final String name)
67      {
68          super(name);
69      }
70  
71      /**
72       * Configures the idle period between repairs.
73       * <p>
74       * @param idlePeriod The new idlePeriod value
75       */
76      public static void setIdlePeriod( final long idlePeriod )
77      {
78          if ( idlePeriod > AbstractAuxiliaryCacheMonitor.idlePeriod )
79          {
80              AbstractAuxiliaryCacheMonitor.idlePeriod = idlePeriod;
81          }
82      }
83  
84      /**
85       * Notifies the cache monitor that an error occurred, and kicks off the error recovery process.
86       */
87      public void notifyError()
88      {
89          if (allright.compareAndSet(true, false))
90          {
91              signalTrigger();
92          }
93      }
94  
95      /**
96       * Notifies the cache monitor that the service shall shut down
97       */
98      public void notifyShutdown()
99      {
100         if (shutdown.compareAndSet(false, true))
101         {
102             signalTrigger();
103         }
104     }
105 
106     // Trigger continuation of loop
107     private void signalTrigger()
108     {
109         try
110         {
111             lock.lock();
112             trigger.signal();
113         }
114         finally
115         {
116             lock.unlock();
117         }
118     }
119 
120     /**
121      * Clean up all resources before shutdown
122      */
123     protected abstract void dispose();
124 
125     /**
126      * do actual work
127      */
128     protected abstract void doWork();
129 
130     /**
131      * Main processing method for the AbstractAuxiliaryCacheMonitor object
132      */
133     @Override
134     public void run()
135     {
136         do
137         {
138             if ( allright.get() )
139             {
140                 log.debug( "ERROR DRIVEN MODE: allright = true, cache monitor will wait for an error." );
141             }
142             else
143             {
144                 log.debug( "ERROR DRIVEN MODE: allright = false cache monitor running." );
145             }
146 
147             if ( allright.get() )
148             {
149                 // Failure driven mode.
150                 try
151                 {
152                     lock.lock();
153                     trigger.await();
154                     // wake up only if there is an error.
155                 }
156                 catch ( final InterruptedException ignore )
157                 {
158                     //no op, this is expected
159                 }
160                 finally
161                 {
162                     lock.unlock();
163                 }
164             }
165 
166             // check for requested shutdown
167             if ( shutdown.get() )
168             {
169                 log.info( "Shutting down cache monitor" );
170                 dispose();
171                 return;
172             }
173 
174             // The "allright" flag must be false here.
175             // Simply presume we can fix all the errors until proven otherwise.
176             allright.set(true);
177 
178             log.debug( "Cache monitor running." );
179 
180             doWork();
181 
182             try
183             {
184                 // don't want to sleep after waking from an error
185                 // run immediately and sleep here.
186                 log.debug( "Cache monitor sleeping for {0} between runs.", idlePeriod );
187 
188                 Thread.sleep( idlePeriod );
189             }
190             catch ( final InterruptedException ex )
191             {
192                 // ignore;
193             }
194         }
195         while ( true );
196     }
197 }