1 2 12 package com.versant.core.metadata; 13 14 import com.versant.core.common.Debug; 15 import com.versant.core.common.config.ConfigInfo; 16 import com.versant.core.jdo.QueryDetails; 17 import com.versant.core.jdo.sco.VersantSCOFactoryRegistry; 18 import com.versant.core.metadata.parser.*; 19 import com.versant.core.jdo.query.ParseException; 20 import com.versant.core.jdo.query.QueryParser; 21 import com.versant.core.jdo.externalizer.Externalizer; 22 import com.versant.core.jdo.externalizer.SerializedExternalizer; 23 import com.versant.core.jdo.externalizer.TypeAsBytesExternalizer; 24 import com.versant.core.jdo.externalizer.TypeAsStringExternalizer; 25 import com.versant.core.util.classhelper.ClassHelper; 26 import com.versant.core.util.BeanUtils; 27 import com.versant.core.util.IntArray; 28 29 import java.io.Serializable ; 30 import java.lang.reflect.*; 31 import java.util.*; 32 33 import com.versant.core.common.BindingSupportImpl; 34 35 40 public class MetaDataBuilder implements MDStatics { 41 42 protected final ConfigInfo config; 43 protected final ClassLoader loader; 44 protected final boolean quiet; 45 protected final ModelMetaData jmd; 46 47 private MetaDataPreProcessor metaDataPreProcessor; 48 49 private final MetaDataEnums MDE = new MetaDataEnums(); 50 51 protected final MetaDataUtils mdutils = new MetaDataUtils(); 52 protected final VersantSCOFactoryRegistry scoFactoryRegistry; 53 54 private Map appIdUniqueMap = new HashMap(); 55 private Map externalizerMap = new HashMap(); 56 57 private PackageMetaData[] packageMetaData; 58 private HashMap classMap = new HashMap(); private HashMap classInfoMap = new HashMap(); private HashMap interfaceMap = new HashMap(); private HashMap classAndInterfaceMap = new HashMap(); 62 64 private final FetchGroupBuilder fetchGroupBuilder; 65 private final QueryParser queryParser; 66 private static final String ARRAY_SUFFIX = "[]"; 67 68 72 private static class PackageMetaData { 73 74 public String nameWithDot; 75 public JdoPackage jdoPackage; 76 } 77 78 82 private static class ClassInfo { 83 84 public boolean refsInDefaultFetchGroup; 85 public JdoClass jdoClass; 86 public ArrayList horizontalFields; 87 } 88 89 public MetaDataBuilder(ConfigInfo config, ClassLoader loader, 90 boolean quiet) { 91 this.config = config; 92 this.loader = loader; 93 this.quiet = quiet; 94 jmd = new ModelMetaData(); 95 jmd.testing = config.testing; 96 fetchGroupBuilder = createFetchGroupBuilder(); 97 queryParser = new QueryParser(jmd); 98 scoFactoryRegistry = new VersantSCOFactoryRegistry( 99 config.scoFactoryRegistryMappings, loader); 100 101 102 if (config.metaDataPreProcessor == null) 103 config.metaDataPreProcessor = EJB_JDBC_PRE_PROCESSOR; 104 105 106 if (config.metaDataPreProcessor != null) { 107 try { 108 Class cls = loadClass(config.metaDataPreProcessor); 109 metaDataPreProcessor = (MetaDataPreProcessor) cls.getConstructor( 110 new Class [] {ClassLoader .class, MetaDataUtils.class}). 111 newInstance(new Object [] {loader, mdutils}); 112 } catch (Throwable e) { 113 System.out.println("Unable to load 'metaDataPreProcessor' class '" 114 + config.metaDataPreProcessor + "'"); 115 } 116 } 117 } 118 119 protected FetchGroupBuilder createFetchGroupBuilder() { 120 return new FetchGroupBuilder(jmd, 121 isSendCurrentForFGWithSecFields(), isReadObjectBeforeWrite()); 122 } 123 124 public FetchGroupBuilder getFetchGroupBuilder() { 125 return fetchGroupBuilder; 126 } 127 128 129 130 133 public ModelMetaData buildMetaData(JdoRoot[] roots) { 134 135 fillExternalizerMap(); 137 138 JdoRoot jdoRoot = buildSingleJdoRoot(roots); 140 141 int n = jdoRoot.packages.length; 143 packageMetaData = new PackageMetaData[n]; 144 for (int i = 0; i < n; i++) { 145 packageMetaData[i] = createPackageMetaData(jdoRoot.packages[i]); 146 } 147 148 if (Debug.DEBUG) { 150 System.out.println( 151 "MDB: Creating initial meta data for all classes and interfaces"); 152 } 153 154 ClassMetaData[] classes = jmd.classes = new ClassMetaData[jmd.classResourceMap.size()]; 155 for (int i = 0, c = 0; i < packageMetaData.length; i++) { 156 PackageMetaData pmd = packageMetaData[i]; 157 JdoClass[] ca = pmd.jdoPackage.classes; 158 for (int j = 0; j < ca.length; j++) { 159 if (metaDataPreProcessor != null) metaDataPreProcessor.process(ca[j]); 160 ClassMetaData cmd = createMetaData(pmd, ca[j], quiet); 161 classes[c++] = cmd; 162 classMap.put(cmd.cls, cmd); 163 } 164 JdoExtension[] extensions = pmd.jdoPackage.extensions; 165 if (extensions != null) { 166 for (int j = 0; j < extensions.length; j++) { 167 JdoExtension e = extensions[j]; 168 if (e.key == JdoExtensionKeys.INTERFACE) { 169 InterfaceMetaData imd = createInterfaceMetaData(pmd, e); 170 interfaceMap.put(imd.cls, imd); 171 } 172 } 173 } 174 } 175 jmd.buildObjectIdClassMap(); 176 jmd.buildAbstractSchemaNameMap(); 177 classAndInterfaceMap.putAll(classMap); 178 classAndInterfaceMap.putAll(interfaceMap); 179 180 if (Debug.DEBUG) { 183 System.out.println( 184 "MDB: Sorting classes by name and generating classIds"); 185 } 186 Arrays.sort(classes, new Comparator() { 187 public int compare(Object aa, Object bb) { 188 ClassMetaData a = (ClassMetaData)aa; 189 ClassMetaData b = (ClassMetaData)bb; 190 return a.qname.compareTo(b.qname); 191 } 192 }); 193 int clen = classes.length; 194 for (int i = 0; i < clen; i++) { 195 ClassMetaData c = classes[i]; 196 c.setClassId(mdutils.generateClassId(c.qname)); 197 } 198 199 if (Debug.DEBUG) System.out.println("MDB: Filling pcClassMetaData"); 201 for (int i = 0; i < clen; i++) { 202 ClassMetaData c = classes[i]; 203 Class pcs = c.pcSuperClass; 204 if (pcs == null) continue; 205 c.pcSuperMetaData = (ClassMetaData)classMap.get(pcs); 206 if (c.pcSuperMetaData == null) { 207 RuntimeException x = BindingSupportImpl.getInstance().runtime("persistence-capable-superclass not declared in meta data: " + 208 pcs.getName() + "\n" + 209 c.jdoClass.getContext()); 210 c.addError(x, quiet); 211 } else if (c.pcSuperMetaData.horizontal) { 212 c.horizontalCMD = c.pcSuperMetaData; 213 c.pcSuperMetaData = null; 214 } 215 } 216 217 if (Debug.DEBUG) { 219 System.out.println("MDB: Building pcSubclasses arrays"); 220 } 221 ArrayList a = new ArrayList(); 222 for (int i = 0; i < clen; i++) { 223 ClassMetaData c = classes[i]; 224 a.clear(); 225 for (int j = 0; j < clen; j++) { 226 ClassMetaData sc = classes[j]; 227 if (sc.pcSuperMetaData == c) a.add(sc); 228 } 229 int len = a.size(); 230 if (len > 0) { 231 c.pcSubclasses = new ClassMetaData[len]; 232 a.toArray(c.pcSubclasses); 233 } 234 } 235 236 if (Debug.DEBUG) { 239 System.out.println( 240 "MDB: Filling pcHeirachy field + copying identity type down"); 241 } 242 for (int i = 0; i < clen; i++) { 243 ClassMetaData cmd = classes[i]; 244 if (cmd.pcSuperMetaData == null) { 245 cmd.calcPcHeirachy(); 246 if (config.hyperdrive) { 247 cmd.oidClassName = MDStatics.GEN_OID_START + 248 cmd.qname.replace('.', '_').replace('$', '_'); 249 } 250 } 251 } 252 253 if (config.hyperdrive) { 255 for (int i = 0; i < clen; i++) { 256 ClassMetaData cmd = classes[i]; 257 if (cmd.pcSuperMetaData != null) { 258 cmd.oidClassName = cmd.top.oidClassName; 259 } 260 cmd.stateClassName = MDStatics.GEN_STATE_START + 261 cmd.qname.replace('.', '_').replace('$', '_'); 262 } 263 } 264 265 if (Debug.DEBUG) System.out.println("MDB: Creating field meta data"); 267 ClassMetaData[] ca = jmd.classes; 268 for (int j = 0; j < ca.length; j++) { 269 ClassMetaData cmd = ca[j]; 270 try { 271 createFieldMetaData(cmd, quiet); 272 } catch (RuntimeException e) { 273 cmd.addError(e, quiet); 274 } 275 } 276 277 doEmbedded(ca); 278 doHorizontal(ca); 279 280 if (Debug.DEBUG) { 282 System.out.println("MDB: Extracting primary key fields"); 283 } 284 for (int i = 0; i < clen; i++) { 285 extractPrimaryKeyFields(classes[i], quiet); 286 } 287 288 if (Debug.DEBUG) System.out.println("MDB: Sorting classes by classId"); 291 Arrays.sort(jmd.classes); 292 for (int i = 0; i < clen; i++) classes[i].index = i; 293 294 if (Debug.DEBUG) { 297 System.out.println("MDB: Calling preBuildFetchGroupsHook"); 298 } 299 preBuildFetchGroupsHook(); 300 301 if (Debug.DEBUG) System.out.println("MDB: Creating fetch groups"); 303 fetchGroupBuilder.buildFetchGroups(quiet); 304 305 calcSuperCounts(classes); 306 307 if (Debug.DEBUG) { 309 System.out.println("MDB: Resolving collection field ordering"); 310 } 311 for (int i = 0; i < clen; i++) resolveOrdering(classes[i], quiet); 312 313 if (Debug.DEBUG) { 316 System.out.println("MDB: Calling postAllFieldsCreatedHook"); 317 } 318 postAllFieldsCreatedHook(); 319 320 if (Debug.DEBUG) { 322 System.out.println("MDB: Calculating maxFieldsLength"); 323 } 324 int max = 0; 325 for (int i = 0; i < clen; i++) { 326 ClassMetaData c = classes[i]; 327 int len = c.stateFields == null ? 0 : c.stateFields.length; 328 if (len > max) max = len; 329 } 330 jmd.maxFieldsLength = max; 331 332 if (Debug.DEBUG) { 334 System.out.println("MDB: Creating pass2Fields[] for each class"); 335 } 336 IntArray ia = new IntArray(); 337 for (int i = 0; i < clen; i++) { 338 ClassMetaData cmd = classes[i]; 339 ia.clear(); 340 FieldMetaData[] fields = cmd.fields; 341 if (fields == null) continue; int fc = fields.length; 343 for (int j = 0; j < fc; j++) { 344 FieldMetaData fmd = fields[j]; 345 if (fmd.secondaryField) ia.add(fmd.fieldNo); 346 } 347 cmd.pass2Fields = ia.toArray(); 348 } 349 350 if (Debug.DEBUG) { 352 System.out.println("MDB: Calling initMDFields() for each class"); 353 } 354 for (int i = 0; i < classes.length; i++) { 355 ClassMetaData cmd = classes[i]; 356 if (cmd.pcSuperMetaData == null) cmd.initMDFields(); 357 } 358 359 for (int i = 0; i < classes.length; i++) { 360 ClassMetaData cmd = classes[i]; 361 if (cmd.pcSuperMetaData == null) cmd.initMDFields2(); 362 } 363 364 368 setMasterDetailFlags(classes); 369 370 373 for (int i = 0; i < classes.length; i++) { 374 ClassMetaData cmd = classes[i]; 375 cmd.totalNoOfSubClasses = getSubClassCount(cmd); 376 } 377 378 for (int i = 0; i < classes.length; i++) { 379 ClassMetaData aClass = classes[i]; 380 if (aClass.objectIdClass != null) { 381 try { 382 validateIDClass(aClass); 383 } catch (RuntimeException e) { 384 aClass.addError(e, quiet); 385 } 386 } 387 } 388 389 if (Debug.DEBUG) { 391 System.out.println("MDB: Finishing fetch group initialization"); 392 } 393 for (int i = 0; i < clen; i++) classes[i].finishFetchGroups(); 394 for (int i = 0; i < clen; i++) classes[i].finishFetchGroups2(); 395 for (int i = 0; i < clen; i++) { 396 ClassMetaData cmd = classes[i]; 397 if (cmd.pcSuperMetaData == null) checkHeirachy(cmd); 398 } 399 for (int i = 0; i < clen; i++) { 400 ClassMetaData cmd = classes[i]; 401 FieldMetaData[] fmds = cmd.fields; 402 if (fmds == null) continue; for (int j = 0; j < fmds.length; j++) { 404 FieldMetaData.setStateMethodName(fmds[j]); 405 } 406 } 407 408 for (int i = 0; i < classes.length; i++) { 412 ClassMetaData cmd = classes[i]; 413 FieldMetaData[] fmds = cmd.stateFields; 414 if (fmds == null) continue; for (int j = 0; j < fmds.length; j++) { 416 FieldMetaData fmd = fmds[j]; 417 if (fmd.inverseFieldMetaData != null) { 418 fmd.inverseFieldNo = fmd.inverseFieldMetaData.managedFieldNo; 419 } 420 } 421 } 422 423 for (int i = 0; i < clen; i++) { 425 ClassMetaData cmd = classes[i]; 426 if (cmd.pcSuperMetaData == null) cmd.overRideCacheStrategy(); 427 } 428 429 for (int i = 0; i < clen; i++) { 431 ClassMetaData cmd = classes[i]; 432 try { 433 createQueryParamsForNamedQueries(cmd); 434 } catch (RuntimeException e) { 435 cmd.addError(e, quiet); 436 } 437 } 438 439 appIdUniqueMap = null; 440 441 jmd.cleanupAfterMetaDataGeneration(); 443 444 jmd.validate(); 446 447 return jmd; 448 } 449 450 protected void doHorizontal(ClassMetaData[] ca) { 451 } 452 453 protected void doEmbedded(ClassMetaData[] ca) { 454 } 455 456 protected void createHorizontalFieldMetaData(ClassMetaData cmd, boolean quiet) { 457 ClassMetaData superCmd = cmd.horizontalCMD; 458 if (superCmd == null) return; 459 if (superCmd.fields == null) return; 460 461 Map fieldMap = new HashMap(); 462 createFmdWithReflection(cmd.horizontalCMD, fieldMap, superCmd.getShortName() + "."); 463 updateMDFromHorizontalSuper(cmd); 464 updateFmdFromMetadata(cmd.horizontalCMD, fieldMap, quiet, cmd.jdoClass.elements); 465 List fields = updateFmd(fieldMap, cmd, quiet); 466 467 for (int i = 0; i < fields.size(); i++) { 468 FieldMetaData fieldMetaData = (FieldMetaData) fields.get(i); 469 fieldMetaData.classMetaData = cmd; 470 fieldMetaData.fake = true; 471 fieldMetaData.origFmd = superCmd.fields[i]; 472 fieldMetaData.horizontalFakeField = true; 473 } 474 475 cmd.horizontalFields = new FieldMetaData[fields.size()]; 476 fields.toArray(cmd.horizontalFields); 477 478 fields.addAll(0, Arrays.asList(cmd.fields)); 479 cmd.fields = new FieldMetaData[fields.size()]; 480 fields.toArray(cmd.fields); 481 482 for (int i = cmd.fields.length - 1; i >= 0; i--) { 483 cmd.fields[i].fieldNo = i; 484 } 485 486 updateScoFields(cmd); 487 } 488 489 493 protected void calcSuperCounts(ClassMetaData[] classes) { 494 if (Debug.DEBUG) { 495 System.out.println("MDB: Calcing superFieldCount and superFetchGroupCount " + 496 "filling stateFields"); 497 } 498 int clen = classes.length; 499 for (int i = 0; i < clen; i++) { 500 ClassMetaData cmd = classes[i]; 501 if (cmd.pcSuperMetaData == null) { 502 cmd.calcSuperCounts(); 503 } 504 } 505 } 506 507 511 protected void setMasterDetailFlags(ClassMetaData[] classes) { 512 } 514 515 519 protected void preBuildFetchGroupsHook() { 520 } 521 522 526 protected void postAllFieldsCreatedHook() { 527 } 528 529 private void createQueryParamsForNamedQueries(ClassMetaData cmd) { 530 JdoClass jdoClass = getClassInfo(cmd).jdoClass; 531 ArrayList queries = jdoClass.queries; 532 if (queries == null || queries.isEmpty()) return; 533 int n = queries.size(); 534 for (int i = 0; i < n; i++) { 535 JdoQuery q = (JdoQuery)queries.get(i); 536 if (cmd.getNamedQuery(q.name) != null) { 537 throw BindingSupportImpl.getInstance().runtime("There " + 538 "is already a query called '" + q.name + "' on " + 539 cmd.qname + "\n" + q.getContext()); 540 } 541 cmd.addNamedQuery(q.name, new QueryDetails(cmd, q)); 542 } 543 } 544 545 548 public int getCdCacheStrategy() { 549 return MDStatics.CACHE_STRATEGY_YES; 550 } 551 552 555 public boolean isCdRefsInDefaultFetchGroup() { 556 return false; 557 } 558 559 562 private int getSubClassCount(ClassMetaData cmd) { 563 if (cmd.pcSubclasses == null) return 0; 564 int count = cmd.pcSubclasses.length; 565 for (int i = 0; i < cmd.pcSubclasses.length; i++) { 566 count += getSubClassCount(cmd.pcSubclasses[i]); 567 } 568 return count; 569 } 570 571 574 protected void resolveOrdering(ClassMetaData cmd, boolean quiet) { 575 FieldMetaData[] fields = cmd.fields; 576 if (fields == null) return; int flen = fields.length; 578 for (int i = 0; i < flen; i++) { 579 FieldMetaData fmd = fields[i]; 580 if (fmd.ordering != null) { 581 int len = fmd.ordering.length; 582 try { 583 for (int j = 0; j < len; j++) { 584 fmd.ordering[j].resolve(queryParser, 585 fmd.elementTypeMetaData, false); 586 } 587 } catch (Exception e) { 588 if (BindingSupportImpl.getInstance().isOwnFatalUserException( 589 e)) { 590 fmd.addError((RuntimeException )e, quiet); 591 } else { 592 RuntimeException jfue = BindingSupportImpl.getInstance().runtime( 593 "Invalid ordering extension for field " + fmd.getQName(), 594 e); 595 fmd.addError(jfue, quiet); 596 } 597 } 598 } 599 } 600 } 601 602 private void checkHeirachy(ClassMetaData cmd) { 603 if (cmd.pcSubclasses == null) return; 604 ClassMetaData[] pcSubs = cmd.pcSubclasses; 605 FetchGroup[] superFG = cmd.fetchGroups; 606 for (int i = 0; i < pcSubs.length; i++) { 607 ClassMetaData pcSub = pcSubs[i]; 608 for (int j = 0; j < superFG.length; j++) { 609 FetchGroup fetchGroup = superFG[j]; 610 FetchGroup subFG = pcSub.getFetchGroup(fetchGroup.name); 611 if (subFG == null || subFG.superFetchGroup != fetchGroup) { 612 throw BindingSupportImpl.getInstance().internal( 613 "FG hierachy broken"); 614 } 615 } 616 checkHeirachy(pcSub); 617 } 618 } 619 620 623 public static void throwUnexpectedExtension(JdoExtension e) { 624 throw BindingSupportImpl.getInstance().runtime("Extension not allowed here: " + 625 e + "\n" + e.getContext()); 626 } 627 628 631 private void extractPrimaryKeyFields(ClassMetaData cmd, boolean quiet) { 632 ArrayList a = new ArrayList(4); 634 JdoElement[] ea = cmd.jdoClass.elements; 635 int n = ea.length; 636 for (int i = 0; i < n; i++) { 637 JdoElement o = ea[i]; 638 if (!(o instanceof JdoField)) continue; 639 FieldMetaData fmd = cmd.getFieldMetaData(((JdoField)o).name); 640 if (fmd != null && fmd.primaryKey) a.add(fmd); 641 } 642 643 boolean appid = cmd.identityType == IDENTITY_TYPE_APPLICATION; 644 if (a.isEmpty()) { 645 if (appid && cmd.pcSuperClass == null) { 646 RuntimeException e = BindingSupportImpl.getInstance().runtime("No primary key fields found for class with identity-type " + 647 "application and no persistence-capable-superclass\n" + 648 cmd.jdoClass.getContext()); 649 cmd.addError(e, quiet); 650 return; 651 } 652 } else { 653 if (!appid && !cmd.horizontal) { 654 RuntimeException e = BindingSupportImpl.getInstance().runtime("Only classes with identity-type application may have " + 655 "primary-key fields\n" + 656 cmd.jdoClass.getContext()); 657 cmd.addError(e, quiet); 658 } 659 cmd.pkFields = new FieldMetaData[a.size()]; 660 a.toArray(cmd.pkFields); 661 662 initPkFieldDefaultValue(cmd, a, quiet); 663 } 664 } 665 666 private void initPkFieldDefaultValue(ClassMetaData cmd, ArrayList a, boolean quiet) { 667 if (cmd.identityType != IDENTITY_TYPE_APPLICATION) return; 668 try { 669 Object inst = null; 670 if (cmd.objectIdClass != null) { 671 inst = cmd.objectIdClass.newInstance(); 672 } else { 673 inst = cmd.cls.newInstance(); 674 675 } 676 for (int i = 0; i < a.size(); i++) { 677 FieldMetaData fmd = (FieldMetaData) a.get(i); 678 Field field = null; 679 Class cls = inst.getClass(); 680 for (;cls != null;) { 681 try { 682 field = cls.getDeclaredField(fmd.name); 683 break; 684 } catch (NoSuchFieldException e) { 685 cls = cls.getSuperclass(); 686 } catch (SecurityException e) { 687 e.printStackTrace(System.out); 688 break; 689 } 690 } 691 if (field != null) { 692 ClassHelper.get().setAccessible(field, true); 693 fmd.setPkDefaultValue(field.get(inst)); 694 } 695 } 696 } catch (Exception e) { 697 if (!BindingSupportImpl.getInstance().isOwnException(e)) { 698 e = BindingSupportImpl.getInstance().runtime(e.getMessage(),e); 699 } 700 cmd.addError((RuntimeException ) e, quiet); 701 if (!quiet) { 702 throw (RuntimeException ) e; 703 } 704 } 705 } 706 707 708 709 712 private JdoRoot buildSingleJdoRoot(JdoRoot[] roots) { 713 714 HashMap classMap = new HashMap(); 716 ArrayList packageList = new ArrayList(); 717 int n = roots.length; 718 for (int i = 0; i < n; i++) { 719 JdoRoot root = roots[i]; 720 if (root.isQueryMetaData()) continue; 721 for (int k = root.packages.length - 1; k >= 0; k--) { 722 JdoPackage p = root.packages[k]; 723 boolean addPackage = true; 724 for (int j = p.classes.length - 1; j >= 0; j--) { 725 JdoClass cls = p.classes[j]; 726 String qname = cls.getQName(); 727 String other = (String )jmd.classResourceMap.get(qname); 728 if (other != null) { 729 730 731 if (other.equals(root.name)) { 732 throw BindingSupportImpl.getInstance().runtime( 733 "Class " + p.classes[j].name + 734 " is defined more than once in " + root.name); 735 } else { 736 throw BindingSupportImpl.getInstance().runtime( 737 "Class " + p.classes[j].name + 738 " is defined in " + other + " and " + root.name); 739 } 740 741 } 742 jmd.classResourceMap.put(qname, root.name); 743 classMap.put(qname, cls); 744 } 745 if (addPackage == true) 746 packageList.add(p); 747 } 748 } 749 750 for (int i = 0; i < n; i++) { 752 JdoRoot root = roots[i]; 753 if (!root.isQueryMetaData()) continue; 754 for (int k = root.packages.length - 1; k >= 0; k--) { 755 JdoPackage p = root.packages[k]; 756 for (int j = p.classes.length - 1; j >= 0; j--) { 757 JdoClass cls = p.classes[j]; 758 if (cls.queries == null) continue; 759 for (Iterator t = cls.queries.iterator(); t.hasNext();) { 760 JdoQuery q = (JdoQuery)t.next(); 761 String qname = q.getCandidateClass(); 762 JdoClass target = (JdoClass)classMap.get(qname); 763 if (target == null) { 764 throw BindingSupportImpl.getInstance().runtime("Candidate class for query is not " + 765 "defined in the meta data: " + qname + "\n" + 766 q.getContext()); 767 } 768 target.addJdoQuery(q); 769 } 770 } 771 } 772 } 773 774 JdoRoot root = new JdoRoot(); 776 root.packages = new JdoPackage[packageList.size()]; 777 root.name = "combined"; 778 packageList.toArray(root.packages); 779 783 return root; 784 } 785 786 789 private Class loadClass(String name) throws ClassNotFoundException { 790 return ClassHelper.get().classForName(name, false, loader); 791 } 792 793 797 private PackageMetaData createPackageMetaData(JdoPackage p) { 798 PackageMetaData pmd = new PackageMetaData(); 799 pmd.nameWithDot = p.name + "."; 800 pmd.jdoPackage = p; 801 return pmd; 802 } 803 804 807 private InterfaceMetaData createInterfaceMetaData(PackageMetaData pmd, 808 JdoExtension ext) { 809 String qname = ext.getString(); 810 if (qname.indexOf('.') < 0) qname = pmd.nameWithDot + qname; 811 Class cls; 812 try { 813 cls = loadClass(qname); 814 } catch (ClassNotFoundException e) { 815 throw BindingSupportImpl.getInstance().runtime( 816 "Interface not found: " + qname + "\n" + ext.getContext(), 817 e); 818 } 819 if (!cls.isInterface()) { 820 throw BindingSupportImpl.getInstance().runtime("Expected interface, found class: " + qname + "\n" + 821 ext.getContext()); 822 } 823 return new InterfaceMetaData(cls); 824 } 825 826 831 private ClassMetaData createMetaData(PackageMetaData pmd, JdoClass jdoCls, 832 boolean quiet) { 833 ClassMetaData cmd = new ClassMetaData(jdoCls, jmd); 834 ClassInfo classInfo = getClassInfo(cmd); 835 classInfo.jdoClass = jdoCls; 836 837 cmd.packageNameWithDot = pmd.nameWithDot; 839 classInfo.refsInDefaultFetchGroup = isCdRefsInDefaultFetchGroup(); 840 cmd.cacheStrategy = getCdCacheStrategy(); 841 cmd.setObjectIdClasssRequired(jdoCls.objectIdClasssRequired); 842 843 try { 845 cmd.cls = loadClass(cmd.qname); 846 } catch (ClassNotFoundException e) { 847 RuntimeException x = BindingSupportImpl.getInstance().runtime("Class not found: " + cmd.qname + "\n" + 848 jdoCls.getContext(), e); 849 cmd.addError(x, quiet); 850 return cmd; 851 } 852 if (cmd.cls.isInterface()) { 853 RuntimeException x = BindingSupportImpl.getInstance().runtime("Expected class, found interface: " + cmd.qname + "\n" + 854 jdoCls.getContext()); 855 cmd.addError(x, quiet); 856 return cmd; 857 } 858 859 String qname = jdoCls.getPCSuperClassQName(); 861 if (qname != null) { 862 try { 863 cmd.pcSuperClass = loadClass(qname); 864 } catch (ClassNotFoundException e) { 865 RuntimeException x = BindingSupportImpl.getInstance().runtime("persistence-capable-superclass not found: " + 866 qname + "\n" + 867 jdoCls.getContext(), e); 868 cmd.addError(x, quiet); 869 return cmd; 870 } 871 } 872 873 checkForHorizontal(jdoCls, cmd); 874 updateIdMetaData(cmd, jdoCls); 875 876 JdoElement[] elements = jdoCls.elements; 878 int n = elements.length; 879 for (int i = 0; i < n; i++) { 880 JdoElement o = elements[i]; 881 if (o instanceof JdoExtension) { 882 JdoExtension e = (JdoExtension)o; 883 switch (e.key) { 884 case JdoExtensionKeys.READ_ONLY: 885 try { 886 cmd.readOnly = e.getBoolean(); 887 } catch (RuntimeException x) { 888 cmd.addError(x, quiet); 889 } 890 break; 891 case JdoExtensionKeys.CACHE_STRATEGY: 892 try { 893 cmd.cacheStrategy = e.getEnum(MDE.CACHE_ENUM); 894 } catch (RuntimeException x) { 895 cmd.addError(x, quiet); 896 } 897 break; 898 case JdoExtensionKeys.DELETE_ORPHANS: 899 try { 900 cmd.deleteOrphans = e.getBoolean(); 901 } catch (RuntimeException x) { 902 cmd.addError(x, quiet); 903 } 904 break; 905 case JdoExtensionKeys.OIDS_IN_DEFAULT_FETCH_GROUP: 906 try { 907 getClassInfo(cmd).refsInDefaultFetchGroup = e.getBoolean(); 908 } catch (RuntimeException x) { 909 cmd.addError(x, quiet); 910 } 911 break; 912 case JdoExtensionKeys.CREATE_OID_AT_MAKE_PERSISTENT: 913 break; 915 } 916 } 917 } 918 919 return cmd; 920 } 921 922 private void updateIdMetaData(ClassMetaData cmd, JdoClass jdoCls) { 923 cmd.identityType = jdoCls.identityType; 925 if (cmd.identityType == IDENTITY_TYPE_APPLICATION) { 926 String qname = jdoCls.getObjectIdClassQName(); 927 if (qname == null) { 928 if (cmd.isObjectIdClasssRequired()) { 929 RuntimeException x = BindingSupportImpl.getInstance().runtime( 930 "objectid-class is required for application identity\n" + 931 jdoCls.getContext()); 932 cmd.addError(x, quiet); 933 } 934 return; 935 } 936 937 String pcRootClsName = (String )appIdUniqueMap.get(qname); 938 if (pcRootClsName == null) { 939 appIdUniqueMap.put(qname, jdoCls.getQName()); 940 } else { 941 RuntimeException x = BindingSupportImpl.getInstance().invalidOperation("The objectid-class for " + 942 jdoCls.getQName() + " has already been used for " + 943 pcRootClsName + ": " + qname + "\n" + 944 jdoCls.getContext()); 945 cmd.addError(x, quiet); 946 return; 947 } 948 949 try { 950 cmd.objectIdClass = loadClass(qname); 951 } catch (ClassNotFoundException e) { 952 RuntimeException x = BindingSupportImpl.getInstance().runtime("objectid-class not found: " + qname + "\n" + 953 jdoCls.getContext(), e); 954 cmd.addError(x, quiet); 955 return; 956 } 957 } else if (cmd.identityType == IDENTITY_TYPE_NONDURABLE) { 958 RuntimeException x = BindingSupportImpl.getInstance().runtime("nondurable identity-type is not supported\n" + 959 jdoCls.getContext()); 960 cmd.addError(x, quiet); 961 return; 962 } else { 963 cmd.identityType = IDENTITY_TYPE_DATASTORE; 964 if (jdoCls.objectIdClass != null) { 965 RuntimeException x = BindingSupportImpl.getInstance().runtime("objectid-class is only allowed for application identity\n" + 966 jdoCls.getContext()); 967 cmd.addError(x, quiet); 968 return; 969 } 970 } 971 } 981 982 987 protected void checkForHorizontal(JdoClass jdoCls, ClassMetaData cmd) { 988 } 989 990 994 private void validateIDClass(ClassMetaData cmd) { 995 Class idClass = cmd.objectIdClass; 996 997 if (!Modifier.isPublic(idClass.getModifiers())) { 998 throw BindingSupportImpl.getInstance().runtime("Application id class '" 999 + idClass.getName() 1000 + "' must be public"); 1001 } 1002 1003 if (idClass.isInterface()) { 1004 throw BindingSupportImpl.getInstance().runtime("Application id class '" 1005 + idClass.getName() 1006 + "' may not be an interface"); 1007 } 1008 1009 FieldMetaData[] pkFields = cmd.pkFields; 1010 for (int i = 0; i < pkFields.length; i++) { 1011 pkFields[i].getObjectidClassField(); 1012 } 1013 1014 if (!Serializable .class.isAssignableFrom(idClass)) { 1016 throw BindingSupportImpl.getInstance().runtime("Application id class '" 1017 + idClass.getName() 1018 + "' does not implement java.io.Serializable"); 1019 } 1020 1021 Constructor[] constructors = idClass.getDeclaredConstructors(); 1023 boolean foundDefaultCon = false; 1024 for (int i = 0; i < constructors.length; i++) { 1025 Constructor constructor = constructors[i]; 1026 if (!Modifier.isPublic(constructor.getModifiers())) continue; 1027 if (constructor.getParameterTypes().length != 0) continue; 1028 foundDefaultCon = true; 1029 } 1030 if (!foundDefaultCon) { 1031 throw BindingSupportImpl.getInstance().runtime("Application id class '" 1032 + idClass.getName() 1033 + "' does not have a public no-arg constructor"); 1034 } 1035 1036 boolean foundStringCon = false; 1038 for (int i = 0; i < constructors.length; i++) { 1039 Constructor constructor = constructors[i]; 1040 if (!Modifier.isPublic(constructor.getModifiers())) continue; 1041 if (constructor.getParameterTypes().length != 1) continue; 1042 if (constructor.getParameterTypes()[0].isAssignableFrom( 1043 String .class)) { 1044 foundStringCon = true; 1045 } 1046 } 1047 if (!foundStringCon) { 1048 throw BindingSupportImpl.getInstance().runtime( 1049 "Application id class '" 1050 + idClass.getName() 1051 + "' does not have a public constructor that accepts a String parameter"); 1052 } 1053 1054 try { 1056 Method tos = null; 1057 for (Class c = idClass; c != Object .class; c = c.getSuperclass()) { 1058 try { 1059 tos = c.getDeclaredMethod("toString", null); 1060 break; 1061 } catch (NoSuchMethodException e) { 1062 } 1064 } 1065 if (tos == null) { 1066 throw BindingSupportImpl.getInstance().runtime("Application id class '" 1067 + idClass.getName() + "' must override toString"); 1068 } 1069 } catch (SecurityException e) { 1070 throw BindingSupportImpl.getInstance().exception(e.getMessage(), e); 1071 } 1072 } 1073 1074 1079 private void createFieldMetaData(ClassMetaData cmd, boolean quiet) { 1080 if (cmd.pcSuperMetaData != null) return; 1081 createFieldMetaDataImp(cmd, quiet); 1082 } 1083 1084 protected void createEmbeddeFieldMetaData(ClassMetaData cmd, boolean quiet) { 1085 if (cmd.pcSuperMetaData != null) return; 1086 createEmbeddeFieldMetaDataImp(cmd, quiet); 1087 } 1088 1089 1092 private void updateMDFromHorizontalSuper(ClassMetaData cmd) { 1093 if (cmd.horizontalCMD == null) return; 1094 1095 JdoElement[] ea = cmd.jdoClass.elements; 1096 List newFields = new ArrayList(Arrays.asList(ea)); 1097 JdoElement[] hor = cmd.horizontalCMD.jdoClass.elements; 1098 final String prefix = cmd.horizontalCMD.getShortName() + "."; 1099 1100 for (int i = 0; i < hor.length; i++) { 1101 JdoElement o = hor[i]; 1102 if (!(o instanceof JdoField)) continue; 1103 JdoField jdoField = (JdoField)o; 1104 1105 1109 JdoField extendedField = findJdoFieldIn(ea, prefix + jdoField.name); 1110 if (extendedField == null) { 1111 extendedField = jdoField.createCopy(cmd.jdoClass); 1112 extendedField.name = prefix + extendedField.name; 1113 newFields.add(extendedField); 1114 } else { 1115 extendedField.synchWith(jdoField, Collections.EMPTY_SET, false); 1116 } 1117 } 1118 ea = new JdoElement[newFields.size()]; 1119 newFields.toArray(ea); 1120 cmd.jdoClass.elements = ea; 1121 } 1122 1123 1124 private JdoField findJdoFieldIn(JdoElement[] elements, String name) { 1125 for (int i = 0; i < elements.length; i++) { 1126 JdoElement element = elements[i]; 1127 if (!(element instanceof JdoField)) continue; 1128 JdoField jdoField = (JdoField) element; 1129 if (jdoField.name.equals(name)) { 1130 return jdoField; 1131 } 1132 } 1133 return null; 1134 } 1135 1136 private void createEmbeddeFieldMetaDataImp(ClassMetaData cmd, boolean quiet) { 1137 ArrayList currentFields = new ArrayList(Arrays.asList(cmd.fields)); 1138 HashMap parents = new HashMap(cmd.fields.length * 5); 1139 FieldMetaData fmd = null; 1140 for (int i = 0; i < currentFields.size(); i++) { 1141 fmd = (FieldMetaData) currentFields.get(i); 1142 1143 if (fmd.isEmbeddedRef()) { 1144 ClassMetaData embeddedCmd = fmd.typeMetaData; 1145 1146 Map fieldMap = new HashMap(); 1147 createFmdWithReflection(embeddedCmd, fieldMap, fmd.name + "/"); 1148 1149 1154 Map copiedJdoFields = new HashMap(); 1155 for (int j = 0; j < embeddedCmd.jdoClass.elements.length; j++) { 1156 JdoElement element = embeddedCmd.jdoClass.elements[j]; 1157 if (!(element instanceof JdoField)) continue; 1158 JdoField copy = ((JdoField) element).createCopy(cmd.jdoClass); 1159 copiedJdoFields.put(copy.name, copy); 1161 copy.origName = copy.name; 1162 copy.name = fmd.name + "/" + copy.name; 1163 if (fmd.jdoField != null && fmd.jdoField.extensions != null) { 1164 JdoExtension ext = JdoExtension.find(JdoExtensionKeys.FIELD, copy.origName, fmd.jdoField.extensions); 1165 if (ext != null) copy.applyEmbeddedExtensions(ext.nested); 1166 } else { 1167 copy.applyEmbeddedExtensions(null); 1168 } 1169 } 1170 1171 if (fmd.jdoField != null && fmd.jdoField.extensions != null) { 1173 JdoExtension exts[] = fmd.jdoField.extensions; 1174 Iterator iter = fieldMap.keySet().iterator(); 1175 while (iter.hasNext()) { 1176 String name = (String ) iter.next(); 1177 name = name.substring((fmd.name + "/").length()); 1178 if (copiedJdoFields.containsKey(name)) continue; 1179 JdoExtension ext = JdoExtension.find(JdoExtensionKeys.FIELD, name, exts); 1180 if (ext != null) { 1181 JdoField newJdoField = new JdoField(fmd.jdoField); 1182 newJdoField.name = fmd.name + "/" + name; 1183 newJdoField.applyEmbeddedExtensions(ext.nested); 1184 copiedJdoFields.put(name, newJdoField); 1185 } 1186 } 1187 } 1188 1189 JdoElement[] els = new JdoElement[copiedJdoFields.size()]; 1190 copiedJdoFields.values().toArray(els); 1191 1192 updateFmdFromMetadata(embeddedCmd, fieldMap, quiet, els); 1193 List fields = updateFmd(fieldMap, cmd, quiet); 1194 findNullIndicationFmd(fields, fmd); 1195 1196 for (int j = 0; j < fields.size(); j++) { 1197 FieldMetaData fieldMetaData = (FieldMetaData) fields.get(j); 1198 fieldMetaData.classMetaData = cmd; 1199 fieldMetaData.fake = true; 1200 fieldMetaData.origFmd = embeddedCmd.fields[j]; 1201 fieldMetaData.embeddedFakeField = true; 1202 1203 checkRecursiveEmbedded(fieldMetaData, fmd, parents); 1205 } 1206 1207 1208 fmd.embeddedFmds = new FieldMetaData[fields.size()]; 1209 fields.toArray(fmd.embeddedFmds); 1210 1211 1219 if (fmd.jdoField.extensions != null) { 1220 for (int j = 0; j < fmd.jdoField.extensions.length; j++) { 1221 JdoExtension ext = fmd.jdoField.extensions[j]; 1222 if (ext.key == JdoExtensionKeys.NULL_INDICATOR) { 1223 } 1225 } 1226 } 1227 currentFields.addAll(fields); 1228 } 1229 } 1230 1231 1232 cmd.fields = new FieldMetaData[currentFields.size()]; 1233 currentFields.toArray(cmd.fields); 1234 1235 for (int j = cmd.fields.length - 1; j >= 0; j--) { 1236 cmd.fields[j].fieldNo = j; 1237 } 1238 1239 updateScoFields(cmd); 1240 1241 if (cmd.pcSubclasses != null) { 1242 for (int i = 0; i < cmd.pcSubclasses.length; i++) { 1243 createEmbeddeFieldMetaDataImp(cmd.pcSubclasses[i], quiet); 1244 } 1245 } 1246 } 1247 1248 private void findNullIndicationFmd(List fields, FieldMetaData fmd) { 1249 for (int j = 0; j < fields.size(); j++) { 1250 FieldMetaData fieldMetaData = (FieldMetaData) fields.get(j); 1251 if (fieldMetaData.jdoField != null && fieldMetaData.jdoField.nullIndicator) { 1252 fmd.setNullIndicatorFmd(fieldMetaData); 1253 break; 1254 } 1255 } 1256 } 1257 1258 private void checkRecursiveEmbedded(FieldMetaData fieldMetaData, FieldMetaData fmd, HashMap parents) { 1259 if (fieldMetaData.jdoField != null && fieldMetaData.isDirectRef()) { 1260 JdoExtension ext = null; 1261 if (fieldMetaData.jdoField.extensions != null) { 1262 ext = JdoExtension.find(JdoExtensionKeys.EMBEDDED, fieldMetaData.jdoField.extensions); 1263 } 1264 if (ext != null) { 1265 if (ext.getBoolean()) { 1266 fieldMetaData.embedded = true; 1267 } else { 1268 fieldMetaData.embedded = false; 1269 } 1270 } else { 1271 if (fieldMetaData.embedded) { 1272 HashSet parentTypes = new HashSet(5); 1273 FieldMetaData field = fmd; 1274 while(field != null){ 1275 ClassMetaData refClass = field.typeMetaData; 1276 while(refClass != null){ 1277 parentTypes.add(refClass); 1278 refClass = refClass.pcSuperMetaData; 1279 } 1280 FieldMetaData tempParent = (FieldMetaData)parents.get(field); 1281 if(tempParent == null){ 1282 refClass = field.classMetaData; 1283 while(refClass != null){ 1284 parentTypes.add(refClass); 1285 refClass = refClass.pcSuperMetaData; 1286 } 1287 } 1288 if(parentTypes.contains(fieldMetaData.typeMetaData)){ 1289 fieldMetaData.embedded = false; 1290 break; 1291 } 1292 field = tempParent; 1293 } 1294 } 1295 } 1296 } 1297 } 1298 1299 1303 private void createFieldMetaDataImp(ClassMetaData cmd, boolean quiet) { 1304 HashMap fieldMap = new HashMap(); createFmdWithReflection(cmd, fieldMap, ""); 1306 updateFmdFromMetadata(cmd, fieldMap, quiet, cmd.jdoClass.elements); 1307 List fields = updateFmd(fieldMap, cmd, quiet); 1308 finalizeFmds(fields, cmd, quiet); 1309 } 1310 1311 1315 private List updateFmd(Map fieldMap, ClassMetaData cmd, boolean quiet) { 1316 ArrayList fields = new ArrayList(); 1317 FieldMetaData fmd = null; 1318 for (Iterator i = fieldMap.values().iterator(); i.hasNext();) { 1319 fmd = (FieldMetaData)i.next(); 1320 if (fmd.persistenceModifier == PERSISTENCE_MODIFIER_NONE) continue; 1321 JdoField jdoField = fmd.jdoField; 1322 if (Modifier.isTransient(fmd.modifiers)) { 1323 if (jdoField == null) continue; 1324 } 1325 fields.add(fmd); 1326 Class tt = fmd.componentType; 1327 if (tt == null) tt = fmd.type; 1328 fmd.typeMetaData = (ClassMetaData)classMap.get(tt); 1329 if (fmd.category == 0) { 1330 fmd.category = mdutils.getFieldCategory( 1331 fmd.persistenceModifier, 1332 fmd.type, classAndInterfaceMap); 1333 } 1334 if (fmd.category == MDStatics.CATEGORY_COLLECTION 1335 || fmd.category == MDStatics.CATEGORY_ARRAY 1336 || fmd.category == MDStatics.CATEGORY_MAP) { 1337 fmd.collectionDiffType = true; 1338 } 1339 if ((!fmd.embedded && fmd.category == CATEGORY_REF || fmd.category == CATEGORY_POLYREF) 1340 && (jdoField == null || jdoField.defaultFetchGroup == NOT_SET)) { 1341 fmd.defaultFetchGroup = getClassInfo(cmd).refsInDefaultFetchGroup; 1342 } 1343 if (fmd.category == MDStatics.CATEGORY_TRANSACTIONAL && fmd.scoField == true) { 1344 fmd.scoField = false; 1345 } 1346 if (fmd.category == MDStatics.CATEGORY_EXTERNALIZED) { 1347 if (fmd.externalizer == null) { 1348 fmd.externalizer = getExternalizerForType(fmd.type); 1349 } 1350 fmd.scoField = false; 1351 } 1352 if (fmd.category != MDStatics.CATEGORY_TRANSACTIONAL) { 1353 try { 1354 fillCollectionMetaData(fmd); 1355 } catch (RuntimeException e) { 1356 fmd.addError(e, quiet); 1357 } 1358 } 1359 } 1360 Collections.sort(fields); 1362 return fields; 1363 } 1364 1365 1368 private void updateFmdFromMetadata(ClassMetaData cmd, Map fieldMap, 1369 boolean quiet, JdoElement[] ea) { 1370 int n = ea.length; 1371 for (int i = 0; i < n; i++) { 1372 JdoElement o = ea[i]; 1373 if (!(o instanceof JdoField)) continue; 1374 JdoField jdoField = (JdoField)o; 1375 if (jdoField.persistenceModifier == PERSISTENCE_MODIFIER_NONE) { 1376 fieldMap.remove(jdoField.name); 1377 continue; 1378 } 1379 1380 FieldMetaData fmd = (FieldMetaData)fieldMap.get(jdoField.name); 1381 1384 if (fmd == null) { 1385 final String prefix = cmd.getShortName() + "."; 1386 if (jdoField.name.startsWith(prefix)) { 1387 String name = jdoField.name.substring(prefix.length()); 1388 fmd = (FieldMetaData)fieldMap.get(name); 1389 } 1390 } 1391 if (fmd == null) { 1392 int cIndex = jdoField.name.lastIndexOf("/"); 1393 if (cIndex != -1) { 1394 String name = jdoField.name.substring(cIndex); 1395 fmd = (FieldMetaData)fieldMap.get(name); 1396 } 1397 } 1398 try { 1399 if (fmd == null) { 1400 if (cmd.horizontal || 1401 (cmd.horizontalCMD != null && jdoField.name.startsWith(cmd.horizontalCMD.getShortName() + "."))) { 1402 continue; 1404 } 1405 throw BindingSupportImpl.getInstance().runtime("Field " + 1406 jdoField.name + " not found on " + cmd.qname + "\n" + 1407 jdoField.getContext()); 1408 } 1409 if (fmd.jdoField != null) { 1410 throw BindingSupportImpl.getInstance().runtime("Duplicate meta data for field " + jdoField.name + "\n" + 1411 jdoField.getContext()); 1412 } 1413 fmd.jdoField = jdoField; 1414 fmd.cascadeType = jdoField.cascadeType; 1415 1416 if (jdoField.persistenceModifier != NOT_SET) { 1417 fmd.persistenceModifier = jdoField.persistenceModifier; 1418 } 1419 1420 if (!mdutils.isPersistentModifiers(fmd.modifiers)) { 1422 throw BindingSupportImpl.getInstance().runtime("Field " + jdoField.name + " is static and/or final\n" + 1423 jdoField.getContext()); 1424 } 1425 1426 fmd.primaryKey = jdoField.primaryKey; 1428 fmd.nullValue = jdoField.nullValue; 1429 if (fetchGroupBuilder.findFetchGroupExt(jdoField.extensions) != null) { 1430 fmd.defaultFetchGroup = false; 1431 } else if (jdoField.defaultFetchGroup != NOT_SET) { 1432 fmd.defaultFetchGroup = jdoField.defaultFetchGroup == TRUE; 1433 } 1434 if (jdoField.embedded != NOT_SET) { 1435 fmd.embedded = jdoField.embedded == TRUE; 1436 } 1437 fmd.jdoCollection = jdoField.collection; 1438 fmd.jdoArray = jdoField.array; 1439 fmd.jdoMap = jdoField.map; 1440 1441 processFieldExtensions(fmd, quiet); 1443 1444 if (fmd.persistenceModifier == PERSISTENCE_MODIFIER_TRANSACTIONAL) { 1447 fmd.defaultFetchGroup = false; 1448 } 1449 } catch (RuntimeException e) { 1450 if (quiet) { 1451 if (fmd != null) fmd.addError(e, quiet); 1452 else cmd.addError(e, quiet); 1453 continue; 1454 } else { 1455 throw e; 1456 } 1457 } 1458 } 1459 } 1460 1461 1466 private void createFmdWithReflection(ClassMetaData cmd, Map fieldMap, String prefix) { 1467 ClassMetaData.FieldInfo[] fa = cmd.getDeclaredFields(); 1468 for (int i = fa.length - 1; i >= 0; i--) { 1469 ClassMetaData.FieldInfo f = fa[i]; 1470 String fname = f.getName(); 1471 1472 if (mdutils.isEnhancerAddedField(fname)) continue; 1473 1474 FieldMetaData fmd = new FieldMetaData(); 1475 fmd.classMetaData = cmd; 1476 fmd.name = prefix + fname; 1477 fmd.origName = fname; 1478 fmd.setType(f.getType()); 1479 fmd.setComponentType(fmd.type.getComponentType()); 1480 fmd.modifiers = f.getModifiers(); 1481 fmd.scoField = mdutils.isMutableType(fmd.type); 1482 if (mdutils.isDefaultPersistentField(f, 1483 classAndInterfaceMap)) { 1484 fmd.persistenceModifier = PERSISTENCE_MODIFIER_PERSISTENT; 1485 } else { 1486 fmd.persistenceModifier = PERSISTENCE_MODIFIER_NONE; 1487 } 1488 fmd.nullValue = NULL_VALUE_NONE; 1489 fmd.defaultFetchGroupDefault = mdutils.isDefaultFetchGroupType(fmd.type); 1490 fmd.defaultFetchGroup = fmd.defaultFetchGroupDefault; 1491 fmd.embedded = mdutils.isEmbeddedType(fmd.type); 1492 fieldMap.put(fmd.name, fmd); 1493 } 1494 } 1495 1496 1499 private void finalizeFmds(List fields, ClassMetaData cmd, boolean quiet) { 1500 FieldMetaData[] fmda = cmd.fields = new FieldMetaData[fields.size()]; 1502 fields.toArray(fmda); 1503 cmd.realFieldCount = fmda.length; 1504 1505 for (int i = fmda.length - 1; i >= 0; i--) { 1507 fmda[i].fieldNo = i; 1508 } 1509 1510 ClassMetaData[] pcSubclasses = cmd.pcSubclasses; 1512 if (pcSubclasses != null) { 1513 int len = pcSubclasses.length; 1514 for (int i = 0; i < len; i++) { 1515 createFieldMetaDataImp(pcSubclasses[i], quiet); 1516 } 1517 } 1518 updateScoFields(cmd); 1519 } 1520 1521 private void updateScoFields(ClassMetaData cmd) { 1522 FieldMetaData fmd; 1523 for (int i = 0; i < cmd.fields.length; i++) { 1524 fmd = cmd.fields[i]; 1525 if (fmd.category == MDStatics.CATEGORY_ARRAY 1526 || fmd.category == MDStatics.CATEGORY_COLLECTION 1527 || fmd.category == MDStatics.CATEGORY_MAP 1528 1529 || fmd.typeCode == MDStatics.DATE) { 1530 fmd.setScoField(true); 1531 setSCOFactory(fmd); 1532 } 1533 } 1534 } 1535 1536 1539 private void processFieldExtensions(FieldMetaData fmd, boolean quite) { 1540 JdoExtension[] a = fmd.jdoField.extensions; 1541 if (a == null) return; 1542 for (int i = 0; i < a.length; i++) { 1543 JdoExtension e = a[i]; 1544 switch (e.key) { 1545 case JdoExtensionKeys.NULL_INDICATOR: 1546 fmd.embedded = true; 1547 break; 1548 case JdoExtensionKeys.FIELD: 1549 fmd.embedded = true; 1550 break; 1551 case JdoExtensionKeys.EXTERNALIZER: 1552 fmd.category = MDStatics.CATEGORY_EXTERNALIZED; 1553 try { 1554 fmd.externalizer = createExternalizer(fmd.type, e); 1555 } catch (RuntimeException x) { 1556 fmd.addError(x, quiet); 1557 } 1558 break; 1559 case JdoExtensionKeys.NULL_IF_NOT_FOUND: 1560 fmd.nullIfNotFound = e.getBoolean(); 1561 break; 1562 case JdoExtensionKeys.DEPENDENT: 1563 fmd.dependentValues = e.getBoolean(); 1564 break; 1565 case JdoExtensionKeys.KEYS_DEPENDENT: 1566 fmd.dependentKeys = e.getBoolean(); 1567 break; 1568 case JdoExtensionKeys.AUTOSET: 1569 int v = e.getEnum(MDE.AUTOSET_ENUM); 1570 int tc = fmd.typeCode; 1571 if (v != AUTOSET_NO && tc != DATE && tc != INT 1572 && tc != SHORT && tc != BYTE ) { 1573 RuntimeException ex = BindingSupportImpl.getInstance().runtime("The autoset extension " + 1574 "may only be used on java.util.Date, int, short and byte fields\n" + 1575 e.getContext()); 1576 fmd.addError(ex, quite); 1577 } 1578 fmd.setAutoSet(v); 1579 break; 1580 case JdoExtensionKeys.NULL_VALUE: 1581 case JdoExtensionKeys.FETCH_GROUP: 1582 case JdoExtensionKeys.VALID_CLASS: 1583 break; 1585 case JdoExtensionKeys.SCO_FACTORY: 1586 try { 1587 Class factoryClass = ClassHelper.get().classForName 1588 (e.value, false, loader); 1589 Object factory = factoryClass.newInstance(); 1590 fmd.setScoFactory(factory); 1591 } catch (Exception ex) { 1592 RuntimeException exception = BindingSupportImpl.getInstance().runtime( 1593 "Unable to add SCO factory mapping:\n" + ex.getMessage(), 1594 ex); 1595 fmd.addError(exception, quite); 1596 } 1597 break; 1598 default: 1599 if (e.isCommon()) { 1600 RuntimeException ex = BindingSupportImpl.getInstance().runtime( 1601 "Unexpected extension\n " + e.getContext()); 1602 fmd.addError(ex, quite); 1603 } 1604 } 1605 } 1606 } 1607 1608 1609 1619 private Class resolveTypeName(String name, String qname, String descr, 1620 JdoElement context) { 1621 Class type = MDStaticUtils.toSimpleClass(name); 1622 if (type == null) { 1623 try { 1624 if (name.endsWith(ARRAY_SUFFIX)) { 1625 return Array.newInstance(resolveTypeName( 1626 name.substring(0, name.length() - ARRAY_SUFFIX.length()), 1627 qname.substring(0, qname.length() - ARRAY_SUFFIX.length()), 1628 descr, context), 0).getClass(); 1629 } else { 1630 type = loadClass(name); 1631 } 1632 } catch (ClassNotFoundException e) { 1633 } 1635 if (qname != null) { 1636 try { 1637 type = loadClass(qname); 1638 } catch (ClassNotFoundException e) { 1639 throw BindingSupportImpl.getInstance().runtime(descr + " class not found: " + qname + "\n" + 1640 context.getContext(), e); 1641 } 1642 } 1643 } 1644 return type; 1645 } 1646 1647 1650 private void fillCollectionMetaData(FieldMetaData fmd) { 1651 String msg = null; 1652 JdoExtension[] extensions = null; 1653 Class t; 1654 switch (fmd.category) { 1655 case CATEGORY_COLLECTION: 1656 if (fmd.jdoArray != null) { 1657 msg = "array"; 1658 } else if (fmd.jdoMap != null) msg = "map"; 1659 if (msg != null) break; 1660 fmd.ordered = List.class.isAssignableFrom(fmd.type) 1661 1662 ; 1663 fmd.setElementType(Object .class); 1664 JdoCollection col = fmd.jdoCollection; 1665 if (col != null) { 1666 extensions = col.extensions; 1667 t = resolveTypeName(col.elementType, 1668 col.getElementTypeQName(), "element-type", col); 1669 } else { 1670 t = null; 1671 extensions = null; 1672 } 1673 if (t == null) { 1674 t = MetaDataUtils.getGenericElementType( 1675 fmd.getReflectField()); 1676 if (t == null) t = Object .class; 1677 } 1678 1679 fmd.setElementType(t); 1680 fmd.elementTypeMetaData = (ClassMetaData)classMap.get( 1681 fmd.elementType); 1682 if (col != null && col.embeddedElement != NOT_SET) { 1683 fmd.embeddedElement = col.embeddedElement == TRUE; 1684 } 1685 break; 1686 1687 case CATEGORY_ARRAY: 1688 if (fmd.jdoCollection != null) { 1689 msg = "collection"; 1690 } else if (fmd.jdoMap != null) msg = "map"; 1691 if (msg != null) break; 1692 fmd.ordered = true; 1693 fmd.setElementType(fmd.componentType); 1694 fmd.elementTypeMetaData = (ClassMetaData)classMap.get( 1695 fmd.elementType); 1696 JdoArray ar = fmd.jdoArray; 1697 if (ar != null) { 1698 extensions = ar.extensions; 1699 if (ar.embeddedElement != NOT_SET) { 1700 fmd.embeddedElement = ar.embeddedElement == TRUE; 1701 } 1702 } 1703 break; 1704 1705 case CATEGORY_MAP: 1706 if (fmd.jdoArray != null) { 1707 msg = "array"; 1708 } else if (fmd.jdoCollection != null) msg = "collection"; 1709 if (msg != null) break; 1710 fmd.setElementType(Object .class); 1711 fmd.setKeyType(Object .class); 1712 JdoMap map = fmd.jdoMap; 1713 extensions = map == null ? null : map.extensions; 1714 if (map != null) { 1715 t = resolveTypeName(map.valueType, map.getValueTypeQName(), 1716 "value-type", map); 1717 extensions = map.extensions; 1718 } else { 1719 t = null; 1720 extensions = null; 1721 } 1722 if (t == null) { 1723 t = MetaDataUtils.getGenericValueType( 1724 fmd.getReflectField()); 1725 if (t == null) t = Object .class; 1726 } 1727 fmd.setElementType(t); 1728 fmd.elementTypeMetaData = (ClassMetaData)classMap.get( 1729 fmd.elementType); 1730 if (map != null && map.embeddedValue != NOT_SET) { 1731 fmd.embeddedElement = map.embeddedValue == TRUE; 1732 } 1733 if (map != null) { 1734 t = resolveTypeName(map.keyType, map.getKeyTypeQName(), 1735 "key-type", map); 1736 } else { 1737 t = null; 1738 } 1739 if (t == null) { 1740 t = MetaDataUtils.getGenericKeyType(fmd.getReflectField()); 1741 if (t == null) t = Object .class; 1742 } 1743 fmd.setKeyType(t); 1744 fmd.keyTypeMetaData = (ClassMetaData)classMap.get(fmd.keyType); 1745 if (map != null && map.embeddedKey != NOT_SET) { 1746 fmd.embeddedKey = map.embeddedKey == TRUE; 1747 } 1748 break; 1749 } 1750 if (msg != null) { 1751 throw BindingSupportImpl.getInstance().runtime("Element <" + msg + "> is " + 1752 "not allowed for field " + fmd.name + "\n" + 1753 fmd.jdoField.getContext()); 1754 } 1755 1756 switch (fmd.category) { 1758 case CATEGORY_COLLECTION: 1759 case CATEGORY_ARRAY: 1760 case CATEGORY_MAP: 1761 if (!fmd.dependentValues || fmd.isElementTypePC()) break; 1763 default: 1764 if (fmd.category == CATEGORY_REF 1765 || fmd.category == CATEGORY_POLYREF 1766 || !fmd.dependentValues) { 1767 break; 1768 } 1769 throw BindingSupportImpl.getInstance().runtime("The dependent extension is only valid for " + 1770 "references, collections and maps of persistent classes\n" + 1771 fmd.jdoField.getContext()); 1772 } 1773 1774 if (fmd.category == CATEGORY_MAP) { 1776 if (fmd.dependentKeys && fmd.keyTypeMetaData == null) { 1778 throw BindingSupportImpl.getInstance().runtime("The keys-dependent extension is only valid for " + 1779 "maps with a persistent class key\n" + 1780 fmd.jdoField.getContext()); 1781 } 1782 } else if (fmd.dependentKeys) { 1783 throw BindingSupportImpl.getInstance().runtime("The keys-dependent extension is only valid for maps\n" + 1784 fmd.jdoField.getContext()); 1785 } 1786 1787 if (extensions != null) { 1789 int n = extensions.length; 1790 JdoExtension ordered = null; 1791 JdoExtension ordering = null; 1792 for (int i = 0; i < n; i++) { 1793 JdoExtension e = extensions[i]; 1794 switch (e.key) { 1795 case JdoExtensionKeys.ORDERED: 1796 if (!fmd.ordered) { 1797 throw BindingSupportImpl.getInstance().runtime("The ordered extension is not allowed here\n" + 1798 e.getContext()); 1799 } 1800 ordered = e; 1801 break; 1802 case JdoExtensionKeys.ORDERING: 1803 ordering = e; 1804 break; 1805 case JdoExtensionKeys.MANAGED: 1806 break; 1808 default: 1809 if (e.isCommon()) { 1810 throw BindingSupportImpl.getInstance().runtime( 1811 "Unexpected extension\n" + e.getContext()); 1812 } 1813 } 1814 } 1815 if (ordered != null) fmd.ordered = ordered.getBoolean(); 1816 if (ordering != null) { 1817 if (ordered != null && ordered.getBoolean()) { 1818 throw BindingSupportImpl.getInstance().runtime("You may not specify an ordering if you also have ordered=true\n" + 1819 ordering.getContext()); 1820 } 1821 fmd.ordered = false; 1822 try { 1823 fmd.ordering = queryParser.parseOrdering( 1824 fmd.elementTypeMetaData, ordering.getString()); 1825 } catch (ParseException e) { 1826 throw BindingSupportImpl.getInstance().runtime("Invalid ordering extension: " + e.getMessage() + "\n" + 1827 ordering.getContext() + "\n", e); 1828 } 1829 } 1830 } 1831 } 1832 1833 1836 private void setSCOFactory(FieldMetaData fmd) { 1837 if (fmd.checkCustomFactory()) { 1838 return; 1839 } 1840 if (fmd.scoField) { 1841 switch (fmd.category) { 1842 case CATEGORY_SIMPLE: 1843 if (fmd.simpleSCOFactory == null) { 1844 fmd.simpleSCOFactory = scoFactoryRegistry.getJdoGenieSCOFactory( 1845 fmd); 1846 } 1847 break; 1848 case CATEGORY_COLLECTION: 1849 if (fmd.collectionFactory == null) { 1850 fmd.collectionFactory = scoFactoryRegistry.getJDOGenieSCOCollectionFactory( 1851 fmd); 1852 } 1853 break; 1854 case CATEGORY_MAP: 1855 if (fmd.mapFactory == null) { 1856 fmd.mapFactory = scoFactoryRegistry.getJDOGenieSCOMapFactory( 1857 fmd); 1858 } 1859 break; 1860 } 1861 } 1862 } 1863 1864 1868 private ClassInfo getClassInfo(ClassMetaData cmd) { 1869 ClassInfo ans = (ClassInfo)classInfoMap.get(cmd); 1870 if (ans == null) classInfoMap.put(cmd, ans = new ClassInfo()); 1871 return ans; 1872 } 1873 1874 1877 private void fillExternalizerMap() { 1878 externalizerMap.clear(); 1879 int n = config.externalizers.size(); 1880 for (int i = 0; i < n; i++) { 1881 ConfigInfo.ExternalizerInfo ei = 1882 (ConfigInfo.ExternalizerInfo)config.externalizers.get(i); 1883 if (!ei.enabled) continue; 1884 try { 1885 Class key = loadClass(ei.typeName); 1886 Class cls = loadExternalizerClass(ei.externalizerName); 1887 externalizerMap.put(key, createExternalizer(cls, key, ei.args)); 1888 mdutils.registerExternalizedType(key); 1889 } catch (Throwable x) { 1890 RuntimeException e; 1891 if (BindingSupportImpl.getInstance().isOwnException(x)) { 1892 e = (RuntimeException )x; 1893 } else { 1894 e = BindingSupportImpl.getInstance().runtime("Unable to create Externalizer for '" + 1895 ei.typeName + "':\n" + x.toString(), x); 1896 } 1897 jmd.addError(e, quiet); 1898 } 1899 } 1900 } 1901 1902 private Externalizer createExternalizer(Class externalizerCls, 1903 Class type, Map props) throws IllegalAccessException , 1904 InstantiationException , InvocationTargetException { 1905 Externalizer externalizer; 1906 try { 1907 Constructor m = externalizerCls.getConstructor( 1908 new Class []{Class .class}); 1909 externalizer = (Externalizer)m.newInstance(new Object []{type}); 1910 } catch (NoSuchMethodException e) { 1911 externalizer = (Externalizer)externalizerCls.newInstance(); 1912 } 1913 BeanUtils.setProperties(externalizer, props); 1914 return externalizer; 1915 } 1916 1917 1922 private Class loadExternalizerClass(String name) 1923 throws ClassNotFoundException { 1924 if (name == null || SerializedExternalizer.SHORT_NAME.equals(name)) { 1925 return SerializedExternalizer.class; 1926 } else if (TypeAsBytesExternalizer.SHORT_NAME.equals(name)) { 1927 return TypeAsBytesExternalizer.class; 1928 } else if (TypeAsStringExternalizer.SHORT_NAME.equals(name)) { 1929 return TypeAsStringExternalizer.class; 1930 } 1931 return loadClass(name); 1932 } 1933 1934 1937 private Externalizer getExternalizerForType(Class type) { 1938 Externalizer ex = (Externalizer) externalizerMap.get(type); 1939 if (ex == null && Serializable .class.isAssignableFrom(type)) { 1940 try { 1941 ex = createExternalizer(SerializedExternalizer.class, type, null); 1942 } catch (Exception e) { 1943 throw BindingSupportImpl.getInstance().internal(e.getMessage(), e); 1944 } 1945 } 1946 return ex; 1947 } 1948 1949 1953 private Externalizer createExternalizer(Class type, JdoExtension e) { 1954 try { 1955 String cname = e.getString(); 1956 Class cls = loadExternalizerClass(cname); 1957 return createExternalizer(cls, type, e.getPropertyMap()); 1958 } catch (Throwable x) { 1959 x = BindingSupportImpl.getInstance().findCause(x); 1960 if (BindingSupportImpl.getInstance().isOwnException(x)) { 1961 throw (RuntimeException )x; 1962 } 1963 throw BindingSupportImpl.getInstance().runtime(x.toString(), x); 1964 } 1965 } 1966 1967 1971 public boolean isSendCurrentForFGWithSecFields() { 1972 return false; 1973 } 1974 1975 1978 public boolean isReadObjectBeforeWrite() { 1979 return false; 1980 } 1981} 1982 | Popular Tags |