/*
 * Created on Jun 11, 2003
 *
 * JtestResourceAdapter.java is a Resource Adapter to test the J2EE Connector
 * as implemented by JOnAS. This class implements all the connector classes. Each
 * connector method simulates actual functionality and returns test results to the
 * caller which is a JUnit test program.
 */
package fictional.resourceadapter;

import java.io.PrintWriter;
import java.io.Serializable;
import java.util.Date;
import java.util.Iterator;
import java.util.Set;
import java.util.Vector;

import javax.naming.NamingException;
import javax.naming.Reference;
import javax.resource.NotSupportedException;
import javax.resource.Referenceable;
import javax.resource.ResourceException;
import javax.resource.spi.ConnectionEvent;
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.ManagedConnectionFactory;
import javax.resource.spi.ManagedConnectionMetaData;
import javax.resource.spi.ResourceAllocationException;
import javax.resource.spi.security.GenericCredential;
import javax.resource.spi.security.PasswordCredential;
import javax.security.auth.Subject;
import javax.transaction.xa.XAResource;

import org.objectweb.jonas.common.Log;
import org.objectweb.util.monolog.api.BasicLevel;
import org.objectweb.util.monolog.api.Logger;

/**
 * @author Bob Kruse
 *
 * used to test the J2EE Connector as implemented by JOnAS.
 *
 */
