0001: /*
0002: * Copyright 2004 (C) TJDO.
0003: * All rights reserved.
0004: *
0005: * This software is distributed under the terms of the TJDO License version 1.0.
0006: * See the terms of the TJDO License in the documentation provided with this software.
0007: *
0008: * $Id: PersistenceManagerImpl.java,v 1.14 2004/01/18 05:46:55 jackknifebarber Exp $
0009: */
0010:
0011: package com.triactive.jdo;
0012:
0013: import com.triactive.jdo.PersistenceManagerFactoryImpl;
0014: import com.triactive.jdo.model.ClassMetaData;
0015: import com.triactive.jdo.state.StateManagerImpl;
0016: import com.triactive.jdo.store.ClassTable;
0017: import com.triactive.jdo.store.OID;
0018: import com.triactive.jdo.store.SCOID;
0019: import com.triactive.jdo.store.StoreManager;
0020: import com.triactive.jdo.store.StoreManagerFactory;
0021: import com.triactive.jdo.util.WeakValueMap;
0022: import java.io.PrintWriter;
0023: import java.security.AccessController;
0024: import java.security.PrivilegedAction;
0025: import java.sql.Connection;
0026: import java.sql.SQLException;
0027: import java.util.ArrayList;
0028: import java.util.Arrays;
0029: import java.util.Collection;
0030: import java.util.Collections;
0031: import java.util.HashSet;
0032: import java.util.Iterator;
0033: import java.util.Map;
0034: import java.util.Set;
0035: import javax.jdo.Extent;
0036: import javax.jdo.JDOFatalInternalException;
0037: import javax.jdo.JDOFatalUserException;
0038: import javax.jdo.JDOUserException;
0039: import javax.jdo.JDOUnsupportedOptionException;
0040: import javax.jdo.PersistenceManagerFactory;
0041: import javax.jdo.Query;
0042: import javax.jdo.spi.PersistenceCapable;
0043: import org.apache.log4j.Category;
0044:
0045: /**
0046: * Implements the PersistenceManager interface.
0047: *
0048: * @author <a href="mailto:mmartin5@austin.rr.com">Mike Martin</a>
0049: * @version $Revision: 1.14 $
0050: */
0051:
0052: public class PersistenceManagerImpl implements PersistenceManager {
0053: private static final Category LOG = Category
0054: .getInstance(PersistenceManagerImpl.class);
0055:
0056: private final PersistenceManagerFactoryImpl pmf;
0057: private final ClassLoader origContextClassLoader;
0058:
0059: private StoreManager srm;
0060: private Transaction tx;
0061: private boolean ignoreCache;
0062: private boolean multithreaded;
0063: private int dataStoreModCount = 0;
0064: private Object userObject = null;
0065: private boolean closed = false;
0066:
0067: private Map weakSMCache = new WeakValueMap();
0068: private Set txCache = new HashSet();
0069:
0070: private PersistenceCapable lookingForStateManagerFor = null;
0071: private StateManager foundStateManager = null;
0072: private StateManager dirtyStateManager = null;
0073: private Connection nonTxConnection = null;
0074:
0075: public PersistenceManagerImpl(PersistenceManagerFactoryImpl pmf,
0076: String userName, String password) {
0077: this .pmf = pmf;
0078:
0079: origContextClassLoader = getContextClassLoaderPrivileged();
0080:
0081: srm = StoreManagerFactory.getStoreManager(pmf, userName,
0082: password);
0083: tx = new NonmanagedTransaction(this , userName, password);
0084:
0085: setIgnoreCache(pmf.getIgnoreCache());
0086: setMultithreaded(pmf.getMultithreaded());
0087: }
0088:
0089: /**
0090: * Calls getContextClassLoader() for the current thread in a doPrivileged
0091: * block.
0092: *
0093: * @return
0094: * The context class loader of the current thread.
0095: *
0096: * @exception SecurityException
0097: * If getContextClassLoader() fails.
0098: */
0099:
0100: private ClassLoader getContextClassLoaderPrivileged()
0101: throws SecurityException {
0102: return (ClassLoader) AccessController
0103: .doPrivileged(new PrivilegedAction() {
0104: public Object run() {
0105: return Thread.currentThread()
0106: .getContextClassLoader();
0107: }
0108: });
0109: }
0110:
0111: private Class classForName(String name, Class contextClass)
0112: throws ClassNotFoundException {
0113: if (contextClass != null) {
0114: try {
0115: return Class.forName(name, true, contextClass
0116: .getClassLoader());
0117: } catch (ClassNotFoundException e) {
0118: }
0119: }
0120:
0121: try {
0122: return Class.forName(name, true,
0123: getContextClassLoaderPrivileged());
0124: } catch (ClassNotFoundException e) {
0125: return Class.forName(name, true, origContextClassLoader);
0126: }
0127: }
0128:
0129: public StoreManager getStoreManager() {
0130: return srm;
0131: }
0132:
0133: public synchronized void dataStoreModified() {
0134: ++dataStoreModCount;
0135: }
0136:
0137: public int dataStoreModifyCount() {
0138: return dataStoreModCount;
0139: }
0140:
0141: public Connection getConnection(boolean forWriting)
0142: throws SQLException {
0143: return tx.getConnection(forWriting);
0144: }
0145:
0146: public synchronized void releaseConnection(Connection conn)
0147: throws SQLException {
0148: tx.releaseConnection(conn);
0149: }
0150:
0151: public synchronized void enlistInTransaction(StateManager sm) {
0152: if (!tx.isActive())
0153: throw new TransactionNotActiveException();
0154:
0155: if (LOG.isDebugEnabled())
0156: LOG.debug("Enlisting in transactional cache:" + sm);
0157:
0158: if (!txCache.add(sm))
0159: LOG.debug("Already enlisted:" + sm);
0160: }
0161:
0162: public synchronized void evictFromTransaction(StateManager sm) {
0163: if (LOG.isDebugEnabled())
0164: LOG.debug("Evicting from transactional cache:" + sm);
0165:
0166: if (!txCache.remove(sm))
0167: throw new JDOFatalInternalException(
0168: "Not enlisted in transaction: " + sm);
0169: }
0170:
0171: public synchronized void removeStateManager(StateManager sm) {
0172: txCache.remove(sm);
0173:
0174: Object id = sm.getObjectId();
0175:
0176: if (id != null)
0177: weakSMCache.remove(id);
0178: }
0179:
0180: private void assertIsOpen() {
0181: if (closed)
0182: throw new JDOFatalUserException(
0183: "Persistence manager has been closed");
0184: }
0185:
0186: private static boolean isPersistenceCapableClass(Class cls) {
0187: return ClassMetaData.forClass(cls) != null;
0188: }
0189:
0190: public boolean isClosed() {
0191: return closed;
0192: }
0193:
0194: private synchronized void closeInternal() {
0195: srm = null;
0196: tx = null;
0197: userObject = null;
0198: closed = true;
0199: }
0200:
0201: /** Called by the PMF to forcibly close this PM. */
0202: void forceClose() {
0203: try {
0204: if (tx.isActive())
0205: tx.rollback();
0206: } catch (Exception e) {
0207: LOG.warn("Failed forcing closure of " + this , e);
0208: } finally {
0209: closeInternal();
0210: }
0211: }
0212:
0213: public synchronized void close() {
0214: if (tx.isActive())
0215: throw new TransactionActiveException();
0216:
0217: closeInternal();
0218: pmf.pmClosed(this );
0219: }
0220:
0221: public javax.jdo.Transaction currentTransaction() {
0222: assertIsOpen();
0223:
0224: return tx;
0225: }
0226:
0227: private void internalEvict(Object obj) {
0228: StateManager sm = findStateManager(obj);
0229:
0230: if (sm != null)
0231: sm.evict();
0232: }
0233:
0234: public synchronized void evict(Object pc) {
0235: assertIsOpen();
0236:
0237: internalEvict(pc);
0238: }
0239:
0240: public synchronized void evictAll(Object[] pcs) {
0241: evictAll(Arrays.asList(pcs));
0242: }
0243:
0244: public synchronized void evictAll(Collection pcs) {
0245: assertIsOpen();
0246:
0247: ArrayList failures = new ArrayList();
0248:
0249: Iterator i = pcs.iterator();
0250:
0251: while (i.hasNext()) {
0252: try {
0253: internalEvict(i.next());
0254: } catch (RuntimeException e) {
0255: failures.add(e);
0256: }
0257: }
0258:
0259: if (!failures.isEmpty())
0260: throw new JDOUserException(
0261: "One or more instances could not be evicted",
0262: (Exception[]) failures
0263: .toArray(new Exception[failures.size()]));
0264: }
0265:
0266: public synchronized void evictAll() {
0267: assertIsOpen();
0268:
0269: /*
0270: * Evict all PClean instances. This is done by calling evict() on all
0271: * transactional instances, which is a no-op for all transactional
0272: * states except PClean.
0273: */
0274: ArrayList failures = new ArrayList();
0275: Iterator i = txCache.iterator();
0276:
0277: while (i.hasNext()) {
0278: try {
0279: ((StateManager) i.next()).evict();
0280: } catch (RuntimeException e) {
0281: failures.add(e);
0282: }
0283: }
0284:
0285: if (!failures.isEmpty())
0286: throw new JDOUserException(
0287: "One or more instances could not be evicted",
0288: (Exception[]) failures
0289: .toArray(new Exception[failures.size()]));
0290: }
0291:
0292: private void internalRefresh(Object obj) {
0293: StateManager sm = findStateManager(obj);
0294:
0295: if (sm != null)
0296: sm.refresh();
0297: }
0298:
0299: public synchronized void refresh(Object pc) {
0300: assertIsOpen();
0301:
0302: internalRefresh(pc);
0303: }
0304:
0305: public synchronized void refreshAll(Object[] pcs) {
0306: refreshAll(Arrays.asList(pcs));
0307: }
0308:
0309: public synchronized void refreshAll(Collection pcs) {
0310: assertIsOpen();
0311:
0312: ArrayList failures = new ArrayList();
0313:
0314: Iterator i = pcs.iterator();
0315:
0316: while (i.hasNext()) {
0317: try {
0318: internalRefresh(i.next());
0319: } catch (RuntimeException e) {
0320: failures.add(e);
0321: }
0322: }
0323:
0324: if (!failures.isEmpty())
0325: throw new JDOUserException(
0326: "One or more instances could not be refreshed",
0327: (Exception[]) failures
0328: .toArray(new Exception[failures.size()]));
0329: }
0330:
0331: public synchronized void refreshAll() {
0332: assertIsOpen();
0333:
0334: ArrayList failures = new ArrayList();
0335:
0336: Iterator i = tx.isActive() ? txCache.iterator()
0337: : new ArrayList(weakSMCache.values()).iterator();
0338:
0339: while (i.hasNext()) {
0340: try {
0341: ((StateManager) i.next()).refresh();
0342: } catch (RuntimeException e) {
0343: failures.add(e);
0344: }
0345: }
0346:
0347: if (!failures.isEmpty())
0348: throw new JDOUserException(
0349: "One or more instances could not be refreshed",
0350: (Exception[]) failures
0351: .toArray(new Exception[failures.size()]));
0352: }
0353:
0354: private void internalRetrieve(Object obj, boolean DFGOnly) {
0355: StateManager sm = findStateManager(obj);
0356:
0357: if (sm != null)
0358: sm.retrieve(DFGOnly);
0359: }
0360:
0361: public synchronized void retrieve(Object pc) {
0362: assertIsOpen();
0363:
0364: internalRetrieve(pc, false);
0365: }
0366:
0367: public synchronized void retrieveAll(Object[] pcs) {
0368: retrieveAll(pcs, false);
0369: }
0370:
0371: public synchronized void retrieveAll(Object[] pcs, boolean DFGOnly) {
0372: retrieveAll(Arrays.asList(pcs), DFGOnly);
0373: }
0374:
0375: public synchronized void retrieveAll(Collection pcs) {
0376: retrieveAll(pcs, false);
0377: }
0378:
0379: public synchronized void retrieveAll(Collection pcs, boolean DFGOnly) {
0380: assertIsOpen();
0381:
0382: ArrayList failures = new ArrayList();
0383:
0384: Iterator i = pcs.iterator();
0385:
0386: while (i.hasNext()) {
0387: try {
0388: internalRetrieve(i.next(), DFGOnly);
0389: } catch (RuntimeException e) {
0390: failures.add(e);
0391: }
0392: }
0393:
0394: if (!failures.isEmpty())
0395: throw new JDOUserException(
0396: "One or more instances could not be retrieved",
0397: (Exception[]) failures
0398: .toArray(new Exception[failures.size()]));
0399: }
0400:
0401: private void internalMakePersistent(Object obj) {
0402: if (obj == null)
0403: return;
0404:
0405: PersistenceCapable pc = asPC(obj);
0406: StateManager sm = findStateManager(pc);
0407: boolean wasUnmanaged = false;
0408:
0409: /*
0410: * If the object is currently unmanaged (Transient) it first has to
0411: * transition thru a TransientClean state in order to get to
0412: * PersistentNew. If the makePersistent() subsequently fails we'll
0413: * rollback its state to unmanaged Transient.
0414: */
0415: if (sm == null) {
0416: wasUnmanaged = true;
0417: sm = new StateManagerImpl(this , pc); // makeTransactional
0418: }
0419:
0420: try {
0421: if (sm.makePersistent())
0422: weakSMCache.put(sm.getObjectId(), sm);
0423: } finally {
0424: if (wasUnmanaged && !sm.isPersistent(pc))
0425: sm.makeNontransactional();
0426: }
0427: }
0428:
0429: public synchronized void makePersistent(Object obj) {
0430: assertIsOpen();
0431:
0432: internalMakePersistent(obj);
0433: }
0434:
0435: public synchronized void makePersistentAll(Object[] pcs) {
0436: makePersistentAll(Arrays.asList(pcs));
0437: }
0438:
0439: public synchronized void makePersistentAll(Collection pcs) {
0440: assertIsOpen();
0441:
0442: ArrayList failures = new ArrayList();
0443:
0444: Iterator i = pcs.iterator();
0445:
0446: while (i.hasNext()) {
0447: try {
0448: internalMakePersistent(i.next());
0449: } catch (RuntimeException e) {
0450: failures.add(e);
0451: }
0452: }
0453:
0454: if (!failures.isEmpty())
0455: throw new JDOUserException(
0456: "One or more instances could not be made persistent",
0457: (Exception[]) failures
0458: .toArray(new Exception[failures.size()]));
0459: }
0460:
0461: private void internalDeletePersistent(Object obj) {
0462: if (obj != null)
0463: getStateManager(obj).deletePersistent();
0464: }
0465:
0466: public synchronized void deletePersistent(Object obj) {
0467: assertIsOpen();
0468:
0469: internalDeletePersistent(obj);
0470: }
0471:
0472: public synchronized void deletePersistentAll(Object[] pcs) {
0473: deletePersistentAll(Arrays.asList(pcs));
0474: }
0475:
0476: public synchronized void deletePersistentAll(Collection pcs) {
0477: assertIsOpen();
0478:
0479: ArrayList failures = new ArrayList();
0480:
0481: Iterator i = pcs.iterator();
0482:
0483: while (i.hasNext()) {
0484: try {
0485: internalDeletePersistent(i.next());
0486: } catch (RuntimeException e) {
0487: failures.add(e);
0488: }
0489: }
0490:
0491: if (!failures.isEmpty())
0492: throw new JDOUserException(
0493: "One or more instances could not be deleted",
0494: (Exception[]) failures
0495: .toArray(new Exception[failures.size()]));
0496: }
0497:
0498: private void internalMakeTransient(Object obj) {
0499: StateManager sm = findStateManager(obj);
0500:
0501: if (sm != null)
0502: sm.makeTransient();
0503: }
0504:
0505: public synchronized void makeTransient(Object pc) {
0506: assertIsOpen();
0507:
0508: internalMakeTransient(pc);
0509: }
0510:
0511: public synchronized void makeTransientAll(Object[] pcs) {
0512: makeTransientAll(Arrays.asList(pcs));
0513: }
0514:
0515: public synchronized void makeTransientAll(Collection pcs) {
0516: assertIsOpen();
0517:
0518: ArrayList failures = new ArrayList();
0519:
0520: Iterator i = pcs.iterator();
0521:
0522: while (i.hasNext()) {
0523: try {
0524: internalMakeTransient(i.next());
0525: } catch (RuntimeException e) {
0526: failures.add(e);
0527: }
0528: }
0529:
0530: if (!failures.isEmpty())
0531: throw new JDOUserException(
0532: "One or more instances could not be made transient",
0533: (Exception[]) failures
0534: .toArray(new Exception[failures.size()]));
0535: }
0536:
0537: private void internalMakeTransactional(Object obj) {
0538: if (obj == null)
0539: return;
0540:
0541: PersistenceCapable pc = asPC(obj);
0542: StateManager sm = findStateManager(pc);
0543:
0544: if (sm == null)
0545: sm = new StateManagerImpl(this , pc);
0546: else
0547: sm.makeTransactional();
0548: }
0549:
0550: public synchronized void makeTransactional(Object pc) {
0551: assertIsOpen();
0552:
0553: internalMakeTransactional(pc);
0554: }
0555:
0556: public synchronized void makeTransactionalAll(Object[] pcs) {
0557: makeTransactionalAll(Arrays.asList(pcs));
0558: }
0559:
0560: public synchronized void makeTransactionalAll(Collection pcs) {
0561: assertIsOpen();
0562:
0563: ArrayList failures = new ArrayList();
0564:
0565: Iterator i = pcs.iterator();
0566:
0567: while (i.hasNext()) {
0568: try {
0569: internalMakeTransactional(i.next());
0570: } catch (RuntimeException e) {
0571: failures.add(e);
0572: }
0573: }
0574:
0575: if (!failures.isEmpty())
0576: throw new JDOUserException(
0577: "One or more instances could not be made transactional",
0578: (Exception[]) failures
0579: .toArray(new Exception[failures.size()]));
0580: }
0581:
0582: private void internalMakeNontransactional(Object obj) {
0583: if (obj != null)
0584: getStateManager(obj).makeNontransactional();
0585: }
0586:
0587: public synchronized void makeNontransactional(Object pc) {
0588: assertIsOpen();
0589:
0590: internalMakeNontransactional(pc);
0591: }
0592:
0593: public synchronized void makeNontransactionalAll(Object[] pcs) {
0594: makeNontransactionalAll(Arrays.asList(pcs));
0595: }
0596:
0597: public synchronized void makeNontransactionalAll(Collection pcs) {
0598: assertIsOpen();
0599:
0600: ArrayList failures = new ArrayList();
0601:
0602: Iterator i = pcs.iterator();
0603:
0604: while (i.hasNext()) {
0605: try {
0606: internalMakeNontransactional(i.next());
0607: } catch (RuntimeException e) {
0608: failures.add(e);
0609: }
0610: }
0611:
0612: if (!failures.isEmpty())
0613: throw new JDOUserException(
0614: "One or more instances could not be made non-transactional",
0615: (Exception[]) failures
0616: .toArray(new Exception[failures.size()]));
0617: }
0618:
0619: public Object newObjectIdInstance(Class clazz, String str) {
0620: return new OID(str);
0621: }
0622:
0623: public synchronized Query newQuery() {
0624: assertIsOpen();
0625:
0626: return srm.getQuery(this , null);
0627: }
0628:
0629: public synchronized Query newQuery(Object obj) {
0630: assertIsOpen();
0631:
0632: return srm.getQuery(this , obj);
0633: }
0634:
0635: public synchronized Query newQuery(String language, Object query) {
0636: assertIsOpen();
0637:
0638: return srm.getQuery(language, this , query);
0639: }
0640:
0641: public synchronized Query newQuery(Class cls) {
0642: assertIsOpen();
0643:
0644: Query query = newQuery();
0645: query.setClass(cls);
0646:
0647: return query;
0648: }
0649:
0650: public synchronized Query newQuery(Extent cln) {
0651: assertIsOpen();
0652:
0653: Query query = newQuery();
0654: query.setCandidates(cln);
0655:
0656: return query;
0657: }
0658:
0659: public synchronized Query newQuery(Class cls, Collection cln) {
0660: assertIsOpen();
0661:
0662: Query query = newQuery();
0663: query.setClass(cls);
0664: query.setCandidates(cln);
0665:
0666: return query;
0667: }
0668:
0669: public synchronized Query newQuery(Class cls, String filter) {
0670: assertIsOpen();
0671:
0672: Query query = newQuery();
0673: query.setClass(cls);
0674: query.setFilter(filter);
0675:
0676: return query;
0677: }
0678:
0679: public synchronized Query newQuery(Class cls, Collection cln,
0680: String filter) {
0681: assertIsOpen();
0682:
0683: Query query = newQuery();
0684: query.setClass(cls);
0685: query.setCandidates(cln);
0686: query.setFilter(filter);
0687:
0688: return query;
0689: }
0690:
0691: public synchronized Query newQuery(Extent cln, String filter) {
0692: assertIsOpen();
0693:
0694: Query query = newQuery();
0695: query.setCandidates(cln);
0696: query.setFilter(filter);
0697:
0698: return query;
0699: }
0700:
0701: public synchronized Extent getExtent(Class cls, boolean flag) {
0702: assertIsOpen();
0703:
0704: return srm.getExtent(this , cls, flag);
0705: }
0706:
0707: private synchronized StateManager getStateManagerById(Object id,
0708: final Class contextClass) {
0709: StateManager sm = (StateManager) weakSMCache.get(id);
0710:
0711: if (sm == null) {
0712: sm = new StateManagerImpl(this , getClassForObjectID(id,
0713: contextClass), id);
0714:
0715: weakSMCache.put(id, sm);
0716: }
0717:
0718: return sm;
0719: }
0720:
0721: public Object getObjectById(Object id, boolean validate) {
0722: return getObjectById(id, null, validate);
0723: }
0724:
0725: public Object getObjectById(Object id, Class contextClass,
0726: boolean validate) {
0727: assertIsOpen();
0728:
0729: if (id == null)
0730: return null;
0731:
0732: StateManager sm = getStateManagerById(id, contextClass);
0733:
0734: if (validate)
0735: sm.validate();
0736:
0737: return sm.getObject();
0738: }
0739:
0740: public Object getObjectById(Object id, Class contextClass,
0741: int[] fieldNumbers, FieldManager fm) {
0742: assertIsOpen();
0743:
0744: if (id == null)
0745: return null;
0746:
0747: StateManager sm = getStateManagerById(id, contextClass);
0748:
0749: sm.offerPrefetchedFields(fieldNumbers, fm);
0750:
0751: return sm.getObject();
0752: }
0753:
0754: public Object getObjectId(Object pc) {
0755: assertIsOpen();
0756:
0757: if (pc == null || !(pc instanceof PersistenceCapable))
0758: return null;
0759: else
0760: return ((PersistenceCapable) pc).jdoGetObjectId();
0761: }
0762:
0763: public Object getTransactionalObjectId(Object pc) {
0764: assertIsOpen();
0765:
0766: if (pc == null || !(pc instanceof PersistenceCapable))
0767: return null;
0768: else
0769: return ((PersistenceCapable) pc)
0770: .jdoGetTransactionalObjectId();
0771: }
0772:
0773: public synchronized void setUserObject(Object userObject) {
0774: assertIsOpen();
0775:
0776: this .userObject = userObject;
0777: }
0778:
0779: public synchronized Object getUserObject() {
0780: assertIsOpen();
0781:
0782: return userObject;
0783: }
0784:
0785: public PersistenceManagerFactory getPersistenceManagerFactory() {
0786: return pmf;
0787: }
0788:
0789: /**
0790: * Returns the class of the object having the given object ID.
0791: *
0792: * @param id
0793: * The JDO identity of some object.
0794: * @param contextClass
0795: * A class used to establish the class loader context in case the
0796: * object's class needs to be loaded.
0797: *
0798: * @return The class of the corresponding object.
0799: *
0800: * @exception JDOUserException
0801: * If the type of ID is not recognized ({@link OID} or {@link SCOID})
0802: * or, for OIDs, the type referred to in the OID is not recognized.
0803: */
0804:
0805: private Class getClassForObjectID(Object id, Class contextClass) {
0806: if (id instanceof OID) {
0807: int classID = ((OID) id).getClassID();
0808: ClassTable ct = null;
0809:
0810: try {
0811: ct = (ClassTable) srm.getTable(classID);
0812: } catch (ClassCastException e) {
0813: throw new JDOUserException("Not a class table, ID = "
0814: + classID, e);
0815: }
0816:
0817: if (ct == null) {
0818: /*
0819: * The ClassTable for this class ID has not yet been initialized.
0820: * Ask the store manager which class name it corresponds to.
0821: */
0822: Class c;
0823:
0824: try {
0825: c = classForName(srm.getJavaName(classID),
0826: contextClass);
0827: } catch (ClassNotFoundException e) {
0828: throw new JDOUserException("Class not found, ID = "
0829: + classID, e);
0830: }
0831:
0832: /*
0833: * We know the answer here, but make sure its ClassTable gets
0834: * initialized as a side effect.
0835: */
0836: ct = srm.getTable(c);
0837: }
0838:
0839: return ct.getType();
0840: } else if (id instanceof SCOID)
0841: return ((SCOID) id).getSCOClass();
0842: else
0843: throw new JDOUserException("Unrecognized object ID class: "
0844: + id.getClass().getName());
0845: }
0846:
0847: public Class getObjectIdClass(Class cls) {
0848: assertIsOpen();
0849:
0850: if (cls == null || !isPersistenceCapableClass(cls))
0851: return null;
0852: else if (ClassMetaData.forClass(cls).requiresExtent())
0853: return OID.class;
0854: else
0855: return SCOID.class;
0856: }
0857:
0858: public void setMultithreaded(boolean flag) {
0859: assertIsOpen();
0860:
0861: multithreaded = flag;
0862: }
0863:
0864: public boolean getMultithreaded() {
0865: assertIsOpen();
0866:
0867: return multithreaded;
0868: }
0869:
0870: public void setIgnoreCache(boolean flag) {
0871: assertIsOpen();
0872:
0873: ignoreCache = flag;
0874: }
0875:
0876: public boolean getIgnoreCache() {
0877: assertIsOpen();
0878:
0879: return ignoreCache;
0880: }
0881:
0882: private PersistenceCapable asPC(Object obj) {
0883: try {
0884: return (PersistenceCapable) obj;
0885: } catch (ClassCastException e) {
0886: throw new ClassNotPersistenceCapableException(obj
0887: .getClass());
0888: }
0889: }
0890:
0891: /**
0892: * Returns the StateManager for a given object.
0893: *
0894: * @return
0895: * Always returns a valid non-null StateManager or an exception is
0896: * thrown.
0897: *
0898: * @exception JDOUserException
0899: * If <var>obj</var> is null, not PersistenceCapable, has no state
0900: * manager, or is managed by a different PersistenceManager.
0901: */
0902:
0903: private StateManager getStateManager(Object obj) {
0904: StateManager sm = findStateManager(obj);
0905:
0906: if (sm == null)
0907: throw new JDOUserException("Object is not managed", obj);
0908:
0909: return sm;
0910: }
0911:
0912: /**
0913: * Returns the StateManager for a given object.
0914: *
0915: * @return
0916: * The object's state manager, or <code>null</code> if obj is null or
0917: * has no state manager.
0918: *
0919: * @exception JDOUserException
0920: * If <var>obj</var> is not PersistenceCapable or is managed by a
0921: * different PersistenceManager.
0922: */
0923:
0924: public StateManager findStateManager(Object obj) {
0925: return obj == null ? null : findStateManager(asPC(obj));
0926: }
0927:
0928: /**
0929: * Returns an object's StateManager, or null if it has none.
0930: * pc must be non-null.
0931: */
0932:
0933: private synchronized StateManager findStateManager(
0934: PersistenceCapable pc) {
0935: StateManager sm = null;
0936:
0937: PersistenceCapable previousLookingFor = lookingForStateManagerFor;
0938: StateManager previousFound = foundStateManager;
0939:
0940: try {
0941: lookingForStateManagerFor = pc;
0942: foundStateManager = null;
0943:
0944: if (pc.jdoGetPersistenceManager() != null) {
0945: if (foundStateManager == null)
0946: throw new JDOUserException(
0947: "Object managed by a different PersistenceManager",
0948: pc);
0949: }
0950:
0951: sm = foundStateManager;
0952: } finally {
0953: lookingForStateManagerFor = previousLookingFor;
0954: foundStateManager = previousFound;
0955: }
0956:
0957: return sm;
0958: }
0959:
0960: public synchronized void hereIsStateManager(StateManager sm,
0961: Object pc) {
0962: if (lookingForStateManagerFor == pc)
0963: foundStateManager = sm;
0964: }
0965:
0966: public synchronized void markDirty(StateManager sm) {
0967: if (sm != dirtyStateManager)
0968: flushDirty();
0969:
0970: dirtyStateManager = sm;
0971: }
0972:
0973: public synchronized void flushDirty() {
0974: if (dirtyStateManager != null) {
0975: StateManager sm = dirtyStateManager;
0976: dirtyStateManager = null;
0977: sm.flush();
0978: }
0979: }
0980:
0981: /**
0982: * Commit any changes made to objects managed by the persistence manager
0983: * to the database.
0984: */
0985: synchronized void postCommit() {
0986: ArrayList failures = new ArrayList();
0987:
0988: try {
0989: StateManager[] sms = (StateManager[]) txCache
0990: .toArray(new StateManager[txCache.size()]);
0991:
0992: for (int i = 0; i < sms.length; ++i) {
0993: try {
0994: sms[i].postCommit();
0995: } catch (RuntimeException e) {
0996: failures.add(e);
0997: }
0998: }
0999: } finally {
1000: txCache.clear();
1001: }
1002:
1003: if (!failures.isEmpty())
1004: throw new CommitStateTransitionException(
1005: (Exception[]) failures
1006: .toArray(new Exception[failures.size()]));
1007: }
1008:
1009: /**
1010: * Rollback any changes made to objects managed by the persistence manager
1011: * to the database.
1012: */
1013: synchronized void preRollback() {
1014: ArrayList failures = new ArrayList();
1015:
1016: try {
1017: dirtyStateManager = null;
1018:
1019: StateManager[] sms = (StateManager[]) txCache
1020: .toArray(new StateManager[txCache.size()]);
1021:
1022: for (int i = 0; i < sms.length; ++i) {
1023: try {
1024: sms[i].preRollback();
1025: } catch (RuntimeException e) {
1026: failures.add(e);
1027: }
1028: }
1029: } finally {
1030: txCache.clear();
1031: }
1032:
1033: if (!failures.isEmpty())
1034: throw new RollbackStateTransitionException(
1035: (Exception[]) failures
1036: .toArray(new Exception[failures.size()]));
1037: }
1038:
1039: public void dump(Object obj, PrintWriter out) {
1040: getStateManager(obj).dump(out);
1041: }
1042: }
|