/*
 * Created on December 11, 2003
 *
 * ManagedConnectionImpl.java is a Resource Adapter class to test the J2EE Connector
 * as implemented by JOnAS.
 */
package ersatz.resourceadapter;

import java.io.PrintWriter;
import java.util.Date;
import java.util.Vector;  // <=========
import javax.security.auth.Subject;
import javax.resource.ResourceException;
import javax.resource.spi.ConnectionEvent;
import javax.transaction.xa.XAResource;
import javax.resource.spi.ManagedConnectionFactory;
import javax.resource.spi.ConnectionEventListener;
import javax.resource.spi.ConnectionManager;
import javax.resource.spi.ConnectionRequestInfo;
import javax.resource.spi.LocalTransaction;
import javax.resource.spi.ManagedConnection;
import javax.resource.spi.ManagedConnectionMetaData;

/**
 * @author Bob Kruse
 *
 * used to test the J2EE Connector as implemented by JOnAS.
 *
 */
public class ManagedConnectionImpl 
	implements ManagedConnection
{
    String Id = "";
    private String userName="";  
    private String password="";
    private ManagedConnectionFactory mcf;     // loaded by ManagedConnectionFactory
    public ConnectionManager cm;              // loaded by ManagedConnectionFactory
    private ConnectionRequestInfoImpl crii;
    public LocalTransactionImpl loTx=null;
	PrintWriter pw;                            // App Server sets to null by default
    private Vector listeners;
    //Managed environment
    public String res_auth;  // set by ConnectionFactory.getConnection()
                              // then put into ManagedConnection when created
    public String re_authentication_UserName;  // set by ConnectionFactory.getConnection()
    public String re_authentication_Password;
    public XAResource     xar;
    public XAResourceImpl xari;
    boolean closed;
    public ConnectionImpl cHandle;    // ManagedConnection mapped 1:1 to a physical connection
    private boolean destroyed;        //set when destroyed
    public boolean inXATrans;
    public boolean inLocalTrans;
    public boolean sendEvent;
    String cName = "ManagedConnectionImpl";
                                        
    //
    // constructor 
    public ManagedConnectionImpl(ConnectionRequestInfoImpl CRII)
    {
        crii = new ConnectionRequestInfoImpl(CRII);
        userName=crii.userName;
        password=crii.password;
        closed    = true;        
        listeners = new Vector();
        pw        = null;
        xar       = null;        
        xari      = null;
        loTx      = null;        
    }
    public void setUserName(String u) {
        userName=u;
        Utility.log(cName+".setUserName="+u);
    }
    public void setPassword(String p) {
        password=p;
        Utility.log(cName+".setPassword="+p);
    }
    public void setRes_Auth(String r) {
        res_auth=r;
        Utility.log(cName+".setRes_Auth="+r);
    }
	//
	// Referenced classes of package javax.resource.spi:
	//            ConnectionRequestInfo, ConnectionEventListener, LocalTransaction, 
	//            ManagedConnectionMetaData
    //
    // NOTE: Subject is instantiated by Application Server
    //
    public int cntListeners() {
        Vector lst = (Vector) listeners.clone();
        int len = lst.size();
        Utility.log(cName+".cntListeners counted="+len);
        return len;
    }
    public ConnectionImpl getCHandle() {
        return cHandle; 
    }
    public boolean isClosed() {
        return closed;
    }
    public ConnectionRequestInfoImpl getCrii() {
        return crii;
    }
        
	public Object getConnection(Subject subject, ConnectionRequestInfo connectionrequestinfo)
		throws ResourceException 
	{
        Utility.log(cName+".getConnection *******************");
        if (subject!=null) {
            // 
            //  for this code to execute, the following will be present in ra.xml
            //   <reauthentication-support>true</reauthentication-support>
            // 
            Utility.log(cName+".getConnection via PasswordCredential");
            Utility.log("<reauthentication-support>true</reauthentication-support>");
            try {
                // TODO Find out about org.ietf.jgss.GSSCredential interface in J2SE 1.4
            } catch (Exception e) {
                Utility.log(cName+".getConnection getPasswordCredential error: e="
                             +e.toString());
            }
        } 
        // Code for reauthentication-support when Subject==null and ConnectionRequestInfo
        // contains different password and username
        //
        if (connectionrequestinfo!=null) {
            Utility.log(cName+".getConnection via ConnectionRequestInfo");
            Utility.log("<reauthentication-support>true</reauthentication-support>");
            ConnectionRequestInfoImpl cri = (ConnectionRequestInfoImpl)connectionrequestinfo;
            String re_authentication_UserName = new String(cri.getUserName());
            String re_authentication_Password = new String(cri.getPassword()); 
            Utility.log(
                  " re-authentication userName="+re_authentication_UserName+
                  " compare to existing userName="+userName);
            Utility.log(
                  " re-authentication password="+re_authentication_Password+
                  " compare to existing password="+password);
        }
		Object obj = new ConnectionImpl(this);
        cHandle = (ConnectionImpl)obj;
        closed=false;
        destroyed=false;
        return obj;
	}
	public void destroy()
		throws ResourceException 
	{
        Utility.log(cName+".destroy");
        // the physical connection is closed
        destroyed = true;
        closed = true;
        cHandle=null;
	}

	public void cleanup()
		throws ResourceException 
	{
        // the physical connection stays open
        // but all connection handles invalidated
        Utility.log(cName+".cleanup");
        cHandle=null;
        closed=true;
        
	}

	public void associateConnection(Object obj)
		throws ResourceException 
	{
        Utility.log(cName+".associateConnection");
        if (obj instanceof ConnectionImpl) {
            ConnectionImpl conn = (ConnectionImpl) obj;
            conn.associateConnection(this); // TODO may need more arg to associate
        } else {
            Utility.log(cName+".associateConnection "+
            "error: obj not instanceof ConnectionImpl");
        }
	}

	public void addConnectionEventListener(ConnectionEventListener listener) 
	{
        listeners.addElement(listener);
        Utility.log(cName+".addConnectionEventListener listener="
            +listener);
	}

	public void removeConnectionEventListener(ConnectionEventListener listener) 
	{
        Vector lst = (Vector) listeners.clone();
        int len = lst.size();
        Utility.log(cName+".removeConnectionEventListener "
                 +"Number of listeners="+len);
        try {
            listeners.removeElement(listener);
        } catch (Exception e) {
            Utility.log(cName+".removeConnectionEventListener error: "
                 +"unable to remove listener");
        }
        lst = (Vector) listeners.clone();
        len = lst.size();
        Utility.log(cName+".removeConnectionEventListener listener="
            +listener+" was removed. Number listeners left="+len);
	}

    public XAResource getXAResource()
        throws ResourceException 
    {
        // TODO determine if <transaction-support>NoTransaction
        // throw ResourceException
        if (xar==null)
            xar = (XAResource)new XAResourceImpl(this);
        Utility.log(cName+".getXAResource xar="+xar);
        return xar;
    }
    public void resetXar() {
        // dissociate XAResource Xid from this ManagedConnection 
        Utility.log(cName+
                  ".resetXar dissociate XAResource Xid from this ManagedConnection");
        xar=null;
        xari=null;
    }
    public XAResourceImpl getCurrentXar()
        throws ResourceException 
    {
        xari=(XAResourceImpl)xar;
        Utility.log(cName+".getCurrentXar xari="+xari);
        return xari;
    }

    public javax.resource.cci.LocalTransaction getLocalTransaction(boolean sendEvent)
        throws ResourceException 
    {
        LocalTransactionImpl lt = null;
        Utility.log(cName+".getLocalTransaction(sendEvent)");
        this.sendEvent=sendEvent;
        try {
            lt = (LocalTransactionImpl) getLocalTransaction();
            Utility.log(cName+".getLocalTransaction(sendEvent) lt="+lt);
        } catch (Exception e) {
            Utility.log(cName+".getLocalTransaction(sendEvent) "
            +"error: "+e.getMessage());
        }
        return (lt);
    }

    public LocalTransaction getLocalTransaction()
        throws ResourceException 
    {
        Utility.log(cName+".getLocalTransaction");
        if (loTx==null) {
            loTx = new LocalTransactionImpl(this, sendEvent);
            Utility.log(cName+".getLocalTransaction new loTx="+loTx);
            return loTx;
        } else {
            Utility.log(cName+".getLocalTransaction old loTx="+loTx);
            loTx.setSendEvent(sendEvent);
            return loTx;
        }
    }

	public ManagedConnectionMetaData getMetaData()
		throws ResourceException 
	{
        Utility.log(cName+".getMetaData");
        return  new ManagedConnectionMetaDataImpl();
	}
    /** Send the specified event to all the EventListeners that have 
     *  registered with this ManagedConnection instance.
     *
     *  @param   int   Event type to send
     *  @param   Exception  if one is associated with this event
     *  @param   ch    Connection handle associated with this event
     *  @throws  ResourceException  generic exception if operation fails 
     *  @throws  IllegalArgumentException  if an invalid event is specified
     **/
    public void sendEvent(int eType, Exception ex, Object ch) throws ResourceException
    {
        Vector lst = (Vector) listeners.clone();
        ConnectionEvent ce = null;
        if (ex==null) {
            ce = new ConnectionEvent(this, eType);
        } 
        else 
            ce = new ConnectionEvent(this, eType, ex);
        
        if (ch != null) 
            ce.setConnectionHandle(ch);
        else
            Utility.log(cName+".sendEvent ch==null");

        int len = lst.size();
        for (int i=0; i<len; i++) 
        {
          ConnectionEventListener cel = (ConnectionEventListener) lst.elementAt(i);
          switch (eType) 
          {
            case ConnectionEvent.CONNECTION_CLOSED:
              if (closed == false)
              {
                 closed = true;
                 cel.connectionClosed(ce);
                 Utility.log(cName
                    +".sendEvent 'CONNECTION_CLOSED' to listener="+cel+" Num="+i);
              }
              break;
            case ConnectionEvent.CONNECTION_ERROR_OCCURRED:
              if (closed == false)
              {
                 closed=true;
                 cel.connectionErrorOccurred(ce);
                 Utility.log(cName
                    +".sendEvent 'CONNECTION_ERROR_OCCURRED' to listener="+cel+" Num="+i);
              }
              break;
            case ConnectionEvent.LOCAL_TRANSACTION_STARTED:
              cel.localTransactionStarted(ce);
              Utility.log(cName
                 +".sendEvent 'LOCAL_TRANSACTION_STARTED' to listener="+cel+" Num="+i);
              break;
            case ConnectionEvent.LOCAL_TRANSACTION_COMMITTED:
              cel.localTransactionCommitted(ce);
              Utility.log(cName
                 +".sendEvent 'LOCAL_TRANSACTION_COMMITTED' to listener="+cel+" Num="+i);
              break;
            case ConnectionEvent.LOCAL_TRANSACTION_ROLLEDBACK:
              cel.localTransactionRolledback(ce);
              Utility.log(cName
                 +".sendEvent 'LOCAL_TRANSACTION_ROLLEDBACK' to listener="+cel+" Num="+i);
              break;
            default:
              IllegalArgumentException iae = 
                    new IllegalArgumentException("Illegal eventType: "+eType);
              Utility.log(cName+".sendEvent error: "+iae.toString());
              throw iae;
          }
        }

    }
    public void setMcf(ManagedConnectionFactory MCF) { // called by ManagedConnectionFactory
        Utility.log(cName+".setMcf to "+MCF);
        this.mcf=MCF;
    }
    public ManagedConnectionFactory getMcf() {
        return this.mcf;
    }
    //
    // The setLogWriter and getLogWriter are used in ManagedConnectionFactory
    // and ManagedConnection
    // the Application Server calls ManagedConnection.setLogWriter(pw)
    //
    public void setLogWriter(PrintWriter printwriter)
        throws ResourceException
    {
        Utility.log(cName+".setLogWriter mci.pw="+pw+" ApplicationServer's PrintWriter="+printwriter);
        if (printwriter!=null) pw = printwriter;
    }
    
    public PrintWriter getLogWriter()
        throws ResourceException
    {
        return pw;
    }
    public boolean equals(Object other) 
    {
        boolean match = false;
        if (other==null) {
            return match;
        } 
        if (other instanceof ManagedConnectionImpl) {
            ManagedConnectionImpl otherMci = (ManagedConnectionImpl)other;
            try {
                match = crii.equals(otherMci.crii);
            } catch (Exception e) {
                Utility.log(cName+".equals("+otherMci+") error: false Exception="+e);
                return false;
            }
        }
        return match;
    }

}