/* * @(#) src/net/sf/ivmaidns/util/ActivityCore.java -- * Class for active observable entities. ** * Copyright (c) 2000 Ivan Maidanski <ivmai@mail.ru> * All rights reserved. */ /* * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. ** * This software 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 * General Public License (GPL) for more details. ** * Linking this library statically or dynamically with other modules is * making a combined work based on this library. Thus, the terms and * conditions of the GNU General Public License cover the whole * combination. ** * As a special exception, the copyright holders of this library give you * permission to link this library with independent modules to produce an * executable, regardless of the license terms of these independent * modules, and to copy and distribute the resulting executable under * terms of your choice, provided that you also meet, for each linked * independent module, the terms and conditions of the license of that * module. An independent module is a module which is not derived from * or based on this library. If you modify this library, you may extend * this exception to your version of the library, but you are not * obligated to do so. If you do not wish to do so, delete this * exception statement from your version. */ package net.sf.ivmaidns.util; /** * Class for active observable entities. ** * This is a basis implementation of <CODE>SafeRunnable</CODE> * interface, which also extends <CODE>ObservedCore</CODE> class, * providing an easy way to create a custom active observable * object, which starts running on its creation and stops when done * or when safe stop is requested by the user of the object (or when * Java Virtual Machine terminates). Active objects may be also * interrupted, suspended and resumed. The activity of such object * is implemented through the encapsulation of <CODE>Thread</CODE> * instance. Created <VAR>thread</VAR> is not daemon (unless current * thread is a daemon). Important notes: the Java Virtual Machine * exits when the only threads running are all daemons or if * <CODE>exit(int)</CODE> method of <CODE>Runtime</CODE> class is * called; <CODE>Runnable</CODE> interface is implemented here * entirely for the internal purpose. ** * @version 2.0 * @author Ivan Maidanski */ public abstract class ActivityCore extends ObservedCore implements SafeRunnable, Runnable { /** * Represents the default idle sleep time in milliseconds. ** * This <CODE>int</CODE> (positive) value is used as a default * argument for <CODE>wait(long)</CODE> of <CODE>Object</CODE> class * and for <CODE>sleep(long)</CODE> of <CODE>Thread</CODE> class * when infinitely waiting for a particular event. ** * @since 2.0 */ protected static final int IDLE_SLEEP_MILLIS = 1000; /** * Indicates whether or not <CODE>run()</CODE> method is called. ** * This internal flag is used only to ensure that <CODE>run()</CODE> * is called only once. The flag is trigged only once. ** * @see #run() */ private boolean initiated; /** * Indicates whether or not safe suspending is requested for * <CODE>this</CODE> active object. ** * This internal flag is used only to safely process the user * intention to temporarily suspend running of <CODE>this</CODE> * active object. Clearing of this flag means running is immediately * resumed. ** * @see #run() * @see #suspend() * @see #waitSuspend() * @see #resume() */ private boolean suspending; /** * Indicates whether or not <CODE>this</CODE> object is safely * suspended. ** * This flag may be checked via <CODE>isSuspended()</CODE>. ** * @see #run() * @see #waitSuspend() * @see #resume() * @see #isSuspended() */ private boolean suspended; /** * Indicates whether or not safe stop is requested for * <CODE>this</CODE> active object. ** * This internal flag is used only to safely process the user * intention to terminate (abort) running of <CODE>this</CODE> * active object. The flag is never trigged or trigged only once. ** * @see #run() * @see #stop() * @see #join() * @see #isAlive() */ private boolean stopping; /** * The encapsulated <CODE>Thread</CODE> instance for * <CODE>this</CODE> active object. ** * <VAR>thread</VAR> (must be non-<CODE>null</CODE>) is started in * the constructor. The target of this thread is <CODE>run()</CODE> * method of this class. <VAR>thread</VAR> is not accessible outside * the class (even for the subclasses of it). ** * @see ActivityCore#ActivityCore(java.lang.String) * @see #run() */ private final Thread thread; /** * Constructs an active observable object with the specified thread * name. ** * Created <VAR>thread</VAR> is marked as a daemon only if current * thread is a daemon. The thread is started (activated) just after * its creation. The user of <CODE>this</CODE> constructed object * may safely suspend/resume or stop its activity at any time (while * it is running). <VAR>name</VAR> is entirely used to identify the * thread in the computer system (for the purpose of the system * performance monitoring). ** * @param name * the name (must be non-<CODE>null</CODE>) of created * <VAR>thread</VAR>. * @exception NullPointerException * if <VAR>name</VAR> is <CODE>null</CODE>. * @exception OutOfMemoryError * if there is not enough memory. * @exception InternalError * if Java VM internal error occurs or if the security manager * prohibits the creation of a new thread. ** * @see #run() * @see #stop() * @see #join() * @see #isAlive() */ public ActivityCore(String name) throws NullPointerException { name.equals(name); try { (this.thread = new Thread(this, name)).start(); } catch (SecurityException e) { throw new InternalError("SecurityException: new Thread()"); } name = null; } /** * Custom initialization method which is executed just at the * beginning of the execution of <CODE>this</CODE> active object. ** * This method is only called internally once (in the encapsulated * thread, not in the constructor) before calling * <CODE>loop()</CODE>. If <CODE>OutOfMemoryError</CODE> is thrown * then <CODE>loop()</CODE> is skipped and <CODE>done()</CODE> is * called. This method should be <CODE>protected final</CODE> in the * subclasses if overridden (if not overridden then it is dummy). ** * @exception OutOfMemoryError * if there is not enough memory. ** * @see ActivityCore#ActivityCore(java.lang.String) * @see #loop() * @see #done() * @see #run() */ protected void init() {} /** * Custom action main method which is executed in <CODE>this</CODE> * active object as many times as needed. ** * This method is only called internally (in the encapsulated * thread) many times (may be none) while soft stop is not requested * and result is <CODE>true</CODE>. If <CODE>OutOfMemoryError</CODE> * is thrown then <CODE>loop()</CODE> is not called anymore and * <CODE>done()</CODE> is called. This method should be * <CODE>protected final</CODE> in the subclasses. ** * @return * <CODE>true</CODE> only if this method requests to be called * again. * @exception OutOfMemoryError * if there is not enough memory. ** * @see #init() * @see #done() * @see #run() * @see #stop() */ protected abstract boolean loop(); /** * Custom clean-up method which is executed before normal * termination of <CODE>this</CODE> active object. ** * This method is called internally once (in the encapsulated * thread) at the end after calling <CODE>loop()</CODE> method. This * method is called even if soft stop operation is being performed * or even if <CODE>loop()</CODE> (or <CODE>init()</CODE>) method * has just thrown <CODE>OutOfMemoryError</CODE>. If this method * throws <CODE>OutOfMemoryError</CODE> then it is caught silently. * This method should be <CODE>protected final</CODE> in the * subclasses if overridden (if not overridden then it is dummy). ** * @exception OutOfMemoryError * if there is not enough memory. ** * @see #init() * @see #loop() * @see #run() * @see #stop() */ protected void done() {} /** * The thread execution body (an internal method). ** * This method is called internally (only once) by * <CODE>Thread</CODE> object when <VAR>thread</VAR> of * <CODE>this</CODE> is initialized (when <CODE>this</CODE> active * object is constructed). This method first calls * <CODE>init()</CODE> method then calls <CODE>loop()</CODE> many * times while it returns <CODE>true</CODE>, then calls * <CODE>done()</CODE> (semantics of all these three methods is * defined by the subclass), and returns. Each time, before calling * <CODE>loop()</CODE>, this method analyses the state of * <VAR>suspending</VAR> and <VAR>stopping</VAR> to perform safe * suspend/resume and stop operations whenever they are requested by * the user of <CODE>this</CODE> active object. If * <VAR>suspending</VAR> is set then this method waits (before * calling <CODE>loop()</CODE>) while <VAR>suspending</VAR> remains * set. Setting of <VAR>stopping</VAR> would stop looping, this * method calls <CODE>done()</CODE> and returns. If * <CODE>OutOfMemoryError</CODE> is thrown during execution of these * 'init/loop/done' methods then it is silently ignored and has the * same effect as if <VAR>stopping</VAR> is <CODE>true</CODE>. * Important notes: on return of this method <VAR>thread</VAR> is * terminated; if this method is called outside <CODE>Thread</CODE> * then it does nothing. ** * @see ActivityCore#ActivityCore(java.lang.String) * @see #suspend() * @see #waitSuspend() * @see #resume() * @see #stop() */ public final void run() { Thread thread; boolean stopping; synchronized (thread = this.thread) { stopping = this.initiated; this.initiated = true; } if (!stopping) { try { init(); do { if (!(stopping = this.stopping)) if (!this.suspending) { try { Thread.sleep(0); } catch (InterruptedException e) {} } else synchronized (thread) { if (this.suspending) { this.suspended = true; thread.notifyAll(); do { try { thread.wait(IDLE_SLEEP_MILLIS); } catch (InterruptedException e) {} } while (this.suspending); this.suspended = false; } stopping = this.stopping; } } while (!stopping && loop()); } catch (OutOfMemoryError e) {} try { done(); } catch (OutOfMemoryError e) {} } thread = null; } /** * Frees extra memory. ** * This method re-allocates internal structures (of the object) * releasing unused memory occupied by them. This method must be * synchronized outside. ** * @see ActivityCore#ActivityCore(java.lang.String) */ public void trimToSize() { super.trimToSize(); } /** * Interrupts sleeping or waiting inside active object. ** * Interruption means sending a special <VAR>interrupt</VAR> signal * to each thread of active object (resulting in throwing of * <CODE>InterruptedException</CODE> inside thread when it is * waiting or sleeping). This method returns immediately. This * method may be overridden in the subclasses. Important notes: * current thread interruption status may be cleared via * <CODE>sleep(0)</CODE> of <CODE>Thread</CODE> class. ** * @see #isAlive() */ public void interrupt() { Thread thread = this.thread; try { thread.interrupt(); } catch (SecurityException e) {} thread = null; } /** * Initiates safe suspend operation. ** * This method just sets <VAR>suspending</VAR> flag which signals * active object that all its threads (only which are alive) must be * safely suspended (turned to sleeping state) as soon as possible. * This method returns immediately. This method may be overridden in * the subclasses. ** * @see #waitSuspend() * @see #resume() * @see #isSuspended() * @see #stop() */ public void suspend() { this.suspending = true; } /** * Initiates and waits for safe suspend. ** * This method sets <VAR>suspending</VAR> flag which signals active * object that all its threads (only which are alive) must be safely * suspended (turned to sleeping state) as soon as possible. This * method returns just after all threads of active object have been * suspended (or died). This method may be overridden in the * subclasses. ** * @see #suspend() * @see #resume() * @see #isSuspended() */ public void waitSuspend() { Thread thread; synchronized (thread = this.thread) { this.suspending = true; while (!this.suspended && thread.isAlive()) { try { thread.wait(IDLE_SLEEP_MILLIS); } catch (InterruptedException e) {} } } thread = null; } /** * Resumes running after suspend. ** * This method clears <VAR>suspending</VAR> flag, thus telling * active object to resume normal running (stop sleeping) after safe * suspend for all its still alive threads. This method returns * immediately. ** * @see #suspend() * @see #waitSuspend() * @see #isSuspended() */ public final void resume() { Thread thread; synchronized (thread = this.thread) { this.suspending = false; if (this.suspended && thread.isAlive()) thread.notifyAll(); } thread = null; } /** * Initiates safe stop operation. ** * This method just sets <VAR>stopping</VAR> flag which signals * active object that all its threads (only which are alive) must be * safely terminated (stopped) as soon as possible. This method * returns immediately. If active object is suspended then safe stop * operation begins just when resuming. This method may be * overridden in the subclasses. ** * @see #suspend() * @see #resume() * @see #join() * @see #isSuspended() * @see #isAlive() */ public void stop() { this.stopping = true; } /** * Waits while active object is alive. ** * This method infinitely waits for the death (termination) of all * threads inside this active object. ** * @see #stop() * @see #isAlive() * @see #waitSuspend() */ public final void join() { Thread thread; synchronized (thread = this.thread) { while (thread.isAlive()) { try { thread.wait(IDLE_SLEEP_MILLIS); } catch (InterruptedException e) {} } } thread = null; } /** * Tests whether this active object is suspended. ** * This method just immediately returns <VAR>suspended</VAR> flag * which is true only when active object is in safe-suspend state * (and alive). ** * @return * <CODE>true</CODE> if and only if active object is suspended. ** * @see #suspend() * @see #waitSuspend() * @see #resume() * @see #isAlive() */ public final boolean isSuspended() { boolean suspended; synchronized (this.thread) { suspended = this.suspended; } return suspended; } /** * Tests whether this active object is still alive. ** * This method just immediately returns the flag indicating that one * or more threads (inside this active object) have not died yet. ** * @return * <CODE>true</CODE> if and only if active object is alive. ** * @see #stop() * @see #join() * @see #isSuspended() */ public final boolean isAlive() { return this.thread.isAlive(); } /** * Creates and returns a copy of <CODE>this</CODE> object. ** * The implementation of this method prohibits (since thread object * is not cloneable) the usage of standard <CODE>clone()</CODE> * method of <CODE>Object</CODE> (even in the subclasses) by * throwing <CODE>CloneNotSupportedException</CODE>. But, if needed, * this method may be overridden (and made <CODE>public</CODE>) in * the subclasses, providing 'pseudo-cloning' (through the * constructor of a subclass). ** * @return * a copy (not <CODE>null</CODE> and != <CODE>this</CODE>) of * <CODE>this</CODE> instance. * @exception CloneNotSupportedException * if cloning is not implemented. * @exception OutOfMemoryError * if there is not enough memory. ** * @since 1.1 */ protected Object clone() throws CloneNotSupportedException { throw new CloneNotSupportedException(); } /** * Verifies <CODE>this</CODE> object for its integrity. ** * For debug purpose only. ** * @exception InternalError * if integrity violation is detected. ** * @since 2.0 */ public void integrityCheck() { super.integrityCheck(); if (this.thread == null) throw new InternalError("thread: null"); } }