db-ojb-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From arm...@apache.org
Subject svn commit: r495677 [3/9] - in /db/ojb/trunk: ./ profile/ src/java/org/apache/ojb/broker/ src/java/org/apache/ojb/broker/accesslayer/ src/java/org/apache/ojb/broker/accesslayer/batch/ src/java/org/apache/ojb/broker/accesslayer/sql/ src/java/org/apache/...
Date Fri, 12 Jan 2007 18:19:45 GMT
Modified: db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/StatementManagerImpl.java
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/StatementManagerImpl.java?view=diff&rev=495677&r1=495676&r2=495677
==============================================================================
--- db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/StatementManagerImpl.java (original)
+++ db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/StatementManagerImpl.java Fri Jan 12 10:19:39 2007
@@ -31,11 +31,16 @@
 import org.apache.ojb.broker.platforms.Platform;
 import org.apache.ojb.broker.platforms.PlatformException;
 import org.apache.ojb.broker.util.SqlHelper;
+import org.apache.ojb.broker.util.ExceptionHelper;
 import org.apache.ojb.broker.util.logging.Logger;
 import org.apache.ojb.broker.util.logging.LoggerFactory;
 
 /**
- * Manages the JDBC-Statement resources.
+ * Manages the JDBC-Statement resources. This class is responsible to create statements
+ * and to cleanup used resources like statements and result sets.
+ * <br/>
+ * Additionally this implementation supports a simple statement cache (without wrapping
+ * or "proxying" the used {@link java.sql.Connection} and {@link java.sql.Statement}).
  *
  * @version $Id$
  */
