001    package org.apache.ojb.broker.accesslayer;
002    
003    /* Copyright 2003-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.Iterator;
021    
022    import org.apache.ojb.broker.Identity;
023    import org.apache.ojb.broker.PersistenceBrokerFactory;
024    import org.apache.ojb.broker.core.PersistenceBrokerConfiguration;
025    import org.apache.ojb.broker.core.PersistenceBrokerImpl;
026    import org.apache.ojb.broker.metadata.ClassDescriptor;
027    import org.apache.ojb.broker.metadata.DescriptorRepository;
028    import org.apache.ojb.broker.metadata.FieldDescriptor;
029    import org.apache.ojb.broker.query.Criteria;
030    import org.apache.ojb.broker.query.Query;
031    import org.apache.ojb.broker.query.QueryByCriteria;
032    import org.apache.ojb.broker.query.QueryFactory;
033    import org.apache.ojb.broker.util.configuration.ConfigurationException;
034    import org.apache.ojb.broker.util.logging.Logger;
035    import org.apache.ojb.broker.util.logging.LoggerFactory;
036    
037    /**
038     * Abstract Prefetcher.
039     * @author <a href="mailto:olegnitz@apache.org">Oleg Nitz</a>
040     * @version $Id: BasePrefetcher.java,v 1.1 2007-08-24 22:17:30 ewestfal Exp $
041     */
042    public abstract class BasePrefetcher implements RelationshipPrefetcher
043    {
044        /** The numer of columns to query for. */
045        protected static final int IN_LIMIT = getPrefetchInLimit();
046    
047        private Logger logger;
048        private PersistenceBrokerImpl broker;
049        /** Class descriptor for the item type. */ 
050        protected ClassDescriptor itemClassDesc;
051        /** Maximum number of pk's in one query. */ 
052        protected final int pkLimit;
053    
054        /**
055         * Returns the number of column to query for, from the configuration.
056         * 
057         * @return The prefetch limit
058         */
059        private static int getPrefetchInLimit()
060        {
061            try
062            {
063                PersistenceBrokerConfiguration config = (PersistenceBrokerConfiguration) PersistenceBrokerFactory.getConfigurator().getConfigurationFor(null);
064    
065                return config.getSqlInLimit();
066            }
067            catch (ConfigurationException e)
068            {
069                return 200;
070            }
071        }
072    
073        /**
074         * Constructor for BasePrefetcher.
075         */
076        public BasePrefetcher(PersistenceBrokerImpl aBroker, Class anItemClass)
077        {
078            super();
079            broker = aBroker;
080            itemClassDesc = aBroker.getDescriptorRepository().getDescriptorFor(anItemClass);
081            logger = LoggerFactory.getLogger(this.getClass());
082            pkLimit = getPrefetchInLimit() / getItemClassDescriptor().getPkFields().length;
083        }
084    
085        /**
086         * The limit of objects loaded by one SQL query
087         */
088        public int getLimit()
089        {
090            return pkLimit;
091        }
092    
093        /**
094         * associate the batched Children with their owner object <br>
095         */
096        protected abstract void associateBatched(Collection owners, Collection children);
097    
098        /**
099        * @see org.apache.ojb.broker.accesslayer.RelationshipPrefetcher#prefetchRelationship(Collection)
100        */
101        public void prefetchRelationship(Collection owners)
102        {
103            Query queries[];
104            Collection children = new ArrayList();
105    
106            queries = buildPrefetchQueries(owners, children);
107    
108            for (int i = 0; i < queries.length; i++)
109            {
110                Iterator iter = getBroker().getIteratorByQuery(queries[i]);
111                while (iter.hasNext())
112                {
113                    children.add(iter.next());
114                }
115            }
116    
117            // BRJ: performRetrieval of childrens references BEFORE associating with owners
118            // TODO: this is a quick fix ! 
119            getBroker().getReferenceBroker().performRetrievalTasks();
120            
121            associateBatched(owners, children);
122        }
123    
124        
125        protected QueryByCriteria buildPrefetchQuery(Collection ids, FieldDescriptor[] fields)
126        {
127            return buildPrefetchQuery(getItemClassDescriptor().getClassOfObject(), ids, fields);
128        }
129    
130        
131        /**
132         * 
133         * @param ids collection of identities
134         * @param fields
135         * @return
136         */
137        protected Criteria buildPrefetchCriteria(Collection ids, FieldDescriptor[] fields)
138        {
139            if (fields.length == 1)
140            {
141                return buildPrefetchCriteriaSingleKey(ids, fields[0]);
142            }
143            else
144            {
145                return buildPrefetchCriteriaMultipleKeys(ids, fields);
146            }
147            
148        }
149       
150        /**
151         * 
152         * @param clazz
153         * @param ids collection of identities
154         * @param fields
155         * @return
156         */
157        protected QueryByCriteria buildPrefetchQuery(Class clazz, Collection ids, FieldDescriptor[] fields)
158        {
159            return QueryFactory.newQuery(clazz, buildPrefetchCriteria(ids, fields));
160        }
161    
162        /**
163         * Build the Criteria using IN(...) for single keys
164         * @param ids collection of identities
165         * @param field
166         * @return Criteria
167         */
168        private Criteria buildPrefetchCriteriaSingleKey(Collection ids, FieldDescriptor field)
169        {
170            Criteria crit = new Criteria();
171            ArrayList values = new ArrayList(ids.size());
172            Iterator iter = ids.iterator();
173            Identity id;
174    
175            while (iter.hasNext())
176            {
177                id = (Identity) iter.next();
178                values.add(id.getPrimaryKeyValues()[0]);
179            }
180    
181            switch (values.size())
182            {
183                case 0:
184                    break;
185                case 1:
186                    crit.addEqualTo(field.getAttributeName(), values.get(0));
187                    break;
188                default:
189                    // create IN (...) for the single key field
190                    crit.addIn(field.getAttributeName(), values);
191                    break;
192            }
193    
194            return crit;
195        }
196    
197        /**
198         * Build the Criteria using multiple ORs
199         * @param ids collection of identities
200         * @param fields
201         * @return Criteria
202         */
203        private Criteria buildPrefetchCriteriaMultipleKeys(Collection ids, FieldDescriptor fields[])
204        {
205            Criteria crit = new Criteria();
206            Iterator iter = ids.iterator();
207            Object[] val;
208            Identity id;
209    
210            while (iter.hasNext())
211            {
212                Criteria c = new Criteria();
213                id = (Identity) iter.next();
214                val = id.getPrimaryKeyValues();
215                for (int i = 0; i < val.length; i++)
216                {
217                    if (val[i] == null)
218                    {
219                        c.addIsNull(fields[i].getAttributeName());
220                    }
221                    else
222                    {
223                        c.addEqualTo(fields[i].getAttributeName(), val[i]);
224                    }
225                }
226                crit.addOrCriteria(c);
227            }
228    
229            return crit;
230        }
231    
232        /**
233         * Return the DescriptorRepository
234         */
235        protected DescriptorRepository getDescriptorRepository()
236        {
237            return getBroker().getDescriptorRepository();
238        }
239    
240        /**
241         * Returns the ClassDescriptor of the item Class
242         * @return ClassDescriptor
243         */
244        public ClassDescriptor getItemClassDescriptor()
245        {
246            return itemClassDesc;
247        }
248    
249        protected abstract Query[] buildPrefetchQueries(Collection owners, Collection children);
250    
251        /**
252         * Returns the broker.
253         * @return PersistenceBrokerImpl
254         */
255        protected PersistenceBrokerImpl getBroker()
256        {
257            return broker;
258        }
259    
260        /**
261         * Returns the logger.
262         * @return Logger
263         */
264        protected Logger getLogger()
265        {
266            return logger;
267        }
268    }