| 1 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 ; 59 import java.util.ArrayList ; 60 import java.util.Iterator ; 61 import java.util.List ; 62 63 75 public class JormMIBuilder implements MIBuilderHelper { 76 77 80 public final static String GENCLASS_ID_PREFIX = "id_"; 81 82 85 public final static String GENCLASS_ELM_PREFIX = "elem_"; 86 87 public final static String DEFAULT_RDB_BUILDER 88 = "org.objectweb.speedo.generation.jorm.rdb.OneTableRdbJormIMappingBuilder"; 89 90 93 public final static String LIST_INDEX = "idx"; 94 public final static String MAP_INDEX = "idx"; 95 96 100 private Manager manager = null; 101 private NamingManagerFactory nmf; 102 103 private Logger logger = null; 104 private boolean debug = false; 105 106 110 public JormMIBuilder() { 111 } 112 113 117 public JormMIBuilder(Manager manager, Logger logger) { 118 this.manager = manager; 119 this.logger = logger; 120 } 121 122 126 public JormMIBuilder(Manager manager, NamingManagerFactory nmf, Logger logger) { 127 this.manager = manager; 128 this.logger = logger; 129 this.nmf = nmf; 130 } 131 132 136 public Manager getManager() { 137 return manager; 138 } 139 140 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 164 public Collection createMI(List scs) throws SpeedoException, PException { 165 return createMI(scs, null, null); 166 } 167 168 178 public Collection createMI(List scs, 179 String projectName, 180 String mapperName) 181 throws SpeedoException, PException { 182 JormMIMappingBuilder jmimb = null; 183 String 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 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 216 public Collection createMI(List scs, 217 String projectName, 218 String 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 createdMOs = new ArrayList (size * 2); 228 SpeedoClass sc; 229 String mn; 230 if (mapperName != null) { 231 int idx = mapperName.indexOf("."); 233 mn = (idx != -1 ? mapperName.substring(0, idx) : mapperName); 234 } else { 235 mn = null; 236 } 237 238 for(int i=0; i<size; i++) { 240 sc = (SpeedoClass) scs.get(i); 241 createJormClass(sc, projectName, mn, mb, createdMOs); 242 } 243 244 List newscs = new ArrayList (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 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 sc = (SpeedoClass) newscs.get(idx); 267 if (debug) { 268 logger.log(BasicLevel.DEBUG, "Find children of the class '" + sc.getFQName() + "'."); 269 } 270 for(int i = 0; i<scs.size();) { 272 SpeedoClass child = (SpeedoClass) scs.get(i); 273 if (child.jormclass.getSuperClass(sc.jormclass.getFQName()) != null) { 274 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 for(int i=0; i<size; i++) { 296 sc = (SpeedoClass) scs.get(i); 297 createPrimitiveField(sc, projectName, mn, mb); 298 } 299 300 for(int i=0; i<size; i++) { 302 sc = (SpeedoClass) scs.get(i); 303 mb.finalizeClassMapping(sc,projectName, mn); 304 } 305 306 for(int i=0; i<size; i++) { 308 sc = (SpeedoClass) scs.get(i); 309 createIdentifierNameDef(sc, projectName, mn, mb, createdMOs); 310 } 311 312 for(int i=0; i<size; i++) { 314 sc = (SpeedoClass) scs.get(i); 315 createReferences(sc, projectName, mn, mb, createdMOs); 316 } 317 318 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 352 private void createJormClass(SpeedoClass sc, 353 String projectName, 354 String mapperName, 355 JormMIMappingBuilder mb, 356 Collection createdMOs) 357 throws SpeedoException, PException { 358 Class 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 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 return; 390 } 391 mapping = cp.createMapping(mapperName); 392 mb.createClassMapping(clazz, sc, mapping); 393 } 394 } 395 396 private void createPrimitiveField(SpeedoClass sc, 397 String projectName, 398 String mapperName, 399 JormMIMappingBuilder mb) 400 throws SpeedoException, PException { 401 Class 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 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 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 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 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 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 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 490 private boolean createIdentifierNameDef(SpeedoClass sc, 491 String projectName, 492 String 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 550 private void createReferences(SpeedoClass sc, 551 String projectName, 552 String mapperName, 553 JormMIMappingBuilder mb, 554 Collection createdMOs) 555 throws SpeedoException, PException { 556 Class 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 fieldsIt = sc.jdoField.values().iterator(); 567 while (fieldsIt.hasNext()) { 569 SpeedoField sp = (SpeedoField) fieldsIt.next(); 570 if (clazz.getTypedElement(sp.name) != null) { 571 continue; 573 } 574 Type t = Type.getType(sp.desc); 575 String javatype = t.getClassName(); 576 if (!isGenClassRef(javatype)) { 577 if (debug) { 580 logger.log(BasicLevel.DEBUG, "Class reference field: " 581 + sp.name + " / javatype: " + javatype); 582 } 583 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 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 String 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 if (type != null) { 633 gcr.createPrimitiveElement(type, PType.NOSIZE, PType.NOSIZE); 635 } else if (!isGenClassRef(innerType)) { 636 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 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 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 NameDef refNd = gcr.createRefNameDef(); 680 fillNameDef(refNd, sc, sc, clazz, gcr, cm, mb, false, false, false, createdMOs); 681 if (cm != |