/*
 * Created on January 10, 2004
 *
 * ResourceAdapterImpl.java is used to test JCA 1.5
 * as implemented by JOnAS. This class implements the ResourceAdapter Interface
 *  
 */
package ersatz.resourceadapter;

import javax.transaction.xa.XAResource;
import javax.transaction.xa.Xid;
import javax.transaction.xa.XAException;
import javax.resource.NotSupportedException;
import javax.resource.spi.endpoint.MessageEndpointFactory;
import javax.resource.ResourceException;
import javax.resource.spi.work.WorkManager;
import javax.resource.spi.work.Work;
import javax.resource.spi.work.WorkException;
import javax.resource.spi.ActivationSpec;
import javax.resource.spi.BootstrapContext;
import javax.resource.spi.ResourceAdapterInternalException;
import java.util.HashMap;

/**
 * @author Bob Kruse
 *
 * JCA1.5 Resource Adapter
 *
 * used to test the J2EE Connector as implemented by JOnAS.
 * 
 */
public class ResourceAdapterImpl 
        implements javax.resource.spi.ResourceAdapter,
                   java.io.Serializable
{
    public String EIS_URL = ""; // should be the RA name when set, ie, ErsatzEIS
    private boolean isReused = false;
    public BootstrapContext bootstrapCtx = null; // set in start()
    private WorkManager wm;
    private WorkAdapterImpl wa;
    private int countWork = 0;
    private transient HashMap   endpointFactories = new HashMap();
    String cName = "ResourceAdapterImpl";
    String reUseError="Application Server attempted to reuse RA";
    private MessageEndpointFactory factory;
    private ActivationSpec spec;
    private Work deliverWork;

    public ResourceAdapterImpl() { // constructor
    }

    public String getEIS_URL() {
        Utility.log(cName+".getEIS_URL "+EIS_URL);
        return EIS_URL;
    }
    public void setEIS_URL(String EIS_URL) {  // ra.xml deployment supplies value
        Utility.log(cName+".setEIS_URL "+EIS_URL);
        this.EIS_URL = EIS_URL;
    }
    public int isWorkStarted()
    {
        return countWork;
    }
    public void start(BootstrapContext bootstrapCtx)
        throws ResourceAdapterInternalException
    {
        this.bootstrapCtx=bootstrapCtx;
        if (isReused) {
            Utility.log(cName+".start Error: "+reUseError);
            throw new ResourceAdapterInternalException(reUseError);
        }
        Utility.log(cName+".start "
                  +"Functional resource adapter instance created");
        if (EIS_URL.equals("ErsatzEIS")) {
            try {
                engageWorkManager();
            } catch (Exception e) {
                // TODO is more logic needed here?
                throw new ResourceAdapterInternalException(e.toString());
            } catch (Throwable t) {
                throw new ResourceAdapterInternalException(t.toString());
            }
        }
    }
    private void engageWorkManager() throws Exception
    {
        Utility.log(cName+".engageWorkManager [enter]");
        // get WorkManager reference
        wm = bootstrapCtx.getWorkManager();
        //  TODO setup network endpoints
        //
        //  provide 3 Work objects to WorkManager
        //
        Work work=null;
        for (int i=1; i<4; i++) {
            try {
                work = new WorkImpl("work"+i);
            } catch (Exception e) {
                Utility.log(cName
                +".engageWorkManager error: new WorkImpl(work"+i+") failed. exception="+e.toString());
                throw e;
            }
            // create instance of WorkAdapter as the WorkListener
            if (i==1) createWorkAdapter();

            if (i==1) {
                // test #1 "startWork()"
                try {
                    wm.startWork(work);
                    ++countWork;
                    Utility.log(cName+".engageWorkManager startWork(work"+i+")");
                } catch (Exception e) {
                    Utility.log(cName
                    +".engageWorkManager error: startWork(work"+i+") returned exception="+e.toString());
                    throw e;
                }
            }
            if (i==2) {
                // test #2 "scheduleWork()"
                try {
                    wm.scheduleWork(work);
                    ++countWork;
                    Utility.log(cName+".engageWorkManager scheduleWork(work"+i+")");
                } catch (Exception e) {
                    Utility.log(cName
                    +".engageWorkManager error: scheduleWork(work"+i+") returned exception="+e.toString());
                    throw e;
                }
            }
            if (i==3) {
                // test #3 "doWork()"
                try {
                    wm.doWork(work);
                    ++countWork;
                    Utility.log(cName+".engageWorkManager doWork(work"+i+")");
                } catch (Exception e) {
                    Utility.log(cName
                    +".engageWorkManager error: doWork(work"+i+") returned exception="+e.toString());
                    throw e;
                }
            }
        }
    
    }
    private void createWorkAdapter()
    {
        wa=new WorkAdapterImpl();
    }
    public void stop()
    {
        Utility.log(cName+".stop "+EIS_URL);
        isReused=true;
        release();
    }

    public void release()
    {
        Utility.log(cName+".release");
    }

    /** Called by the application server when a message-driven bean 
     * (MessageEndpoint) is deployed.
     * 
     */
    public void endpointActivation(MessageEndpointFactory factory, ActivationSpec spec)
        throws NotSupportedException, ResourceAdapterInternalException
    {
        Utility.log(cName+".endpointActivation. MessageEndpointFactory="+factory);
        Utility.log(cName+".endpointActivation. ActivationSpec="+spec);
        Utility.log(cName+".endpointActivation. RA name="+EIS_URL);
        this.factory=factory;
        this.spec=spec;
        
        if (isReused) {
            Utility.log(cName+".endpointActivation Error: "+reUseError);
            throw new ResourceAdapterInternalException(reUseError);
        }
        if ( ! (spec instanceof ActivationSpecImpl))
        {
            Utility.log(cName+".endpointActivation Invalid spec error");
            throw new NotSupportedException("invalid spec");
        }
        try {
            endpointFactories.put(spec, factory);
        } catch (Exception e) {
            Utility.log(cName+".endpointActivation put(spec, factory) Error: "+e);
            throw new ResourceAdapterInternalException(e.toString());
        }

    }

    public void endpointDeactivation(MessageEndpointFactory factory, ActivationSpec spec)
    {
        Utility.log(cName+".endpointDeactivation for RA name="+EIS_URL);
        endpointFactories.remove(spec);
    }

    public XAResource[] getXAResources(ActivationSpec[] specs)
        throws ResourceException
    {
        XAResource[] X = null;
        Utility.log(cName+".getXAResources only returns null");
        /*
         * Do nothing
         */
        
        return X;
    }
    //
    //        Deliver Message to Work Object   called by InboundCASLR.java
    //
    public boolean deliverMsg(String msg) throws Exception
    {
        Utility.log(cName+".deliverMsg factory="+factory+" ActivationSpecImpl="+spec);
        if (factory==null) {
            String s="End point factory==null";
            throw new Exception(cName+".deliverMsg"+s);
        }
        try {
            deliverWork = new WorkImpl(factory, msg);
            Utility.log(cName+".deliverMsg created WorkImpl object");
        } catch (Exception e) {
            Utility.log(cName
            +".deliverMsg error: new WorkImpl() failed. exception="+e.toString());
            throw e;
        }
        try {
            if (wa==null) createWorkAdapter();
            wm.startWork(deliverWork,wm.INDEFINITE,null,wa);
            Utility.log(cName+".deliverMsg executed startWork(). Examin trace for WorkAdapterImpl results.");
        } catch (WorkException we) {
            Utility.log(cName
            +".deliverMsg error: wm.startWork failed. WorkException="+we.toString());
            throw we;
        } catch (Exception ee) {
            Utility.log(cName
            +".deliverMsg error: wm.startWork failed. exception="+ee.toString());
            throw ee;
        }
        return true;
    }
}