svn commit: r495668 [1/2] - in /db/ojb/trunk: lib/ src/java/org/apache/ojb/broker/accesslayer/batch/ src/java/org/apache/ojb/broker/cache/ src/java/org/apache/ojb/broker/core/ src/java/org/apache/ojb/broker/metadata/ src/java/org/apache/ojb/broker/util...

[email protected]
Newsgroups gmane.comp.jakarta.ojb.devel
Message-ID <[email protected]>
Author: arminw
Date: Fri Jan 12 10:06:09 2007
New Revision: 495668

URL: http://svn.apache.org/viewvc?view=rev&rev=495668
Log:
- merge trunk with OJB 1.0.x branch
- continue work on caching
- continue work on batch handling
- introduce possibility to persist generic objects at runtime (used to populate the m:n indirection table)

Added:
    db/ojb/trunk/lib/DdlUtils-1.0-RC1.jar   (with props)
    db/ojb/trunk/lib/commons-betwixt-0.8.jar   (with props)
    db/ojb/trunk/lib/commons-digester-1.8.jar   (with props)
    db/ojb/trunk/lib/junit-3.8.1.jar   (with props)
    db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/batch/Batcher.java
    db/ojb/trunk/src/java/org/apache/ojb/broker/cache/CachingPipe.java   (contents, props changed)
      - copied, changed from r451479, db/ojb/trunk/src/java/org/apache/ojb/broker/cache/CachingStrategy.java
    db/ojb/trunk/src/java/org/apache/ojb/broker/cache/CachingPipeAbstractImpl.java   (contents, props changed)
      - copied, changed from r451479, db/ojb/trunk/src/java/org/apache/ojb/broker/cache/CachingStrategyAbstractImpl.java
    db/ojb/trunk/src/java/org/apache/ojb/broker/cache/CachingPipeFlatCopyImpl.java   (contents, props changed)
      - copied, changed from r451479, db/ojb/trunk/src/java/org/apache/ojb/broker/cache/CachingStrategyTwoLevelImpl.java
    db/ojb/trunk/src/java/org/apache/ojb/broker/cache/CachingPipeNoopImpl.java   (contents, props changed)
      - copied, changed from r451479, db/ojb/trunk/src/java/org/apache/ojb/broker/cache/CachingStrategyDefaultImpl.java
    db/ojb/trunk/src/java/org/apache/ojb/broker/cache/CachingPolicy.java
    db/ojb/trunk/src/java/org/apache/ojb/broker/cache/Connector.java
    db/ojb/trunk/src/java/org/apache/ojb/broker/cache/InvalidationRegistry.java
    db/ojb/trunk/src/java/org/apache/ojb/broker/core/CollectionTypes.java
    db/ojb/trunk/src/java/org/apache/ojb/broker/metadata/GenericDescriptor.java
    db/ojb/trunk/src/java/org/apache/ojb/broker/metadata/GenericObject.java
    db/ojb/trunk/src/java/org/apache/ojb/broker/metadata/IndirectionTableDescriptor.java
    db/ojb/trunk/src/java/org/apache/ojb/broker/util/ConvertHelper.java
    db/ojb/trunk/src/java/org/apache/ojb/broker/util/IdentityHashSet.java
    db/ojb/trunk/src/java/org/apache/ojb/broker/util/WeakIdentityList.java
    db/ojb/trunk/src/java/org/apache/ojb/broker/util/collections/RemovalAwareVector.java
    db/ojb/trunk/src/java/org/apache/ojb/broker/util/sequence/PerFieldManager.java
    db/ojb/trunk/src/java/org/apache/ojb/broker/util/sequence/SequenceManagerIdentityImpl.java
    db/ojb/trunk/src/test/org/apache/ojb/broker/BatchStrategyTest.java
    db/ojb/trunk/src/test/org/apache/ojb/broker/OneToOneWithoutFKTest.java

Added: db/ojb/trunk/lib/DdlUtils-1.0-RC1.jar
URL: http://svn.apache.org/viewvc/db/ojb/trunk/lib/DdlUtils-1.0-RC1.jar?view=auto&rev=495668
==============================================================================
Binary file - no diff available.

Propchange: db/ojb/trunk/lib/DdlUtils-1.0-RC1.jar
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: db/ojb/trunk/lib/commons-betwixt-0.8.jar
URL: http://svn.apache.org/viewvc/db/ojb/trunk/lib/commons-betwixt-0.8.jar?view=auto&rev=495668
==============================================================================
Binary file - no diff available.

Propchange: db/ojb/trunk/lib/commons-betwixt-0.8.jar
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: db/ojb/trunk/lib/commons-digester-1.8.jar
URL: http://svn.apache.org/viewvc/db/ojb/trunk/lib/commons-digester-1.8.jar?view=auto&rev=495668
==============================================================================
Binary file - no diff available.

Propchange: db/ojb/trunk/lib/commons-digester-1.8.jar
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: db/ojb/trunk/lib/junit-3.8.1.jar
URL: http://svn.apache.org/viewvc/db/ojb/trunk/lib/junit-3.8.1.jar?view=auto&rev=495668
==============================================================================
Binary file - no diff available.

