Mark,

Thank you for taking the lead on this. Comments in line.

At 22:24 28.05.2002 -0700, [EMAIL PROTECTED] wrote:

>1) The purpose of the reconfigurator is to primarily "watch" or "monitor" a
>"source" for some indication that said "source" has been changed or updated
>with new/different configuration data.

>2) Once the change in state has been detected, the reconfigurator is
>implemented and configured with enough information to reconfigure log4j
>using the new/updated configuration data.

>3) The reconfigurator implementation does not deal with the specific format
>of the configuration data or even the specific reconfiguration of log4j.  It
>delegates this responsibility to the Configurator class, where it belongs.
>This means that the reconfigurator design should support any Configurator
>implementation.  The most the reconfigurator knows about the source of the
>new configuration data is how to locate it and hand it off to the
>Configurator.
>
>4) The reconfigurator design should provide for better control over when a
>reconfigurator is active and allows for reconfigurators to be stopped and
>even restarted.

Yes on all 4 accounts. :-)

[snip]

>When reviewing this design and code, it might be useful to keep the
>following items in mind:
>
>1) How easy would it be for a developer to pick up the interface and/or base
>class and use it to develop their own reconfigurator?  Does the base class
>help or hinder in this regard?
>2) Knowing that allowing reconfigurators to be created/started within
>settings in a configuration file, does this design lend itself to this goal?
>Should the current set of active reconfigurators "live" in a known location?
>Where would this location be?  How can this be strictly enforced?
>3) Is Reconfigurator the right name for this functionality?

How about "Scout" or "ScriptScout"? A ScriptScout scouts for changes
in configuration scripts. Scout is both a noun and a verb, so method
names like startScouting or stopScouting make sense.

I propose ScriptScout as the interface name and ScriptScoutBase as the
base class implemented by FileScout, HTTPScout, SocketScout
subclasses.

>Watchdog.java----------------------------------------------

[snip]

No comments on the interface. It looks complete and perfectly reasonable.


>WatchdogBase.java----------------------------------------------
>
>/**

[snip]

>   @author Mark Womack
>*/
>public abstract class WatchdogBase implements Watchdog, Runnable {
>
>   /**
>     The thread running this watchdog. */
>   protected Thread watchdogThread;
>
>   /**
>     True if this watchdog is running. */
>   private boolean running = false;
>
>   /**
>     The name of this watchdog. */
>   protected String name;
>
>   /**
>     The class name of the configurator to use when reconfigurating. */
>   protected String configuratorClassName;
>
>   /**
>     Returns true if this watchdog is currently running. */
>   public
>   synchronized
>   boolean isRunning() {
>     return running;
>   }
>
>   /**
>      Set the name of this watchdog. The name is used by other
>      components to identify this watchdog. */
>   public
>   void setName(String _name) {
>     name = _name;
>   }
>
>   /**
>      Get the name of this watchdog. The name uniquely identifies the
>      watchdog.  */
>   public
>   String getName() {
>     return name;
>   }
>
>   /**
>     Sets the configurator class used for reconfiguration. */
>   public
>   void setConfigurator(String _configuratorClassName) {
>     configuratorClassName = _configuratorClassName;
>   }
>
>   /**
>     Gets the configurator class used for reconfiguration. */
>   public
>   String getConfigurator() {
>     return configuratorClassName;
>   }
>
>   /**
>     Starts this watchdog. After calling this method the
>     watchdog will be active. */
>   public
>   synchronized
>   void startWatching() {
>     // if not already running
>     if (!running) {
>       // create a thread to run this
>       watchdogThread = new Thread(this);
>
>       // setup the thread
>       watchdogThread.setName(this.name);
>       watchdogThread.setDaemon(true);
>
>       LogLog.debug(this.getName() + " watchdog starting");
>
>       // start the thread
>       running = true;
>       watchdogThread.start();
>     }
>   }
>
>   /**
>     Stops this watchdog. After calling this method the
>     watchdog will become inactive, but it is not guaranteed
>     to be immediately inactive. It may take time for the
>     thread to be interupted and exited. */
>   public
>   synchronized
>   void stopWatching() {
>     // if already running
>     if (running) {
>       LogLog.debug(this.getName() + " watchdog stopping");
>
>       // indicate we are no longer supposed to run
>       running = false;
>
>       // interrupt the thread if it is sleeping
>       watchdogThread.interrupt();

The Thread.interrupt() method is evil. It is also absolutely useless
except for indulging in excruciatingly complex interrupt/notify race
conditions. Thread.interrupt() makes it unnecessarily complicated to
write robust multi-threaded code.  As you might except, log4j does not
contain any Thread.interrupt() method calls.

See for example:

http://www.profcon.com/cargill/jgf/9805/threadingIssues.html
http://elvis.rowan.edu/~hartley/SIGCSE/Workshop/raceConditions.html

In his book "Concurrent Programming", Stephen Hartley a Computer
Science professor gives an example of a Semaphore implemented in Java
using monitors. His implementation contains a interrupt/notify related
race condition. It will take him another 4 iterations until he gets it
right (after the book is published) that is until someone finds a bug
in the 4th iteration.

For more info on the book see:

    http://www.mcs.drexel.edu/~shartley/ConcProgJava/

It's a good book by the way. If the Thread.interrupt method gives an
Computer Science professor and an expert in the field such hard time, I
don't think we should attempt to be "smart". Thread.interrupt is not
needed. Nice and simple. End of story.

Just remove the "watchdogThread.interrupt();" statement and your code
will continue to run just as well.

>       // lose the reference to this thread for gc
>       watchdogThread = null;
>     }
>   }
>
>   /**
>     Implementation required by the Runnable interface.  Calls the
>     setup() method, then enters a loop that will run until the
>     boolean member running becomes false.  The loop calls the
>     checkForReconfiguration() method, and if this method returns
>     true, the reconfigure() method is called. When this loop is
>     exited, the cleanup() method is called before this method
>     is exited. */
>   public
>   void run()
>
>     try {
>       // setup before starting loop
>       setup();
>
>       LogLog.debug(this.getName() + " watchdog now active");
>
>       // while we are supposed to be running
>       while (isRunning()) {
>
>         // check for new reconfiguration data
>         if (checkForReconfiguration() && isRunning()) {
>
>           LogLog.debug(this.getName() + " watchdog reconfiguring");
>
>           reconfigure();
>         }
>       }
>     }

You might want to modify the loop as follows:

   while(isRunning()) {
     if(reconfigurationNeeded()) {
        reconfigure();
     }
     delay();
   }

I renamed checkForReconfiguration as reconfigurationNeeded. The
isRunning check in the if statement is correct but not absolutely
required.  The delay method allows a subclass to introduce a delay if
it needs to have a delay, e.g. FileScout, HTTPScout but not
SocketScout.


>     finally
>
>       // cleanup after finishing loop
>       cleanup();
>     }
>
>     LogLog.debug(this.name + " watchdog now inactive");
>   }

[snip]


--
Ceki

SUICIDE BOMBING - A CRIME AGAINST HUMANITY
Sign the petition: http://www.petitiononline.com/1234567b
I am signer number 22106. What is your number?


--
To unsubscribe, e-mail:   <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>

Reply via email to