/*
* Copyright (c) 2005 Thomas Weise
*
* E-Mail : tweise@gmx.de
* Creation Date : 2005-09-01 12:01:26
* Original Filename: org.sfc.parallel.SfcThreadGroup.java
* Version : 3.1.0
* Last modification: 2006-06-08
* by: Thomas Weise
*
* License : GNU LESSER GENERAL PUBLIC LICENSE
* Version 2.1, February 1999
* You should have received a copy of this license along
* with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307, USA or download the license under
* http://www.gnu.org/copyleft/lesser.html.
*
* Warranty : This software is provided "as is" without any
* warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose.
* See the Gnu Lesser General Public License for more
* details.
*/
package org.sfc.parallel;
import org.sfc.events.IEventListener;
import org.sfc.parallel.events.ParallelStateEvent;
/**
* The sfc-pendant of a thread group.
*
* @author Thomas Weise
*/
public abstract class SfcThreadGroup extends ThreadGroup
implements IWaitable, IAbortable
{
/**
* The sfc thread grop name.
*/
private static final String NAME = "SfcThreadGroup";
/**
* The internal count of active sub-objects.
*/
private volatile int m_cnt ;
/**
* The internal sync-point.
*/
private final SyncPoint m_sync ;
/**
* The propagator for error events.
*/
private final IEventListener m_events ;
/**
* Create a new sfc thread group.
* @param p_group The thread group owning this one, or null
.
*/
public SfcThreadGroup (final SfcThreadGroup p_group)
{
this(p_group, null);
}
/**
* Create a new sfc thread group.
* @param p_group The sfc-thread group owning this thread. This can be
* null
.
* @param p_events The event propagator to be used internally.
*/
public SfcThreadGroup (final SfcThreadGroup p_group,
IEventListener p_events)
{
super((p_group != null) ? p_group
: Thread.currentThread().getThreadGroup(), NAME);
ThreadGroup l_t;
if(p_events == null)
{
l_t = this.getParent();
if(l_t instanceof SfcThreadGroup)
{
p_events = ((SfcThreadGroup)l_t).get_propagator();
}
}
this.m_events = p_events;
this.m_sync = new SyncPoint(false);
}
/**
* Create a new SfcThreadGroup
.
* @param p_events The event propagator to use.
*/
public SfcThreadGroup (final IEventListener p_events)
{
this(null, p_events);
}
/**
* Register something to this group.
*/
final void register ()
{
SyncPoint l_sp;
ThreadGroup l_tg;
l_sp = this.m_sync;
synchronized(l_sp)
{
if((this.m_cnt++) == 0)
{
l_tg = this.getParent();
if(l_tg instanceof SfcThreadGroup)
{
((SfcThreadGroup)l_tg).register();
}
if(this.m_events != null)
{
this.m_events.receive(new ParallelStateEvent(this, true));
}
this.m_sync.set_wait(true);
}
}
}
/**
* Unregister something from this group
*/
final void unregister ()
{
ThreadGroup l_tg;
SyncPoint l_sp;
l_sp = this.m_sync;
synchronized(l_sp)
{
if( (--this.m_cnt) <= 0)
{
if(this.m_events != null)
{
this.m_events.receive(new ParallelStateEvent(this, false));
}
l_tg = this.getParent();
if(l_tg instanceof SfcThreadGroup)
{
((SfcThreadGroup)l_tg).unregister();
}
this.m_sync.release(false);
}
}
}
/**
* Wait for this object.
*/
public final void wait_for ()
{
this.m_sync.wait_for();
}
/**
* Abort this activity.
* This method does not block.
*/
public final void abort ()
{
SyncPoint l_sp;
int l_i;
Thread[] l_t;
Thread l_tt;
ThreadGroup[] l_tg;
ThreadGroup l_tgg;
l_sp = this.m_sync;
l_t = null;
do
{
synchronized(l_sp)
{
l_i = this.activeGroupCount();
l_tg = new ThreadGroup[l_i];
l_i = this.enumerate(l_tg, false);
for(--l_i; l_i >= 0; l_i--)
{
l_tgg = l_tg[l_i];
if(l_tgg instanceof SfcThreadGroup) ((SfcThreadGroup)l_tgg).abort();
else l_tgg.interrupt();
}
l_i = this.activeCount();
l_t = new Thread[l_i];
l_i = this.enumerate(l_t, false);
for(--l_i; l_i >= 0; l_i--)
{
l_tt = l_t[l_i];
if(l_tt instanceof SfcThread) ((SfcThread)l_tt).abort();
else l_tt.interrupt();
}
}
} while( (this.activeGroupCount() > 0) ||
(this.activeCount() > 0) );
}
/**
* Tells the activity to stop its actions. This is the proper method to
* allow the activity to terminate itself.
* This method does block until the activity has finished.
* @see #abort()
*/
public final void abort_and_wait ()
{
this.abort();
this.wait_for();
}
/**
* Obtain the event propagator of this thread group. You can use it to
* propagate error events.
* @return The event propagator of this thread group.
*/
public final IEventListener get_propagator ()
{
return this.m_events;
}
/**
* Obtain the name of the thread group.
* @return A human readable name of the sfc thread group.
*/
@Override
public abstract String toString();
}