You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@avalon.apache.org by Leo Simons <le...@apache.org> on 2003/10/08 23:10:59 UTC

seperation of concerns applied: Thread Management

okay, had an itch to scratch here and some time on my hands. Here's an 
essay:

===========
The Problem
===========
Steve wrote:
 > I think the real underlying issue here is component/container
 > responsibility. Who should be creating and supervising/monitoring the
 > thread - the component or the container?

In a COP environment, a common question is "Which entity is 
responsibility for a particular function?". Its one of the main 
questions we ask when we do system decomposition.

Lets analyze the problem and work towards a neat solution!

Seperation of Concerns
----------------------
The key to solving this problem in a good way is proper seperation of 
concerns. This will allow for a clean and evolvable system, and may even 
provide us with some components that can be reused in another environment.

For example, within avalon, the container is responsible for, at the 
least, component creation, destruction, lifecycle management, dependency 
resolution, configuration, logging, and often management. Components are 
responsible for application logic. This means that the application logic 
in these components is more likely to be reusable in other contexts.

Taking this a little further, a smart container will be built using 
components to which it delegates functionality. There might be a 
component that handles instantiation, another one which handles 
lifecycle management, another one which handles dependency resolution, 
etc. You could build an extensible container this way, where you would 
be able to change facets of its behaviour to make it usable in many 
different problem domains. Yeah!

Back to the problem at hand. What we identify here is several more 
concerns/responsibilities:

1 - thread creation
2 - thread allocation
3 - thread deallocation
4 - thread destruction
5 - thread monitoring
6 - thread-related exception handling

we might make these more fine-grained, or we might group them into a 
single concern dubbed "thread management".

Solution! or not?
-----------------
Okay, got it. Seperate concerns, put system-level concerns in the 
container, specify the relationship between container and component in 
interfaces. Keep components passive (IoC).

A few solutions immediately pop into mind. One of them is to modify 
avalon-framework to specify these concerns, and our container to support 
them. Perhaps something like:

interface ThreadedComponent extends Startable
{
   /**
    * Retrieve the worker. This will then be started in a
    * container-managed thread.
    */
   Runnable getWorker();
   /**
    * Tell the component something bad happened and allow it to recover.
    * After it has, the getWorker() method will be called by the
    * container once more and a new thread will be created.
    */
   void threadProblemOccured( Exception e );
}

this is a bad idea. It requires modification of the core framework 
contracts to support, it requires extensive modification of the 
container, and it does not allow a lot of reuse of thread management 
code across containers and components.

What happened? Well, we got the inversion of control figured out, and we 
seperated concerns (thread creation and management is seperated out from 
the business logic), but it still sucks. But what we forgot was the 
component-oriented programming.

Lets do some IoC/SoC/COP analysis and come up with something better!

========
Analysis
========
The Avalon-Framework contract
-----------------------------
Most components are passive. When you invoke one of their work interface 
methods, they perform a unit of work in the current thread of execution. 
Some components are active. These perform units of work in a seperate 
thread of execution.

In avalon, active components implement the "Startable" interface, and by 
contract they begin their "active" life when the container calls 
start(), and end that life when the container calls stop().

Per the avalon-framework contracts, a component is allowed to deal with 
any of the concerns listed in 1-6 itself in any way it wants. The 
avalon-framework thread management contract is very coarse with regard 
to thread management: it specifies components become active on start() 
and passive on stop().

This is on purpose, and its good, because it allows broad reuse of the 
framework.

It also implies that containers don't concern themselves with any thread 
management concerns.


The Thread-Management contracts
-------------------------------
That is all fine and good, but it seems like a good idea to implement 
all the thread management logic once, and then reuse that for all 
components. Well, sure! That is what COP is all about. Lets identify a 
few contracts (I like code examples, so this is pseudocode):

/** A factory which builds new threads on demand. */
interface ThreadCreator			// concern 1
{
	Thread create( Runnable runnable );
}
/** An 'inverted' factory which destroys threads on demand. */
interface ThreadDestructor		// concern 2
{
	void destroy( Thread thread );
}
/** Provides a thread to a client on demand. */
interface ThreadAllocator		// concern 3
{
	Thread get( Runnable runnable );
}
/** Receives a thread that is no longer required by a client. */
interface ThreadDeallocator		// concern 4
{
	void release( Thread thread );
}
/** Continuously observes a thread and notifies a delegate if anything 
goes wrong with it. */
interface ThreadMonitor			// concern 5
{
	void monitor( Thread thread,
		IllegalThreadStateHandler listener );
}
/** Deals with anything that goes wrong during thread management. */
interface IllegalThreadStateHandler	// concern 6
{
	void handleIllegalThreadState(
		Thread thread, Throwable problem );
}

We've decomposed the "thread management" concern into distinct work 
interfaces. Now, experience shows that this is not particular useful: 
these contracts are too fine-grained. Also, we've not yet exemplified 
the relationships between all these components. What might work better is:

/**
  * Handles thread creation, destruction, allocation, deallocation,
  * monitoring and thread corruption recovery.
  *
  * @avalon.dependency type="ExceptionHandler"
  * @avalon.dependency type="ThreadFactory"
  */
interface ThreadPool
{
	Thread get( Runnable runnable );
	void release( Thread thread );
}
interface ThreadFactory
{
	Thread create( Runnable runnable );
	void destroy( Thread thread );
}
interface ExceptionHandler
{
	void handle( Throwable problem );
}

Now, this is still pretty non-generic. We would like to abstract this 
even further:

/**
  * Handles creation, destruction, allocation, deallocation,
  * monitoring and recovery.
  *
  * @avalon.dependency type="ExceptionHandler"
  * @avalon.dependency type="Factory"
  */
interface Pool
{
	Object get();
	void release( Object object );
}
interface Factory
{
	Object create();
	void destroy( Object object );
}
interface ExceptionHandler
{
	void handle( Throwable problem );
}

this makes the interfaces much more generically reusable, at the cost of 
some classcasts and thus less type safety. For example, we might have 
various pool implementations differing in their management policy, and 
each of these would be capable of managing both Bees and Threads. Also, 
we might have a single global ExceptionHandler that deals with 
everything from out of memory errors to thread corruption (by logging 
them, then calling System.exit(someStatus), perhaps).

However, some annoying person decided that you can't associate and 
re-associate threads with runnables. There are many other ways around 
that, but I'll get to that later.


==============
Implementation
==============
A threaded component
--------------------
Consider a socket server. This is a good example of an active 
server-side component. It might not allow any client components, so its 
work interface could look like:

   /** Listens for socket requests and handles them. */
   interface SocketServer {}

Below is a possible implementation. It uses a single worker thread which 
listens for connections, then delegates those connections to a seperate 
handler. Most actual socket server implementations delegate to a set of 
handlers kept in a pool. A handler looks like:

interface ConnectionHandler	                  // code sketch
{
   public void handle( Socket socket );
}