Propchange: db/ojb/trunk/lib/junit-3.8.1.jar
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/batch/Batcher.java
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/batch/Batcher.java?view=auto&rev=495668
==============================================================================
--- db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/batch/Batcher.java (added)
+++ db/ojb/trunk/src/java/org/apache/ojb/broker/accesslayer/batch/Batcher.java Fri Jan 12 10:06:09 2007
@@ -0,0 +1,432 @@
+package org.apache.ojb.broker.accesslayer.batch;
+
+/* Copyright 2002-2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.sql.CallableStatement;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Collections;
+
+import org.apache.commons.lang.builder.ToStringBuilder;
+import org.apache.commons.lang.builder.ToStringStyle;
+import org.apache.ojb.broker.accesslayer.JdbcAccess;
+import org.apache.ojb.broker.accesslayer.StatementManager;
+import org.apache.ojb.broker.core.ValueContainer;
+import org.apache.ojb.broker.metadata.ClassDescriptor;
+import org.apache.ojb.broker.metadata.ProcedureDescriptor;
+import org.apache.ojb.broker.metadata.GenericDescriptor;
+import org.apache.ojb.broker.metadata.IndirectionTableDescriptor;
+import org.apache.ojb.broker.query.Query;
+import org.apache.ojb.broker.util.ReflectionHelper;
+import org.apache.ojb.broker.PersistenceBrokerInternal;
+
+/**
+ * This class is responsible to encapsulate batch metadata information, batch values
+ * and to execute the batch.
+ *
+ * @version $Id: $
+ */
+abstract public class Batcher
+{
+    public static final int TYPE_UNKOWN = 0;
+    public static final int TYPE_INSERT = 1;
+    public static final int TYPE_UPDATE = 2;
+    public static final int TYPE_DELETE = 3;
+    public static final int TYPE_INDIRECTION_TABLE_INSERT = 4;
+    public static final int TYPE_INDIRECTION_TABLE_DELETE = 5;
+
+    private static final int[] EMPTY_INT_ARRAY = new int[]{};
+
+    List values;
+    int[] expectedResults = EMPTY_INT_ARRAY;
+    String sql;
+    boolean optimisticLocking;
+
+    Batcher(String sql)
+    {
+        this.sql = sql;
+        this.optimisticLocking = false;
+    }
+
+    abstract public int getType();
+
+    abstract public String getTableName();
+
+    abstract public ClassDescriptor getClassDescriptor();
+
+    abstract public ProcedureDescriptor getProcedureDescriptor();
+
+    public boolean isInsert()
+    {
+        return getType() == TYPE_INSERT || getType() == TYPE_INDIRECTION_TABLE_INSERT;
+    }
+
+    public boolean isUpdate()
+    {
+        return getType() == TYPE_UPDATE;
+    }
+
+    public boolean isDelete()
+    {
+        return getType() == TYPE_DELETE || getType() == TYPE_INDIRECTION_TABLE_DELETE;
+    }
+
+    public boolean isIndirectionTable()
+    {
+        return false;
+    }
+
+    public boolean useOptimisticLocking()
+    {
+        return optimisticLocking;
+    }
+
+    public void setOptimisticLocking(boolean optimisticLocking)
+    {
+        this.optimisticLocking = optimisticLocking;
+    }
+
+    public String getSql()
+    {
+        return sql;
+    }
+
+    /**
+     * Return the expected {@link java.sql.Statement} return values (when batch was executed).
+     *
+     * @return The expected result of the batch execution.
+     */
+    public int[] getExpectedResults()
+    {
+        return expectedResults;
+    }
+
+    /**
+     * The number of added batch entries (number of added rows).
+     *
+     * @return The number of enqueued batch objects.
+     */
+    public int batchSize()
+    {
+        return values != null ? values.size() : 0;
+    }
+
+    public List getValues()
+    {
+        return values != null ? values : Collections.EMPTY_LIST;
+    }
+
+    public void cleanup()
+    {
+        if(values != null)
+        {
+            if(values.size() < 1000)
+            {
+                values.clear();
+            }
+            else
+            {
+                values = null;
+            }
+        }
+        expectedResults = EMPTY_INT_ARRAY;
+    }
+
+    public void add(ValueContainer[] row, int expectedResult)
+    {
+        if(values == null)
+        {
+            values = new ArrayList();
+        }
+        int[] newResults = new int[expectedResults.length + 1];
+        System.arraycopy(expectedResults, 0, newResults, 0, expectedResults.length);
+        newResults[newResults.length - 1] = expectedResult;
+        expectedResults = newResults;
+        values.add(row);
+    }
+
+    /**
+     * Perform the batch statement - after calling this method
+     * it's necassary to cleanup this instance using {@link #cleanup()}.
+     *
+     * @return The result og the batch execution.
+     * @throws java.sql.SQLException
+     * @throws org.apache.ojb.broker.OptimisticLockException
+     */
+    public int[] executeBatch(StatementManager sm, JdbcAccess ja) throws SQLException
+    {
+        if(batchSize() == 0)
+        {
+            return getExpectedResults();
+        }
+        else
+        {
+            int[] result = null;
+            PreparedStatement stmt = null;
+            ValueContainer[] values;
+            try
+            {
+                stmt = sm.getPreparedStatement(getSql(), Query.NOT_SCROLLABLE, StatementManager.FETCH_SIZE_NOT_APPLICABLE);
+                if(batchSize() > 1)
+                {
+                    for(Iterator iterator = getValues().iterator(); iterator.hasNext();)
+                    {
+                        values = (ValueContainer[]) iterator.next();
+                        if(getProcedureDescriptor() == null)
+                        {
+                            ja.bindValues(stmt, values, 1);
+                        }
+                        else
+                        {
+                            ja.bindValues((CallableStatement) stmt, values, 1, getProcedureDescriptor());
+                        }
+                        stmt.addBatch();
+                    }
+                    result = stmt.executeBatch();
+                }
+                else
+                {
+                    values = (ValueContainer[]) getValues().get(0);
+                    if(getProcedureDescriptor() == null)
+                    {
+                        ja.bindValues(stmt, values, 1);
+                    }
+                    else
+                    {
+                        ja.bindValues((CallableStatement) stmt, values, 1, getProcedureDescriptor());
+                    }
+                    result = new int[]{stmt.executeUpdate()};
+                }
+            }
+            finally
+            {
+                sm.closeResources(stmt, null);
+            }
+            return result;
+        }
+    }
+
+    public boolean equals(Object obj)
+    {
+        boolean result = false;
+        if(this == obj)
+        {
+            result = true;
+        }
+        else
+        {
+            if(obj instanceof Batcher)
+            {
+                Batcher other = (Batcher) obj;
+                result = getType() == other.getType() && getSql().equals(other.getSql());
+            }
+        }
+        return result;
+    }
+
+    public String toString()
+    {
+        ToStringBuilder toStr = new ToStringBuilder(this, ToStringStyle.DEFAULT_STYLE);
+        toStr.append("table", getTableName());
+        toStr.append("type", ReflectionHelper.reflectNameFor(Batcher.class, getType()));
+        toStr.append("batch queue size", values != null ? values.size() : 0);
+        if(getClassDescriptor() != null) toStr.append("target class", getClassDescriptor().getClassOfObject());
+        toStr.append("sql", getSql());
+        return toStr.toString();
+    }
+
+    //===================================================================
+    // inner abstract class
+    //===================================================================
+    /**
+     * The base class for {@link org.apache.ojb.broker.metadata.ClassDescriptor} based
+     * objects.
+     */
+    static abstract class ClassBased extends Batcher
+    {
+        private ClassDescriptor cld;
+        private ProcedureDescriptor pd;
+
+        public ClassBased(ClassDescriptor cld, ProcedureDescriptor descriptor, String sql)
+        {
+            super(sql);
+            if(cld == null)
+            {
+                throw new NullPointerException("ClassDescriptor is 'null'");
+            }
+            this.cld = cld;
+            this.pd = descriptor;
+        }
+
+        public String getTableName()
+        {
+            return cld.getFullTableName();
+        }
+
+        public ClassDescriptor getClassDescriptor()
+        {
+            return cld;
+        }
+
+        public ProcedureDescriptor getProcedureDescriptor()
+        {
+            return pd;
+        }
+    }
+
+    //===================================================================
+    // inner abstract class
+    //===================================================================
+    /**
+     * The base class for generic objects.
+     */
+    static abstract class Generic extends Batcher
+    {
+        GenericDescriptor descriptor;
+
+        protected Generic(GenericDescriptor descriptor)
+        {
+            super(null);
+            this.descriptor = descriptor;
+        }
+
+        public String getTableName()
+        {
+            return descriptor.getTableName();
+        }
+
+        public ClassDescriptor getClassDescriptor()
+        {
+            return null;
+        }
+
+        public ProcedureDescriptor getProcedureDescriptor()
+        {
+            return null;
+        }
+
+        public boolean isIndirectionTable()
+        {
+            return descriptor instanceof IndirectionTableDescriptor;
+        }
+    }
+
+
+    //===================================================================
+    // Implementation class
+    //===================================================================
+    public static class Insert extends ClassBased
+    {
+        public Insert(ClassDescriptor cld, ProcedureDescriptor descriptor, String sql)
+        {
+            super(cld, descriptor, sql);
+        }
+
+
+        public int getType()
+        {
+            return TYPE_INSERT;
+        }
+    }
+
+    //===================================================================
+    // Implementation class
+    //===================================================================
+    public static class Update extends ClassBased
+    {
+        public Update(ClassDescriptor cld, ProcedureDescriptor descriptor, String sql)
+        {
+            super(cld, descriptor, sql);
+            setOptimisticLocking(cld.isLocking());
+        }
+
+        public int getType()
+        {
+            return TYPE_UPDATE;
+        }
+    }
+
+    //===================================================================
+    // Implementation class
+    //===================================================================
+    public static class Delete extends ClassBased
+    {
+        public Delete(ClassDescriptor cld, ProcedureDescriptor descriptor, String sql)
+        {
+            super(cld, descriptor, sql);
+            setOptimisticLocking(cld.isLocking());
+        }
+
+        public int getType()
+        {
+            return TYPE_DELETE;
+        }
+    }
+
+    //===================================================================
+    // Implementation class
+    //===================================================================
+    public static class GenericInsert extends Generic
+    {
+        public GenericInsert(GenericDescriptor descriptor, PersistenceBrokerInternal broker)
+        {
+            super(descriptor);
+            this.sql = descriptor.insertSql(broker);
+        }
+
+        public int getType()
+        {
+            return isIndirectionTable() ? TYPE_INDIRECTION_TABLE_INSERT : TYPE_INSERT;
+        }
+    }
+
+    //===================================================================
+    // Implementation class
+    //===================================================================
+    public static class GenericUpdate extends Generic
+    {
+        public GenericUpdate(GenericDescriptor descriptor, PersistenceBrokerInternal broker)
+        {
+            super(descriptor);
+            this.sql = descriptor.updateSql(broker);
+        }
+
+        public int getType()
+        {
+            return TYPE_UPDATE;
+        }
+    }
+
+    //===================================================================
+    // Implementation class
+    //===================================================================
+    public static class GenericDelete extends Generic
+    {
+        public GenericDelete(GenericDescriptor descriptor, PersistenceBrokerInternal broker)
+        {
+            super(descriptor);
+            this.sql = descriptor.deleteSql(broker);
+        }
+
+        public int getType()
+        {
+            return isIndirectionTable() ? TYPE_INDIRECTION_TABLE_DELETE : TYPE_DELETE;
+        }
+    }
+}

Copied: db/ojb/trunk/src/java/org/apache/ojb/broker/cache/CachingPipe.java (from r451479, db/ojb/trunk/src/java/org/apache/ojb/broker/cache/CachingStrategy.java)
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/java/org/apache/ojb/broker/cache/CachingPipe.java?view=diff&rev=495668&p1=db/ojb/trunk/src/java/org/apache/ojb/broker/cache/CachingStrategy.java&r1=451479&p2=db/ojb/trunk/src/java/org/apache/ojb/broker/cache/CachingPipe.java&r2=495668
==============================================================================
--- db/ojb/trunk/src/java/org/apache/ojb/broker/cache/CachingStrategy.java (original)
+++ db/ojb/trunk/src/java/org/apache/ojb/broker/cache/CachingPipe.java Fri Jan 12 10:06:09 2007
@@ -1,7 +1,7 @@
 package org.apache.ojb.broker.cache;
 
 import org.apache.ojb.broker.Identity;
-import org.apache.ojb.broker.metadata.ObjectCacheDescriptor;
+import org.apache.ojb.broker.PersistenceBrokerInternal;
 
 /* Copyright 2002-2004 The Apache Software Foundation
  *
@@ -19,79 +19,40 @@
  */
 
 /**
- * The <em>caching strategy</em> is the connector between the {@link SessionCache} and
- * the application/second level cache represented by {@link ObjectCache} and can be used
+ * The <em>caching pipe</em> is a pass-through filter and connector between the {@link SessionCache} and
+ * the application cache layer represented by the {@link ObjectCache} interface and can be used
  * to modify, copy or pre-filter cacheable objects.
+ * <br/>
+ * NOTE: All implementations have to be <em>thread-safe</em>!
  *
  * @version $Id$
  */
