db-ojb-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From b..@apache.org
Subject cvs commit: db-ojb/src/java/org/apache/ojb/broker/accesslayer MtoNCollectionPrefetcher.java RelationshipPrefetcherFactory.java CollectionPrefetcher.java
Date Mon, 22 Dec 2003 15:34:54 GMT
brj         2003/12/22 07:34:54

  Modified:    src/java/org/apache/ojb/broker/accesslayer
                        RelationshipPrefetcherFactory.java
                        CollectionPrefetcher.java
  Added:       src/java/org/apache/ojb/broker/accesslayer
                        MtoNCollectionPrefetcher.java
  Log:
  support for prefetching m:n relationships
  
  Revision  Changes    Path
  1.3       +10 -2     db-ojb/src/java/org/apache/ojb/broker/accesslayer/RelationshipPrefetcherFactory.java
  
  Index: RelationshipPrefetcherFactory.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/broker/accesslayer/RelationshipPrefetcherFactory.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- RelationshipPrefetcherFactory.java	8 Dec 2003 21:13:19 -0000	1.2
  +++ RelationshipPrefetcherFactory.java	22 Dec 2003 15:34:54 -0000	1.3
  @@ -75,7 +75,15 @@
       {
           if (ord instanceof CollectionDescriptor)
           {
  -            return new CollectionPrefetcher(aBroker, ord);                
  +            CollectionDescriptor cds = (CollectionDescriptor)ord;
  +            if (cds.isMtoNRelation())
  +            {
  +                return new MtoNCollectionPrefetcher(aBroker, cds);                    
           
  +            }
  +            else
  +            {
  +                return new CollectionPrefetcher(aBroker, cds);                
  +            }
           }
           else
           {    
  
  
  
  1.21      +52 -43    db-ojb/src/java/org/apache/ojb/broker/accesslayer/CollectionPrefetcher.java
  
  Index: CollectionPrefetcher.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/broker/accesslayer/CollectionPrefetcher.java,v
  retrieving revision 1.20
  retrieving revision 1.21
  diff -u -r1.20 -r1.21
  --- CollectionPrefetcher.java	14 Dec 2003 11:03:15 -0000	1.20
  +++ CollectionPrefetcher.java	22 Dec 2003 15:34:54 -0000	1.21
  @@ -60,6 +60,7 @@
   import java.util.HashMap;
   import java.util.HashSet;
   import java.util.Iterator;
  +import java.util.List;
   
   import org.apache.ojb.broker.Identity;
   import org.apache.ojb.broker.ManageableCollection;
  @@ -163,43 +164,40 @@
       protected void associateBatched(Collection owners, Collection children)
       {
           CollectionDescriptor cds = getCollectionDescriptor();
  -        ClassDescriptor cld;
           PersistentField field = cds.getPersistentField();
           PersistenceBroker pb = getBroker();
           Class ownerTopLevelClass = pb.getTopLevelClass(getOwnerClassDescriptor().getClassOfObject());
       
           Class collectionClass = cds.getCollectionClass(); // this collection type will
be used:
  -        Object owner, relatedObject;
  -        Object fkValues[];
  -        Identity id;
           HashMap ownerIdsToLists = new HashMap();
  -        ArrayList list;
  -        Object result;
   
  +        // initialize the owner list map
  +        for (Iterator it = owners.iterator(); it.hasNext();)
  +        {
  +            Object owner = it.next();
  +            ownerIdsToLists.put(new Identity(owner,pb), new ArrayList());
  +        }
  +        
  +        // build the children lists for the owners
           for (Iterator it = children.iterator(); it.hasNext();)
           {
  -            relatedObject = it.next();
  +            Object child = it.next();
               // BRJ: use cld for real class, relatedObject could be Proxy
  -            cld = getDescriptorRepository().getDescriptorFor(ProxyHelper.getRealClass(relatedObject));
  -            fkValues = cds.getForeignKeyValues(relatedObject, cld);
  -            id = new Identity(null, ownerTopLevelClass, fkValues);
  -            list = (ArrayList) ownerIdsToLists.get(id);
  -            if (list == null)
  -            {
  -                list = new ArrayList();
  -                ownerIdsToLists.put(id, list);
  -            }
  -            list.add(relatedObject);
  +            ClassDescriptor cld = getDescriptorRepository().getDescriptorFor(ProxyHelper.getRealClass(child));
  +            
  +            Object[] fkValues = cds.getForeignKeyValues(child, cld);
  +            Identity ownerId = new Identity(null, ownerTopLevelClass, fkValues);
  +            List list = (List) ownerIdsToLists.get(ownerId);
  +            list.add(child);
           }
   
  +        // connect children list to owners  
           for (Iterator it = owners.iterator(); it.hasNext();)
           {
  -            owner = it.next();
  -            id = new Identity(owner, pb);
  -            list = (ArrayList) ownerIdsToLists.get(id);
  -            if (list == null)
  -            {
  -                list = new ArrayList();
  -            }
  +            Object result;
  +            Object owner = it.next();
  +            Identity ownerId = new Identity(owner, pb);
  +            List list = (List) ownerIdsToLists.get(ownerId);
  +                       
               if ((collectionClass == null) && field.getType().isArray())
               {
                   int length = list.size();
  @@ -212,23 +210,7 @@
               }
               else
               {
  -                ManageableCollection col;
  -
  -                if (collectionClass == null)
  -                {
  -                    col = new RemovalAwareCollection();
  -                }
  -                else
  -                {
  -                    try
  -                    {
  -                        col = (ManageableCollection) collectionClass.newInstance();
  -                    }
  -                    catch (Exception e)
  -                    {
  -                        throw new OJBRuntimeException("Can't create new Collection for
owner", e);
  -                    }
  -                }
  +                ManageableCollection col = createCollection(collectionClass);
                   for (Iterator it2 = list.iterator(); it2.hasNext();)
                   {
                       col.ojbAdd(it2.next());
  @@ -237,7 +219,6 @@
               }
   
               Object value = field.get(owner);
  -
               if ((value instanceof CollectionProxy) && (result instanceof Collection))
               {
                   ((CollectionProxy) value).setData((Collection) result);
  @@ -247,6 +228,34 @@
                   field.set(owner, result);
               }
           }
  +    }
  +
  +    /**
  +     * Create a Collection of class collectionClass
  +     * if collectionClass is null return a RemovalAwareCollection
  +     * @param collectionClass
  +     * @return
  +     */
  +    protected ManageableCollection createCollection(Class collectionClass)
  +    {
  +        ManageableCollection col;
  +
  +        if (collectionClass == null)
  +        {
  +            col = new RemovalAwareCollection();
  +        }
  +        else
  +        {
  +            try
  +            {
  +                col = (ManageableCollection) collectionClass.newInstance();
  +            }
  +            catch (Exception e)
  +            {
  +                throw new OJBRuntimeException("Can't create new Collection for owner",
e);
  +            }
  +        }
  +        return col;
       }
   
       protected CollectionDescriptor getCollectionDescriptor()
  
  
  
  1.1                  db-ojb/src/java/org/apache/ojb/broker/accesslayer/MtoNCollectionPrefetcher.java
  
  Index: MtoNCollectionPrefetcher.java
  ===================================================================
  
  package org.apache.ojb.broker.accesslayer;
  
  /* ====================================================================
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2001 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgment:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "Apache" and "Apache Software Foundation" and
   *    "Apache ObjectRelationalBridge" must not be used to endorse or promote products
   *    derived from this software without prior written permission. For
   *    written permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    "Apache ObjectRelationalBridge", nor may "Apache" appear in their name, without
   *    prior written permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  import java.lang.reflect.Array;
  import java.util.ArrayList;
  import java.util.Collection;
  import java.util.HashMap;
  import java.util.HashSet;
  import java.util.Iterator;
  import java.util.List;
  
  import org.apache.ojb.broker.Identity;
  import org.apache.ojb.broker.ManageableCollection;
  import org.apache.ojb.broker.PersistenceBroker;
  import org.apache.ojb.broker.metadata.ClassDescriptor;
  import org.apache.ojb.broker.metadata.CollectionDescriptor;
  import org.apache.ojb.broker.metadata.FieldDescriptor;
  import org.apache.ojb.broker.metadata.ObjectReferenceDescriptor;
  import org.apache.ojb.broker.metadata.fieldaccess.PersistentField;
  import org.apache.ojb.broker.query.Criteria;
  import org.apache.ojb.broker.query.Query;
  import org.apache.ojb.broker.query.QueryByMtoNCriteria;
  import org.apache.ojb.broker.query.ReportQueryByMtoNCriteria;
  import org.apache.ojb.broker.util.BrokerHelper;
  
  /**
   * Relationship Prefetcher for MtoN-Collections.
   * 
   * @author <a href="mailto:jbraeuchi@gmx.ch">Jakob Braeuchi</a>
   * @version $Id: MtoNCollectionPrefetcher.java,v 1.1 2003/12/22 15:34:54 brj Exp $
   */
  public class MtoNCollectionPrefetcher extends CollectionPrefetcher
  {
  
      /**
       * @param aBroker
       * @param anOrd
       */
      public MtoNCollectionPrefetcher(PersistenceBroker aBroker, ObjectReferenceDescriptor
anOrd)
      {
          super(aBroker, anOrd);
      }
  
      /**
       * @see org.apache.ojb.broker.accesslayer.RelationshipPrefetcher#prefetchRelationship(Collection)
       */
      public void prefetchRelationship(Collection owners)
      {
          Query queries[];
          Query mToNQueries[];
          Collection children = new ArrayList();
          Collection mToNImplementors = new ArrayList();
          Class collectionClass = getCollectionClass();
  
          queries = buildPrefetchQueries(owners, children);
          mToNQueries = buildMtoNImplementorQueries(owners, children);
  
          for (int i = 0; i < queries.length; i++)
          {
              Collection newChildren;
  
              if (collectionClass != null)
              {
                  newChildren = (Collection) getBroker().getCollectionByQuery(collectionClass,
queries[i]);
              }
              else
              {
                  newChildren = getBroker().getCollectionByQuery(queries[i]);
              }
              children.addAll(newChildren);
              
              Iterator iter = getBroker().getReportQueryIteratorByQuery(mToNQueries[i]);
              while (iter.hasNext())
              {
                  mToNImplementors.add(iter.next());
              }
          }
          associateBatched(owners, children, mToNImplementors);
      }
      
      /**
       * Build the prefetch query for a M-N relationship, The query looks like the following
sample :
       * <br>
       * <pre>
       *       crit = new Criteria(); 
       *       crit.addIn("PERSON_PROJECT.PROJECT_ID", ids); 
       *       crit.addEqualToField("id","PERSON_PROJECT.PERSON_ID"); 
       *       qry = new QueryByMtoNCriteria(Person.class, "PERSON_PROJECT", crit, true);
       * </pre>
       * 
       * @param ids Collection containing all identities of objects of the M side
       * @return
       */
      protected Query buildPrefetchQuery(Collection ids)
      {
          CollectionDescriptor cds = getCollectionDescriptor();
          String[] indFkCols = cds.getFksToThisClass();
          String[] indItemFkCols = cds.getFksToItemClass();
          FieldDescriptor[] itemPkFields = getItemClassDescriptor().getPkFields();
      
          Criteria crit = buildPrefetchCriteria(ids, indFkCols, indItemFkCols, itemPkFields);
            
          return new QueryByMtoNCriteria(cds.getItemClass(), cds.getIndirectionTable(), crit,
true);
      }
  
      
      protected Query buildMtoNImplementorQuery(Collection ids)
      {
          CollectionDescriptor cds = getCollectionDescriptor();
          String[] indFkCols = cds.getFksToThisClass();
          String[] indItemFkCols = cds.getFksToItemClass();
          FieldDescriptor[] itemPkFields = getItemClassDescriptor().getPkFields();
          String[] cols = new String[indFkCols.length + indItemFkCols.length]; 
          
          System.arraycopy(indFkCols,0,cols,0,indFkCols.length);
          System.arraycopy(indItemFkCols,0,cols,indFkCols.length,indItemFkCols.length);
          
          Criteria crit = buildPrefetchCriteria(ids, indFkCols, indItemFkCols, itemPkFields);
          
          ReportQueryByMtoNCriteria q = new ReportQueryByMtoNCriteria(getItemClassDescriptor().getClassOfObject(),
cols, crit, true);
          q.setIndirectionTable(cds.getIndirectionTable());
          
          return q;
      }
  
      /**
       * Build the multiple queries for one relationship because of limitation of IN(...)
       * 
       * @param owners Collection containing all objects of the ONE side
       */
      protected Query[] buildMtoNImplementorQueries(Collection owners, Collection children)
      {
          ClassDescriptor cld = getOwnerClassDescriptor();
          Class topLevelClass = getBroker().getTopLevelClass(cld.getClassOfObject());
          BrokerHelper helper = getBroker().serviceBrokerHelper();
          Collection queries = new ArrayList();
          Collection idsSubset = new HashSet();
          Object[] fkValues;
          Object owner;
          Identity id;
  
          Iterator iter = owners.iterator();
          while (iter.hasNext())
          {
              owner = iter.next();
              fkValues = helper.extractValueArray(helper.getKeyValues(cld, owner));
              id = new Identity(null, topLevelClass, fkValues);
              idsSubset.add(id);
              if (idsSubset.size() == pkLimit)
              {
                  queries.add(buildMtoNImplementorQuery(idsSubset));
                  idsSubset.clear();
              }
          }
  
          if (idsSubset.size() > 0)
          {
              queries.add(buildMtoNImplementorQuery(idsSubset));
          }
  
          return (Query[]) queries.toArray(new Query[queries.size()]);
      }    
      /**
       * Build the prefetch criteria
       * 
       * @param ids Collection of identities of M side
       * @param fkCols indirection table fks to this class
       * @param itemFkCols indirection table fks to item class
       * @param itemPkFields
       * @return
       */
      private Criteria buildPrefetchCriteria(Collection ids, String[] fkCols, String[] itemFkCols,
FieldDescriptor itemPkFields[])
      {
          if (fkCols.length == 1)
          {
              return buildPrefetchCriteriaSingleKey(ids, fkCols[0], itemFkCols[0], itemPkFields[0]);
               
          }
          else
          {
              return buildPrefetchCriteriaMultipleKeys(ids, fkCols, itemFkCols, itemPkFields);
          }
      
      }
  
      /**
       * Build the prefetch criteria
       * 
       * @param ids Collection of identities of M side
       * @param fkCol indirection table fks to this class
       * @param itemFkCol indirection table fks to item class
       * @param itemPkField
       * @return
       */
      private Criteria buildPrefetchCriteriaSingleKey(Collection ids, String fkCol, String
itemFkCol, FieldDescriptor itemPkField)
      {
          Criteria crit = new Criteria();
          ArrayList values = new ArrayList();
          Iterator iter = ids.iterator();
          Identity id;
      
          String fkColumn = getCollectionDescriptor().getIndirectionTable() + "." + fkCol;
          String itemFkColumn = getCollectionDescriptor().getIndirectionTable() + "." + itemFkCol;
      
          while (iter.hasNext())
          {
              id = (Identity) iter.next();
              values.add(id.getPrimaryKeyValues()[0]);
          }
      
          switch (values.size())
          {
              case 0 :
                  break;
              case 1 :
                  crit.addEqualTo(fkColumn, values.get(0));
                  break;
              default :
                  // create IN (...) for the single key field
                  crit.addIn(fkColumn, values);
                  break;
          }
      
          crit.addEqualToField(itemPkField.getAttributeName(), itemFkColumn);
  
          return crit;
      }
  
      /**
       * Build the prefetch criteria
       * 
       * @param ids Collection of identities of M side
       * @param fkCols indirection table fks to this class
       * @param itemFkCols indirection table fks to item class
       * @param itemPkFields
       * @return
       */
      private Criteria buildPrefetchCriteriaMultipleKeys(Collection ids, String fkCols[],
String itemFkCols[], FieldDescriptor itemPkFields[])
      {
          Criteria crit = new Criteria();
          Iterator iter = ids.iterator();
      
          while (iter.hasNext())
          {
              Criteria c = new Criteria();
              Identity id = (Identity) iter.next();
              Object[] val = id.getPrimaryKeyValues();
      
              for (int i = 0; i < val.length; i++)
              {
                  String fkColumn = getCollectionDescriptor().getIndirectionTable() + "."
+ fkCols[i];
                  String itemFkColumn = getCollectionDescriptor().getIndirectionTable() +
"." + itemFkCols[i];
      
                  if (val[i] == null)
                  {
                      c.addIsNull(fkColumn);
                  }
                  else
                  {
                      c.addEqualTo(fkColumn, val[i]);
                  }
      
                  crit.addEqualToField(itemPkFields[i].getAttributeName(), itemFkColumn);
              }
              crit.addOrCriteria(c);
          }
      
          return crit;
      }
      
      /**
       * associate the batched Children with their owner object loop over children
       */   
      protected void associateBatched(Collection owners, Collection children, Collection mToNImplementors)
      {
          CollectionDescriptor cds = getCollectionDescriptor();
          PersistentField field = cds.getPersistentField();
          PersistenceBroker pb = getBroker();
          Class ownerTopLevelClass = pb.getTopLevelClass(getOwnerClassDescriptor().getClassOfObject());
       
          Class childTopLevelClass = pb.getTopLevelClass(getItemClassDescriptor().getClassOfObject());
       
          Class collectionClass = cds.getCollectionClass(); // this collection type will be
used:
          HashMap childMap = new HashMap();
          HashMap ownerIdsToLists = new HashMap();
          
          // initialize the owner list map
          for (Iterator it = owners.iterator(); it.hasNext();)
          {
              Object owner = it.next();
              ownerIdsToLists.put(new Identity(owner,pb), new ArrayList());
          }
          
          // build the children map
          for (Iterator it = children.iterator(); it.hasNext();)
          {
              Object child = it.next();
              childMap.put(new Identity(child,pb), child);
          }
        
          int ownerPkLen = getOwnerClassDescriptor().getPkFields().length;
          int childPkLen = getItemClassDescriptor().getPkFields().length;
          Object[] ownerPk = new Object[ownerPkLen];
          Object[] childPk = new Object[childPkLen];
  
          // build list of children based on m:n implementors 
          for (Iterator it = mToNImplementors.iterator(); it.hasNext();)
          {
              Object[] mToN = (Object[])it.next();
              System.arraycopy(mToN,0,ownerPk,0,ownerPkLen);
              System.arraycopy(mToN,ownerPkLen,childPk,0,childPkLen);
              
              Identity ownerId = new Identity(null, ownerTopLevelClass, ownerPk);
              Identity childId = new Identity(null, childTopLevelClass, childPk);
              
              Collection list = (Collection) ownerIdsToLists.get(ownerId);     
              Object child = childMap.get(childId);
              list.add(child);
          }    
            
          // connect children list to owners  
          for (Iterator it = owners.iterator(); it.hasNext();)
          {
              Object result;
              Object owner = it.next();
              Identity ownerId = new Identity(owner,pb);
              
              List list = (List)ownerIdsToLists.get(ownerId);
              
              if ((collectionClass == null) && field.getType().isArray())
              {
                  int length = list.size();
                  Class itemtype = field.getType().getComponentType();
                  
                  result = Array.newInstance(itemtype, length);
                  
                  for (int j = 0; j < length; j++)
                  {
                      Array.set(result, j, list.get(j));
                  }
              }
              else
              {
                  ManageableCollection col = createCollection(collectionClass);
                  
                  for (Iterator it2 = list.iterator(); it2.hasNext();)
                  {
                      col.ojbAdd(it2.next());
                  }
                  result = col;
              }   
              
              Object value = field.get(owner);
              if ((value instanceof CollectionProxy) && (result instanceof Collection))
              {
                  ((CollectionProxy) value).setData((Collection) result);
              }
              else
              {
                  field.set(owner, result);
              }
          }
              
              
      }
      
  }
  
  
  

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