KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > speedo > generation > jorm > JormMIBuilder


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

18 package org.objectweb.speedo.generation.jorm;
19
20 import org.objectweb.speedo.metadata.SpeedoClass;
21 import org.objectweb.speedo.metadata.SpeedoField;
22 import org.objectweb.speedo.metadata.SpeedoIdentity;
23 import org.objectweb.speedo.metadata.SpeedoCollection;
24 import org.objectweb.speedo.metadata.SpeedoMap;
25 import org.objectweb.speedo.metadata.SpeedoExtension;
26 import org.objectweb.speedo.api.SpeedoException;
27 import org.objectweb.speedo.api.SpeedoProperties;
28 import org.objectweb.speedo.api.UserFieldMapping;
29 import org.objectweb.speedo.generation.generator.proxy.ProxyGenerator;
30 import org.objectweb.speedo.naming.api.MIBuilderHelper;
31 import org.objectweb.speedo.naming.lib.NamingManagerFactory;
32 import org.objectweb.jorm.metainfo.api.Class;
33 import org.objectweb.jorm.metainfo.api.Manager;
34 import org.objectweb.jorm.metainfo.api.ClassProject;
35 import org.objectweb.jorm.metainfo.api.Mapping;
36 import org.objectweb.jorm.metainfo.api.PrimitiveElement;
37 import org.objectweb.jorm.metainfo.api.NameDef;
38 import org.objectweb.jorm.metainfo.api.ClassMapping;
39 import org.objectweb.jorm.metainfo.api.ClassRef;
40 import org.objectweb.jorm.metainfo.api.GenClassRef;
41 import org.objectweb.jorm.metainfo.api.GenClassMapping;
42 import org.objectweb.jorm.metainfo.api.MetaObject;
43 import org.objectweb.jorm.metainfo.api.ScalarField;
44 import org.objectweb.jorm.metainfo.api.CommonClassMapping;
45 import org.objectweb.jorm.metainfo.api.Reference;
46 import org.objectweb.jorm.metainfo.api.IdentifierMapping;
47 import org.objectweb.jorm.metainfo.api.TypedElement;
48 import org.objectweb.jorm.metainfo.api.ReferenceMapping;
49 import org.objectweb.jorm.metainfo.lib.MetaInfoPrinter;
50 import org.objectweb.jorm.type.api.PType;
51 import org.objectweb.jorm.type.api.PTypeSpace;
52 import org.objectweb.jorm.api.PException;
53 import org.objectweb.jorm.util.api.Loggable;
54 import org.objectweb.asm.Type;
55 import org.objectweb.util.monolog.api.Logger;
56 import org.objectweb.util.monolog.api.BasicLevel;
57
58 import java.util.Collection JavaDoc;
59 import java.util.ArrayList JavaDoc;
60 import java.util.Iterator JavaDoc;
61 import java.util.List JavaDoc;
62
63 /**
64  * This class is a builder of jorm meta information. Its entries are the folowing:
65  * <UL>
66  * <LI>the jorm meta information manager,</LI>
67  * <LI>A collection of SpeedoClass object,</LI>
68  * <LI>the project name,</LI>
69  * <LI>the mapper name,</LI>
70  * <LI>a JormMIMappingBuilder instance able to build the mapping part for the
71  * mapper which the name is specified.</LI>
72  * </UL>
73  * @author S.Chassande-Barrioz
74  */

