1 19 20 package org.apache.cayenne.map; 21 22 import java.io.Serializable ; 23 import java.util.ArrayList ; 24 import java.util.Collection ; 25 import java.util.Collections ; 26 import java.util.HashMap ; 27 import java.util.Iterator ; 28 import java.util.List ; 29 import java.util.Map ; 30 31 import org.apache.cayenne.CayenneRuntimeException; 32 import org.apache.cayenne.ObjectId; 33 import org.apache.cayenne.Persistent; 34 import org.apache.cayenne.query.Query; 35 import org.apache.cayenne.reflect.ClassDescriptor; 36 import org.apache.cayenne.reflect.ClassDescriptorMap; 37 import org.apache.cayenne.reflect.LifecycleCallbackRegistry; 38 import org.apache.cayenne.reflect.generic.DataObjectDescriptorFactory; 39 import org.apache.cayenne.reflect.pojo.EnhancedPojoDescriptorFactory; 40 import org.apache.cayenne.reflect.valueholder.ValueHolderDescriptorFactory; 41 import org.apache.cayenne.util.Util; 42 import org.apache.commons.collections.collection.CompositeCollection; 43 44 55 public class EntityResolver implements MappingNamespace, Serializable { 56 57 static final Object DUPLICATE_MARKER = new Object (); 58 59 protected boolean indexedByClass; 60 61 protected transient Map queryCache; 62 protected transient Map embeddableCache; 63 protected transient Map entityListenerCache; 64 protected transient Map dbEntityCache; 65 protected transient Map objEntityCache; 66 protected transient Map procedureCache; 67 protected List maps; 68 protected transient Map entityInheritanceCache; 69 protected EntityResolver clientEntityResolver; 70 71 protected transient ClassDescriptorMap classDescriptorMap; 74 75 protected transient LifecycleCallbackRegistry callbackRegistry; 77 78 81 public EntityResolver() { 82 this.indexedByClass = true; 83 this.maps = new ArrayList (); 84 this.embeddableCache = new HashMap (); 85 this.entityListenerCache = new HashMap (); 86 this.queryCache = new HashMap (); 87 this.dbEntityCache = new HashMap (); 88 this.objEntityCache = new HashMap (); 89 this.procedureCache = new HashMap (); 90 this.entityInheritanceCache = new HashMap (); 91 } 92 93 96 public EntityResolver(Collection dataMaps) { 97 this(); 98 this.maps.addAll(dataMaps); this.constructCache(); 100 } 101 102 105 synchronized void initCallbacks() { 106 if (callbackRegistry == null) { 107 LifecycleCallbackRegistry callbackRegistry = new LifecycleCallbackRegistry( 108 this); 109 110 Iterator maps = this.maps.iterator(); 112 while (maps.hasNext()) { 113 DataMap map = (DataMap) maps.next(); 114 Iterator listeners = map.getDefaultEntityListeners().iterator(); 115 while (listeners.hasNext()) { 116 EntityListener listener = (EntityListener) listeners.next(); 117 Object listenerInstance = createListener(listener); 118 119 CallbackDescriptor[] callbacks = listener 120 .getCallbackMap() 121 .getCallbacks(); 122 for (int i = 0; i < callbacks.length; i++) { 123 124 Iterator callbackMethods = callbacks[i] 125 .getCallbackMethods() 126 .iterator(); 127 while (callbackMethods.hasNext()) { 128 String method = (String ) callbackMethods.next(); 129 130 callbackRegistry.addDefaultListener( 132 i, 133 listenerInstance, 134 method); 135 } 136 } 137 } 138 } 139 140 Iterator entities = getObjEntities().iterator(); 142 while (entities.hasNext()) { 143 ObjEntity entity = (ObjEntity) entities.next(); 144 Class entityClass = entity.getJavaClass(); 145 146 Iterator entityListeners = entity.getEntityListeners().iterator(); 148 while (entityListeners.hasNext()) { 149 EntityListener listener = (EntityListener) entityListeners.next(); 150 Object listenerInstance = createListener(listener); 151 152 CallbackDescriptor[] callbacks = listener 153 .getCallbackMap() 154 .getCallbacks(); 155 for (int i = 0; i < callbacks.length; i++) { 156 157 Iterator callbackMethods = callbacks[i] 158 .getCallbackMethods() 159 .iterator(); 160 while (callbackMethods.hasNext()) { 161 String method = (String ) callbackMethods.next(); 162 163 callbackRegistry.addListener( 165 i, 166 entityClass, 167 listenerInstance, 168 method); 169 } 170 } 171 } 172 173 CallbackDescriptor[] callbacks = entity.getCallbackMap().getCallbacks(); 174 for (int i = 0; i < callbacks.length; i++) { 175 Iterator callbackMethods = callbacks[i] 176 .getCallbackMethods() 177 .iterator(); 178 while (callbackMethods.hasNext()) { 179 String method = (String ) callbackMethods.next(); 180 181 callbackRegistry.addListener(i, entityClass, method); 183 } 184 } 185 } 186 187 this.callbackRegistry = callbackRegistry; 188 } 189 } 190 191 194 private Object createListener(EntityListener listener) { 195 Class listenerClass; 196 197 try { 198 listenerClass = Util.getJavaClass(listener.getClassName()); 199 } 200 catch (ClassNotFoundException e) { 201 throw new CayenneRuntimeException("Invalid listener class: " 202 + listener.getClassName(), e); 203 } 204 205 try { 206 return listenerClass.newInstance(); 207 } 208 catch (Exception e) { 209 throw new CayenneRuntimeException("Listener class " 210 + listener.getClassName() 211 + " default constructor call failed", e); 212 } 213 } 214 215 221 public LifecycleCallbackRegistry getCallbackRegistry() { 222 if (callbackRegistry == null) { 223 initCallbacks(); 224 } 225 226 return callbackRegistry; 227 } 228 229 235 public EntityResolver getClientEntityResolver() { 236 237 if (clientEntityResolver == null) { 238 239 synchronized (this) { 240 241 if (clientEntityResolver == null) { 242 243 EntityResolver resolver = new ClientEntityResolver(); 244 245 Iterator it = getDataMaps().iterator(); 247 while (it.hasNext()) { 248 DataMap map = (DataMap) it.next(); 249 DataMap clientMap = map.getClientDataMap(this); 250 251 if (clientMap != null) { 252 resolver.addDataMap(clientMap); 253 } 254 } 255 256 clientEntityResolver = resolver; 257 } 258 } 259 } 260 261 return clientEntityResolver; 262 } 263 264 267 public Collection getDbEntities() { 268 CompositeCollection c = new CompositeCollection(); 269 Iterator it = getDataMaps().iterator(); 270 while (it.hasNext()) { 271 DataMap map = (DataMap) it.next(); 272 c.addComposited(map.getDbEntities()); 273 } 274 275 return c; 276 } 277 278 public Collection getObjEntities() { 279 CompositeCollection c = new CompositeCollection(); 280 Iterator it = getDataMaps().iterator(); 281 while (it.hasNext()) { 282 DataMap map = (DataMap) it.next(); 283 c.addComposited(map.getObjEntities()); 284 } 285 286 return c; 287 } 288 289 public Collection getProcedures() { 290 CompositeCollection c = new CompositeCollection(); 291 Iterator it = getDataMaps().iterator(); 292 while (it.hasNext()) { 293 DataMap map = (DataMap) it.next(); 294 c.addComposited(map.getProcedures()); 295 } 296 297 return c; 298 } 299 300 public Collection getQueries() { 301 CompositeCollection c = new CompositeCollection(); 302 Iterator it = getDataMaps().iterator(); 303 while (it.hasNext()) { 304 DataMap map = (DataMap) it.next(); 305 c.addComposited(map.getQueries()); 306 } 307 308 return c; 309 } 310 311 public DbEntity getDbEntity(String name) { 312 return _lookupDbEntity(name); 313 } 314 315 public ObjEntity getObjEntity(String name) { 316 return _lookupObjEntity(name); 317 } 318 319 public Procedure getProcedure(String name) { 320 return lookupProcedure(name); 321 } 322 323 public Query getQuery(String name) { 324 return lookupQuery(name); 325 } 326 327 330 public Embeddable getEmbeddable(String className) { 331 Embeddable result = (Embeddable) embeddableCache.get(className); 332 333 if (result == null) { 334 constructCache(); 337 result = (Embeddable) embeddableCache.get(className); 338 } 339 340 return result; 341 } 342 343 346 public EntityListener getEntityListener(String className) { 347 EntityListener result = (EntityListener) entityListenerCache.get(className); 348 349 if (result == null) { 350 constructCache(); 353 result = (EntityListener) entityListenerCache.get(className); 354 } 355 356 return result; 357 } 358 359 365 public synchronized ClassDescriptor getClassDescriptor(String entityName) { 366 if (entityName == null) { 367 throw new IllegalArgumentException ("Null entityName"); 368 } 369 370 return getClassDescriptorMap().getDescriptor(entityName); 371 } 372 373 public synchronized void addDataMap(DataMap map) { 374 if (!maps.contains(map)) { 375 maps.add(map); 376 map.setNamespace(this); 377 clearCache(); 378 } 379 } 380 381 386 public synchronized void clearCache() { 387 queryCache.clear(); 388 dbEntityCache.clear(); 389 objEntityCache.clear(); 390 procedureCache.clear(); 391 entityInheritanceCache.clear(); 392 entityListenerCache.clear(); 393 clientEntityResolver = null; 394 } 395 396 400 protected synchronized void constructCache() { 401 clearCache(); 402 403 405 Iterator mapIterator0 = maps.iterator(); 408 while (mapIterator0.hasNext()) { 409 DataMap map = (DataMap) mapIterator0.next(); 410 411 Iterator dbEntities = map.getDbEntities().iterator(); 412 while (dbEntities.hasNext()) { 413 DbEntity de = (DbEntity) dbEntities.next(); 414 dbEntityCache.put(de.getName(), de); 415 } 416 } 417 418 Iterator mapIterator1 = maps.iterator(); 419 while (mapIterator1.hasNext()) { 420 DataMap map = (DataMap) mapIterator1.next(); 421 422 Iterator objEntities = map.getObjEntities().iterator(); 424 while (objEntities.hasNext()) { 425 ObjEntity oe = (ObjEntity) objEntities.next(); 426 427 objEntityCache.put(oe.getName(), oe); 429 430 if (indexedByClass) { 432 String className = oe.getJavaClassName(); 433 if (className == null) { 434 continue; 435 } 436 437 String classKey = classKey(className); 438 439 Object existing = objEntityCache.get(classKey); 442 if (existing != null) { 443 444 if (existing != DUPLICATE_MARKER) { 445 objEntityCache.put(classKey, DUPLICATE_MARKER); 446 } 447 } 448 else { 449 objEntityCache.put(classKey, oe); 450 } 451 } 452 } 453 454 Iterator procedures = map.getProcedures().iterator(); 456 while (procedures.hasNext()) { 457 Procedure proc = (Procedure) procedures.next(); 458 procedureCache.put(proc.getName(), proc); 459 } 460 461 Iterator queries = map.getQueries().iterator(); 463 while (queries.hasNext()) { 464 Query query = (Query) queries.next(); 465 String name = query.getName(); 466 Object existingQuery = queryCache.put(name, query); 467 468 if (existingQuery != null && query != existingQuery) { 469 throw new CayenneRuntimeException("More than one Query for name" 470 + name); 471 } 472 } 473 474 Iterator listeners = map.getEntityListeners().iterator(); 476 while (listeners.hasNext()) { 477 EntityListener listener = (EntityListener) listeners.next(); 478 entityListenerCache.put(listener.getClassName(), listener); 479 } 480 } 481 482 Iterator mapIterator2 = maps.iterator(); 484 while (mapIterator2.hasNext()) { 485 DataMap map = (DataMap) mapIterator2.next(); 486 487 Iterator objEntities = map.getObjEntities().iterator(); 489 while (objEntities.hasNext()) { 490 ObjEntity oe = (ObjEntity) objEntities.next(); 491 492 EntityInheritanceTree node = (EntityInheritanceTree) entityInheritanceCache 495 .get(oe.getName()); 496 if (node == null) { 497 node = new EntityInheritanceTree(oe); 498 entityInheritanceCache.put(oe.getName(), node); 499 } 500 501 String superOEName = oe.getSuperEntityName(); 502 if (superOEName != null) { 503 EntityInheritanceTree superNode = (EntityInheritanceTree) entityInheritanceCache 504 .get(superOEName); 505 506 if (superNode == null) { 507 ObjEntity superOE = (ObjEntity) objEntityCache.get(superOEName); 509 if (superOE != null) { 510 superNode = new EntityInheritanceTree(superOE); 511 entityInheritanceCache.put(superOEName, superNode); 512 } 513 else { 514 continue; 519 } 520 } 521 522 superNode.addChildNode(node); 523 } 524 } 525 } 526 } 527 528 531 public synchronized DataMap getDataMap(String mapName) { 532 if (mapName == null) { 533 return null; 534 } 535 536 Iterator it = maps.iterator(); 537 while (it.hasNext()) { 538 DataMap map = (DataMap) it.next(); 539 if (mapName.equals(map.getName())) { 540 return map; 541 } 542 } 543 544 return null; 545 } 546 547 public synchronized void setDataMaps(Collection maps) { 548 this.maps.clear(); 549 this.maps.addAll(maps); 550 clearCache(); 551 } 552 553 556 public Collection getDataMaps() { 557 return Collections.unmodifiableList(maps); 558 } 559 560 567 public synchronized DbEntity lookupDbEntity(Class aClass) { 568 ObjEntity oe = lookupObjEntity(aClass); 569 return oe != null ? oe.getDbEntity() : null; 570 } 571 572 579 public synchronized DbEntity lookupDbEntity(Persistent dataObject) { 580 return lookupDbEntity(dataObject.getClass()); 581 } 582 583 588 public EntityInheritanceTree lookupInheritanceTree(ObjEntity entity) { 589 590 EntityInheritanceTree tree = (EntityInheritanceTree) entityInheritanceCache 591 .get(entity.getName()); 592 593 if (tree == null) { 594 597 constructCache(); 600 tree = (EntityInheritanceTree) entityInheritanceCache.get(entity.getName()); 601 } 602 603 return (tree == null || tree.getChildrenCount() == 0) ? null : tree; 605 } 606 607 613 public synchronized ObjEntity lookupObjEntity(Class aClass) { 614 if (!indexedByClass) { 615 throw new CayenneRuntimeException("Class index is disabled."); 616 } 617 618 return _lookupObjEntity(classKey(aClass.getName())); 619 } 620 621 627 public synchronized ObjEntity lookupObjEntity(Object object) { 628 if (object instanceof ObjEntity) { 629 return (ObjEntity) object; 630 } 631 632 if (object instanceof Persistent) { 633 ObjectId id = ((Persistent) object).getObjectId(); 634 if (id != null) { 635 return _lookupObjEntity(id.getEntityName()); 636 } 637 } 638 else if (object instanceof Class ) { 639 return lookupObjEntity((Class ) object); 640 } 641 642 return lookupObjEntity(object.getClass()); 643 } 644 645 652 public synchronized ObjEntity lookupObjEntity(String entityName) { 653 return _lookupObjEntity(entityName); 654 } 655 656 public Procedure lookupProcedure(Query q) { 657 return q.getMetaData(this).getProcedure(); 658 } 659 660 public Procedure lookupProcedure(String procedureName) { 661 662 Procedure result = (Procedure) procedureCache.get(procedureName); 663 if (result == null) { 664 constructCache(); 667 result = (Procedure) procedureCache.get(procedureName); 668 } 669 670 return result; 671 } 672 673 676 public synchronized Query lookupQuery(String name) { 677 Query result = (Query) queryCache.get(name); 678 679 if (result == null) { 680 constructCache(); 683 result = (Query) queryCache.get(name); 684 } 685 return result; 686 } 687 688 public synchronized void removeDataMap(DataMap map) { 689 if (maps.remove(map)) { 690 clearCache(); 691 } 692 } 693 694 public boolean isIndexedByClass() { 695 return indexedByClass; 696 } 697 698 public void setIndexedByClass(boolean b) { 699 indexedByClass = b; 700 } 701 702 707 protected String classKey(String className) { 708 return "^cl^" + className; 711 } 712 713 722 protected DbEntity _lookupDbEntity(Object object) { 723 if (object instanceof DbEntity) { 724 return (DbEntity) object; 725 } 726 727 Object result = dbEntityCache.get(object); 728 if (result == null) { 729 constructCache(); 732 result = dbEntityCache.get(object); 733 } 734 735 if (result == DUPLICATE_MARKER) { 736 throw new CayenneRuntimeException( 737 "Can't perform lookup. There is more than one DbEntity mapped to " 738 + object); 739 } 740 741 return (DbEntity) result; 742 } 743 744 753 protected ObjEntity _lookupObjEntity(String key) { 754 755 Object result = objEntityCache.get(key); 756 if (result == null) { 757 constructCache(); 760 result = objEntityCache.get(key); 761 } 762 763 if (result == DUPLICATE_MARKER) { 764 throw new CayenneRuntimeException( 765 "Can't perform lookup. There is more than one ObjEntity mapped to " 766 + key); 767 } 768 769 return (ObjEntity) result; 770 } 771 772 778 public ClassDescriptorMap getClassDescriptorMap() { 779 if (classDescriptorMap == null) { 780 ClassDescriptorMap classDescriptorMap = new ClassDescriptorMap(this); 781 782 classDescriptorMap.addFactory(new ValueHolderDescriptorFactory( 784 classDescriptorMap)); 785 classDescriptorMap.addFactory(new EnhancedPojoDescriptorFactory( 786 classDescriptorMap)); 787 classDescriptorMap.addFactory(new DataObjectDescriptorFactory( 788 classDescriptorMap)); 789 790 this.classDescriptorMap = classDescriptorMap; 791 } 792 793 return classDescriptorMap; 794 } 795 } 796 | Popular Tags |