-public interface CachingStrategy
+public interface CachingPipe
 {
     /**
-     * Returns the underlying application/second-level cache.
+     * Called immediately after the object is read from the application cache.
+     * E.g. allows to materialize/populate the referenced objects of "flat" cached objects
+     * or to modify objects read from the application cache.
      *
-     * @return The extended {@link ObjectCache} instance.
-     */
-    public ObjectCacheExt getObjectCache();
-
-    /**
-     * Cache the object.
-     *
-     * @param oid        The {@link org.apache.ojb.broker.Identity} of the object.
-     * @param entry        The object entry to cache.
-     * @param cacheIfNew When <em>true</em> the object was only cached when
-     *                   not already in the cache.
-     */
-    public void cache(Identity oid, ObjectEntry entry, boolean cacheIfNew);
-
-    /**
-     * Lookup an cached object.
-     *
-     * @param oid The {@link org.apache.ojb.broker.Identity} of the wanted object.
-     * @return The matching object or <em>null</em> if no object was found
-     *         for given {@link org.apache.ojb.broker.Identity}.
-     */
-    public ObjectEntry lookup(Identity oid);
+     * @param broker The current {@link org.apache.ojb.broker.PersistenceBrokerInternal} instance.
+     * @param oid The {@link org.apache.ojb.broker.Identity} of the object.
+     * @param obj The cached object read from the application cache.
+     * @return The full prepared object ready for use by OJB.
+     * @see #write(org.apache.ojb.broker.PersistenceBrokerInternal, org.apache.ojb.broker.Identity, Object)
+     */
+    public Object read(final PersistenceBrokerInternal broker, final Identity oid,
+                       final Object obj);
 
     /**
-     * Removes an Object from the cache.
+     * Called before an object is written to the application cache.
+     * E.g. allows to make "flat" object copies (without referenced objects) or to cache
+     * objects field by field.
      *
-     * @param oid Identity of the object to be removed.
-     */
-    public void remove(Identity oid);
-
-    /**
-     * Evict all cached objects from the underlying {@link ObjectCache} instance.
+     * @param oid       The {@link org.apache.ojb.broker.Identity} of the object.
+     * @param obj       The target object to cache in application cache.
+     * @return The modified object or a copy of the object to write to application cache.
+     * @see #read(org.apache.ojb.broker.PersistenceBrokerInternal, org.apache.ojb.broker.Identity, Object)
      */
-    public void clear();
-
-    /**
-     * Return the associated {@link org.apache.ojb.broker.metadata.ObjectCacheDescriptor};
-     */
-    public ObjectCacheDescriptor getObjectCacheDescriptor();
-
-//    /**
-//     * Called after the object is read from the application cache (second level cache).
-//     * E.g. allows to materialize/populate the referenced objects of "flat" cached objects
-//     * or to modify objects read from the second level cache.
-//     *
-//     * @param oid The {@link org.apache.ojb.broker.Identity} of the object.
-//     * @param entry The object entry read from the application cache.
-//     * @return The modified object or a copy of the object.
-//     * @see #write(org.apache.ojb.broker.Identity, ObjectEntry, ObjectEntry)
-//     */
-//    public ObjectEntry read(Identity oid, ObjectEntry entry);
-//
-//    /**
-//     * Called before an object is written to the application cache (second level cache).
-//     * E.g. allows to make "flat" object copies (without referenced objects) or to cache
-//     * objects field by field.
-//     *
-//     * @param oid       The {@link org.apache.ojb.broker.Identity} of the object.
-//     * @param entry       The target object to cache in application cache.
-//     * @param oldEntry The old cache object or <em>null</em>.
-//     * @return The modified object or a copy of the object to write to application cache.
-//     * @see #read(org.apache.ojb.broker.Identity, ObjectEntry)
-//     */
-//    public ObjectEntry write(Identity oid, ObjectEntry entry, ObjectEntry oldEntry);
+    public Object write(final PersistenceBrokerInternal broker, final Identity oid,
+                        final Object obj);
 }

Propchange: db/ojb/trunk/src/java/org/apache/ojb/broker/cache/CachingPipe.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: db/ojb/trunk/src/java/org/apache/ojb/broker/cache/CachingPipe.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Copied: db/ojb/trunk/src/java/org/apache/ojb/broker/cache/CachingPipeAbstractImpl.java (from r451479, db/ojb/trunk/src/java/org/apache/ojb/broker/cache/CachingStrategyAbstractImpl.java)
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/java/org/apache/ojb/broker/cache/CachingPipeAbstractImpl.java?view=diff&rev=495668&p1=db/ojb/trunk/src/java/org/apache/ojb/broker/cache/CachingStrategyAbstractImpl.java&r1=451479&p2=db/ojb/trunk/src/java/org/apache/ojb/broker/cache/CachingPipeAbstractImpl.java&r2=495668
==============================================================================
--- db/ojb/trunk/src/java/org/apache/ojb/broker/cache/CachingStrategyAbstractImpl.java (original)
+++ db/ojb/trunk/src/java/org/apache/ojb/broker/cache/CachingPipeAbstractImpl.java Fri Jan 12 10:06:09 2007
@@ -1,7 +1,5 @@
 package org.apache.ojb.broker.cache;
 
-import org.apache.ojb.broker.Identity;
-import org.apache.ojb.broker.PersistenceBrokerInternal;
 import org.apache.ojb.broker.metadata.ObjectCacheDescriptor;
 import org.apache.commons.lang.builder.ToStringBuilder;
 
@@ -21,21 +19,16 @@
  */
 
 /**
- * Abstract base class for {@link CachingStrategy} implementations.
+ * Abstract base class for {@link CachingPipe} implementations.
  * 
- * @author <a href="mailto:[email protected]">Armin Waibel</a>
  * @version $Id$
  */
-abstract class CachingStrategyAbstractImpl implements CachingStrategy
+abstract class CachingPipeAbstractImpl implements CachingPipe
 {
-    private PersistenceBrokerInternal broker;
-    private ObjectCacheExt applicationCache;
     private ObjectCacheDescriptor objectCacheDescriptor;
 
-    public CachingStrategyAbstractImpl(PersistenceBrokerInternal broker, ObjectCacheExt applicationCache, ObjectCacheDescriptor ocd)
+    public CachingPipeAbstractImpl(ObjectCacheDescriptor ocd)
     {
-        this.broker = broker;
-        this.applicationCache = applicationCache;
         this.objectCacheDescriptor = ocd;
     }
 
@@ -44,30 +37,8 @@
         return objectCacheDescriptor;
     }
 
-    public void remove(Identity oid)
-    {
-        getObjectCache().remove(oid);
-    }
-
-    public void clear()
-    {
-        getObjectCache().clear();
-    }
-
-    public ObjectCacheExt getObjectCache()
-    {
-        return applicationCache;
-    }
-
-    public PersistenceBrokerInternal getBroker()
-    {
-        return broker;
-    }
-
     public String toString()
     {
-        return new ToStringBuilder(this)
-                .append("applicationCache", applicationCache)
-                .toString();
+        return new ToStringBuilder(this).toString();
     }
 }

Propchange: db/ojb/trunk/src/java/org/apache/ojb/broker/cache/CachingPipeAbstractImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: db/ojb/trunk/src/java/org/apache/ojb/broker/cache/CachingPipeAbstractImpl.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Copied: db/ojb/trunk/src/java/org/apache/ojb/broker/cache/CachingPipeFlatCopyImpl.java (from r451479, db/ojb/trunk/src/java/org/apache/ojb/broker/cache/CachingStrategyTwoLevelImpl.java)
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/java/org/apache/ojb/broker/cache/CachingPipeFlatCopyImpl.java?view=diff&rev=495668&p1=db/ojb/trunk/src/java/org/apache/ojb/broker/cache/CachingStrategyTwoLevelImpl.java&r1=451479&p2=db/ojb/trunk/src/java/org/apache/ojb/broker/cache/CachingPipeFlatCopyImpl.java&r2=495668
==============================================================================
--- db/ojb/trunk/src/java/org/apache/ojb/broker/cache/CachingStrategyTwoLevelImpl.java (original)
+++ db/ojb/trunk/src/java/org/apache/ojb/broker/cache/CachingPipeFlatCopyImpl.java Fri Jan 12 10:06:09 2007
@@ -20,19 +20,20 @@
 
 import org.apache.ojb.broker.Identity;
 import org.apache.ojb.broker.PersistenceBrokerInternal;
+import org.apache.ojb.broker.util.logging.LoggerFactory;
+import org.apache.ojb.broker.util.logging.Logger;
 import org.apache.ojb.broker.core.factory.ObjectFactory;
 import org.apache.ojb.broker.metadata.ClassDescriptor;
 import org.apache.ojb.broker.metadata.FieldDescriptor;
 import org.apache.ojb.broker.metadata.ObjectCacheDescriptor;
-import org.apache.ojb.broker.util.logging.Logger;
-import org.apache.ojb.broker.util.logging.LoggerFactory;
+import org.apache.ojb.broker.metadata.fieldaccess.PersistentField;
 
 /**
- * This {@link CachingStrategy} is used to enable real <em>two-level caching</em> of
+ * This {@link CachingPipe} is used to enable real <em>two-level caching</em> of
  * objects.
  * <br/>
  * All objects <em>put in</em> the second-level/backend {@link ObjectCache}
- * implementation will be "flat copied" by this caching strategy. This means
+ * implementation will be "flat copied" by this caching pipe. This means
  * that only the normal fields (without references) are read from the
  * original objects and stored in the second-level/backend cache.
  * <br/>
@@ -59,45 +60,59 @@
  *
  * @version $Id$
  */
