001    package org.apache.ojb.broker.accesslayer;
002    
003    /* Copyright 2002-2005 The Apache Software Foundation
004     *
005     * Licensed under the Apache License, Version 2.0 (the "License");
006     * you may not use this file except in compliance with the License.
007     * You may obtain a copy of the License at
008     *
009     *     http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    
018    import java.util.ArrayList;
019    import java.util.Collection;
020    import java.util.HashMap;
021    import java.util.HashSet;
022    import java.util.Iterator;
023    
024    import org.apache.ojb.broker.Identity;
025    import org.apache.ojb.broker.PersistenceBroker;
026    import org.apache.ojb.broker.cache.ObjectCache;
027    import org.apache.ojb.broker.core.PersistenceBrokerImpl;
028    import org.apache.ojb.broker.metadata.ClassDescriptor;
029    import org.apache.ojb.broker.metadata.ObjectReferenceDescriptor;
030    import org.apache.ojb.broker.metadata.fieldaccess.PersistentField;
031    import org.apache.ojb.broker.query.Query;
032    
033    /**
034     * Relationship Prefetcher for References.
035     *
036     * @author <a href="mailto:jbraeuchi@hotmail.com">Jakob Braeuchi</a>
037     * @version $Id: ReferencePrefetcher.java,v 1.1 2007-08-24 22:17:30 ewestfal Exp $
038     */
039    public class ReferencePrefetcher extends RelationshipPrefetcherImpl
040    {
041    
042        /**
043        * Constructor for ReferencePrefetcher.
044        * @param aBroker
045        * @param anOrd
046        */
047        public ReferencePrefetcher(PersistenceBrokerImpl aBroker, ObjectReferenceDescriptor anOrd)
048        {
049            super(aBroker, anOrd);
050        }
051    
052        /**
053         * Associate the batched Children with their owner object.
054         * Loop over owners
055         */
056        protected void associateBatched(Collection owners, Collection children)
057        {
058            ObjectReferenceDescriptor ord = getObjectReferenceDescriptor();
059            ClassDescriptor cld = getOwnerClassDescriptor();
060            Object owner;
061            Object relatedObject;
062            Object fkValues[];
063            Identity id;
064            PersistenceBroker pb = getBroker();
065            PersistentField field = ord.getPersistentField();
066            Class topLevelClass = pb.getTopLevelClass(ord.getItemClass());
067            HashMap childrenMap = new HashMap(children.size());
068    
069    
070            for (Iterator it = children.iterator(); it.hasNext(); )
071            {
072                relatedObject = it.next();
073                childrenMap.put(pb.serviceIdentity().buildIdentity(relatedObject), relatedObject);
074            }
075    
076            for (Iterator it = owners.iterator(); it.hasNext(); )
077            {
078                owner = it.next();
079                fkValues = ord.getForeignKeyValues(owner,cld);
080                if (isNull(fkValues))
081                {
082                    field.set(owner, null);
083                    continue;
084                }
085                id = pb.serviceIdentity().buildIdentity(null, topLevelClass, fkValues);
086                relatedObject = childrenMap.get(id);
087                field.set(owner, relatedObject);
088            }
089        }
090    
091        private boolean isNull(Object[] arr)
092        {
093            for (int i = 0; i < arr.length; i++)
094            {
095                if (arr[i] != null)
096                {
097                    return false;
098                }
099            }
100            return true;
101        }
102        
103        /**
104         * Build the multiple queries for one relationship because of limitation of IN(...)
105         * @param owners Collection containing all objects of the ONE side
106         * @param children Collection where related objects found in the cache should be added.
107         */
108        protected Query[] buildPrefetchQueries(Collection owners, Collection children)
109        {
110            ClassDescriptor cld = getOwnerClassDescriptor();
111            ObjectReferenceDescriptor ord = getObjectReferenceDescriptor();
112            Collection queries = new ArrayList(owners.size());
113            Collection idsSubset = new HashSet(owners.size());
114            Iterator iter = owners.iterator();
115            Class topLevelClass = getBroker().getTopLevelClass(ord.getItemClass());
116            Object[] fkValues;
117            Object owner;
118            Identity id;
119            PersistenceBroker pb = getBroker();
120            ObjectCache cache = pb.serviceObjectCache();
121    
122            while (iter.hasNext())
123            {
124                owner = iter.next();
125                fkValues = ord.getForeignKeyValues(owner,cld);
126                if (isNull(fkValues))
127                {
128                    continue;
129                }
130                id = pb.serviceIdentity().buildIdentity(null, topLevelClass, fkValues);
131                if (cache.lookup(id) != null)
132                {
133                    children.add(pb.getObjectByIdentity(id));
134                    continue;
135                }
136                idsSubset.add(id);
137                if (idsSubset.size() == pkLimit)
138                {
139                    queries.add(buildPrefetchQuery(idsSubset));
140                    idsSubset.clear();
141                }
142            }
143    
144            if (idsSubset.size() > 0)
145            {
146                queries.add(buildPrefetchQuery(idsSubset));
147            }
148    
149            return (Query[]) queries.toArray(new Query[queries.size()]);
150        }
151    
152        /**
153         * @see org.apache.ojb.broker.accesslayer.RelationshipPrefetcherImpl#buildPrefetchCriteria(java.util.Collection, org.apache.ojb.broker.metadata.FieldDescriptor[])
154         */
155        protected Query buildPrefetchQuery(Collection ids)
156        {
157            return buildPrefetchQuery(ids, getItemClassDescriptor().getPkFields());
158        }
159    }