/**
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 -
 - JASS: Java Advanced tranSaction Support
 -
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 -
 - This module was originally developed by 
 -
 -    LSD (Distributed Systems Lab, http://lsd.ls.fi.upm.es/lsd/lsd.htm)
 -    at Universidad Politecnica de Madrid (UPM) as an ObjectWeb Consortium
 -    (http://www.objectweb.org) project.
 -
 -    This project has been partially funded by the European Commission under
 -    the IST programme of V FP grant IST-2001-37126 and by the Spanish
 -    Ministry of Science & Technology (MCyT) grants TIC2002-10376-E and
 -    TIC2001-1586-C03-02
 -
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 -  The original code and portions created by LSD are 
 -  Copyright (c) 2004 LSD (UPM)  
 -  All rights reserved.
 -  
 - Redistribution and use in source and binary forms, with or without 
 - modification, are permitted provided that the following conditions are met:
 -
 - -Redistributions of source code must retain the above copyright notice, this
 - list of conditions and the following disclaimer. 
 -
 - -Redistributions in binary form must reproduce the above copyright notice, 
 - this list of conditions and the following disclaimer in the documentation 
 - and/or other materials provided with the distribution. 
 -
 - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
 - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
 - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
 - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
 - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
 - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
 - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
 - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
 - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
 - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
 - POSSIBILITY OF SUCH DAMAGE.
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 -
 -  Author: Francisco Perez Sorrosal (frperezs)
 -
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/

package org.objectweb.jass.as;

import java.io.Serializable;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import javax.activity.ActivityCompletedException;
import javax.activity.ActivityCoordinator;
import javax.activity.ActivityNotProcessedException;
import javax.activity.ActivityPendingException;
import javax.activity.CompletionStatus;
import javax.activity.ContextPendingException;
import javax.activity.GlobalId;
import javax.activity.InvalidActivityException;
import javax.activity.InvalidStateException;
import javax.activity.NoActivityException;
import javax.activity.NoImplementException;
import javax.activity.NotOriginatorException;
import javax.activity.Outcome;
import javax.activity.PropertyGroupUnknownException;
import javax.activity.ServiceAlreadyRegisteredException;
import javax.activity.ServiceInformation;
import javax.activity.ServiceNotRegisteredException;
import javax.activity.SignalSetUnknownException;
import javax.activity.Status;
import javax.activity.SystemException;
import javax.activity.TimeoutRangeException;
import javax.activity.UserActivity;
import javax.activity.coordination.ServiceManager;
import javax.activity.propertygroup.PropertyGroup;
import javax.activity.propertygroup.PropertyGroupManager;

import org.apache.log4j.Logger;

/**
 * Implements the access interface to the AS (UserActivity) available to HLSs.
 * @author fran
 * Date: Feb 12, 2004
 * org.objectweb.jass.asUserActivityImpl.java
 */
public class UserActivityImpl implements UserActivity, Serializable {

	// Constants --------------------------------------------------------------

	// Default timeout in seconds. Zero, means no timeout for activities
	public static int DEFAULT_TIMEOUT = 0;
	public static String SYNCHRONIZATION_SS_NAME =
		"org.omg.CosActivity.Syncrhonization";
	public static String CHILDLIFETIME_SS_NAME =
		"org.omg.CosActivity.ChildLifetime";

	// Attributes -------------------------------------------------------------

	private static Logger log = Logger.getLogger(UserActivityImpl.class);

	// A refercence to the unique Activity Id Generator
	private static ActivityIdGenerator activityIdGenerator = null;

	// The ServiceManager asociated with each instance of UserActivity
	protected ServiceManager sm = null;
	// Information about the registered ServiceManager
	private ServiceInformation serviceInformation = null;
	// TODO : PropertyGroupManagers
	private HashMap propertyGroupManagers = new HashMap();
	// A table which contains non-finalized activities
	// The keys are the Ids of the activities
	private Map activities = Collections.synchronizedMap(new HashMap());
	// DefaultTimeout for activities started here
	private int defaultTimeout = DEFAULT_TIMEOUT;