-public class CachingStrategyTwoLevelImpl extends CachingStrategyAbstractImpl
+public class CachingPipeFlatCopyImpl extends CachingPipeAbstractImpl
 {
-    private Logger log = LoggerFactory.getLogger(CachingStrategyTwoLevelImpl.class);
+    private Logger log = LoggerFactory.getLogger(CachingPipeFlatCopyImpl.class);
 
     private static final String CLASS_NAME_STR = "ojbClassName11";
+    private boolean forceProxies = false;
+    private boolean forceProxiesCheckDone = false;
 
-    public CachingStrategyTwoLevelImpl(PersistenceBrokerInternal broker,
-                                       ObjectCacheExt applicationCache, ObjectCacheDescriptor ocd)
+    public CachingPipeFlatCopyImpl(ObjectCacheDescriptor ocd)
     {
-        super(broker, applicationCache, ocd);
+        super(ocd);
     }
 
     /**
-     * This caching strategy implementation pass "flat" objects (persistent objects without any
-     * references) to the {@link ObjectCache}, so when {@link #lookup(org.apache.ojb.broker.Identity)}
+     * This caching pipe implementation pass "flat" objects (persistent objects without any
+     * references) to the {@link ObjectCache}, so when lookup
      * a cached object it needs full materialization (assign all referenced objects) before
      * it can be returned. The materialization of the referenced objects based on the auto-XXX settings
      * specified in the metadata mapping.
-     *
-     * @param entry The "flat" object for full materialization
      */
-    protected ObjectEntry materializeFullObject(Identity oid, ObjectEntry entry)
+    public Object read(final PersistenceBrokerInternal broker, final Identity oid, final Object obj)
     {
-        ObjectEntry result;
-        PersistenceBrokerInternal pb = getBroker();
-        SessionCache sc = pb.serviceSessionCache();
-        HashMap source = (HashMap) entry.getObject();
+        Object result;
+        SessionCache sc = broker.serviceSessionCache();
+        HashMap source = (HashMap) obj;
         String className = (String) source.get(CLASS_NAME_STR);
-        ClassDescriptor cld = getBroker().getDescriptorRepository().getDescriptorFor(className);
+        ClassDescriptor cld = broker.getDescriptorRepository().getDescriptorFor(className);
         try
         {
-            result = read(oid, source, cld);
+            result = readFlat(broker, oid, source, cld);
             // TODO: Check if use of materialization cache is needed
             sc.enableMaterializationCache();
-            sc.cache(oid, result.getObject(), SessionCache.TYPE_CACHED_READ, SessionCache.LEVEL_SESSION);
+            sc.cache(oid, result, SessionCache.TYPE_CACHED_READ, SessionCache.LEVEL_SESSION);
             // don't force, let OJB use the user settings
-            final boolean forced = false;
-            pb.getReferenceBroker().retrieveReferences(result.getObject(), cld, forced);
-            pb.getReferenceBroker().retrieveCollections(result.getObject(), cld, forced);
+            if(forceProxies)
+            {
+                if (!forceProxiesCheckDone && broker.getProxyFactory().interfaceRequiredForProxyGeneration())
+                {
+                    forceProxiesCheckDone = true;
+                    log.warn("'forceProxies' is set to true, however a ProxyFactory implementation " +
+                    "[" + broker.getProxyFactory().getClass().getName() +"] " +
+                    " that requires persistent objects to implement an inteface is being used. Please ensure " +
+                    "that all persistent objects implement an interface, or change the ProxyFactory setting to a dynamic " +
+                    "proxy generator (like ProxyFactoryCGLIBImpl).");
+                }
+                broker.getReferenceBroker().retrieveProxyReferences(result, cld, false);
+                broker.getReferenceBroker().retrieveProxyCollections(result, cld, false);
+            }
+            else
+            {
+                broker.getReferenceBroker().retrieveReferences(result, cld, false);
+                broker.getReferenceBroker().retrieveCollections(result, cld, false);
+            }
             sc.disableMaterializationCache();
         }
         catch(RuntimeException e)
@@ -109,67 +124,66 @@
     }
 
     /**
-     * Called before an object is written to the application cache (second level cache).
+     * Called before an object is written to the application cache.
      * E.g. allows to make "flat" object copies (without referenced objects) or to cache
      * objects field by field.
      *
      * @param oid       The {@link org.apache.ojb.broker.Identity} of the object.
-     * @param entry       The target object to cache in application cache.
-     * @param oldEntry The old cache object or <em>null</em>.
+     * @param source       The target object to cache in application cache.
      * @return The modified object or a copy of the object to write to application cache.
-     * @see #read(org.apache.ojb.broker.Identity, java.util.HashMap, org.apache.ojb.broker.metadata.ClassDescriptor)
      */
-    protected ObjectEntry write(Identity oid, ObjectEntry entry, ObjectEntry oldEntry)
+    public Object write(final PersistenceBrokerInternal broker, final Identity oid, final Object source)
     {
-        ClassDescriptor cld = getBroker().getClassDescriptor(entry.getObject().getClass());
+        final ClassDescriptor cld = broker.getClassDescriptor(source.getClass());
         // we store field values by name in a Map
-        HashMap target = oldEntry != null ? (HashMap) oldEntry.getObject() : new HashMap();
+        final HashMap target = new HashMap();
         // perform main object values
         FieldDescriptor[] flds = cld.getFieldDescriptor(true);
         FieldDescriptor fld;
-        Object source = entry.getObject();
         int length = flds.length;
         for(int i = 0; i < length; i++)
         {
             fld = flds[i];
-            // get the value
-            Object value = fld.getPersistentField().get(source);
-            // convert value to a supported sql type
-            value = fld.getFieldConversion().javaToSql(value);
-            // copy the sql type
-            value = fld.getJdbcType().getFieldType().copy(value);
-            target.put(fld.getPersistentField().getName(), value);
+            target.put(fld.getPersistentField().getName(), fld.getCopyOfValue(source));
         }
-        target.put(CLASS_NAME_STR, entry.getObject().getClass().getName());
-        return new ObjectEntryImpl(target);
+        target.put(CLASS_NAME_STR, source.getClass().getName());
+        return target;
     }
 
     /**
-     * Called after the object is read from the application cache (second level cache).
+     * Called after the object is read from the application cache.
      * E.g. allows to materialize/populate the referenced objects of "flat" cached objects
-     * or to modify objects read from the second level cache.
+     * or to modify objects read from the application cache.
      *
      * @param oid The {@link org.apache.ojb.broker.Identity} of the object.
      * @param source The map with cached fields.
      * @param cld The associated descriptor of the cached object.
      * @return The modified object or a copy of the object.
-     * @see #write(org.apache.ojb.broker.Identity, ObjectEntry, ObjectEntry)
      */
-    protected ObjectEntry read(Identity oid, HashMap source, ClassDescriptor cld)
+    protected Object readFlat(final PersistenceBrokerInternal broker, final Identity oid, final HashMap source, final ClassDescriptor cld)
     {
-        ObjectFactory     factory           = getBroker().getConfiguration().getObjectFactory();
+        ObjectFactory     factory           = broker.getConfiguration().getObjectFactory();
         FieldDescriptor[] creationFields    = cld.getCreationArgumentFields();
         FieldDescriptor[] nonCreationFields = cld.getNonCreationArgumentFields(true);
         Object            target            = factory.newInstance(cld, getFieldValues(source, creationFields), null);
-        Object[]          fieldValues       = getFieldValues(source, nonCreationFields);
 
         // copy main object values
-        int length = fieldValues.length;
+        int length = nonCreationFields.length;
+        FieldDescriptor field;
+        Object value;
         for (int idx = 0; idx < length; idx++)
         {
-            nonCreationFields[idx].getPersistentField().set(target, fieldValues[idx]);
+            field = nonCreationFields[idx];
+            PersistentField pf = field.getPersistentField();
+            // read the sql field value
+            value = source.get(pf.getName());
+            // copy the sql field value
+            if(value != null) value = field.getJdbcType().getFieldType().copy(value);
+            // now make a field-conversion to java-type value
+            value = field.getFieldConversion().sqlToJava(value);
+            pf.set(target, value);
         }
-        return new ObjectEntryImpl(target);
+        return target;
     }
 
     /**
@@ -180,69 +194,34 @@
      * @param fields The fields
      * @return The values
      */
-    private Object[] getFieldValues(Map source, FieldDescriptor[] fields)
+    private Object[] getFieldValues(final Map source, final FieldDescriptor[] fields)
     {
         Object[] result = new Object[fields.length];
 
         int length = fields.length;
+        FieldDescriptor field;
+        Object value;
         for (int idx = 0; idx < length; idx++)
         {
-            FieldDescriptor field = fields[idx];
-
+            field = fields[idx];
             // read the field value
-            Object value = source.get(field.getPersistentField().getName());
+            value = source.get(field.getPersistentField().getName());
             // copy the field value
             if(value != null) value = field.getJdbcType().getFieldType().copy(value);
-            // now make a field-conversion to java-type, because we only
-            // the sql type of the field
+            // now make a field-conversion to java-type
             result[idx] = field.getFieldConversion().sqlToJava(value);
         }
         return result;
     }
-    
-    public void cache(Identity oid, ObjectEntry entry, boolean cacheIfNew)
-    {
-        ObjectEntry target = write(oid, entry, (cacheIfNew ? null : (ObjectEntry) getObjectCache().lookup(oid)));
-        if(cacheIfNew)
-        {
-            getObjectCache().cacheIfNew(oid, entry);
-        }
-        else
-        {
-            getObjectCache().cache(oid, target);
-        }
-    }
 
-    public ObjectEntry lookup(Identity oid)
+    public boolean isForceProxies()
     {
-        ObjectEntry result = null;
-        ObjectCache cache = getObjectCache();
-        ObjectEntry entry = (ObjectEntry) cache.lookup(oid);
-        if(entry != null)
-        {
-            if(log.isDebugEnabled()) log.debug("Read object from second level cache: " + oid);
-            result = materializeFullObject(oid, entry);
-        }
-        return result;
+        return forceProxies;
     }
 
-    static final class ObjectEntryImpl implements ObjectEntry
+    public void setForceProxies(boolean forceProxies)
     {
-        final Object obj;
-
-        public ObjectEntryImpl(Object obj)
-        {
-            this.obj = obj;
-        }
-
-        public Object getObject()
-        {
-            return obj;
-        }
-
-        public String toString()
-        {
-            return "[ObjectEntry: obj=" + obj + "]";
-        }
+        this.forceProxiesCheckDone = false;
+        this.forceProxies = forceProxies;
     }
 }

Propchange: db/ojb/trunk/src/java/org/apache/ojb/broker/cache/CachingPipeFlatCopyImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: db/ojb/trunk/src/java/org/apache/ojb/broker/cache/CachingPipeFlatCopyImpl.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Copied: db/ojb/trunk/src/java/org/apache/ojb/broker/cache/CachingPipeNoopImpl.java (from r451479, db/ojb/trunk/src/java/org/apache/ojb/broker/cache/CachingStrategyDefaultImpl.java)
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/java/org/apache/ojb/broker/cache/CachingPipeNoopImpl.java?view=diff&rev=495668&p1=db/ojb/trunk/src/java/org/apache/ojb/broker/cache/CachingStrategyDefaultImpl.java&r1=451479&p2=db/ojb/trunk/src/java/org/apache/ojb/broker/cache/CachingPipeNoopImpl.java&r2=495668
==============================================================================
--- db/ojb/trunk/src/java/org/apache/ojb/broker/cache/CachingStrategyDefaultImpl.java (original)
+++ db/ojb/trunk/src/java/org/apache/ojb/broker/cache/CachingPipeNoopImpl.java Fri Jan 12 10:06:09 2007
@@ -20,9 +20,9 @@
 import org.apache.ojb.broker.metadata.ObjectCacheDescriptor;
 
 /**
- * This {@link CachingStrategy} implementation let pass all objects (with all
- * referenced objects) unchanged to/from the specified second-level/backend
- * {@link ObjectCache}, thus dependend on the used backend cache and
+ * This {@link CachingPipe} implementation let pass all objects (with all
+ * referenced objects) unchanged to/from the specified application cache (
+ * {@link ObjectCache}), thus dependend on the used backend cache and
  * <em>object locking strategy</em> it could happen that concurrent user
  * operate on the same object instances or outdated referenced objects.
  * <br/>
@@ -30,7 +30,8 @@
  * <ul>
  * <li>
  * put/return the original object instances with all referenced objects, it could
- * happen that concurrent user operate on the same object instance and a user could read
+ * happen (dependend on the used locking strategy/settings) that concurrent user
+ * operate on the same object instance and a user could read
  * modified field by another user before commit (some kind of dirty reads).
  * <br/>
  * If an appropriate <em>pessimistic locking strategy</em> is used this can be prevented.
@@ -64,28 +65,20 @@
  *
  * @version $Id$
  */
