1 2 12 package com.versant.core.metadata; 13 14 import com.versant.core.common.*; 15 import com.versant.core.util.classhelper.ClassHelper; 16 import com.versant.core.util.IntArray; 17 18 import javax.jdo.spi.JDOImplHelper; 19 import java.io.PrintStream ; 20 import java.io.Serializable ; 21 import java.lang.reflect.Constructor ; 22 import java.lang.reflect.Modifier ; 23 import java.util.*; 24 25 import com.versant.core.common.BindingSupportImpl; 26 import com.versant.core.jdo.VersantOid; 27 28 31 public final class ModelMetaData implements Serializable { 32 33 37 public boolean returnNullForRowNotFound; 38 41 public ClassMetaData[] classes; 42 46 private final HashMap objectIdClassMap = new HashMap(); 47 50 public int maxFieldsLength; 51 54 public transient Object jdbcMetaData; 55 58 public transient Object vdsModel; 59 63 public boolean sendStateOnDelete; 64 67 public HashMap classResourceMap = new HashMap(); 68 69 private transient RuntimeException error; 70 71 76 public transient boolean testing; 77 78 79 private static final ThreadLocal META_DATA = new ThreadLocal (); 80 81 private final Class [] EMPTY_CLASS_ARRAY = new Class [0]; 82 83 private Map abstractSchemaNameMap; 85 private StateAndOIDFactory untypedOIDFactory = new StateAndOIDFactory() { 86 public OID createOID(ClassMetaData cmd, boolean resolved) { 87 throw BindingSupportImpl.getInstance().internal(""); 88 } 89 public State createState(ClassMetaData cmd) { 90 throw BindingSupportImpl.getInstance().internal(""); 91 } 92 public NewObjectOID createNewObjectOID(ClassMetaData cmd) { 93 throw BindingSupportImpl.getInstance().internal(""); 94 } 95 public OID createUntypedOID() { 96 throw BindingSupportImpl.getInstance().unsupported( 97 "Untyped OIDs are not supported by the datastore"); 98 } 99 }; 100 101 public ModelMetaData() { 102 } 103 104 108 public static ModelMetaData getThreadMetaData() { 109 110 return (ModelMetaData)META_DATA.get(); 111 112 113 } 114 115 119 120 public static void setThreadMetaData(ModelMetaData jmd) { 121 META_DATA.set(jmd); 122 } 123 124 125 128 public ClassMetaData getClassMetaData(int classId) { 129 int low = 0; 131 int high = classes.length - 1; 132 while (low <= high) { 133 int mid = (low + high) / 2; 134 ClassMetaData midVal = classes[mid]; 135 int midValClassId = midVal.classId; 136 if (midValClassId < classId) { 137 low = mid + 1; 138 } else if (midValClassId > classId) { 139 high = mid - 1; 140 } else { 141 return midVal; 142 } 143 } 144 return null; 145 } 146 147 150 public ClassMetaData getClassMetaData(Class cls) { 151 for (int i = classes.length - 1; i >= 0; i--) { 152 ClassMetaData cmd = classes[i]; 153 if (cmd.cls == cls) return cmd; 154 } 155 return null; 156 } 157 158 163 public ClassMetaData getClassMetaData(String qname) { 164 for (int i = classes.length - 1; i >= 0; i--) { 165 ClassMetaData cmd = classes[i]; 166 if (cmd.qname.equals(qname)) return cmd; 167 } 168 return null; 169 } 170 171 175 public ClassMetaData getClassMetaData(ClassMetaData base, String className) { 176 ClassMetaData ans = getClassMetaData(className); 177 if (ans == null) { 178 ans = getClassMetaData(base.packageNameWithDot + className); 179 } 180 return ans; 181 } 182 183 187 public void buildAbstractSchemaNameMap() { 188 abstractSchemaNameMap = new HashMap(); 189 for (int i = classes.length - 1; i >= 0; i--) { 190 ClassMetaData cmd = classes[i]; 191 ClassMetaData dup = (ClassMetaData)abstractSchemaNameMap.put( 192 cmd.abstractSchemaName, cmd); 193 if (dup != null) { 194 } 200 } 201 } 202 203 206 public ClassMetaData getClassMetaByASN(String abstractSchemaName) { 207 return (ClassMetaData)abstractSchemaNameMap.get(abstractSchemaName); 208 } 209 210 211 212 213 public void dump() { 214 dump(Debug.OUT, ""); 215 } 216 217 public void dump(PrintStream out, String indent) { 218 out.println(indent + this); 219 String is = indent + " "; 220 for (int i = 0; i < classes.length; i++) { 221 classes[i].dump(out, is); 222 } 223 } 224 225 229 public List findNonPCClassNames() { 230 ArrayList a = new ArrayList(); 231 int n = classes.length; 232 for (int i = 0; i < n; i++) { 233 if (!classes[i].isPersistenceCapable()) a.add(classes[i].qname); 234 } 235 return a; 236 } 237 238 242 public void checkForNonPCClasses() { 243 List nonPCList = findNonPCClassNames(); 244 if (!nonPCList.isEmpty()) { 245 StringBuffer s = new StringBuffer (); 246 s.append("One or more classes in the JDO meta data have not " + 247 "been enhanced:"); 248 int n = nonPCList.size(); 249 int i; 250 for (i = 0; i < n && i < 10; i++) { 251 s.append('\n'); 252 s.append(nonPCList.get(i)); 253 } 254 if (i < n) s.append("\n..."); 255 throw BindingSupportImpl.getInstance().runtime(s.toString()); 256 } 257 } 258 259 265 public void buildObjectIdClassMap() { 266 int n = classes.length; 267 for (int i = 0; i < n; i++) { 268 ClassMetaData cmd = classes[i]; 269 if (cmd.pcSuperMetaData == null && cmd.objectIdClass != null) { 270 objectIdClassMap.put(cmd.objectIdClass, cmd); 271 } 272 } 273 } 274 275 280 public ClassMetaData getClassMetaDataForObjectIdClass(Class cls) { 281 return (ClassMetaData)objectIdClassMap.get(cls); 282 } 283 284 288 public void forceClassRegistration() { 289 HashMap classMap = new HashMap(); 290 ClassMetaData[] cmds = classes; 291 for (int i = 0; i < cmds.length; i++) { 292 ClassMetaData cmd = cmds[i]; 293 if (cmd.pcSuperClass == null){ 294 initClass(cmd.cls); 295 classMap.put(cmd.cls, null); 296 ClassMetaData[] subCmds = cmd.pcSubclasses; 297 if (subCmds != null){ 298 for (int j = 0; j < subCmds.length; j++) { 299 initClass(subCmds[j].cls); 300 classMap.put(subCmds[j].cls, null); 301 } 302 } 303 } 304 } 305 for (int i = 0; i < cmds.length; i++) { 306 if (!classMap.containsKey(cmds[i].cls)){ 307 initClass(cmds[i].cls); 308 } 309 } 310 } 311 312 315 private void initClass(Class cls){ 316 try { 317 if (!Modifier.isAbstract(cls.getModifiers())) { 318 Constructor cons = cls.getDeclaredConstructor(null); 319 ClassHelper.get().setAccessible(cons, true); 320 cons.newInstance(null); 321 } 322 } catch (Exception e) { 323 } 325 } 326 327 332 public int[] convertToClassIndexes(Class [] classes, 333 boolean includeSubclasses) { 334 if (includeSubclasses) { 335 int n = classes.length; 336 IntArray a = new IntArray(16); 337 for (int i = 0; i < n; i++) { 338 ClassMetaData cmd = getClassMetaData(classes[i]); 339 if (cmd == null) { 340 throw BindingSupportImpl.getInstance().invalidOperation("Not a persistent class: " + 341 classes[i].getName()); 342 } 343 cmd.findHeirachyIndexes(a); 344 } 345 return a.toArray(); 346 } else { 347 int n = classes.length; 348 int[] a = new int[n]; 349 for (int i = 0; i < n; i++) { 350 ClassMetaData cmd = getClassMetaData(classes[i]); 351 if (cmd == null) { 352 throw BindingSupportImpl.getInstance().invalidOperation("Not a persistent class: " + 353 classes[i].getName()); 354 } 355 a[i] = cmd.index; 356 } 357 return a; 358 } 359 } 360 361 366 public Class [] convertFromClassIndexes(int[] classIndexes) { 367 int n = classIndexes.length; 368 Class [] ans = new Class [n]; 369 int max = classes.length; 370 for (int i = 0; i < n; i++) { 371 int ci = classIndexes[i]; 372 if (ci < 0 || ci >= max) { 373 throw BindingSupportImpl.getInstance().invalidOperation("Invalid class index: " + ci); 374 } 375 ans[i] = classes[ci].cls; 376 } 377 return ans; 378 } 379 380 384 public void validate() { 385 for (int i = 0; i < classes.length; i++) { 386 classes[i].validate(); 387 } 388 } 389 390 393 public void cleanupAfterMetaDataGeneration() { 394 for (int i = 0; i < classes.length; i++) { 395 classes[i].cleanupAfterMetaDataGeneration(); 396 } 397 } 398 399 404 public OID newOIDFromIDString(String value, boolean resolved) { 405 try { 406 char c = value.charAt(0); 407 int cid = c - '0'; 408 int i = 1; 409 for (; ;) { 410 c = value.charAt(i++); 411 if (c == MDStatics.OID_CHAR_SEPERATOR) break; 412 cid = cid * 10 + (c - '0'); 413 } 414 ClassMetaData cmd = getClassMetaData(cid); 415 if (cmd == null) { 416 throw BindingSupportImpl.getInstance().invalidOperation("Invalid OID String (bad class ID): '" + 417 value + "'"); 418 } 419 if (cmd.identityType != MDStatics.IDENTITY_TYPE_DATASTORE) { 420 throw BindingSupportImpl.getInstance().invalidOperation("Class " + cmd.qname + " for class-id " + cid + 421 " does not use datastore identity"); 422 } 423 resolved = (resolved || (cmd.pcSubclasses == null)); 424 OID oid = cmd.createOID(resolved || cmd.pcSubclasses == null); 425 oid.fillFromIDString(value, i); 426 return oid; 427 } catch (RuntimeException e) { 428 if( BindingSupportImpl.getInstance().isOwnException(e) ) 429 { 430 throw e; 431 } 432 else 433 { 434 throw BindingSupportImpl.getInstance().invalidOperation("Invalid OID String: '" + 435 value + "'", e); 436 } 437 } 438 } 439 440 445 public String toExternalString(OID oid) { 446 StringBuffer b = new StringBuffer (); 447 ClassMetaData cmd = oid.getAvailableClassMetaData(); 448 if (cmd.top.objectIdClass == null) { 449 b.append('d'); 450 b.append(' '); 451 b.append(oid); 452 } else { 453 b.append('a'); 454 b.append(' '); 455 b.append(cmd.classIdString); 456 b.append(' '); 457 Object o; 458 try { 459 o = cmd.top.objectIdClass.newInstance(); 460 } catch (Exception e) { 461 throw BindingSupportImpl.getInstance().internal(e.toString(), 462 e); 463 } 464 oid.populateObjectIdClassInstance(o); 465 b.append(o); 466 } 467 String ans = b.toString(); 468 if (Debug.DEBUG) { 469 OID oid2 = newOIDFromExternalString(ans); 470 if (!oid.equals(oid2)) { 471 throw BindingSupportImpl.getInstance().internal( 472 "string does not parse properly for " + oid); 473 } 474 } 475 return ans; 476 } 477 478 482 public OID newOIDFromExternalString(String s) { 483 switch (s.charAt(0)) { 484 case 'd': 485 return newOIDFromIDString(s.substring(2), true); 486 case 'a': 487 int i = s.indexOf(' ', 2); 488 int cid = Integer.parseInt(s.substring(2, i)); 489 ClassMetaData cmd = getClassMetaData(cid); 490 if (cmd == null) { 491 throw BindingSupportImpl.getInstance().invalidOperation("Invalid string: '" + s + "', no class found for " + 492 "class-id: " + cid); 493 } 494 Object o; 495 try { 496 o = JDOImplHelper.getInstance().newObjectIdInstance( 497 cmd.cls, s.substring(i + 1)); 498 } catch (Exception e) { 499 if( BindingSupportImpl.getInstance().isOwnException(e) ) 500 { 501 throw (RuntimeException ) e; 502 } 503 else 504 { 505 throw BindingSupportImpl.getInstance().invalidOperation( 506 "Invalid string: '" + s + "': " + e, e); 507 } 508 } 509 OID oid = cmd.createOID(true); 510 oid.fillFromPK(o); 511 return oid; 512 default: 513 throw BindingSupportImpl.getInstance().invalidOperation("Invalid string: '" + s + "'"); 514 } 515 } 516 517 public void addError(RuntimeException e, boolean quiet) { 518 if (error == null) { 519 error = e; 520 try { 521 Thread.sleep(1); 522 } catch (InterruptedException e1) { 523 } 525 } 526 if (!quiet) throw e; 527 } 528 529 public boolean hasErrors() { 530 if (error != null) { 531 return true; 532 } 533 for (int i = 0; i < classes.length; i++) { 534 if (classes[i].hasErrors()) return true; 535 } 536 return false; 537 } 538 539 public RuntimeException getFirstError() { 540 if (error != null) { 541 return error; 542 } 543 for (int i = 0; i < classes.length; i++) { 544 RuntimeException e = classes[i].getFirstError(); 545 if (e != null) return e; 546 } 547 return null; 548 } 549 550 553 public OID convertFromAppIdToOID(Object appId) { 554 OID oid = null; 555 ClassMetaData cmd = getClassMetaDataForObjectIdClass(appId.getClass()); 556 if (cmd == null) { 557 throw BindingSupportImpl.getInstance().invalidOperation("Instance is not an objectid-class for any persistent classes: " + 558 appId.getClass().getName() + ": " + toString(appId)); 559 } 560 oid = cmd.createOID(false); 561 oid.fillFromPK(appId); 562 return oid; 563 } 564 565 568 public OID convertJDOGenieOIDtoOID(VersantOid versantOid) { 569 if (versantOid.actualOID != null) { 570 return versantOid.actualOID.getAvailableOID(); 571 } 572 ClassMetaData cmd = getClassMetaData(versantOid.classId); 573 if (cmd == null) { 574 throw BindingSupportImpl.getInstance().invalidOperation("Invalid classID in VersantOid: " 575 + versantOid); 576 } 577 OID oid = cmd.createOID(true); 578 oid.setLongPrimaryKey(versantOid.pk); 579 return versantOid.actualOID = oid; 580 } 581 582 586 public OID convertToOID(Object oid) { 587 if (oid instanceof VersantOid) { 588 return convertJDOGenieOIDtoOID((VersantOid)oid); 589 } else if (oid instanceof OID) { 590 return (OID)oid; 591 } else { 592 return convertFromAppIdToOID(oid); 593 } 594 } 595 596 600 public OID[] convertToOID(Object [] oids, int n) { 601 OID[] a = new OID[n]; 602 for (int i = 0; i < n; i++) { 603 Object oid = oids[i]; 604 if (oid instanceof VersantOid) { 605 a[i] = convertJDOGenieOIDtoOID((VersantOid)oid); 606 } else if (oid instanceof OID) { 607 a[i] = (OID)oid; 608 } else if (oid != null) { 609 a[i] = convertFromAppIdToOID(oid); 610 } 611 } 612 return a; 613 } 614 615 619 private static String toString(Object o) { 620 if (o == null) return "null"; 621 try { 622 return o.toString(); 623 } catch (Exception e) { 624 return o.getClass().getName() + ".toString() failed: " + e; 625 } 626 } 627 628 631 public ClassMetaData[] getClassMetaDataForHeirachy(ClassMetaData base) { 632 if (base.pcSubclasses == null) { 633 return new ClassMetaData[]{base}; 634 } 635 ArrayList a = new ArrayList(); 636 getClassMetaDataForHeirachyImp(base, a); 637 ClassMetaData[] ans = new ClassMetaData[a.size()]; 638 a.toArray(ans); 639 return ans; 640 } 641 642 private void getClassMetaDataForHeirachyImp(ClassMetaData cmd, ArrayList a) { 643 a.add(cmd); 644 if (cmd.pcSubclasses != null) { 645 for (int i = 0; i < cmd.pcSubclasses.length; i++) { 646 getClassMetaDataForHeirachyImp(cmd.pcSubclasses[i], a); 647 } 648 } 649 } 650 651 654 public OID createUnresolvedOID(int classIndex) { 655 return classes[classIndex].createOID(false); 656 } 657 658 662 public void setUntypedOIDFactory(StateAndOIDFactory untypedOIDFactory) { 663 this.untypedOIDFactory = untypedOIDFactory; 664 } 665 666 670 public OID createUntypedOID() { 671 return untypedOIDFactory.createUntypedOID(); 672 } 673 674 private Map candidatesForClsMap = new HashMap(); 675 676 680 public synchronized Class [] getQueryCandidatesFor(Class cls) { 681 Class [] clsArray = (Class []) candidatesForClsMap.get(cls); 685 if (clsArray == null) { 686 ClassMetaData cmd = getClassMetaData(cls); 687 if (cmd != null && !cmd.horizontal) { 688 clsArray = new Class [] {cls}; 690 } else { 691 Set result = new HashSet(); 692 if (cls.isInterface()) { 693 throw BindingSupportImpl.getInstance().unsupported( 694 "Query by interface is not currently supported"); 695 } else { 696 for (int i = 0; i < classes.length; i++) { 697 ClassMetaData aClass = classes[i]; 698 if (cls.equals(aClass.cls.getSuperclass())) { 699 result.add(aClass.cls); 700 } 701 } 702 } 703 if (result.isEmpty()) { 704 clsArray = EMPTY_CLASS_ARRAY; 705 } else { 706 clsArray = new Class [result.size()]; 707 result.toArray(clsArray); 708 } 709 } 710 candidatesForClsMap.put(cls, clsArray); 711 } 712 return clsArray; 713 } 714 715 } 716 | Popular Tags |