	// Constructors -----------------------------------------------------------

	/**
	 * Default Constructor. It takes count of the number of service 
	 * instances created.
	 */
	public UserActivityImpl() {

		instances = instances + 1;
		log.debug(
			Thread.currentThread().getName()
				+ " UserActivity instance number "
				+ instances
				+ " has been created");
	}

	// Public -----------------------------------------------------------------

	// UserActivity implementation --------------------------------------------

	/**
	 * Create a new Activity and associate it with the current thread.
	 * 
	 * @param timeout - the period (in seconds) within which the Activity
	 * must be completed. If it is not completed within this period then
	 * it is subject to being completed by the Activity service with
	 * the CompletionStatusFail status.
	 * @throws InvalidStateException - Thrown if the parent Activity has
	 * been marked as CompletionStatusFailOnly.
	 * @throws ServiceNotRegisteredException - Thrown if no ServiceManager
	 * has been registered.
	 * @throws TimeoutRangeException - Thrown if timeout is less than -1 or
	 * if it is outside an administratively configured range in the deployed
	 * system.
	 * @throws SystemException
	 */
	public void begin(int timeout)
		throws
			InvalidStateException,
			ServiceNotRegisteredException,
			TimeoutRangeException,
			SystemException {

		ActivityImpl newActivity = null; // The new activity...
		ActivityIdImpl activityId = null; // ...and its Id
		// Ancestror of the new created Activity
		ActivityImpl superior = null;

		boolean child = false; // Identifies the beginnig of a child activity

		if (activityIdGenerator == null)
			throw new SystemException("ActivityIdGenerator is not set !!!!!");
		if (sm == null)
			throw new ServiceNotRegisteredException();
		if (timeout < -1)
			throw new TimeoutRangeException();

		ThreadInfo ti = getThreadInfo();
		ActivityImpl currentActivity = ti.activity;

		// If the currentActivity is not null, then new activity will be a
		// child and its superior will be the current activity.
		if (currentActivity != null) {
			superior = currentActivity;
			if (superior.getCompletionStatus()
				== CompletionStatus.CompletionStatusFailOnly)
				throw new InvalidStateException();
			child = true;
			disassociateThread(ti);
			log.info("Starting a CHILD activity of " + superior.getName());
		} else
			log.info("Starting a ROOT activity");

		// New Activity Id generation
		activityId = activityIdGenerator.newActivityId();

		if (timeout == -1)
			newActivity = new ActivityImpl(this, activityId, superior, 0);
		else if (timeout == 0)
			newActivity =
				new ActivityImpl(this, activityId, superior, defaultTimeout);
		else
			newActivity = new ActivityImpl(this, activityId, superior, timeout);

		// Put the activity in the non-finalized activities HashMap
		activities.put(activityId, newActivity);
		// Make active the new activity context
		associateThread(ti, newActivity);

		if (child) {
			// Tell the parent that the new activity is a child of the actual
			superior.addChild(newActivity);
			// Now the child activity context is the active context on the thread
			// TODO : Process the ChildLifetimeSS.
			// TODO : SEE Activity Service Spec. (Pg.31)
		}
	}