Here's the socket server implementation:

/** @avalon.component type="SocketServer" */
class ThreadedSocketServer implements SocketServer,
     Servicable, Configurable, Initializable, Startable, Disposable
{
   public final static int DEFAULT_PORT = 80;
   public final static String DEFAULT_ADDRESS = "localhost";
   private int m_port;
   private String m_address;

   private Pool m_threadPool;

   private ServerSocket m_socket;
   private Worker m_worker;
   private thread m_workerThread;
   private ConnectionHandler m_handler;

   public void configure( Configuration conf )
     throws ConfigurationException
   {
     m_port = conf.getChild("port").getValueAsInteger( DEFAULT_PORT );
     m_address = conf.getChild("address").getValue( DEFAULT_ADDRESS );
   }
   /**
    * @avalon.dependency type="Pool"
    * @avalon.dependency type="ConnectionHandler"
    */
   public void service( ServiceManager sm ) throws ServiceException
   {
     m_threadPool = sm.Lookup( Pool.ROLE );
     m_handler = sm.lookup( ConnectionHandler.ROLE );
   }

   public void initialize() throws Exception
   {
     m_socket = getServerSocket();
     m_worker = new Worker();
   }

   public void start() throws Exception
   {
     m_workerThread = (Thread)m_threadPool.get( m_worker );
     m_workerThread.start();
   }

   public void stop()
   {
     m_worker.stop();
     Thread.sleep(100);
     m_workerThread.interrupt();
   }

   public void dispose()
   {
     m_threadPool.release( m_workerThread );
     m_workerThread = null;
   }

   private class Worker implements Runnable
   {
       private boolean running = false;

       public void stop()
       {
         running = false;
       }
       public void run()
       {
         running = true;

         while(running)
         {
           Socket socket = m_socket.accept(); // block
           m_handler.handle( socket ); // delegate

           if(Thread.isInterrupted())
           {
             running = false;
             break; // die
           }
         }
       }
   }
}

Ugly!
-----
There's a substantial amount of thread management code in this server. 
In fact, that's the bulk of the logic. How can we remove the last bits?

===========
Refactoring
===========

The Executor
------------
The socket server is not really concerned with threads; it doesn't care 
whether its worker is run in a unique thread, whether some form of time 
sharing is used, or even if it runs in some version of Java where the 
concept of "thread" doesn't even exist! All it needs is some other 
component which it can ask to make sure that its worker does what it does.

Our minds been clouded by our familiarity with threading. If we step 
back a little here, what we see is that the socket server isn't looking 
for /thread/ management, it is looking for /execution/ management. 
Something like this:

interface Executor
{
   void execute( Runnable runnable );
}

this executor can do thread pooling, thread slicing, or apply whatever 
resource and thread management policies it wants. This allows the socket 
server to be simplified a little more:

/** @avalon.component type="SocketServer" */
class ThreadedSocketServer implements SocketServer,
     Servicable, Configurable, Initializable, Startable
{
   public final static int DEFAULT_PORT = 80;
   public final static String DEFAULT_ADDRESS = "localhost";
   private int m_port;
   private String m_address;

   private Pool m_threadPool;

   private ServerSocket m_socket;
   private Worker m_worker;
   private ConnectionHandler m_handler;

   public void configure( Configuration conf )
     throws ConfigurationException
   {
     m_port = conf.getChild("port").getValueAsInteger( DEFAULT_PORT );
     m_address = conf.getChild("address").getValue( DEFAULT_ADDRESS );
   }
   /**
    * @avalon.dependency type="Executor"
    * @avalon.dependency type="ConnectionHandler"
    */
   public void service( ServiceManager sm ) throws ServiceException
   {
     m_executor = sm.Lookup( Executor.ROLE );
     m_handler = sm.lookup( ConnectionHandler.ROLE );
   }

   public void initialize() throws Exception
   {
     m_socket = getServerSocket();
     m_worker = new Worker();
   }

   public void start() throws Exception
   {
     m_executor.execute( m_worker );
   }

   public void stop()
   {
     m_worker.stop();
   }

   private class Worker implements Runnable
   {
       private boolean running = false;

       public void stop()
       {
         running = false;
       }
       public void run()
       {
         running = true;

         while(running)
         {
           Socket socket = m_socket.accept(); // block
           m_handler.handle( socket ); // delegate

           if(Thread.isInterrupted())
           {
             running = false;
             break; // die
           }
         }
       }
   }
}


Thread Monitoring and Error Management
--------------------------------------
But what if some thread grows stale? There is no way to check whether 
the worker is running, so in the event of a JVM problem the application 
slowly corrupts. Right?

Wrong! The Executor implementation has not been specified yet. Since 
we've decided its in charge of thread and execution management, this 
also seems like a good place to deal with thread monitoring...

public interface ThreadMonitor
{
   void monitor( Runnable runnable, Thread runner );

   ThreadMonitorEntry[] getMonitoredThreads();
}
public class ThreadMonitorEntry
{
   public final Runnable runnable;
   public final Thread runner;

   public ThreadMonitorEntry( Runnable runnable, Thread runner )
   {
     this.runnable = runnable;
     this.runner = runner;
   }
}
/** @avalon.component type="Executor" */
public class MonitoringThreadedExecutor implements Executor,
     Servicable
{
   ThreadMonitor m_monitor; // set through service()

   /** @avalon.dependency type="ThreadMonitor" */
   public void service( ServiceManager sm )
     throws ServiceException
   {
     m_monitor = sm.lookup( ThreadMonitor.ROLE );
   }

   public void execute( Runnable runnable )
   {
     Thread runner = new Thread( runnable );
     runnable.start();

     m_monitor.monitor( runnable, runner );
   }
}
/** @avalon.component type="ThreadMonitor" */
public class ContainerThreadMonitor implements ThreadMonitor
{
   private Container m_container; // callback gotten from Context

   private m_entries = new ArrayList();

   public void add( Runnable runnable, Thread runner )
   {
     Entry e = new Entry( runnable, runner );
     m_entries.add( e );
   }

   public ThreadMonitorEntry[] getMonitoredThreads()
   {
     return (ThreadMonitorEntry[])m_entries.toArray(
       new ThreadMonitorEntry[0] );
   }
}

...this clearly allows you to determine the state of your system: look 
up the ContainerThreadMonitor implementation via your management 
mechanism and you'll be able to inspect and modify all the threads. For 
example, you might do:

restart( containerHolder )       // BeanShell code sketch
{
   container = containerHolder.get( Container.ROLE );
   monitor = container.get( ThreadMonitor.ROLE );
   entries = monitor.getMonitoredThreads();
   for( int i = 0; i < entries; length; i++ )
   {
     entries[i].runner.interrupt();
   }

   Thread.sleep(10000);

   container.stop();
   container.dispose();
   container = new Container();
   container.start();

   containerHolder.set( Container.ROLE, container );
}


