/* * Copyright (C) 2012, Katy Hilgenberg. * Special acknowledgments to: Knowledge & Data Engineering Group, University of Kassel (http://www.kde.cs.uni-kassel.de). * Contact: sdcf@cs.uni-kassel.de * * This file is part of the SDCFramework (Sensor Data Collection Framework) project. * * The SDCFramework is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * The SDCFramework is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with the SDCFramework. If not, see <http://www.gnu.org/licenses/>. */ package de.unikassel.android.sdcframework.util; import java.util.concurrent.atomic.AtomicBoolean; import de.unikassel.android.sdcframework.util.facade.WorkerThread; /** * Abstract base class for any thread in the SDC Framework. <br/> * <br/> * Does provide the following features: * <ul> * <li>can be used to execute cyclic work by implementing the protected method * {@linkplain #doWork()},</li> * <li>will be started by calling {@linkplain #startWork()},</li> * <li>work execution can be paused by calling {@linkplain #stopWork()},</li> * <li>will run as long as {@linkplain #doTerminate()} is not explicitly called. * </li> * </ul> * * @author Katy Hilgenberg * */ public abstract class AbstractWorkerThread extends Thread implements WorkerThread { /** * The new created state flag */ private final AtomicBoolean isNew; /** * The terminated state flag */ private final AtomicBoolean hasTerminated; /** * The isWorking state flag */ private final AtomicBoolean isWorking; /** * The logging state flag */ private final AtomicBoolean doLog; /** * Synchronization lock */ private final Object syncLock; /** * Constructor * */ public AbstractWorkerThread() { super(); isNew = new AtomicBoolean( true ); doLog = new AtomicBoolean( true ); hasTerminated = new AtomicBoolean( false ); isWorking = new AtomicBoolean( false ); syncLock = new Object(); setDaemon( true ); } /* * (non-Javadoc) * * @see de.unikassel.android.sdcframework.util.WorkerThread#isWorking() */ @Override public final boolean isWorking() { return this.isWorking.get(); } /* * (non-Javadoc) * * @see * de.unikassel.android.sdcframework.util.WorkerThread#setLogging(boolean) */ @Override public final void setLogging( boolean doLog ) { this.doLog.set( doLog ); } /* * (non-Javadoc) * * @see de.unikassel.android.sdcframework.util.facade.WorkerThread#isLogging() */ @Override public final boolean isLogging() { return doLog.get(); } /* * (non-Javadoc) * * @see de.unikassel.android.sdcframework.util.WorkerThread#hasTerminated() */ @Override public final boolean hasTerminated() { return hasTerminated.get(); } /* * (non-Javadoc) * * @see java.lang.Thread#start() */ @Override public final synchronized void start() { if ( isNew.compareAndSet( true, false ) ) { super.start(); } } /* * (non-Javadoc) * * @see java.lang.Thread#run() */ @Override public final void run() { super.run(); while ( !hasTerminated() ) { try { if ( isWorking() ) { // next working cycle doWork(); } else { synchronized ( syncLock ) { // non busy wait for work state change syncLock.wait(); } } } catch ( InterruptedException e ) {} catch ( Exception e ) { if ( isLogging() ) Logger.getInstance().error( this, " Unexpected exception caught: " + e ); e.printStackTrace(); } } stopWork(); doCleanUp(); } /* * (non-Javadoc) * * @see de.unikassel.android.sdcframework.util.WorkerThread#startWork() */ @Override public final synchronized void startWork() { if ( !hasTerminated() ) { // safe test and set working state flag if ( isWorking.compareAndSet( false, true ) ) { // if thread wasn't started yet or is sleeping -> switch to running doRun(); logMessage( " started " ); } } } /** * Does send the thread into running mode either by starting it if not alive * or by waking a sleeping thread up. */ private final void doRun() { if ( isNew.get() ) { // start a new thread start(); } else { // wake up stopped thread synchronized ( syncLock ) { syncLock.notifyAll(); } } } /* * (non-Javadoc) * * @see de.unikassel.android.sdcframework.util.WorkerThread#stopWork() */ @Override public final synchronized void stopWork() { if ( isWorking.compareAndSet( true, false ) ) { interrupt(); logMessage( " stopped" ); } } /* * (non-Javadoc) * * @see de.unikassel.android.sdcframework.util.WorkerThread#doTerminate() */ @Override public final synchronized void doTerminate() { // secure check and set flag for termination state if ( hasTerminated.compareAndSet( false, true ) ) { // assure not working thread will become alive in run loop // to terminated interrupt(); // start a new thread for initial termination if ( isNew.get() ) { // start a new thread start(); } // with termination flag set it will terminate now! logMessage( " terminating" ); } } /** * Does log a message if logging is enabled * * @param message * the message to log */ protected final void logMessage( String message ) { if ( isLogging() ) Logger.getInstance().info( this, message ); } /** * The clean up method executed on termination */ protected abstract void doCleanUp(); /** * The working method executed in the running loop if started */ protected abstract void doWork(); }