@@ -43,13 +48,17 @@
 {
     private Logger log = LoggerFactory.getLogger(StatementManagerImpl.class);
 
+    protected final static short STMT_TYPE_PREPARED = 2;
+    protected final static short STMT_TYPE_CALLABLE = 3;
+    protected final static short STMT_TYPE_NORMAL = 4;
+
     /** the associated broker */
     protected final PersistenceBrokerInternal broker;
     protected final Platform platform;
     protected final ConnectionManagerIF connectionManager;
 
     /** force use of JDBC 1.0 statement creation */
-    protected boolean FORCEJDBC1_0 = false;
+    protected boolean forceJdbc_1_0 = false;
     /** Global fetch size, set in {@link org.apache.ojb.broker.metadata.ConnectionFactoryDescriptor}. */
     protected final int fetchSize;
 
@@ -71,26 +80,34 @@
         statementCache = new StatementBuffer(maxCachedStatements);
         // detect JDBC level
         double level = connectionManager.getConnectionDescriptor().getJdbcLevel();
-        FORCEJDBC1_0 = level == 1.0;
+        forceJdbc_1_0 = level == 1.0;
     }
 
     public void closeResources(Statement stmt, ResultSet rs)
     {
-        Statement tmpStmt = stmt;
         if(useStatementCache && statementCache.containsValue(stmt))
         {
-            tmpStmt = null;
+            // don't close the cached statement
+            internalCloseResources(null, rs);
+        }
+        else
+        {
+            internalCloseResources(stmt, rs);
         }
+    }
+
+    void internalCloseResources(Statement stmt, ResultSet rs)
+    {
         try
         {
-            platform.beforeStatementClose(tmpStmt, rs);
+            platform.beforeStatementClose(stmt, rs);
             //close statement on wrapped statement class, or real statement
-            if(tmpStmt != null)
+            if(stmt != null)
             {
-                if(log.isDebugEnabled()) log.debug("close used statement: " + tmpStmt);
-                tmpStmt.close();
+                if(log.isDebugEnabled()) log.debug("close used statement: " + stmt);
+                stmt.close();
             }
-            platform.afterStatementClose(tmpStmt, rs);
+            platform.afterStatementClose(stmt, rs);
         }
         catch(PlatformException e)
         {
@@ -105,6 +122,11 @@
 
     public void beforeConnectionRelease()
     {
+        clearStatementCache();
+    }
+
+    protected void clearStatementCache()
+    {
         if(statementCache.size() > 0)
         {
             boolean old = useStatementCache;
@@ -115,7 +137,7 @@
                 while(it.hasNext())
                 {
                     it.next();
-                    closeResources((PreparedStatement) it.getValue(), null);
+                    internalCloseResources((PreparedStatement) it.getValue(), null);
                     it.remove();
                 }
             }
@@ -134,7 +156,11 @@
     {
         try
         {
-            return prepareStatement(connectionManager.getConnection(), sql, scrollable, callableStmt, explicitFetchSizeHint);
+            return (PreparedStatement) prepareStatement(
+                    sql,
+                    scrollable,
+                    callableStmt ? STMT_TYPE_CALLABLE : STMT_TYPE_PREPARED,
+                    explicitFetchSizeHint);
         }
         catch(SQLException ex)
         {
@@ -156,14 +182,14 @@
     }
 
     /**
-     * return a generic Statement for the given ClassDescriptor.
+     * Return a generic Statement for the given ClassDescriptor.
      * Never use this method for UPDATE/INSERT/DELETE if you want to use the batch mode.
      */
     public Statement getGenericStatement(boolean scrollable) throws PersistenceBrokerException
     {
         try
         {
-            return createStatement(connectionManager.getConnection(), scrollable,
+            return prepareStatement(null, scrollable, STMT_TYPE_NORMAL,
                     StatementManager.FETCH_SIZE_NOT_EXPLICITLY_SET);
         }
         catch(SQLException ex)
@@ -181,195 +207,155 @@
     /**
      * Prepares a statement with parameters that should work with most RDBMS.
      *
-     * @param con the connection to utilize
      * @param sql the sql syntax to use when creating the statement.
      * @param scrollable determines if the statement will be scrollable.
-     * @param callableStmt if <code>false</code>, then a {@link java.sql.PreparedStatement}
-     * will be created. If <code>true</code>, then a {@link java.sql.CallableStatement} will be created.
+     * @param stmtType The type of the statement, see {@link #STMT_TYPE_CALLABLE},
+     * {@link #STMT_TYPE_PREPARED}, {@link #STMT_TYPE_NORMAL}.
      * @param explicitFetchSizeHint will be used as fetchSize hint
      * (if applicable) if > 0
      * @return a statement that can be used to execute the syntax contained in
      *         the <code>sql</code> argument.
      */
-    protected PreparedStatement prepareStatement(Connection con,
-                                                 String sql,
+    protected Statement prepareStatement(String sql,
                                                  boolean scrollable,
-                                                 boolean callableStmt,
-                                                 int explicitFetchSizeHint) throws SQLException
+                                                 short stmtType,
+                                                 int explicitFetchSizeHint) throws SQLException, LookupException
     {
-        PreparedStatement result;
+        final Connection con = connectionManager.getConnection();
+        Statement result = null;
 
-        if(useStatementCache && !callableStmt)
+        if(useStatementCache && stmtType != STMT_TYPE_NORMAL)
         {
             result = statementCache.getStatement(sql, scrollable, explicitFetchSizeHint);
-            if(result != null)
+            if(result != null && !(result.getConnection() == con))
             {
-                return result;
+                result = null;
             }
         }
-
-        // if a JDBC1.0 driver is used the signature
-        // prepareStatement(String, int, int) is  not defined.
-        // we then call the JDBC1.0 variant prepareStatement(String)
-        try
+        if(result == null)
         {
-            // if necessary use JDB1.0 methods
-            if(!FORCEJDBC1_0)
+            // if a JDBC1.0 driver is used the signature
+            // prepareStatement(String, int, int) is  not defined.
+            // we then call the JDBC1.0 variant prepareStatement(String)
+            try
             {
-                if(!callableStmt)
+                // if necessary use JDB1.0 methods
+                if(!forceJdbc_1_0)
                 {
-                    result =
-                            con.prepareStatement(
-                                    sql,
-                                    scrollable
-                                            ? ResultSet.TYPE_SCROLL_INSENSITIVE
-                                            : ResultSet.TYPE_FORWARD_ONLY,
-                                    ResultSet.CONCUR_READ_ONLY);
-                    performFetchSizeSetting(result, explicitFetchSizeHint);
-
-                    // add statement to cache
-                    if(useStatementCache) statementCache.addStatement(sql, result, scrollable);
+                    result = jdbcVersionTwoStatement(con, sql, scrollable, stmtType, explicitFetchSizeHint);
+                    performFetchSizeSetting(result, explicitFetchSizeHint, sql);
                 }
                 else
                 {
-                    result =
-                            con.prepareCall(
-                                    sql,
-                                    scrollable
-                                            ? ResultSet.TYPE_SCROLL_INSENSITIVE
-                                            : ResultSet.TYPE_FORWARD_ONLY,
-                                    ResultSet.CONCUR_READ_ONLY);
+                    result = jdbcVersionOneStatement(con, sql, stmtType);
                 }
             }
-            else
+            catch(AbstractMethodError err)
             {
-                if(callableStmt)
+                // this exception is raised if Driver is not JDBC 2.0 compliant
+                log.warn("Used driver seems not JDBC 2.0 compatible, use the JDBC 1.0 mode", err);
+                result = jdbcVersionOneStatement(con, sql, stmtType);
+                forceJdbc_1_0 = true;
+            }
+            catch(SQLException eSql)
+            {
+                // there are JDBC Driver that nominally implement JDBC 2.0, but
+                // throw DriverNotCapableExceptions. If we catch one of these
+                // we force usage of JDBC 1.0
+                if(eSql
+                        .getClass()
+                        .getName()
+                        .equals("interbase.interclient.DriverNotCapableException"))
                 {
-                    result = con.prepareStatement(sql);
-
-                    // add statement to cache
-                    if(useStatementCache) statementCache.addStatement(sql, result, scrollable);
+                    log.warn("JDBC 2.0 problems with this interbase driver, we use the JDBC 1.0 mode");
+                    result = jdbcVersionOneStatement(con, sql, stmtType);
+                    forceJdbc_1_0 = true;
                 }
                 else
                 {
-                    result = con.prepareCall(sql);
+                    throw eSql;
                 }
             }
-        }
-        catch(AbstractMethodError err)
-        {
-            // this exception is raised if Driver is not JDBC 2.0 compliant
-            log.warn("Used driver seems not JDBC 2.0 compatible, use the JDBC 1.0 mode", err);
-            if(callableStmt)
-            {
-                result = con.prepareStatement(sql);
-            }
-            else
+            try
             {
-                result = con.prepareCall(sql);
+                platform.afterStatementCreate(result);
             }
-            FORCEJDBC1_0 = true;
-        }
-        catch(SQLException eSql)
-        {
-            // there are JDBC Driver that nominally implement JDBC 2.0, but
-            // throw DriverNotCapableExceptions. If we catch one of these
-            // we force usage of JDBC 1.0
-            if(eSql
-                    .getClass()
-                    .getName()
-                    .equals("interbase.interclient.DriverNotCapableException"))
+            catch(PlatformException e)
             {
-                log.warn("JDBC 2.0 problems with this interbase driver, we use the JDBC 1.0 mode");
-                if(callableStmt)
-                {
-                    result = con.prepareStatement(sql);
-                }
-                else
-                {
-                    result = con.prepareCall(sql);
-                }
-                FORCEJDBC1_0 = true;
-            }
-            else
-            {
-                throw eSql;
+                log.error("Platform dependend failure after create of new statement", e);
             }
         }
-        try
-        {
-            platform.afterStatementCreate(result);
-        }
-        catch(PlatformException e)
-        {
-            log.error("Platform dependend failure", e);
-        }
         return result;
     }
 
-    /** Creates a statement with parameters that should work with most RDBMS. */
-    protected Statement createStatement(Connection con, boolean scrollable, int explicitFetchSizeHint) throws SQLException
+    protected Statement jdbcVersionTwoStatement(final Connection con,
+                                                final String sql,
+                                                final boolean scrollable,
+                                                final short stmtType,
+                                                final int explicitFetchSizeHint) throws SQLException
     {
-        Statement result;
+        final Statement result;
         try
         {
-            // if necessary use JDBC1.0 methods
-            if(!FORCEJDBC1_0)
+            if(stmtType == STMT_TYPE_PREPARED)
             {
-                result =
-                        con.createStatement(
-                                scrollable
-                                        ? ResultSet.TYPE_SCROLL_INSENSITIVE
-                                        : ResultSet.TYPE_FORWARD_ONLY,
-                                ResultSet.CONCUR_READ_ONLY);
-                performFetchSizeSetting(result, explicitFetchSizeHint);
+                result = con.prepareStatement( sql,
+                        scrollable ? ResultSet.TYPE_SCROLL_INSENSITIVE : ResultSet.TYPE_FORWARD_ONLY,
+                        ResultSet.CONCUR_READ_ONLY);
+                performFetchSizeSetting(result, fetchSize, sql);
+                // add statement to cache
+                if(useStatementCache) statementCache.addStatement(sql, result, scrollable);
+            }
+            else if(stmtType == STMT_TYPE_CALLABLE)
+            {
+                result = con.prepareCall(sql,
+                        scrollable ? ResultSet.TYPE_SCROLL_INSENSITIVE : ResultSet.TYPE_FORWARD_ONLY,
+                        ResultSet.CONCUR_READ_ONLY);
+                performFetchSizeSetting(result, fetchSize, sql);
+                // add statement to cache
+                if(useStatementCache) statementCache.addStatement(sql, result, scrollable);
             }
             else
             {
-                result = con.createStatement();
+                result = con.createStatement(
+                        scrollable ? ResultSet.TYPE_SCROLL_INSENSITIVE : ResultSet.TYPE_FORWARD_ONLY,
+                        ResultSet.CONCUR_READ_ONLY);
             }
         }
-        catch(AbstractMethodError err)
+        catch(SQLException e)
         {
-            // if a JDBC1.0 driver is used, the signature
-            // createStatement(int, int) is  not defined.
-            // we then call the JDBC1.0 variant createStatement()
-            log.warn("Used driver seems not JDBC 2.0 compatible, use the JDBC 1.0 mode", err);
-            result = con.createStatement();
-            FORCEJDBC1_0 = true;
+            String msg = ExceptionHelper.generateMessage("Statement creation failed", e, sql);
+            log.error(msg);
+            throw e;
         }
-        catch(SQLException eSql)
+        return result;
+    }
+
+    protected Statement jdbcVersionOneStatement(final Connection con,
+                                                final String sql,
+                                                final short stmtType) throws SQLException
+    {
+        final Statement result;
+        if(stmtType == STMT_TYPE_PREPARED)
         {
-            // there are JDBC Driver that nominally implement JDBC 2.0, but
-            // throw DriverNotCapableExceptions. If we catch one of these
-            // we force usage of JDBC 1.0
-            if(eSql
-                    .getClass()
-                    .getName()
-                    .equals("interbase.interclient.DriverNotCapableException"))
-            {
-                log.warn("JDBC 2.0 problems with this interbase driver, we use the JDBC 1.0 mode");
-                FORCEJDBC1_0 = true;
-                result = con.createStatement();
-            }
-            else
-            {
-                throw eSql;
-            }
+            result = con.prepareStatement(sql);
+            // add statement to cache
+            if(useStatementCache) statementCache.addStatement(sql, result, false);
         }
-        try
+        else if(stmtType == STMT_TYPE_CALLABLE)
         {
-            platform.afterStatementCreate(result);
+            result = con.prepareCall(sql);
+            // add statement to cache
+            if(useStatementCache) statementCache.addStatement(sql, result, false);
         }
-        catch(PlatformException e)
+        else
         {
-            log.error("Platform dependend failure", e);
+            result = con.createStatement();
         }
         return result;
     }
 
-    private void performFetchSizeSetting(Statement stmt, int explicitFetchSizeHint)
-            throws SQLException
+    private void performFetchSizeSetting(final Statement stmt, final int explicitFetchSizeHint, final String sql)
     {
         if(stmt != null)
         {
@@ -384,11 +370,22 @@
             }
             else
             {
-                fetchSizeHint = fetchSize; // connection pool default
+                fetchSizeHint = fetchSize; // configured default setting
             }
-            if(fetchSizeHint > 0)
+            try
             {
-                stmt.setFetchSize(fetchSize);
+                if(fetchSizeHint > 0)
+                {
+                    stmt.setFetchSize(fetchSize);
+                }
+                else if(useStatementCache) // guarantee that cached stmt will use default fetch size setting
+                {
+                    stmt.setFetchSize(StatementManager.FETCH_SIZE_NOT_EXPLICITLY_SET);
+                }
+            }
+            catch(SQLException e)
+            {
+                log.warn("Can't set fetch size '" + fetchSize + "' on statement for query: " + sql);
             }
         }
     }
@@ -401,6 +398,15 @@
     public void setUseStatementCache(boolean useStatementCache)
     {
         this.useStatementCache = useStatementCache;
+        if(!useStatementCache && statementCache.size() > 0)
+        {
+            clearStatementCache();
+        }
+    }
+
+    public Platform getPlatform()
+    {
+        return platform;
     }
 
     //===================================================================
@@ -415,27 +421,19 @@
             super(max);
         }
 
-        void addStatement(String sql, PreparedStatement stmt, boolean scrollable)
+        void addStatement(String sql, Statement stmt, boolean scrollable)
         {
             // important to differ if the sql should be scrollable or not, thus
             // append the result at the end of the sql key string
             super.put(sql + BooleanUtils.toStringTrueFalse(scrollable), stmt);
         }
 
-        PreparedStatement getStatement(String sql, boolean scrollable, int fetchSize)
+        Statement getStatement(String sql, boolean scrollable, int fetchSize)
         {
             // important to differ if the sql should be scrollable or not, thus
             // append the result at the end of the sql key string
-            PreparedStatement result = (PreparedStatement) super.get(sql + BooleanUtils.toStringTrueFalse(scrollable));
-            try
-            {
-                // allow to set fetch size for statement
-                performFetchSizeSetting(result, fetchSize);
-            }
-            catch(SQLException e)
-            {
-                log.error("Can't set fetch size '" + fetchSize + "' on statement for query: " + sql);
-            }
+            Statement result = (Statement) super.get(sql + BooleanUtils.toStringTrueFalse(scrollable));
+            performFetchSizeSetting(result, fetchSize, sql);
             return result;
         }
 
@@ -445,17 +443,8 @@
          */
         protected boolean removeLRU(LinkEntry linkEntry)
         {
-            boolean old = useStatementCache;
-            useStatementCache = false;
-            try
-            {
-                closeResources((PreparedStatement) linkEntry.getValue(), null);
-                return super.removeLRU(linkEntry);
-            }
-            finally
-            {
-                useStatementCache = old;
-            }
+            internalCloseResources((Statement) linkEntry.getValue(), null);
+            return super.removeLRU(linkEntry);
         }
     }
 }

Modified: db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/batch/BatchListener.java
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/batch/BatchListener.java?view=diff&rev=495677&r1=495676&r2=495677
==============================================================================
--- db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/batch/BatchListener.java (original)
+++ db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/batch/BatchListener.java Fri Jan 12 10:19:39 2007
@@ -18,22 +18,21 @@
 /**
  * Makes possible to hock up in batch process.
  *
- * @author <a href="mailto:arminw@apache.org">Armin Waibel</a>
  * @version $Id$
  */
 public interface BatchListener
 {
     /**
-     * Called before the {@link BatchEntity} was executed.
+     * Called before the {@link Batcher} was executed.
      * @param entity The entity the {@link BatchManager} work on.
      */
-    void beforeBatchExecution(BatchEntity entity);
+    void beforeBatchExecution(Batcher entity);
 
     /**
-     * Called after the {@link BatchEntity} was executed. If an exception occurs
+     * Called after the {@link Batcher} was executed. If an exception occurs
      * while batch entry execution, this method will be skipped.
      *
      * @param entity The entity the {@link BatchManager} work on.
      */
-    void afterBatchExecution(BatchEntity entity);
+    void afterBatchExecution(Batcher entity);
 }

Modified: db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/batch/BatchManager.java
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/batch/BatchManager.java?view=diff&rev=495677&r1=495676&r2=495677
==============================================================================
--- db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/batch/BatchManager.java (original)
+++ db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/batch/BatchManager.java Fri Jan 12 10:19:39 2007
@@ -31,24 +31,26 @@
     /**
      * Add values to batch.
      *
-     * @param info The metadata of the batch statement.
+     * @param batcher The batch metadata and values.
      * @param values An array of {@link ValueContainer} representing the object
      * or database row to batch.
      * @param expectedResult The expected {@link java.sql.Statement} return
      * value (number of modified rows).
      * @throws SQLException
      */
-    public void addToBatch(BatchInfo info, ValueContainer[] values, int expectedResult) throws SQLException;
+    public void add(Batcher batcher, ValueContainer[] values, int expectedResult) throws SQLException;
 
-    /** Execute all hold out batch statements. */
+    /**
+     * Execute all hold out batch statements.
+     */
     public void executeBatch() throws PersistenceBrokerException;
 
     /**
-     * Execute batch on given {@link BatchEntity}.
+     * Execute batch on given {@link Batcher}.
      *
-     * @param entity The {@link BatchEntity} to execute.
+     * @param batcher The {@link Batcher} to execute.
      */
-    public void executeBatch(BatchEntity entity) throws PersistenceBrokerException;
+    public void executeBatch(Batcher batcher) throws PersistenceBrokerException;
 
     /**
      * Discard all batched statements and close all resources without
@@ -57,17 +59,13 @@
     public void cancelBatch();
 
     /**
-     * Creates a new {@link BatchEntity} instance.
-     *
-     * @param descriptor An {@link BatchInfo} encapsulates meta info of the batch statement.
-     * @return a new create batch entity.
+     * Add an {@link BatchListener} object.
      */
-    public BatchEntity createEntity(BatchInfo descriptor);
-
-    /** Add an {@link BatchListener} object. */
     public void addBatchListener(BatchListener listener);
 
-    /** Removes an {@link BatchListener} object. */
+    /**
+     * Removes an {@link BatchListener} object.
+     */
     public void removeBatchListener(BatchListener listener);
 
     /**
@@ -128,13 +126,19 @@
      */
     public boolean getBatchSupportOptimisticLocking();
 
-    /** Set the batch limit. */
+    /**
+     * Set the batch limit.
+     */
     public void setBatchLimit(int limit);
 
-    /** Get the batch limit. */
+    /**
+     * Get the batch limit.
+     */
     public int getBatchLimit();
 
-    /** Returns the used {@link BatchStrategy}. */
+    /**
+     * Returns the used {@link BatchStrategy}.
+     */
     public BatchStrategy getStrategy();
 
     /**

Modified: db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/batch/BatchManagerImpl.java
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/batch/BatchManagerImpl.java?view=diff&rev=495677&r1=495676&r2=495677
==============================================================================
--- db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/batch/BatchManagerImpl.java (original)
+++ db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/batch/BatchManagerImpl.java Fri Jan 12 10:19:39 2007
@@ -26,6 +26,7 @@
 import org.apache.ojb.broker.metadata.JdbcConnectionDescriptor;
 import org.apache.ojb.broker.platforms.Platform;
 import org.apache.ojb.broker.util.ExceptionHelper;
+import org.apache.ojb.broker.util.IdentityArrayList;
 import org.apache.ojb.broker.util.logging.Logger;
 import org.apache.ojb.broker.util.logging.LoggerFactory;
 
@@ -42,7 +43,7 @@
  * <td><strong>Property Values</strong></td>
  * </tr>
  * <tr>
- * <td>batch.includeOptimisticLocking</td>
+ * <td>batch.supportOptimisticLocking</td>
  * <td>
  * To support optimistic locking within batch mode the used jdbc-driver have to return
  * the number of affected rows for each batched statement, see {@link java.sql.PreparedStatement#executeBatch()}.
@@ -57,7 +58,6 @@
  * </tr>
  * </table>
  *
- * @author <a href="mailto:armin@codeAuLait.de">Armin Waibel</a>
  * @version $Id$
  */
 public class BatchManagerImpl implements BatchManager
@@ -69,7 +69,6 @@
     protected ReturnValueValidator validator;
 
     private static final String BATCH_INCLUDE_OPTIMISTIC_LOCKING_PROPERTY_STR = "batch.supportOptimisticLocking";
-    private static final BatchListener[] NULL_LISTENER = new BatchListener[0];
     private int batchLimit = 50;
     private int batchLimitCounter;
     private boolean batchMode;
@@ -87,7 +86,10 @@
      * can be set <em>true</em> to optimize the batch handling for objects with optimistic locking enabled.
      */
     private boolean batchSupportOptimisticLocking;
-    private BatchListener[] batchListener = NULL_LISTENER;
+    /**
+     * Object identity based list to register {@link BatchListener}.
+     */
+    private List batchListener = new IdentityArrayList();
     private List batchEntities = new ArrayList();
 
     public BatchManagerImpl(PersistenceBrokerInternal broker, ReturnValueValidator validator)
@@ -132,66 +134,20 @@
         this.strategy = strategy;
     }
 
-    /** @see BatchManager#createEntity */
-    public BatchEntity createEntity(BatchInfo descriptor)
-    {
-        return new BatchEntity(this, descriptor);
-    }
-
-    public void addToBatch(BatchInfo info, ValueContainer[] values, int expectedResult) throws SQLException
+    public void executeBatch(Batcher batcher)
     {
-        if(checkBatchLimit())
-        {
-            if(log.isEnabledFor(Logger.INFO))
-            {
-                log.info("Batch limit reached, execute batch before add new batch entry");
-            }
-            executeBatch();
-        }
-
-        BatchEntity entity = findEntity(info);
-        if(entity == null)
-        {
-            // create new entity
-            entity = new BatchEntity(this, info);
-            if(log.isDebugEnabled()) log.debug("Create new BatchEntity: " + entity);
-            // lookup batch strategy and ask for updated (reordered, reduced, ...)
-            // list of batch entities
-            batchEntities = strategy.prepareForBatch(batchEntities, entity);
-        }
-        if(log.isDebugEnabled()) log.debug("Add batch values " + ArrayUtils.toString(values));
-        entity.addBatch(values, expectedResult);
-    }
-
-    private BatchEntity findEntity(BatchInfo info)
-    {
-        for(int i = 0; i < batchEntities.size(); i++)
-        {
-            BatchEntity batchEntity = (BatchEntity) batchEntities.get(i);
-            if(batchEntity.getInfo().equals(info))
-            {
-                return batchEntity;
-            }
-        }
-        return null;
-    }
-
-    /** @see BatchManager#executeBatch(BatchEntity) */
-    public void executeBatch(BatchEntity entity)
-    {
-        if(log.isDebugEnabled()) log.debug("Execute BatchEntity performing "
-                + entity.batchSize() + " batch entries. BatchEntity=" + entity);
-        for(int i = 0; i < batchListener.length; i++)
+        if(log.isDebugEnabled()) log.debug("Execute Batcher performing "
+                + batcher.batchSize() + " batch entries. Batcher=" + batcher);
+        for(int i = 0; i < batchListener.size(); i++)
         {
             try
             {
-                batchListener[i].beforeBatchExecution(entity);
+                ((BatchListener) batchListener.get(i)).beforeBatchExecution(batcher);
             }
             catch(Exception e)
             {
-                log.error("BatchListener cause exception", e);
-                throw new BatchException(
-                        "Error while perform batch listener before batch execution: " + batchListener[i]);
+                throw new BatchException("Error while perform batch listener before batch execution: "
+                        + batchListener.get(i), e);
             }
         }
 
@@ -200,32 +156,31 @@
         {
             try
             {
-                result = entity.executeBatch();
+                result = batcher.executeBatch(broker.serviceStatementManager(), broker.serviceJdbcAccess());
                 Platform platform = broker.getConfiguration().getJdbcConnectionDescriptor().getPlatform();
-                validator.validateResult(platform, entity.getInfo(), entity.getExpectedResults(), result);
+                validator.validateResult(platform, batcher, result);
             }
             finally
             {
-                entity.cleanup();
+                batcher.cleanup();
             }
         }
         catch(SQLException e)
         {
-            BatchInfo info = entity.getInfo();
-            throw ExceptionHelper.generateException(e, info.getSql(), info.getCld(), null, null, log);
+            throw ExceptionHelper.generateException(e, batcher.getSql(), batcher.getClassDescriptor(), null, null, log);
         }
 
-        for(int i = 0; i < batchListener.length; i++)
+        for(int i = 0; i < batchListener.size(); i++)
         {
             try
             {
-                batchListener[i].afterBatchExecution(entity);
+                ((BatchListener) batchListener.get(i)).afterBatchExecution(batcher);
             }
             catch(Exception e)
             {
                 log.error("BatchListener cause exception", e);
                 throw new BatchException(
-                        "Error while perform batch listener after batch execution: " + batchListener[i]);
+                        "Error while perform batch listener after batch execution: " + batchListener.get(i));
             }
         }
         batchLimitCounter -= result.length;
@@ -236,24 +191,24 @@
     {
         if(batchEntities.size() == 0) return;
 
-        if(log.isDebugEnabled()) log.debug("Excecute batch call on " + batchEntities.size() + " BatchEntity instances");
+        if(log.isDebugEnabled()) log.debug("Excecute batch call on " + batchEntities.size() + " Batcher instances");
         try
         {
             Iterator it = batchEntities.iterator();
-            BatchEntity entity;
+            Batcher batcher;
             while(it.hasNext())
             {
-                entity = (BatchEntity) it.next();
-                executeBatch(entity);
+                batcher = (Batcher) it.next();
+                executeBatch(batcher);
             }
         }
         finally
         {
-            cancelBatch();
+            cleanupAndPrepare();
         }
     }
 
-    public boolean checkBatchLimit()
+    public boolean batchLimitReached()
     {
         return batchLimitCounter > batchLimit;
     }
@@ -261,49 +216,39 @@
     /** @see BatchManager#cancelBatch */
     public void cancelBatch()
     {
+        cleanupAndPrepare();
+    }
+
+    /**
+     * Cleanup and prepare for reuse.
+     */
+    private void cleanupAndPrepare()
+    {
         batchEntities.clear();
         resetBatchCount();
     }
 
     public void addBatchListener(BatchListener listener)
     {
-        BatchListener[] newListeners = new BatchListener[batchListener.length + 1];
-        System.arraycopy(batchListener, 0, newListeners, 0, batchListener.length);
-        newListeners[newListeners.length - 1] = listener;
-        batchListener = newListeners;
+        if(!batchListener.contains(listener))
+        {
+            batchListener.add(listener);
+        }
+        else
+        {
+            log.info("BatchListener add: Already added listener found, will ignore multiple listener add");
+        }
     }
 
     public void removeBatchListener(BatchListener listener)
     {
-        if(batchListener.length == 0) return;
-
-        BatchListener[] newListeners = new BatchListener[batchListener.length - 1];
-        int pos = 0;
-        boolean match = false;
-        for(int i = 0; i < batchListener.length; i++)
-        {
-            if(batchListener[i] != listener)
-            {
-                if(pos == batchListener.length)
-                {
-                    // no listener match, break and don't change listener array
-                    log.info("Given BatchListener does not match, can't remove listener: " + listener);
-                    break;
-                }
-                newListeners[pos++] = batchListener[i];
-            }
-            else
-            {
-                match = true;
-            }
-        }
-        if(match) batchListener = newListeners;
+        batchListener.remove(listener);
     }
 
     public void reset()
     {
         cancelBatch();
-        batchListener = NULL_LISTENER;
+        batchListener.clear();
     }
 
     public void setBatchLimit(int limit)
@@ -348,7 +293,7 @@
     }
 
     /**
-     * Was called by {@link BatchEntity} when a new set of values
+     * Was called by {@link Batcher} when a new set of values
      * are added to batch.
      */
     void increaseBatchCount()