-public class CachingStrategyDefaultImpl extends CachingStrategyAbstractImpl
+public class CachingPipeNoopImpl extends CachingPipeAbstractImpl
 {
-    public CachingStrategyDefaultImpl(PersistenceBrokerInternal broker,
-                                     ObjectCacheExt applicationCache, ObjectCacheDescriptor ocd)
+    public CachingPipeNoopImpl(ObjectCacheDescriptor ocd)
     {
-        super(broker, applicationCache, ocd);
+        super(ocd);
     }
 
-    public void cache(Identity oid, ObjectEntry entry, boolean cacheIfNew)
+    public Object read(final PersistenceBrokerInternal broker, final Identity oid, final Object cached)
     {
-        if(cacheIfNew)
-        {
-            getObjectCache().cacheIfNew(oid, entry);
-        }
-        else
-        {
-            getObjectCache().cache(oid, entry);
-        }
+        return cached;
     }
 
-    public ObjectEntry lookup(Identity oid)
+    public Object write(final PersistenceBrokerInternal broker, final Identity oid, final Object entry)
     {
-        return (ObjectEntry) getObjectCache().lookup(oid);
+        return entry;
     }
 }

Propchange: db/ojb/trunk/src/java/org/apache/ojb/broker/cache/CachingPipeNoopImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: db/ojb/trunk/src/java/org/apache/ojb/broker/cache/CachingPipeNoopImpl.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: db/ojb/trunk/src/java/org/apache/ojb/broker/cache/CachingPolicy.java
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/java/org/apache/ojb/broker/cache/CachingPolicy.java?view=auto&rev=495668
==============================================================================
--- db/ojb/trunk/src/java/org/apache/ojb/broker/cache/CachingPolicy.java (added)
+++ db/ojb/trunk/src/java/org/apache/ojb/broker/cache/CachingPolicy.java Fri Jan 12 10:06:09 2007
@@ -0,0 +1,334 @@
+package org.apache.ojb.broker.cache;
+
+import java.io.Serializable;
+
+/* Copyright 2002-2007 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * The <em>caching policy</em> define how the {@link SessionCache} interacts with
+ * the application cache ({@link ObjectCache}):
+ * <ul>
+ * <li>enable/disable read objects from the application cache</li>
+ * <li>remove all read objects (e.g. when perform a query) from the application cache</li>
+ * <li>enable/disable put objects to the application cache on insert/update or when
+ * new object is read from datastore</li>
+ * </ul>
+ *
+ * @version $Id$
+ */
+public interface CachingPolicy extends Serializable
+{
+    /*
+     TODO: Implement use of CachingPolicy and implicit locking on PB-level
+     TODO: Add comment on concurrency issues and locking when enable remove/putRead mode
+    */
+
+    /**
+     * Returns the name of the caching policy.
+     */
+    public String getName();
+
+    /**
+     * If <em>true</em> lookup objects from application cache is allowed (except
+     * the object metadata indicate that the object always needs refresh data
+     * from the datastore).
+     */
+    public boolean read();
+
+    /**
+     * If <em>true</em> put "insert objects" to application cache is allowed.
+     */
+    public boolean putInsert();
+
+    /**
+     * If <em>true</em> put "update objects" to application cache is allowed.
+     */
+    public boolean putUpdate();
+
+    /**
+     * If <em>true</em> put of "new read objects" (read from the datastore)
+     * to the application cache using method
+     * {@link org.apache.ojb.broker.cache.ObjectCache#cacheIfNew(org.apache.ojb.broker.Identity, Object)}
+     * is allowed.
+     */
+    public boolean putNewRead();
+
+    /**
+     * If <em>true</em> all objects read from the datastore are immediately put to the
+     * application cache. If <em>true</em> this will override/overlay setting in {@link #putNewRead()}.
+     */
+    public boolean putRead();
+
+    /**
+     * If <em>true</em> all objects read from the datastore are immediately removed from the
+     * application cache. If <em>true</em> this will override/overlay setting in {@link #putNewRead()}
+     * and {@link #putRead()}.
+     */
+    public boolean removeRead();
+
+
+    /**
+     * This policy will read objects from the application cache and
+     * put inserted and updated objects to the application cache.
+     */
+    public static final CachingPolicy PUT = new CachingPolicy(){
+
+        public String getName()
+        {
+            return "PUT";
+        }
+
+        public boolean putInsert()
+        {
+            return true;
+        }
+
+        public boolean putNewRead()
+        {
+            return false;
+        }
+
+        public boolean putRead()
+        {
+            return false;
+        }
+
+        public boolean putUpdate()
+        {
+            return true;
+        }
+
+        public boolean read()
+        {
+            return true;
+        }
+
+        public boolean removeRead()
+        {
+            return false;
+        }
+    };
+
+    /**
+     * This policy will read objects from the application cache and
+     * put inserted, updated and new read objects to the application cache.
+     */
+    public static final CachingPolicy PUT_MAX = new CachingPolicy(){
+
+        public String getName()
+        {
+            return "PUT_MAX";
+        }
+
+        public boolean putInsert()
+        {
+            return true;
+        }
+
+        public boolean putNewRead()
+        {
+            return true;
+        }
+
+        public boolean putRead()
+        {
+            return false;
+        }
+
+        public boolean putUpdate()
+        {
+            return true;
+        }
+
+        public boolean read()
+        {
+            return true;
+        }
+
+        public boolean removeRead()
+        {
+            return false;
+        }
+    };
+
+    /**
+     * This policy will read objects from the application cache and
+     * put only updated objects to the application cache.
+     */
+    public static final CachingPolicy PUT_MIN = new CachingPolicy(){
+
+        public String getName()
+        {
+            return "PUT_MIN";
+        }
+
+        public boolean putInsert()
+        {
+            return false;
+        }
+
+        public boolean putNewRead()
+        {
+            return false;
+        }
+
+        public boolean putRead()
+        {
+            return false;
+        }
+
+        public boolean putUpdate()
+        {
+            return true;
+        }
+
+        public boolean read()
+        {
+            return true;
+        }
+
+        public boolean removeRead()
+        {
+            return false;
+        }
+    };
+
+    /**
+     * This policy will never read objects from the application cache and
+     * put inserted and updated objects to the application cache.
+     */
+    public static final CachingPolicy NO_READ = new CachingPolicy(){
+
+        public String getName()
+        {
+            return "NO_READ";
+        }
+
+        public boolean putInsert()
+        {
+            return true;
+        }
+
+        public boolean putNewRead()
+        {
+            return false;
+        }
+
+        public boolean putRead()
+        {
+            return false;
+        }
+
+        public boolean putUpdate()
+        {
+            return true;
+        }
+
+        public boolean read()
+        {
+            return false;
+        }
+
+        public boolean removeRead()
+        {
+            return false;
+        }
+    };
+
+    /**
+     * This policy will never read objects from the application cache and
+     * put only updated objects to the application cache.
+     */
+    public static final CachingPolicy NO_READ_MIN = new CachingPolicy(){
+
+        public String getName()
+        {
+            return "NO_READ_MIN";
+        }
+
+        public boolean putInsert()
+        {
+            return false;
+        }
+
+        public boolean putNewRead()
+        {
+            return false;
+        }
+
+        public boolean putRead()
+        {
+            return false;
+        }
+
+        public boolean putUpdate()
+        {
+            return true;
+        }
+
+        public boolean read()
+        {
+            return false;
+        }
+
+        public boolean removeRead()
+        {
+            return false;
+        }
+    };
+
+    /**
+     * This policy will remove all read objects (e.g. when perform a query) from the
+     * application cache and put only updated objects to the application cache.
+     */
+    public static final CachingPolicy REMOVE = new CachingPolicy(){
+
+        public String getName()
+        {
+            return "REMOVE";
+        }
+
+        public boolean putInsert()
+        {
+            return false;
+        }
+
+        public boolean putNewRead()
+        {
+            return false;
+        }
+
+        public boolean putRead()
+        {
+            return false;
+        }
+
+        public boolean putUpdate()
+        {
+            return true;
+        }
+
+        public boolean read()
+        {
+            return false;
+        }
+
+        public boolean removeRead()
+        {
+            return true;
+        }
+    };
+}

