KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > jorm > mapper > rdb > generator > RdbCommonHelper


1 /**
2  * JORM: an implementation of a generic mapping system for persistent Java
3  * objects. Two mapping are supported: to RDBMS and to binary files.
4  * Copyright (C) 2001-2003 France Telecom R&D - INRIA
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  * Contact: jorm-team@objectweb.org
21  *
22  */

23
24 package org.objectweb.jorm.mapper.rdb.generator;
25
26 import org.objectweb.jorm.api.PException;
27 import org.objectweb.jorm.generator.lib.CommonHelper;
28 import org.objectweb.jorm.mapper.rdb.adapter.RdbAdapterFactory;
29 import org.objectweb.jorm.mapper.rdb.adapter.api.RdbAdapter;
30 import org.objectweb.jorm.mapper.rdb.metainfo.RdbClassMapping;
31 import org.objectweb.jorm.mapper.rdb.metainfo.RdbClassMultiMapping;
32 import org.objectweb.jorm.mapper.rdb.metainfo.RdbExternalTable;
33 import org.objectweb.jorm.mapper.rdb.metainfo.RdbJoin;
34 import org.objectweb.jorm.mapper.rdb.metainfo.RdbMapping;
35 import org.objectweb.jorm.mapper.rdb.metainfo.RdbPrimitiveElementMapping;
36 import org.objectweb.jorm.mapper.rdb.metainfo.RdbTable;
37 import org.objectweb.jorm.metainfo.api.Class;
38 import org.objectweb.jorm.metainfo.api.ClassMapping;
39 import org.objectweb.jorm.metainfo.api.Mapping;
40 import org.objectweb.jorm.metainfo.api.NameDef;
41 import org.objectweb.jorm.metainfo.api.Package;
42 import org.objectweb.jorm.metainfo.api.ParentClassMapping;
43 import org.objectweb.jorm.metainfo.api.PrimitiveElement;
44 import org.objectweb.jorm.metainfo.api.Reference;
45 import org.objectweb.jorm.metainfo.api.ReferenceMapping;
46 import org.objectweb.jorm.metainfo.api.TypedElement;
47 import org.objectweb.jorm.type.api.PType;
48 import org.objectweb.util.monolog.api.BasicLevel;
49 import org.objectweb.util.monolog.api.Logger;
50
51 import java.util.ArrayList JavaDoc;
52 import java.util.Collections JavaDoc;
53 import java.util.Comparator JavaDoc;
54 import java.util.HashMap JavaDoc;
55 import java.util.Iterator JavaDoc;
56 import java.util.List JavaDoc;
57 import java.util.Map JavaDoc;
58 import java.util.TreeMap JavaDoc;
59
60 /**
61  * This helper contains all common tool methods shared by the RdbBindingMOP and
62  * the RdbMappingMOP.
63  * @author Sebastien Chassande-Barrioz
64  */