public class JtestResourceAdapter 
	implements ManagedConnectionFactory,
	ConnectionRequestInfo,
	//LocalTransaction,
	ManagedConnection,
	ManagedConnectionMetaData,
	GenericCredential,
	Serializable, Referenceable
{
	Reference reference;
    String timeStamp = "";
    private String defaultUserName="";     // used in ManagedConnection, ConnectionRequestInfo  
    private String defaultPassword="";     // set by "getter" method
    private String userName="";  
    private String password="";
    private ManagedConnectionFactory mcf;     // loaded by ManagedConnectionFactory
    public ConnectionManager cm;              // loaded by ManagedConnectionFactory
    public LocalTransactionImpl loTx=null;
	PrintWriter pw;                            // App Server sets to null by default
    private Vector listeners;
    private Logger logger = null;
    //Managed environment
    public boolean managed; // see ConnectionRequestInfo
    public String res_auth;  // set by ConnectionFactory.getConnection()
                              // then put into ManagedConnection when created
    public String re_authentication_UserName;  // see by ConnectionFactory.getConnection()
    public String re_authentication_Password;
    public XAResource     xar = null;
    public XAResourceImpl xari = null;
    String cName = "";
    //
    // constructor for all "implements" in this class 
    public JtestResourceAdapter()
    {
        if (logger == null) {
            logger = Log.getLogger("fictional.resourceadapter");
        }
        timeStamp = Long.toString(System.currentTimeMillis()); // unique for this obj
        forceMatchNull=false;
        managed   = true;  
        closed    = true;          // Managed Connection
        connDate  = null;          // Managed Connection
        listeners = new Vector();  // used in ManagedConnection
        pw        = null;
        xar       = null;          // used in ManagedConnection
        xari      = null;
        loTx      = null;          // used in ManagedConnection
    }

    private String impl(Object obj) {
        if (obj instanceof ManagedConnectionFactory) {
            return "ManagedConnectionFactory";
        } else if (obj instanceof ConnectionRequestInfo) {
            return "ConnectionRequestInfo";
        } else if (obj instanceof ManagedConnection) {
            return "ManagedConnection";
        } else if (obj instanceof ManagedConnectionMetaData) {
            return "ManagedConnectionMetaData";
        } else if (obj instanceof GenericCredential) {
            return "GenericCredential";
        } else
            return "JtestResourceAdapter. Is this an error";

    }
	// ************************
	// ManagedConnectionFactory           methods see 5.5.3
	// ************************
	// Referenced classes of package javax.resource.spi:
	//            ConnectionManager, ConnectionRequestInfo, ManagedConnection
	public Object createConnectionFactory(ConnectionManager connectionmanager)
		throws ResourceException
	{
        cm = connectionmanager;
        cName="ManagedConnectionFactory";
        logger.log(BasicLevel.DEBUG, cName+".createConnectionFactory cm="+cm);
		Object obj;
		obj = new CommonClient(this, connectionmanager); // creates ConnectionFactory
        return obj;
	}
	/**
	 * 
	 * When the createConnectionFactory method takes no arguments, the resource adapter 
	 * provides a default ConnectionManager instance. This case is used in a non-managed 
	 * application scenario.
	 *  see 5.5.3
	 */
	public Object createConnectionFactory()
		throws ResourceException
	{
        cName="ManagedConnectionFactory";
        logger.log(BasicLevel.DEBUG, cName+": error - non-managed detected");
        throw new NotSupportedException(
            "A non-managed two-tier application environment is not supported in J2EE testing.");
	}
	public ManagedConnection createManagedConnection(Subject subject, 
                                                    ConnectionRequestInfo connectionrequestinfo)
		throws ResourceException
	{
        cName="ManagedConnectionFactory";
        logger.log(BasicLevel.DEBUG, cName+".createManagedConnection subject="+subject
                    +", cri="+connectionrequestinfo);
        mcf = (ManagedConnectionFactory) this;
        if (subject!=null) {
            //
            // The application server user's password to the EIS is carried in Subject
            //
            try {
                PasswordCredential pc = getPasswordCredential(mcf, subject, connectionrequestinfo);
                if (pc==null) {
                    logger.log(BasicLevel.DEBUG, cName
                              +".createManagedConnection PasswordCredential = null, Subject not null.");
                } else {
                    if (pc.getUserName()==null || pc.getUserName().length()==0) {
                        logger.log(BasicLevel.DEBUG, cName+".createManagedConnection userName=empty");
                    } else {
                        userName = new String(pc.getUserName());
                        logger.log(BasicLevel.DEBUG, cName+".createManagedConnection"
                        +" PasswordCredential userName="+userName);
                        password = new String(pc.getPassword()); // pc.password is char[]
                        logger.log(BasicLevel.DEBUG, cName+".createManagedConnection"
                        +" PasswordCredential password="+password);
                    }
                }
            } catch (Exception e) {
                logger.log(BasicLevel.DEBUG, cName+".createManagedConnection getPasswordCredential "
                       +"error: e="+e.toString());
            }
        }

        if (connectionrequestinfo != null) {
            //
            // The client application component user's password is carried in ConnectionRequestInfo
            // Use defaults if userName or password is empty
            //
            JtestResourceAdapter jinfo = (JtestResourceAdapter) connectionrequestinfo;
            String s = jinfo.getUserName();
            if (s.length()>0) userName = s;
            else
                logger.log(BasicLevel.DEBUG, cName+".createManagedConnection"
                      +" ConnectionRequestInfo userName="+s+". Use default="+userName);
            logger.log(BasicLevel.DEBUG, cName+".createManagedConnection"
                      +" ConnectionRequestInfo userName="+userName);
            s = jinfo.getPassword();
            if (s.length()>0) password = s;
            else
                logger.log(BasicLevel.DEBUG, cName+".createManagedConnection"
                      +" ConnectionRequestInfo password="+s+". Use default="+password);
            logger.log(BasicLevel.DEBUG, cName+".createManagedConnection"
                      +" ConnectionRequestInfo password="+password);
        }

        if (subject==null && connectionrequestinfo==null) {
            //
            // The default user's password is carried in the ManagedConnectionFactory instance
            //
            userName=defaultUserName;
            password=defaultPassword;
            logger.log(BasicLevel.DEBUG, cName+".createManagedConnection default userName="+userName);
            logger.log(BasicLevel.DEBUG, cName+".createManagedConnection default password="+password);
        }
        
        Date cDate = new Date();
		try {
            //
            //  Create the ManagedConnection Instance
            //
            ManagedConnection mc = (ManagedConnection) new JtestResourceAdapter();
            JtestResourceAdapter obj = (JtestResourceAdapter)mc;
            obj.setConnDate(cDate);
            obj.setMcf(mcf);
            obj.setPassword(password);
            obj.setUserName(userName);
            obj.setRes_Auth(res_auth);
            obj.setLogWriter(pw);
            logger.log(BasicLevel.DEBUG, cName+".createManagedConnection mc="+mc
                                   +" with connDate="+cDate);
            return mc;
        } catch (Exception ex) {
            logger.log(BasicLevel.DEBUG, cName+".createManagedConnection : error - Exception ex="
                     +ex.getMessage());
            throw new ResourceAllocationException(ex.getMessage());            
        }
	}
	boolean forceMatchNull;
    public void setMatchNull(boolean truefalse) {
        forceMatchNull=truefalse;
    }
    public ManagedConnection matchManagedConnections(Set connectionSet, 
	                                                 Subject subject, 
	                                                 ConnectionRequestInfo connectionrequestinfo)
		throws ResourceException
	{
        cName="ManagedConnectionFactory";
        logger.log(BasicLevel.DEBUG, cName+".matchManagedConnections");
        ManagedConnection mc = null;
        if (forceMatchNull) {
            logger.log(BasicLevel.DEBUG, cName+".matchManagedConnections force new connection");
            return mc;  // forces new connection
        } 
        JtestResourceAdapter wmc = null;
        Iterator it = connectionSet.iterator();
        int cnt=0;
        while (it.hasNext()) {
            Object obj = it.next();
            logger.log(BasicLevel.DEBUG, cName+".matchManagedConnections "
               +"find next ManagedConnection in Set. connectionSet cnt="+ (++cnt));
            if (obj instanceof ManagedConnection) {
                // see if ManagedConnection is available
                // i.e., no connection handle exists for mc instance
                // i.e., the connection is closed
                // TODO choose one of the above
                wmc = (JtestResourceAdapter) obj;
                if (wmc.getCHandle()==null || wmc.isClosed()) {
                    mc=(ManagedConnection)wmc;
                    logger.log(BasicLevel.DEBUG, cName+".matchManagedConnections "
                        +"connection handle == null. connectionSet cnt="+cnt);
                } else {
                    // error: connection should not exist J2ee 1.0 pg. 32
                    String s = "connection handle should not exist";
                    logger.log(BasicLevel.DEBUG, cName+".matchManagedConnections "
                        +"error: "+s+". connectionSet cnt="+cnt);
                }
            }
        }
        if (mc==null) 
            logger.log(BasicLevel.DEBUG, cName+".matchManagedConnections mc=null connectionSet cnt="+cnt);
        else 
            logger.log(BasicLevel.DEBUG, cName+".matchManagedConnections with connDate="
                   +wmc.getConnDate());
        return mc;
	}
        //
        // The setLogWriter and getLogWriter are used in ManagedConnectionFactory
        // and ManagedConnection
        // the Application Server calls ManagedConnection.setLogWriter(pw)
        //
	public void setLogWriter(PrintWriter printwriter)
		throws ResourceException
	{
		if (printwriter!=null) pw = printwriter;
	}

	public PrintWriter getLogWriter()
		throws ResourceException
	{
		return pw;
	}
    //
    // config-property processing "setter" properties
    //
    String ServerName="";
    String PortNumber="";
    String protocol="";
    /** Set the JOnAS config-property..  Default value is "".
     *
     *  @param   c1    String of config-property.
     *                  for testng RA.
    **/
    public void setServerName(String c1)
    {
      ServerName = c1;
      //logger.log(BasicLevel.DEBUG, cName+".setServerName="+ServerName);
    }
    public String getServerName() {
        return ServerName;
    }
    public void setPortNumber(String s)
    {
        PortNumber=s;
        //logger.log(BasicLevel.DEBUG, cName+".setPortNumber="+PortNumber);
    }
    public void setDUserName(String s)
    {
        defaultUserName=s;
        //logger.log(BasicLevel.DEBUG, cName+".setDUserName="+defaultUserName);
    }
    public void setDPassword(String s)
    {
        defaultPassword=s;
        //logger.log(BasicLevel.DEBUG, cName+".setDPassword="+defaultPassword);
    }
    public void setProtocol(String s)
    {
        protocol=s;
        //logger.log(BasicLevel.DEBUG, cName+".setProtocol="+protocol);
    }
    public String getProtocol()
    {
        return protocol;
    }
    public ConnectionManager getCM()
    {
        return cm;
    }
    public String getRes_Auth() {
        return res_auth;
    }
    public void setRes_Auth(String r) {
        res_auth=r;
    }
    //************************
    // ConnectionRequestInfo                                          
    //************************
    //          module to add additional connection properties than   
    //          the ones configured for the ConnectionFactory.  This  
    //          class is passed to the App Server and will be used    
    //          on matchManagedConnections or createConnection        
    //          methods by the App Server.                            
    //                                                                
    String Id="";  // used in hashcode() for ConnectionRequestInfo
    //
    public void setUserName(String u) {
        userName=u;
        if (cName.length() == 0) cName=impl(this);
        logger.log(BasicLevel.DEBUG, cName+".setUserName="+u);
    }
    public void setPassword(String p) {
        password=p;
        if (cName.length() == 0) cName=impl(this);
        logger.log(BasicLevel.DEBUG, cName+".setPassword="+p);
    }
    public  String getUserName() {
        if (cName.length() == 0) cName=impl(this);
        logger.log(BasicLevel.DEBUG, cName+".getUserName="+userName);
        return userName;
    }
    public String getPassword() {
        if (cName.length() == 0) cName=impl(this);
        logger.log(BasicLevel.DEBUG, cName+".getPassword="+password);
        return password;
    }
    private void setId()
    {
        if (Id == null || Id.length() == 0)
            Id=timeStamp;
        
    }
    //
    // hashCode and equals method used in ConnectionRequestInfo,
    //                                    ManagedConnectionFactory
    //                               and  GenericCredential
    public int hashCode() 
    {
        int hash = 1;
        setId();
        hash = Id.hashCode();
        return hash;
    }
    public boolean equals(Object obj) 
    {
        boolean match = false;
        if (obj==null) {
            return match;
        } 
        JtestResourceAdapter other = (JtestResourceAdapter)obj;
        if (this.timeStamp.equals(other.getTimeStamp())) match = true;
        return match;
    }
    
	// *****************
	// GenericCredential methods
	// *****************
	//
    String gcID ="";  // used in hashcode() for GenericCredential
	public  String getName()
	{
        cName="GenericCredential";
        logger.log(BasicLevel.DEBUG, cName+".getName");
		return "";
	}

	public  String getMechType()
	{
        cName="GenericCredential";
        logger.log(BasicLevel.DEBUG, cName+".getMechType");
		return "";
	}

	public  byte[] getCredentialData()
		throws SecurityException
	{
        cName="GenericCredential";
        logger.log(BasicLevel.DEBUG, cName+".getCredentialData");
		byte[] x = {0,0};
		return x;
	}

	// *****************
	// ManagedConnection  methods
	// *****************
	//
	// Referenced classes of package javax.resource.spi:
	//            ConnectionRequestInfo, ConnectionEventListener, LocalTransaction, 
	//            ManagedConnectionMetaData
    //
    // NOTE: Subject is instantiated by Application Server
    //
    boolean closed;
    public ConnectionImpl cHandle;    // ManagedConnection mapped 1:1 to a physical connection
    private boolean destroyed;       //set when destroyed
    private Date    connDate;         //save connection date/time for a ManagedConnection
    public boolean inXATrans;
    public boolean inLocalTrans;
    public boolean sendEvent;
                                        
    public int cntListeners() {
        cName="ManagedConnection";
        Vector lst = (Vector) listeners.clone();
        int len = lst.size();
        logger.log(BasicLevel.DEBUG, cName+".cntListeners counted="+len);
        return len;
    }
    public ConnectionImpl getCHandle() {
        return cHandle; 
    }
    public boolean isClosed() {
        return closed;
    }
        
	public Object getConnection(Subject subject, ConnectionRequestInfo connectionrequestinfo)
		throws ResourceException 
	{
        cName="ManagedConnection";
        logger.log(BasicLevel.DEBUG, cName+".getConnection *******************");
        if (subject!=null) {
            // 
            //  for this code to execute, the following will be present in ra.xml
            //   <reauthentication-support>true</reauthentication-support>
            // 
            logger.log(BasicLevel.DEBUG, cName+".getConnection via PasswordCredential");
            logger.log(BasicLevel.DEBUG, "<reauthentication-support>true</reauthentication-support>");
            try {
                PasswordCredential pc = getPasswordCredential(mcf, subject, connectionrequestinfo);
                if (pc==null) {
                    logger.log(BasicLevel.DEBUG, cName+".getConnection PasswordCredential = null");
                } else {
                    if (pc.getUserName()==null || pc.getUserName().length()==0) {
                        logger.log(BasicLevel.DEBUG, cName+".getConnection userName=empty");
                    } else {
                        String re_authentication_UserName = new String(pc.getUserName());
                        String re_authentication_Password = new String(pc.getPassword());
                        logger.log(BasicLevel.DEBUG, cName+".getConnection"
                              +" re-authentication userName="+re_authentication_UserName);
                        logger.log(BasicLevel.DEBUG, cName+".getConnection"
                              +" compare to existing userName="+userName);
                        logger.log(BasicLevel.DEBUG, cName+".getConnection"
                              +" re-authentication password="+re_authentication_Password);
                        logger.log(BasicLevel.DEBUG, cName+".getConnection"
                              +" compare to existing password="+password);
                    }
                }
            } catch (Exception e) {
                logger.log(BasicLevel.DEBUG, cName+".getConnection getPasswordCredential error: e="
                             +e.toString());
            }
        } 
        // Code for reauthentication-support when Subject==null and ConnectionRequestInfo
        // contains different password and username
        //
        if (connectionrequestinfo!=null) {
            logger.log(BasicLevel.DEBUG, impl(this)+".getConnection via ConnectionRequestInfo");
            logger.log(BasicLevel.DEBUG, "<reauthentication-support>true</reauthentication-support>");
            JtestResourceAdapter jcri = (JtestResourceAdapter) connectionrequestinfo;
            String re_authentication_UserName = new String(jcri.getUserName());
            String re_authentication_Password = new String(jcri.getPassword()); 
            logger.log(BasicLevel.DEBUG, 
                  " re-authentication userName="+re_authentication_UserName+
                  " compare to existing userName="+userName);
            logger.log(BasicLevel.DEBUG, 
                  " 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 
	{
        cName="ManagedConnection";
        logger.log(BasicLevel.DEBUG, cName+".destroy");
        // the physical connection is closed
        destroyed = true;
        closed = true;
        cHandle=null;
	}

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

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

	public void addConnectionEventListener(ConnectionEventListener listener) 
	{
        cName="ManagedConnection";
        listeners.addElement(listener);
        logger.log(BasicLevel.DEBUG, cName+".addConnectionEventListener listener="
            +listener);
	}

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

    public XAResource getXAResource()
        throws ResourceException 
    {
        cName="ManagedConnection";
        if (xar==null)
            xar = (XAResource)new XAResourceImpl(this);
        logger.log(BasicLevel.DEBUG, cName+".getXAResource xar="+xar);
        return xar;
    }
    public void resetXar() {
        // dissociate XAResource Xid from this ManagedConnection 
        xar=null;
        xari=null;
    }
    public XAResourceImpl getCurrentXar()
        throws ResourceException 
    {
        xari=(XAResourceImpl)xar;
        return xari;
    }

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

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

	public ManagedConnectionMetaData getMetaData()
		throws ResourceException 
	{
        cName="ManagedConnection";
        logger.log(BasicLevel.DEBUG, cName+".getMetaData");
        return (ManagedConnectionMetaData) new JtestResourceAdapter();
	}
    /** 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
    {
        cName="ManagedConnection";
        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
            logger.log(BasicLevel.DEBUG, 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);
                 cName="ManagedConnection";  // re-establish cName
                 logger.log(BasicLevel.DEBUG, cName
                    +".sendEvent 'CONNECTION_CLOSED' to listener="+cel+" Num="+i);
              }
              break;
            case ConnectionEvent.CONNECTION_ERROR_OCCURRED:
              if (closed == false)
              {
                 closed=true;
                 cel.connectionErrorOccurred(ce);
                 cName="ManagedConnection";  // re-establish cName
                 logger.log(BasicLevel.DEBUG, cName
                    +".sendEvent 'CONNECTION_ERROR_OCCURRED' to listener="+cel+" Num="+i);
              }
              break;
            case ConnectionEvent.LOCAL_TRANSACTION_STARTED:
              cel.localTransactionStarted(ce);
              cName="ManagedConnection";  // re-establish cName
              logger.log(BasicLevel.DEBUG, cName
                 +".sendEvent 'LOCAL_TRANSACTION_STARTED' to listener="+cel+" Num="+i);
              break;
            case ConnectionEvent.LOCAL_TRANSACTION_COMMITTED:
              cel.localTransactionCommitted(ce);
              cName="ManagedConnection";  // re-establish cName
              logger.log(BasicLevel.DEBUG, cName
                 +".sendEvent 'LOCAL_TRANSACTION_COMMITTED' to listener="+cel+" Num="+i);
              break;
            case ConnectionEvent.LOCAL_TRANSACTION_ROLLEDBACK:
              cel.localTransactionRolledback(ce);
              cName="ManagedConnection";  // re-establish cName
              logger.log(BasicLevel.DEBUG, cName
                 +".sendEvent 'LOCAL_TRANSACTION_ROLLEDBACK' to listener="+cel+" Num="+i);
              break;
            default:
              IllegalArgumentException iae = 
                    new IllegalArgumentException("Illegal eventType: "+eType);
              logger.log(BasicLevel.DEBUG, cName+".sendEvent error: "+iae.toString());
              throw iae;
          }
        }

    }
    public void setConnDate(Date cDate) { // called by ManagedConnectionFactory
        cName="ManagedConnection";
        logger.log(BasicLevel.DEBUG, cName+".setConnDate to "+cDate);
        connDate=cDate;
    }
    public void setMcf(ManagedConnectionFactory MCF) { // called by ManagedConnectionFactory
        cName="ManagedConnection";
        logger.log(BasicLevel.DEBUG, cName+".setMcf to "+MCF);
        this.mcf=MCF;
    }
    public Date getConnDate() {
        return connDate;
    }
    public ManagedConnectionFactory getMcf() {
        return this.mcf;
    }
    public void setTimeStamp(String ts) {
        cName=impl(this);
        timeStamp=ts;
        logger.log(BasicLevel.DEBUG, cName+".setTimeStamp to "+ts);
    }
    public String getTimeStamp() {
        return timeStamp;
    }
	// *************************
	// ManagedConnectionMetaData  methods
	// *************************
	//
	String product="Fictional EIS";
    String version="1.1";
    public  String getEISProductName()
		throws ResourceException
	{
        cName="ManagedConnectionMetaData";
        logger.log(BasicLevel.DEBUG, cName+".getEISProductName");
		return product;
	}

	public  String getEISProductVersion()
		throws ResourceException
	{
        cName="ManagedConnectionMetaData";
        logger.log(BasicLevel.DEBUG, cName+".getEISProductVersion");
		return version;
	}

	public  int getMaxConnections()
		throws ResourceException
	{
        cName="ManagedConnectionMetaData";
        logger.log(BasicLevel.DEBUG, cName+".getMaxConnections");
		return 0;
	}

	/** Required by the referencable attribute
	 *  @param  ref Reference object
	**/
	public void setReference(javax.naming.Reference ref) 
	{
	  this.reference = ref;
	}

	/** Required by the referencable attribute
	 *  @return  Reference object
	**/
	public Reference getReference() 
		throws NamingException
	{
	  return reference;
	}
    /** Returns the Password credential
    *
    * @param mcf      ManagedConnectionFactory currently being used
    * @param subject  Subject associated with this call
    * @param info     ConnectionRequestInfo
    *
    * @return         PasswordCredential for this user
    */
    public PasswordCredential getPasswordCredential
           (ManagedConnectionFactory mcf, 
            Subject subject, 
            ConnectionRequestInfo info
            )
                                        throws ResourceException 
    {

        logger.log(BasicLevel.DEBUG, cName+".getPasswordCredential subject="+subject);
        PasswordCredential pc = null;
        try {
            if (subject == null) 
            {
               if (info == null) return null;
               JtestResourceAdapter crii = (JtestResourceAdapter) info; // ConnectionRequestInfo
               pc = new PasswordCredential(crii.userName,crii.password.toCharArray());
               pc.setManagedConnectionFactory(mcf);
               return pc;
            } 
            Set cred = subject.getPrivateCredentials(PasswordCredential.class);
            pc = null;
            for (Iterator iter = cred.iterator();  iter.hasNext();)
            {
                PasswordCredential tmpPc = (PasswordCredential) iter.next();
                if (mcf.equals(tmpPc.getManagedConnectionFactory())) 
                {
                    logger.log(BasicLevel.DEBUG, cName+".getPasswordCredential PasswordCredential "
                             +"found mcf="+mcf);
                    pc = tmpPc;
                    break;
                }
            }
        } catch (Exception e) {
            logger.log(BasicLevel.DEBUG, cName+".getPasswordCredential error: "+e.toString());
            pc=null;
        }
        if (pc == null) 
        {
            SecurityException se = new SecurityException("No PasswordCredential found");
            logger.log(BasicLevel.DEBUG, cName+".getPasswordCredential error: "+se);
            throw se;
        } 
        return pc;
    }

}