Added: db/ojb/trunk/src/java/org/apache/ojb/broker/cache/Connector.java
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/java/org/apache/ojb/broker/cache/Connector.java?view=auto&rev=495668
==============================================================================
--- db/ojb/trunk/src/java/org/apache/ojb/broker/cache/Connector.java (added)
+++ db/ojb/trunk/src/java/org/apache/ojb/broker/cache/Connector.java Fri Jan 12 10:06:09 2007
@@ -0,0 +1,100 @@
+package org.apache.ojb.broker.cache;
+
+/* Copyright 2002-2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import org.apache.ojb.broker.metadata.ObjectCacheDescriptor;
+import org.apache.ojb.broker.Identity;
+import org.apache.ojb.broker.PersistenceBrokerInternal;
+
+/**
+ * Encapsulates caching classes and provide convenience methods to cache and lookup objects
+ * from the application cache (e.g. a second level cache) and allows direct cache and lookup calls
+ * on the application cache.
+ *
+ * @version $Id: $
+ */
+public class Connector
+{
+    ObjectCacheDescriptor ocd;
+    ObjectCache applicationCache;
+    CachingPipe cachingPipe;
+
+    Connector(final ObjectCacheDescriptor ocd, final ObjectCache applicationCache, final CachingPipe cachingPipe)
+    {
+        this.ocd = ocd;
+        this.applicationCache = applicationCache;
+        this.cachingPipe = cachingPipe;
+    }
+
+    /**
+     * Convenience method to cache an object using
+     * {@link CachingPipe#write(org.apache.ojb.broker.PersistenceBrokerInternal, org.apache.ojb.broker.Identity, Object)}
+     * and {@link ObjectCache#cache(org.apache.ojb.broker.Identity, Object)}.
+     *
+     * @param broker The current {@link org.apache.ojb.broker.PersistenceBrokerInternal} instance.
+     * @param oid The {@link org.apache.ojb.broker.Identity} of the object.
+     * @param obj The object to cache.
+     */
+    public void cache(final PersistenceBrokerInternal broker, final Identity oid, final Object obj)
+    {
+        applicationCache.cache(oid, cachingPipe.write(broker, oid, obj));
+    }
+
+    /**
+     * Convenience method to cache new materialized objects using
+     * {@link CachingPipe#write(org.apache.ojb.broker.PersistenceBrokerInternal, org.apache.ojb.broker.Identity, Object)}
+     * and {@link ObjectCache#cacheIfNew(org.apache.ojb.broker.Identity, Object)}.
+     *
+     * @param broker The current {@link org.apache.ojb.broker.PersistenceBrokerInternal} instance.
+     * @param oid The {@link org.apache.ojb.broker.Identity} of the object.
+     * @param obj The object to cache.
+     */
+    public boolean cacheIfNew(final PersistenceBrokerInternal broker, final Identity oid, final Object obj)
+    {
+        return applicationCache.cacheIfNew(oid, cachingPipe.write(broker, oid, obj));
+    }
+
+    /**
+     * Convenience method to lookup an object using
+     * {@link ObjectCache#cache(org.apache.ojb.broker.Identity, Object)} and
+     * {@link CachingPipe#read(org.apache.ojb.broker.PersistenceBrokerInternal, org.apache.ojb.broker.Identity, Object)}
+     *
+     * @param broker The current {@link org.apache.ojb.broker.PersistenceBrokerInternal} instance.
+     * @param oid The {@link org.apache.ojb.broker.Identity} of the object.
+     * @return The matched object from the application cache filtered/modified by the caching pipe.
+     */
+    public Object lookup(final PersistenceBrokerInternal broker, final Identity oid)
+    {
+        Object cached = applicationCache.lookup(oid);
+        return cached != null ? cachingPipe.read(broker, oid, cached) : null;
+    }
+
+    /**
+     * Returns the application cache - a {@link ObjectCache} instance.
+     */
+    public ObjectCache getObjectCache()
+    {
+        return applicationCache;
+    }
+
+    /**
+     * Returns the {@link CachingPipe}.
+     */
+    public CachingPipe getCachingPreparer()
+    {
+        return cachingPipe;
+    }
+}

Added: db/ojb/trunk/src/java/org/apache/ojb/broker/cache/InvalidationRegistry.java
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/java/org/apache/ojb/broker/cache/InvalidationRegistry.java?view=auto&rev=495668
==============================================================================
--- db/ojb/trunk/src/java/org/apache/ojb/broker/cache/InvalidationRegistry.java (added)
+++ db/ojb/trunk/src/java/org/apache/ojb/broker/cache/InvalidationRegistry.java Fri Jan 12 10:06:09 2007
@@ -0,0 +1,53 @@
+package org.apache.ojb.broker.cache;
+
+/* Copyright 2002-2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.lang.Object;
+import java.util.List;
+
+/**
+ * Manage {@link org.apache.ojb.broker.cache.InvalidationListener} objects.
+ * <br/>
+ * <strong>NOTE:</strong> Take care, the added listener is only <em>weakly reachable</em>
+ * (see {@link java.lang.ref.WeakReference}) by this class and will be garbage collected
+ * if no other reference to the listener exists.
+ *
+ * @version $Id: InvalidationRegistry.java 364930 2005-08-27 14:06:45 +0200 (Sa, 27 Aug 2005) arminw $
+ */
+public interface InvalidationRegistry
+{
+    /**
+     * Add an {@link org.apache.ojb.broker.cache.InvalidationListener} to this cache. Double added
+     * listener will be ignored. All listener objects will only be add
+     * <strong>weakly reachable</strong> (see {@link java.lang.ref.WeakReference}),
+     * thus take care about the added listener.
+     *
+     * @param listener The listener to add.
+     */
+    public void addInvalidationListener(InvalidationListener listener);
+
+    /**
+     * Remove an {@link org.apache.ojb.broker.cache.InvalidationListener} from this cache strategy.
+     *
+     * @param listener The listener to remove.
+     */
+    public void removeInvalidationListener(InvalidationListener listener);
+
+    /**
+     * Return a list of all invalidation listener.
+     */
+    public List getAllInvalidationListener();
+}

Added: db/ojb/trunk/src/java/org/apache/ojb/broker/core/CollectionTypes.java
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/java/org/apache/ojb/broker/core/CollectionTypes.java?view=auto&rev=495668
==============================================================================
--- db/ojb/trunk/src/java/org/apache/ojb/broker/core/CollectionTypes.java (added)
+++ db/ojb/trunk/src/java/org/apache/ojb/broker/core/CollectionTypes.java Fri Jan 12 10:06:09 2007
@@ -0,0 +1,169 @@
+package org.apache.ojb.broker.core;
+
+/* Copyright 2002-2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import org.apache.ojb.broker.util.collections.ManageableListImpl;
+import org.apache.ojb.broker.util.collections.ManageableSetImpl;
+import org.apache.ojb.broker.util.collections.ManageableVector;
+import org.apache.ojb.broker.util.collections.RemovalAwareCollection;
+import org.apache.ojb.broker.util.collections.RemovalAwareList;
+import org.apache.ojb.broker.util.collections.RemovalAwareSet;
+import org.apache.ojb.broker.util.collections.RemovalAwareVector;
+
+/**
+ * This class provide the default collection implementation classes for 1:n, m:n references
+ * and query results.
+ *
+ * @version $Id: $
+ */
+public class CollectionTypes
+{
+    private Class oneToManyArray = RemovalAwareCollection.class;
+    private Class oneToManyCollection = RemovalAwareCollection.class;
+    private Class oneToManyList = RemovalAwareList.class;
+    private Class oneToManyVector = RemovalAwareVector.class;
+    private Class oneToManySet = RemovalAwareSet.class;
+
+    private Class manyToManyArray = ManageableListImpl.class;
+    private Class manyToManyCollection = ManageableListImpl.class;
+    private Class manyToManyList = ManageableListImpl.class;
+    private Class manyToManyVector = ManageableVector.class;
+    private Class manyToManySet = ManageableSetImpl.class;
+
+    private Class query = ManageableListImpl.class;
+    private Class OQLQuery = ManageableListImpl.class;
+
+
+    public Class getOneToManyArray()
+    {
+        return oneToManyArray;
+    }
+
+    public void setOneToManyArray(Class oneToManyArray)
+    {
+        this.oneToManyArray = oneToManyArray;
+    }
+
+    public Class getOneToManyCollection()
+    {
+        return oneToManyCollection;
+    }
+
+    public void setOneToManyCollection(Class oneToManyCollection)
+    {
+        this.oneToManyCollection = oneToManyCollection;
+    }
+
+    public Class getOneToManyList()
+    {
+        return oneToManyList;
+    }
+
+    public void setOneToManyList(Class oneToManyList)
+    {
+        this.oneToManyList = oneToManyList;
+    }
+
+    public Class getOneToManyVector()
+    {
+        return oneToManyVector;
+    }
+
+    public void setOneToManyVector(Class oneToManyVector)
+    {
+        this.oneToManyVector = oneToManyVector;
+    }
+
+    public Class getOneToManySet()
+    {
+        return oneToManySet;
+    }
+
+    public void setOneToManySet(Class oneToManySet)
+    {
+        this.oneToManySet = oneToManySet;
+    }
+
+    public Class getManyToManyArray()
+    {
+        return manyToManyArray;
+    }
+
+    public void setManyToManyArray(Class manyToManyArray)
+    {
+        this.manyToManyArray = manyToManyArray;
+    }
+
+    public Class getManyToManyCollection()
+    {
+        return manyToManyCollection;
+    }
+
+    public void setManyToManyCollection(Class manyToManyCollection)
+    {
+        this.manyToManyCollection = manyToManyCollection;
+    }
+
+    public Class getManyToManyList()
+    {
+        return manyToManyList;
+    }
+
+    public void setManyToManyList(Class manyToManyList)
+    {
+        this.manyToManyList = manyToManyList;
+    }
+
+    public Class getManyToManyVector()
+    {
+        return manyToManyVector;
+    }
+
+    public void setManyToManyVector(Class manyToManyVector)
+    {
+        this.manyToManyVector = manyToManyVector;
+    }
+
+    public Class getManyToManySet()
+    {
+        return manyToManySet;
+    }
+
+    public void setManyToManySet(Class manyToManySet)
+    {
+        this.manyToManySet = manyToManySet;
+    }
+
+    public Class getOQLQuery()
+    {
+        return OQLQuery;
+    }
+
+    public void setOQLQuery(Class OQLQuery)
+    {
+        this.OQLQuery = OQLQuery;
+    }
+
+    public Class getQuery()
+    {
+        return query;
+    }
+
+    public void setQuery(Class query)
+    {
+        this.query = query;
+    }
+}