Advanced Thread Management
--------------------------
but what about just restarting the one component? The above 
implementation might be quite 'eavy, no? Well, to restart a single 
component, we'd need the monitor to be aware of what component a 
particular runnable belongs to. In code:


public class ThreadMonitorEntry
{
   public final Runnable runnable;
   public final Thread runner;
   public final Object component;

   public ThreadMonitorEntry( Runnable runnable, Thread runner,
       Object component )
   {
     this.runnable = runnable;
     this.runner = runner;
     this.component = component;
   }
}

restartDeadThreads( container )       // BeanShell code sketch
{
   monitor = container.get( ThreadMonitor.ROLE );
   entries = monitor.getMonitoredThreads();
   for( int i = 0; i < entries; length; i++ )
   {
     if(!entries[i].runner.isAlive()) // dumb check to see if something
                                      // is wrong, this should be
                                      // something intelligent
         container.restart( entries[i] );
   }
}


but how do we get that component reference in the right location? 
There's a whole range of options. For example, the container could 
associate an instance with the thread it is created in (ie, subclass 
Thread). But that's just ugly. "Subclassing considered evil until all 
alternatives have been exhausted", if you wish.

We could also modify the executor interface, requiring components to 
provide a reference to themselves:

interface Executor
{
   /** usage: execute( getWorker(), this ); */
   void execute( Runnable runnable, Object caller );
}

Or, we could opt to create an executor for each and every component that 
requires one, and delegate creation of executors to the container:

/** @avalon.component type="Executor" */
public class MonitoringThreadedExecutor implements Executor,
     Servicable
{
   ThreadMonitor m_monitor; // set through service()
   Object m_component;

   /** @avalon.dependency type="ThreadMonitor" */
   public void service( ServiceManager sm )
     throws ServiceException
   {
     m_monitor = sm.lookup( ThreadMonitor.ROLE );
   }

   public void setComponent( Object component )
   {
     m_component = component;
   }

   public void execute( Runnable runnable )
   {
     Thread runner = new Thread( runnable );
     runnable.start();

     m_monitor.monitor( runnable, runner, m_component );
   }
}

A final option would be to use AOP or some smart proxying to rewrite the 
call to execute() to include the caller as an argument, but that's a bit 
too much magic to delve into here. Besides, I've done enough thinking 
for tonight :D

