KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > jorm > mapper > rdb > lib > RdbExtentGenInfos


1 /**
2  * Copyright (C) 2003-2004
3  * - France Telecom R&D
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18  *
19  * Release: 1.0
20  *
21  * Authors: Olivier Lobry (olivier.lobry@francetelecom.com)
22  * Date: 14 sept. 2004
23  * Time: 11:15:44
24  */

25
26 package org.objectweb.jorm.mapper.rdb.lib;
27
28 import java.util.ArrayList JavaDoc;
29 import java.util.Collection JavaDoc;
30 import java.util.Collections JavaDoc;
31 import java.util.HashMap JavaDoc;
32 import java.util.HashSet JavaDoc;
33 import java.util.Iterator JavaDoc;
34 import java.util.Map JavaDoc;
35
36 import org.objectweb.jorm.api.PException;
37 import org.objectweb.jorm.mapper.rdb.metainfo.RdbClassMapping;
38 import org.objectweb.jorm.mapper.rdb.metainfo.RdbClassMultiMapping;
39 import org.objectweb.jorm.mapper.rdb.metainfo.RdbJoin;
40 import org.objectweb.jorm.mapper.rdb.metainfo.RdbPrimitiveElementMapping;
41 import org.objectweb.jorm.mapper.rdb.metainfo.RdbTable;
42 import org.objectweb.jorm.metainfo.api.Class;
43 import org.objectweb.jorm.metainfo.api.NameDef;
44 import org.objectweb.jorm.metainfo.api.ParentClassMapping;
45 import org.objectweb.jorm.metainfo.api.PrimitiveElement;
46 import org.objectweb.util.monolog.api.BasicLevel;
47 import org.objectweb.util.monolog.api.Logger;
48
49 public class RdbExtentGenInfos {
50     
51     public Logger logger;
52     public boolean debug = false;
53
54     public RdbExtentGenInfos(Logger logger) {
55         this.logger = logger;
56         debug = logger != null && logger.isLoggable(BasicLevel.DEBUG);
57     }
58
59     /**
60      * Calculates the query representing the extent of the class.
61      * The query will be made of an union (in case of horizontal mappings)
62      * of filtered (in case of filtered and vertical mappings) tables.
63      * Elements of the extent may come from the tables on which the class is mapped
64      * or from tables on which its sub(sub...)classes are mapped.
65      * The main problem is to retrieve those tables and in those tables the right
66      * columns mapping fields defined in the mother class knowing that:
67      * - different inheritance rules may be encountered (filtered, horizontal,
68      * vertical). Some will need union, some others will need selection
69      * - classes may be mapped on multiple tables, requiring joins to retrieve the
70      * needed columns
71      * - only tables columns mapping fields of the mother class should be included
72      * in the expression of the query
73      * - columns mapping the same field in different class mapping may have
74      * different names, thus requiring renaming for realizing the required unions
75      *
76      * How the query is calculated depends on whether the class is at the top
77      * of the hierarchy tree.
78      * 1) If is at the top, its extent is made of all the instances coming from its
79      * tables and those of its children (if they are mapped to other tables).
80      * 2) If it is in the middle of the tree and its inheritance rule is 'to-new-structures'
81      * then, none of its instances comes from its parents' tables, so we can apply the
82      * same algorithm
83      * 3) If it is in the middle and its inheritance rule is 'to-extended-structures', then its
84      * filter and those of its children must be used not to get instances of its
85      * parent class.
86      *
87      * In the first two cases, the query is created with the following formula:
88      * Q(A) = T(A) U (U (PROJECT(ATTR(A)) T))
89      * |
90      * T in T(SUB(A)) and T != T(A)
91      * where Q(A) = query for A's extent, ATTR(A) = attributes of A,
92      * T(X) = main table for class X, SUB(A) = all sub(sub(...))classes of A
93      *
94      * In the third case, the query is created with the following formula:
95      * Q(A) = (FILTER(A) AND (AND FILTER(X))) T(A) U (U (PROJECT(ATTR(A)) T(X)))
96      * | |
97      * X in SUB_F(A) and T(X)=T(A) T in T(SUB(A) - SUB_F(A)) and T != T(A)
98      * where Q(A) = query for A's extent, ATTR(A) = attributes of A,
99      * T(X) = main table for class X,
100      * SUB_F(A) = all sub(sub(...))classes that is 'filter chained'* w/ A
101      * (*) 'filter chained' means that all inheritance link from A to X
102      * is a filter inheritance rule
103      *
104      * Actually, this is a simplification since a single class may be mapped to
105      * multiple tables and the extent be calculated by joining these tables.
106      * However, since the filters express conditions on the key and the key is
107      * entirely contained in a table, this does not change the principles
108      * discussed above but simply complexifies the expression of the formulae.
109      * Instead of T(A) (resp. T(X)) we will have the joins between A's
110      * (resp. X's) tables.
111      *
112      * Also, the case of abstract classes must be taken into account. If class A
113      * its extents is the union of the extents of its subclasses. This is true
114      * whether it defines or extends an inherited mapping or not. So there is
115      * no need to construct a "select from where" at its level.
116      *
117      * @return a collection of ExtentMappingInfos that must be unioned to get the extent
118      */

119     //TODO: remove this method when integrating the horizontal and verticla mapping in speedo
120
//not forget to change the method call in the velocity template with the next method
121
public Collection JavaDoc getPolymorphicClassExtent(Class JavaDoc classA, String JavaDoc projectName,
122                                                String JavaDoc mapperName) throws PException {
123         //System.out.println("debug=" + debug + "logger=" + logger
124
// + (logger == null ? "" : ", logger.name=" + logger.getName()));
125
if (debug) logger.log(BasicLevel.INFO, "Calculating extent for class"
126                     + classA.getFQName() + " project: " + projectName +
127                 ", mapperName: " + mapperName);
128         RdbClassMapping classMappingOfA = (RdbClassMapping)
129                 classA.getClassMapping(projectName, mapperName);
130
131
132         // The term "class A" is used for the name of the class of which we are calculating
133
// the extent and "class X" is used as a sub(sub...)class of A
134

135         // get all the primitive elements of class A (non-hidden)
136
ArrayList JavaDoc primElsOfA = new ArrayList JavaDoc();
137         if (debug) logger.log(BasicLevel.DEBUG, "Primitive elements are: ");
138         for (Iterator JavaDoc itTE = classA.getAllFields().iterator(); itTE.hasNext();) {
139             Object JavaDoc te = itTE.next();
140             if (te instanceof PrimitiveElement) {
141                 primElsOfA.add(te);
142                 if (debug) logger.log(BasicLevel.DEBUG, " " +
143                         ((PrimitiveElement) te).getName());
144             }
145         }
146         // add hidden fields
147
for (Iterator JavaDoc itTE = classA.getAllHiddenFields().iterator(); itTE.hasNext();) {
148             Object JavaDoc te = itTE.next();
149             if (te instanceof PrimitiveElement) {
150                 primElsOfA.add(te);
151                 if (debug) logger.log(BasicLevel.DEBUG, " " +
152                         ((PrimitiveElement) te).getName() + " (hidden)");
153             }
154         }
155
156         HashMap JavaDoc extMappingInfosMap = new HashMap JavaDoc(); // <Class->ExtentMappingInfos>
157
HashSet JavaDoc extMappingInfos = new HashSet JavaDoc(); // <ExtentMappingInfos>
158

159         // Remaining classes to inspect. The algorithm follows a top-down
160
// horizontal traversal of the tree, classes being added progressively
161
// during the traversal
162
ArrayList JavaDoc remClasses = new ArrayList JavaDoc();
163         remClasses.add(classA);
164         while (!remClasses.isEmpty()) {
165             // remove the first class in list to treat it
166
Class JavaDoc classX = (Class JavaDoc) remClasses.remove(0);
167             // and add its children
168
Collection JavaDoc xSubClasses = classX.getSubClasses();
169             if (xSubClasses != null) {
170                 remClasses.addAll(xSubClasses);
171             }
172
173             // get its class mapping in the current project
174
RdbClassMultiMapping classMappingOfX = (RdbClassMultiMapping)
175                     classX.getClassMapping(projectName, mapperName);
176             if (classMappingOfX == null) {
177                 throw new PException("Could not find a class mapping for class "
178                         + classA.getName());
179             }
180
181
182             // will reference the extent mapping information relative to class X
183
// EMIs can be shared by classes that map fields to the same structures
184
RdbExtentMappingInfos emi;
185
186
187             // sub-class inspection
188
if (classX != classA) {
189                 if (debug) logger.log(BasicLevel.DEBUG, "Inspecting subclass: "
190                             + classX.getName());
191                 Class JavaDoc[] parent = new Class JavaDoc[1];
192                 RdbExtentMappingInfos emiParent = getParentEMI(classX, extMappingInfosMap, parent);
193                 // NB: the ext mapping info may be attached to a ancestor of the parent
194
// so do not use emiParent.clazz to retrieve the pcm but the real parent instead
195
ParentClassMapping pcmOfX = classMappingOfX.
196                         getParentClassMapping(parent[0].getFQName());
197
198                 // sanity check
199
if (pcmOfX == null) {
200                     throw new PException("Could not find a parent class mapping" +
201                             " for class " + classX.getName() + " to super class" +
202                             classA.getName());
203                 }
204
205                 // gets the inheritance rule
206
String JavaDoc ruleName = pcmOfX.getRuleName();
207                 if (debug) logger.log(BasicLevel.DEBUG, " inherits mapping from : " +
208                         ((Class JavaDoc) pcmOfX.getLinkedMO()).getFQName() +
209                         " with rule=" + ruleName);
210
211
212                 // in the case of an 'extended' or 'added' mapping,
213
// add the filter if it exists (and if required) to the
214
// emi of the parent
215
if ((RdbClassMapping.MAP_NEW_FIELDS_TO_EXTENDED_STRUCTURES
216                         .equalsIgnoreCase(ruleName)) ||
217                         (RdbClassMapping.MAP_NEW_FIELDS_TO_ADDED_STRUCTURES
218                         .equalsIgnoreCase(ruleName))) {
219                     // if the parent has unmapped fields, then we need to
220
// construct the union of its children's extents
221
// Otherwise, we can generate a single select/from/where
222
// clause with approriate filters
223
if (emiParent.hasUnmappedFields) {
224                         if (debug) logger.log(BasicLevel.DEBUG,
225                                 "Parent class has unmapped fields, create new EMI");
226                         emi = new RdbExtentMappingInfos(classX, classX.getName(), primElsOfA.size());
227                         extMappingInfos.add(emi);
228                         emi.addFilters = emiParent.addFilters;
229                         emi.hasUnmappedFields = classMappingOfX.
230                                 hasUnmappedPrimitiveElements(primElsOfA);
231                     } else {
232                         if (debug) logger.log(BasicLevel.DEBUG,
233                                 "Parent class has all its fields mapped, complement its EMI");
234                         emi = emiParent;
235                     }
236
237                     // add filter if required and if some exist (there is none
238
// if the class is abstract)
239
if (emi.addFilters && (!classX.isAbstract())) {
240                         emi.filters.add(classX.getFQName());
241                     }
242                 } else if (RdbClassMapping.REMAP_FIELDS_TO_NEW_STRUCTURES
243                         .equalsIgnoreCase(ruleName)) {
244                     // mapping completely redefined on new structures,
245
// so create a new extent mapping info to generate a seperate
246
// select/from/where clause
247
emi = new RdbExtentMappingInfos(classX, classX.getName(), primElsOfA.size());
248                     // TODO: should optimize this. The necessity to add filters depends on the inheritance
249
// relationship with the super classes AND the sub-classes
250
emi.addFilters = true;
251                     extMappingInfos.add(emi);
252                     emi.hasUnmappedFields = classMappingOfX.hasUnmappedPrimitiveElements(primElsOfA);
253                 } else {
254                     throw new InternalError JavaDoc("Unexpected inheritance rule: "
255                             + ruleName);
256                 }
257                 // register the extent mapping info for that class
258
extMappingInfosMap.put(classX, emi);
259
260                 // if class A is abstract it has no instances and has
261
// (or at least should have) no filters
262
// so we can stop here
263
if (classX.isAbstract()) {
264                     if (debug) logger.log(BasicLevel.DEBUG, "Class is abstract, next one");
265                     continue;
266                 }
267
268             } else { // class X == class A
269
emi = new RdbExtentMappingInfos(classX, classX.getName(), primElsOfA.size());
270                 extMappingInfos.add(emi);
271                 extMappingInfosMap.put(classX, emi);
272
273                 // in case of class A, determines the 'add filters' condition
274
// that will be checked for its subclasses
275
// TODO: should optimize this. The necessity to add filters depends on the inheritance
276
// relationship with the super classes AND the sub-classes
277
// emi.addFilters = classMappingOfX.inheritsStructures();
278
emi.addFilters = true;
279                 emi.hasUnmappedFields = classMappingOfX.hasUnmappedPrimitiveElements(primElsOfA);
280                 if (debug) logger.log(BasicLevel.DEBUG, " should add filters ? "
281                         + (emi.addFilters ? "yes" : "no"));
282
283                 // if class A is abstract it has no instances and has
284
// (or at least should have) no filters
285
// so we can stop here
286
if (classX.isAbstract()) {
287                     if (debug) logger.log(BasicLevel.DEBUG, "Class is abstract, next one");
288                     continue;
289                 }
290                 if (emi.addFilters) {
291                     emi.filters.add(classX.getFQName());
292                 }
293             }
294
295
296
297             // finds how primitive elements defined in class A are mapped
298
// in class X and construct select/from/where clauses to fetch
299
// the corresponding tuples from X's tables
300
int pos = 0;
301             for (Iterator JavaDoc it = primElsOfA.iterator(); it.hasNext(); pos++) {
302                 PrimitiveElement pe = (PrimitiveElement) it.next();
303                 if (debug) logger.log(BasicLevel.DEBUG, " find mapping for "
304                         + "primitive element " + pe.getName());
305                 if (emi.mappingDone(pos)) {
306                     if (debug) logger.log(BasicLevel.DEBUG, " already done");
307                     continue;
308                 }
309                 // search the PEM, looking in super classes if necessary
310
RdbPrimitiveElementMapping mappingOfpeInX = (RdbPrimitiveElementMapping)
311                         classMappingOfX.getPrimitiveElementMapping(pe.getName(), true);
312                 // for classes mapped to several tables, the primitive element
313
// may be mapped on an external table, requiring a join
314
RdbJoin join = mappingOfpeInX.getJoinByPrimitiveElement(pe);
315                 String JavaDoc tableName;
316                 if (join != null) {
317                     if (debug) logger.log(BasicLevel.DEBUG, " mapped to external table");
318                     tableName = join.getExternalTable().getName();
319                     emi.addJoin(join);
320                 } else {
321                     if (debug) logger.log(BasicLevel.DEBUG, " mapped to main table");
322                     emi.mainTable = (RdbTable) mappingOfpeInX.getParent();
323                     tableName = emi.mainTable.getName();
324                 }
325                 
326                 emi.addProjection(tableName, mappingOfpeInX.getName(),
327                         pe.getName(), classX.getFQName(), pos);
328             }
329         } // while !remClasses.isEmpty()
330

331         // remove empty requests
332
for (Iterator JavaDoc emiIt = extMappingInfos.iterator(); emiIt.hasNext();) {
333             RdbExtentMappingInfos emi = (RdbExtentMappingInfos) emiIt.next();
334             if (emi.isEmpty()) {
335                 emiIt.remove();
336             }
337         }
338
339     return extMappingInfos;
340     }
341     
342     /**
343      * This method is used to create the list of extent mapping infos for the class classA.
344      * @param classA: the JORM class
345      * @param projectName: the name of the project
346      * @param mapperName: the name of the mapper
347      * @param prefetch: true or false
348      */

349     public Collection JavaDoc getPolymorphicClassExtent(Class JavaDoc classA, String JavaDoc projectName, String JavaDoc mapperName, boolean prefetch) throws PException {
350         if (debug)
351             logger.log(BasicLevel.INFO, "Calculating extent for class"
352                     + classA.getFQName() + " project: " + projectName
353                     + ", mapperName: " + mapperName);
354         RdbClassMapping classMappingOfA = (RdbClassMapping) classA
355                 .getClassMapping(projectName, mapperName);
356
357         // The term "class A" is used for the name of the class of which we are
358
// calculating
359
// the extent and "class X" is used as a sub(sub...)class of A
360

361         //the list of primitive elements for classA
362
ArrayList JavaDoc primElsOfA = new ArrayList JavaDoc();
363         
364         // get all the primitive elements of class A (including non-hidden fields) (and its subclasses if prefetch is true)
365
ArrayList JavaDoc primEls = getPrimitiveElements(prefetch, classA, projectName, primElsOfA);
366
367         HashMap JavaDoc extMappingInfosMap = new HashMap JavaDoc(); // <Class->ExtentMappingInfos>
368
HashSet JavaDoc extMappingInfos = new HashSet JavaDoc(); // <ExtentMappingInfos>
369

370         // Remaining classes to inspect. The algorithm follows a top-down
371
// horizontal traversal of the tree, classes being added progressively
372
// during the traversal
373
ArrayList JavaDoc remClasses = new ArrayList JavaDoc();
374         remClasses.add(classA);
375         while (!remClasses.isEmpty()) {
376             // remove the first class in list to treat it
377
Class JavaDoc classX = (Class JavaDoc) remClasses.remove(0);
378             // and add its children
379
Collection JavaDoc xSubClasses = classX.getSubClasses();
380             if (xSubClasses != null) {
381                 remClasses.addAll(xSubClasses);
382             }
383
384             // get its class mapping in the current project
385
RdbClassMultiMapping classMappingOfX = (RdbClassMultiMapping) classX
386                     .getClassMapping(projectName, mapperName);
387             if (classMappingOfX == null) {
388                 throw new PException(
389                         "Could not find a class mapping for class "
390                                 + classA.getName());
391             }
392
393             // will reference the extent mapping information relative to class X
394
// EMIs can be shared by classes that map fields to the same
395
// structures
396
RdbExtentMappingInfos emi;
397
398             // sub-class inspection
399
if (classX != classA) {
400                 if (debug)
401                     logger.log(BasicLevel.DEBUG, "Inspecting subclass: "
402                             + classX.getName());
403                 Class JavaDoc[] parent = new Class JavaDoc[1];
404                 RdbExtentMappingInfos emiParent = getParentEMI(classX,
405                         extMappingInfosMap, parent);
406                 // NB: the ext mapping info may be attached to a ancestor of the
407
// parent
408
// so do not use emiParent.clazz to retrieve the pcm but the
409
// real parent instead
410
ParentClassMapping pcmOfX = classMappingOfX
411                         .getParentClassMapping(parent[0].getFQName());
412
413                 // sanity check
414
if (pcmOfX == null) {
415                     throw new PException(
416                             "Could not find a parent class mapping"
417                                     + " for class " + classX.getName()
418                                     + " to super class" + classA.getName());
419                 }
420
421                 // gets the inheritance rule
422
String JavaDoc ruleName = pcmOfX.getRuleName();
423                 if (debug)
424                     logger.log(BasicLevel.DEBUG, " inherits mapping from : "
425                             + ((Class JavaDoc) pcmOfX.getLinkedMO()).getFQName()
426                             + " with rule=" + ruleName);
427
428                 // in the case of an 'extended' or 'added' mapping,
429
// add the filter if it exists (and if required) to the
430
// emi of the parent
431
if ((RdbClassMapping.MAP_NEW_FIELDS_TO_EXTENDED_STRUCTURES.equalsIgnoreCase(ruleName))
432                     ||
433                     ((RdbClassMapping.MAP_NEW_FIELDS_TO_ADDED_STRUCTURES.equalsIgnoreCase(ruleName)) && !prefetch) ) {
434                     // if the parent has unmapped fields, then we need to
435
// construct the union of its children's extents
436
// Otherwise, we can generate a single select/from/where
437
// clause with approriate filters
438
if (emiParent.hasUnmappedFields) {
439                         if (debug)
440                             logger
441                                     .log(BasicLevel.DEBUG,
442                                             "Parent class has unmapped fields, create new EMI");
443                         emi = new RdbExtentMappingInfos(classX, classX.getName(),
444                                 primEls.size());
445                         extMappingInfos.add(emi);
446                         emi.addFilters = emiParent.addFilters;
447                         emi.hasUnmappedFields = classMappingOfX
448                                 .hasUnmappedPrimitiveElements(primElsOfA);
449                     } else {
450                         if (debug)
451                             logger
452                                     .log(BasicLevel.DEBUG,
453                                             "Parent class has all its fields mapped, complement its EMI");
454                         emi = emiParent;
455                     }
456
457                     // add filter if required and if some exist (there is none
458
// if the class is abstract)
459
if (emi.addFilters && (!classX.isAbstract())) {
460                         emi.filters.add(classX.getFQName());
461                     }
462                 } else if (RdbClassMapping.REMAP_FIELDS_TO_NEW_STRUCTURES.equalsIgnoreCase(ruleName)
463                             ||
464                             ((RdbClassMapping.MAP_NEW_FIELDS_TO_ADDED_STRUCTURES.equalsIgnoreCase(ruleName)) && prefetch)) {
465                     // mapping completely redefined on new structures,
466
// so create a new extent mapping info to generate a
467
// seperate
468
// select/from/where clause
469
emi = new RdbExtentMappingInfos(classX, classX.getName(),
470                             primEls.size());
471                     // TODO: should optimize this. The necessity to add filters
472
// depends on the inheritance
473
// relationship with the super classes AND the sub-classes
474
emi.addFilters = true;
475                     extMappingInfos.add(emi);
476                     emi.hasUnmappedFields = classMappingOfX
477                             .hasUnmappedPrimitiveElements(primElsOfA);
478                 } else {
479                     throw new InternalError JavaDoc("Unexpected inheritance rule: "
480                             + ruleName);
481                 }
482                 // register the extent mapping info for that class
483
extMappingInfosMap.put(classX, emi);
484
485                 // if class A is abstract it has no instances and has
486
// (or at least should have) no filters
487
// so we can stop here
488
if (classX.isAbstract()) {
489                     if (debug)
490                         logger.log(BasicLevel.DEBUG,
491                                 "Class is abstract, next one");
492                     continue;
493                 }
494
495             } else { // class X == class A
496
emi = new RdbExtentMappingInfos(classX, classX.getName(),
497                         primEls.size());
498                 extMappingInfos.add(emi);
499                 extMappingInfosMap.put(classX, emi);
500
501                 // in case of class A, determines the 'add filters' condition
502
// that will be checked for its subclasses
503
// TODO: should optimize this. The necessity to add filters
504
// depends on the inheritance
505
// relationship with the super classes AND the sub-classes
506
//emi.addFilters = classMappingOfX.inheritsStructures();
507
emi.addFilters = true;
508                 emi.hasUnmappedFields = classMappingOfX
509                         .hasUnmappedPrimitiveElements(primElsOfA);
510                 if (debug)
511                     logger.log(BasicLevel.DEBUG, " should add filters ? "
512                             + (emi.addFilters ? "yes" : "no"));
513
514                 // if class A is abstract it has no instances and has
515
// (or at least should have) no filters
516
// so we can stop here
517
if (classX.isAbstract()) {
518                     if (debug)
519                         logger.log(BasicLevel.DEBUG,
520                                 "Class is abstract, next one");
521                     continue;
522                 }
523                 if (emi.addFilters) {
524                     emi.filters.add(classX.getFQName());
525                 }
526             }
527
528             // finds how primitive elements defined in class A (and subclasses if prefetch is true) are mapped
529
// in class X and construct select/from/where clauses to fetch
530
// the corresponding tuples from X's tables
531
int pos = 0;
532             for (Iterator JavaDoc it = primEls.iterator(); it.hasNext(); pos++) {
533                 PrimitiveElement pe = (PrimitiveElement) it.next();
534                 if (debug)
535                     logger.log(BasicLevel.DEBUG, " find mapping for "
536                             + "primitive element " + pe.getName());
537                 //if the mapping is already done and it is not the NULL mapping (a NULL mappping for the c column is: select t.a, t.b, NULL, t.d from t)
538
//do nothing
539
if (emi.mappingDone(pos) && !emi.mappingNull(pos)) {
540                     if (debug)
541                         logger.log(BasicLevel.DEBUG, " already done");
542                     continue;
543                 }
544                 // search the PEM, looking in super classes if necessary
545
RdbPrimitiveElementMapping mappingOfpeInX = (RdbPrimitiveElementMapping) classMappingOfX
546                         .getPrimitiveElementMapping(pe.getName(), true);
547                 String JavaDoc tableName = "";
548                 if(prefetch && mappingOfpeInX == null){
549                     //if prefetch is true and the pe is not in the list of primitive elements for the class classX,
550
//put NULL for the name of the column in the select statement and nothing for the tableName:
551
//select a, b, NULL, d from...
552
//is the class associated the current class (classX) or the class of the pe???
553
emi.addProjection(tableName, RdbExtentMappingInfos.NULL_COLUMN, pe.getName(), ((Class JavaDoc) pe.getParent()).getFQName()/*classX.getFQName()*/, pos);
554                 }
555                 else{
556                     // for classes mapped to several tables, the primitive element
557
// may be mapped on an external table, requiring a join
558
RdbJoin join = mappingOfpeInX.getJoinByPrimitiveElement(pe);
559                     if (join != null) {
560                         if (debug)
561                             logger.log(BasicLevel.DEBUG," mapped to external table");
562                         tableName = join.getExternalTable().getName();
563                         emi.addJoin(join);
564                     } else {
565                         if (debug)
566                             logger.log(BasicLevel.DEBUG," mapped to main table");
567                         emi.setMainTable((RdbTable) mappingOfpeInX.getParent());
568                         tableName = emi.getMainTable().getName();
569                     }
570                     emi.addProjection(tableName, mappingOfpeInX.getName(), pe.getName(), ((Class JavaDoc) pe.getParent()).getFQName()/*classX.getFQName()*/, pos);
571                 }
572             }
573         } // while !remClasses.isEmpty()
574

575         // remove empty requests
576
for (Iterator JavaDoc emiIt = extMappingInfos.iterator(); emiIt.hasNext();) {
577             RdbExtentMappingInfos emi = (RdbExtentMappingInfos) emiIt.next();
578             if (emi.isEmpty()) {
579                 emiIt.remove();
580             }
581         }
582
583         return extMappingInfos;
584     }
585     
586     /**
587      * Returns the list of the primitive elements (hidden and non-hidden) for:
588      * - the class classA ,
589      * - all its parents and parents of parents...
590      * - all its subclasses and subclasses of subclasses...
591      */

592     public ArrayList JavaDoc getAllPrimitiveElementsInGraph(Class JavaDoc classA, String JavaDoc projectName){
593         //get all the ancestor(s) of classA
594
Collection JavaDoc ancestors = classA.getAllAncestors();
595         if (ancestors == Collections.EMPTY_LIST)
596             ancestors = new ArrayList JavaDoc(1);
597         //add classA to this list
598
ancestors.add(classA);
599         //the list of primitive elements to return
600
ArrayList JavaDoc primEls = new ArrayList JavaDoc();
601         Iterator JavaDoc it = ancestors.iterator();
602         //for each class
603
while (it.hasNext()) {
604             Class JavaDoc currentClass = (Class JavaDoc) it.next();
605             boolean withSubclasses = false;
606             if (currentClass == classA)
607                 withSubclasses = true;
608             //gets the list of pe for the class currentClass
609
// plus the list of pe for subclasses just in the case of the classA class
610
ArrayList JavaDoc primElsOfCurrent = getPrimitiveElements(withSubclasses, currentClass, projectName, null);
611             Iterator JavaDoc peIt = primElsOfCurrent.iterator();
612             while (peIt.hasNext()) {
613                 PrimitiveElement pe = (PrimitiveElement) peIt.next();
614                 if (!primEls.contains(pe)) {
615                     //adds the pe if not already in the list
616
primEls.add(pe);
617                 }
618             }
619         }
620         
621         return primEls;
622     }
623     
624     /**
625      * Returns the list of the primitive elements (hidden and non-hidden) for:
626      * - the class classA if withSubtypes is false
627      * - the class classA and all its subclasses and subclasses of subclasses... if withSubtypes is true
628      * This method also compute the list of primitive elements, only for classA and put it in the primElsOfA list if primElsOfA is not null
629      */

630     private ArrayList JavaDoc getPrimitiveElements(boolean withSubtypes, Class JavaDoc classA, String JavaDoc projectName, ArrayList JavaDoc primElsOfA){
631         //the list of primitive elements
632
ArrayList JavaDoc primEls = new ArrayList JavaDoc();
633         //the list of class to process
634
ArrayList JavaDoc remClasses = new ArrayList JavaDoc();
635         //add the first class classA
636
remClasses.add(classA);
637         
638         while(!remClasses.isEmpty()){
639             Class JavaDoc currentClass = (Class JavaDoc) remClasses.remove(0);
640             
641             //if prefetch is true, add the subclasses as classes to process
642
//else, only process classA
643
if(withSubtypes)
644                 remClasses.addAll(currentClass.getSubClasses());
645             
646             NameDef ndef = currentClass.getNameDef(projectName);
647             if (debug)
648                 logger.log(BasicLevel.DEBUG, "Primitive elements are: ");
649             for (Iterator JavaDoc itTE = currentClass.getAllFields().iterator(); itTE.hasNext();) {
650                 Object JavaDoc te = itTE.next();
651                 if (te instanceof PrimitiveElement) {
652                     //add it only if it is not already in the list
653
if(!primEls.contains(te))
654                         primEls.add(te);
655                     if (debug)
656                         logger.log(BasicLevel.DEBUG, " " + ((PrimitiveElement) te).getName());
657                 }
658             }
659             // add hidden fields
660
for (Iterator JavaDoc itTE = currentClass.getAllHiddenFields().iterator(); itTE.hasNext();) {
661                 Object JavaDoc te = itTE.next();
662                 if (te instanceof PrimitiveElement) {
663                     //add it only if it is not already in the list
664
if(!primEls.contains(te))
665                         primEls.add(te);
666                     if (debug)
667                         logger.log(BasicLevel.DEBUG, " " + ((PrimitiveElement) te).getName() + " (hidden)");
668                 }
669             }
670             
671             if(primElsOfA != null && currentClass == classA)
672                 primElsOfA.addAll(primEls);
673         }
674         return primEls;
675     }
676   
677     /**
678      * finds the parent's extent mapping info of a class in the inheritance hierarchy
679      * @param clazz the clazz from wich searching for parents
680      * @param EMIMap map of < clazz,extent mapping infos > into wich searching
681      * @return
682      */

683     private RdbExtentMappingInfos getParentEMI(Class JavaDoc clazz, Map JavaDoc EMIMap, Class JavaDoc[] parent) {
684         logger.log(BasicLevel.DEBUG, "Get parent's EMI");
685         if (parent != null) {
686             parent[0] = null;
687         }
688         RdbExtentMappingInfos emiOfParent = null;
689         Collection JavaDoc parentsOfX = clazz.getSuperClasses();
690         for (Iterator JavaDoc itP = parentsOfX.iterator(); itP.hasNext();) {
691             Class JavaDoc superClass = (Class JavaDoc) itP.next();
692             emiOfParent = (RdbExtentMappingInfos)
693                     EMIMap.get(superClass);
694             if (emiOfParent != null) {
695                 if (parent != null) {
696                     logger.log(BasicLevel.DEBUG, "Return parent=" + superClass.getFQName());
697                     parent[0] = superClass;
698                 }
699                 return emiOfParent;
700             }
701         }
702         logger.log(BasicLevel.DEBUG, "Found none");
703         return null;
704     }
705    
706 }
Popular Tags