001package org.apache.commons.jcs3.auxiliary;
002
003/*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements.  See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership.  The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License.  You may obtain a copy of the License at
011 *
012 *   http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied.  See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022import java.util.concurrent.atomic.AtomicBoolean;
023import java.util.concurrent.locks.Condition;
024import java.util.concurrent.locks.Lock;
025import java.util.concurrent.locks.ReentrantLock;
026
027import org.apache.commons.jcs3.log.Log;
028import org.apache.commons.jcs3.log.LogManager;
029
030/**
031 * Used to monitor and repair any failed connection for the lateral cache service. By default the
032 * monitor operates in a failure driven mode. That is, it goes into a wait state until there is an
033 * error. Upon the notification of a connection error, the monitor changes to operate in a time
034 * driven mode. That is, it attempts to recover the connections on a periodic basis. When all failed
035 * connections are restored, it changes back to the failure driven mode.
036 */
037public abstract class AbstractAuxiliaryCacheMonitor extends Thread
038{
039    /** The logger */
040    protected final Log log = LogManager.getLog( this.getClass() );
041
042    /** How long to wait between runs */
043    protected static long idlePeriod = 20 * 1000;
044
045    /**
046     * Must make sure AbstractAuxiliaryCacheMonitor is started before any error can be detected!
047     */
048    protected AtomicBoolean allright = new AtomicBoolean(true);
049
050    /**
051     * shutdown flag
052     */
053    private final AtomicBoolean shutdown = new AtomicBoolean(false);
054
055    /** Synchronization helper lock */
056    private final Lock lock = new ReentrantLock();
057
058    /** Synchronization helper condition */
059    private final Condition trigger = lock.newCondition();
060
061    /**
062     * Constructor
063     *
064     * @param name the thread name
065     */
066    public AbstractAuxiliaryCacheMonitor(final String name)
067    {
068        super(name);
069    }
070
071    /**
072     * Configures the idle period between repairs.
073     * <p>
074     * @param idlePeriod The new idlePeriod value
075     */
076    public static void setIdlePeriod( final long idlePeriod )
077    {
078        if ( idlePeriod > AbstractAuxiliaryCacheMonitor.idlePeriod )
079        {
080            AbstractAuxiliaryCacheMonitor.idlePeriod = idlePeriod;
081        }
082    }
083
084    /**
085     * Notifies the cache monitor that an error occurred, and kicks off the error recovery process.
086     */
087    public void notifyError()
088    {
089        if (allright.compareAndSet(true, false))
090        {
091            signalTrigger();
092        }
093    }
094
095    /**
096     * Notifies the cache monitor that the service shall shut down
097     */
098    public void notifyShutdown()
099    {
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}