Anyway, the second version of MonitoringThreadedExecutor does not 
require modification of the Executor interface (which is a good thing, 
since the client component does not need to know a reference to it is 
being kept), still allows components to run in various environments 
(you'll just have to provide an Executor yourself, instead of having the 
container do so, in case the container doesn't support them), and allows 
  the monitoring and threading code to be reused as well.

==========
Conclusion
==========
We started of with a design issue: making thread management for 
components simpler. We did some preliminary analysis and came up with a 
very ugly solution. Through the application of COP, IoC and SoC, and 
some heavy refactoring, we've arrived at a much better solution to our 
problem. Along the way, we found out that we don't want thread 
management for our components, but rather execution management.

Our new solution does not require modification of Avalon-Framework, fits 
naturally with the average needs of Startable components, results in a 
codebase which is largely reusable, allows advanced monitoring, error 
recovery, load balancing, and various other things to happen 
transparently inside advanced containers.

Clearly, COP/IoC/SoC are a winning combination when it comes to 
facilitating reusable and keeping compact but evolvable frameworks!

Putting this to use?
--------------------
So, should we now add Executor support to Merlin, along with thread 
monitoring coupled with dynamic component reloading on thread 
disruption? If so, where do we hook it in, and how?

IMO, this stuff should be an optional extension only and it should not 
disrupt existing code or make it too complex. In order to do that, some 
merlin refactoring might be required :D

Credits
-------
The Executor interface and pattern is from Doug Lea's "Concurrent 
programming in Java". The pooling and socket server code draws from 
concepts introduced in avalon-cornerstone, which were written by various 
authors.

About the author
----------------
Leo Simons is a physics student and likes cracking tough programming 
problems in his free time. He has been hanging around the avalon project 
for years now.

cheers!

- LSD



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@avalon.apache.org
For additional commands, e-mail: dev-help@avalon.apache.org


Re: seperation of concerns applied: Thread Management

Posted by Berin Loritsch <bl...@apache.org>.
Jonathan Hawkes wrote:

> Where is this AbstractWizard located?  Does the CommandManager support these
> "Wizard" commands.  (Last time I checked the source it didn't.)

It is in my GUIApp project.  The CommandManager doesn't really need to know
about the specifics of it, as it doesn't see anything different than it already
expects.

Right now it is somewhat specific to the GUIApp project, but the general concept
still works.

-- 

"They that give up essential liberty to obtain a little temporary safety
  deserve neither liberty nor safety."
                 - Benjamin Franklin


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@avalon.apache.org
For additional commands, e-mail: dev-help@avalon.apache.org


Re: seperation of concerns applied: Thread Management

Posted by Jonathan Hawkes <jh...@adsnm.com>.
Where is this AbstractWizard located?  Does the CommandManager support these
"Wizard" commands.  (Last time I checked the source it didn't.)

----- Original Message ----- 
From: "Berin Loritsch" <bl...@apache.org>
To: "Avalon Developers List" <de...@avalon.apache.org>
Sent: Thursday, October 09, 2003 10:17 AM
Subject: Re: seperation of concerns applied: Thread Management


> Jonathan Hawkes wrote:
>
> > Speaking of explicit time slicing...  What about something like the
> > following?  and then a modified Executor?  A thread pool could execute
one
> > step of the iteration and then requeue the loop until it was complete.
> > Loop.beforeRun is called with the Thread that the current iteration will
be
> > executed on.
>
> It's not really necessary.  I did something along these lines with a
"Wizard"
> type of Command.  It used reflection to determine the number of steps,
therefore
> the number of repeats.  All the user had to do was implement the
following:
>
> class MyWizard extends AbstractWizard
> {
>      public void step1() throws Exception
>      {
>          //perform step
>      }
>      public void step2() throws Exception
>      {
>          //perform step
>      }
>      public void step3() throws Exception
>      {
>          //perform step
>      }
>      public void step4() throws Exception
>      {
>          //perform step
>      }
> }
>
> It works pretty well.  The AbstractWizard also provides some methods to
reset
> the wizard so that it can be re-used, and go back to the starting position
if
> one of the steps had to be finished early.
>
> It's pretty easy to do.
>
> -- 
>
> "They that give up essential liberty to obtain a little temporary safety
>   deserve neither liberty nor safety."
>                  - Benjamin Franklin
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscribe@avalon.apache.org
> For additional commands, e-mail: dev-help@avalon.apache.org
>
>


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@avalon.apache.org
For additional commands, e-mail: dev-help@avalon.apache.org


Re: seperation of concerns applied: Thread Management

Posted by Berin Loritsch <bl...@apache.org>.
Jonathan Hawkes wrote:

> Speaking of explicit time slicing...  What about something like the
> following?  and then a modified Executor?  A thread pool could execute one
> step of the iteration and then requeue the loop until it was complete.
> Loop.beforeRun is called with the Thread that the current iteration will be
> executed on.

It's not really necessary.  I did something along these lines with a "Wizard"
type of Command.  It used reflection to determine the number of steps, therefore
the number of repeats.  All the user had to do was implement the following:

class MyWizard extends AbstractWizard
{
     public void step1() throws Exception
     {
         //perform step
     }
     public void step2() throws Exception
     {
         //perform step
     }
     public void step3() throws Exception
     {
         //perform step
     }
     public void step4() throws Exception
     {
         //perform step
     }
}

It works pretty well.  The AbstractWizard also provides some methods to reset
the wizard so that it can be re-used, and go back to the starting position if
one of the steps had to be finished early.

It's pretty easy to do.

-- 

"They that give up essential liberty to obtain a little temporary safety
  deserve neither liberty nor safety."
                 - Benjamin Franklin


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@avalon.apache.org
For additional commands, e-mail: dev-help@avalon.apache.org


Re: seperation of concerns applied: Thread Management

Posted by Jonathan Hawkes <jh...@adsnm.com>.
Speaking of explicit time slicing...  What about something like the
following?  and then a modified Executor?  A thread pool could execute one
step of the iteration and then requeue the loop until it was complete.
Loop.beforeRun is called with the Thread that the current iteration will be
executed on.

/**
 * <pre>
 * // Semantics:
 * Thread ct = Thread.currentThread();
 * for (initLoop(); beforeRun(ct); ) {
 *     try {
 *         run();
 *     } catch (Throwable t) {
 *         throwableThrown(t);
 *     }
 *     if ( !afterRun() ) {
 *         break;
 *     }
 * }
 * </pre>
 */
public interface Loop extends Runnable {

    public void initLoop();

    public boolean beforeRun(Thread thread);

    public void run();
    public void throwableThrown(Throwable t);

    public boolean afterRun();
}


----- Original Message ----- 
From: "Berin Loritsch" <bl...@apache.org>
To: "Avalon Developers List" <de...@avalon.apache.org>
Sent: Thursday, October 09, 2003 9:46 AM
Subject: Re: seperation of concerns applied: Thread Management


> Leo Simons wrote:
>
> <snip type="all types of useful things"/>
>
> >
> > ==========
> > Conclusion
> > ==========
> > We started of with a design issue: making thread management for
> > components simpler. We did some preliminary analysis and came up with a
> > very ugly solution. Through the application of COP, IoC and SoC, and
> > some heavy refactoring, we've arrived at a much better solution to our
> > problem. Along the way, we found out that we don't want thread
> > management for our components, but rather execution management.
> >
> > Our new solution does not require modification of Avalon-Framework, fits
> > naturally with the average needs of Startable components, results in a
> > codebase which is largely reusable, allows advanced monitoring, error
> > recovery, load balancing, and various other things to happen
> > transparently inside advanced containers.
> >
> > Clearly, COP/IoC/SoC are a winning combination when it comes to
> > facilitating reusable and keeping compact but evolvable frameworks!
>
> You know, this is the line of thinking I had when I designed the
CommandManager
> in the Event package.  Maybe it could be made more generic or something,
but
> here me out.
>
> I did not introduce the ThreadMonitor type of interface, but the
COmmandManager
> hides one or more Executors.  The main interface to it is an event Queue.
> The Queue accepts Commands (an object that performs an action) and
processes
> them in the order received.  The Executor it uses can be a PooledExecutor
(as
> is now the case).  Anyhoo, there are more than one command type available.
> THere is a DelayedCommand which will execute after a certain period of
time.
> There is also a RepeatedCommand which will keep repeating the command in
the
> system until the number of repeats is exhausted.  This gives the illusion
of
> a long running thread without occupying the thread for the full time.
>
> In essence, we get a natural thread slicing in our system.
>
> To rewrite your connection handling code a little it would look something
like
> this:
>
> /** @avalon.component type="SocketServer" */
> class ThreadedSocketServer implements SocketServer,
>      Servicable, Configurable, Initializable, Startable
> {
>    public final static int DEFAULT_PORT = 80;
>    public final static String DEFAULT_ADDRESS = "localhost";
>    private int m_port;
>    private String m_address;
>
>    private Queue m_executor;
>
>    private ServerSocket m_socket;
>    private Worker m_worker;
>    private ConnectionHandler m_handler;
>
>    public void configure( Configuration conf )
>      throws ConfigurationException
>    {
>      m_port = conf.getChild("port").getValueAsInteger( DEFAULT_PORT );
>      m_address = conf.getChild("address").getValue( DEFAULT_ADDRESS );
>    }
>    /**
>     * @avalon.dependency type="Queue"
>     * @avalon.dependency type="ConnectionHandler"
>     */
>    public void service( ServiceManager sm ) throws ServiceException
>    {
>      m_executor = sm.Lookup( Queue.ROLE );
>      m_handler = sm.lookup( ConnectionHandler.ROLE );
>    }
>
>    public void initialize() throws Exception
>    {
>      m_socket = getServerSocket();
>      m_worker = new Worker();
>    }
>
>    public void start() throws Exception
>    {
>      m_executor.execute( m_worker );
>    }
>
>    public void stop()
>    {
>      m_worker.stop();
>    }
>
>    private class Worker implements RepeatedCommand  {
>        public int getNumberOfRepeats() { return -1; } // don't stop
>
>        public long getDelay() { return 0; } // start immediately
>
>        public long getInterval() { return 100; } // every 100ms
>
>        public void execute() throws Exception
>        {
>            Socket socket = m_socket.accept(); // block
>            m_handler.handle( socket ); // delegate
>        }
>    }
> }
>
> Isn't it so much cleaner when you don't have to worry about the looping
> code yourself?  Not to mention, other commands can share the same thread.
> Now this does throw a monkey wrench in your ThreadMonitor type process.
> That monkey wrench is that with this system, a thread is not tied to a
> component.  The command is.
>
> If a thread dies, it can be removed and handled accordingly.  The
> associated component does not need to restart, the ThreadManager that the
> CommandManager uses will restart the thread, and give it the command that
> did not run.
>
> Granted, the CommandManager still has some rough edges, but I also believe
> it has some advantages too.  Whadayathink?
>
> -- 
>
> "They that give up essential liberty to obtain a little temporary safety
>   deserve neither liberty nor safety."
>                  - Benjamin Franklin
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscribe@avalon.apache.org
> For additional commands, e-mail: dev-help@avalon.apache.org
>
>


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@avalon.apache.org
For additional commands, e-mail: dev-help@avalon.apache.org


Re: seperation of concerns applied: Thread Management

Posted by Berin Loritsch <bl...@apache.org>.
Leo Simons wrote:

<snip type="all types of useful things"/>

> 
> ==========
> Conclusion
> ==========
> We started of with a design issue: making thread management for 
> components simpler. We did some preliminary analysis and came up with a 
> very ugly solution. Through the application of COP, IoC and SoC, and 
> some heavy refactoring, we've arrived at a much better solution to our 
> problem. Along the way, we found out that we don't want thread 
> management for our components, but rather execution management.
> 
> Our new solution does not require modification of Avalon-Framework, fits 
> naturally with the average needs of Startable components, results in a 
> codebase which is largely reusable, allows advanced monitoring, error 
> recovery, load balancing, and various other things to happen 
> transparently inside advanced containers.
> 
> Clearly, COP/IoC/SoC are a winning combination when it comes to 
> facilitating reusable and keeping compact but evolvable frameworks!

You know, this is the line of thinking I had when I designed the CommandManager
in the Event package.  Maybe it could be made more generic or something, but
here me out.

I did not introduce the ThreadMonitor type of interface, but the COmmandManager
hides one or more Executors.  The main interface to it is an event Queue.
The Queue accepts Commands (an object that performs an action) and processes
them in the order received.  The Executor it uses can be a PooledExecutor (as
is now the case).  Anyhoo, there are more than one command type available.
THere is a DelayedCommand which will execute after a certain period of time.
There is also a RepeatedCommand which will keep repeating the command in the
system until the number of repeats is exhausted.  This gives the illusion of
a long running thread without occupying the thread for the full time.

In essence, we get a natural thread slicing in our system.

To rewrite your connection handling code a little it would look something like
this:

/** @avalon.component type="SocketServer" */
class ThreadedSocketServer implements SocketServer,
     Servicable, Configurable, Initializable, Startable
{
   public final static int DEFAULT_PORT = 80;
   public final static String DEFAULT_ADDRESS = "localhost";
   private int m_port;
   private String m_address;

   private Queue m_executor;

   private ServerSocket m_socket;
   private Worker m_worker;
   private ConnectionHandler m_handler;

   public void configure( Configuration conf )
     throws ConfigurationException
   {
     m_port = conf.getChild("port").getValueAsInteger( DEFAULT_PORT );
     m_address = conf.getChild("address").getValue( DEFAULT_ADDRESS );
   }
   /**
    * @avalon.dependency type="Queue"
    * @avalon.dependency type="ConnectionHandler"
    */
   public void service( ServiceManager sm ) throws ServiceException
   {
     m_executor = sm.Lookup( Queue.ROLE );
     m_handler = sm.lookup( ConnectionHandler.ROLE );
   }

   public void initialize() throws Exception
   {
     m_socket = getServerSocket();
     m_worker = new Worker();
   }

   public void start() throws Exception
   {
     m_executor.execute( m_worker );
   }

   public void stop()
   {
     m_worker.stop();
   }

   private class Worker implements RepeatedCommand  {
       public int getNumberOfRepeats() { return -1; } // don't stop

       public long getDelay() { return 0; } // start immediately

       public long getInterval() { return 100; } // every 100ms

       public void execute() throws Exception
       {
           Socket socket = m_socket.accept(); // block
           m_handler.handle( socket ); // delegate
       }
   }
}

Isn't it so much cleaner when you don't have to worry about the looping
code yourself?  Not to mention, other commands can share the same thread.
Now this does throw a monkey wrench in your ThreadMonitor type process.
That monkey wrench is that with this system, a thread is not tied to a
component.  The command is.

If a thread dies, it can be removed and handled accordingly.  The
associated component does not need to restart, the ThreadManager that the
CommandManager uses will restart the thread, and give it the command that
did not run.

Granted, the CommandManager still has some rough edges, but I also believe
it has some advantages too.  Whadayathink?

-- 

"They that give up essential liberty to obtain a little temporary safety
  deserve neither liberty nor safety."
                 - Benjamin Franklin


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@avalon.apache.org
For additional commands, e-mail: dev-help@avalon.apache.org


Re: seperation of concerns applied: Thread Management

Posted by hammett <ha...@apache.org>.
----- Original Message -----
From: "Leo Simons" <le...@apache.org>


> hammett wrote:
> > What are you waiting to put this in a docbook format and upload to
> > avalon-site as an article ????? :-)
>
> I'm waiting for someone else to volunteer :D

Ok... +1 task in my list  ;-)

> The attributes stuff is from the other Leo (Sutic), its now a commmons
> project at

Wops. Well, it happens even in the best families [1] :-p

> g'night!

See you!


Regards,

hammett


[1] Common excuse-expression here - don't know if has the same meaning there
:-))



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@avalon.apache.org
For additional commands, e-mail: dev-help@avalon.apache.org


