db-ojb-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From arm...@apache.org
Subject 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...
Date Fri, 12 Jan 2007 18:06:11 GMT
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:arminw@apache.org">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();
+        }
+    }
+}



---------------------------------------------------------------------
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