| 1 27 28 package org.objectweb.speedo.pm.lib; 29 30 import java.util.ArrayList ; 31 import java.util.Collection ; 32 import java.util.Collections ; 33 import java.util.HashMap ; 34 import java.util.Iterator ; 35 import java.util.Map ; 36 import java.util.Set ; 37 38 import javax.jdo.Extent; 39 import javax.jdo.FetchPlan; 40 import javax.jdo.JDODataStoreException; 41 import javax.jdo.JDOException; 42 import javax.jdo.JDOFatalInternalException; 43 import javax.jdo.JDOFatalUserException; 44 import javax.jdo.JDOUnsupportedOptionException; 45 import javax.jdo.JDOUserException; 46 import javax.jdo.PersistenceManager; 47 import javax.jdo.PersistenceManagerFactory; 48 import javax.jdo.Query; 49 import javax.jdo.datastore.JDOConnection; 50 import javax.jdo.datastore.Sequence; 51 import javax.jdo.listener.InstanceLifecycleEvent; 52 import javax.jdo.listener.InstanceLifecycleListener; 53 import javax.transaction.Status ; 54 55 import org.objectweb.fractal.api.Component; 56 import org.objectweb.fractal.api.Interface; 57 import org.objectweb.fractal.api.NoSuchInterfaceException; 58 import org.objectweb.fractal.api.control.BindingController; 59 import org.objectweb.fractal.util.Fractal; 60 import org.objectweb.jorm.api.PClassMapping; 61 import org.objectweb.jorm.api.PException; 62 import org.objectweb.jorm.naming.api.PName; 63 import org.objectweb.jorm.naming.api.PNameCoder; 64 import org.objectweb.jorm.util.api.Loggable; 65 import org.objectweb.perseus.cache.api.CacheEntry; 66 import org.objectweb.perseus.concurrency.lib.Semaphore; 67 import org.objectweb.perseus.persistence.api.NoDSIPersistenceException; 68 import org.objectweb.perseus.persistence.api.PersistenceException; 69 import org.objectweb.perseus.persistence.api.RolledBackPersistenceException; 70 import org.objectweb.perseus.persistence.api.State; 71 import org.objectweb.perseus.persistence.api.StateFilter; 72 import org.objectweb.perseus.persistence.api.TransactionalPersistenceManager; 73 import org.objectweb.perseus.persistence.api.TransactionalWorkingSet; 74 import org.objectweb.perseus.persistence.api.VirtualState; 75 import org.objectweb.speedo.api.ExceptionHelper; 76 import org.objectweb.speedo.api.SpeedoProperties; 77 import org.objectweb.speedo.genclass.api.SpeedoGenClassProxy; 78 import org.objectweb.speedo.mapper.api.JormFactory; 79 import org.objectweb.speedo.metadata.SpeedoVersion; 80 import org.objectweb.speedo.mim.api.DetachedLifeCycle; 81 import org.objectweb.speedo.mim.api.LifeCycle; 82 import org.objectweb.speedo.mim.api.SpeedoAccessor; 83 import org.objectweb.speedo.mim.api.SpeedoHome; 84 import org.objectweb.speedo.mim.api.SpeedoProxy; 85 import org.objectweb.speedo.mim.lib.SpeedoFetchPlan; 86 import org.objectweb.speedo.pm.api.ProxyManager; 87 import org.objectweb.speedo.pm.api.ProxyManagerFactory; 88 import org.objectweb.speedo.query.api.QueryDefinition; 89 import org.objectweb.speedo.query.api.QueryManager; 90 import org.objectweb.speedo.query.api.QueryManagerAttribute; 91 import org.objectweb.speedo.query.lib.SpeedoExtent; 92 import org.objectweb.speedo.query.lib.SpeedoQuery; 93 import org.objectweb.speedo.workingset.api.Transaction; 94 import org.objectweb.util.monolog.api.BasicLevel; 95 import org.objectweb.util.monolog.api.Logger; 96 import org.objectweb.util.monolog.api.LoggerFactory; 97 98 99 126 public class SpeedoProxyManager 127 implements PersistenceManager, 128 ProxyManager, 129 BindingController{ 130 131 public final static String PROXY_MANAGER_FACTORY_BINDING = "proxy-manager-factory"; 132 public final static String TRANSACTIONAL_PERSISTENCE_MANAGER_BINDING = "transactional-persistence-manager"; 133 public final static String QUERY_MANAGER_BINDING = "query-manager"; 134 public final static String TRANSACTION_BINDING = "transaction"; 135 public final static String JORM_FACTORY_BINDING = "jorm-factory"; 136 public final static String PNAME_CODER_BINDING = "pname-coder"; 137 public final static String COMPONENT_BINDING = "component"; 138 public final static String LOGGER_NAME 139 = SpeedoProperties.LOGGER_NAME + ".rt.SpeedoProxyManager"; 140 141 private Logger logger; 142 private LoggerFactory loggerFactory; 143 144 147 private ProxyManagerFactory pmf = null; 148 149 153 private QueryManager queryManager = null; 154 155 158 private Transaction tx; 159 160 163 private TransactionalPersistenceManager tpm = null; 164 165 168 private JormFactory jf = null; 169 170 173 private PNameCoder pnc = null; 174 175 178 private Object connectionSpec = null; 179 180 184 private short nbUse = 0; 185 186 189 private Object userObject = null; 190 191 194 boolean ignoreCache = true; 195 196 199 private ProxyManager thisPM = null; 200 201 204 private Thread currentThread = null; 205 206 209 private Semaphore semaphore; 210 211 private boolean prefetchOnExtent = true; 212 private boolean prefetchOnQuery = true; 213 214 private FetchPlan fetchPlan; 215 216 private HashMap userObjects = new HashMap (); 217 218 public SpeedoProxyManager() { 219 semaphore = new Semaphore(false); 220 } 221 222 public Query createQuery(Object o) { 223 SpeedoQuery sq = new SpeedoQuery(); 224 sq.withPrefetch(prefetchOnQuery); 225 sq.setProxyManager(this); 226 sq.setFetchPlan(getFetchPlan()); 228 sq.setQueryManager(queryManager); 229 sq.setIgnoreCache(ignoreCache); 230 sq.setLogger(loggerFactory.getLogger(logger.getName() + ".query")); 231 if (o!= null && o instanceof QueryDefinition) { 232 sq.defineWith((QueryDefinition) o); 233 } 234 return sq; 235 } 236 237 238 241 public String [] listFc() { 242 return new String [] { 243 PROXY_MANAGER_FACTORY_BINDING, 244 QUERY_MANAGER_BINDING, 245 TRANSACTIONAL_PERSISTENCE_MANAGER_BINDING, 246 TRANSACTION_BINDING, 247 JORM_FACTORY_BINDING, 248 PNAME_CODER_BINDING 249 }; 250 } 251 252 public Object lookupFc(String s) { 253 if (PROXY_MANAGER_FACTORY_BINDING.equals(s)) { 254 return pmf; 255 } else if (QUERY_MANAGER_BINDING.equals(s)) { 256 return queryManager; 257 } else if (TRANSACTIONAL_PERSISTENCE_MANAGER_BINDING.equals(s)) { 258 return tpm; 259 } else if (TRANSACTION_BINDING.equals(s)) { 260 return tx; 261 } else if (PNAME_CODER_BINDING.equals(s)) { 262 return pnc; 263 } else if (JORM_FACTORY_BINDING.equals(s)) { 264 return jf; 265 } else { 266 return null; 267 } 268 } 269 270 public void bindFc(String s, Object o) { 271 if ("monolog-factory".equals(s)) { 272 loggerFactory = (LoggerFactory) o; 273 } else if ("logger".equals(s)) { 274 logger = (Logger) o; 275 } else if (PROXY_MANAGER_FACTORY_BINDING.equals(s)) { 276 pmf = (ProxyManagerFactory) o; 277 } else if (QUERY_MANAGER_BINDING.equals(s)) { 278 queryManager = (QueryManager) o; 279 if (queryManager != null) { 280 try { 281 QueryManagerAttribute qma = (QueryManagerAttribute) 282 Fractal.getAttributeController( 283 ((Interface) queryManager).getFcItfOwner()) ; 284 prefetchOnExtent = qma.getPrefetchActivatedOnExtent(); 285 prefetchOnQuery = qma.getPrefetchActivatedOnQuery(); 286 } catch (Exception e) { 287 logger.log(BasicLevel.WARN, 288 "impossible to fetch the attribute prefetchActivatedOnExtent: ", e); 289 } 290 } 291 } else if (TRANSACTIONAL_PERSISTENCE_MANAGER_BINDING.equals(s)) { 292 tpm = (TransactionalPersistenceManager) o; 293 } else if (TRANSACTION_BINDING.equals(s)) { 294 tx = (Transaction) o; 295 } else if (PNAME_CODER_BINDING.equals(s)) { 296 pnc = (PNameCoder) o; 297 } else if (JORM_FACTORY_BINDING.equals(s)) { 298 jf = (JormFactory) o; 299 } else if (COMPONENT_BINDING.equals(s)) { 300 try { 301 thisPM = (ProxyManager) ((Component) o).getFcInterface("proxy-manager"); 302 } catch (NoSuchInterfaceException e) { 303 304 } 305 } 306 } 307 308 public void unbindFc(String s) { 309 if (PROXY_MANAGER_FACTORY_BINDING.equals(s)) 310 pmf = null; 311 else if (TRANSACTIONAL_PERSISTENCE_MANAGER_BINDING.equals(s)) 312 tpm = null; 313 else if (TRANSACTION_BINDING.equals(s)) 314 tx = null; 315 else if (QUERY_MANAGER_BINDING.equals(s)) 316 queryManager = null; 317 else if (PNAME_CODER_BINDING.equals(s)) 318 pnc = null; 319 else if (JORM_FACTORY_BINDING.equals(s)) 320 jf = null; 321 } 322 323 326 public Object getNativeConnection() { 327 try { 328 if (tx.getOptimistic()) { 329 return new DSConnectionFilter( 330 tx.getConnectionHolder().getCHConnectionForRead(), 331 true); 332 } else { 333 return new DSConnectionFilter( 334 tx.getConnectionHolder().getCHConnectionForWrite(), 335 false); 336 } 337 } catch(PersistenceException e) { 338 throw new JDODataStoreException("Impossible to allocate a native connection:", e); 339 } 340 } 341 342 public void addInstanceLifecycleListener(InstanceLifecycleListener l, Class [] classes) { 345 } 347 public void removeInstanceLifecycleListener(InstanceLifecycleListener classes) { 348 } 350 public void flush() { 351 try { 352 tpm.flush(tx, (StateFilter) null); 353 } catch (PersistenceException e) { 354 throw new JDODataStoreException("Impossible to flush the working set"); 355 } 356 } 357 358 public JDOConnection getDataStoreConnection() { 359 return this; 360 } 361 362 public FetchPlan getFetchPlan() { 363 if(fetchPlan == null){ 364 fetchPlan = new SpeedoFetchPlan(); 365 } 366 return fetchPlan; 367 } 368 369 372 public java.lang.Class getObjectIdClass(Class cls) { 373 bindPMThread(); 374 if (cls == null) { 375 return null; 376 } 377 try { 378 return jf.getPBinder(cls).getNull().getClass(); 379 } catch (PException e) { 380 Exception ie = ExceptionHelper.getNested(e); 381 logger.log(BasicLevel.ERROR, 382 "Error during the fetching of the manager of the class " 383 + cls.getName(), ie); 384 throw new JDOException("", ie); 385 } 386 } 387 388 393 public boolean isClosed() { 394 bindPMThread(); 395 return nbUse == 0; 396 } 397 398 405 public void close() { 406 if (semaphore.on) { 407 semaphore.P(); 408 } 409 if (nbUse == 0) { 410 return; 411 } else if (nbUse > 1) { 412 nbUse--; 413 logger.log(BasicLevel.DEBUG, "Imbricated persistence Manager closed (" 414 + nbUse + ")"); 415 return; 416 } 417 bindPMThread(); 418 try { 419 tpm.close(tx); 420 } catch (PersistenceException e) { 421 throw new JDOFatalInternalException( 422 "Impossible to close the persistence manager", 423 ExceptionHelper.getNested(e)); 424 } finally { 425 nbUse--; 426 userObject = null; 427 connectionSpec = null; 429 currentThread = null; 430 try { 431 pmf.proxyManagerClosed(thisPM); 432 } finally { 433 if (semaphore.on) { 434 semaphore.V(); 435 } 436 if (logger.isLoggable(BasicLevel.INFO)) 437 logger.log(BasicLevel.INFO, "Persistence Manager closed"); 438 } 439 } 440 } 441 442 447 public javax.jdo.Transaction currentTransaction() { 448 bindPMThread(); 449 return tx; 450 } 451 452 456 public void evict(Object o) { 457 if (o == null) 458 return; 459 assertIsOpen(); 460 bindPMThread(); 461 SpeedoProxy sp = (SpeedoProxy) o; 462 if (tx.isActive() && sp.jdoIsDirty()) 463 throw new JDOUserException("Impossible to evict a dirty " + 464 "instance attached to an active transaction"); 465 try { 466 tpm.evict(tx, sp.getCeIdentifier(), false); 467 } catch (PersistenceException e) { 468 throw new JDOUserException( 469 "Impossible to evict the persistent object from the cache", e); 470 } 471 } 472 473 478 public void evictAll(Object [] pcs) { 479 Throwable [] th = new Throwable [pcs.length]; 480 int lg = 0; 481 for (int i = 0; i < pcs.length; i++) { 482 try { 483 if (pcs[i] != null) { 484 evict(pcs[i]); 485 } 486 } catch (Throwable e) { 487 th[lg] = e; 488 lg++; 489 } 490 } 491 if (lg > 0) { 492 Throwable [] tfin = new Throwable [lg]; 493 System.arraycopy(th, 0, tfin, 0, lg); 494 throw new JDOUserException("Impossible to evict", tfin); 495 } 496 } 497 498 502 public void evictAll(Collection pcs) { 503 evictAll(pcs.toArray()); 504 } 505 506 512 public void evictAll() { 513 assertIsOpen(); 514 try { 515 tpm.evictAll(tx, false); 516 } catch (PersistenceException e) { 517 throw new JDOException("Error during the eviction of all cache entries: ", 518 ExceptionHelper.getNested(e)); 519 } 520 } 521 522 531 public void refresh(Object o) { 532 if (o == null) 533 return; 534 SpeedoProxy sp = (SpeedoProxy) o; 535 assertIsOpen(); 536 bindPMThread(); 537 assertIsSpeedoProxy(sp, "refresh"); 538 assertPersistenceManager(sp); 539 if (!sp.jdoIsPersistent()) 540 throw new JDOUserException("Refresh on a transient instance."); 541 speedoRefresh(sp, new HashMap (), new ArrayList ()); 542 } 543 544 public void speedoRefresh(SpeedoProxy sp, Map map, Collection fgHints){ 545 try { 546 if (map != null && !map.containsKey(sp.getPName())) { 547 map.put(sp.getPName(), sp); 548 tpm.refresh(tx, sp); 549 SpeedoAccessor sa = (SpeedoAccessor) tpm.readIntention(tx, sp, null); 550 sa.refresh(this, map, fgHints); 551 } 552 } catch (PersistenceException e) { 553 throw new JDOException("Impossible to refresh a persistent instance", e); 554 } 555 } 556 557 562 public void refreshAll(Object [] pcs) { 563 Throwable [] th = new Throwable [pcs.length]; 564 int lg = 0; 565 for (int i = 0; i < pcs.length; i++) { 566 try { 567 if (pcs[i] != null) { 568 refresh(pcs[i]); 569 } 570 } catch (Throwable e) { 571 th[lg] = e; 572 lg++; 573 } 574 } 575 if (lg > 0) { 576 Throwable [] tfin = new Throwable [lg]; 577 System.arraycopy(th, 0, tfin, 0, lg); 578 throw new JDOUserException("Impossible to refresh", tfin); 579 } 580 } 581 582 586 public void refreshAll(Collection pcs) { 587 refreshAll(pcs.toArray()); 588 } 589 590 596 public void refreshAll() { 597 assertIsOpen(); 598 if (!tx.isActive()) { 599 return; 600 } 601 Set entries = tx.entries(); 602 int size = entries.size(); 603 if (size == 0) { 604 return; 605 } 606 Object [] sps = new Object [size]; 607 Iterator it = entries.iterator(); 608 int i=0; 609 while(it.hasNext() && i<sps.length) { 610 State s = (State) it.next(); 611 sps[i] = s.getCacheEntry(); 612 i++; 613 } 614 refreshAll(sps); 615 } 616 617 public void refreshAll(JDOException arg0) { 618 refreshAll(); 620 } 621 622 623 627 public Query newQuery() { 628 assertIsOpen(); 629 bindPMThread(); 630 return createQuery(null); 631 } 632 633 public Query newQuery(String query) { 634 assertIsOpen(); 635 bindPMThread(); 636 return createQuery(null); 638 } 639 640 public Query newNamedQuery(Class klass, String name) { 641 try { 642 QueryDefinition qd = ((SpeedoHome) jf.getPClassMapping(klass)).getNamedQuery(name); 643 return createQuery(qd); 644 } catch (PException e) { 645 Exception ie = ExceptionHelper.getNested(e); 646 logger.log(BasicLevel.ERROR, 647 "Error during the fetching of the manager of the class " 648 + klass.getName(), ie); 649 throw new JDOException("Error during the fetching of the manager of the class ", ie); 650 } 651 } 652 653 663 public Query newQuery(Object compiled) { 664 assertIsOpen(); 665 bindPMThread(); 666 return createQuery(compiled); 667 } 668 669 675 public Query newQuery(String language, Object query) { 676 assertIsOpen(); 677 bindPMThread(); 678 if (language.compareTo("java.jdo.query.toVerify") == 0) { 679 return createQuery(query); 680 } else 681 throw new JDOUnsupportedOptionException("Language \"" + language 682 + "\"" + " is not supported by this jdo implementation"); 683 } 684 685 690 public Query newQuery(Class cls) { 691 assertIsOpen(); 692 bindPMThread(); 693 Query q = createQuery(null); 694 q.setClass(cls); 695 if (getObjectIdClass(cls) == null) 696 throw new JDOUnsupportedOptionException( 697 "There is a problem with the specified class"); 698 return q; 699 } 700 701 public Query newQuery(Extent extent) { 702 assertIsOpen(); 703 bindPMThread(); 704 Query q = createQuery(null); 705 Class c = extent.getCandidateClass(); 706 q.setClass(c); 707 if (getObjectIdClass(c) == null) 708 throw new JDOUnsupportedOptionException( 709 "There is a problem with the specified class"); 710 return q; 711 } 712 713 public Query newQuery(Extent extent, String filter) { 714 assertIsOpen(); 715 bindPMThread(); 716 Query q = newQuery(extent); 717 q.setFilter(filter); 718 return q; 719 } 720 721 728 public Query newQuery(Class cls, Collection cln) { 729 assertIsOpen(); 730 bindPMThread(); 731 Query q = createQuery(null); 732 q.setClass(cls); 733 q.setCandidates(cln); 734 return q; 735 } 736 737 743 public Query newQuery(Class cls, String filter) { 744 assertIsOpen(); 745 bindPMThread(); 746 Query q = createQuery(null); 747 q.setClass(cls); 748 q.setFilter(filter); 749 return q; 750 } 751 752 760 public Query newQuery(Class cls, Collection cln, String filter) { 761 assertIsOpen(); 762 bindPMThread(); 763 Query q = createQuery(null); 764 q.setClass(cls); 765 q.setCandidates(cln); 766 q.setFilter(filter); 767 return q; 768 } 769 770 780 public Extent getExtent(Class persistenceCapableClass, 781 boolean subclasses) { 782 assertIsOpen(); 783 bindPMThread(); 784 return new SpeedoExtent( 785 persistenceCapableClass, subclasses, this, jf, prefetchOnExtent, logger); 786 } 787 788 public Extent getExtent(Class arg0) { 789 return getExtent(arg0, true); 790 } 791 792 793 |