	/**
	 * Causes the active Activity context to complete with the specified
	 * CompletionStatus. If a CompletionSignalSet is used by the registered
	 * ServiceManager, then it will be driven by the Activity service to obtain
	 * completion signals to distribute to any registered Actions. If the
	 * Activity is nested within a parent, then the parent Activity becomes
	 * associated with the thread on completion of this operation. If there are
	 * any child active or suspended Activities or transactions and the
	 * CompletionStatus is CompletionStatusFail or CompletionStatusFailOnly
	 * then those child Activites will have their CompletionStatuses set to
	 * CompletionStatusFailOnly and any child transaction will be called to
	 * setRollbackOnly.
	 * 
	 * @param completionStatus
	 * @return
	 */
	public Outcome completeWithStatus(int completionStatus)
		throws
			NoActivityException,
			ActivityPendingException,
			ContextPendingException,
			ServiceNotRegisteredException,
			NotOriginatorException,
			InvalidStateException,
			ActivityNotProcessedException,
			SystemException {

		log.debug("completeWithStatus " + Thread.currentThread().getName());
		Outcome out = null;

		if (sm == null)
			throw new ServiceNotRegisteredException();

		ThreadInfo ti = getThreadInfo();
		ActivityImpl currentActivity = ti.activity;
		if (currentActivity == null)
			throw new NoActivityException();

		int compStat = getCompletionStatus();
		ActivityImpl[] childs = currentActivity.getChilds();
		if ((compStat == CompletionStatus.CompletionStatusSuccess)
			&& (childs != null))
			throw new ContextPendingException();

		try {
			// Before completing the activity, we set the completion status
			currentActivity.setCompletionStatus(completionStatus);
			out = currentActivity.completeActivity();
			currentActivity = (ActivityImpl) disassociateThread(ti);
			if (currentActivity.getParent() != null) {
				associateThread(ti, (ActivityImpl) currentActivity.getParent());
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

		return out;
	}

	/**
	 * Causes the active Activity context to be completed with its current 
	 * CompletionStatus. If a CompletionSignalSet is used by the registered 
	 * ServiceManager, then it will be driven by the Activity service to obtain 
	 * completion signals to distribute to any registered Actions. If the 
	 * Activity is nested within a parent, then the parent Activity becomes 
	 * associated with the thread on completion of this operation. If there are 
	 * any child active or suspended Activities or transactions and the 
	 * CompletionStatus is CompletionStatusFail or CompletionStatusFailOnly 
	 * then those child Activites will have their CompletionStatus set to 
	 * CompletionStatusFailOnly and any child transaction will be called to 
	 * setRollbackOnly.
	 * 
	 * @return The Outcome returned is both set by and given meaning by the SignalSet used for
	 * completion. In the absence of a CompletionSignalSet a null Outcome object reference
	 * is returned.
	 */
	public Outcome complete()
		throws
			NoActivityException,
			ActivityPendingException,
			ContextPendingException,
			ServiceNotRegisteredException,
			NotOriginatorException,
			ActivityNotProcessedException,
			SystemException {

		log.debug("complete " + Thread.currentThread().getName());
		Outcome out = null;

		if (sm == null)
			throw new ServiceNotRegisteredException();

		ThreadInfo ti = getThreadInfo();
		ActivityImpl currentActivity = ti.activity;
		if (currentActivity == null)
			throw new NoActivityException();

		int compStat = getCompletionStatus();
		ActivityImpl[] childs = currentActivity.getChilds();
		if ((compStat == CompletionStatus.CompletionStatusSuccess)
			&& (childs != null))
			throw new ContextPendingException();

		try {
			out = currentActivity.completeActivity();
			currentActivity = (ActivityImpl) disassociateThread(ti);
			if (currentActivity.getParent() != null) {
				associateThread(ti, (ActivityImpl) currentActivity.getParent());
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return out;
	}

	/** OK
	 * Sets the CompletionStatus of the active Activity. This method may be
	 * called multiple times before the Activity is completed, and the
	 * CompletionStatus may be changed between CompletionStatusSuccess and
	 * CompletionStatusFail to indicate a point in time value. Once the
	 * CompletionStatus has been set to  CompletionStatusFailOnly, it may not
	 * be changed again.
	 * 
	 * @param completionStatus - the CompletionStatus  value to set.
	 * @throws NoActivityException - Thrown if there is no Activity associated
	 * with the calling thread of execution.
	 * @throws InvalidStateException - Thrown if an attempt is made to update a
	 * CompletionStatus of CompletionStatusFailOnly or if a null  or invalid
	 * value is specified by completionStatus.
	 * @throws ServiceNotRegisteredException - Thrown if no ServiceManager has
	 * been registered.
	 * @throws SystemException
	 */
	public void setCompletionStatus(int completionStatus)
		throws
			NoActivityException,
			InvalidStateException,
			ServiceNotRegisteredException,
			SystemException {

		if (sm == null)
			throw new ServiceNotRegisteredException();

		ThreadInfo ti = getThreadInfo();
		ActivityImpl currentActivity = ti.activity;

		if (currentActivity == null)
			throw new NoActivityException();
		if (currentActivity.getCompletionStatus()
			== CompletionStatus.CompletionStatusFailOnly)
			throw new InvalidStateException();

		// All conditions are OK
		currentActivity.setCompletionStatus(completionStatus);
	}

	//OK
	/**
	 * Returns the current value of the CompletionStatus  of the active
	 * Activity.
	 * 
	 * @return The CompletionStatus of the active Activity.
	 * @throws ServiceNotRegisteredException - Thrown if there is no Activity
	 * associated with the calling thread of execution.
	 * @throws NoActivityException - Thrown if no ServiceManager has been
	 * registered.
	 * @throws SystemException - Thrown if the Activity service encounters an
	 * unexpected error condition.
	 */
	public int getCompletionStatus()
		throws ServiceNotRegisteredException, NoActivityException, SystemException {

		if (sm == null)
			throw new ServiceNotRegisteredException();

		ThreadInfo ti = getThreadInfo();
		ActivityImpl currentActivity = ti.activity;

		if (currentActivity == null)
			throw new NoActivityException();

		return currentActivity.getCompletionStatus();
	}

	/**
	 * Returns the current value of the Status  of the active Activity.
	 * 
	 * @return The Status of the active Activity.
	 * @throws ServiceNotRegisteredException Thrown if no ServiceManager
	 * has been registered.
	 * @throws SystemException Thrown if the Activity service encounters an
	 * unexpected error condition.
	 */
	public int getStatus()
		throws ServiceNotRegisteredException, SystemException {

		if (sm == null)
			throw new ServiceNotRegisteredException();

		ThreadInfo ti = getThreadInfo();
		ActivityImpl currentActivity = ti.activity;

		if (currentActivity != null)
			return currentActivity.getStatus();
		else
			throw new SystemException();
	}

	// OK
	/**
	 * Returns a printable string describing the active Activity.
	 * 
	 * @return a printable string describing the active Activity.
	 * If no Activity is associated with the calling thread then null is returned.
	 * @throws ServiceNotRegisteredException Thrown if no ServiceManager has been registered.
	 * @throws SystemException - Thrown if the Activity service encounters an unexpected error condition.
	 */
	public java.lang.String getName()
		throws ServiceNotRegisteredException, SystemException {

		if (sm == null)
			throw new ServiceNotRegisteredException();

		ThreadInfo ti = getThreadInfo();
		ActivityImpl currentActivity = ti.activity;

		if (currentActivity != null)
			return currentActivity.getName();
		else
			throw new SystemException();
	}

	// OK
	/**
	 * Sets the default timeout, in seconds, after which an Activity may
	 * be automatically completed by the Activity service.
	 * 
	 * @param timeout - the default timeout period (in seconds) used by
	 * any future Activities begun with a timeout value of zero. This default
	 * is used for an Activity that is begun with a timeout parameter value
	 * of 0.
	 * A value of -1 indicates no timeout. A value of 0 for the default timeout
	 * indicates that a system-managed value or implementation-specific default
	 * should be used. The timeout is a useful mechanism for protecting against
	 * clients that fail to end an Activity in a timely fashion.
	 * @throws ServiceNotRegisteredException - Thrown if no ServiceManager
	 * has been registered.
	 * @throws TimeoutRangeException - Thrown if timeout is less
	 * than -1 or if it is outside an administratively configured range
	 * in the deployed system.
	 * @throws SystemException - Thrown if the Activity service encounters an
	 * unexpected error condition.
	 */
	public void setTimeout(int timeout)
		throws ServiceNotRegisteredException, TimeoutRangeException, SystemException {

		if (timeout < -1)
			throw new TimeoutRangeException();

		// A default timeout of 0 implies the use of the default timeout value,
		// represented by DEFAULT_TIMEOUT constant
		if (timeout == 0)
			defaultTimeout = DEFAULT_TIMEOUT;
		else
			defaultTimeout = timeout;
	}

	// OK
	/**
	 * Returns the default timeout value.
	 * 
	 * @return The default timeout value, in seconds.
	 * @throws ServiceNotRegisteredException - Thrown if no ServiceManager
	 * has been registered.
	 * @throws SystemException
	 */
	public int getTimeout()
		throws ServiceNotRegisteredException, SystemException {

		if (sm == null)
			throw new ServiceNotRegisteredException();

		return defaultTimeout;
	}

	// OK
	/**
	 * Returns the GlobalId of the active Activity.
	 * 
	 * @return The GlobalId of the active Activity,
	 * or null if there is no Activity associated with the thread.
	 * @throws ServiceNotRegisteredException
	 * @throws SystemException
	 */
	public GlobalId getGlobalId()
		throws ServiceNotRegisteredException, SystemException {

		if (sm == null)
			throw new ServiceNotRegisteredException();

		ThreadInfo ti = getThreadInfo();
		ActivityImpl currentActivity = ti.activity;

		if (currentActivity != null)
			return currentActivity.getGlobalId();
		else
			return null;
	}

	/**
	 * Causes the SignalSet specified by signalSetName to start producing
	 * signals for all registered Actions. This method is used to distribute
	 * Signals to Actions at times other than during completion. Pre-defined
	 * SignalSets, such as Synchronization, cannot be requested to produce
	 * signals via this method.
	 * 
	 * @param signalSetName - the name of the SignalSet that is to produce the
	 * signals.
	 * @return The Outcome returned is both set by and given meaning by the
	 * SignalSet. A null Outcome object reference may be returned if the
	 * SignalSet does not produce an Outcome.
	 * @throws NoActivityException- Thrown if there is no Activity associated
	 * with the calling thread of execution.
	 * @throws SignalSetUnknownException
	 * @throws ServiceNotRegisteredException - Thrown if no ServiceManager has
	 * been registered.
	 * @throws InvalidActivityException Thrown if an attempt is made to use the
	 * Synchronization or ChildLifetime SignalSets, or if the Activity is in
	 * the process of completion.
	 * @throws ActivityNotProcessedException
	 * @throws SystemException
	 */
	public Outcome broadcast(java.lang.String signalSetName)
		throws
			NoActivityException,
			SignalSetUnknownException,
			ServiceNotRegisteredException,
			InvalidActivityException,
			ActivityNotProcessedException,
			SystemException {

		if (sm == null)
			throw new ServiceNotRegisteredException();

		ThreadInfo ti = getThreadInfo();
		ActivityImpl currentActivity = ti.activity;

		if (currentActivity == null)
			throw new NoActivityException();
		if ((signalSetName.equals(SYNCHRONIZATION_SS_NAME))
			|| (signalSetName.equals(SYNCHRONIZATION_SS_NAME))
			|| currentActivity.getStatus() == Status.StatusCompleting)
			throw new InvalidActivityException();

		return currentActivity.processSignalSet(
			signalSetName,
			currentActivity.getStatus());
	}

	// OK
	/**
	 * Returns the ActivityCoordinator of the active Activity,
	 * or null if there is no Activity associated with the calling thread.
	 * 
	 * @return ActivityCoordinator of the active Activity
	 * @throws ServiceNotRegisteredException
	 * @throws NoImplementException
	 * @throws SystemException
	 */
	public ActivityCoordinator getCoordinator()
		throws ServiceNotRegisteredException, NoImplementException, SystemException {

		if (sm == null)
			throw new ServiceNotRegisteredException();

		ThreadInfo ti = getThreadInfo();
		ActivityImpl currentActivity = ti.activity;

		if (currentActivity != null)
			return currentActivity;
		else
			return null;
	}

	// OK
	/** 
	 * Returns the ActivityCoordinator of the parent of the active Activity, or
	 * null if the active Activity is a top-level Activity. In some execution 
	 * environments, such as a J2EE client, this method need not be implemented 
	 * and calling it may result in a NoImplementationException.
	 * 
	 * @return The ActivityCoordinator  of the active Activity. If there is no Activity
	 * associated with the calling thread then a null object reference is returned.
	 * @throws ServiceNotRegisteredException - Thrown if no ServiceManager  has been registered.
	 * @throws NoImplementException - Thrown if the Activity service does not provide an implementation
	 * of this method in the calling environment, for example if a J2EE client
	 * calls this method.
	 * @throws SystemException
	 */
	public ActivityCoordinator getParentCoordinator()
		throws ServiceNotRegisteredException, NoImplementException, SystemException {

		if (sm == null)
			throw new ServiceNotRegisteredException();

		ThreadInfo ti = getThreadInfo();
		ActivityImpl currentActivity = ti.activity;

		if ((currentActivity != null) && (currentActivity.getParent() != null))
			return currentActivity.getParent();
		else
			return null;
	}

	/**
	 * NOT YET IMPLEMENTED
	 */
	public PropertyGroup getPropertyGroup(java.lang.String name)
		throws
			PropertyGroupUnknownException,
			ServiceNotRegisteredException,
			NoActivityException,
			SystemException {

		return null;
	}

	/**
	 * Registers a ServiceManager for the type of high-level service (HLS) whose activities
	 * are to be demarcated through the target UserActivity instance. The Activity service uses
	 * the properties of the registered ServiceManager to create and operate on Activities specific
	 * to that service. The UserActivity (or specialised ActivityManager) instance requires a
	 * ServiceManager to be registered with it before it may be used to begin new Activities.
	 * 
	 * @param service - the ServiceManager for the HLS whose activities are to be demarcated
	 * through the target UserActivity instance.
	 * @throws PropertyGroupUnknownException - Thrown if the ServiceManager cannot obtain a
	 * PropertyGroupManager for one or more of the PropertyGroups it uses.
	 * @throws ServiceAlreadyRegisteredException - Thrown if a ServiceManager has already
	 * been registered with the UserActivity instance.
	 * @throws SystemException
	 */
	public void registerService(ServiceManager service)
		throws
			PropertyGroupUnknownException,
			ServiceAlreadyRegisteredException,
			SystemException {

		String[] propertyGroupNames = null;

		if (sm != null)
			throw new ServiceAlreadyRegisteredException();

		sm = service;
		serviceInformation = sm.getServiceInformation();
		propertyGroupNames = sm.getPropertyGroupNames();
		if (propertyGroupNames != null) {
			for (int i = 0; i < propertyGroupNames.length; i++)
				try {
					PropertyGroupManager pgm =
						sm.getPropertyGroupManager(propertyGroupNames[i]);
					propertyGroupManagers.put(propertyGroupNames[i], pgm);
				} catch (PropertyGroupUnknownException e) {
					throw new PropertyGroupUnknownException();
				}
		}
		log.info(
			"Service Manager "
				+ serviceInformation.getServiceName()
				+ " has been registered");

	}

	/**
	 * Returns the registered ServiceManager for this UserActivity instance.
	 * 
	 * @return The ServiceManager for this UserActivity instance, or null if none
	 * has been registered.
	 * @throws SystemException
	 */
	public ServiceManager getService() throws SystemException {

		if (sm != null)
			return sm;
		else
			return null;
	}

	/**
	 * NOT YET IMPLEMENTED
	 */
	public ActivityCoordinator recreate(
		GlobalId activity,
		GlobalId parent,
		boolean resume)
		throws
			ServiceNotRegisteredException,
			ActivityCompletedException,
			java.lang.IllegalArgumentException,
			SystemException {

		return null;
	}

	/**
	 * NOT YET IMPLEMENTED
	 */	
	public GlobalId[] recover()
		throws ServiceNotRegisteredException, SystemException {

		return null;
	}

	/**
	 * NOT YET IMPLEMENTED
	 */
	public void forget(GlobalId globalId)
		throws ServiceNotRegisteredException, SystemException {

	}

	// My Public ------------------------------------------------------------------

	/**
	 * Sets the Activity Id Generator for all Activity Service instances.
	 * 
	 * @param generator - A reference to the unique ActivityIdGenerator
	 */
	public static void setActivityIdGenerator(ActivityIdGenerator generator) {
		activityIdGenerator = generator;
	}

	/**
	 * Return the number of activities in the activities HashMap.
	 * 
	 * @return Number of activities currently in the HashMap.
	 */
	public int getNumberOfActivities() {
		return activities.size();
	}

	// My Private -----------------------------------------------------------------

	private void completeChilds(ActivityImpl currentActivity) {
		try {
			int compStat = getCompletionStatus();
			if ((compStat == CompletionStatus.CompletionStatusFail)
				|| (compStat == CompletionStatus.CompletionStatusFailOnly)) {
				// Complete nested activities with CompletionStatusFailOnly
				// if they are active or suspended
				ActivityImpl[] childs = currentActivity.getChilds();

				for (int i = 0; i < childs.length; i++) {
					if (childs[i].getStatus() == Status.StatusActive)
						childs[i].setCompletionStatus(
							CompletionStatus.CompletionStatusFailOnly);
				}
			}
		} catch (ServiceNotRegisteredException e) {
			e.printStackTrace();
		} catch (NoActivityException e) {
			e.printStackTrace();
		} catch (SystemException e) {
			e.printStackTrace();
		} catch (InvalidStateException e) {
			e.printStackTrace();
		}
	}

	// My Protected ---------------------------------------------------------------

	// Local thread info
	protected ThreadLocal threadActivity = new ThreadLocal();

	/**
	 * Obtains the info associated with the current thread
	 * @return Information associated with the current thread
	 */
	protected ThreadInfo getThreadInfo() {

		ThreadInfo ret = (ThreadInfo) threadActivity.get();

		if (ret == null) {
			ret = new ThreadInfo();
			threadActivity.set(ret);
		}

		return ret;
	}

	/**
	 * Provides the association of an activity to a thread.
	 * 
	 * @param ti - current thread info.
	 * @param activity - the activity.
	 */
	protected void associateThread(ThreadInfo ti, ActivityImpl activity) {

		ti.activity = activity;
		activity.associateCurrentThread();
	}

	/**
	 * Provides the disassociation of an activity from a thread.
	 * 
	 * @param ti - current thread info.
	 * @return - the activity currently associated with the thread
	 */
	protected ActivityCoordinator disassociateThread(ThreadInfo ti) {

		ActivityImpl current = ti.activity;
		ti.activity = null;
		current.disassociateCurrentThread();

		return current;
	}

	/**
	 * Removes the specified activity from the activities HashMap.
	 * 
	 * @param activity - the activity to remove.
	 */
	protected void releaseActivityImpl(ActivityImpl activity) {
		try {
			activities.remove(activity.getGlobalId());
		} catch (SystemException e) {
			e.printStackTrace();
		}
		log.debug("Activities in this instance " + activities.size());
	}

	// Inner classes --------------------------------------------------------------

	/**
	 * The thread-associated activity.
	 */
	static class ThreadInfo {
		ActivityImpl activity;
	}

	// Debug ----------------------------------------------------------------------

	private static int instances = 0;

	public static int getInstances() {
		return instances;
	}

	// End Debug ------------------------------------------------------------------

}