75 public class JormMIBuilder implements MIBuilderHelper {
76
77     /**
78      * is the prefix of the fields used to identify a generic class
79      */

80     public final static String JavaDoc GENCLASS_ID_PREFIX = "id_";
81
82     /**
83      * is the prefix of the fields used for the element of a generic class
84      */

85     public final static String JavaDoc GENCLASS_ELM_PREFIX = "elem_";
86
87     public final static String JavaDoc DEFAULT_RDB_BUILDER
88             = "org.objectweb.speedo.generation.jorm.rdb.OneTableRdbJormIMappingBuilder";
89
90     /**
91      * is the name of the index field in the list (Genclass).
92      */

93     public final static String JavaDoc LIST_INDEX = "idx";
94     public final static String JavaDoc MAP_INDEX = "idx";
95
96     /**
97      * is the jorm meta information manager iinside which the Class and the
98      * composite name must be defined.
99      */

100     private Manager manager = null;
101     private NamingManagerFactory nmf;
102
103     private Logger logger = null;
104     private boolean debug = false;
105
106     /**
107      * Builds a JormMIBuilder without a jorm meta information manager
108      * and a logger.
109      */

110     public JormMIBuilder() {
111     }
112
113     /**
114      * Builds a JormMIBuilder with a jorm meta information manager and a logger
115      * @param manager
116      */

117     public JormMIBuilder(Manager manager, Logger logger) {
118         this.manager = manager;
119         this.logger = logger;
120     }
121
122     /**
123      * Builds a JormMIBuilder with a jorm meta information manager and a logger
124      * @param manager
125      */

126     public JormMIBuilder(Manager manager, NamingManagerFactory nmf, Logger logger) {
127         this.manager = manager;
128         this.logger = logger;
129         this.nmf = nmf;
130     }
131
132     /**
133      * retrieves the jorm meta information manager hosting the Class and
134      * CompositeName instances.
135      */

136     public Manager getManager() {
137         return manager;
138     }
139
140     /**
141      * retrieves the jorm meta information manager hosting the Class and
142      * CompositeName instances.
143      */

144     public void setManager(Manager manager) {
145         this.manager = manager;
146     }
147
148     public Logger getLogger() {
149         return logger;
150     }
151
152     public void setLogger(Logger logger) {
153         this.logger = logger;
154     }
155
156     /**
157      * Creates the jorm meta information for a set of persistent classes. Only
158      * the generic part will be created.
159      *
160      * @param scs is a list of SpeedoClass instances.
161      * @return a Collection of jorm meta object composed by Class instances and
162      * CompositeName instances.
163      */

164     public Collection createMI(List JavaDoc scs) throws SpeedoException, PException {
165         return createMI(scs, null, null);
166     }
167
168     /**
169      * Creates the jorm meta information for a set of persistent classes.
170      * @param scs is a list of SpeedoClass instances.
171      * @param projectName is the project name for which the mapping must
172      * be defined. If the value is null no mapping will be generated.
173      * @param mapperName is the mapper name for which the mapping must
174      * be defined. If the value is null no mapping will be generated.
175      * @return a Collection of jorm meta object composed by Class instances and
176      * CompositeName instances.
177      */

178     public Collection createMI(List JavaDoc scs,
179                                String JavaDoc projectName,
180                                String JavaDoc mapperName)
181             throws SpeedoException, PException {
182         JormMIMappingBuilder jmimb = null;
183         String JavaDoc buildercn;
184         if (mapperName != null) {
185             if (mapperName.startsWith("rdb")) {
186                 buildercn = DEFAULT_RDB_BUILDER;
187             } else {
188                 throw new SpeedoException(
189                         "No default JormMIMappingBuilder for the mapper "
190                         + mapperName);
191             }
192             try {
193                 jmimb = (JormMIMappingBuilder)
194                         java.lang.Class.forName(buildercn).newInstance();
195             } catch (Exception JavaDoc e) {
196                 throw new SpeedoException("Impossible to instanciate a the class "
197                         + buildercn);
198             }
199             if (jmimb instanceof Loggable) {
200                 ((Loggable) jmimb).setLogger(logger);
201             }
202         }
203         return createMI(scs, projectName, mapperName, jmimb);
204     }
205     /**
206      * Creates the jorm meta information for a set of persistent classes.
207      * @param scs is a list of SpeedoClass instances.
208      * @param projectName is the project name for which the mapping must
209      * be defined
210      * @param mapperName is the mapper name for which the mapping must
211      * be defined
212      * @param mb is the build of the mapping part of the meta information
213      * @return a Collection of jorm meta object composed by Class instances and
214      * CompositeName instances.
215      */

216     public Collection createMI(List JavaDoc scs,
217                                String JavaDoc projectName,
218                                String JavaDoc mapperName,
219                                JormMIMappingBuilder mb)
220             throws SpeedoException, PException {
221         if (manager == null) {
222             throw new SpeedoException(
223                     "the Jorm meta information manager must be assigned");
224         }
225         int size = scs.size();
226         debug = logger.isLoggable(BasicLevel.DEBUG);
227         ArrayList JavaDoc createdMOs = new ArrayList JavaDoc(size * 2);
228         SpeedoClass sc;
229         String JavaDoc mn;
230         if (mapperName != null) {
231             // take the mapper name without the sub mapper name
232
int idx = mapperName.indexOf(".");
233             mn = (idx != -1 ? mapperName.substring(0, idx) : mapperName);
234         } else {
235             mn = null;
236         }
237
238         // Create Class meta objects
239
for(int i=0; i<size; i++) {
240             sc = (SpeedoClass) scs.get(i);
241             createJormClass(sc, projectName, mn, mb, createdMOs);
242         }
243
244         //Order the list in according to the inheritance order
245
List JavaDoc newscs = new ArrayList JavaDoc(size);
246         if (debug) {
247             logger.log(BasicLevel.DEBUG, "before ordering scs.size()=" + scs.size());
248         }
249         for(int i = 0; i<scs.size();) {
250             sc = (SpeedoClass) scs.get(i);
251             if (sc.superClassName == null) {
252                 //Add classes without parent
253
scs.remove(i);
254                 newscs.add(sc);
255                 if (debug) {
256                     logger.log(BasicLevel.DEBUG, "Class '" + sc.getFQName()
257                         + "' has no parent");
258                 }
259             } else {
260                 i++;
261             }
262         }
263         int idx = 0;
264         while (!scs.isEmpty() && idx < newscs.size()) {
265             //Take an element in the new list
266
sc = (SpeedoClass) newscs.get(idx);
267             if (debug) {
268                 logger.log(BasicLevel.DEBUG, "Find children of the class '" + sc.getFQName() + "'.");
269             }
270             //Search its children in the old list
271
for(int i = 0; i<scs.size();) {
272                 SpeedoClass child = (SpeedoClass) scs.get(i);
273                 if (child.jormclass.getSuperClass(sc.jormclass.getFQName()) != null) {
274                     //It is a child
275
scs.remove(i);
276                     newscs.add(child);
277                     if (debug) {
278                         logger.log(BasicLevel.DEBUG, "Class '"
279                             + child.getFQName() + "' is a child of the class '"
280                             + sc.getFQName() + "'.");
281                     }
282                 } else {
283                     i++;
284                 }
285             }
286             idx ++;
287         }
288         if (debug) {
289             logger.log(BasicLevel.DEBUG, "after ordering scs.size()=" + scs.size());
290             logger.log(BasicLevel.DEBUG, "newscs.size()=" + scs.size());
291         }
292         scs = newscs;
293
294         // Fill the meta information with primitive fields
295
for(int i=0; i<size; i++) {
296             sc = (SpeedoClass) scs.get(i);
297             createPrimitiveField(sc, projectName, mn, mb);
298         }
299         
300         //create parent class mapping and inheritance links
301
for(int i=0; i<size; i++) {
302             sc = (SpeedoClass) scs.get(i);
303             mb.finalizeClassMapping(sc,projectName, mn);
304         }
305         
306         // Define the identifier of classes (list with the inheritance order)
307
for(int i=0; i<size; i++) {
308             sc = (SpeedoClass) scs.get(i);
309             createIdentifierNameDef(sc, projectName, mn, mb, createdMOs);
310         }
311
312         // Fill the meta information with reference fields
313
for(int i=0; i<size; i++) {
314             sc = (SpeedoClass) scs.get(i);
315             createReferences(sc, projectName, mn, mb, createdMOs);
316         }
317
318         //define the mapping of inherited field (list with the inheritance order)
319
for(int i=0; i<size; i++) {
320             sc = (SpeedoClass) scs.get(i);
321             mapInheritance(sc, projectName, mn, mb);
322         }
323
324
325         if (logger.isLoggable(BasicLevel.DEBUG)) {
326             MetaInfoPrinter mip = new MetaInfoPrinter(manager);
327             for(int i=0; i<createdMOs.size(); i++) {
328                 mip.print("", (MetaObject) createdMOs.get(i), logger);
329             }
330         }
331         return createdMOs;
332     }
333
334     /**
335      * Creates the jorm meta information for a persistent class. Only the
336      * primitive fields are defined in the meta information. To define the
337      * references of a persistent object the 'createReferences' method must be
338      * used.
339      * @param sc is the Speedo meta object describing the class which the jorm
340      * meta information must be built.
341      * @param projectName is the project name for which the mapping must
342      * be defined
343      * @param mapperName is the mapper name for which the mapping must
344      * be defined
345      * @param mb is the build of the mapping part of the meta information
346      * @param createdMOs is a result paramter. This collection must be fill with
347      * the created Jorm Meta objects representing a class or a composite name.
348      * Here the meta object of the class will be added. In addition if the name
349      * def of the class is based on a composite name then its meta object will
350      * be added too.
351      */

352     private void createJormClass(SpeedoClass sc,
353                             String JavaDoc projectName,
354                             String JavaDoc mapperName,
355                             JormMIMappingBuilder mb,
356                             Collection createdMOs)
357             throws SpeedoException, PException {
358         Class JavaDoc clazz = manager.getClass(sc.getFQName());
359         if (clazz == null) {
360             clazz = manager.createClass(sc.getFQName());
361             createdMOs.add(clazz);
362         }
363         if (sc.superClassName != null) {
364             SpeedoClass parent = sc.getSpeedoClassFromContext(sc.superClassName);
365             if (parent == null) {
366                 throw new SpeedoException("No super class '"
367                         + sc.superClassName + "'found in the .jdo file: "
368                         + sc.getJDOFileName());
369             }
370             Class JavaDoc parentClazz = manager.getClass(parent.getFQName());
371             if (parentClazz == null) {
372                 parentClazz = manager.createClass(parent.getFQName());
373                 createdMOs.add(parentClazz);
374             }
375             clazz.addSuperClass(parentClazz);
376         }
377         sc.jormclass = clazz;
378         sc.jormclass.setAbstract(sc.isAbstract);
379         if (projectName != null && mapperName != null) {
380             ClassProject cp = clazz.getClassProject(projectName);
381             if (cp == null) {
382                 cp = clazz.createClassProject(projectName);
383             }
384             Mapping mapping = cp.getMapping(mapperName);
385             if (mapping != null) {
386                 //If the mapping is already defined then that means the jorm meta
387
// information has been already defined.
388
// => no meta object has been added.
389
return;
390             }
391             mapping = cp.createMapping(mapperName);
392             mb.createClassMapping(clazz, sc, mapping);
393         }
394     }
395
396     private void createPrimitiveField(SpeedoClass sc,
397                                       String JavaDoc projectName,
398                                       String JavaDoc mapperName,
399                             JormMIMappingBuilder mb)
400             throws SpeedoException, PException {
401         Class JavaDoc clazz = sc.jormclass;
402         ClassMapping cm = clazz.getClassProject(projectName)
403             .getMapping(mapperName).getClassMapping();
404         logger.log(BasicLevel.DEBUG, "Generate the Jorm MI for the class "
405                 + clazz.getFQName());
406         for (Iterator JavaDoc fieldsIt = sc.jdoField.values().iterator();fieldsIt.hasNext();) {
407             SpeedoField sp = (SpeedoField) fieldsIt.next();
408             SpeedoExtension se = sp.getExtensionByKey(
409                     SpeedoProperties.FIELD_CONVERTER);
410             PType ptype = null;
411             String JavaDoc className = null;
412             if (se != null) {
413                 try {
414                     UserFieldMapping ufm = (UserFieldMapping)
415                             java.lang.Class.forName(se.value).newInstance();
416                     ptype = getPrimitivePType(ufm.getStorageType().getName());
417                     if (ptype == null) {
418                         className = ufm.getStorageType().getName();
419                     }
420                 } catch (Exception JavaDoc e) {
421                     throw new SpeedoException(
422                             "Impossible to instanciate the UserFieldMapping class '"
423                             + se.value + "' for the field '" + sp.name
424                             + "' of the class '" + sc.getFQName() + "':", e);
425                 }
426             } else {
427                 Type type = Type.getType(sp.desc);
428                 ptype = getPrimitivePType(type);
429                 if (ptype == null) {
430                     className = type.getClassName();
431                 }
432             }
433             if (ptype == null) {
434                 if (isPersistentClass(className, sc.jdoPackage.name, manager)) {
435                     //reference field
436
continue;
437                 } else {
438                     logger.log(BasicLevel.INFO, "The field '" + sc.getFQName()
439                         + "." + sp.name + " is managed as a Serialized field.");
440                     ptype = PTypeSpace.SERIALIZED;
441                 }
442             }
443             logger.log(BasicLevel.DEBUG, "primitive field: " + sp.name + " / javatype: " + ptype.getJavaName());
444             se = sp.getExtensionByKey(SpeedoProperties.SIZE);
445             int size = PType.NOSIZE;
446             if (se != null) {
447                 try {
448                     size = Integer.parseInt(se.value);
449                 } catch (NumberFormatException JavaDoc e) {
450                     logger.log(BasicLevel.ERROR,
451                         "The specified size for the field '"
452                         + sp.name + "' of the class '" + sc.getFQName()
453                         + "' cannot be parsed: " + se.value, e);
454                 }
455             }
456             int scale = PType.NOSIZE;
457             se = sp.getExtensionByKey(SpeedoProperties.SCALE);
458             if (se != null) {
459                 try {
460                     scale = Integer.parseInt(se.value);
461                 } catch (NumberFormatException JavaDoc e) {
462                     logger.log(BasicLevel.ERROR,
463                         "The specified scale for the field '"
464                         + sp.name + "' of the class '" + sc.getFQName()
465                         + "' cannot be parsed: " + se.value, e);
466                 }
467             }
468             PrimitiveElement pe = clazz.createPrimitiveElement(
469                 sp.name, ptype, size, scale);
470             if (cm != null && mb != null) {
471                 mb.createFieldMapping(pe, sp, cm);
472             }
473         }
474     }
475
476     /**
477      * Creates the identifier name and its mapping for a persistent class.
478      * @param sc is the SpeedoClass meta object describing the persistent which
479      * the identifier has to be defined.
480      * @param projectName is the jorm project name
481      * @param mapperName is the mapper name
482      * @param mb is the builder of the Jorm Mapping meta info
483      * @param createdMOs is the list of created meta object (Class or
484      * CompositeName).
485      * @return a boolean value indicating if the identifier has been created. In
486      * the inheritance case the identifier is inherited from the parent. If the
487      * parent identifier is not defined, it is not possible to create the
488      * identifier of the specified persistent class.
489      */

490     private boolean createIdentifierNameDef(SpeedoClass sc,
491                                       String JavaDoc projectName,
492                                       String JavaDoc mapperName,
493                             JormMIMappingBuilder mb,
494                             Collection createdMOs)
495             throws SpeedoException, PException {
496         ClassMapping cm = sc.jormclass.getClassProject(projectName)
497             .getMapping(mapperName).getClassMapping();
498         NameDef classNd = null;
499         IdentifierMapping im = cm.getIdentifierMapping();
500         if (im != null) {
501             classNd = (NameDef) im.getLinkedMO();
502             if (classNd != null) {
503                 return true;
504             }
505         }
506         if (sc.superClassName == null) {
507             classNd = sc.jormclass.createNameDef();
508             fillNameDef(classNd, sc, sc, sc.jormclass, null, cm, mb, true, false,
509                 sc.identityType == SpeedoIdentity.CONTAINER_ID, createdMOs);
510             if (cm != null) {
511                 cm.createIdentifierMapping(classNd);
512             }
513         } else {
514             SpeedoClass parent = sc.getSpeedoClassFromContext(sc.superClassName);
515             im = parent.jormclass
516                 .getClassProject(projectName).getMapping(mapperName)
517                 .getClassMapping().getIdentifierMapping();
518             if (im != null) {
519                 classNd = (NameDef) im.getLinkedMO();
520                 if (classNd != null) {
521                     cm.createIdentifierMapping(classNd);
522                 }
523             }
524         }
525         if (debug) {
526             logger.log(BasicLevel.DEBUG, "Create the identifier of the class '"
527                 + sc.getFQName() + "'"
528                 + (sc.superClassName == null ? ""
529                 : "(parent class name='" + sc.superClassName + "')")
530                 + ", namedef=" + classNd + ".");
531         }
532         return classNd != null;
533     }
534
535     /**
536      * Builds the jorm meta objects representing the references of a persitent
537      * class. It is supposed that if the reference targets a persistent class,
538      * then the Class meta object and its NameDef are already defined.
539      * @param sc is the Speedo meta object describing the class which the jorm
540      * meta information must be built.
541      * @param projectName is the project name for which the mapping must
542      * be defined
543      * @param mapperName is the mapper name for which the mapping must
544      * be defined
545      * @param mb is the build of the mapping part of the meta information
546      * @param createdMOs is a result paramter. This collection must be fill with
547      * the created Jorm Meta objects representing a class or a composite name.
548      * Here only the new used composite name will be added.
549      */

550     private void createReferences(SpeedoClass sc,
551                                  String JavaDoc projectName,
552                                  String JavaDoc mapperName,
553                                  JormMIMappingBuilder mb,
554                                  Collection createdMOs)
555             throws SpeedoException, PException {
556         Class JavaDoc clazz = manager.getClass(sc.getFQName());
557         logger.log(BasicLevel.DEBUG, "Generate the Jorm MI for the references of class "
558                 + clazz.getFQName());
559         Mapping mapping = null;
560         ClassMapping cm = null;
561         if (projectName != null && mapperName != null) {
562             mapping = clazz.getClassProject(projectName)
563                 .getMapping(mapperName);
564             cm = mapping.getClassMapping();
565         }
566         Iterator JavaDoc fieldsIt = sc.jdoField.values().iterator();
567         //System.out.println("Manage reference of the class " + sc.getFQName());
568
while (fieldsIt.hasNext()) {
569             SpeedoField sp = (SpeedoField) fieldsIt.next();
570             if (clazz.getTypedElement(sp.name) != null) {
571                 //the primitive element is already managed before(createJormClass)
572
continue;
573             }
574             Type t = Type.getType(sp.desc);
575             String JavaDoc javatype = t.getClassName();
576             if (!isGenClassRef(javatype)) {
577                 // reference to a class //
578
//============================================================//
579
if (debug) {
580                     logger.log(BasicLevel.DEBUG, "Class reference field: "
581                         + sp.name + " / javatype: " + javatype);
582                 }
583                 // reference to a class
584
SpeedoClass tsc = sc.jdoPackage.jdoXMLDescriptor
585                         .getSpeedoClass(javatype, true);
586                 if (tsc == null) {
587                     throw new SpeedoException("No persistent class '"
588                             + javatype + "' found in the file: "
589                             + sc.jdoPackage.jdoXMLDescriptor.xmlFile);
590                 }
591                 Class JavaDoc tclass = manager.getClass(tsc.getFQName());
592                 if (tclass == null) {
593                     manager.createClass(tsc.getFQName());
594                 }
595                 ClassRef cr = clazz.createClassRef(sp.name, tclass);
596                 NameDef refNd = cr.createRefNameDef();
597                 fillNameDef(refNd, tsc, sc, clazz, cr, cm, mb, false, false, true, createdMOs);
598                 if ( cm != null) {
599                     cm.createReferenceMapping(sp.name, refNd);
600                     cm.addDependency(tsc.getFQName());
601                 }
602
603             } else {
604                 // reference to a generic class //
605
//============================================================//
606
String JavaDoc innerType = getInnerType(sp);
607                 if (innerType == null) {
608                     throw new SpeedoException("The inner element type is " +
609                             "required for the multivalued field '" + sp.name
610                             + "' of the class '" + sc.getFQName()
611                             + "' in the .jdo file '"
612                             + sc.jdoPackage.jdoXMLDescriptor.xmlFile + "'");
613                 }
614                 PType type = getPrimitivePType(innerType);
615                 if (type == null && !isPersistentClass(innerType, sc.jdoPackage.name, manager)) {
616                     logger.log(BasicLevel.INFO, "The field '" + sc.getFQName()
617                             + "." + sp.name + " is managed as a Serialized field.");
618                     type = PTypeSpace.SERIALIZED;
619                 }
620                 if (debug) {
621                     logger.log(BasicLevel.DEBUG, "GenClass reference field: "
622                         + sp.name + " / javatype: " + javatype
623                         + " / innerType: " + innerType
624                         + " / ptype=" + (type == null ? null : type.getJavaName()));
625                 }
626                 GenClassRef gcr = clazz.createGenClassRef(sp.name, javatype);
627                 GenClassMapping gcm = null;
628                 ClassRef cr = null;
629                 SpeedoClass tsc = null;
630
631                 //element of the gen class
632
if (type != null) {
633                     // gen class of primitive type
634
gcr.createPrimitiveElement(type, PType.NOSIZE, PType.NOSIZE);
635                 } else if (!isGenClassRef(innerType)) {
636                     // gen class of classref
637
tsc = sc.jdoPackage.jdoXMLDescriptor.smi
638                             .getSpeedoClass(innerType, sc.jdoPackage);
639                     if (tsc == null) {
640                         throw new SpeedoException("The persistent class '"
641                                 + sc.getFQName()
642                                 + "' tries to reference (througth the field '"
643                                 + sp.name
644                                 + "') the class '" + innerType
645                                 + "' not defined in the .jdo file '"
646                                 + sc.jdoPackage.jdoXMLDescriptor.xmlFile + "'");
647                     }
648                     Class JavaDoc tclass = manager.getClass(tsc.getFQName());
649                     if (tclass == null) {
650                         throw new SpeedoException("The inner element class '"
651                             + tsc.getFQName() + "' of the multivalued field '"
652                             + sp.name + "' of the class '" + sc.getFQName()
653                             + "' in the .jdo file '"
654                             + sc.jdoPackage.jdoXMLDescriptor.xmlFile
655                                 + "' has not been found among the persitent classes : "
656                             + manager.getClasses());
657                     }
658                     cr = gcr.createClassRef(tclass);
659                 } else {
660                     throw new SpeedoException(
661                             "unmanaged the inner-element of the field '"
662                             + sp.name + "' of the class '" + sc.getFQName()
663                             + "' : " + innerType);
664                 }
665                 //Map the element of the generic class
666
if (mapping != null) {
667                     gcm = mb.createGenClassMapping(gcr, sp, mapping);
668                     if (gcr.isPrimitive()) {
669                         mb.createFieldMapping(gcr.getPrimitiveElement(), null, gcm);
670                     } else {
671                         NameDef elemNd = cr.createRefNameDef();
672                         fillNameDef(elemNd, tsc, sc, gcr, gcr, gcm, mb, false, true, true, createdMOs);
673                         gcm.createReferenceMapping(sp.name, elemNd);
674                         cm.addDependency(tsc.getFQName());
675                     }
676                 }
677
678                 // reference to a generic class from the class
679
NameDef refNd = gcr.createRefNameDef();
680                 fillNameDef(refNd, sc, sc, clazz, gcr, cm, mb, false, false, false, createdMOs);
681                 if (cm != null) {
682                     cm.createReferenceMapping(sp.name, refNd);
683                 }
684
685                 //identifier of the gen class
686
NameDef gcidNd = gcr.createIdNameDef();
687                 fillNameDef(gcidNd, sc, sc, gcr, gcr, gcm, mb, true, true, true, createdMOs);
688                 if (gcm != null) {
689                     gcm.createIdentifierMapping(gcidNd);
690                 }
691
692                 //index of the gen class
693
java.lang.Class JavaDoc gcClass;
694                 try {
695                     gcClass = java.lang.Class.forName(javatype);
696                 } catch (ClassNotFoundException JavaDoc e) {
697                     throw new SpeedoException(
698                             "The multivalued field '" + sp.name
699                             + "' of the class '" + sc.getFQName()
700                             + "' is not a well known class " + javatype, e);
701                 }
702                 if (isSubType(gcClass, java.util.List JavaDoc.class)) {
703                     PrimitiveElement pe = gcr.createHiddenField(
704                             LIST_INDEX, PTypeSpace.INT, PType.NOSIZE, PType.NOSIZE);
705                     if (gcm != null) {
706                         mb.createFieldMapping(pe, sp, gcm);
707                     }
708                     gcr.addIndexField(LIST_INDEX);
709                 } else if (isSubType(gcClass, java.util.Map JavaDoc.class)) {
710                     String JavaDoc keyfield = sp.getExtensionValueByKey(SpeedoProperties.KEY_FIELD);
711                     if (keyfield == null) {
712                         keyfield = MAP_INDEX;
713                     }
714                     PrimitiveElement pe = gcr.createHiddenField(
715                             keyfield, getMapKeyPType(sp), PType.NOSIZE, PType.NOSIZE);
716                     if (gcm != null) {
717                         mb.createFieldMapping(pe, sp, gcm);
718                     }
719                     gcr.addIndexField(pe.getName());
720                 }
721             }
722         }
723
724     }
725
726     private void mapInheritance(SpeedoClass sc,
727                                  String JavaDoc projectName,
728                                  String JavaDoc mapperName,
729                                  JormMIMappingBuilder mb)
730         throws SpeedoException, PException {
731         ClassMapping cm = sc.jormclass.getClassProject(projectName)
732             .getMapping(mapperName).getClassMapping();
733         NameDef nd = (NameDef) cm.getIdentifierMapping().getLinkedMO();
734
735         String JavaDoc filter = sc.getExtensionValueByKey(SpeedoProperties.INHERITANCE_FILTER);
736         if (filter != null && filter.length() > 0) {
737             logger.log(BasicLevel.DEBUG, "Assign filter " + filter + ")");
738             sc.jormclass.setInheritanceFilter(nd, filter);
739         }
740
741         String JavaDoc key = sc.getExtensionValueByKey(SpeedoProperties.INHERITANCE_KEY);
742         if (key != null && key.length() > 0) {
743             sc.jormclass.setInheritanceNamingKey(nd, key);
744         }
745         if (sc.superClassName == null) {
746             return;
747         }
748         SpeedoClass parent = sc.getSpeedoClassFromContext(sc.superClassName);
749         String JavaDoc im = sc.getExtensionValueByKey(SpeedoProperties.INHERITANCE_MAPPING);
750
751         // Map the inherited field if required
752
if (SpeedoProperties.INHERITANCE_HORIZONTAL_MAPPING.equals(im)) {
753             //Map all visible fields
754
Collection tes = parent.jormclass.getAllFields();
755             Iterator JavaDoc it = tes.iterator();
756             while(it.hasNext()) {
757                 TypedElement te = (TypedElement) it.next();
758                 Class JavaDoc ancestor = (Class JavaDoc) te.getParent();
759                 if (debug) {
760                     logger.log(BasicLevel.DEBUG, "Map the inherited field '"
761                         + te.getName() + "' from the super class '"
762                         + ancestor.getFQName() + "'.");
763                 }
764                 if (te instanceof PrimitiveElement) {
765                     //The mapping specification( sql name, sql type) are defined
766
// as extensions of the current SpeedoClass: sc
767
mb.createFieldMapping((PrimitiveElement) te, sc, cm);
768                 } else {
769                     //Use the same NameDef for the reference
770
ClassMapping acm = ancestor.getClassProject(projectName)
771                         .getMapping(mapperName).getClassMapping();
772                     ReferenceMapping rm = acm.getReferenceMapping(te.getName());
773                     cm.createReferenceMapping(rm.getRuleName(), (NameDef) rm.getLinkedMO());
774                 }
775             }
776             //Map all hidden fields
777
tes = parent.jormclass.getAllHiddenFields();
778             it = tes.iterator();
779             while(it.hasNext()) {
780                 TypedElement te = (TypedElement) it.next();
781                 Class JavaDoc jancestor = (Class JavaDoc) te.getParent();
782                 if (debug) {
783                     logger.log(BasicLevel.DEBUG, "Map the inherited hidden field '"
784                         + te.getName() + "' from the super class '"
785                         + jancestor.getFQName() + "'.");
786                 }
787                 SpeedoClass ancestor = sc.getSpeedoClassFromContext(
788                     jancestor.getFQName());
789                 mb.createFieldMapping((PrimitiveElement) te, ancestor, cm);
790             }
791         }
792     }
793
794     private boolean isSubType(java.lang.Class JavaDoc c1, java.lang.Class JavaDoc c2) {
795         if (c1 == null) {
796             return false;
797         }
798         if (c1 == c2) {
799             return true;
800         }
801         if (c2.isInterface()) {
802             java.lang.Class JavaDoc[] cs = c1.getInterfaces();
803             for(int i = 0; i<cs.length; i++) {
804                 if (isSubType(cs[i], c2)) {
805                     return true;
806                 }
807             }
808         }
809         return isSubType(c1.getSuperclass(), c2);
810     }
811
812     private PType getMapKeyPType(SpeedoField sf) throws SpeedoException {
813         SpeedoMap sm = (SpeedoMap) sf.jdoTuple;
814         if (sm.keyType == null) {
815             throw new SpeedoException(
816                 "It is required to define a key-type for the Map field'"
817                 + sf.name + "' of the class '" + sf.jdoClass.getFQName() +"' ");
818         }
819         PType res = getPrimitivePType((String JavaDoc) sm.keyType);
820         boolean isPersistClass = isPersistentClass(
821             (String JavaDoc) sm.keyType, sf.jdoClass.jdoPackage.name, manager);
822         if (res == null && !isPersistClass) {
823             logger.log(BasicLevel.INFO, "The field '" + sf.jdoClass.getFQName()
824                     + "." + sf.name + " is managed as a Serialized field.");
825             res = PTypeSpace.SERIALIZED;
826         }
827         if (res == null) {
828             throw new SpeedoException("The key-type '" + sm.keyType
829                     + "' of the Map field'" + sf.name + "' of the class '"
830                     + sf.jdoClass.getFQName() +"' is not supported");
831         }
832         return res;
833     }
834
835     /**
836      * Fill the name def of an identifier or a reference
837      * @param nd is the name def to fill
838      * @param isIdentifier indicates if the name represents an identifier (true)
839      * or a reference (false).
840      * @param isInGenClass indicates if the name is defined in a generic class
841      * (true) of in a class (false).
842      * @param ref meta object which the name def must be
843      * defined. This value is used only in the case of isIdentifier == false and
844      * isInGenClass == false.
845      * @param tsc is the speedo meta object representing the referenced class.
846      * This value is used only in the case of isIdentifier == false.
847      * @param mo is the jorm meta object hosting the name def and on which the
848      * eventual hidden field will be created.
849      * @param hcm if the mapping structure hosting the mapping of the reference.
850      * This value must be ClassMapping or GenClassMapping instance.
851      * @param mb is the mapping builder permitting the creation of the mapping
852      * part.
853      * @param createdMOs is a result paramter. This collection must be fill with
854      * the created Jorm Meta objects representing a class or a composite name.
855      * Here only the new used composite name will be added.
856      * @throws SpeedoException if the speedo meta information is not completly
857      * defined.
858      */

859     private void fillNameDef(NameDef nd,
860                              SpeedoClass tsc,
861                              SpeedoClass ssc,
862                              MetaObject mo,
863                              Reference ref,
864                              CommonClassMapping hcm,
865                              JormMIMappingBuilder mb,
866                              boolean isIdentifier,
867                              boolean isInGenClass,
868                              boolean createField,
869                              Collection createdMOs)
870             throws SpeedoException, PException {
871         nmf.getNamingManager(tsc)
872                 .fillNameDef(this,manager, nd, tsc, ssc, mo, ref, hcm,
873                         mb, isIdentifier, isInGenClass, createField, createdMOs);
874     }
875
876     /**
877      * Calculates the prefix of a field use in a name def.
878      * @param ref is the meta object of the reference if the namedef is
879      * used for a reference.
880      * @param isIdentifier indicates if the namedef is used for an identifier
881      * (true) or if the namedef is used for a reference (false).
882      * @param isInGenClass indicates if the namedef is used in a Generic class
883      * (true) or if the namedef is used in a class (false).
884      * @return a string value (never null) representing the prefix of a name
885      * def field.
886      */

887     public String JavaDoc getNameDefFieldPrefix(Reference ref,
888                                          boolean isIdentifier,
889                                          boolean isInGenClass) {
890         if (isIdentifier) {
891             return "";
892         } else {
893             if (isInGenClass) {
894                 return GENCLASS_ELM_PREFIX;
895             } else {
896                 if (ref instanceof GenClassRef) {
897                     //The reference of the GCR is mapped over the class identifer
898
// fields
899
return "";
900                 } else {
901                     return ref.getName() + '_';
902                 }
903             }
904         }
905     }
906
907     /**
908      * It creates a field of a name def. This field will be hidden
909      * @param mo is the jorm meta object hosting the field to create
910      * @param fn is the name of the field to create
911      * @param type is the type of the field to create
912      * @param size is the size of the field to create
913      * @return the jorm meta object representing the namedef field
914      */

915     public ScalarField createNameDefField(MetaObject mo,
916                                           String JavaDoc fn,
917                                           PType type, int size, int scale)
918             throws SpeedoException {
919         ScalarField sf;
920         if (mo instanceof Class JavaDoc) {
921             sf = ((Class JavaDoc) mo).createHiddenField(fn, type, size, scale);
922         } else if (mo instanceof GenClassRef) {
923             sf = ((GenClassRef) mo).createHiddenField(fn, type, size, scale);
924         } else {
925             throw new SpeedoException(
926                     "Impossible to create hidden field on this meta object: " + mo);
927         }
928         return sf;
929     }
930
931     /**
932      * It creates a field of a name def. This field will be hidden
933      * @param mo is the jorm meta object hosting the field to create
934      * @param fn is the name of the field to create
935      * @param type is the type of the field to create
936      * @return the jorm meta object representing the namedef field
937      */

938     public ScalarField createNameDefField(MetaObject mo,
939                                           String JavaDoc fn,
940                                           PType type)
941             throws SpeedoException {
942         return createNameDefField(mo, fn, type, PType.NOSIZE, PType.NOSIZE);
943     }
944
945     /**
946      * Retrieves the jorm type matching to primitive type. It converts a Type
947      * defined in ASM into a PType defined in Jorm. If the type is not a jorm
948      * primitive type then a null value is returned.
949      */

950     public PType getPrimitivePType(Type t) {
951         switch (t.getSort()) {
952         case Type.BOOLEAN:
953             return PTypeSpace.BOOLEAN;
954         case Type.CHAR:
955             return PTypeSpace.CHAR;
956         case Type.BYTE:
957             return PTypeSpace.BYTE;
958         case Type.SHORT:
959             return PTypeSpace.SHORT;
960         case Type.INT:
961             return PTypeSpace.INT;
962         case Type.FLOAT:
963             return PTypeSpace.FLOAT;
964         case Type.LONG:
965             return PTypeSpace.LONG;
966         case Type.DOUBLE:
967             return PTypeSpace.DOUBLE;
968         case Type.ARRAY:
969             PType innerType = getPrimitivePType(t.getElementType());
970             if (innerType !=null) {
971                 if (innerType == PTypeSpace.CHAR) {
972                     return PTypeSpace.CHARARRAY;
973                 } else if (innerType == PTypeSpace.BYTE) {
974                     return PTypeSpace.BYTEARRAY;
975                 } else {
976                     return PTypeSpace.SERIALIZED;
977                 }
978             }
979             return null;
980         default:
981         case Type.OBJECT:
982             String JavaDoc cn = t.getClassName();
983             PType res = getPrimitivePType(cn);
984             if (res == null && !isPersistentClass(cn, null, manager)) {
985                 return PTypeSpace.SERIALIZED;
986             } else {
987                 return res;
988             }
989         }
990     }
991
992     private PType getPrimitivePType(String JavaDoc cn) {
993         for (int i = 0; i < PTypeSpace.PREDEFINEDPTYPES.length; i++) {
994             if (PTypeSpace.PREDEFINEDPTYPES[i] != PTypeSpace.REFTOP
995                 && PTypeSpace.PREDEFINEDPTYPES[i].getJavaName().equals(cn)) {
996                 return PTypeSpace.PREDEFINEDPTYPES[i];
997             }
998         }
999         if (java.sql.Date JavaDoc.class.getName().equals(cn)) {
1000            return PTypeSpace.DATE;
1001        } else if (java.sql.Time JavaDoc.class.getName().equals(cn)) {
1002            return PTypeSpace.DATE;
1003        } else if (java.sql.Timestamp JavaDoc.class.getName().equals(cn)) {
1004            return PTypeSpace.DATE;
1005        } else if (java.util.Locale JavaDoc.class.getName().equals(cn)) {
1006            return PTypeSpace.STRING;
1007        } else {
1008            return null;
1009        }
1010    }
1011
1012    private boolean isPersistentClass(String JavaDoc cn, String JavaDoc currentPackage, Manager manager) {
1013        if (isGenClassRef(cn)) {
1014            return true;
1015        }
1016        if (cn.indexOf('.') != -1 || currentPackage == null) {
1017            return manager.getClass(cn) != null;
1018        } else {
1019            return manager.getClass(currentPackage + '.' + cn) != null;
1020        }
1021    }
1022
1023    /**
1024     * Indicates if the string representing a java type is a generic class (
1025     * java.util.Collection | java.util.Set | java.util.Map
1026     * @param javatype
1027     * @return
1028     */

1029    private boolean isGenClassRef(String JavaDoc javatype) {
1030        int i=0;
1031        while(i<ProxyGenerator.GC_IMPL .length
1032                && !ProxyGenerator.GC_IMPL[i][0].equals(javatype)) {
1033            i++;
1034        }
1035        return i<ProxyGenerator.GC_IMPL .length;
1036    }
1037
1038    /**
1039     * Retrieves the type of a generic class element.
1040     * @param sp is the field which represents the generic class
1041     * @return a String value representing the java type of the element, or null
1042     * if the Speedofield does not represents a generic class.
1043     */

1044    private String JavaDoc getInnerType(SpeedoField sp) {
1045        if (sp.jdoTuple instanceof SpeedoCollection) {
1046            return (String JavaDoc) ((SpeedoCollection) sp.jdoTuple).elementType;
1047        } else if (sp.jdoTuple instanceof SpeedoMap) {
1048            return (String JavaDoc) ((SpeedoMap) sp.jdoTuple).valueType;
1049        }
1050        return null;
1051    }
1052
1053
1054    /**
1055     * retrieves the start of a pretty error message.
1056     */

1057    public String JavaDoc getErrorMessage(SpeedoClass sc, MetaObject mo, Reference ref) {
1058        String JavaDoc fqcn;
1059        if (mo == null) {
1060            fqcn = "null";
1061        } else if (mo instanceof Class JavaDoc) {
1062            fqcn = ((Class JavaDoc) mo).getFQName();
1063        } else if (mo instanceof GenClassRef) {
1064            fqcn = ((GenClassRef) mo).getGenClassId();
1065        } else {
1066            fqcn = mo.toString();
1067        }
1068        String JavaDoc res = "Impossible to define an user identifier for the ";
1069        if (ref == null) {
1070            res += "identifier of the class '" + fqcn;
1071        } else {
1072            res += "reference '" + ref.getName()
1073                    + "' from the class '" + fqcn
1074                    + "' to the class '" + sc.getFQName();
1075        }
1076        return res + "': ";
1077    }
1078
1079    public PrimitiveElement getPrimitiveField(MetaObject mo, String JavaDoc name) {
1080        if (mo instanceof Class JavaDoc) {
1081            return (PrimitiveElement) ((Class JavaDoc) mo).getTypedElement(name);
1082        } else if (mo instanceof GenClassRef) {
1083            return ((GenClassRef) mo).getHiddenField(name);
1084        } else {
1085            return null;
1086        }
1087    }
1088}
1089
Popular Tags