@@ -359,5 +304,43 @@
     private void resetBatchCount()
     {
         batchLimitCounter = 0;
+    }
+
+    public void add(Batcher batcher, ValueContainer[] values, int expectedResult) throws SQLException
+    {
+        if(batchLimitReached())
+        {
+            if(log.isEnabledFor(Logger.INFO))
+            {
+                log.info("Batch limit reached, execute batch before add new batch entry");
+            }
+            executeBatch();
+        }
+
+        Batcher entity = checkForExistingBatcher(batcher);
+        if(entity == null)
+        {
+            entity = batcher;
+            if(log.isDebugEnabled()) log.debug("Add new Batcher: " + batcher);
+            // lookup batch strategy and ask for updated (reordered, reduced, ...)
+            // list of batch entities
+            batchEntities = strategy.prepareForBatch(batchEntities, batcher);
+        }
+        if(log.isDebugEnabled()) log.debug("Add batch value row on batcher " + entity + ", values are "+ ArrayUtils.toString(values));
+        entity.add(values, expectedResult);
+        increaseBatchCount();
+    }
+
+    private Batcher checkForExistingBatcher(Batcher newBatcher)
+    {
+        for(int i = 0; i < batchEntities.size(); i++)
+        {
+            Batcher batcher = (Batcher) batchEntities.get(i);
+            if(batcher.equals(newBatcher))
+            {
+                return batcher;
+            }
+        }
+        return null;
     }
 }

