/********************************************************************
 * Copyright © 2006 VHA. All rights reserved
 ********************************************************************/
package gov.va.med.fw.service.support;

// Library Classes
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

// Framework Classes
import gov.va.med.fw.service.AbstractComponent;
import gov.va.med.fw.util.TimeoutException;

/**
 * Around advice that will execute a MethodInvocation in a spawned Thread.
 * By default, current execution thread will block until either return or timeout.
 * <p/>
 * Created Apr 10, 2006 5:53:53 PM
 *
 * @author DNS   BOHMEG
 */
public class SpawnedThreadAdvice extends AbstractComponent implements MethodInterceptor
{
    private boolean blocking = true;
    private Integer spawnedThreadTimeout;
    private boolean enabled = true;

    /**
     * @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation)
     */
    public Object invoke(MethodInvocation arg0) throws Throwable, TimeoutException
    {
    	if(!enabled) {
    		return arg0.proceed();
    	}
    	
        SpawnedMethodInvocation mi = new SpawnedMethodInvocation(arg0);
        SpawnedThreadInvoker invoker = new SpawnedThreadInvoker(mi, blocking);
        if(spawnedThreadTimeout != null)
            invoker.setTimeout(spawnedThreadTimeout.intValue());
        invoker.execute();

        if(invoker.isTimedOut()) {
            invoker.abort();
            throw new TimeoutException("Spawned thread has timed out while attempting to call: " + arg0.getMethod().getName());
        }
        else if(invoker.isFailed()) {
            throw invoker.getError();
        }

        return invoker.getResult();
    }

    /**
     * @return Returns the blocking.
     */
    public boolean isBlocking()
    {
        return blocking;
    }

    /**
     * @param blocking The blocking to set.
     */
    public void setBlocking(boolean blocking)
    {
        this.blocking = blocking;
    }

    /**
     * @return Returns the spawnedThreadTimeout.
     */
    public Integer getSpawnedThreadTimeout()
    {
        return spawnedThreadTimeout;
    }

    /**
     * @param spawnedThreadTimeout The spawnedThreadTimeout to set.
     */
    public void setSpawnedThreadTimeout(Integer spawnedThreadTimeout)
    {
        this.spawnedThreadTimeout = spawnedThreadTimeout;
    }

    public void afterPropertiesSet()
    {
        if (spawnedThreadTimeout != null)
        {
            blocking = true;
        }
    }

	/**
	 * @return Returns the enabled.
	 */
	public boolean isEnabled() {
		return enabled;
	}

	/**
	 * @param enabled The enabled to set.
	 */
	public void setEnabled(boolean enabled) {
		this.enabled = enabled;
	}
}
