View Javadoc

1   package org.apache.ojb.broker.accesslayer;
2   
3   /* Copyright 2003-2005 The Apache Software Foundation
4    *
5    * Licensed under the Apache License, Version 2.0 (the "License");
6    * you may not use this file except in compliance with the License.
7    * You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  import java.util.ArrayList;
19  import java.util.Collection;
20  import java.util.Iterator;
21  
22  import org.apache.ojb.broker.Identity;
23  import org.apache.ojb.broker.PersistenceBrokerFactory;
24  import org.apache.ojb.broker.core.PersistenceBrokerConfiguration;
25  import org.apache.ojb.broker.core.PersistenceBrokerImpl;
26  import org.apache.ojb.broker.metadata.ClassDescriptor;
27  import org.apache.ojb.broker.metadata.DescriptorRepository;
28  import org.apache.ojb.broker.metadata.FieldDescriptor;
29  import org.apache.ojb.broker.query.Criteria;
30  import org.apache.ojb.broker.query.Query;
31  import org.apache.ojb.broker.query.QueryByCriteria;
32  import org.apache.ojb.broker.query.QueryFactory;
33  import org.apache.ojb.broker.util.configuration.ConfigurationException;
34  import org.apache.ojb.broker.util.logging.Logger;
35  import org.apache.ojb.broker.util.logging.LoggerFactory;
36  
37  /**
38   * Abstract Prefetcher.
39   * @author <a href="mailto:olegnitz@apache.org">Oleg Nitz</a>
40   * @version $Id: BasePrefetcher.java,v 1.1 2007-08-24 22:17:30 ewestfal Exp $
41   */
42  public abstract class BasePrefetcher implements RelationshipPrefetcher
43  {
44      /** The numer of columns to query for. */
45      protected static final int IN_LIMIT = getPrefetchInLimit();
46  
47      private Logger logger;
48      private PersistenceBrokerImpl broker;
49      /** Class descriptor for the item type. */ 
50      protected ClassDescriptor itemClassDesc;
51      /** Maximum number of pk's in one query. */ 
52      protected final int pkLimit;
53  
54      /**
55       * Returns the number of column to query for, from the configuration.
56       * 
57       * @return The prefetch limit
58       */
59      private static int getPrefetchInLimit()
60      {
61          try
62          {
63              PersistenceBrokerConfiguration config = (PersistenceBrokerConfiguration) PersistenceBrokerFactory.getConfigurator().getConfigurationFor(null);
64  
65              return config.getSqlInLimit();
66          }
67          catch (ConfigurationException e)
68          {
69              return 200;
70          }
71      }
72  
73      /**
74       * Constructor for BasePrefetcher.
75       */
76      public BasePrefetcher(PersistenceBrokerImpl aBroker, Class anItemClass)
77      {
78          super();
79          broker = aBroker;
80          itemClassDesc = aBroker.getDescriptorRepository().getDescriptorFor(anItemClass);
81          logger = LoggerFactory.getLogger(this.getClass());
82          pkLimit = getPrefetchInLimit() / getItemClassDescriptor().getPkFields().length;
83      }
84  
85      /**
86       * The limit of objects loaded by one SQL query
87       */
88      public int getLimit()
89      {
90          return pkLimit;
91      }
92  
93      /**
94       * associate the batched Children with their owner object <br>
95       */
96      protected abstract void associateBatched(Collection owners, Collection children);
97  
98      /**
99      * @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 }