KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > jorm > mapper > rdb > metainfo > RdbInheritanceQuery


1 /**
2  * Speedo: an implementation of JDO compliant personality on top of JORM generic
3  * I/O sub-system.
4  * Copyright (C) 2001-2004 France Telecom R&D
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  *
20  *
21  *
22  * Contact: speedo@objectweb.org
23  *
24  */

25
26 package org.objectweb.jorm.mapper.rdb.metainfo;
27
28 import java.util.ArrayList JavaDoc;
29 import java.util.Collection JavaDoc;
30 import java.util.Collections JavaDoc;
31 import java.util.HashSet JavaDoc;
32 import java.util.Iterator JavaDoc;
33
34 import org.objectweb.jorm.api.PClassMapping;
35 import org.objectweb.jorm.api.PException;
36 import org.objectweb.jorm.api.PMapper;
37 import org.objectweb.jorm.mapper.rdb.adapter.api.JoinedTable;
38 import org.objectweb.jorm.mapper.rdb.adapter.api.RdbAdapter;
39 import org.objectweb.jorm.mapper.rdb.lib.PMapperRdb;
40 import org.objectweb.jorm.mapper.rdb.lib.RdbExtentGenInfos;
41 import org.objectweb.jorm.mapper.rdb.lib.RdbExtentMappingInfos;
42 import org.objectweb.jorm.metainfo.api.Class;
43 import org.objectweb.jorm.metainfo.api.MetaObject;
44 import org.objectweb.jorm.metainfo.api.PrimitiveElement;
45 import org.objectweb.jorm.metainfo.api.PrimitiveElementMapping;
46 import org.objectweb.jorm.metainfo.lib.BasicMetaObject;
47
48 /**
49  * This class stores two queries in String format:
50  * a query with prefetch
51  * a query without prefetch
52  * These queries retrieve the Extent of a class in case of inheritance.
53  * The list of fields to select is also stored as a collection of String.
54  * @author Y.Bersihand
55  */