Added: db/ojb/trunk/src/java/org/apache/ojb/broker/metadata/GenericDescriptor.java
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/java/org/apache/ojb/broker/metadata/GenericDescriptor.java?view=auto&rev=495668
==============================================================================
--- db/ojb/trunk/src/java/org/apache/ojb/broker/metadata/GenericDescriptor.java (added)
+++ db/ojb/trunk/src/java/org/apache/ojb/broker/metadata/GenericDescriptor.java Fri Jan 12 10:06:09 2007
@@ -0,0 +1,109 @@
+package org.apache.ojb.broker.metadata;
+
+/* Copyright 2002-2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.io.Serializable;
+
+import org.apache.ojb.broker.PersistenceBrokerInternal;
+
+/**
+ * Abstract base class to handle/persist generic objects.
+ *
+ * @version $Id: $
+ */
+abstract public class GenericDescriptor implements Serializable
+{
+    /**
+     * Returns the full table name.
+     */
+    abstract public String getTableName();
+
+    /**
+     * If <em>true</em> the obtained insert, update, delete statements can be used
+     * to batch object values, if <em>false</em> batching is not allowed.
+     */
+    abstract public boolean isBatchable();
+
+    /**
+     * Returns the INSERT sql statement.
+     *
+     * @param broker The current used {@link org.apache.ojb.broker.PersistenceBrokerInternal} instance.
+     * @return An sql string for prepared statement.
+     */
+    abstract public String insertSql(PersistenceBrokerInternal broker);
+
+    /**
+     * Returns the UPDATE sql statement.
+     *
+     * @param broker The current used {@link org.apache.ojb.broker.PersistenceBrokerInternal} instance.
+     * @return An sql string for prepared statement.
+     */
+    abstract public String updateSql(PersistenceBrokerInternal broker);
+
+    /**
+     * Returns the DELETE sql statement.
+     *
+     * @param broker The current used {@link org.apache.ojb.broker.PersistenceBrokerInternal} instance.
+     * @return An sql string for prepared statement.
+     */
+    abstract public String deleteSql(PersistenceBrokerInternal broker);
+
+    /**
+     * Returns the insert {@link java.sql.Statement}.
+     *
+     * @param broker The current used {@link org.apache.ojb.broker.PersistenceBrokerInternal} instance.
+     * @param obj The object/the objects to insert.
+     * @return The insert statement.
+     */
+    abstract public PreparedStatement insert(PersistenceBrokerInternal broker, GenericObject obj) throws SQLException;
+
+    /**
+     * Returns the update {@link java.sql.Statement}.
+     *
+     * @param broker The current used {@link org.apache.ojb.broker.PersistenceBrokerInternal} instance.
+     * @param obj The object/the objects to update.
+     * @return The update statement.
+     */
+    abstract public PreparedStatement update(PersistenceBrokerInternal broker, GenericObject obj) throws SQLException;
+
+    /**
+     * Returns the delete {@link java.sql.Statement}.
+     *
+     * @param broker The current used {@link org.apache.ojb.broker.PersistenceBrokerInternal} instance.
+     * @param obj The object/the objects to delete.
+     * @return The delete statement.
+     */
+    abstract public PreparedStatement delete(PersistenceBrokerInternal broker, GenericObject obj) throws SQLException;
+
+//    /**
+//     * Returns the "find by primary key" statement.
+//     *
+//     * @param broker The current used {@link org.apache.ojb.broker.PersistenceBrokerInternal} instance.
+//     * @param obj The primary keys/identifier values..
+//     * @return The find by PK statement.
+//     */
+//    abstract public PreparedStatement byPrimaryKey(PersistenceBrokerInternal broker, GenericObject obj) throws SQLException;
+//
+//    /**
+//     * Prepare a query result.
+//     *
+//     * @param result The query result.
+//     * @return The prepared query result.
+//     */
+//    abstract public Object prepareQueryResult(ResultSetAndStatement result) throws SQLException;
+}

Added: db/ojb/trunk/src/java/org/apache/ojb/broker/metadata/GenericObject.java
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/java/org/apache/ojb/broker/metadata/GenericObject.java?view=auto&rev=495668
==============================================================================
--- db/ojb/trunk/src/java/org/apache/ojb/broker/metadata/GenericObject.java (added)
+++ db/ojb/trunk/src/java/org/apache/ojb/broker/metadata/GenericObject.java Fri Jan 12 10:06:09 2007
@@ -0,0 +1,30 @@
+package org.apache.ojb.broker.metadata;
+
+/* Copyright 2002-2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.lang.Object;
+
+import org.apache.ojb.broker.core.ValueContainer;
+
+/**
+ * This class
+ *
+ * @version $Id: $
+ */
+public interface GenericObject
+{
+    public ValueContainer[] getValues();
+}