65 public class RdbCommonHelper extends CommonHelper {
66
67     private Map JavaDoc rdbAdapters = new HashMap JavaDoc();
68
69     public RdbCommonHelper() {
70     }
71     public RdbCommonHelper(Logger logger) {
72         setLogger(logger);
73     }
74
75     /**
76      * Retrieves the adapter associated with the given mapper.
77      * @param mappername The name of the corresponding mapper.
78      * @return The RDB adapter.
79      * @throws org.objectweb.jorm.api.PException
80      */

81     protected RdbAdapter getRdbAdapter(String JavaDoc mappername) throws PException {
82         RdbAdapter res = (RdbAdapter) rdbAdapters.get(mappername);
83         if (res != null) {
84             return res;
85         }
86         String JavaDoc dbn;
87         if (mappername.indexOf(".") == -1)
88             dbn = RdbAdapterFactory.DATABASE_NAME_JDBC;
89         else
90             dbn = mappername.substring(mappername.indexOf(".") + 1);
91         try {
92             res = RdbAdapterFactory.getTypeConverter(dbn);
93         } catch (org.objectweb.jorm.mapper.rdb.adapter.api.RdbAdapterException e) {
94             throw new PException(e, "");
95         }
96         rdbAdapters.put(mappername, res);
97         return res;
98     }
99
100     public String JavaDoc getSqlType(RdbPrimitiveElementMapping pem,
101                              String JavaDoc adapter,
102                              boolean usedInPk) throws PException {
103         String JavaDoc userSQLType = pem.getType();
104         if (userSQLType == null || userSQLType.length() == 0) {
105             StringBuffer JavaDoc sb = new StringBuffer JavaDoc(adapter);
106             sb.append(".getSqlType(");
107             PrimitiveElement pe = (PrimitiveElement) pem.getLinkedMO();
108             sb.append(pe.getType().getProgName());
109             sb.append(".getTypeCode(), ");
110             sb.append(usedInPk);
111             sb.append(", ");
112             if (pe.getSize() == PType.NOSIZE) {
113                 sb.append("RdbAdapter.NOSIZE");
114             } else {
115                 sb.append(pe.getSize());
116             }
117             sb.append(", ");
118             if (pe.getScale() == PType.NOSIZE) {
119                 sb.append("RdbAdapter.NOSIZE");
120             } else {
121                 sb.append(pe.getScale());
122             }
123             sb.append(")");
124             return sb.toString();
125         } else {
126             return "\"" + userSQLType + "\"";
127         }
128     }
129     /**
130      * Creates a generation context that can be shared between binding and
131      * mapping generation for a particular class.
132      *
133      * If the current class has a parent class and if a vertical mapping
134      * has been defined: the main table of the current class then references
135      *
136      *
137      * cm.getRdbTable() returns the main table of one of the parent classes (P class).
138      * rcm.getRdbAllExternalTables() : returns all the external tables defines for
139      * the current class and for all the parent classes up to the P class.
140      *
141      */

142     RdbGenInfos getRdbGenInfos(Class JavaDoc clazz, String JavaDoc projectName, String JavaDoc mapperName)
143     throws PException {
144             Mapping mapping = clazz.getClassProject(projectName).getMapping(mapperName);
145             return createRdbGenInfosContext((RdbMapping) mapping,
146                 (Class JavaDoc) mapping.getClassMapping().getJormClass());
147     }
148
149     RdbGenInfos getRdbGenInfos(Mapping mapping)
150             throws PException {
151         return createRdbGenInfosContext((RdbMapping) mapping,
152             (Class JavaDoc) mapping.getClassMapping().getLinkedMO());
153     }
154
155     RdbGenInfos getRdbGenInfos(Mapping mapping, Map JavaDoc ctx)
156         throws PException {
157         return createRdbGenInfosContext((RdbMapping) mapping,
158                 (Class JavaDoc) mapping.getClassMapping().getLinkedMO(), ctx);
159     }
160
161     RdbGenInfos createRdbGenInfosContext(RdbMapping mapping, Class JavaDoc clazz) throws PException {
162         return createRdbGenInfosContext(mapping, clazz, new HashMap JavaDoc());
163     }
164     RdbGenInfos createRdbGenInfosContext(RdbMapping mapping, Class JavaDoc clazz, Map JavaDoc ctx)
165             throws PException {
166         //mapping2geninfos.clear();
167
debug = logger != null && logger.isLoggable(BasicLevel.DEBUG);
168
169         // create the gen info and register it
170
RdbGenInfos rgi = new RdbGenInfos();
171
172         // set mapping, logger & debug
173
rgi.mapping = mapping;
174         rgi.logger = logger;
175         rgi.debug = debug;
176
177
178
179         // get the main table
180
RdbClassMultiMapping classMapping = (RdbClassMultiMapping)
181                 mapping.getClassMapping();
182         if (debug) {
183             logger.log(BasicLevel.DEBUG, "mapping.getClassMapping() " + classMapping);
184             logger.log(BasicLevel.DEBUG, "Creating the generation MI for the class = "
185                     + ((Class JavaDoc) classMapping.getLinkedMO()).getFQName());
186         }
187
188
189         // create a RdbGenTable from the RdbTable of the class
190
RdbTable mainRdbTable = classMapping.getMainRdbTable();
191         if (mainRdbTable == null) {
192             logger.log(BasicLevel.DEBUG, "No main table defined for this " +
193                     "class (implicit inheritance ?). Abort Gen infos creation");
194             return rgi;
195         }
196         if (debug) {
197             logger.log(BasicLevel.DEBUG, "Main table: "
198                     + mainRdbTable.getName());
199         }
200
201         RdbGenTable mainGenTable = new RdbGenTable(mainRdbTable, clazz, rgi);
202
203         rgi.mainTable = mainGenTable;
204
205
206         // Retrieves inherited mapping definition
207
getInheritedData(classMapping,
208                 mainGenTable.inheritedColumns,
209                 rgi.readableColumns,
210                 rgi.genRefs,
211                 rgi.tables,
212                 clazz,
213                 ctx);
214         if (debug) {
215             logger.log(BasicLevel.DEBUG, "Inherited columns:");
216             printColumns(rgi.readableColumns);
217         }
218
219         // Filtered mapping and concrete parent classes
220

221         rgi.tables.put(mainGenTable.tableName, mainGenTable);
222         addColumnUnique(mainGenTable.columns, rgi.readableColumns, false);
223
224
225         // Get the external tables and defined columns
226
for (Iterator JavaDoc it = classMapping.getExternalTables().iterator();
227              it.hasNext();) {
228             RdbExternalTable extTable = (RdbExternalTable) it.next();
229
230             // translation: RdbTable => RdbGenTable
231
RdbGenTable genTable = new RdbGenTable(extTable, mainGenTable,
232                     clazz, rgi);
233
234             // cross reference: genInfos <->> genTable
235
rgi.tables.put(genTable.tableName, genTable);
236
237
238             if (debug) {
239                 logger.log(BasicLevel.DEBUG,
240                         "ext table -- name = " + genTable.getTableName());
241             }
242
243             // add columns that do not participate in the join
244
// with main table (OL: why ??)
245
for (int i = 0; i < genTable.columns.size(); i++) {
246                 RdbGenColumn genColumn = (RdbGenColumn) genTable.columns.get(i);
247                 if (genColumn.joinCol == null) {
248                     rgi.readableColumns.add(genColumn);
249                 }
250             }
251         }
252
253         // define GenRef of the class identifier
254
//System.out.println("get the namedef");
255
NameDef nd = classMapping.getIdentifierMapping().getNameDef();
256         Integer JavaDoc ndIdInteger = (Integer JavaDoc) ctx.get("ndid");
257         
258         int ndId = (ndIdInteger == null ? 0 : ndIdInteger.intValue());
259         
260         rgi.genId = defineGenRef(nd, null, ndId++, classMapping, rgi);
261
262         if (debug) {
263             for (Iterator JavaDoc iter = clazz.getAllFields().iterator();
264                  iter.hasNext();) {
265                 TypedElement typedElem = (TypedElement) iter.next();
266                 if (typedElem instanceof Reference) {
267                     logger.log(BasicLevel.DEBUG, "current class: " + clazz.getName() + "current reference field " + typedElem.getName());
268                     logger.log(BasicLevel.DEBUG, "classMapping.getReferenceMapping(typedElem.getName()) " + classMapping.getReferenceMapping(typedElem.getName()));
269                     NameDef namedef = (NameDef) classMapping.getReferenceMapping(typedElem.getName()).getLinkedMO();
270                     logger.log(BasicLevel.DEBUG, "current reference field " + typedElem.getName() + " namedef " + namedef);
271                 }
272             }
273         }
274
275         // define GenRef for each reference field of the current class
276
for (Iterator JavaDoc it = classMapping.getReferenceMappings().iterator(); it.hasNext();) {
277             nd = (NameDef) ((ReferenceMapping) it.next()).getLinkedMO();
278             String JavaDoc fn = ((Reference) nd.getParent()).getName();
279             rgi.genRefs.put(fn, defineGenRef(nd, fn, ndId++, classMapping, rgi));
280         }
281         ctx.put("ndid", new Integer JavaDoc(ndId));
282
283         // fix the mustGenerateUpdate attribute for this table
284
for (Iterator JavaDoc it = rgi.tables.values().iterator(); it.hasNext();) {
285             ((RdbGenTable) it.next()).fixMustGenerateUpdate();
286         }
287
288         Collections.sort(rgi.readableColumns, new RGCComparator());
289         if (debug) {
290             logger.log(BasicLevel.DEBUG, "ReadableColumn: ");
291             for(int i=0; i<rgi.readableColumns.size(); i++) {
292                 RdbGenColumn col = (RdbGenColumn) rgi.readableColumns.get(i);
293                 if (col.joins == null) {
294                     logger.log(BasicLevel.DEBUG, "\tCOL=" + col.columnName
295                             + " / TABLE=" + col.table.tableName
296                             + " / COL_IDX=" + rgi.getColumnPosition(col)
297                             + " rgc=" + col);
298                 } else {
299                     logger.log(BasicLevel.DEBUG, "\tCOL=" + col.columnName
300                             + " / TABLE=" + col.table.tableName
301                             + " rgc=" + col);
302                     for(int j=0; j<col.joins.size(); j++) {
303                         RdbGenJoin join = (RdbGenJoin) col.joins.get(j);
304                         logger.log(BasicLevel.DEBUG, "\t\tJOIN_IDX=" + join.getJoinIdx()
305                                 + " / COL_IDX=" + rgi.getColumnPosition(col, join));
306                     }
307                 }
308             }
309             logger.log(BasicLevel.DEBUG, "End of createClassGenerationContext for class " + clazz.getFQName());
310         }
311
312         // filter
313
rgi.filterExpr = rgi.getFilterExpression();
314         return rgi;
315     }
316     // PRIVATE METHODS
317

318     private class RGCComparator implements Comparator JavaDoc {
319         public int compare(Object JavaDoc o1, Object JavaDoc o2) {
320             RdbGenColumn rgc1 = (RdbGenColumn) o1;
321             RdbGenColumn rgc2 = (RdbGenColumn) o2;
322             return rgc1.columnName.compareTo(rgc2.columnName);
323         }
324     }
325
326     /**
327      * Adds all elements of @source to @dest excep those already in @dest.
328      * Insertion begings at position @pos in dest
329      * @param source the source list of element to insert
330      * @param dest the list into wich inserting
331      * @param addInHead if true add in head else add in tail
332      */

333     private void addColumnUnique(List JavaDoc source, List JavaDoc dest, boolean addInHead) {
334         int pos = (addInHead) ? 0 : dest.size();
335         for(int i=0; i<source.size(); i++) {
336             boolean found = false;
337             RdbGenColumn rgcToAdd = (RdbGenColumn) source.get(i);
338             for(int j=0; j<dest.size() && !found; j++) {
339                 RdbGenColumn col = (RdbGenColumn) dest.get(j);
340                 found = col.table.tableName.equals(rgcToAdd.table.tableName)
341                     && col.columnName.equals(rgcToAdd.columnName);
342             }
343             if (!found) {
344                 dest.add(pos++, rgcToAdd);
345             }
346         }
347     }
348
349     /**
350      * Defines the RdbGenDef associated either with the identifier of this class
351      * mapping, or with one of its references.
352      * @param nd The NameDef associated with the identifier or a reference.
353      * @param fn ??
354      * @param cnid The composite name identifier allocated for code generation
355      * @param cm ??
356      * @param rgi ??
357      * of references.
358      * @return The created RdbGenRef describing the identifier or a reference.
359      */

360     private RdbGenRef defineGenRef(NameDef nd,
361                                    String JavaDoc fn,
362                                    int cnid,
363                                    RdbClassMapping cm,
364                                    RdbGenInfos rgi)
365             throws PException {
366
367         RdbGenRef rgr = new RdbGenRef();
368         rgr.nd = nd;
369         rgr.fieldName = fn;
370         if (nd.isFieldName()) {
371             // get the primitive element mapping of the field (searching in super classes)
372
RdbPrimitiveElementMapping pem = (RdbPrimitiveElementMapping)
373                     cm.getPrimitiveElementMapping(nd.getFieldName(), true);
374             if (pem == null) {
375                 throw new PException(
376                         "Unable to find the mapping of the field "
377                         + nd.getFieldName());
378             }
379             RdbTable table = (RdbTable) pem.getParent();
380             if (debug) {
381                 logger.log(BasicLevel.DEBUG, "nd(" + fn
382                         + ") FieldName, field=" + nd.getFieldName()
383                         + " / column name=" + pem.getName()
384                         + " in the table: " + table.getName());
385             }
386             RdbGenTable rgt = (RdbGenTable) rgi.tables.get(table.getName());
387             if (rgt == null) {
388                 throw new NullPointerException JavaDoc("No table " + table.getName() + " found among: " + rgi.tables);
389             }
390             rgr.refColumn = rgt.getColumn(pem.getName());
391             if (rgt.joins != null) {
392                 getJoin(rgt, pem, nd.getFieldName(), rgr);
393             }
394         } else { // this is a NameRef
395
if (debug) {
396                 logger.log(BasicLevel.DEBUG, "nd(" + fn + ") CommpositeName, cnId=" + cnid);
397             }
398             rgr.cnId = cnid;
399             rgr.cnName = nd.getNameRef().getCompositeName().getName();
400             rgr.cnPackage = ((Package JavaDoc) nd.getNameRef().getCompositeName().getParent()).getName();
401             rgr.cnFieldColumns = new TreeMap JavaDoc();
402             Iterator JavaDoc itp = nd.getNameRef().getProjection().entrySet().iterator();
403             RdbPrimitiveElementMapping pem = null;
404             while (itp.hasNext()) {
405                 Map.Entry JavaDoc me = (Map.Entry JavaDoc) itp.next();
406                 String JavaDoc cnfield = (String JavaDoc) me.getKey();
407                 String JavaDoc clafn = (String JavaDoc) me.getValue();
408                 // get the primitive element mapping of the field (searching in super classes)
409
pem = (RdbPrimitiveElementMapping)
410                         cm.getPrimitiveElementMapping(clafn, true);
411                 if (pem == null) {
412                     throw new PException(
413                             "Unable to find the mapping of the field "
414                             + nd.getFieldName());
415                 }
416                 RdbTable table = (RdbTable) pem.getParent();
417                 if (debug) {
418                     logger.log(BasicLevel.DEBUG, "nd(" + fn
419                             + ") composite field name=" + cnfield
420                             + " / class field name=" + clafn
421                             + " / column name=" + pem.getName()
422                             + " in the table: " + table.getName());
423                 }
424                 RdbGenTable rgt = (RdbGenTable) rgi.tables.get(table.getName());
425                 if (rgt == null) {
426                     throw new PException("Cannot find gen table");
427                 }
428                 RdbGenColumn c = rgt.getColumn(pem.getName());
429                 rgr.cnFieldColumns.put(cnfield, c);
430                 if (rgr.join == null && rgt.joins != null) {
431                     getJoin(rgt, pem, clafn, rgr);
432                 }
433             }
434         }
435         return rgr;
436     }
437
438     private void getJoin(RdbGenTable rgt,
439                          RdbPrimitiveElementMapping pem,
440                          String JavaDoc fn,
441                          RdbGenRef rgr) {
442         if (debug) {
443             logger.log(BasicLevel.DEBUG, "getJoin: fn: " + rgr.fieldName
444                     + " / col: " + pem.getName()
445                     + " / rgt: " + rgt.tableName);
446         }
447         if (rgt.joins.size() == 1) {
448             rgr.join = (RdbGenJoin) rgt.joins.get(0);
449             if (debug) {
450                 logger.log(BasicLevel.DEBUG, "return: fn: " + rgr.fieldName
451                         + " / col: " + pem.getName()
452                         + " / join: " + rgr.join.joinIdx);
453             }
454         }
455         Iterator JavaDoc it = pem.getPrimitiveElementByRdbJoin().entrySet().iterator();
456         while (it.hasNext()) {
457             Map.Entry JavaDoc me2 = (Map.Entry JavaDoc) it.next();
458             PrimitiveElement pe = (PrimitiveElement) me2.getValue();
459             if (pe.getName().equals(fn)) {
460                 rgr.join = (RdbGenJoin)
461                         rgt.jn2join.get(((RdbJoin) me2.getKey()).getName());
462                 if (debug) {
463                     logger.log(BasicLevel.DEBUG, "return fn: " + rgr.fieldName
464                             + " / col: " + pem.getName()
465                             + " / joinName: " + ((RdbJoin) me2.getKey()).getName()
466                             + " / join: " + rgr.join.joinIdx);
467                 }
468             }
469         }
470     }
471
472     /**
473      * Gets the inherited data
474      * @param cm the rdb class mapping of the class
475      * @param inheritedColumns list in which to return the inherited
476      * @param inheritedReadableColumns
477      * @param inheritedGenRefs
478      * @param inheritedExtTables
479      * @param constantHolderClass
480      * @throws PException
481      */

482     private void getInheritedData(RdbClassMapping cm,
483                                   List JavaDoc inheritedColumns,
484                                   List JavaDoc inheritedReadableColumns,
485                                   Map JavaDoc inheritedGenRefs,
486                                   Map JavaDoc inheritedExtTables,
487                                   Class JavaDoc constantHolderClass,
488                                   Map JavaDoc ctx)
489             throws PException {
490         // loop on super classes
491
for (Iterator JavaDoc pcmit = cm.getParentClassMappings().iterator();
492              pcmit.hasNext();) {
493             ParentClassMapping pcm = (ParentClassMapping) pcmit.next();
494             // only consider 'added' or 'extended' inheritance rules
495
if (cm.inheritsStructures(pcm)) {
496                 Class JavaDoc superClass = pcm.getMOClass();
497                 if (debug) {
498                     logger.log(BasicLevel.DEBUG,
499                             "rule-name = " + pcm.getRuleName() + "=<" + superClass.getFQName() + ">"
500                             + " abstract =<" + superClass.isAbstract() + ">");
501                 }
502
503                 RdbClassMapping superClassMapping = (RdbClassMapping)
504                         superClass.getClassMapping(
505                                 cm.getProjectName(),
506                                 cm.getMapperName());
507                 
508                 if (superClassMapping.getMainRdbTable() != null) {
509                     RdbGenInfos superGenInfos =
510                             getRdbGenInfos((Mapping) superClassMapping.getParent(), ctx);
511                     addColumnUnique(superGenInfos.getReferenceTable().columns,
512                             inheritedColumns, true);
513                     addColumnUnique(superGenInfos.readableColumns,
514                             inheritedReadableColumns, true);
515                     inheritedGenRefs.putAll(superGenInfos.genRefs);
516                     inheritedExtTables.putAll(superGenInfos.tables);
517                 }
518                
519                 // recursively gets the infos inherited by the super class
520
getInheritedData(superClassMapping,
521                         inheritedColumns,
522                         inheritedReadableColumns,
523                         inheritedGenRefs,
524                         inheritedExtTables,
525                         constantHolderClass,
526                         ctx);
527             }
528         }
529     }
530
531     private void printColumns(List JavaDoc columns) {
532         RdbGenColumn rgc = null;
533         for (int i = 0; i < columns.size(); i++) {
534             rgc = (RdbGenColumn) columns.get(i);
535             logger.log(BasicLevel.DEBUG, "\tcolumn : " + rgc.columnName
536                     + " isHiddenField: " + rgc.isHiddenField()
537                     + " isConstantField: " + (rgc.constant != null));
538         }
539     }
540 }
541
Popular Tags