56 public class RdbInheritanceQuery extends BasicMetaObject {
57
58     //index for the pk fields: shared by all the RdbInheritanceQuery instances
59
private static int pkIndex = 0;
60     
61     public static final String JavaDoc PK = "pk";
62     
63     private RdbClassMapping rdbClassMapping;
64     //the query with prefetch
65
private String JavaDoc queryPrefetch;
66     //the query with the PK only
67
private String JavaDoc queryPKOnly;
68     //the query with the PK + the fields of the class and its super classes
69
private String JavaDoc queryPKAndFields;
70     //the list of fields to select
71
private Collection JavaDoc fieldsPrefetch;
72     private Collection JavaDoc fieldsPKOnly;
73     private Collection JavaDoc fieldsPKAndFields;
74     //the list if class associated to the fields in the fieldsPrefetch list
75
private Collection JavaDoc prefetchClasses;
76     
77     public RdbInheritanceQuery(MetaObject parent) {
78         super(parent);
79         rdbClassMapping = (RdbClassMapping) parent;
80         queryPrefetch = "";
81         queryPKOnly = "";
82         queryPKAndFields = "";
83         fieldsPrefetch = new ArrayList JavaDoc();
84         fieldsPKOnly = new ArrayList JavaDoc();
85         fieldsPKAndFields = new ArrayList JavaDoc();
86         prefetchClasses = new ArrayList JavaDoc();
87     }
88     
89     /**
90      * Returns the query of the extent as a String.
91      */

92     public String JavaDoc getExtentQuery(PMapper mapper, boolean prefetch, boolean pkOnly, String JavaDoc primaryKey, PClassMapping pcm){
93         if (prefetch) {
94             return getQueryPrefetch(mapper, primaryKey, pcm);
95         } else {
96             if (pkOnly) {
97                 return getQueryPKOnly(mapper, primaryKey, pcm);
98             } else {
99                 return getQueryPKAndFields(mapper, primaryKey, pcm);
100             }
101         }
102     }
103     
104     /**
105      * Returns the list of fields to be selected.
106      */

107     public Collection JavaDoc getExtentFieldsNames(boolean prefetch, boolean pkOnly){
108         if (prefetch) {
109             return fieldsPrefetch;
110         } else {
111             if (pkOnly) {
112                 return fieldsPKOnly;
113             } else {
114                 return fieldsPKAndFields;
115             }
116         }
117     }
118     
119     /**
120      * Adds all the fields of the collection c to the fieldsPKOnly list.
121      * If one the fields is already present in the list, it is not added a second time.
122      */

123     public void addFieldPKOnly(Collection JavaDoc c){
124         Iterator JavaDoc itC = c.iterator();
125         while (itC.hasNext()) {
126             String JavaDoc s = (String JavaDoc) itC.next();
127             if (!fieldsPKOnly.contains(s))
128                 fieldsPKOnly.add(s);
129         }
130     }
131     
132     /**
133      * Adds all the fields of the collection fields to the fieldsPrefetch list.
134      * If one the fields is already present in the list, it is not added a second time.
135      * In the same time, classes associated to these added fields are added to the prefetchClasses list.
136      */

137     public void addFieldPrefetch(Collection JavaDoc fields, Collection JavaDoc classes){
138         Iterator JavaDoc itF = fields.iterator();
139         Iterator JavaDoc itC = classes.iterator();
140         while (itF.hasNext()) {
141             String JavaDoc field = (String JavaDoc) itF.next();
142             String JavaDoc className = (String JavaDoc) itC.next();
143             if (!fieldsPrefetch.contains(field)) {
144                 //add the field
145
fieldsPrefetch.add(field);
146                 //add the class associated
147
prefetchClasses.add(className);
148             }
149         }
150     }
151     
152     /**
153      * Adds all the fields of the collection c to the fieldsPKAndFields list.
154      * If one the fields is already present in the list, it is not added a second time.
155      */

156     public void addFieldPKAndFields(Collection JavaDoc c){
157         Iterator JavaDoc itC = c.iterator();
158         while (itC.hasNext()) {
159             String JavaDoc s = (String JavaDoc) itC.next();
160             if (!fieldsPKAndFields.contains(s))
161                 fieldsPKAndFields.add(s);
162         }
163     }
164     
165     /**
166      *
167      * @param mapper
168      * @param primaryKey: a string representing the list of columns composing the primary key
169      * @return
170      */

171     private String JavaDoc getQueryPKOnly(PMapper mapper, String JavaDoc primaryKey, PClassMapping pcm){
172         if(queryPKOnly.equals("")){
173             //compute query
174
RdbExtentGenInfos extentGenInfos = new RdbExtentGenInfos(logger);
175             
176             RdbAdapter adapter;
177             try {
178                 adapter = ((PMapperRdb) mapper).getRdbAdapter();
179                 if (adapter == null) {
180                     throw new PException("No rdb adapter found on the mapper: " + mapper);
181                 }
182                 //Calculate the extent structure (a set of ExtentMappingInfos)
183
//each one corresponding to a select/from/where statement plus filters
184
Collection JavaDoc emis = extentGenInfos.getPolymorphicClassExtent((Class JavaDoc)rdbClassMapping.getLinkedMO(), rdbClassMapping.getProjectName(), rdbClassMapping.getMapperName(), false);
185                 //loop on extent mapping info objects
186
JoinedTable jt = null;
187                 JoinedTable.Join joinCond = null;
188                 Iterator JavaDoc itEmis = emis.iterator();
189                 while (itEmis.hasNext()) {
190                     RdbExtentMappingInfos emi = (RdbExtentMappingInfos) itEmis.next();
191                     //add the aliases to the list of fields (belonging to the primary key only) to select
192
addFieldPKOnly(emi.getColumnAliases(false, primaryKey, null));
193                     //create the JoinedTable object to pass to the getQuery
194
jt = new JoinedTable(emi.getMainTable().getName());
195                     HashSet JavaDoc hsJoins = emi.getJoins();
196                     Iterator JavaDoc itJoins = hsJoins.iterator();
197                     while (itJoins.hasNext()) {
198                         RdbJoin rdbJoin = (RdbJoin) itJoins.next();
199                         joinCond = jt.createChildren(rdbJoin.getExternalTable().getName());
200                         int pos = 0;
201                         Iterator JavaDoc itCName = rdbJoin.getPTJoinColumnNames().iterator();
202                         while (itCName.hasNext()) {
203                             String JavaDoc cName = (String JavaDoc) itCName.next();
204                             joinCond.addJoinColumn(cName, (String JavaDoc) rdbJoin.getETJoinColumnNames().get(pos));
205                             pos++;
206                         }
207                     }
208                     //select x1 as y1, x2 as y2, x3 as y3 from T
209
queryPKOnly += adapter.getQuery(emi.getSelectPKOnly(adapter, primaryKey), Collections.singletonList(jt), null, false, false);
210                     //where x1='filter'
211
queryPKOnly += emi.getWhereParameter(pcm);
212                     if(itEmis.hasNext())
213                         queryPKOnly += " UNION ";
214                 }
215                 //System.out.println("fields pk only=" + fieldsPKOnly.toString());
216
} catch (Exception JavaDoc e) {
217                 e.printStackTrace();
218             }
219         }
220         return queryPKOnly;
221     }
222     
223     /**
224      *
225      * @param mapper
226      * @param primaryKey: a string representing the list of columns composing the primary key
227      * @return
228      */

229     private String JavaDoc getQueryPKAndFields(PMapper mapper, String JavaDoc primaryKey, PClassMapping pcm){
230         if(queryPKAndFields.equals("")){
231             //compute query
232
RdbExtentGenInfos extentGenInfos = new RdbExtentGenInfos(logger);
233             
234             RdbAdapter adapter;
235             try {
236                 adapter = ((PMapperRdb) mapper).getRdbAdapter();
237                 if (adapter == null) {
238                     throw new PException("No rdb adapter found on the mapper: " + mapper);
239                 }
240                 //Calculate the extent structure (a set of ExtentMappingInfos)
241
//each one corresponding to a select/from/where statement plus filters
242
Collection JavaDoc emis = extentGenInfos.getPolymorphicClassExtent((Class JavaDoc)rdbClassMapping.getLinkedMO(), rdbClassMapping.getProjectName(), rdbClassMapping.getMapperName(), false);
243                 //loop on extent mapping info objects
244
JoinedTable jt = null;
245                 JoinedTable.Join joinCond = null;
246                 Iterator JavaDoc itEmis = emis.iterator();
247                 while (itEmis.hasNext()) {
248                     RdbExtentMappingInfos emi = (RdbExtentMappingInfos) itEmis.next();
249                     //add the aliases to the list of fields (belonging to the primary key only) to select
250
addFieldPKAndFields(emi.getColumnAliases(false, primaryKey, (Class JavaDoc)rdbClassMapping.getLinkedMO()));
251                     //create the JoinedTable object to pass to the getQuery
252
jt = new JoinedTable(emi.getMainTable().getName());
253                     HashSet JavaDoc hsJoins = emi.getJoins();
254                     Iterator JavaDoc itJoins = hsJoins.iterator();
255                     while (itJoins.hasNext()) {
256                         RdbJoin rdbJoin = (RdbJoin) itJoins.next();
257                         joinCond = jt.createChildren(rdbJoin.getExternalTable().getName());
258                         int pos = 0;
259                         Iterator JavaDoc itCName = rdbJoin.getPTJoinColumnNames().iterator();
260                         while(itCName.hasNext()){
261                             String JavaDoc cName = (String JavaDoc) itCName.next();
262                             joinCond.addJoinColumn(cName, (String JavaDoc) rdbJoin.getETJoinColumnNames().get(pos));
263                             pos++;
264                         }
265                     }
266                     //select x1 as y1, x2 as y2, x3 as y3 from T
267
queryPKAndFields += adapter.getQuery(emi.getSelectPKAndFields(adapter, (Class JavaDoc)rdbClassMapping.getLinkedMO()), Collections.singletonList(jt), null, false, false);
268                     //where x1='filter'
269
queryPKAndFields += emi.getWhereParameter(pcm);
270                     if (itEmis.hasNext())
271                         queryPKAndFields += " UNION ";
272                 }
273                 //System.out.println("fields pk and fields=" + fieldsPKAndFields.toString());
274
} catch (Exception JavaDoc e) {
275                 e.printStackTrace();
276             }
277         }
278         return queryPKAndFields;
279     }
280     
281     /**
282      *
283      * @param mapper
284      * @param primaryKey : a string representing the list of columns composing the primary key
285      * @return
286      */

287     private String JavaDoc getQueryPrefetch(PMapper mapper, String JavaDoc primaryKey, PClassMapping pcm){
288         if(queryPrefetch.equals("")){
289             //compute query
290
RdbExtentGenInfos extentGenInfos = new RdbExtentGenInfos(logger);
291             
292             RdbAdapter adapter;
293             try {
294                 adapter = ((PMapperRdb) mapper).getRdbAdapter();
295                 if (adapter == null) {
296                     throw new PException("No rdb adapter found on the mapper: " + mapper);
297                 }
298                 //Calculate the extent structure (a set of ExtentMappingInfos)
299
//each one corresponding to a select/from/where statement plus filters
300
Collection JavaDoc emis = extentGenInfos.getPolymorphicClassExtent((Class JavaDoc)rdbClassMapping.getLinkedMO(), rdbClassMapping.getProjectName(), rdbClassMapping.getMapperName(), true);
301                 //loop on extent mapping info objects
302
JoinedTable jt = null;
303                 JoinedTable.Join joinCond = null;
304                 Iterator JavaDoc itEmis = emis.iterator();
305                 while (itEmis.hasNext()) {
306                     RdbExtentMappingInfos emi = (RdbExtentMappingInfos) itEmis.next();
307                     //add the aliases to the list of fields to select and the classes associated to the list prefetchClasses
308
addFieldPrefetch(emi.getColumnAliases(true, "", null), emi.getColumnClasses());
309                     //add the pk aliases to the list of pk fields
310
addFieldPKOnly(emi.getColumnAliases(false, primaryKey, null));
311                     //create the JoinedTable object to pass to the getQuery
312
jt = new JoinedTable(emi.getMainTable().getName());
313                     HashSet JavaDoc hsJoins = emi.getJoins();
314                     Iterator JavaDoc itJoins = hsJoins.iterator();
315                     while (itJoins.hasNext()) {
316                         RdbJoin rdbJoin = (RdbJoin) itJoins.next();
317                         joinCond = jt.createChildren(rdbJoin.getExternalTable().getName());
318                         int pos = 0;
319                         Iterator JavaDoc itCName = rdbJoin.getPTJoinColumnNames().iterator();
320                         while (itCName.hasNext()) {
321                             String JavaDoc cName = (String JavaDoc) itCName.next();
322                             joinCond.addJoinColumn(cName, (String JavaDoc) rdbJoin.getETJoinColumnNames().get(pos));
323                             pos++;
324                         }
325                     }
326                     //select x1 as y1, x2 as y2, x3 as y3 from T
327
queryPrefetch += adapter.getQuery(
328                             emi.getSelectPrefetch(adapter, rdbClassMapping.getJormClass()),
329                             Collections.singletonList(jt), null, false, false);
330                     //add the PName fields in end the of the columns to select,
331
//that is to say between the last column and the FROM key word
332
int fromIndex = queryPrefetch.toUpperCase().indexOf(" FROM ");
333                     String JavaDoc tmpQuery = queryPrefetch.substring(0, fromIndex);
334                     tmpQuery += ", " + aliasPK(primaryKey, adapter) + " ";
335                     tmpQuery += queryPrefetch.substring(fromIndex);
336                     queryPrefetch = tmpQuery;
337                     //either WHERE x1='filter' or AND x1='filter'
338
queryPrefetch += emi.getWhereParameter(pcm);
339                     if (itEmis.hasNext())
340                         queryPrefetch += " UNION ";
341                 }
342                 //System.out.println("fields with prefetch=" + fieldsPrefetch.toString());
343
} catch (Exception JavaDoc e) {
344                 e.printStackTrace();
345             }
346             //compute the association table of field indexes for each subclass
347
setSubTreeFieldAssociationTable(mapper, pcm);
348         }
349         return queryPrefetch;
350     }
351     
352     /**
353      * For each subclass of the class linked to the pcm (including itself),
354      * compute the association table of field indexes
355      * and add the element [pcm -> table] in the map of the subclass PClassMapping
356      */

357     public void setSubTreeFieldAssociationTable(PMapper mapper, PClassMapping pcm){
358         try{
359             ArrayList JavaDoc pcms = new ArrayList JavaDoc();
360             pcms.add(pcm);
361             PClassMapping[] subPCMs = pcm.getSubPCMs();
362             //add children (if any)
363
if (subPCMs != null) {
364                 for (int indexPCM = 0; indexPCM < subPCMs.length; indexPCM++) {
365                     pcms.add(subPCMs[indexPCM]);
366                 }
367             }
368             String JavaDoc[] classes = new String JavaDoc[prefetchClasses.size()];
369             Iterator JavaDoc it = prefetchClasses.iterator();
370             int i = 0;
371             while (it.hasNext()) {
372                 classes[i++] = (String JavaDoc) it.next();
373             }
374             //get the mapper name
375
String JavaDoc mapperName = mapper.getMapperName();
376             if (mapperName.indexOf(".") != -1)
377                 mapperName = mapperName.substring(0, mapperName.indexOf("."));
378             // for each pcm
379
Iterator JavaDoc itPCM = pcms.iterator();
380             while (itPCM.hasNext()) {
381                 PClassMapping currentPCM = (PClassMapping) itPCM.next();
382                 ArrayList JavaDoc indexes = new ArrayList JavaDoc(0);
383                 //get the jorm class associated to the childPCM
384
RdbMapping rdbm = (RdbMapping) mapper.getMetaInfoManager().getClass(currentPCM.getClassName()).getClassProject(currentPCM.getProjectName()).getMapping(mapperName);
385                 RdbClassMapping rdbcm = (RdbClassMapping) rdbm.getClassMapping();
386                 Class JavaDoc cl = rdbcm.getJormClass();
387                 if (cl == null) {
388                     return;
389                 }
390                 //get all the superclasses
391
Collection JavaDoc superClasses = getSuperClasses(cl);
392                 
393                 //for each field in the select clause,
394
//decide wether it is part of the association table or not
395
for (int indexField = 0; indexField < prefetchClasses.size(); indexField++) {
396                     if (superClasses.contains(classes[indexField])) {
397                         //get the field name
398
String JavaDoc fieldName = (String JavaDoc) ((ArrayList JavaDoc)fieldsPrefetch).get(indexField);
399                         PrimitiveElementMapping pem = rdbcm.getPrimitiveElementMapping(fieldName, true);
400                         RdbJoin rdbJoin = ((RdbPrimitiveElementMapping) pem).getJoinByPrimitiveElement((PrimitiveElement)cl.getTypedElement(fieldName));
401                         //create the indexed pem: if no join, then put the void string
402
IndexedPEM indexedPem = new IndexedPEM(pem, (rdbJoin != null ? rdbJoin.getName():""), indexField);
403                         //and add it in the list
404
indexes.add(indexedPem);
405                     }
406                 }
407                 //sort the list of indexed pem: elements are sorted according to
408
//the name of sql column then according to the name of joins
409
Collections.sort(indexes);
410                 //fill in the int[] table using the sorted indexes list
411
int[] table = new int[indexes.size()];
412                 for (int j = 0; j < table.length; j++) {
413                     table[j] = ((IndexedPEM) indexes.get(j)).index;
414                 }
415                 // add the association [initial PCM -> table] to the sub pcm
416
currentPCM.addAssociation(pcm, table);
417             }
418         } catch(PException e){
419             e.printStackTrace();
420         }
421     }
422     
423     /**
424      * Returns the list of super class names including the name of the class cl
425      */

426     private Collection JavaDoc getSuperClasses(Class JavaDoc cl){
427         Collection JavaDoc superClasses = new ArrayList JavaDoc(1);
428         //add the current class name to the list of super classes
429
superClasses.add(cl.getFQName());
430         //get all the ancestors of the class cl
431
Iterator JavaDoc it = cl.getAllAncestors().iterator();
432         //and add the names of these classes to the superClasses list
433
while (it.hasNext()) {
434             Class JavaDoc currentClass = (Class JavaDoc) it.next();
435             superClasses.add(currentClass.getFQName());
436         }
437         return superClasses;
438     }
439     
440     
441     /**
442      * Assuming the primaryKey String is of type "x1,x2,x3",
443      * returns "x1 as pk0, x2 as pk1, x3 as pk2"
444      * @param primaryKey
445      * @return
446      */

447     private String JavaDoc aliasPK(String JavaDoc primaryKey, RdbAdapter adapter){
448         String JavaDoc tmp = primaryKey;
449         String JavaDoc aliasName = PK;
450         String JavaDoc separator = ",";
451         int separatorIndex = tmp.indexOf(separator);
452         while (separatorIndex != -1) {
453             String JavaDoc alias = adapter.getColumnAliasExpr(aliasName + pkIndex++);
454             String JavaDoc beginning = primaryKey.substring(0, separatorIndex);
455             String JavaDoc end = primaryKey.substring(separatorIndex);
456             primaryKey = beginning + alias + end;
457             separatorIndex = primaryKey.indexOf(separator, separatorIndex + alias.length() + 1);
458         }
459         primaryKey += adapter.getColumnAliasExpr(aliasName + pkIndex++);
460         return primaryKey;
461     }
462     
463     /**
464      * This class is only used to sort the elements while building the association table
465      * different pcms in an inheritance graph.
466      * See the setSubTreeFieldAssociationTable method.
467      */

468     private class IndexedPEM implements Comparable JavaDoc {
469         protected PrimitiveElementMapping pem;
470         protected int index;
471         protected String JavaDoc joinName;
472         
473         public IndexedPEM(PrimitiveElementMapping pem, String JavaDoc joinName, int index) {
474             this.pem = pem;
475             this.joinName = joinName;
476             this.index = index;
477         }
478
479         //compare pem sql column names first
480
//and then compare join names
481
public int compareTo(Object JavaDoc o) {
482             IndexedPEM indexedPem = (IndexedPEM) o;
483             int result = ((RdbPrimitiveElementMapping)pem).compareTo(indexedPem.pem);
484             if (result == 0)
485                 result = joinName.compareTo(indexedPem.joinName);
486             return result;
487         }
488         
489     }
490 }
491
Popular Tags