Re: seperation of concerns applied: Thread Management

Posted by Leo Simons <le...@apache.org>.
hammett wrote:
> What are you waiting to put this in a docbook format and upload to
> avalon-site as an article ????? :-)

I'm waiting for someone else to volunteer :D

> BTW where did you put your attributes work?

The attributes stuff is from the other Leo (Sutic), its now a commmons 
project at

jakarta.apache.org/commons/sandbox/attributes

g'night!

- LSD



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@avalon.apache.org
For additional commands, e-mail: dev-help@avalon.apache.org


Re: seperation of concerns applied: Thread Management

Posted by hammett <ha...@apache.org>.
What are you waiting to put this in a docbook format and upload to
avalon-site as an article ????? :-)
BTW where did you put your attributes work?


Regards,

hammett

----- Original Message -----
From: "Leo Simons" <le...@apache.org>
To: <de...@avalon.apache.org>
Sent: Wednesday, October 08, 2003 6:10 PM
Subject: seperation of concerns applied: Thread Management


> <snip type="nice work" />


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@avalon.apache.org
For additional commands, e-mail: dev-help@avalon.apache.org


RE: Monitored Components

Posted by Leo Sutic <le...@inspireinfrastructure.com>.

> From: news [mailto:news@sea.gmane.org] On Behalf Of Leo Simons
>
> Leo Sutic wrote:
> > IoC doesn't mean that there's no flow of information from the 
> > component to the container, just that *the container has the final
> > word* regarding what is actually *done* with the information.
> 
> The way I was looking at it, the container controls when information 
> flows, and the component is not allowed to initiate any 
> communication on its own ("You shall speak only when spoken to"). 
> Your definition is much more useful.
> 
> thinking...it seems like the "Will only speak when spoken to" is a 
> natural property for passive components (ie that don't implement 
> startable nor use seperate threads of execution), whereas you 
> won't be able to hold it for active components.

"You shall speak only when spoken to" makes sense, but you need to
allow for another order, or interpret "when spoken to" a bit wider: 
"You shall speak only when given permission to speak."

 + Speak when spoken to - because if I ask you something, you
   should interpret that as an implicit request that you shall
   speak to me (tell me the answer).

 + Notify me about things I have told you to notify me about - 
   because I have given you explicit permission to speak.