Added: db/ojb/trunk/src/java/org/apache/ojb/broker/metadata/IndirectionTableDescriptor.java
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/java/org/apache/ojb/broker/metadata/IndirectionTableDescriptor.java?view=auto&rev=495668
==============================================================================
--- db/ojb/trunk/src/java/org/apache/ojb/broker/metadata/IndirectionTableDescriptor.java (added)
+++ db/ojb/trunk/src/java/org/apache/ojb/broker/metadata/IndirectionTableDescriptor.java Fri Jan 12 10:06:09 2007
@@ -0,0 +1,436 @@
+package org.apache.ojb.broker.metadata;
+
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.util.Collection;
+import java.util.Iterator;
+
+import org.apache.commons.lang.ArrayUtils;
+import org.apache.commons.lang.builder.ToStringBuilder;
+import org.apache.ojb.broker.OJBRuntimeException;
+import org.apache.ojb.broker.PersistenceBrokerInternal;
+import org.apache.ojb.broker.accesslayer.ResultSetAndStatement;
+import org.apache.ojb.broker.accesslayer.StatementManager;
+import org.apache.ojb.broker.accesslayer.sql.SqlGenerator;
+import org.apache.ojb.broker.accesslayer.sql.SqlStatement;
+import org.apache.ojb.broker.core.ValueContainer;
+import org.apache.ojb.broker.query.Query;
+import org.apache.ojb.broker.util.BrokerHelper;
+
+/* Copyright 2002-2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Encapsulates metadata mapping information of an m:n indirection table.
+ *
+ * @version $Id: $
+ */
+public class IndirectionTableDescriptor extends GenericDescriptor
+{
+    private CollectionDescriptor thisCollectionDescriptor;
+    private ClassDescriptor otherFirstMappedDescriptor;
+    private ClassDescriptor otherDescriptor;
+    private String[] mergedColumns;
+    private boolean sharedIndirectionTableColumns = false;
+    private int[] sharedIndirectionTableColumnIndices = new int[]{};
+
+    private transient SqlStatement insertSql;
+    private transient SqlStatement deleteSql;
+    private transient SqlStatement selectAllOtherColumns;
+
+    public IndirectionTableDescriptor(CollectionDescriptor thisDescriptor)
+    {
+        this.thisCollectionDescriptor = thisDescriptor;
+        mergeColumns();
+    }
+
+    public GenericObject createObject(final PersistenceBrokerInternal broker, final Object thisObj, final Object otherObj)
+    {
+        return new TableObject(broker, this, thisObj, otherObj);
+    }
+
+    public GenericObject createObject(final PersistenceBrokerInternal broker,
+                                      final ValueContainer[] pkValues, final ValueContainer[] fkValues)
+    {
+        return new TableObject(this, pkValues, fkValues);
+    }
+
+    public boolean isBatchable()
+    {
+        return true;
+    }
+
+    public String insertSql(final PersistenceBrokerInternal broker)
+    {
+        if(insertSql == null)
+        {
+            insertSql = broker.serviceSqlGenerator().getGenericPreparedStatement(
+                    SqlGenerator.TYPE_GENERIC_INSERT, getTableName(), mergedColumns, null);
+        }
+        return insertSql.getStatement();
+    }
+
+    public String updateSql(final PersistenceBrokerInternal broker)
+    {
+        // not supported
+        throw new UnsupportedOperationException("Not supported");
+    }
+
+    public String deleteSql(PersistenceBrokerInternal broker)
+    {
+        if(deleteSql == null)
+        {
+            deleteSql = broker.serviceSqlGenerator().getGenericPreparedStatement(
+                    SqlGenerator.TYPE_GENERIC_DELETE, getTableName(), null, mergedColumns);
+        }
+        return deleteSql.getStatement();
+    }
+
+    public PreparedStatement insert(PersistenceBrokerInternal broker, GenericObject obj) throws SQLException
+    {
+        IndirectionTableDescriptor.TableObject tabObj = (IndirectionTableDescriptor.TableObject) obj;
+        PreparedStatement stmt = broker.serviceStatementManager().getPreparedStatement(
+                insertSql(broker), false, StatementManager.FETCH_SIZE_NOT_APPLICABLE, false);
+        broker.serviceJdbcAccess().bindValues(stmt, tabObj.getValues(), 1);
+        return stmt;
+    }
+
+    public PreparedStatement update(PersistenceBrokerInternal broker, GenericObject obj) throws SQLException
+    {
+        // not supported
+        throw new UnsupportedOperationException("Not supported");
+    }
+
+    public PreparedStatement delete(PersistenceBrokerInternal broker, GenericObject obj) throws SQLException
+    {
+        IndirectionTableDescriptor.TableObject tabObj = (IndirectionTableDescriptor.TableObject) obj;
+        PreparedStatement stmt = broker.serviceStatementManager().getPreparedStatement(
+                deleteSql(broker), false, StatementManager.FETCH_SIZE_NOT_APPLICABLE, false);
+        broker.serviceJdbcAccess().bindValues(stmt, tabObj.getValues(), 1);
+        return stmt;
+    }
+
+//    public PreparedStatement byPrimaryKey(PersistenceBrokerInternal broker, GenericObject obj) throws SQLException
+//    {
+//        // not supported
+//        throw new UnsupportedOperationException("Not supported");
+//    }
+//
+//    public Object prepareQueryResult(ResultSetAndStatement result)
+//    {
+//        // not supported
+//        throw new UnsupportedOperationException("Not supported");
+//    }
+
+    public String getTableName()
+    {
+        return thisCollectionDescriptor.getIndirectionTable();
+    }
+
+    public CollectionDescriptor getThisCollectionDescriptor()
+    {
+        return thisCollectionDescriptor;
+    }
+
+    public String[] getThisColumns()
+    {
+        return thisCollectionDescriptor.getFksToThisClass();
+    }
+
+    public String[] getOtherColumns()
+    {
+        return thisCollectionDescriptor.getFksToItemClass();
+    }
+
+    public ClassDescriptor getThisClassDescriptor()
+    {
+        return thisCollectionDescriptor.getClassDescriptor();
+    }
+
+    public ClassDescriptor getOtherClassDescriptor()
+    {
+        if(otherDescriptor == null)
+        {
+            otherDescriptor = getThisCollectionDescriptor().getItemClassDescriptor();
+        }
+        return otherDescriptor;
+    }
+
+    public ClassDescriptor getOtherFirstMappedDescriptor()
+    {
+        if(otherFirstMappedDescriptor == null)
+        {
+            otherFirstMappedDescriptor = findFirstRealSubClassDescriptor(getOtherClassDescriptor());
+        }
+        return otherFirstMappedDescriptor;
+    }
+
+    private ClassDescriptor findFirstRealSubClassDescriptor(final ClassDescriptor cld)
+    {
+        ClassDescriptor result = cld;
+        if(!result.isMappedToTable())
+        {
+            Collection extents = cld.getRepository().getAllConcreteSubclassDescriptors(cld);
+            for(Iterator iterator = extents.iterator(); iterator.hasNext();)
+            {
+                ClassDescriptor tmp = (ClassDescriptor) iterator.next();
+                if(tmp.isMappedToTable())
+                {
+                    result = tmp;
+                    break;
+                }
+            }
+        }
+        return result;
+    }
+
+    public String[] getMergedColumns()
+    {
+        return mergedColumns;
+    }
+
+    public void mergeColumns()
+    {
+        String[] thisColumns = getThisColumns();
+        String[] otherColumns = getOtherColumns();
+        mergedColumns = mergeColumns(
+                mergeSharedIndirectionTableColumns(thisColumns, otherColumns),
+                otherColumns);
+    }
+
+    private String[] mergeSharedIndirectionTableColumns(final String[] isThis, final String[] isOther)
+    {
+        String[] thisResult = isThis;
+        /*
+        fix for OJB-76, composite M & N keys that have some fields common
+        find the "shared" indirection table columns, values and remove these from m- or n- side
+        */
+        for(int i = 0; i < isOther.length; i++)
+        {
+            int index = ArrayUtils.indexOf(isThis, isOther[i]);
+            if(index != -1)
+            {
+                // shared indirection table column found, remove this column from one side
+                thisResult = (String[]) ArrayUtils.remove(isThis, index);
+                sharedIndirectionTableColumnIndices = ArrayUtils.add(sharedIndirectionTableColumnIndices, index);
+                sharedIndirectionTableColumns = true;
+            }
+        }
+        return thisResult;
+    }
+
+    private String[] mergeColumns(final String[] isThis, final String[] isOther)
+    {
+        String[] cols = new String[isThis.length + isOther.length];
+        System.arraycopy(isThis, 0, cols, 0, isThis.length);
+        System.arraycopy(isOther, 0, cols, isThis.length, isOther.length);
+        return cols;
+    }
+
+    ValueContainer[] removeSharedIndirectionTableColumns(final ValueContainer[] thisValues)
+    {
+        ValueContainer[] result = thisValues;
+        for(int i = 0; i < sharedIndirectionTableColumnIndices.length; i++)
+        {
+            int index = sharedIndirectionTableColumnIndices[i];
+            result = (ValueContainer[]) ArrayUtils.remove(result, index);
+        }
+        return result;
+    }
+
+    boolean isSharedIndirectionTableColumns()
+    {
+        return sharedIndirectionTableColumns;
+    }
+
+    /**
+     * Returns an sql query string for prepared statements to select all
+     * foreign key columns of the other objects in indirection table associated with
+     * this object. Expects the primary key values of this object as prepared statement arguments.
+     */
+    private String selectAllForeignKeyColumnsSql(PersistenceBrokerInternal broker)
+    {
+        if(selectAllOtherColumns == null)
+        {
+            selectAllOtherColumns = broker.serviceSqlGenerator().getGenericPreparedStatement(
+                    SqlGenerator.TYPE_GENERIC_SELECT,
+                    getTableName(),
+                    getOtherColumns(),
+                    getThisColumns());
+        }
+        return selectAllOtherColumns.getStatement();
+    }
+
+    /**
+     * This method queries the foreign key columns of all other objects in indirection table
+     * associated with the specified object.
+     *
+     * @param broker The current used {@link org.apache.ojb.broker.PersistenceBrokerInternal}.
+     * @param thisObj The object we search for indirection table entries.
+     * @return The query result.
+     */
+    public ResultSetAndStatement selectAllForeignKeyColumns(PersistenceBrokerInternal broker, Object thisObj)
+    {
+        ValueContainer[] pkValues = broker.serviceBrokerHelper().getKeyValues(getThisClassDescriptor(), thisObj, true);
+        return broker.serviceJdbcAccess().executeSQL(selectAllForeignKeyColumnsSql(broker), pkValues, Query.NOT_SCROLLABLE);
+    }
+
+    /**
+     * Deletes all indirection table entries of the specified object.
+     *
+     * @param broker The current used {@link org.apache.ojb.broker.PersistenceBrokerInternal} instance.
+     * @param obj The source object.
+     * @return The number of deleted entries.
+     */
+    public int deleteAllIndirectionTableEntries(PersistenceBrokerInternal broker, Object obj)
+    {
+        ClassDescriptor cld = broker.getDescriptorRepository().getDescriptorFor(obj.getClass());
+        ValueContainer[] pkValues = broker.serviceBrokerHelper().getKeyValues(cld, obj, true);
+        String deleteStmt = broker.serviceSqlGenerator().getGenericPreparedStatement(
+                SqlGenerator.TYPE_GENERIC_DELETE,
+                getTableName(),
+                null,
+                getThisColumns()).getStatement();
+        return broker.serviceJdbcAccess().executeUpdateSQL(deleteStmt, pkValues);
+    }
+
+    //===================================================================
+    // inner class
+    //===================================================================
+
+    public static final class TableObject implements GenericObject
+    {
+        private IndirectionTableDescriptor descriptor;
+        private ValueContainer[] values;
+        int hc;
+
+        public TableObject(final PersistenceBrokerInternal broker, final IndirectionTableDescriptor descriptor, final Object thisObj, final Object otherObj)
+        {
+            BrokerHelper helper = broker.serviceBrokerHelper();
+            this.descriptor = descriptor;
+            ValueContainer[] thisValues = helper.getKeyValues(
+                    descriptor.getThisClassDescriptor(),
+                    thisObj, true);
+            ValueContainer[] otherValues = helper.getKeyValues(
+                    descriptor.getOtherFirstMappedDescriptor(),
+                    otherObj, true);
+            values = mergeValues(thisValues, otherValues);
+        }
+
+        public TableObject(final IndirectionTableDescriptor descriptor, final ValueContainer[] pkValues, final ValueContainer[] fkValues)
+        {
+            this.descriptor = descriptor;
+            values = mergeValues(pkValues, fkValues);
+        }
+
+        public TableObject(final IndirectionTableDescriptor descriptor, final ValueContainer[] values)
+        {
+            this.descriptor = descriptor;
+            this.values = values;
+        }
+
+        private ValueContainer[] mergeValues(ValueContainer[] isThis, final ValueContainer[] isOther)
+        {
+            if(descriptor.isSharedIndirectionTableColumns())
+            {
+                isThis = descriptor.removeSharedIndirectionTableColumns(isThis);
+            }
+            ValueContainer[] values = new ValueContainer[isThis.length + isOther.length];
+            System.arraycopy(isThis, 0, values, 0, isThis.length);
+            System.arraycopy(isOther, 0, values, isThis.length, isOther.length);
+            return values;
+        }
+
+        public ValueContainer[] getValues()
+        {
+            return values;
+        }
+
+        public boolean equals(Object obj)
+        {
+            if(this == obj)
+            {
+                return true;
+            }
+            boolean result = false;
+            if(obj instanceof TableObject)
+            {
+                TableObject other = (TableObject) obj;
+
+                if(descriptor.getTableName().equals(other.descriptor.getTableName()))
+                {
+                    for(int i = 0; i < descriptor.mergedColumns.length; i++)
+                    {
+                        int otherIndex = other.indexForColumn(descriptor.mergedColumns[i]);
+                        if(otherIndex < 0)
+                        {
+                            result = false;
+                            break;
+                        }
+                        result = values[i].equals(other.values[otherIndex]);
+                        if(!result) break;
+                    }
+                }
+            }
+            return result;
+        }
+
+        public int hashCode()
+        {
+            if(hc == 0)
+            {
+                for(int i = 0; i < values.length; i++)
+                {
+                    hc += values[i].hashCode();
+                }
+            }
+            return hc;
+        }
+
+        int indexForColumn(String name)
+        {
+            int result = -1;
+            for(int i = 0; i < descriptor.mergedColumns.length; i++)
+            {
+                if(descriptor.mergedColumns[i].equals(name))
+                {
+                    result = i;
+                    break;
+                }
+            }
+            return result;
+        }
+
+        public ValueContainer getValueFor(String columnName)
+        {
+            try
+            {
+                return values[indexForColumn(columnName)];
+            }
+            catch(Exception e)
+            {
+                throw new OJBRuntimeException("Can't find value for column " + columnName
+                        + (indexForColumn(columnName) < 0 ? ". Column name was not found" : ""), e);
+            }
+        }
+
+        public String toString()
+        {
+            return new ToStringBuilder(this)
+                    .append("indirection_table", descriptor.getTableName())
+                    .append("values", values).toString();
+        }
+    }
+}
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.