001: /**
002: * Copyright (C) 2001-2005 France Telecom R&D
003: */package org.objectweb.speedo.pm.lib;
004:
005: import org.objectweb.fractal.api.Component;
006: import org.objectweb.fractal.api.Interface;
007: import org.objectweb.fractal.api.NoSuchInterfaceException;
008: import org.objectweb.fractal.util.Fractal;
009: import org.objectweb.jorm.api.PClassMapping;
010: import org.objectweb.jorm.api.PException;
011: import org.objectweb.jorm.naming.api.PBinder;
012: import org.objectweb.jorm.naming.api.PName;
013: import org.objectweb.jorm.naming.api.PNameCoder;
014: import org.objectweb.jorm.util.api.Loggable;
015: import org.objectweb.perseus.cache.api.CacheEntry;
016: import org.objectweb.perseus.concurrency.lib.Semaphore;
017: import org.objectweb.perseus.persistence.api.PersistenceException;
018: import org.objectweb.perseus.persistence.api.RolledBackPersistenceException;
019: import org.objectweb.perseus.persistence.api.State;
020: import org.objectweb.perseus.persistence.api.StateFilter;
021: import org.objectweb.perseus.persistence.api.TransactionalPersistenceManager;
022: import org.objectweb.perseus.persistence.api.TransactionalWorkingSet;
023: import org.objectweb.perseus.persistence.api.VirtualState;
024: import org.objectweb.speedo.api.ExceptionHelper;
025: import org.objectweb.speedo.api.SpeedoRuntimeException;
026: import org.objectweb.speedo.genclass.api.SpeedoGenClassPO;
027: import org.objectweb.speedo.mapper.api.JormFactory;
028: import org.objectweb.speedo.mim.api.FetchPlanItf;
029: import org.objectweb.speedo.mim.api.HomeItf;
030: import org.objectweb.speedo.mim.api.PersistentObjectItf;
031: import org.objectweb.speedo.mim.api.StateItf;
032: import org.objectweb.speedo.pm.api.POManagerFactoryItf;
033: import org.objectweb.speedo.pm.api.POManagerItf;
034: import org.objectweb.speedo.query.api.QueryManager;
035: import org.objectweb.speedo.query.api.QueryManagerAttribute;
036: import org.objectweb.speedo.workingset.api.TransactionItf;
037: import org.objectweb.speedo.workingset.jdo.api.JDOTransactionItf;
038: import org.objectweb.util.monolog.api.BasicLevel;
039: import org.objectweb.util.monolog.api.Logger;
040: import org.objectweb.util.monolog.api.LoggerFactory;
041:
042: import java.util.Collection;
043: import java.util.Map;
044:
045: import javax.jdo.listener.InstanceLifecycleEvent;
046: import javax.transaction.Status;
047:
048: public abstract class AbstractPOManager implements POManagerItf {
049: public final static String PO_MANAGER_FACTORY_BINDING = "po-manager-factory";
050: public final static String TRANSACTIONAL_PERSISTENCE_MANAGER_BINDING = "transactional-persistence-manager";
051: public final static String QUERY_MANAGER_BINDING = "query-manager";
052: public final static String TRANSACTION_BINDING = "transaction";
053: public final static String JORM_FACTORY_BINDING = "jorm-factory";
054: public final static String PNAME_CODER_BINDING = "pname-coder";
055: public final static String COMPONENT_BINDING = "component";
056:
057: protected Logger logger;
058: protected LoggerFactory loggerFactory;
059:
060: /**
061: * The POManagedFactory managing this POManagerItf
062: */
063: protected POManagerFactoryItf pmf = null;
064:
065: /**
066: * The transaction associated to this po manager.
067: */
068: protected TransactionItf tx;
069:
070: /**
071: * The manager of Query. It contains the optimized queries already
072: * used.
073: */
074: protected QueryManager queryManager = null;
075:
076: /**
077: * The TransactionalPersistenceManager (Perseus)
078: */
079: protected TransactionalPersistenceManager tpm = null;
080:
081: /**
082: * The JormFactory able to initialize the Persistent of classes
083: */
084: protected JormFactory jf = null;
085:
086: /**
087: * The PNameCoder able to encode/decode all PName
088: */
089: protected PNameCoder pnc = null;
090:
091: /**
092: * is the information permiting the access to the data store
093: */
094: protected Object connectionSpec = null;
095:
096: /**
097: * Indicates if number of po manager user. O means the POManagerItf
098: * is closed.
099: */
100: protected short nbUse = 0;
101:
102: /**
103: * The fractal reference to this
104: */
105: protected POManagerItf this PM = null;
106:
107: /**
108: * The lastest thread associated to the current POManagerItf
109: */
110: protected Thread currentThread = null;
111:
112: /**
113: * A semaphore object used to support the multithread mode
114: */
115: protected Semaphore semaphore;
116:
117: protected boolean prefetchOnExtent = true;
118: protected boolean prefetchOnQuery = true;
119:
120: protected FetchPlanItf fetchPlan;
121:
122: /**
123: *
124: */
125: public AbstractPOManager() {
126: semaphore = new Semaphore(false);
127: }
128:
129: // IMPLEMENTATION OF THE UserBindingController INTERFACE //
130: //-------------------------------------------------------//
131:
132: public String[] listFc() {
133: return new String[] { PO_MANAGER_FACTORY_BINDING,
134: QUERY_MANAGER_BINDING,
135: TRANSACTIONAL_PERSISTENCE_MANAGER_BINDING,
136: TRANSACTION_BINDING, JORM_FACTORY_BINDING,
137: PNAME_CODER_BINDING };
138: }
139:
140: public Object lookupFc(String s) {
141: if (PO_MANAGER_FACTORY_BINDING.equals(s)) {
142: return pmf;
143: } else if (QUERY_MANAGER_BINDING.equals(s)) {
144: return queryManager;
145: } else if (TRANSACTIONAL_PERSISTENCE_MANAGER_BINDING.equals(s)) {
146: return tpm;
147: } else if (TRANSACTION_BINDING.equals(s)) {
148: return tx;
149: } else if (PNAME_CODER_BINDING.equals(s)) {
150: return pnc;
151: } else if (JORM_FACTORY_BINDING.equals(s)) {
152: return jf;
153: } else {
154: return null;
155: }
156: }
157:
158: public void bindFc(String s, Object o) {
159: if ("monolog-factory".equals(s)) {
160: loggerFactory = (LoggerFactory) o;
161: } else if ("logger".equals(s)) {
162: logger = (Logger) o;
163: } else if (PO_MANAGER_FACTORY_BINDING.equals(s)) {
164: pmf = (POManagerFactoryItf) o;
165: } else if (QUERY_MANAGER_BINDING.equals(s)) {
166: queryManager = (QueryManager) o;
167: if (queryManager != null) {
168: try {
169: QueryManagerAttribute qma = (QueryManagerAttribute) Fractal
170: .getAttributeController(((Interface) queryManager)
171: .getFcItfOwner());
172: prefetchOnExtent = qma
173: .getPrefetchActivatedOnExtent();
174: prefetchOnQuery = qma.getPrefetchActivatedOnQuery();
175: } catch (Exception e) {
176: logger
177: .log(
178: BasicLevel.WARN,
179: "impossible to fetch the attribute prefetchActivatedOnExtent: ",
180: e);
181: }
182: }
183: } else if (TRANSACTIONAL_PERSISTENCE_MANAGER_BINDING.equals(s)) {
184: tpm = (TransactionalPersistenceManager) o;
185: } else if (TRANSACTION_BINDING.equals(s)) {
186: tx = (TransactionItf) o;
187: } else if (PNAME_CODER_BINDING.equals(s)) {
188: pnc = (PNameCoder) o;
189: } else if (JORM_FACTORY_BINDING.equals(s)) {
190: jf = (JormFactory) o;
191: } else if (COMPONENT_BINDING.equals(s)) {
192: try {
193: this PM = (POManagerItf) ((Component) o)
194: .getFcInterface("po-manager");
195: } catch (NoSuchInterfaceException e) {
196:
197: }
198: }
199: }
200:
201: public void unbindFc(String s) {
202: if (PO_MANAGER_FACTORY_BINDING.equals(s))
203: pmf = null;
204: else if (TRANSACTIONAL_PERSISTENCE_MANAGER_BINDING.equals(s))
205: tpm = null;
206: else if (TRANSACTION_BINDING.equals(s))
207: tx = null;
208: else if (QUERY_MANAGER_BINDING.equals(s))
209: queryManager = null;
210: else if (PNAME_CODER_BINDING.equals(s))
211: pnc = null;
212: else if (JORM_FACTORY_BINDING.equals(s))
213: jf = null;
214: }
215:
216: // IMPLEMENTATION OF THE POManagerItf INTERFACE //
217: //----------------------------------------------//
218:
219: public abstract FetchPlanItf speedoGetFetchPlan();
220:
221: public TransactionalPersistenceManager getTransactionalPersistenceManager() {
222: return tpm;
223: }
224:
225: public void open(Object connectionspec) {
226: resetPMOnOpen(connectionspec);
227: try {
228: tx.activate();
229: } catch (PersistenceException e) {
230: throw new SpeedoRuntimeException(
231: "Impossible to open this persistence manager", e);
232: }
233: }
234:
235: public Object getConnectionSpec() {
236: return connectionSpec;
237: }
238:
239: public void addUse() {
240: nbUse++;
241: logger.log(BasicLevel.DEBUG, "POManagerItf used: " + nbUse);
242: }
243:
244: /**
245: * A POManager instance can be used until it is closed.
246: * @return true if this POManager has been closed
247: * @see #closePOManager()
248: */
249: public boolean isPOMClosed() {
250: bindPMThread();
251: return nbUse == 0;
252: }
253:
254: public void closePOManager() {
255: if (semaphore.on) {
256: semaphore.P();
257: }
258: if (nbUse == 0) {
259: return;
260: } else if (nbUse > 1) {
261: nbUse--;
262: logger.log(BasicLevel.DEBUG,
263: "Imbricated POManager closed (" + nbUse + ")");
264: return;
265: }
266: bindPMThread();
267: try {
268: tpm.close(tx);
269: } catch (PersistenceException e) {
270: throw new SpeedoRuntimeException(
271: "Impossible to close the persistence manager",
272: ExceptionHelper.getNested(e));
273: } finally {
274: nbUse--;
275: //Forget the information to access to the data store.
276: connectionSpec = null;
277: currentThread = null;
278: try {
279: pmf.poManagerClosed(this PM);
280: } finally {
281: if (semaphore.on) {
282: semaphore.V();
283: }
284: if (logger.isLoggable(BasicLevel.INFO))
285: logger.log(BasicLevel.INFO,
286: "Persistence Manager closed");
287: }
288: }
289: }
290:
291: public TransactionItf getSpeedoTransaction() {
292: return tx;
293: }
294:
295: public POManagerFactoryItf getPOManagerFactory() {
296: return pmf;
297: }
298:
299: public Object getEncodedPName(PersistentObjectItf o) {
300: try {
301: assertIsPO(o, "");
302: } catch (Exception e) {
303: return null;
304: }
305: PersistentObjectItf po = (PersistentObjectItf) o;
306: assertPOManager(po);
307: if (!po.speedoIsActive()) {
308: throw new SpeedoRuntimeException(
309: "Non persistent object does not have identifier: "
310: + o);
311: }
312: try {
313: return pnc.encodeAbstract(po.getPName());
314: } catch (PException e) {
315: throw new SpeedoRuntimeException(
316: "Problem while encoding persistent name.",
317: new Exception[] { ExceptionHelper.getNested(e) });
318: }
319: }
320:
321: public PName decodeIdentifier(Class aClass, Object s) {
322: assertIsOpen();
323: bindPMThread();
324: try {
325: return pnc.decodeAbstract(s, aClass);
326: } catch (PException e) {
327: throw new SpeedoRuntimeException(
328: "Invalid persistent object identifier " + s
329: + " for the class " + aClass,
330: new Exception[] { e });
331: }
332: }
333:
334: public void speedoDeletePersistentAll(Object[] o) {
335: if (o == null || o.length == 0) {
336: return;
337: }
338: for (int i = 0; i < o.length; i++) {
339: speedoDeletePersistent(o[i]);
340: }
341: }
342:
343: // IMPLEMENTATION OF THE Synchronization INTERFACE //
344: //-------------------------------------------------//
345:
346: public void beforeCompletion() {
347: byte stat = tx.getStatus();
348: if (stat == TransactionalWorkingSet.CTX_PREPARED_FAIL
349: || stat == TransactionalWorkingSet.CTX_PREPARED_OK) {
350: /**
351: * The PersistenceManager has been registered several times as a
352: * Synchronization and the beforeCompletion method is call several
353: * times.
354: */
355: return;
356: }
357: bindPMThread();
358: logger.log(BasicLevel.INFO,
359: "beforeCompletion of the transaction: ");
360: try {
361: tpm.prepare(tx);
362: } catch (PersistenceException e) {
363: Exception ie = ExceptionHelper.getNested(e);
364: logger.log(BasicLevel.ERROR,
365: "Error during the preparation of the transaction:",
366: ie);
367: throw new SpeedoRuntimeException("", ie);
368: }
369: }
370:
371: public void afterCompletion(int i) {
372: if (nbUse == 0) {
373: /**
374: * The PersistenceManager has been registered several times as a
375: * Synchronization and the afterCompletion method is call several
376: * times.
377: */
378: return;
379: }
380: bindPMThread();
381: boolean commit = (i == Status.STATUS_COMMITTED);
382: try {
383: if (commit) {
384: logger
385: .log(BasicLevel.DEBUG,
386: "afterCompletion(STATUS_COMMITTED) of the transaction: ");
387: tpm.commit(tx);
388: } else {
389: logger
390: .log(BasicLevel.DEBUG,
391: "afterCompletion(STATUS_ROLLEDBACK) of the transaction: ");
392: tpm.rollback(tx);
393: }
394: } catch (PersistenceException e) {
395: Exception ie = ExceptionHelper.getNested(e);
396: logger.log(BasicLevel.ERROR, "Error during the "
397: + (commit ? "commit" : "rollback")
398: + " of the transaction:", ie);
399: throw new SpeedoRuntimeException("", ie);
400: } finally {
401: closePOManager();
402: }
403: }
404:
405: // OTHER METHODS //
406: //---------------//
407: public Object speedoGetObject(PName pn, boolean validate) {
408: if (pn.isNull()) {
409: return null;
410: }
411: try {
412: if (!(pn.getPNameManager() instanceof PBinder)) {
413: pn = pnc.decodeAbstract(pn, tx.getConnectionHolder());
414: }
415: if (validate) {
416: State s = tx.lookup(pn);
417: if (s != null && s != VirtualState.instance) {
418: return s.getCacheEntry();
419: } else {
420: //Fetch an instance (new or from the cache)
421: CacheEntry ce = tpm.getObjectById(tx, pn);
422: //clear the state
423: tpm.refresh(tx, ce);
424: //if it exists then object loading else exception
425: tpm.readIntention(tx, ce, null);
426: return ce;
427: }
428: } else {
429: //do not reload if present in the cache
430: return tpm.readIntention(tx, pn, null).getCacheEntry();
431: }
432: } catch (PersistenceException e) {
433: throw new SpeedoRuntimeException(e);
434: } catch (PException e) {
435: throw new SpeedoRuntimeException(e);
436: }
437: }
438:
439: public Object speedoGetObject(Object id, Class poc, boolean validate)
440: throws PException, PersistenceException {
441: Object oid = id;
442: if (poc != null) {
443: oid = pnc.decodeAbstract(oid, poc);
444: }
445: PName pn = pnc.decodeAbstract(oid, tx.getConnectionHolder());
446: return speedoGetObject(pn, validate);
447: }
448:
449: protected Object speedoPersist(PersistentObjectItf po, Map map)
450: throws PException, PersistenceException {
451: //initialize the PBinding of the persistent object
452: PClassMapping pcm;
453: if (po instanceof SpeedoGenClassPO) {
454: pcm = jf.getGenClassMapping(((SpeedoGenClassPO) po)
455: .speedoGetGenClassId());
456: //Assign the PBinding
457: ((SpeedoGenClassPO) po).speedoSetPBinding(pcm
458: .createPBinding());
459: if (po instanceof Loggable) {
460: ((Loggable) po).setLogger(logger);
461: }
462: } else {
463: pcm = jf.getPClassMapping(po.getClass());
464: }
465: po.init(pcm);
466: po.speedoGetHome().sendEvent(HomeItf.PRE_NEW, po, null);
467: Object hints = po.speedoGetPNameHints();
468: final StateItf state;
469: if (hints == null) {
470: state = (StateItf) tpm.export(tx, po);
471: } else {
472: state = (StateItf) tpm.export(tx, po, hints);
473: }
474: if (logger.isLoggable(BasicLevel.DEBUG)) {
475: logger.log(BasicLevel.DEBUG,
476: "New persistent instance, identifier="
477: + po.getPName());
478: }
479: if (map == null) {
480: //call the po to make persistent the reference field
481: state.makePersistent(this );
482: } else {
483: //call the po to make persistent the reference field, with the map context
484: state.makePersistentOnAttach(this , map);
485: }
486: po.speedoGetHome().sendEvent(HomeItf.POST_NEW, po, null);
487: return po;
488: }
489:
490: public void speedoFlush() throws PersistenceException {
491: tpm.flush(tx, (StateFilter) null);
492: }
493:
494: protected void resetPMOnOpen(Object connectionspec) {
495: connectionSpec = connectionspec;
496: nbUse = 0;
497: //??? init the transaction mode Optimistic or not ?
498: //??? init the ignoreCache property or not ?
499: //??? init the multithread property or not ?
500: }
501:
502: public Semaphore getSemaphore() {
503: return semaphore;
504: }
505:
506: protected void bindPMThread() {
507: if (currentThread != Thread.currentThread()) {
508: currentThread = Thread.currentThread();
509: pmf.bindPM2Thread(this PM);
510: currentThread = null;
511: }
512: }
513:
514: /**
515: * Verify the persistence manager is open.
516: * @exception SpeedoRuntimeException if the pomanager is closed.
517: */
518: protected void assertIsOpen() {
519: if (nbUse == 0)
520: throw new SpeedoRuntimeException(
521: "The persistent manager is closed.");
522: }
523:
524: /**
525: * Verify that an instance is persistence object.
526: * @param pc the object to test.
527: * @exception SpeedoRuntimeException if the object is not persistence capable.
528: */
529: protected void assertIsPO(Object pc, String cmd) {
530: if (!(pc instanceof PersistentObjectItf)) {
531: if (pc == null) {
532: throw new SpeedoRuntimeException(
533: "Null persistent object instance specified");
534: } else if (pc.getClass().isArray()
535: || pc instanceof Collection) {
536: throw new SpeedoRuntimeException("You must use the "
537: + cmd
538: + "All method with a multivalued parameter: "
539: + pc);
540: } else {
541: throw new SpeedoRuntimeException(
542: "The object is not a PersistentObjectItf, beware to : "
543: + pc);
544: }
545: }
546: }
547:
548: /**
549: * Verify the instance is managed by this persistence manager.
550: * @param sp a speedo po instance.
551: * @exception SpeedoRuntimeException if the instance is managed by
552: * another persistence manager.
553: */
554: protected void assertPOManager(PersistentObjectItf sp) {
555: POManagerItf pm = (POManagerItf) sp.speedoGetPOManager();
556: if (!this PM.equals(pm)) {
557: if (pm == null) {
558: try {
559: tpm.readIntention(tx, sp, null);
560: } catch (RolledBackPersistenceException e) {
561: throw ((JDOTransactionItf) tx)
562: .rollBackOnInternalError(e);
563: } catch (PersistenceException e) {
564: throw new SpeedoRuntimeException(
565: "Impossible to add the "
566: + "persistent object into the working set",
567: e);
568: }
569: } else {
570: throw new SpeedoRuntimeException(
571: "Object not managed by this persistence manager, object: "
572: + sp);
573: }
574: }
575: }
576:
577: }
|