Thinking about a little child that is taught that "you shall speak 
only when spoken to". However, you should be able to instruct the
kid to "clean your room, and tell me when you are done". In this
case, you set up a callback ("tell me when you are done") and then
make an asynchronous call to the kid ("clean your room"). In the
same way "do your job and notify me about important events":

    component.setComponentMonitor (monitor); // Notify me
    component.start (); // do your job

(I've use the setXXX pattern just to make the analogy fit better.)

The important thing about IoC is the C - Control. The container
controls how the component speaks. It controls what is done
with the speech. I.e. the component cn yell and scream all it
wants and it will make no difference to the container:

 You: "Time to go sleep now."
 Kid: "But I don't want to!"
 You: "You do."  { kid.suspend(); }

A non-IoC is when the component starts to run the container:

 You: "Time to go sleep now."
 Kid: "But I don't want to!" 
 You: "Oh well I guess you don't have to, then..."
 Kid: "I want ice cream!"
 You: "OK, here you are..."
 ...

> > I have no problem with your use of lookup() to obtain a monitor. 
> > Perhaps even more in line would be to use the Context for this, 
> > though. (Or are we getting rid of that one in favor of the
> > ServiceManager?)
> 
> here we go again :D

Let's not...

> Me, I'm a type 3 convert, and in that world there is no distinction 
> between container or component-provided services. Which works.

Sounds OK to me, too.

> > Regarding the multitude of status messages - I don't think 
> > that will be any help.
> 
> It ties in with the no-logging idea I think. You want the container to

> notify an admin that a component died. It'd be useful for the 
> admin to know why that happened. Hence the specific message. And 
> since, in java, things die because of exceptions, that's a nice way 
> of providing the message.

OK - yep that makes sense. I just don't see the value of propagating
this to the other components other than as a FYI. One shouldn't expect
the other components to actually *help* here.

Makes sense - a broken component is an exceptional state, so we should
use similar objects to describe it (although we won't be throwing
the Exceptions), but as you say, since the root of the broken-ness 
probably will be an Exception, just re-using it will be the clearest,
most user-friendly thing.

Even though you'll get a stack trace and a OwwwBrokenThingException
in the logs (not normally considered user-friendly), I think that this
is the 
most user-friendlyness we can hope for and what we should aim for.
Exceptions are exceptional. If they break components one should not try
to 
hide it, but show as much data as possible, as it is something that
should never happen.

/LS


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@avalon.apache.org
For additional commands, e-mail: dev-help@avalon.apache.org


Re: Monitored Components

Posted by Leo Simons <le...@apache.org>.
Leo Sutic wrote:
> IoC doesn't mean that there's no flow of information from the
> component to the container, just that *the container has the final
> word* regarding what is actually *done* with the information.

The way I was looking at it, the container controls when information 
flows, and the component is not allowed to initiate any communication on 
its own ("You shall speak only when spoken to"). Your definition is much 
more useful.

thinking...it seems like the "Will only speak when spoken to" is a 
natural property for passive components (ie that don't implement 
startable nor use seperate threads of execution), whereas you won't be 
able to hold it for active components.

> I have no problem with your use of lookup() to obtain a monitor.
> Perhaps even more in line would be to use the Context for this,
> though. (Or are we getting rid of that one in favor of the
> ServiceManager?)

here we go again :D

I believe the last time we talked about all this we resolved (after 
three weeks of debate or so) that the context is used for 
container-component communication and the servicemanager for 
inter-component communication. The tricky part is when you have a 
service which can either be provided by the container or by another 
component. Muddy, since your average container makes most things into 
components.

So no clear answer here.

Me, I'm a type 3 convert, and in that world there is no distinction 
between container or component-provided services. Which works.

> Regarding the multitude of status messages - I don't think that will
> be any help.

It ties in with the no-logging idea I think. You want the container to 
notify an admin that a component died. It'd be useful for the admin to 
know why that happened. Hence the specific message. And since, in java, 
things die because of exceptions, that's a nice way of providing the 
message.

> I don't really want to have one component notify every
> other component that they're broken, because there's usually nothing
> the other components can do about it.

agreed.

> Just throwing more into the mess - multithreading:

actually...no problem at all!

The socket server IMV is not actually concerned with multithreading, nor 
does it need to be (unless you're running an infiniband-style 
200-processor server where a single processor cannot accept() 
connections as fast as the networking hardware). Just let the executor 
and handlers worry about that.

The single function of the socket server is to hand off connections to a 
handler. The handler is allowed to do multithreading if it wants to. It 
might again depend on an Executor, like this:

class AlternatingConnectionHandler implements ConnectionHandler
                                                      // code sketch
{
   /** in this example: a specialized pool that will call setSocket()
       on get() */
   WorkerPool m_workers = /* ... */

   handle( Socket socket )
   {
     worker = m_workers.get( socket );
     m_executor.execute( worker );
   }

   stop()
   {
     m_workers.stopAll();
   }

   class Worker implements Runnable
   {
     Worker() { /* ... */ }
     setSocket( Socket socket ) { /* ... */ }
     run()
     {
       try
       {
         /* ... */
         if(!running) return; Thread.yield();
         /* ... */
         if(!running) return; Thread.yield();
         /* ... */
       }
       finally
       {
         m_workers.release( this );
       }
     }
     stop() { running = false; }
   }
}

and you just happen to pass in a PooledExecutor here when you want 
multi-threading. Or you might just let connections queue up in your 
handler. Or...

 > m_executor.interruptAndStopAll(); // Does this method even exist?

nope, it doesn't. In fact, the executor interface specifies that it 
might even be single-threaded. But if you're using a PooledExecutor, for 
example, it does:

http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/PooledExecutor.html#shutdownNow()

However, in general, it is not the responsibility of the server or 
handler components to shut down the threads in a pool, but of the pool 
itself (which, after all, is a component, too).

cheers!

- LSD



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@avalon.apache.org
For additional commands, e-mail: dev-help@avalon.apache.org


RE: Monitored Components

Posted by Leo Sutic <le...@inspireinfrastructure.com>.
Thanks for the comments - just a quick reply to some of the many
good points (will get a bigger reply out later):

> From: news [mailto:news@sea.gmane.org] On Behalf Of Leo Simons
> 
> >     public interface ComponentMonitor {
> >         public void statusChange (Status status);
> >     }
> 
> the objection someone raised to this one is that it breaks 
> IoC because 
> it is a way for a component to tell the container to do 
> something. The 
> obvious way around that is to make the monitor active and have it use 
> polling, ie in my example it was:
> 
>    /** m_monitor runs a seperate thread which polls for status */
>    m_monitor.monitor( runnable, runner, m_component );

It is IoC, because the container tells the component - "Hey, when you
get a problem, I want to hear about it via this thing!"

(Consider how the military works: You don't expect the squad leader to
"poll" his soldiers - you expect the soldiers to report to him without
being prodded.)

Like Phoenix's requestShutdown() method - IoC doesn't mean that there's
no flow of information from the component to the container, just that
*the
container has the final word* regarding what is actually *done* with the
information.

I have no problem with your use of lookup() to obtain a monitor. Perhaps
even more in line would be to use the Context for this, though. (Or are
we getting rid of that one in favor of the ServiceManager?)

Regarding the multitude of status messages - I don't think that will be
any help. I don't really want to have one component notify every other
component that they're broken, because there's usually nothing the
other components can do about it.

It just removes the image I have in my mind of a component as "an
interface that I can get from a service manager that *just works*".
And I really like that. What complex things happen behind the interface
I don't want to care about! So the SocketManager throws a 
ServerPortInUseException - right, what does the RequestHandler do? Open
its own server socket? It degenerates *quickly*...

> There's an open question: why is there a neccessary and sufficient set

> of conditions for deviating from the usual approach of applying strict

> IoC? 

Strict IoC means that the container has the final word regarding what
actions are taken. We're *not* deviating in the slightest.

((((

Just throwing more into the mess - multithreading:

/** @avalon.component type="SocketServer" */
class ThreadedSocketServer implements SocketServer,
     Servicable, Configurable, Initializable, Startable, Disposable {
   public final static int DEFAULT_PORT = 80;
   public final static int DEFAULT_BACK_LOG = 100;
   public final static String DEFAULT_ADDRESS = "localhost";
   private int m_port;
   private int m_backlog;
   private String m_address;
   private int m_numThreads;

   private ServerSocket m_socket;
   private Monitor m_monitor;

   private Worker m_worker;
   private ConnectionHandler m_handler;

   public void configure( Configuration conf )
     throws ConfigurationException
   {
     m_port = conf.getChild("port").getValueAsInteger( DEFAULT_PORT );
     m_backlog = conf.getChild("backlog")
         .getValueAsInteger( DEFAULT_BACKLOG );
     m_address = conf.getChild("address").getValue( DEFAULT_ADDRESS );
   }

   /**
    * @avalon.dependency type="Executor"
    * @avalon.dependency type="ConnectionHandler"
    * @avalon.dependency type="Monitor"
    */
   public void service( ServiceManager sm ) throws ServiceException
   {
     m_executor = sm.Lookup( Executor.ROLE );
     m_handler = sm.lookup( ConnectionHandler.ROLE );
     m_monitor = sm.lookup( Monitor.ROLE );
   }

   public void initialize() throws Exception
   {
     m_socket = getNewServerSocket();
   }

   public void start() throws Exception
   {
     for( int i = 0; i < m_numThreads; i++ ) {
         m_executor.execute( new Worker() );
     }
   }

   public void stop()
   {
     m_executor.interruptAndStopAll(); // Does this method even exist?
   }

   public void dispose()
   {
     try { m_socket.close(); }
     catch( IOException ioe ) {}
   }

   protected void getNewServerSocket()
   {
     InetAddress address = InetAddress.getByName( m_address );
     ServerSocket socket =
         new ServerSocket( m_port, m_backlog, m_address );

     return socket;
   }

   private class Worker implements Runnable
   {
       private boolean running = false;

       public void stop()
       {
         running = false;
       }
       public void run()
       {
         running = true;

         while(running)
         {
           if(Thread.isInterrupted())
           {
             running = false;
             break; // die
           }

           try
           {
             Socket socket = m_socket.accept(); // block
             m_handler.handle( socket ); // delegate
           }
           catch( Throwable t )
           {
             m_monitor.statusChange( new Status( e ) );
                 // notify others
           }
         }
       }
   }
}

))))

/LS


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@avalon.apache.org
For additional commands, e-mail: dev-help@avalon.apache.org


Re: Monitored Components

Posted by Leo Simons <le...@apache.org>.
Leo Sutic wrote:
> 1. "How does a container detect that a component is broken?" 
>     Whether that broken-ness results from a worker thread 
>     crashing, or from an unhandled exception in a synchronous 
>     call is irrelevant.

+1. But I'm not so sure we're only looking at container doing the 
detection.....there'd be various parties interested in this information. 
So we'll also be looking at a way for querying the container to find out 
what components are broken. Not yet, though.

> 2. "How does a container recover from a broken component?"
>     Dynamic reloading may not always work - consider components
>     that maintain state between method calls (SAXTransformer).
>     Sometimes, a component should just be marked "broken" and
>     any calls to it blocked to keep it from hurting itself.

I am guessing several 'recovery' policies need to exist. Encoding just 
one of them into core contracts seems a bad idea......

>     public interface Monitorable {
>         public void setMonitor (ComponentMonitor monitor);
>     }

If I replace "able" with "Aware" in your example I end up with an 
XWork-style ("IoC type 3") setup. To problem with that (as many have 
found out by now) is the proliferation of XXXable interfaces, that it is 
difficult to remove the 'XXX' functionality in subclasses (like so 
adequately described wrt the Cloneable interface in various books), etc etc.

What about

       public service( ServiceManager sm )
       {
           monitor = sm.lookup( ComponentMonitor.ROLE );
       }

? Seems more consistent with avalon semantics.

>     public interface ComponentMonitor {
>         public void statusChange (Status status);
>     }

the objection someone raised to this one is that it breaks IoC because 
it is a way for a component to tell the container to do something. The 
obvious way around that is to make the monitor active and have it use 
polling, ie in my example it was:

   /** m_monitor runs a seperate thread which polls for status */
   m_monitor.monitor( runnable, runner, m_component );

Which is probably less efficient though...nor does it scale...any 
thoughts on that? In general, it seems to be there's a class of problems 
which are very hard to solve using IoC but simpler using 
events/callbacks/ listeners/etc. Is this a good place to break IoC? Why? 
Can we identify a pattern here?

>     public class Status {
>         public static final Status OK = new Status ("ok");    
>         public static final Status BROKEN = new Status ("broken");
>     }

it seems the 'status' should be a customizable enumeration to allow for 
application-specific policies. Perhaps something similar to HTTP (class 
of 1xx, 2xx, 3xx, 4xx error messages allowing a few base policies, and 
more specific policies based on the 'xx' in advanced implementations 
and/or [5-9]xx) could be figured out. Maybe using subclassing...

  public class Status {}
  public class StatusOK extends Status {}
  public class StatusBroken extends Status {}
  public class StatusDeadWorkerThread extends StatusBroken {}

...wait a minute...seems that's just recreating a hierarchy to parallel 
the exception hierarchy...maybe

   public class Status
   {
     private Throwable m_problem = null;

     public Status( Throwable problem ) { m_problem = problem; }
     public Throwable getProblem( m_problem ) { return m_problem; }
     public boolean isBroken() { return m_problem != null; }
   }

is flexible but still simple?

> [the above decomposition] can solve [the issues mentioned above]?

Yeah, seems like it could work, and it looks simple enough, and it might 
even be possible to implement using lifecycle extensions.

=======
Summary
=======
We're now looking at this seperation of concerns:

1 - work execution
2 - status monitoring

(1) can be addressed naturally using an Executor, whether or not thread 
management comes into the picture is not a concern of the client 
component. In fact, we've made all thread management policy configurable 
in a client-transparent way :D

The case you make is that (2) might be addressed best using a passive, 
one-instance-per-component, status-based component monitor, with the 
main argument that such a setup is much simpler than any kind of 
polling. I'll add that its also likely to be more efficient.

There's an open question: why is there a neccessary and sufficient set 
of conditions for deviating from the usual approach of applying strict 
IoC? (what are those conditions and why do they apply here?)

========================
Complete picture in code
========================

Work execution
--------------
Re-use from util.concurrent:

   interface Executor
   {
     void execute( Runnable runnable );
   }

Monitoring
----------
Passive and event-based:

   public interface ComponentMonitor
   {
     public void statusChange( Status status );
   }
   public class Status
   {
     private Throwable m_problem = null;

     public Status( Throwable problem ) { m_problem = problem; }
     public Throwable getProblem( m_problem ) { return m_problem; }
     public boolean isBroken() { return m_problem != null; }
   }

Socket server example (code sketch)
-----------------------------------
   /** Listens for socket requests and handles them. */
   interface SocketServer {}
   /** Deals with a single socket request at a time. */
   interface ConnectionHandler
   {
     public void handle( Socket socket );
   }

/** @avalon.component type="SocketServer" */
class ThreadedSocketServer implements SocketServer,
     Servicable, Configurable, Initializable, Startable, Disposable
{
   public final static int DEFAULT_PORT = 80;
   public final static int DEFAULT_BACK_LOG = 100;
   public final static String DEFAULT_ADDRESS = "localhost";
   private int m_port;
   private int m_backlog;
   private String m_address;

   private ServerSocket m_socket;
   private Monitor m_monitor;

   private Worker m_worker;
   private ConnectionHandler m_handler;

   public void configure( Configuration conf )
     throws ConfigurationException
   {
     m_port = conf.getChild("port").getValueAsInteger( DEFAULT_PORT );
     m_backlog = conf.getChild("backlog")
         .getValueAsInteger( DEFAULT_BACKLOG );
     m_address = conf.getChild("address").getValue( DEFAULT_ADDRESS );
   }

   /**
    * @avalon.dependency type="Executor"
    * @avalon.dependency type="ConnectionHandler"
    * @avalon.dependency type="Monitor"
    */
   public void service( ServiceManager sm ) throws ServiceException
   {
     m_executor = sm.Lookup( Executor.ROLE );
     m_handler = sm.lookup( ConnectionHandler.ROLE );
     m_monitor = sm.lookup( Monitor.ROLE );
   }

   public void initialize() throws Exception
   {
     m_socket = getNewServerSocket();
     m_worker = new Worker();
   }

   public void start() throws Exception
   {
     m_executor.execute( m_worker );
   }

   public void stop()
   {
     m_worker.stop();
   }

   public void dispose()
   {
     try { m_socket.close(); }
     catch( IOException ioe ) {}
   }

   protected void getNewServerSocket()
   {
     InetAddress address = InetAddress.getByName( m_address );
     ServerSocket socket =
         new ServerSocket( m_port, m_backlog, m_address );

     return socket;
   }

   private class Worker implements Runnable
   {
       private boolean running = false;

       public void stop()
       {
         running = false;
       }
       public void run()
       {
         running = true;

         while(running)
         {
           if(Thread.isInterrupted())
           {
             running = false;
             break; // die
           }

           try
           {
             Socket socket = m_socket.accept(); // block
             m_handler.handle( socket ); // delegate
           }
           catch( Throwable t )
           {
             m_monitor.statusChange( new Status( e ) );
                 // notify others
           }
         }
       }
   }
}

Observations
------------
- it is not transparent to the component that its being monitored. It'd 
be nice if it were. Not sure whether that's even remotely feasible for 
'generic' monitoring unless we introduce some magic (in the form of AOP).

- the configure()/service()/start()/stop()/initialize()/dispose() do not 
fire status changes to the monitor....assumed is that the monitor is 
container-provided and that these status changes will be sent to the 
monitor, if neccessary, by the container.

- I found several bugs and there's likely to be more; this code will 
likely not compile :D

- interesting problem, this is :D


cheers,


- LSD

PS: http://www.google.com/search?q=java+thread+monitoring reveals all 
this is an area of active research :D



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@avalon.apache.org
For additional commands, e-mail: dev-help@avalon.apache.org


Monitored Components (was: Thread Management)

Posted by Leo Sutic <le...@inspireinfrastructure.com>.
All,

seems like the basic issues here are 

1. "How does a container detect that a component is broken?" 
    Whether that broken-ness results from a worker thread 
    crashing, or from an unhandled exception in a synchronous 
    call is irrelevant.

2. "How does a container recover from a broken component?"
    Dynamic reloading may not always work - consider components
    that maintain state between method calls (SAXTransformer).
    Sometimes, a component should just be marked "broken" and
    any calls to it blocked to keep it from hurting itself.

Perhaps a general 

    public interface Monitorable {
        public void setMonitor (ComponentMonitor monitor);
    }

    public interface ComponentMonitor {
        public void statusChange (Status status);
    }

    public class Status {
        public static final Status OK = new Status ("ok");    
        public static final Status BROKEN = new Status ("broken");
    }

can solve this?

The ComponentMonitor can work in two ways:

    /** Simple. */
    public void statusChange (Status status) {
        statusOfComponent = status;
    }

    /** Once broken, always broken. */
    public void statusChange (Status status) {
        if (statusOfComponent == Status.OK) { statusOfComponent = status
};
    }

/LS



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@avalon.apache.org
For additional commands, e-mail: dev-help@avalon.apache.org


Re: seperation of concerns applied: Thread Management

Posted by Stephen McConnell <mc...@apache.org>.

Leo Simons wrote:

>
> Putting this to use?
> --------------------
> So, should we now add Executor support to Merlin, along with thread 
> monitoring coupled with dynamic component reloading on thread 
> disruption? If so, where do we hook it in, and how?
>
> IMO, this stuff should be an optional extension only and it should not 
> disrupt existing code or make it too complex. In order to do that, 
> some merlin refactoring might be required :D 


It's in beta - refactoring is fair game! Seriously though - 2.1 was a 
lot more dynamic and extendible at the runtime level than 3.0. But 3.0 
is a lot better the 2.1 with respect to model separation (and related 
model management).  I want to see 2.1 dynamics coming back in - but 
consistent with the model/runtime separation. 

Things in mind:

1. pluggable lifestyles
2. pluggable lifecycle strategies
3. plugable facilities (e.g. JMX)
4. events and listeners

Cheers, Steve.


p.s.
BTW ... good post!

-- 

Stephen J. McConnell
mailto:mcconnell@apache.org




---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@avalon.apache.org
For additional commands, e-mail: dev-help@avalon.apache.org