Modified: db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/batch/BatchStrategy.java
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/batch/BatchStrategy.java?view=diff&rev=495677&r1=495676&r2=495677
==============================================================================
--- db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/batch/BatchStrategy.java (original)
+++ db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/batch/BatchStrategy.java Fri Jan 12 10:19:39 2007
@@ -22,25 +22,24 @@
 import org.apache.ojb.broker.OptimisticLockException;
 
 /**
- * This class is reponsible for order of {@link BatchEntity} instances.
+ * This class is reponsible for order of {@link Batcher} instances.
  *
- * @author <a href="mailto:armin@codeAuLait.de">Armin Waibel</a>
  * @version $Id$
  */
 public interface BatchStrategy
 {
     /**
-     * Prepare the current enqueued {@link BatchEntity} objects for add of
+     * Prepare the current enqueued {@link Batcher} objects for add of
      * the new entity - in general the strategy checks for conflicts with
-     * the new entity and execute the batch
+     * the new entity and execute the batch.
      *
-     * @param entities A collection of already enqueued {@link BatchEntity} objects.
-     * @param newEntity The new {@link BatchEntity} to add to batch queue.
+     * @param entities A collection of already enqueued {@link Batcher} objects.
+     * @param newEntity The new {@link Batcher} to add to batch queue.
      * @return The new batch entity list <strong>including</strong> the new entity
-     * (the order or/and the number of {@link BatchEntity} can be different from the orginal).
+     * (the order or/and the number of {@link Batcher} can be different from the orginal).
      * @throws OptimisticLockException
      */
-    List prepareForBatch(List entities, BatchEntity newEntity) throws OptimisticLockException;
+    List prepareForBatch(List entities, Batcher newEntity) throws OptimisticLockException;
 
     /**
      * Close this batch strategy.

Modified: db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/batch/BatchStrategyBase.java
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/batch/BatchStrategyBase.java?view=diff&rev=495677&r1=495676&r2=495677
==============================================================================
--- db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/batch/BatchStrategyBase.java (original)
+++ db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/batch/BatchStrategyBase.java Fri Jan 12 10:19:39 2007
@@ -26,7 +26,6 @@
  * {@link org.apache.ojb.broker.accesslayer.batch.BatchStrategyBase.TranspositionBan} interface to
  * control the order of batch entries.
  *
- * @author <a href="mailto:armin@codeAuLait.de">Armin Waibel</a>
  * @version $Id$
  */
 public abstract class BatchStrategyBase implements BatchStrategy
@@ -49,7 +48,7 @@
      */
     public abstract TranspositionBan[] getTranspositionBans();
 
-    public List prepareForBatch(List entities, BatchEntity newEntity) throws OptimisticLockException
+    public List prepareForBatch(List entities, Batcher newEntity) throws OptimisticLockException
     {
         /*
         only new batch entity objects need to be checked.
@@ -73,27 +72,31 @@
         CHECK_BANS_LOOP:
         for(int i = entities.size() - 1; i >= 0; i--)
         {
-            BatchEntity next = (BatchEntity) entities.get(i);
+            Batcher next = (Batcher) entities.get(i);
             for(int j = 0; j < bans.length; j++)
             {
-                if(bans[j].isBanned(newEntity.getInfo(), next.getInfo()))
+                if(bans[j].isBanned(newEntity, next))
                 {
                     toExecute = i + 1;
                     break CHECK_BANS_LOOP;
                 }
             }
         }
+        //System.out.println("*Batcher_before: " + entities.size());
         if(toExecute > 0)
         {
             for(Iterator it = entities.iterator();
                     (toExecute > 0) && it.hasNext(); toExecute--)
             {
-                BatchEntity next = (BatchEntity) it.next();
+                Batcher next = (Batcher) it.next();
                 batchManager.executeBatch(next);
                 it.remove();
+                //System.out.println("*remove: " + next);
             }
         }
+        //System.out.println("*add: " + newEntity);
         entities.add(newEntity);
+        //System.out.println("*Batcher_after: " + entities.size());
         return entities;
     }
 
@@ -105,10 +108,10 @@
         /**
          * Is transposition of batch entries of the given type banned?
          *
-         * @param infoNew The {@link BatchInfo} of the new or first batch entry.
-         * @param infoOld The {@link BatchInfo} of the already buffered batch entry.
+         * @param batcher The {@link Batcher} of the new or first batch entry.
+         * @param batcherOther The {@link Batcher} of the already buffered batch entry.
          * @return <em>True</em> if transposition is banned.
          */
-        public boolean isBanned(BatchInfo infoNew,  BatchInfo infoOld);
+        public boolean isBanned(Batcher batcher,  Batcher batcherOther);
     }
 }

