/********************************************************************
 * Copyright © 2005 VHA. All rights reserved
 ********************************************************************/

package gov.va.med.fw.scheduling;

import gov.va.med.fw.service.AbstractComponent;
import gov.va.med.fw.util.InvalidConfigurationException;

/**
 * Base class for a scheduled process that typically runs on a separate worker thread.
 * 
 * <p>Processes that can have more than one instance running at the same time should
 * be configured as Spring prototype beans (not singleton).  This is necessary for proper
 * handling of process interruption.   
 * 
 * Created Feb 1, 2006 12:07:54 PM
 * 
 * @author DNS   BOHMEG
 */
public abstract class AbstractScheduledProcess extends AbstractComponent
		implements ScheduledProcess {	
	private String auditId;

	boolean interrupted = false;

	public final void invoke() throws Exception {
		invoke(null);
	}

	/**
	 * (non-Javadoc)
	 * 
	 * @see gov.va.med.fw.scheduling.ScheduledProcess#invoke(java.lang.Object)
	 */
	public final void invoke(ScheduledProcessInvocationContext context) throws Exception {
		try {
			if(isInterrupted()) {
				if(logger.isWarnEnabled())
					logger.warn("This ScheduledProcess [" + getAuditInfo() + "] is still in an interrupted state...." +
							"Please wait until it detects this and aborts before trying to execute again.");					
			} else {			
				executeProcess(context);
			}
		} finally {						
			setInterrupted(false);
		}
	}

	public void interrupt() {
		if (logger.isWarnEnabled())
			logger.warn("This ScheduledProcess [" + getAuditInfo() + "] received an interruption request");
		setInterrupted(true);
	}

	public String getAuditInfo(ScheduledProcessInvocationContext context) {
		// default implementation
		return getAuditInfo();
	}
	
	public String getAuditInfo() {
		String auditInfo = auditId != null ? SCHEDULED_PROCESS_AUDIT_PREFIX + auditId
				: SCHEDULED_PROCESS_AUDIT_PREFIX + "Unspecified";
		return auditInfo;
	}

	protected abstract void executeProcess(ScheduledProcessInvocationContext context) throws Exception;

	/**
	 * @return Returns the auditId.
	 */
	public String getAuditId() {
		return auditId;
	}

	/**
	 * @param auditId
	 *            The auditId to set.
	 */
	public void setAuditId(String auditId) {
		this.auditId = auditId;
	}

	/**
	 * @return Returns the interrupted.
	 */
	protected boolean isInterrupted() {
		return interrupted;
	}

	
	/**
	 * @param interrupted The interrupted to set.
	 */
	protected void setInterrupted(boolean interrupted) {
		this.interrupted = interrupted;
	}
	
	
	public void afterPropertiesSet() {
		// this is silly to propagate throws Exception everywhere in this method
		try {
			super.afterPropertiesSet();
		} catch(Exception e) {
			RuntimeException e1 = new InvalidConfigurationException("Invalid configuration for instance of AbstractScheduledProcess");
			e1.initCause(e);
			throw e1;
		}
	}	
}
