/**
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 -
 - 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.hls.ont;

import org.jboss.logging.Logger;

import javax.activity.coordination.SignalSet;
import javax.activity.*;

/**
 * Implements the ONT completion signal set. It is triggered when a ONT 
 * activity ends. The ONT signal set provides the activity_committed and 
 * activity_rolledback signals, and responds appropriately to the outcomes 
 * that are generated in response to those signals.
 * @author fran
 * Date: Feb 12, 2004
 * org.objectweb.jass.hls.ontONTCompletionSS.java
 */
public class ONTCompletionSS implements SignalSet {

	private static Logger log = Logger.getLogger(ONTCompletionSS.class);
	
	// Constants --------------------------------------------------------------

	public static final String COMPLETION_SS_NAME = "javax.activity.opennested.ONT";

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

	private int completionStatus;
	private int status;
	private boolean started;
	private boolean finished;
	private ActivityCoordinator ac;	
	private Outcome outcome = null;

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

	/**
	 * ONT completion signal set constructor.
	 * @param name signal set name.
	 */
	public ONTCompletionSS() {		
		started = false;
		finished = false;
	}

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

	// SignalSet implementation -----------------------------------------------

	// OK
	/**
	 * Returns the name of the target SignalSet.
	 */
	public String getSignalSetName() {
		return COMPLETION_SS_NAME;
	}

	/**
	 * Returns the next signal to be sent to the actions registered for the ONT 
	 * completion signal set. If the completion status is success then the 
	 * activity_committed signal is returned. In this case, if the completing 
	 * activity is nested the parent is attached to the signal. If completion 
	 * status is fail, then activity_rollback is returned.
	 */
	public Signal getSignal() {
		Signal signal = null;
		started = true;

		if (!finished) {
			if (completionStatus == CompletionStatus.CompletionStatusSuccess) {

				try {
					log.debug("Signal: activity_committed with parent");
					signal =
						new Signal(
							"activity_committed",
							null,
							(java.io.Serializable) ac.getParent());

				} catch (SystemException e) {
					log.debug("Signal: activity_committed without parent");
					signal =
						new Signal(
							"activity_committed",
							null,
							(java.io.Serializable) null);
				}

			} else if (
				(completionStatus == CompletionStatus.CompletionStatusFail)
					|| (completionStatus
						== CompletionStatus.CompletionStatusFailOnly)) {
				log.debug("Signal: activity_rolledback");
				signal =
					new Signal(
						"activity_rolledback",
						null,
						(java.io.Serializable) null);
			}
			//finished = true;
		}
		return signal;
	}
	
	/**
	 * Called by an ActivityCoordinator to notify the target SignalSet  of the 
	 * Outcome returned by an Action in response to a signal produced 
	 * by the ONT signal set. If parent_has_completed is received, the signal 
	 * set indicates to the ActivityCoordinator that a subsequent signal 
	 * (activity_rolledback signal) shall be distributed. It returns the 
	 * parent_has_completed outcome. If parent_add_failed is received, the 
	 * signal set indicates to the ActivityCoordinator that a subsequent signal 
	 * (activity_rolledback signal) shall be distributed. It returns the 
	 * parent_add_failed outcome. If compensate_failed is received, the signal 
	 * set indicates to the ActivityCoordinator that the same sinal (remember 
	 * it was activity_rolledback) must be sent to any remaining actions, but
	 * no further signals are distributed.
	 */
	public CoordinationInformation setResponse(Outcome response)
		throws SignalSetInactiveException {

		if (!started)
			throw new SignalSetInactiveException();

		CoordinationInformation coordInfo = null;
		String resName = response.getName();
		log.debug("Response: " + resName);

		if (resName.equals("parent_has_completed")
			|| resName.equals("parent_has_failed")) {
			outcome = new Outcome(resName, (java.io.Serializable) null);
			completionStatus = CompletionStatus.CompletionStatusFail;
			coordInfo = new CoordinationInformation(true, true);
		} else if (resName.equals("compensate_failed")) {
			outcome =
				new Outcome(
					"heuristic_cannot_compensate",
					(java.io.Serializable) null);
			coordInfo = new CoordinationInformation(false, false);
		} else
			finished=true;
					
		return coordInfo;
	}

	/**
	 * Returns the consolidated outcome of the signal set  following the 
	 * completion of signaling.
	 */
	public Outcome getOutcome() throws SignalSetActiveException {
		if ((started) && (!finished))
			throw new SignalSetActiveException();
		return outcome;
	}

	/**
	 * Set both the completion status and status before any signals are 
	 * requested. The signals produced may be influenced by these two statuses.
	 */
	public void setCompletionStatus(int completionStatus, int status) {
		this.completionStatus = completionStatus;
		this.status = status;
	}

	/**
	 * Returns the completion status for the activity as the SignalSet  has 
	 * recorded it.
	 */
	public int getCompletionStatus() throws SignalSetActiveException {
		if (!started)
			throw new SignalSetActiveException();
		return completionStatus;
	}

	/**
	 * Sets the activity coordinator for this instance.
	 */
	public void setActivityCoordinator(ActivityCoordinator coord)
		throws SignalSetActiveException {
		if (started)
			throw new SignalSetActiveException();
		ac = coord;
	}

	/**
	 * Clears the main attributes.
	 */
	public void destroy() {
		log.debug("Destroying SignalSet -> " + COMPLETION_SS_NAME);
		ac = null;
		started = false;
		finished = false;
	}
}
