/**
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 -
 - 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.Action;
import javax.activity.*;
import javax.activity.opennested.Compensator;

/**
 * Implements the compensating action required by the ONT model. It may receive
 * the activity_committed and the activity_rollback signals, performing the required
 * tasks in each case.
 * @author fran
 * Date: Feb 12, 2004
 * org.objectweb.jass.hls.ontCompensatingAction.java
 */
public class CompensatingAction implements Action {

	// Contants ---------------------------------------------------------------

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

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

	private Compensator compensator;
	private int priority;

	// Constructors -----------------------------------------------------------
	
	/**
	 * Constructor.
	 * 
	 * @param compensator - the element that compensates a previous task.
	 * @param priority - compensator priority.
	 */
	public CompensatingAction(Compensator compensator, int priority) {
		this.compensator = compensator;
		this.priority = priority;
	}

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

	// Action implementation --------------------------------------------------
	
	/**
	 * Invoked on the target object, by the AS, during signal processing. When 
	 * the activity_committed signal is processed by a ONT action, it means 
	 * that the activity has completted with success. But the compensator 
	 * mantained by this action may be triggered later if other activity fails.
	 * That is why the action must promote its compensator to the parent 
	 * activity. If a parent coordinator reference is found, the Action wraps 
	 * its compensator in a new action that is registered with the parent. 
	 * Depending on the result of the registration, the Action returns the 
	 * parent_add_successful or the parent_has_completed/parent_add_failed 
	 * outcomes. Else if the parent coordinator is null, the action invokes a 
	 * forget operation on the compensator to inform it about the final 
	 * completion and the compensation_successful outcome is returned. If the
	 * action receives the activity_rollback signal, it invokes the compensate 
	 * operation on the Compensator object. If the action fails to invoke the 
	 * Compensator object it returns the outcome compensation_failed.
	 */
	public Outcome processSignal(Signal signal) throws ActionErrorException {
		Outcome result = null;

		if (signal.getName().equals("activity_committed")) {
			ActivityCoordinator parentAC =
				(ActivityCoordinator) signal.getExtendedValue();
			if (parentAC != null) {
				try {
					int priority =
						parentAC.getNumberRegisteredActions(ONTCompletionSS.COMPLETION_SS_NAME);
					parentAC.addAction(
						new CompensatingAction(compensator, 0),
					ONTCompletionSS.COMPLETION_SS_NAME,
						priority);
					result =
						new Outcome(
							"parent_add_successful",
							(java.io.Serializable) null);
					log.debug("OUTCOME: parent_add_successful");
				} catch (IllegalStateException e) {
					result =
						new Outcome(
							"parent_has_completed",
							(java.io.Serializable) null);
					log.debug("OUTCOME: parent_has_completed");
				} catch (Exception e) {
					result =
						new Outcome("parent_add_failed", (java.io.Serializable) null);
					log.debug("OUTCOME: parent_add_failed");
				}
			} else {
				compensator.forget();
				result =
					new Outcome(
						"compensate_successful",
						(java.io.Serializable) null);
				log.debug("OUTCOME: compensate_successful (forget)");
			}
		}

		// We must to invoke the compensate operation
		if (signal.getName().equals("activity_rolledback")) {
			try {
				compensator.compensate();
				result =
					new Outcome(
						"compensate_successful",
						(java.io.Serializable) null);
				log.debug("OUTCOME: compensate_successful (compensation)");
			} catch (Exception e) {
				e.printStackTrace();
				result =
					new Outcome("compensate_failed", (java.io.Serializable) null);
				log.debug("OUTCOME: compensate_failed");
			}
		}
		return result;
	}

	/**
	 * Clears the main attributes.
	 */
	public void destroy() {
		compensator = null;
	}
}