Modified: db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/batch/BatchStrategyDefaultImpl.java
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/batch/BatchStrategyDefaultImpl.java?view=diff&rev=495677&r1=495676&r2=495677
==============================================================================
--- db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/batch/BatchStrategyDefaultImpl.java (original)
+++ db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/batch/BatchStrategyDefaultImpl.java Fri Jan 12 10:19:39 2007
@@ -27,16 +27,15 @@
  * follows from the known relations between tables,
  * reflected in repository.xml.
  *
- * @author <a href="mailto:olegnitz@apache.org">Oleg Nitz</a>
  * @version $Id$
  */
 public class BatchStrategyDefaultImpl extends BatchStrategyBase
 {
 
     private TranspositionBan[] bans = new TranspositionBan[]{
-        new InsertTranspositionBan(),
-        new DeleteTranspositionBan(),
-        new TheSameTableTranspositionBan(),
+            new InsertTranspositionBan(),
+            new DeleteTranspositionBan(),
+            new TheSameTableTranspositionBan(),
     };
 
     public BatchStrategyDefaultImpl(BatchManager batchManager)
@@ -55,18 +54,17 @@
     /**
      * Does cld1 have reference to cld2?
      */
-    private boolean hasReferenceTo(BatchInfo infoNew, BatchInfo infoOld)
+    private boolean hasReferenceTo(Batcher infoNew, Batcher infoOld)
     {
-        if(infoNew.getCld() != null && infoOld.getCld() != null)
+        if(infoNew.getClassDescriptor() != null && infoOld.getClassDescriptor() != null)
         {
-            List ordList = infoNew.getCld().getObjectReferenceDescriptors();
+            List ordList = infoNew.getClassDescriptor().getObjectReferenceDescriptors();
             if(!ordList.isEmpty())
             {
-                Class class2 = infoOld.getCld().getClassOfObject();
+                Class class2 = infoOld.getClassDescriptor().getClassOfObject();
                 for(Iterator it = ordList.iterator(); it.hasNext();)
                 {
-                    ObjectReferenceDescriptor ord =
-                            (ObjectReferenceDescriptor) it.next();
+                    ObjectReferenceDescriptor ord = (ObjectReferenceDescriptor) it.next();
                     if(ord.getItemClass().isAssignableFrom(class2))
                     {
                         return true;
@@ -80,20 +78,18 @@
     /**
      * Does cld1 have collection of cld2?
      */
-    private boolean hasCollection1ToNOf(BatchInfo infoNew, BatchInfo infoOld)
+    private boolean hasCollection1ToNOf(Batcher infoNew, Batcher infoOld)
     {
-        if(infoNew.getCld() != null && infoOld.getCld() != null)
+        if(infoNew.getClassDescriptor() != null && infoOld.getClassDescriptor() != null)
         {
-            List codList = infoNew.getCld().getCollectionDescriptors();
+            List codList = infoNew.getClassDescriptor().getCollectionDescriptors();
             if(!codList.isEmpty())
             {
-                Class class2 = infoOld.getCld().getClassOfObject();
+                Class class2 = infoOld.getClassDescriptor().getClassOfObject();
                 for(Iterator it2 = codList.iterator(); it2.hasNext();)
                 {
-                    CollectionDescriptor cod =
-                            (CollectionDescriptor) it2.next();
-                    if(!cod.isMtoNRelation()
-                            && cod.getItemClass().isAssignableFrom(class2))
+                    CollectionDescriptor cod = (CollectionDescriptor) it2.next();
+                    if(!cod.isMtoNRelation() && cod.getItemClass().isAssignableFrom(class2))
                     {
                         return true;
                     }
@@ -103,6 +99,33 @@
         return false;
     }
 
+    /**
+     * Is the first argument a indirection table entry and the other batch entry has
+     * a m:n reference to this indirection table?
+     */
+    private boolean isIndirectionTableOf(Batcher potentialIndirectionTable, Batcher potentialReference)
+    {
+        boolean result = false;
+        if(potentialIndirectionTable.isIndirectionTable() && potentialReference.getClassDescriptor() != null)
+        {
+            //System.out.println("# ind: " + potentialIndirectionTable);
+            //System.out.println("# ref: " + potentialReference);
+            List descriptors = potentialReference.getClassDescriptor().getCollectionDescriptors();
+            for(int i = 0; i < descriptors.size(); i++)
+            {
+                CollectionDescriptor colDes = (CollectionDescriptor) descriptors.get(i);
+                if(colDes.isMtoNRelation() && colDes.getIndirectionTableDescriptor().getTableName()
+                        .equals(potentialIndirectionTable.getTableName()))
+                {
+                    result = true;
+                    break;
+                }
+            }
+            //System.out.println("result: " + result);
+        }
+        return result;
+    }
+
 //-------------------- Inner classes -----------------------
 
     /**
@@ -112,19 +135,12 @@
      */
     public class InsertTranspositionBan implements TranspositionBan
     {
-        public boolean isBanned(BatchInfo infoNew,
-                                BatchInfo infoOld)
+        public boolean isBanned(Batcher infoNew, Batcher infoOld)
         {
-            return ((infoNew.getType() == BatchInfo.TYPE_OBJECT_INSERT)
-
-                    && ((infoOld.getType() == BatchInfo.TYPE_OBJECT_INSERT)
-                    || (infoOld.getType() == BatchInfo.TYPE_OBJECT_UPDATE))
-
-                    && (hasReferenceTo(infoOld, infoNew)
-                    || hasCollection1ToNOf(infoNew, infoOld))
-
-                    );
-            // TODO M:N indirection table
+            return infoNew.isInsert() &&
+                    (((infoOld.isInsert() || infoOld.isUpdate())
+                            && (hasReferenceTo(infoOld, infoNew) || hasCollection1ToNOf(infoNew, infoOld))
+                    ) || infoOld.isInsert() && isIndirectionTableOf(infoOld, infoNew));
         }
     }
 
@@ -136,19 +152,12 @@
      */
     public class DeleteTranspositionBan implements TranspositionBan
     {
-        public boolean isBanned(BatchInfo infoNew,
-                                BatchInfo infoOld)
+        public boolean isBanned(Batcher infoNew, Batcher infoOld)
         {
-            return (((infoNew.getType() == BatchInfo.TYPE_OBJECT_DELETE)
-                    || (infoNew.getType() == BatchInfo.TYPE_OBJECT_UPDATE))
-
-                    && (infoOld.getType() == BatchInfo.TYPE_OBJECT_DELETE)
-
-                    && (hasReferenceTo(infoNew, infoOld)
-                    || hasCollection1ToNOf(infoOld, infoNew))
-
-                    );
-            // TODO M:N indirection table
+            return (infoNew.isDelete() || infoNew.isUpdate()) &&
+                    (((infoOld.isDelete()) &&
+                            (hasReferenceTo(infoNew, infoOld) || hasCollection1ToNOf(infoOld, infoNew))
+                    ) || infoOld.isDelete() && isIndirectionTableOf(infoNew, infoOld));
         }
     }
 
@@ -159,28 +168,14 @@
      */
     public class TheSameTableTranspositionBan implements TranspositionBan
     {
-        public boolean isBanned(BatchInfo infoNew,
-                                BatchInfo infoOld)
+        public boolean isBanned(Batcher infoNew,
+                                Batcher infoOld)
         {
-            // TODO M:N indirection table
-            return (
-                    infoNew.getCld() != null
-                            && infoOld.getCld() != null
-                            && infoNew.getCld().getFullTableName().equals(infoOld.getCld().getFullTableName())
-                    &&
+            return infoNew.getTableName().equals(infoOld.getTableName()) &&
                     (
-                    ((infoNew.getType() == BatchInfo.TYPE_OBJECT_INSERT)
-                    && (infoOld.getType() == BatchInfo.TYPE_OBJECT_UPDATE))
-
-                    || ((infoNew.getType() == BatchInfo.TYPE_OBJECT_UPDATE)
-                    && (infoOld.getType() == BatchInfo.TYPE_OBJECT_DELETE))
-
-                    || ((infoNew.getType() == BatchInfo.TYPE_OBJECT_INSERT)
-                    && (infoOld.getType() == BatchInfo.TYPE_OBJECT_DELETE))
-
-                    || ((infoNew.getType() == BatchInfo.TYPE_OBJECT_DELETE)
-                    && (infoOld.getType() == BatchInfo.TYPE_OBJECT_INSERT))
-                    )
+                            (infoNew.isInsert() && (infoOld.isUpdate() || infoOld.isDelete()))
+                                    || (infoNew.isUpdate() && infoOld.isDelete())
+                                    || (infoNew.isDelete() && infoOld.isInsert())
                     );
         }
     }

Modified: db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/batch/ReturnValueValidator.java
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/batch/ReturnValueValidator.java?view=diff&rev=495677&r1=495676&r2=495677
==============================================================================
--- db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/batch/ReturnValueValidator.java (original)
+++ db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/batch/ReturnValueValidator.java Fri Jan 12 10:19:39 2007
@@ -15,7 +15,6 @@
  * limitations under the License.
  */
 
-import java.lang.Object;
 import java.sql.SQLException;
 
 import org.apache.ojb.broker.OptimisticLockException;
@@ -34,11 +33,13 @@
      * results (number of affected rows) with the <em>real</em> returned result array.
      *
      * @param platform The used platform.
-     * @param info The {@link BatchInfo} batch metadata.
-     * @param expectedResults The expected return value array.
+     * @param batcher The {@link Batcher} instance.
      * @param result The real return value array.
-     * @throws java.sql.SQLException If the return values are illegal or signal batch entries execution failures.
+     * @throws java.sql.SQLException If the return values are illegal or signal
+     * batch entries execution failures.
      * @throws org.apache.ojb.broker.OptimisticLockException If an optimistic lock issue occur.
      */
-    void validateResult(Platform platform, BatchInfo info, int[] expectedResults, int[] result) throws SQLException, OptimisticLockException;
+    void validateResult(Platform platform, Batcher batcher, int[] result)
+            throws SQLException, OptimisticLockException;
+
 }

Modified: db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/batch/ReturnValueValidatorImpl.java
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/batch/ReturnValueValidatorImpl.java?view=diff&rev=495677&r1=495676&r2=495677
==============================================================================
--- db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/batch/ReturnValueValidatorImpl.java (original)
+++ db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/batch/ReturnValueValidatorImpl.java Fri Jan 12 10:19:39 2007
@@ -36,18 +36,7 @@
     {
     }
 
-    /**
-     * Validates the batch statement execution result value array by comparing the expected
-     * results (number of affected rows) with the <em>real</em> returned result array.
-     *
-     * @param platform The used platform.
-     * @param info The {@link org.apache.ojb.broker.accesslayer.batch.BatchInfo} batch metadata.
-     * @param expectedResults The expected return value array.
-     * @param result The real return value array.
-     * @throws SQLException If the return values are illegal or signal batch entries execution failures.
-     * @throws OptimisticLockException If an optimistic lock issue occur.
-     */
-    public void validateResult(Platform platform, BatchInfo info, int[] expectedResults, int[] result) throws SQLException, OptimisticLockException
+    public void validateResult(Platform platform, Batcher batcher, int[] result) throws SQLException, OptimisticLockException
     {
         /*
         a batch execution failed when
@@ -56,27 +45,28 @@
         - it signal a failure while statement execution
         - optimistic lock issue
         */
+        int[] expectedResults = batcher.getExpectedResults();
         if(result != null && result.length == expectedResults.length)
         {
-            switch(info.getType())
+            switch(batcher.getType())
             {
-                case BatchInfo.TYPE_OBJECT_UPDATE:
-                    validateUpdate(info, expectedResults, result);
+                case Batcher.TYPE_UPDATE:
+                    validateUpdate(batcher, expectedResults, result);
                     break;
-                case BatchInfo.TYPE_OBJECT_INSERT:
-                    validateInsert(info, expectedResults, result);
+                case Batcher.TYPE_INSERT:
+                    validateInsert(batcher, expectedResults, result);
                     break;
-                case BatchInfo.TYPE_OBJECT_DELETE:
-                    validateDelete(info, expectedResults, result);
+                case Batcher.TYPE_DELETE:
+                    validateDelete(batcher, expectedResults, result);
                     break;
-                case BatchInfo.TYPE_INDIRECTION_TABLE_DELETE:
-                    validateIndirectionTableDelete(info, expectedResults, result);
+                case Batcher.TYPE_INDIRECTION_TABLE_DELETE:
+                    validateIndirectionTableDelete(batcher, expectedResults, result);
                     break;
-                case BatchInfo.TYPE_INDIRECTION_TABLE_INSERT:
-                    validateIndirectionTableInsert(info, expectedResults, result);
+                case Batcher.TYPE_INDIRECTION_TABLE_INSERT:
+                    validateIndirectionTableInsert(batcher, expectedResults, result);
                     break;
                 default:
-                    validateUnkownType(info, expectedResults, result);
+                    validateUnkownType(batcher, expectedResults, result);
             }
         }
         else
@@ -91,13 +81,13 @@
     /**
      * FOR INTERNAL USE ONLY! Validates UPDATE operation batch statement execution results.
      *
-     * @param info The {@link BatchInfo} batch metadata.
+     * @param batcher The {@link Batcher} batch metadata.
      * @param expectedResults The expected return value array.
      * @param result The real return value array.
      * @throws SQLException If the return values are illegal or signal batch entries execution failures.
      * @throws OptimisticLockException If an optimistic lock issue occur.
      */
-    protected void validateUpdate(BatchInfo info, int[] expectedResults, int[] result) throws SQLException, OptimisticLockException
+    protected void validateUpdate(Batcher batcher, int[] expectedResults, int[] result) throws SQLException, OptimisticLockException
     {
         for(int i = 0; i < result.length; i++)
         {
@@ -106,29 +96,29 @@
             {
                 if(resultValue == PreparedStatement.EXECUTE_FAILED)
                 {
-                    throw throwExecuteFailed(info, expectedResults, result, i);
+                    throw throwExecuteFailed(batcher, expectedResults, result, i);
                 }
-                else if(info.useOptimisticLocking())
+                else if(batcher.useOptimisticLocking())
                 {
                     // on insert of objects with enabled opt. locking we allow unverified
                     // return values, otherwise we throw an exception
                     if(resultValue == Statement.SUCCESS_NO_INFO)
                     {
-                        if(info.getType() != BatchInfo.TYPE_OBJECT_INSERT)
+                        if(batcher.getType() != Batcher.TYPE_INSERT)
                         {
-                            throw throwJdbcNotSupported(info, expectedResults, result, i);
+                            throw throwJdbcNotSupported(batcher, expectedResults, result, i);
                         }
                     }
                     else
                     {
-                        throw throwOptimisticLock(info, expectedResults, result, i);
+                        throw throwOptimisticLock(batcher, expectedResults, result, i);
                     }
                 }
                 else if(!(resultValue == PreparedStatement.SUCCESS_NO_INFO
                         || resultValue == PreparedStatement.CLOSE_ALL_RESULTS
                         || resultValue == 0))
                 {
-                    throw throwUnexpectedValue(info, expectedResults, result, i);
+                    throw throwUnexpectedValue(batcher, expectedResults, result, i);
                 }
             }
         }
@@ -137,13 +127,13 @@
     /**
      * FOR INTERNAL USE ONLY! Validates INSERT operation batch statement execution results.
      *
-     * @param info The {@link BatchInfo} batch metadata.
+     * @param batcher The {@link Batcher} batch metadata.
      * @param expectedResults The expected return value array.
      * @param result The real return value array.
      * @throws SQLException If the return values are illegal or signal batch entries execution failures.
      * @throws OptimisticLockException If an optimistic lock issue occur.
      */
-    protected void validateInsert(BatchInfo info, int[] expectedResults, int[] result) throws SQLException, OptimisticLockException
+    protected void validateInsert(Batcher batcher, int[] expectedResults, int[] result) throws SQLException, OptimisticLockException
     {
         for(int i = 0; i < result.length; i++)
         {
@@ -152,11 +142,11 @@
             {
                 if(resultValue == PreparedStatement.EXECUTE_FAILED)
                 {
-                    throw throwExecuteFailed(info, expectedResults, result, i);
+                    throw throwExecuteFailed(batcher, expectedResults, result, i);
                 }
                 else if(resultValue != PreparedStatement.SUCCESS_NO_INFO)
                 {
-                    throw throwUnexpectedValue(info, expectedResults, result, i);
+                    throw throwUnexpectedValue(batcher, expectedResults, result, i);
                 }
             }
         }
@@ -165,13 +155,13 @@
     /**
      * FOR INTERNAL USE ONLY! Validates DELETE operation batch statement execution results.
      *
-     * @param info The {@link BatchInfo} batch metadata.
+     * @param batcher The {@link Batcher} batch metadata.
      * @param expectedResults The expected return value array.
      * @param result The real return value array.
      * @throws SQLException If the return values are illegal or signal batch entries execution failures.
      * @throws OptimisticLockException If an optimistic lock issue occur.
      */
-    protected void validateDelete(BatchInfo info, int[] expectedResults, int[] result) throws SQLException, OptimisticLockException
+    protected void validateDelete(Batcher batcher, int[] expectedResults, int[] result) throws SQLException, OptimisticLockException
     {
         for(int i = 0; i < result.length; i++)
         {
@@ -180,28 +170,28 @@
             {
                 if(resultValue == PreparedStatement.EXECUTE_FAILED)
                 {
-                    throw throwExecuteFailed(info, expectedResults, result, i);
+                    throw throwExecuteFailed(batcher, expectedResults, result, i);
                 }
-                else if(info.useOptimisticLocking())
+                else if(batcher.useOptimisticLocking())
                 {
                     // on insert of objects with enabled opt. locking we allow unverified
                     // return values, otherwise we throw an exception
                     if(resultValue == Statement.SUCCESS_NO_INFO)
                     {
-                        if(info.getType() != BatchInfo.TYPE_OBJECT_INSERT)
+                        if(batcher.getType() != Batcher.TYPE_INSERT)
                         {
-                            throw throwJdbcNotSupported(info, expectedResults, result, i);
+                            throw throwJdbcNotSupported(batcher, expectedResults, result, i);
                         }
                     }
                     else
                     {
-                        throw throwOptimisticLock(info, expectedResults, result, i);
+                        throw throwOptimisticLock(batcher, expectedResults, result, i);
                     }
                 }
                 else if(!(resultValue == PreparedStatement.SUCCESS_NO_INFO
                         || resultValue == 0))
                 {
-                    throw throwUnexpectedValue(info, expectedResults, result, i);
+                    throw throwUnexpectedValue(batcher, expectedResults, result, i);
                 }
             }
         }
@@ -210,13 +200,13 @@
     /**
      * FOR INTERNAL USE ONLY! Validates m:n-INDIRECTIONTABLE-INSERT operation batch statement execution results.
      *
-     * @param info The {@link BatchInfo} batch metadata.
+     * @param batcher The {@link Batcher} batch metadata.
      * @param expectedResults The expected return value array.
      * @param result The real return value array.
      * @throws SQLException If the return values are illegal or signal batch entries execution failures.
      * @throws OptimisticLockException If an optimistic lock issue occur.
      */
-    protected void validateIndirectionTableInsert(BatchInfo info, int[] expectedResults, int[] result) throws SQLException, OptimisticLockException
+    protected void validateIndirectionTableInsert(Batcher batcher, int[] expectedResults, int[] result) throws SQLException, OptimisticLockException
     {
         for(int i = 0; i < result.length; i++)
         {
@@ -227,11 +217,11 @@
             {
                 if(resultValue == PreparedStatement.EXECUTE_FAILED)
                 {
-                    throw throwExecuteFailed(info, expectedResults, result, i);
+                    throw throwExecuteFailed(batcher, expectedResults, result, i);
                 }
                 else if(resultValue != PreparedStatement.SUCCESS_NO_INFO)
                 {
-                    throw throwUnexpectedValue(info, expectedResults, result, i);
+                    throw throwUnexpectedValue(batcher, expectedResults, result, i);
                 }
             }
         }
@@ -240,13 +230,13 @@
     /**
      * FOR INTERNAL USE ONLY! Validates m:n-INDIRECTIONTABLE-DELETE operation batch statement execution results.
      *
-     * @param info The {@link BatchInfo} batch metadata.
+     * @param batcher The {@link Batcher} batch metadata.
      * @param expectedResults The expected return value array.
      * @param result The real return value array.
      * @throws SQLException If the return values are illegal or signal batch entries execution failures.
      * @throws OptimisticLockException If an optimistic lock issue occur.
      */
-    protected void validateIndirectionTableDelete(BatchInfo info, int[] expectedResults, int[] result) throws SQLException, OptimisticLockException
+    protected void validateIndirectionTableDelete(Batcher batcher, int[] expectedResults, int[] result) throws SQLException, OptimisticLockException
     {
         for(int i = 0; i < result.length; i++)
         {
@@ -256,13 +246,13 @@
             {
                 if(resultValue == PreparedStatement.EXECUTE_FAILED)
                 {
-                    throw throwExecuteFailed(info, expectedResults, result, i);
+                    throw throwExecuteFailed(batcher, expectedResults, result, i);
                 }
                 else if(!(resultValue == PreparedStatement.SUCCESS_NO_INFO
                         || resultValue == PreparedStatement.CLOSE_ALL_RESULTS
                         || resultValue == 0))
                 {
-                    throw throwUnexpectedValue(info, expectedResults, result, i);
+                    throw throwUnexpectedValue(batcher, expectedResults, result, i);
                 }
             }
         }
@@ -271,30 +261,30 @@
     /**
      * FOR INTERNAL USE ONLY! Validates UNKOWN TYPES of batch statement execution results.
      *
-     * @param info The {@link BatchInfo} batch metadata.
+     * @param batcher The {@link Batcher} batch metadata.
      * @param expectedResults The expected return value array.
      * @param result The real return value array.
      * @throws SQLException If the return values are illegal or signal batch entries execution failures.
      * @throws OptimisticLockException If an optimistic lock issue occur.
      */
-    protected void validateUnkownType(BatchInfo info, int[] expectedResults, int[] result) throws SQLException, OptimisticLockException
+    protected void validateUnkownType(Batcher batcher, int[] expectedResults, int[] result) throws SQLException, OptimisticLockException
     {
         for(int i = 0; i < result.length; i++)
         {
             int resultValue = result[i];
             if(resultValue == Statement.EXECUTE_FAILED)
             {
-                throwExecuteFailed(info, expectedResults, result, i);
+                throwExecuteFailed(batcher, expectedResults, result, i);
             }
 // arminw: when OJB perform an unkown batch sql-query we don't know the return value 0,1,2....
 //            if(expectedResults[i] > resultValue)
 //            {
-//                throw throwUnexpectedValue(info, expectedResults, result, i);
+//                throw throwUnexpectedValue(batcher, expectedResults, result, i);
 //            }
         }
     }
 
-    protected SQLException throwExecuteFailed(BatchInfo info, int[] expectedResults, int[] result, int index)
+    protected SQLException throwExecuteFailed(Batcher batcher, int[] expectedResults, int[] result, int index)
     {
         String eol = SystemUtils.LINE_SEPARATOR;
         return new SQLException(
@@ -304,7 +294,7 @@
                         "', but found " + ReflectionHelper.reflectNameFor(Statement.class, result[index]));
     }
 
-    protected SQLException throwJdbcNotSupported(BatchInfo info, int[] expectedResults, int[] result, int index)
+    protected SQLException throwJdbcNotSupported(Batcher batcher, int[] expectedResults, int[] result, int index)
     {
         String eol = SystemUtils.LINE_SEPARATOR;
         return new SQLException("JDBC driver does support batch statements but does not"
@@ -316,10 +306,10 @@
                 + eol + " Please use a more sophisticated JDBC driver or a BatchManager implementation"
                 + eol + " which provide a specific property to exclude objects using optimistic locking"
                 + eol + " from being put to batch (OJB's default impl. class supports such a property)."
-                + eol + " Used BatchInfo instance: " + eol + info);
+                + eol + " Used Batcher instance: " + eol + batcher);
     }
 
-    protected SQLException throwUnexpectedValue(BatchInfo info, int[] expectedResults, int[] result, int index)
+    protected SQLException throwUnexpectedValue(Batcher batcher, int[] expectedResults, int[] result, int index)
     {
         return new SQLException("Execute batch returned an unexpected statement return" +
                 " value (row count result)." +
@@ -328,12 +318,12 @@
                 ReflectionHelper.reflectNameFor(Statement.class, result[index]));
     }
 
-    protected OptimisticLockException throwOptimisticLock(BatchInfo info, int[] expectedResults, int[] result, int index)
+    protected OptimisticLockException throwOptimisticLock(Batcher batcher, int[] expectedResults, int[] result, int index)
     {
         String eol = SystemUtils.LINE_SEPARATOR;
         return new OptimisticLockException("Detect optimistic locking conflict while statement" +
                 " execution for batch command number '" + (index + 1) + "' of '" + result.length + "' commands" +
                 ". Expected statement return value (row count) was '" + expectedResults[index] +
-                "', but found '" + result[index] + "'." + eol + " Used BatchInfo instance: " + eol + info);
+                "', but found '" + result[index] + "'." + eol + " Used Batcher instance: " + eol + batcher);
     }
 }

Modified: db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/sql/SelectStatement.java
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/sql/SelectStatement.java?view=diff&rev=495677&r1=495676&r2=495677
==============================================================================
--- db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/sql/SelectStatement.java (original)
+++ db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/sql/SelectStatement.java Fri Jan 12 10:19:39 2007
@@ -19,9 +19,8 @@
 import org.apache.ojb.broker.query.Query;
 
 /**
- * This class
+ * Encapsulates methodes of select statements.
  *
- * @author <a href="mailto:arminw@apache.org">Armin Waibel</a>
  * @version $Id$
  */
 public interface SelectStatement extends SqlStatement
@@ -51,4 +50,9 @@
      * case this method returns <em>true</em>.
      */
     public boolean isUseOjbClassColumn();
+
+    /**
+     * Returns <em>true</em> if the statement is a stored procedure.
+     */
+    public boolean isStoredProcedure();
 }

Modified: db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/sql/SqlProcedureFKStatement.java
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/sql/SqlProcedureFKStatement.java?view=diff&rev=495677&r1=495676&r2=495677
==============================================================================
--- db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/sql/SqlProcedureFKStatement.java (original)
+++ db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/sql/SqlProcedureFKStatement.java Fri Jan 12 10:19:39 2007
@@ -33,9 +33,6 @@
  * Model a call to a stored procedure based on ProcedureDescriptors
  *
  * @see org.apache.ojb.broker.metadata.ProcedureDescriptor
- * @author <a href="mailto:rburt3@mchsi.com">Randall Burt</a>
- * @author <a href="mailto:rgallagh@bellsouth.net">Ron Gallagher</a>
- * @author <a href="mailto:vgritsenko@apache.org">Vadim Gritsenko</a>
  * @version $Id$
  */
 public class SqlProcedureFKStatement implements SelectStatement
@@ -140,5 +137,10 @@
     public boolean isUseOjbClassColumn()
     {
         return false;
+    }
+
+    public boolean isStoredProcedure()
+    {
+        return true;
     }
 }

Modified: db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/sql/SqlProcedureStatement.java
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/sql/SqlProcedureStatement.java?view=diff&rev=495677&r1=495676&r2=495677
==============================================================================
--- db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/sql/SqlProcedureStatement.java (original)
+++ db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/sql/SqlProcedureStatement.java Fri Jan 12 10:19:39 2007
@@ -25,8 +25,6 @@
  * Model a call to a stored procedure based on ProcedureDescriptors
  *
  * @see org.apache.ojb.broker.metadata.ProcedureDescriptor
- * @author <a href="mailto:rburt3@mchsi.com">Randall Burt</a>
- * @author <a href="mailto:rgallagh@bellsouth.net">Ron Gallagher</a>
  * @version $Id$
  */
 
@@ -107,5 +105,10 @@
     public boolean isUseOjbClassColumn()
     {
         return false;
+    }
+
+    public boolean isStoredProcedure()
+    {
+        return true;
     }
 }

Modified: db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/sql/SqlSelectStatement.java
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/sql/SqlSelectStatement.java?view=diff&rev=495677&r1=495676&r2=495677
==============================================================================
--- db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/sql/SqlSelectStatement.java (original)
+++ db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/sql/SqlSelectStatement.java Fri Jan 12 10:19:39 2007
@@ -340,30 +340,9 @@
             
             orderByFields = query.getOrderBy();
             columnList = ensureColumns(orderByFields, columnList, stmt);
-/*
-arminw:
-TODO: this feature doesn't work, so remove this in future
-*/
-            /**
-             * treeder: going to map superclass tables here, 
-             * not sure about the columns, just using all columns for now
-             */
-            ClassDescriptor cld = getBaseClassDescriptor();
-            ClassDescriptor cldSuper = null;
-            if (cld.getSuperClass() != null)
-            {
-                // then we have a super class so join tables
-                cldSuper = cld.getRepository().getDescriptorFor(cld.getSuperClass());
-                appendSuperClassColumns(cldSuper, stmt);
-            }
 
             stmt.append(" FROM ");
             appendTableWithJoins(getRootAlias(), where, stmt);
-
-            if (cld.getSuperClass() != null)
-            {
-                appendSuperClassJoin(cld, cldSuper, stmt, where);
-            }
             
             appendWhereClause(where, whereCrit, stmt);
             appendGroupByClause(groupByFields, stmt);
@@ -377,52 +356,16 @@
            ((ReportQueryByCriteria) query).setAttributeFieldDescriptors(getAttributesToFieldDescriptors());
         }
 
-        return stmt.toString();
-    }
-
-/*
-arminw:
-TODO: this feature doesn't work, so remove this in future
-*/
-    private void appendSuperClassJoin(ClassDescriptor cld, ClassDescriptor cldSuper, StringBuffer stmt, StringBuffer where)
-    {
-        stmt.append(",");
-        appendTable(cldSuper, stmt);
-         
-        if (where != null)
+        if(query.isSelectForUpdate())
         {
-            if (where.length() > 0)
-            {
-                where.append(" AND ");                
-            }
-            
-            // get reference field in super class
-            // TODO: do not use the superclassfield anymore, just assume that the id is the same in both tables - @see PBroker.storeToDb
-            int superFieldRef = cld.getSuperClassFieldRef();
-            FieldDescriptor refField = cld.getFieldDescriptorByIndex(superFieldRef);
-            
-            appendTable(cldSuper, where);
-            where.append(".");
-            appendField(cldSuper.getAutoIncrementFields()[0], where);
-            where.append(" = ");
-            appendTable(cld, where);
-            where.append(".");
-            appendField(refField, where);
+            stmt.append(getPlatform().getSelectForUpdateClause());
         }
-    }
-
-    private void appendSuperClassColumns(ClassDescriptor cldSuper, StringBuffer buf)
-    {
-        FieldDescriptor[] fields = cldSuper.getFieldDescriptions();
-        for (int i = 0; i < fields.length; i++)
+        if(query.getQueryAffix() != null)
         {
-            FieldDescriptor field = fields[i];
-            if (i > 0)
-            {
-                buf.append(",");
-            }   
-            appendColumn(cldSuper.getFullTableName(), field.getColumnName(), buf);
+            stmt.append(" ").append(query.getQueryAffix());
         }
+
+        return stmt.toString();
     }
 
     /**
@@ -475,5 +418,10 @@
     protected void setUseOjbClassColumn(boolean useOjbClassColumn)
     {
         this.useOjbClassColumn = useOjbClassColumn;
+    }
+
+    public boolean isStoredProcedure()
+    {
+        return false;
     }
 }

Modified: db/ojb/trunk/src/java/org/apache/ojb/broker/cache/AbstractObjectCache.java
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/java/org/apache/ojb/broker/cache/AbstractObjectCache.java?view=diff&rev=495677&r1=495676&r2=495677
==============================================================================
--- db/ojb/trunk/src/java/org/apache/ojb/broker/cache/AbstractObjectCache.java (original)
+++ db/ojb/trunk/src/java/org/apache/ojb/broker/cache/AbstractObjectCache.java Fri Jan 12 10:19:39 2007
@@ -1,11 +1,11 @@
 package org.apache.ojb.broker.cache;
 
 import java.util.Iterator;
-import java.util.Map;
+import java.util.List;
+import java.util.ArrayList;
 
-import org.apache.commons.collections.map.ReferenceIdentityMap;
-import org.apache.commons.collections.map.ReferenceMap;
 import org.apache.ojb.broker.Identity;
+import org.apache.ojb.broker.util.WeakIdentityList;
 
 /* Copyright 2002-2004 The Apache Software Foundation
  *
@@ -23,33 +23,41 @@
  */
 
 /**
- * Base class to provide the extended functionality of {@link ObjectCacheExt}
- * to all {@link ObjectCache} implementations extending this class.
+ * Base class to provide the common functionality of {@link ObjectCache}.
  *
  * @version $Id$
  */
-abstract public class AbstractObjectCache implements ObjectCacheExt
+abstract public class AbstractObjectCache implements ObjectCache
 {
-    private final Object dummy = new Object();
-    private Map listeners;
+    private final Object sync = new Object();
+    private List listeners;
 
-    private Map createListenerMap()
+    /**
+     * Implement this method to cache objects.
+     *
+     * @param oid The {@link org.apache.ojb.broker.Identity} of the object.
+     * @param obj The object to cache.
+     */
+    abstract public void doCache(Identity oid, Object obj);
+
+    /**
+     * Internally called for each object cached by this cache implementation.
+     *
+     * @param oid The {@link org.apache.ojb.broker.Identity} of the cached object.
+     */
+    void performInvalidationAction(Identity oid)
     {
-        return new ReferenceIdentityMap(ReferenceMap.WEAK, ReferenceMap.HARD, true);
-    }
-
-    protected void performInvalidationAction(Identity oid)
-    {
-        if(listeners == null) return;
-
-        synchronized(dummy)
+        if(listeners != null)
         {
-            Iterator it = listeners.keySet().iterator();
-            InvalidationListener target;
-            while(it.hasNext())
+            synchronized(sync)
             {
-                target = (InvalidationListener) it.next();
-                if(target != null) target.invalidateObject(oid);
+                Iterator it = listeners.iterator();
+                InvalidationListener target;
+                while(it.hasNext())
+                {
+                    target = (InvalidationListener) it.next();
+                    if(target != null) target.invalidateObject(oid);
+                }
             }
         }
     }
@@ -60,15 +68,13 @@
         {
             throw new NullPointerException("Added InvalidationListener can't be 'null'");
         }
-        if(listeners == null)
+        synchronized(sync)
         {
-            listeners = createListenerMap();
-        }
-        // dummy value
-        Integer id = new Integer(System.identityHashCode(listener));
-        synchronized(dummy)
-        {
-            if(!listeners.containsKey(listener)) listeners.put(listener, id);
+            if(listeners == null)
+            {
+                listeners = new WeakIdentityList();
+            }
+            if(!listeners.contains(listener)) listeners.add(listener);
         }
     }
 
@@ -79,7 +85,7 @@
         {
             throw new NullPointerException("InvalidationListener can't be 'null'");
         }
-        synchronized(dummy)
+        synchronized(sync)
         {
             listeners.remove(listener);
             if(listeners.size() == 0)
@@ -89,25 +95,50 @@
         }
     }
 
+    public List getAllInvalidationListener()
+    {
+        List result = new ArrayList();
+        synchronized(sync)
+        {
+            Iterator it = listeners.iterator();
+            while(it.hasNext())
+            {
+                result.add(it.next());
+            }
+        }
+        return result;
+    }
+
     public void invalidateObject(Identity oid)
     {
         /*
-        invalidate object by direct call to the underlying ObjectCacheExt
+        invalidate object by direct call to the underlying cache
         instance, never use the #remove(oid) method to invalidate to avoid problems
         with caches which add each other as listener.
         */
         remove(oid);
     }
 
+    /**
+     * Not allowed to override this method to guaratee call of
+     * invalidation action. Use methode {@link #doCache(org.apache.ojb.broker.Identity, Object)}
+     * to implement cache method.
+     */
+    final public void cache(final Identity oid, final Object obj)
+    {
+        doCache(oid, obj);
+        performInvalidationAction(oid);
+    }
+
     public String toString()
     {
         StringBuffer msg = new StringBuffer();
-        synchronized(dummy)
+        synchronized(sync)
         {
             if(listeners != null && listeners.size() > 0)
             {
                 msg.append("Registered listener: ");
-                Iterator it = listeners.keySet().iterator();
+                Iterator it = listeners.iterator();
                 boolean first = true;
                 while(it.hasNext())
                 {



---------------------------------------------------------------------
To unsubscribe, e-mail: ojb-dev-unsubscribe@db.apache.org
For additional commands, e-mail: ojb-dev-help@db.apache.org


Mime
View raw message