msmith      02/02/21 20:05:02

  Modified:    src/stores/slidestore/j2ee J2EEDescriptorsStore.java
  Log:
  New J2EEDescriptorsStore.
  
  Notes:
   - this won't create the database tables for you, currently. I'll re-add that
     soon. This is rarely used since most databases need different tables
     from what the code here added. Won't remove the tables either (the old
     one had code for this, but I don't know if it was ever called).
  
   - It's a bit on the verbose side as far as debugging info goes. That'll
     go once a few more people have tested it.
  
   - At some point, the transaction handling stuff should be moved into
     another class so that both this and the content store can use it. At
     the same time, obviously, the content store will need to be updated
     similarly to this - that should be simple and straightforward.
  
  Revision  Changes    Path
  1.4       +315 -314  
jakarta-slide/src/stores/slidestore/j2ee/J2EEDescriptorsStore.java
  
  Index: J2EEDescriptorsStore.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-slide/src/stores/slidestore/j2ee/J2EEDescriptorsStore.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- J2EEDescriptorsStore.java 9 Feb 2002 16:53:48 -0000       1.3
  +++ J2EEDescriptorsStore.java 22 Feb 2002 04:05:01 -0000      1.4
  @@ -1,7 +1,7 @@
   /*
  - * $Header: 
/home/cvs/jakarta-slide/src/stores/slidestore/j2ee/J2EEDescriptorsStore.java,v 1.3 
2002/02/09 16:53:48 dirkv Exp $
  - * $Revision: 1.3 $
  - * $Date: 2002/02/09 16:53:48 $
  + * $Header: 
/home/cvs/jakarta-slide/src/stores/slidestore/j2ee/J2EEDescriptorsStore.java,v 1.4 
2002/02/22 04:05:01 msmith Exp $
  + * $Revision: 1.4 $
  + * $Date: 2002/02/22 04:05:01 $
    *
    * ====================================================================
    *
  @@ -68,10 +68,12 @@
   import java.util.Enumeration;
   import java.util.Vector;
   import java.util.Date;
  +import java.util.Arrays;
   import java.io.FileWriter;
   import java.io.IOException;
   import java.sql.*;
   import javax.transaction.xa.XAException;
  +import javax.transaction.xa.XAResource;
   import javax.transaction.xa.Xid;
   import org.apache.slide.common.*;
   import org.apache.slide.store.*;
  @@ -87,65 +89,26 @@
   import javax.naming.NamingException;
   
   /**
  - * JDBC 1.0 and 2.0 compliant store implementation.
  + * J2EE store implementation.
    *
    * Alpha version (for development only)
    *
    * @author <a href="mailto:[EMAIL PROTECTED]";>Remy Maucherat</a>
    * @author Ashok Kumar
  - * @version $Revision: 1.3 $
  + * @author <a href="mailto:[EMAIL PROTECTED]";>Michael Smith</a>
  + * @version $Revision: 1.4 $
    */
   
   public class J2EEDescriptorsStore
  -    extends AbstractService
  +    extends AbstractXAService
       implements LockStore, NodeStore, RevisionDescriptorsStore, 
       RevisionDescriptorStore, SecurityStore {
   
  -// FIXME: Concurrent access to the J2EE store
  -// ===========================================
  -// The following is a summary what has to be done to complete the J2EE store
  -// This applies to both J2EEDescriptorsStore and J2EEContentStore
  -//
  -// http://marc.theaimsgroup.com/?l=slide-dev&m=101093479323729&w=2
  -// http://marc.theaimsgroup.com/?l=slide-dev&m=101095180715067&w=2
  -// http://marc.theaimsgroup.com/?l=slide-dev&m=101304906406795&w=2
  -// http://marc.theaimsgroup.com/?l=slide-dev&m=101304998408694&w=2
  -// 
  -// (Dirk)
  -// I think something is missing in the store implementation and that's why
  -// you also get those wrong content lengths that you reported in your mail
  -// "Problem with GET and content Length". A second user sees the new
  -// content length before it is committed.
  -// 
  -// In the current implementation, there is only one Connection object and
  -// that connection object is used in all threads (for all concurrect
  -// requests/transactions). I always had the impression that you had to get
  -// a separate connection for each concurrent transaction.
  -// 
  -// (Remy)
  -// Your analysis is accurate.
  -// 
  -// More specifically, we should have a hashtable of active connections keyed by
  -// the global transaction id (add them to the hash when doing the first start,
  -// and remove them when committing or rolling back the transaction).
  -// That's how I was planning to implement it originally, anyway.
  -// 
  -// Here, as you said, the connection object gets used simultaneously in
  -// different transactions, which may indeed cause the problems with dirty reads
  -// (of course, it's rather hard to predict).
  -// 
  -// (Remy)
  -// I think you need to associate 1 connection <-> 1 global transaction ID, and
  -// put back the connection in the pool at the end. That's also what Dirk
  -// suggested, if I remember well.
  -// IMO, you also can also fully rely on the DataSource TX isolation (or at
  -// least allow it as an option), and always accept enlistment in a transaction
  -// (the DB will then handle the rest, which could be finer grained, so it
  -// should end up being faster).
  -
  -   
       // -------------------------------------------------------------- Constants
       
  +    public static final int TX_IDLE = 0;
  +    public static final int TX_PREPARED = 1;
  +    public static final int TX_SUSPENDED = 1;
       
       // Column numbers
       
  @@ -218,93 +181,17 @@
       
       
       /**
  -     * Database connection.
  +     * Database connection source.
        */
  -    protected Connection connection;
  -
       protected DataSource ds;
       protected String datasource;    
  -    
  -    /**
  -     * Driver class name.
  -     */
  -    protected String driver;
  -    
  -    
  -    /**
  -     * Connection URL.
  -     */
  -    protected String url;
  -    
  -    
  -    /**
  -     * User name.
  -     */
  -    protected String user;
  -    
  -    
  -    /**
  -     * Password.
  -     */
  -    protected String password;
  -    
  -    
  -    /**
  -     * JDBC Version to use.
  -     */
  -    protected int jdbcVersion;
  -    
  -    /**
  -     * This store doesn't handle nested transactions, this variable keeps track 
  -     * if the store is already enlisted to a transaction.
  -     */
  -    protected boolean alreadyEnlisted=false;
  -    
  -    // -------------------------------------------------------- Service Methods
  -    
  -    /**
  -     * Returns the sql statements to create the database objects.
  -     */
  -    protected String[] getDatabaseCreateStatements()
  -    {
  -        String[] statements = {
  -            "create table objects(uri varchar(65536) primary key," +
  -            "    classname varchar(4096))",
  -            "create table children(uri varchar(65536), " +
  -            "    childuri varchar(65536))",
  -            "create table links(link varchar(65536), " +
  -            "    linkto varchar(65536))",
  -            "create table permissions(object varchar(65536)," +
  -            "    revisionnumber varchar(20), " +
  -            "    subject varchar(65536), action varchar(65536), " +
  -            "    inheritable int, negative int)",
  -            "create table locks(id varchar(65536), object varchar(4096)," +
  -            "    subject varchar(4096), type varchar(4096), " +
  -            "    expirationdate varchar(15), inheritable int, " +
  -            "    xexclusive int)",
  -            "create table revisions(uri varchar(65536) primary key, " +
  -            "    isversioned int, initialrevision varchar(10))",
  -            "create table workingrevision(uri varchar(65536), " +
  -            "    baserevision varchar(20), xnumber varchar(20))",
  -            "create table latestrevisions(uri varchar(65536), " +
  -            "    branchname varchar(4096), xnumber varchar(20))",
  -            "create table branches(uri varchar(65536), xnumber varchar(20)," +
  -            "    childnumber varchar(20))",
  -            "create table revision(uri varchar(65536), xnumber varchar(20)," +
  -            "    branchname varchar(4096))",
  -            "create table label(uri varchar(65536), xnumber varchar(20)," +
  -            "    label varchar(4096))",
  -            "create table property(uri varchar(65536), xnumber varchar(20)," +
  -            "    name varchar(4096), value varchar(65536), " +
  -            "    namespace varchar(4096), type varchar(100), protected int)"};
   
  -        return statements;
  -    }
  +    protected Hashtable connectionMap = new Hashtable();
   
  -    protected String getDatabaseConnectionTestStatement()
  -    {
  -        return "select 1 from objects where uri is null";
  -    }
  +    /* A connection used when we aren't associated with a transaction correctly. */
  +    protected Connection globalConnection;
  +    
  +    // -------------------------------------------------------- Service Methods
       
       /**
        * Initializes the data source with a set of parameters.
  @@ -330,41 +217,27 @@
        */
       public synchronized void connect()
           throws ServiceConnectionFailedException {
  -        getLogger().log("Connecting to \"" + url + "\" as user \"" + user + 
"\"",LOG_CHANNEL,Logger.INFO);
  +            getLogger().log("Trying connect to database", LOG_CHANNEL, 
  +                    Logger.INFO);
           try {
  -                     connection = ds.getConnection();
  -        } catch (SQLException e) {
  -            getLogger().log("Connecting to \"" + url + "\" as user \"" + user + "\" 
failed",LOG_CHANNEL,Logger.ERROR);
  -            getLogger().log(e.toString(),LOG_CHANNEL,Logger.ERROR);
  -            throw new ServiceConnectionFailedException(this, e);
  -        }
  -        catch(NullPointerException e) {
  -            e.printStackTrace(System.err);
  +            globalConnection = ds.getConnection();
  +        } catch(SQLException e) {
  +            getLogger().log("Couldn't get global transaction.", LOG_CHANNEL,
  +                    Logger.ERROR);
           }
  +        getLogger().log("Done connecting to database. globalConnection is "+
  +                globalConnection, LOG_CHANNEL, Logger.INFO);
  +    }
   
  -        // all updates must be done inside a transaction, no auto commits
  +    /**
  +     * Returns connection status
  +     */
  +    public boolean isConnected() {
           try {
  -            connection.setAutoCommit(false);
  -        } catch (SQLException e) {
  +            return ds!=null && globalConnection != null && 
!globalConnection.isClosed();
  +        } catch(SQLException e) {
  +            return false;
           }
  -        
  -        Statement statement = null;
  -        try {
  -            statement = connection.createStatement();
  -            String[] statements = getDatabaseCreateStatements();
  -            for (int i=0; i<statements.length ; i++ ) {
  -                statement.execute(statements[i]);
  -            }
  -            // Cloudscape needs a commit on DDL statements (create,...)
  -            connection.commit();
  -        } catch (SQLException e) {
  -            try { connection.rollback(); } catch (SQLException ex) { }
  -        } finally {
  -            closeStatement(statement);
  -        }
  -        
  -        // we are just connected and are not enlisted
  -        alreadyEnlisted=false;
       }
       
       
  @@ -376,34 +249,19 @@
        */
       public void disconnect()
           throws ServiceDisconnectionFailedException {
  -        getLogger().log("Disconnecting from \"" + url + "\" as user \"" + user + 
"\"",LOG_CHANNEL,Logger.INFO);
  +        // This doesn't need to do anything any more.
           try {
  -            if (connection != null)
  -                connection.close();
  -            connection = null;
  -        } catch (SQLException e) {
  -            getLogger().log("Disconnecting from \"" + url + "\" as user \"" + user 
+ "\" failed",LOG_CHANNEL,Logger.ERROR);
  -            getLogger().log(e.toString(),LOG_CHANNEL,Logger.ERROR);
  -            throw new ServiceDisconnectionFailedException(this, e);
  -        }
  -    }
  -
  -    /**
  -     * Tries to reconnect if needed but doesn't report failure.
  -     */
  -    protected synchronized void connectIfNeededAndPossible() {
  -        try  {
  -            connectIfNeeded();
  -        }
  -        catch (Throwable ex) {
  -            // ignore
  +            globalConnection.close();
  +        } catch(SQLException e) {
  +            getLogger().log("Failed to close special global connection: "+
  +                    e.getMessage(), LOG_CHANNEL, Logger.ERROR);
           }
       }
   
       /**
        * Initializes data source.
        * <p/>
  -     * Occurs in four steps :
  +     * Occurs in two steps :
        * <li>Datasource is looked up from the pool</li>
        * <li>Creation of the basic tables, if they didn't exist before</li>
        * 
  @@ -434,6 +292,11 @@
               token.getLogger().log(e.toString(),LOG_CHANNEL,Logger.ERROR);
               throw new ServiceInitializationFailedException(this, e.getMessage());
           }
  +
  +        if(ds == null) {
  +            token.getLogger().log("Datasource is null, can't initialise store");
  +            throw new ServiceInitializationFailedException(this, "Null datasource 
from context");
  +        }
       }
       
       
  @@ -444,152 +307,234 @@
        */
       public synchronized void reset()
           throws ServiceResetFailedException {
  -        Statement statement = null;
  -        try {
  -            connectIfNeeded();
  -            
  -            statement = connection.createStatement();
  -            String s = null;
  -            
  -            s = "drop table objects";
  -            statement.execute(s);
  -            
  -            s = "drop table children";
  -            statement.execute(s);
  -            
  -            s = "drop table links";
  -            statement.execute(s);
  -            
  -            s = "drop table permissions";
  -            statement.execute(s);
  -            
  -            s = "drop table locks";
  -            statement.execute(s);
  -            
  -            s = "drop table revisions";
  -            statement.execute(s);
  -            
  -            s = "drop table workingrevision";
  -            statement.execute(s);
  -            
  -            s = "drop table latestrevisions";
  -            statement.execute(s);
  -            
  -            s = "drop table branches";
  -            statement.execute(s);
  -            
  -            s = "drop table revision";
  -            statement.execute(s);
  -            
  -            s = "drop table label";
  -            statement.execute(s);
  -            
  -            s = "drop table property";
  -            statement.execute(s);
  -            
  -            statement.close();
  -            disconnect();
  -        } catch (SQLException e) {
  -            throw new ServiceResetFailedException(this, e.getMessage());
  -        } catch (ServiceAccessException e) {
  -            throw new ServiceResetFailedException(this, e.getMessage());
  -        } catch (ServiceConnectionFailedException e) {
  -            throw new ServiceResetFailedException(this, e.getMessage());
  -        } catch (ServiceDisconnectionFailedException e) {
  -            throw new ServiceResetFailedException(this, e.getMessage());
  -        } finally {
  -            closeStatement(statement);
  -        }
       }
       
       
  +    // ----------------------------------------------------- XAResource Methods
  +    
       /**
  -     * This function tells whether or not the data source is connected.
  -     *
  -     * @return boolean true if we are connected
  -     * @exception ServiceAccessException Error accessing DataSource
  +     * Get the transaction timeout value for this XAResource.
  +     * Just returns 0, we don't have a way of doing transaction timeouts
  +     * with the connection.
        */
  -    public boolean isConnected()
  -        throws ServiceAccessException {
  -        try {
  -           if ((connection == null) || (connection.isClosed())) {
  -                return false;
  -            }
  -            
  -            PreparedStatement statement =
  -                connection.prepareStatement(getDatabaseConnectionTestStatement());
  -            statement.executeQuery();
  -            statement.close();
  +    public int getTransactionTimeout() throws XAException {
  +        return 0;
  +    }
   
  -            // testStatement executed without throwing an exception
  -            return true;
  +    /**
  +     * Set transaction timeout, not implemented (returns false).
  +     */
  +    public boolean setTransactionTimeout(int timeout) throws XAException {
  +        return false;
  +    }
   
  -        } catch (SQLException e) {
  -            throw new ServiceAccessException(this, e);
  +    public Xid[] recover(int flag) 
  +        throws XAException {
  +        
  +        getLogger().log("recover() for thread: "+Thread.currentThread(), 
LOG_CHANNEL, Logger.INFO);    
  +        TransactionId id = (TransactionId)connectionMap.get(
  +                Thread.currentThread());
  +
  +        if(id != null && id.status == TX_PREPARED) {
  +            Xid[] xids = new Xid[1];
  +            xids[0] = id.xid;
  +            return xids;
           }
  +        else
  +            return new Xid[0];
       }
  -    
  -    
  -    // ----------------------------------------------------- XAResource Methods
  -    
  +
  +    public int prepare(Xid xid) 
  +        throws XAException {
  +        
  +        getLogger().log("prepare() for thread: "+Thread.currentThread(), 
LOG_CHANNEL, Logger.INFO);    
  +        TransactionId id = (TransactionId)connectionMap.get(
  +                Thread.currentThread());
  +
  +        if(id == null)
  +            throw new XAException(XAException.XAER_NOTA);
  +        if(xid == null)
  +            throw new XAException(XAException.XAER_INVAL);
  +        
  +        if(id.status != TX_IDLE && id.status != TX_SUSPENDED)
  +            throw new XAException(XAException.XAER_PROTO);
  +
  +        if(id.rollbackOnly)
  +            throw new XAException(XAException.XA_RBROLLBACK);
  +
  +        id.status = TX_PREPARED;
  +
  +        return XAResource.XA_OK;
  +    }
  +
  +    public boolean isSameRM(XAResource xares) throws XAException {
  +        if(xares == null)
  +            return false;
  +        else
  +            return this == xares;
  +    }
  +
  +    public void forget(Xid xid) throws XAException {
  +
  +        getLogger().log("forget() for thread: "+Thread.currentThread(), 
LOG_CHANNEL, Logger.INFO);    
  +        TransactionId id = (TransactionId)connectionMap.get(
  +                Thread.currentThread());
  +
  +        if(id == null || id.xid == null)
  +            throw new XAException(XAException.XAER_NOTA);
  +
  +        if(xid == null)
  +            throw new XAException(XAException.XAER_INVAL);
  +
  +        try {
  +            id.connection.close();
  +        } catch(SQLException e) {
  +            getLogger().log("Couldn't close connection.", LOG_CHANNEL, 
Logger.ERROR);
  +        }
  +        getLogger().log("forget(): removing from map: "+Thread.currentThread(), 
LOG_CHANNEL, Logger.INFO);    
  +        connectionMap.remove(Thread.currentThread()); 
  +    }
  +
  +    public void end(Xid xid, int flags) throws XAException {
  +
  +        getLogger().log("end() for thread: "+Thread.currentThread(), LOG_CHANNEL, 
Logger.INFO);    
  +        TransactionId id = (TransactionId)connectionMap.get(Thread.currentThread());
  +        if(id == null || id.xid == null)
  +            throw new XAException(XAException.XAER_NOTA);
  +        if(xid == null)
  +            throw new XAException(XAException.XAER_INVAL);
  +
  +        if(flags == XAResource.TMSUSPEND)
  +            id.status = TX_SUSPENDED;
  +
  +        if(flags == XAResource.TMFAIL) 
  +            id.rollbackOnly = true;
  +
  +    }
  +
  +
       
       /**
        * Commit the global transaction specified by xid.
        */
       public void commit(Xid xid, boolean onePhase)
           throws XAException {
  -        super.commit(xid, onePhase);
  +
  +        getLogger().log("commit() for thread "+Thread.currentThread()+", removing 
from map",
  +                LOG_CHANNEL, Logger.INFO);
  +
  +        TransactionId id = (TransactionId)connectionMap.remove(
  +                Thread.currentThread());
  +        if(id == null) {
  +            getLogger().log("Error committing: no transaction associated with 
current thread", LOG_CHANNEL, Logger.ERROR);
  +            throw new XAException(XAException.XAER_NOTA);
  +        }
  +        if(xid == null)
  +            throw new XAException(XAException.XAER_INVAL);
  +
  +        if(!onePhase && id.status != TX_PREPARED)
  +            throw new XAException(XAException.XAER_PROTO);
  +        if(onePhase && (!(id.status == TX_IDLE || id.status == TX_SUSPENDED)))
  +            throw new XAException(XAException.XAER_PROTO);
  +
  +        Connection conn = id.connection;
  +
  +        if(conn == null) {
  +            getLogger().log("commit(): No connection in connectionMap for id 
\""+id+"\"", LOG_CHANNEL, Logger.ERROR);
  +            throw new XAException(XAException.XAER_NOTA);
  +        }
  +
           try {
  -//            getLogger().log("commit",LOG_CHANNEL,Logger.DEBUG);
  -            connection.commit();
  -        } catch (SQLException e) {
  +            if(id.rollbackOnly)
  +                conn.rollback();
  +            else
  +                conn.commit();
  +        } catch(SQLException e) {
               throw new XAException(XAException.XA_RBCOMMFAIL);
  +        } finally {
  +            try {
  +                conn.close(); /* We must always return connections to the pool,
  +                                 or we'd eventually run out. */
  +            } catch(SQLException e) {
  +                getLogger().log(e,LOG_CHANNEL,Logger.ERROR);
  +            }
           }
  -        alreadyEnlisted=false;
       }
  -    
  -    
  +
       /**
        * Inform the resource manager to roll back work done on behalf of a
        * transaction branch.
        */
       public void rollback(Xid xid)
           throws XAException {
  -        super.rollback(xid);
  +
  +        getLogger().log("rollback() for thread "+Thread.currentThread()+", removing 
from map",
  +                LOG_CHANNEL, Logger.INFO);
  +
  +        TransactionId id = (TransactionId)connectionMap.remove(
  +                Thread.currentThread());
  +        if(id == null) {
  +            getLogger().log("No transaction associated with current thread, can't 
rollback", LOG_CHANNEL, Logger.ERROR);
  +            throw new XAException(XAException.XAER_NOTA);
  +        }
  +
  +        Connection conn = id.connection;
  +        if(conn == null) {
  +            getLogger().log("rollback(): No connection in connectionMap for id 
\""+id+"\"", LOG_CHANNEL, Logger.ERROR);
  +            throw new XAException(XAException.XAER_NOTA);
  +        }
           try {
  -//            getLogger().log("rollback",LOG_CHANNEL,Logger.DEBUG);
  -            connection.rollback();
  +            conn.rollback();
           } catch (SQLException e) {
               throw new XAException(XAException.XA_HEURCOM);
  -        }
  -        alreadyEnlisted=false;
  -    }
  -    
  -    
  -    /**
  -     * Start work on behalf of a transaction branch specified in xid.
  -     */
  -    public void start(Xid xid, int flags)
  -        throws XAException {
  -        super.start(xid, flags);
  -        if (!alreadyEnlisted) 
  -        {
  +        } finally {
               try {
  -                // getLogger().log("start",LOG_CHANNEL,Logger.DEBUG);
  -
  -                // test connection
  -                connectIfNeeded();
  -
  -                // discard changes made outside a tranaction
  -                connection.rollback();
  -            } catch (Exception e) {
  -                throw new XAException(XAException.XAER_RMERR);
  +                conn.close(); /* We must always return connections to the pool,
  +                                 or we'd eventually run out. */
  +            } catch(SQLException e) {
  +                getLogger().log(e,LOG_CHANNEL,Logger.ERROR);
               }
  -            alreadyEnlisted=true;
           }
       }
       
       
  +   /**
  +    * Start work on behalf of a transaction branch specified in xid.
  +    */
  +   public void start(Xid xid, int flags)
  +       throws XAException {
  +           getLogger().log("start(): beginning transaction with xid "+xid, 
LOG_CHANNEL, Logger.INFO);
  +
  +       TransactionId id = (TransactionId)connectionMap.get(Thread.currentThread());
  +
  +       switch(flags) {
  +           case XAResource.TMNOFLAGS:
  +               if(id != null)
  +                   throw new XAException(XAException.XAER_INVAL);
  +               id = new TransactionId(xid, TX_IDLE);
  +
  +               getLogger().log("start(): adding to map for "+Thread.currentThread(),
  +                   LOG_CHANNEL, Logger.INFO);
  +
  +               connectionMap.put(Thread.currentThread(), id);
  +               break;
  +           case XAResource.TMJOIN:
  +               getLogger().log("TMJOIN for transaction in thread: 
"+Thread.currentThread(), LOG_CHANNEL, Logger.DEBUG);
  +               if(id == null)
  +                   throw new XAException(XAException.XAER_NOTA);
  +               break;
  +           case XAResource.TMRESUME:
  +               getLogger().log("TMRESUME for transaction in thread: 
"+Thread.currentThread(), LOG_CHANNEL, Logger.DEBUG);
  +               if(id == null)
  +                   throw new XAException(XAException.XAER_NOTA);
  +               if(id.status != TX_SUSPENDED)
  +                   throw new XAException(XAException.XAER_INVAL);
  +               id.status = TX_IDLE;
  +               break;
  +       }
  +
  +   }    
  +
       // ----------------------------------------------- DescriptorsStore Methods
       
       
  @@ -605,6 +550,7 @@
           
           ObjectNode result = null;
           PreparedStatement statement = null;
  +        Connection connection = getCurrentConnection();
           
           try {
               
  @@ -698,7 +644,6 @@
               
           } catch (SQLException e) {
               getLogger().log(e,LOG_CHANNEL,Logger.ERROR);
  -            connectIfNeededAndPossible();
               throw new ServiceAccessException(this, e);
           } finally {
               closeStatement(statement);
  @@ -718,6 +663,7 @@
           throws ServiceAccessException, ObjectNotFoundException {
           
           PreparedStatement statement = null;
  +        Connection connection = getCurrentConnection();
           
           try {
               statement = connection.prepareStatement
  @@ -785,7 +731,6 @@
               
           } catch (SQLException e) {
               getLogger().log(e,LOG_CHANNEL,Logger.ERROR);
  -            connectIfNeededAndPossible();
               throw new ServiceAccessException(this, e);
           } finally {
               closeStatement(statement);
  @@ -807,6 +752,7 @@
           throws ServiceAccessException, ObjectAlreadyExistsException {
           
           PreparedStatement statement = null;
  +        Connection connection = getCurrentConnection();
           
           try {
               
  @@ -871,7 +817,6 @@
               
           } catch (SQLException e) {
               getLogger().log(e,LOG_CHANNEL,Logger.ERROR);
  -            connectIfNeededAndPossible();
               throw new ServiceAccessException(this, e);
           } finally {
               closeStatement(statement);
  @@ -891,6 +836,7 @@
           throws ServiceAccessException, ObjectNotFoundException {
           
           PreparedStatement statement = null;
  +        Connection connection = getCurrentConnection();
           
           try {
               
  @@ -923,7 +869,6 @@
               
           } catch (SQLException e) {
               getLogger().log(e,LOG_CHANNEL,Logger.ERROR);
  -            connectIfNeededAndPossible();
               throw new ServiceAccessException(this, e);
           }
       }
  @@ -939,6 +884,7 @@
           throws ServiceAccessException {
           
           PreparedStatement statement = null;
  +        Connection connection = getCurrentConnection();
           
           try {
               int inheritable = 0;
  @@ -966,7 +912,6 @@
               statement.execute();
           } catch (SQLException e) {
               getLogger().log(e,LOG_CHANNEL,Logger.ERROR);
  -            connectIfNeededAndPossible();
               throw new ServiceAccessException(this, e);
           } finally {
               closeStatement(statement);
  @@ -987,6 +932,7 @@
           /* Warning changes to this method should also be done to 
CloudscapeDescriptorsStore */
           
           PreparedStatement statement = null;
  +        Connection connection = getCurrentConnection();
           
           try {
               NodeRevisionNumber revisionNumber = permission.getRevisionNumber();
  @@ -1007,7 +953,6 @@
               statement.execute();
           } catch (SQLException e) {
               getLogger().log(e,LOG_CHANNEL,Logger.ERROR);
  -            connectIfNeededAndPossible();
               throw new ServiceAccessException(this, e);
           } finally {
               closeStatement(statement);
  @@ -1026,6 +971,7 @@
           throws ServiceAccessException {
           
           PreparedStatement statement = null;
  +        Connection connection = getCurrentConnection();
           
           try {
               
  @@ -1035,7 +981,6 @@
               statement.execute();
           } catch (SQLException e) {
               getLogger().log(e,LOG_CHANNEL,Logger.ERROR);
  -            connectIfNeededAndPossible();
               throw new ServiceAccessException(this, e);
           } finally {
               closeStatement(statement);
  @@ -1055,6 +1000,7 @@
           
           Vector permissionVector = new Vector();
           PreparedStatement statement = null;
  +        Connection connection = getCurrentConnection();
           
           try {
               statement = connection.prepareStatement
  @@ -1084,7 +1030,6 @@
               
           } catch (SQLException e) {
               getLogger().log(e,LOG_CHANNEL,Logger.ERROR);
  -            connectIfNeededAndPossible();
               throw new ServiceAccessException(this, e);
           } finally {
               closeStatement(statement);
  @@ -1104,6 +1049,7 @@
           throws ServiceAccessException {
           
           PreparedStatement statement = null;
  +        Connection connection = getCurrentConnection();
           
           try {
               int inheritable = 0;
  @@ -1129,7 +1075,6 @@
               statement.execute();
           } catch (SQLException e) {
               getLogger().log(e,LOG_CHANNEL,Logger.ERROR);
  -            connectIfNeededAndPossible();
               throw new ServiceAccessException(this, e);
           } finally {
               closeStatement(statement);
  @@ -1149,6 +1094,7 @@
           throws ServiceAccessException, LockTokenNotFoundException {
           
           PreparedStatement statement = null;
  +        Connection connection = getCurrentConnection();
           
           try {
               
  @@ -1182,7 +1128,6 @@
               
           } catch (SQLException e) {
               getLogger().log(e,LOG_CHANNEL,Logger.ERROR);
  -            connectIfNeededAndPossible();
               throw new ServiceAccessException(this, e);
           } finally {
               closeStatement(statement);
  @@ -1202,6 +1147,7 @@
           throws ServiceAccessException, LockTokenNotFoundException {
           
           Statement statement = null;
  +        Connection connection = getCurrentConnection();
           
           try {
               
  @@ -1219,7 +1165,6 @@
               
           } catch (SQLException e) {
               getLogger().log(e,LOG_CHANNEL,Logger.ERROR);
  -            connectIfNeededAndPossible();
               throw new ServiceAccessException(this, e);
           } finally {
               closeStatement(statement);
  @@ -1255,6 +1200,7 @@
           
           Vector lockVector = new Vector();
           PreparedStatement statement = null;
  +        Connection connection = getCurrentConnection();
           
           try {
               
  @@ -1286,7 +1232,6 @@
               
           } catch (SQLException e) {
               getLogger().log(e,LOG_CHANNEL,Logger.ERROR);
  -            connectIfNeededAndPossible();
               throw new ServiceAccessException(this, e);
           } finally {
               closeStatement(statement);
  @@ -1309,6 +1254,7 @@
           NodeRevisionDescriptors revisionDescriptors = null;
           PreparedStatement statement = null;
           PreparedStatement statement2 = null;
  +        Connection connection = getCurrentConnection();
           
           try {
               ResultSet res = null;
  @@ -1395,7 +1341,6 @@
               
           } catch (SQLException e) {
               getLogger().log(e,LOG_CHANNEL,Logger.ERROR);
  -            connectIfNeededAndPossible();
               throw new ServiceAccessException(this, e);
           } finally {
               closeStatement(statement);
  @@ -1420,6 +1365,7 @@
           // creating the new records in the database.
           
           PreparedStatement statement = null;
  +        Connection connection = getCurrentConnection();
           
           try {
               ResultSet res = null;
  @@ -1463,7 +1409,6 @@
               
           } catch (SQLException e) {
               getLogger().log(e,LOG_CHANNEL,Logger.ERROR);
  -            connectIfNeededAndPossible();
               throw new ServiceAccessException(this, e);
           } finally {
               closeStatement(statement);
  @@ -1501,6 +1446,7 @@
           throws ServiceAccessException {
           
           PreparedStatement statement = null;
  +        Connection connection = getCurrentConnection();
           
           try {
               
  @@ -1530,7 +1476,6 @@
               
           } catch (SQLException e) {
               getLogger().log(e,LOG_CHANNEL,Logger.ERROR);
  -            connectIfNeededAndPossible();
               throw new ServiceAccessException(this, e);
           } finally {
               closeStatement(statement);
  @@ -1551,6 +1496,7 @@
           
           NodeRevisionDescriptor revisionDescriptor = null;
           PreparedStatement statement = null;
  +        Connection connection = getCurrentConnection();
   
       if(revisionNumber == null)
           throw new RevisionDescriptorNotFoundException(uri.toString());
  @@ -1620,7 +1566,6 @@
               
           } catch (SQLException e) {
               getLogger().log(e,LOG_CHANNEL,Logger.ERROR);
  -            connectIfNeededAndPossible();
               throw new ServiceAccessException(this, e);
           } finally {
               closeStatement(statement);
  @@ -1642,6 +1587,7 @@
           throws ServiceAccessException {
           
           PreparedStatement statement = null;
  +        Connection connection = getCurrentConnection();
           
           try {
               
  @@ -1700,7 +1646,6 @@
               
           } catch (SQLException e) {
               getLogger().log(e,LOG_CHANNEL,Logger.ERROR);
  -            connectIfNeededAndPossible();
               throw new ServiceAccessException(this, e);
           } finally {
               closeStatement(statement);
  @@ -1738,6 +1683,7 @@
           throws ServiceAccessException {
           
           PreparedStatement statement = null;
  +        Connection connection = getCurrentConnection();
           
           try {
               
  @@ -1767,7 +1713,6 @@
               
           } catch (SQLException e) {
               getLogger().log(e,LOG_CHANNEL,Logger.ERROR);
  -            connectIfNeededAndPossible();
               throw new ServiceAccessException(this, e);
           } finally {
               closeStatement(statement);
  @@ -1787,10 +1732,66 @@
               try {
                   statement.close();
               } catch (SQLException e) {
  -                connectIfNeededAndPossible();
  +                getLogger().log(e,LOG_CHANNEL,Logger.ERROR);
               }
           }
       }
  -    
  +
  +    /** 
  +     * Get the Connection object associated with the current transaction.
  +     */
  +
  +    protected Connection getCurrentConnection() {
  +
  +//        getLogger().log("Getting current connection for thread "+
  +//                Thread.currentThread(), LOG_CHANNEL, Logger.INFO);
  +        TransactionId id = (TransactionId)connectionMap.get(Thread.currentThread());
  +        if(id == null) {
  +            getLogger().log("No id for current thread - called outside 
transaction?", LOG_CHANNEL, Logger.INFO);
  +            return globalConnection;
  +        }
  +
  +        Connection conn = id.connection;
  +
  +        if(conn == null) {
  +            getLogger().log("No connection for current id - shouldn't be possible", 
LOG_CHANNEL, Logger.ERROR);
  +            return globalConnection;
  +        }
  +
  +        getLogger().log("Returning current valid connection from map", LOG_CHANNEL, 
Logger.INFO);
  +        return conn;
  +    }
  +
  +    private class TransactionId 
  +    {
  +        public Xid xid;
  +        public int status;
  +        public boolean rollbackOnly;
  +        Connection connection;
  +
  +        public TransactionId(Xid xid, int status) {
  +            this.xid = xid;
  +            this.status = status;
  +            rollbackOnly = false;
  +
  +            /* Now, fetch a connection from the DataSource */
  +            try {
  +                connection = ds.getConnection();
  +                if(connection == null) {
  +                    System.out.println("CONNDEBUG: Got null connection from 
datasource");
  +                    connection = globalConnection;
  +                    return;
  +                }
  +
  +                connection.setAutoCommit(false);
  +                System.out.println("CONNDEBUG: Got connection successfully");
  +            } catch(SQLException e) {
  +                System.out.println("CONNDEBUG: Couldn't get connection: 
"+e.getMessage());
  +                connection = globalConnection;
  +                e.printStackTrace();
  +            }
  +        }
  +
  +    }
       
   }
  
  
  

--
To unsubscribe, e-mail:   <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>

Reply via email to