1 18 package org.objectweb.speedo.mim.lib; 19 20 import org.objectweb.jorm.api.PClassMapping; 21 import org.objectweb.jorm.api.PException; 22 import org.objectweb.perseus.persistence.api.PersistenceException; 23 import org.objectweb.perseus.persistence.api.RolledBackPersistenceException; 24 import org.objectweb.perseus.persistence.api.TransactionalPersistenceManager; 25 import org.objectweb.speedo.api.Debug; 26 import org.objectweb.speedo.api.ExceptionHelper; 27 import org.objectweb.speedo.metadata.SpeedoFetchGroup; 28 import org.objectweb.speedo.mim.api.DetachedLifeCycle; 29 import org.objectweb.speedo.mim.api.SpeedoHome; 30 import org.objectweb.speedo.mim.api.SpeedoAccessor; 31 import org.objectweb.speedo.mim.api.SpeedoProxy; 32 import org.objectweb.speedo.pm.api.ProxyManager; 33 import org.objectweb.speedo.pm.api.ProxyManagerFactory; 34 import org.objectweb.speedo.query.api.QueryDefinition; 35 import org.objectweb.speedo.usercache.api.UserCache; 36 import org.objectweb.speedo.usercache.lib.CompositeUserCache; 37 import org.objectweb.speedo.usercache.lib.UserCacheImpl; 38 import org.objectweb.speedo.workingset.api.Transaction; 39 import org.objectweb.util.monolog.api.BasicLevel; 40 import org.objectweb.util.monolog.api.Logger; 41 42 import java.util.ArrayList ; 43 import java.util.Arrays ; 44 import java.util.Collection ; 45 import java.util.Collections ; 46 import java.util.Iterator ; 47 import java.util.List ; 48 import java.util.Map ; 49 50 import javax.jdo.InstanceCallbacks; 51 import javax.jdo.JDOException; 52 import javax.jdo.JDOUserException; 53 import javax.jdo.listener.AttachLifecycleListener; 54 import javax.jdo.listener.ClearLifecycleListener; 55 import javax.jdo.listener.CreateLifecycleListener; 56 import javax.jdo.listener.DeleteLifecycleListener; 57 import javax.jdo.listener.DetachLifecycleListener; 58 import javax.jdo.listener.DirtyLifecycleListener; 59 import javax.jdo.listener.InstanceLifecycleEvent; 60 import javax.jdo.listener.InstanceLifecycleListener; 61 import javax.jdo.listener.LoadLifecycleListener; 62 import javax.jdo.listener.StoreLifecycleListener; 63 64 67 public abstract class SpeedoHomeImpl implements SpeedoHome { 68 69 75 private InstanceLifecycleListener[][] lifecycleListener = null; 76 77 protected TransactionalPersistenceManager tpm = null; 78 79 protected ProxyManagerFactory pmf = null; 80 81 byte cachePolicy = CACHED; 82 83 boolean isFieldLockingLevel = false; 84 boolean prefetchOnQuery = true; 85 boolean prefetchOnExtent = true; 86 boolean prefetchOnGenClass = true; 87 88 protected Map namedQueries = null; 89 90 public SpeedoHomeImpl() { 91 } 92 93 public SpeedoHomeImpl(TransactionalPersistenceManager _tpm, 94 ProxyManagerFactory _pmf) { 95 this.tpm = _tpm; 96 this.pmf = _pmf; 97 } 98 99 103 protected boolean isAbstract() { 104 return false; 105 } 106 107 112 protected SpeedoProxy newSpeedoProxyInstance(Class clazz) throws Exception { 113 return (SpeedoProxy) clazz.newInstance(); 114 } 115 116 119 public boolean isCacheable() { 120 return (cachePolicy & CACHED) != 0; 121 } 122 123 public boolean allLoaded() { 124 return (cachePolicy & ALL) != 0; 125 } 126 127 public boolean hasToFix() { 128 return (cachePolicy & FIXED) != 0; 129 } 130 131 public void setCachePolicy(byte v) { 132 cachePolicy = v; 133 } 134 135 public boolean isFieldLockingLevel() { 136 return isFieldLockingLevel; 137 } 138 139 public void setFieldLockingLevel(boolean val) { 140 isFieldLockingLevel = val; 141 } 142 143 147 public Collection fgGetNestedFetchGroups(String fgName) { 148 return null; 149 } 150 151 155 public boolean fgIsDefined(String fgName) { 156 return false; 157 } 158 159 163 public Collection fgGetFieldsToLoad(String fgName) { 164 return null; 165 } 166 167 171 public final ProxyManagerFactory getProxyManagerFactory() { 172 return pmf; 173 } 174 175 180 public final void setProxyManagerFactory(ProxyManagerFactory _pmf) { 181 this.pmf = _pmf; 182 } 183 184 185 189 public final TransactionalPersistenceManager getTransactionalPersistenceManager() { 190 return tpm; 191 } 192 193 198 public final void setTransactionalPersistenceManager(TransactionalPersistenceManager _tpm) { 199 this.tpm = _tpm; 200 } 201 202 211 public final SpeedoAccessor readIntention(SpeedoProxy sp, long[] fields) { 212 if (!sp.jdoIsActive()) { 213 SpeedoAccessor sa = sp.getReferenceAccessor(); 214 if (sa == null) { 215 sp.setReferenceAccessor(sp.createAccessor()); 216 } 217 return sa; 218 } 219 ProxyManager pm = pmf.lookup(); 220 if (pm == null) { 221 throw new JDOUserException("When a persistent object is used (read), a PersistenceManager is needed"); 222 } 223 Transaction t = (Transaction) pm.currentTransaction(); 224 try { 225 SpeedoAccessor sa = (SpeedoAccessor) tpm.readIntention(t, sp, null); 226 sa.loadFields(pm, fields); 227 return sa; 228 } catch (RolledBackPersistenceException e) { 229 throw t.rollBackOnInternalError(e); 230 } catch (PersistenceException e) { 231 throw new JDOException ("Impossible to notify a read intention", 232 ExceptionHelper.getNested(e)); 233 } 234 } 235 236 public final SpeedoAccessor writeIntention(SpeedoProxy sp, long[] fields) { 237 return writeIntention(sp, fields, null); 238 } 239 240 250 public SpeedoAccessor writeIntention(SpeedoProxy sp, long[] fields, Object thinLock) { 251 if (!sp.jdoIsActive()) { 252 SpeedoAccessor sa = sp.getReferenceAccessor(); 253 if (sa == null) { 254 sp.setReferenceAccessor(sp.createAccessor()); 255 } 256 return sa; 257 } 258 ProxyManager pm = pmf.lookup(); 259 if (pm == null) { 260 throw new JDOUserException("When a persistent object is used (read), a PersistenceManager is needed"); 261 } 262 Transaction t = (Transaction) pm.currentTransaction(); 263 try { 264 SpeedoAccessor sa = (SpeedoAccessor) tpm.writeIntention(t, sp, 265 isFieldLockingLevel ? thinLock : null); 266 sa.loadFields(pm, fields); 267 return sa; 268 } catch (RolledBackPersistenceException e) { 269 throw t.rollBackOnInternalError(e); 270 } catch (PersistenceException e) { 271 throw new JDOException ("Impossible to notify a write intention", 272 ExceptionHelper.getNested(e)); 273 } 274 } 275 276 284 public final SpeedoAccessor getSpeedoAccessor(SpeedoProxy sp) { 285 if (!sp.jdoIsActive()) { 286 return sp.getReferenceAccessor(); 287 } 288 ProxyManager pm = pmf.lookup(); 289 if (pm == null) { 290 throw new JDOUserException("When a persistent object is used (read or write), a PersistenceManager is needed"); 291 } 292 return (SpeedoAccessor) ((Transaction) pm.currentTransaction()) 293 .lookup(sp.getPName()); 294 } 295 296 public final SpeedoProxy detachCopy(SpeedoProxy sp, 297 ProxyManager pm, 298 Map map, 299 Object clone, 300 Collection fgHints) { 301 Logger logger = getLogger(); 302 if (Debug.ON && logger != null && logger.isLoggable(BasicLevel.DEBUG)) { 303 logger.log(BasicLevel.DEBUG, "detachCopy()"); 304 } 305 if (!isAbstract() && clone == null){ 306 try { 307 clone = newSpeedoProxyInstance(sp.getClass()); 309 SpeedoProxy spClone = (SpeedoProxy)clone; 310 spClone.setEncodedPName(pm.getObjectId(sp)); 311 spClone.setCeAge(0); 312 spClone.jdoIsActive(false); 313 SpeedoAccessor fieldsClone = sp.createAccessor(); 315 spClone.setReferenceAccessor(fieldsClone); 316 fieldsClone.setSpeedoProxy(spClone); 317 if(map != null) 319 map.put(sp, clone); 320 synchronized(fgHints){ 321 readIntention(sp, null).detachCopy(pm, map, fieldsClone, fgHints); 322 } 323 fieldsClone.setDetachedStatus(DetachedLifeCycle.DETACHED_CLEAN); 325 } catch(Exception e){ 326 throw new JDOUserException("Detach cannot be performed", new Exception []{ExceptionHelper.getNested(e)}); 327 } 328 } 329 return (SpeedoProxy)clone; 330 } 331 332 public final void attachCopy(SpeedoProxy sp, 333 ProxyManager pm, 334 Map map, 335 Object clone, 336 SpeedoAccessor sa, 337 boolean makeTransactional) { 338 339 if(map != null) { 340 if( (SpeedoProxy) map.get(clone) == sp) 341 return; 342 map.put(clone, sp); 343 if (!sa.checkVersion(((SpeedoProxy)clone).getReferenceAccessor())) { 345 throw new JDOException("The detached copy is no more valid."); 346 } 347 sa.attachCopy(pm, map, 348 ((SpeedoProxy) clone).getReferenceAccessor(), 349 makeTransactional); 350 } 351 } 352 353 354 public final Collection fgGetFieldsToLoad(String fgName, boolean onlyDirectRef){ 355 Collection c = fgGetFieldsToLoad(fgName); 356 if(onlyDirectRef){ 357 Iterator it = c.iterator(); 358 while(it.hasNext()) { 359 String s = (String ) it.next(); 360 if(s.indexOf(SpeedoFetchGroup.FG_DOT) != -1 361 || s.indexOf(SpeedoFetchGroup.FG_SHARP) != -1 362 || s.indexOf(SpeedoFetchGroup.FG_SLASH) != -1 363 || s.indexOf(SpeedoFetchGroup.FG_KEY) != -1 364 || s.indexOf(SpeedoFetchGroup.FG_VALUE) != -1) { 365 it.remove(); 366 } 367 } 368 } 369 return c; 370 } 371 372 public void setPrefetchOnExtent(boolean prefetch) { 373 this.prefetchOnExtent = prefetch; 374 } 375 376 377 public boolean getPrefetchOnExtent() { 378 return prefetchOnExtent; 379 } 380 public void setPrefetchOnGenClass(boolean prefetch) { 381 this.prefetchOnGenClass = prefetch; 382 } 383 public boolean getPrefetchOnGenClass() { 384 return prefetchOnGenClass; 385 } 386 public void setPrefetchOnQuery(boolean prefetch) { 387 this.prefetchOnQuery = prefetch; 388 } 389 public boolean getPrefetchOnQuery() { 390 return prefetchOnQuery; 391 } 392 393 public void initSH() { 394 } 395 396 public Class getClassForQuery(String className, String queryName) { 397 try { 398 return getClass().getClassLoader().loadClass(className); 399 } catch (ClassNotFoundException e) { 400 throw new JDOUserException("Class '" + className 401 + "' used in the query '" + queryName 402 + "' defined in by the class '" + getClassName() 403 + "' is not available. See the inner class loading problem: ", e); 404 } 405 } 406 407 public final QueryDefinition addNamedQuery(String name, QueryDefinition query) { 408 return (QueryDefinition) namedQueries.put(name, query); 409 } 410 public final QueryDefinition removeNamedQuery(String name) { 411 return (QueryDefinition) namedQueries.remove(name); 412 } 413 public final QueryDefinition getNamedQuery(String name) { 414 return (QueryDefinition) namedQueries.get(name); 415 } 416 417 public String getPath() { 418 return getClassName(); 419 } 420 421 424 protected UserCache[] userCaches = new UserCache[0]; 425 426 protected synchronized UserCache addUserCache(String userCacheName, String [] fields, int id) { 427 UserCacheImpl uc = new UserCacheImpl(); 428 uc.setName(userCacheName); 429 uc.setIndexFieldNames(fields); 430 uc.setId(id); 431 uc.setActive(true); 432 if (id >= userCaches.length) { 433 UserCache[] newUserCaches = new UserCache[id+1]; 434 System.arraycopy(userCaches, 0, newUserCaches, 0, userCaches.length); 435 userCaches = newUserCaches; 436 } 437 userCaches[id] = uc; 438 return uc; 439 } 440 441 444 public boolean activeUserCache(String cacheName) { 445 return false; 446 } 447 public UserCache getUserCache(int cacheId) { 448 if (cacheId < 0 449 || cacheId >= userCaches.length 450 || userCaches[cacheId] == null) { 451 return null; 452 } 453 return userCaches[cacheId]; 454 } 455 456 public UserCache getUserCache(Collection fieldNames) { 457 PClassMapping[] pcms = null; 458 try { 459 pcms = getSubPCMs(); 460 } catch (PException e) { 461 throw new JDOException("Impossible to fetch home of sub class of " 462 + getClassName(), e); 463 } 464 if (pcms == null || pcms.length == 0) { 465 return getUserCacheOfTheClass(fieldNames); 466 } 467 ArrayList ucs = null; 468 UserCache uc = getUserCacheOfTheClass(fieldNames); 470 if(uc != null) { 472 if (ucs == null) { 473 ucs = new ArrayList (); 474 } 475 ucs.add(uc); 476 } 477 for (int i = 0; i < pcms.length; i++) { 479 uc = ((SpeedoHomeImpl) pcms[i]) 480 .getUserCacheOfTheClass(fieldNames); 481 if (uc != null) { 482 if (ucs == null) { 483 ucs = new ArrayList (); 484 } 485 ucs.add(uc); 486 } 487 } 488 if (ucs != null) { 489 return new CompositeUserCache((UserCache[]) 490 ucs.toArray(new UserCache[ucs.size()])); 491 } 492 return null; 493 } 494 495 private UserCache getUserCacheOfTheClass(Collection fieldNames) { 496 for(int i=0; i<userCaches.length; i++) { 497 if (userCaches[i] != null && userCaches[i].isActive()) { 498 String [] fns = userCaches[i].getIndexFieldNames(); 499 List l = Arrays.asList(fns); 500 if (fns.length == fieldNames.size() 501 && fieldNames.containsAll(l) 502 && l.containsAll(fieldNames) 503 ) { 504 return userCaches[i]; 505 } 506 } 507 } 508 return null; 509 } 510 511 public Collection getActiveUserCache() { 512 if (userCaches == null || userCaches.length == 0) { 513 return Collections.EMPTY_LIST; 514 } 515 ArrayList al = new ArrayList (); 516 for(int i=0; i<userCaches.length; i++) { 517 if (userCaches[i] != null && userCaches[i].isActive()) { 518 al.add(userCaches[i]); 519 } 520 } 521 return al; 522 } 523 public void userCacheEntryUnbound(Object oid) { 524 if (userCaches == null || userCaches.length == 0) { 525 return; 526 } 527 for(int i=0; i<userCaches.length; i++) { 528 if (userCaches[i] != null && userCaches[i].isActive()) { 529 userCaches[i].unbindFromOID(oid); 530 } 531 } 532 } 533 534 538 public void addInstanceLifeCycleListener(InstanceLifecycleListener listener) { 539 getLifecycleListener(); 540 if (listener instanceof AttachLifecycleListener) { 541 addListener(InstanceLifecycleEvent.ATTACH, listener); 542 } 543 if (listener instanceof DetachLifecycleListener) { 544 addListener(InstanceLifecycleEvent.DETACH, listener); 545 } 546 if (listener instanceof ClearLifecycleListener) { 547 addListener(InstanceLifecycleEvent.CLEAR, listener); 548 } 549 if (listener instanceof CreateLifecycleListener) { 550 addListener(InstanceLifecycleEvent.CREATE, listener); 551 } 552 if (listener instanceof DeleteLifecycleListener) { 553 addListener(InstanceLifecycleEvent.DELETE, listener); 554 } 555 if (listener instanceof DirtyLifecycleListener) { 556 addListener(InstanceLifecycleEvent.DIRTY, listener); 557 } 558 if (listener instanceof LoadLifecycleListener) { 559 addListener(InstanceLifecycleEvent.LOAD, listener); 560 } 561 if (listener instanceof StoreLifecycleListener) { 562 addListener(InstanceLifecycleEvent.STORE, listener); 563 } 564 } 565 566 570 public void removeInstanceLifeCycleListener(InstanceLifecycleListener listener) { 571 getLifecycleListener(); 572 if (listener instanceof AttachLifecycleListener) { 573 removeListener(InstanceLifecycleEvent.ATTACH, listener); 574 } 575 if (listener instanceof DetachLifecycleListener) { 576 removeListener(InstanceLifecycleEvent.DETACH, listener); 577 } 578 if (listener instanceof ClearLifecycleListener) { 579 removeListener(InstanceLifecycleEvent.CLEAR, listener); 580 } 581 if (listener instanceof CreateLifecycleListener) { 582 removeListener(InstanceLifecycleEvent.CREATE, listener); 583 } 584 if (listener instanceof DeleteLifecycleListener) { 585 removeListener(InstanceLifecycleEvent.DELETE, listener); 586 } 587 if (listener instanceof DirtyLifecycleListener) { 588 removeListener(InstanceLifecycleEvent.DIRTY, listener); 589 } 590 if (listener instanceof LoadLifecycleListener) { 591 removeListener(InstanceLifecycleEvent.LOAD, listener); 592 } 593 if (listener instanceof StoreLifecycleListener) { 594 removeListener(InstanceLifecycleEvent.STORE, listener); 595 } 596 } 597 598 601 private void getLifecycleListener() { 602 if (lifecycleListener == null) { 603 lifecycleListener = new InstanceLifecycleListener[8][]; 604 } 605 } 606 607 614 private synchronized void addListener(int eventType, InstanceLifecycleListener l) { 615 if (lifecycleListener[eventType] == null) { 616 lifecycleListener[eventType] = new InstanceLifecycleListener[]{l}; 617 } else { 618 List list = Arrays.asList(lifecycleListener[eventType]); 619 if (!list.contains(l)) { 620 list.add(l); 621 lifecycleListener[eventType] = (InstanceLifecycleListener[]) 622 list.toArray(new InstanceLifecycleListener[0]); 623 } 624 } 625 } 626 627 633 private synchronized void removeListener(int eventType, InstanceLifecycleListener l) { 634 if (lifecycleListener[eventType] == null || lifecycleListener[eventType].length == 0) { 635 return; 636 } 637 if (lifecycleListener[eventType].length == 1 && lifecycleListener[eventType][0] == l) { 638 lifecycleListener[eventType] = null; 639 } else { 640 InstanceLifecycleListener[] neo = 641 new InstanceLifecycleListener[lifecycleListener[eventType].length -1]; 642 int pos = 0; 643 for(int i=0; i<lifecycleListener[eventType].length; i++) { 644 if (lifecycleListener[eventType][i] != l) { 645 neo[pos++] = lifecycleListener[eventType][i]; 646 } 647 } 648 } 649 } 650 651 public void sendEvent(int eventType, Object source, Object target, boolean pre) { 652 if (source instanceof InstanceCallbacks) { 653 switch(eventType) { 654 case InstanceLifecycleEvent.CLEAR: 655 if (pre) { 656 ((InstanceCallbacks) source).jdoPreClear(); 657 } 658 break; 659 case InstanceLifecycleEvent.DELETE: 660 if (pre) { 661 ((InstanceCallbacks) source).jdoPreDelete(); 662 } 663 break; 664 case InstanceLifecycleEvent.LOAD: 665 if (!pre) { 666 ((InstanceCallbacks) source).jdoPostLoad(); 667 } 668 break; 669 case InstanceLifecycleEvent.STORE: 670 if (pre) { 671 ((InstanceCallbacks) source).jdoPreStore(); 672 } 673 break; 674 } 675 } 676 if (lifecycleListener == null || lifecycleListener[eventType] == null) { 677 return; 678 } 679 InstanceLifecycleEvent ev = new InstanceLifecycleEvent(source, eventType, target); 680 for(int i=0; i<lifecycleListener[eventType].length; i++) { 681 switch(eventType) { 682 case InstanceLifecycleEvent.ATTACH: 683 if (pre) { 684 ((AttachLifecycleListener) lifecycleListener[eventType][i]).preAttach(ev); 685 } else { 686 ((AttachLifecycleListener) lifecycleListener[eventType][i]).postAttach(ev); 687 } 688 break; 689 case InstanceLifecycleEvent.DETACH: 690 if (pre) { 691 ((DetachLifecycleListener) lifecycleListener[eventType][i]).preDetach(ev); 692 } else { 693 ((DetachLifecycleListener) lifecycleListener[eventType][i]).postDetach(ev); 694 } 695 break; 696 case InstanceLifecycleEvent.CREATE: 697 if (!pre) { 698 ((CreateLifecycleListener) lifecycleListener[eventType][i]).postCreate(ev); 699 } 700 break; 701 case InstanceLifecycleEvent.DELETE: 702 if (pre) { 703 ((DeleteLifecycleListener) lifecycleListener[eventType][i]).preDelete(ev); 704 } else { 705 ((DeleteLifecycleListener) lifecycleListener[eventType][i]).postDelete(ev); 706 } 707 break; 708 case InstanceLifecycleEvent.LOAD: 709 if (!pre) { 710 ((LoadLifecycleListener) lifecycleListener[eventType][i]).postLoad(ev); 711 } 712 break; 713 case InstanceLifecycleEvent.STORE: 714 if (pre) { 715 ((StoreLifecycleListener) lifecycleListener[eventType][i]).preStore(ev); 716 } else { 717 ((StoreLifecycleListener) lifecycleListener[eventType][i]).postStore(ev); 718 } 719 break; 720 case InstanceLifecycleEvent.DIRTY: 721 if (pre) { 722 ((DirtyLifecycleListener) lifecycleListener[eventType][i]).preDirty(ev); 723 } else { 724 ((DirtyLifecycleListener) lifecycleListener[eventType][i]).postDirty(ev); 725 } 726 break; 727 case InstanceLifecycleEvent.CLEAR: 728 if (pre) { 729 ((ClearLifecycleListener) lifecycleListener[eventType][i]).preClear(ev); 730 } else { 731 ((ClearLifecycleListener) lifecycleListener[eventType][i]).postClear(ev); 732 } 733 break; 734 } 735 } 736 737 } 738 } 739 | Popular Tags |