0001: /**********************************************************************
0002: Copyright (c) 2003 David Jencks and others. All rights reserved.
0003: Licensed under the Apache License, Version 2.0 (the "License");
0004: you may not use this file except in compliance with the License.
0005: You may obtain a copy of the License at
0006:
0007: http://www.apache.org/licenses/LICENSE-2.0
0008:
0009: Unless required by applicable law or agreed to in writing, software
0010: distributed under the License is distributed on an "AS IS" BASIS,
0011: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0012: See the License for the specific language governing permissions and
0013: limitations under the License.
0014:
0015: Contributors:
0016: 2003 Erik Bengtson - removed exist() operation
0017: 2003 Andy Jefferson - commented
0018: 2003 Andy Jefferson - added check on makePersistent that class is persistence capable
0019: 2003 Andy Jefferson - introduction of localiser
0020: 2003 Erik Bengtson - provided initial caching mechanism
0021: 2003 Erik Bengtson - added getObjectbyAID
0022: 2003 Erik Bengtson - removed unused variables
0023: 2004 Erik Bengtson - implemented evictAll
0024: 2004 Andy Jefferson - converted to use Logger
0025: 2004 Andy Jefferson - added LifecycleListener
0026: 2004 Andy Jefferson - rewritten Cache
0027: 2005 Andy Jefferson - moved ClassLoaderResolver handling to separate class
0028: 2005 Marco Schulze - implemented copying the lifecycle listeners in j2ee environment
0029: 2007 Andy Jefferson - copyOnAttach
0030: ...
0031: **********************************************************************/package org.jpox.jdo;
0032:
0033: import java.lang.reflect.Method;
0034: import java.util.ArrayList;
0035: import java.util.Arrays;
0036: import java.util.Collection;
0037: import java.util.Date;
0038: import java.util.EnumSet;
0039: import java.util.HashMap;
0040: import java.util.Iterator;
0041: import java.util.List;
0042: import java.util.Map;
0043: import java.util.Set;
0044:
0045: import javax.jdo.Extent;
0046: import javax.jdo.FetchPlan;
0047: import javax.jdo.JDOException;
0048: import javax.jdo.JDOFatalUserException;
0049: import javax.jdo.JDOOptimisticVerificationException;
0050: import javax.jdo.JDOUserException;
0051: import javax.jdo.ObjectState;
0052: import javax.jdo.PersistenceManagerFactory;
0053: import javax.jdo.Query;
0054: import javax.jdo.datastore.JDOConnection;
0055: import javax.jdo.datastore.Sequence;
0056: import javax.jdo.listener.InstanceLifecycleListener;
0057: import javax.jdo.spi.PersistenceCapable;
0058:
0059: import org.jpox.ClassLoaderResolver;
0060: import org.jpox.ObjectManager;
0061: import org.jpox.ObjectManagerImpl;
0062: import org.jpox.exceptions.ClassNotResolvedException;
0063: import org.jpox.exceptions.JPOXException;
0064: import org.jpox.exceptions.JPOXOptimisticException;
0065: import org.jpox.exceptions.TransactionActiveOnCloseException;
0066: import org.jpox.jdo.exceptions.TransactionNotActiveException;
0067: import org.jpox.metadata.AbstractClassMetaData;
0068: import org.jpox.metadata.FetchGroupMetaData;
0069: import org.jpox.metadata.FetchPlanMetaData;
0070: import org.jpox.metadata.IdentityType;
0071: import org.jpox.metadata.QueryLanguage;
0072: import org.jpox.metadata.QueryMetaData;
0073: import org.jpox.metadata.SequenceMetaData;
0074: import org.jpox.state.DetachState;
0075: import org.jpox.state.FetchPlanState;
0076: import org.jpox.store.SCOID;
0077: import org.jpox.util.JPOXLogger;
0078: import org.jpox.util.Localiser;
0079:
0080: /**
0081: * Provide the basics of a JDO PersistenceManager using an underlying ObjectManager to perform the
0082: * actual persistence.
0083: *
0084: * @version $Revision: 1.4 $
0085: */
0086: public abstract class AbstractPersistenceManager implements
0087: javax.jdo.PersistenceManager {
0088: /** Localisation utility for output messages */
0089: protected static final Localiser LOCALISER = Localiser
0090: .getInstance("org.jpox.Localisation");
0091:
0092: /** Map of user objects attached to this PM. */
0093: private Map userObjectMap;
0094:
0095: /** User object attached to the PM. */
0096: private Object userObject;
0097:
0098: /** Backing ObjectManager for this PersistenceManager. */
0099: protected ObjectManager objectMgr;
0100:
0101: protected javax.jdo.Transaction jdotx;
0102:
0103: /** Owning PersistenceManagerFactory. */
0104: protected AbstractPersistenceManagerFactory apmf;
0105:
0106: /** JDO Fetch Plan. */
0107: protected JDOFetchPlan fetchPlan = null;
0108:
0109: /**
0110: * Constructor.
0111: * @param apmf Persistence Manager Factory
0112: * @param userName Username for the datastore
0113: * @param password Password for the datastore
0114: */
0115: public AbstractPersistenceManager(
0116: AbstractPersistenceManagerFactory apmf, String userName,
0117: String password) {
0118: objectMgr = new ObjectManagerImpl(apmf, this , userName,
0119: password);
0120: this .apmf = apmf;
0121: userObject = null;
0122: userObjectMap = null;
0123: fetchPlan = new JDOFetchPlan(objectMgr.getFetchPlan());
0124: }
0125:
0126: /**
0127: * Convenience accessor for the ObjectManager performing the actual persistence.
0128: * @return The ObjectManager
0129: */
0130: public ObjectManager getObjectManager() {
0131: return objectMgr;
0132: }
0133:
0134: /**
0135: * Accessor for the PersistenceManager Factory.
0136: * @return The PersistenceManagerFactory
0137: */
0138: public PersistenceManagerFactory getPersistenceManagerFactory() {
0139: // To be implemented by subclasses
0140: throw new JDOException(LOCALISER.msg("011012"));
0141: }
0142:
0143: /**
0144: * Accessor for the PersistenceManager Factory.
0145: * @return The PersistenceManagerFactory
0146: */
0147: public AbstractPersistenceManagerFactory getAbstractPersistenceManagerFactory() {
0148: return apmf;
0149: }
0150:
0151: /**
0152: * Accessor for whether to detach all objects on commit of the transaction.
0153: * @return Whether to detach all on commit.
0154: */
0155: public boolean getDetachAllOnCommit() {
0156: return objectMgr.getDetachAllOnCommit();
0157: }
0158:
0159: /**
0160: * Accessor for whether to copy objects on attaching.
0161: * @return Whether to copy objects on attaching.
0162: */
0163: public boolean getCopyOnAttach() {
0164: return objectMgr.getCopyOnAttach();
0165: }
0166:
0167: /**
0168: * Acessor for the current FetchPlan
0169: * @return The FetchPlan
0170: */
0171: public FetchPlan getFetchPlan() {
0172: return fetchPlan;
0173: }
0174:
0175: /**
0176: * Accessor for whether to ignore the cache.
0177: * @return Whether to ignore the cache.
0178: */
0179: public boolean getIgnoreCache() {
0180: return objectMgr.getIgnoreCache();
0181: }
0182:
0183: /**
0184: * Accessor for whether the Persistence Manager is multithreaded.
0185: * @return Whether to run multithreaded.
0186: */
0187: public boolean getMultithreaded() {
0188: return objectMgr.getMultithreaded();
0189: }
0190:
0191: /**
0192: * Mutator for whether to detach all objects on commit of the transaction.
0193: * @param flag Whether to detach all on commit.
0194: */
0195: public void setDetachAllOnCommit(boolean flag) {
0196: objectMgr.setDetachAllOnCommit(flag);
0197: }
0198:
0199: /**
0200: * Mutator for whether to copy objects on attach.
0201: * @param flag Whether to copy on attaching
0202: */
0203: public void setCopyOnAttach(boolean flag) {
0204: objectMgr.setCopyOnAttach(flag);
0205: }
0206:
0207: /**
0208: * Mutator for whether to ignore the cache.
0209: * @param flag Whether to ignore the cache.
0210: */
0211: public void setIgnoreCache(boolean flag) {
0212: objectMgr.setIgnoreCache(flag);
0213: }
0214:
0215: /**
0216: * Mutator for whether the Persistence Manager is multithreaded.
0217: * @param flag Whether to run multithreaded.
0218: */
0219: public void setMultithreaded(boolean flag) {
0220: objectMgr.setMultithreaded(flag);
0221: }
0222:
0223: /**
0224: * Accessor for the date on the datastore.
0225: * @return Date on the datastore
0226: */
0227: public Date getServerDate() {
0228: try {
0229: return objectMgr.getStoreManager().getDatastoreDate();
0230: } catch (JPOXException jpe) {
0231: throw JPOXJDOHelper.getJDOExceptionForJPOXException(jpe);
0232: }
0233: }
0234:
0235: /**
0236: * Method to close the Persistence Manager.
0237: */
0238: public synchronized void close() {
0239: userObject = null;
0240: userObjectMap = null;
0241:
0242: try {
0243: // Close the ObjectManager
0244: objectMgr.close();
0245: apmf.releasePersistenceManager(this );
0246: objectMgr.postClose();
0247: } catch (TransactionActiveOnCloseException tae) {
0248: throw new JDOUserException(tae.getMessage(), this );
0249: } catch (JPOXException jpe) {
0250: throw JPOXJDOHelper.getJDOExceptionForJPOXException(jpe);
0251: }
0252: }
0253:
0254: /**
0255: * Accessor for whether this ObjectManager is closed.
0256: * @return Whether this manager is closed.
0257: */
0258: public boolean isClosed() {
0259: return objectMgr.isClosed();
0260: }
0261:
0262: /**
0263: * Accessor for the current transaction.
0264: * @return The transaction
0265: */
0266: public javax.jdo.Transaction currentTransaction() {
0267: assertIsOpen();
0268: return jdotx;
0269: }
0270:
0271: /**
0272: * Method to allow setting of the transaction by a superclass.
0273: * @param tx The transaction
0274: */
0275: protected void setTransaction(org.jpox.Transaction tx) {
0276: jdotx = new JDOTransaction(this , tx);
0277: }
0278:
0279: // ----------------------------- Eviction --------------------------------------------
0280:
0281: /**
0282: * JDO Convenience method to wrap any JPOX exceptions for the evict process.
0283: * @param obj The object to evict
0284: * @throws JDOUserException thrown if some instances could not be evicted
0285: */
0286: private void jdoEvict(Object obj) {
0287: try {
0288: objectMgr.evictObject(obj);
0289: } catch (JPOXException jpe) {
0290: // Convert any JPOX exceptions into what JDO expects
0291: throw JPOXJDOHelper.getJDOExceptionForJPOXException(jpe);
0292: }
0293: }
0294:
0295: /**
0296: * Method to evict an object from L1 cache.
0297: * @param obj The object
0298: * @throws JDOUserException thrown if some instances could not be evicted
0299: */
0300: public synchronized void evict(Object obj) {
0301: assertIsOpen();
0302: jdoEvict(obj);
0303: }
0304:
0305: /**
0306: * Method to evict all objects of the specified type (and optionaly its subclasses).
0307: * @param cls Type of persistable object
0308: * @param subclasses Whether to include subclasses
0309: * @deprecated
0310: */
0311: public synchronized void evictAll(Class cls, boolean subclasses) {
0312: try {
0313: objectMgr.evictObjects(cls, subclasses);
0314: } catch (JPOXException jpe) {
0315: // Convert any JPOX exceptions into what JDO expects
0316: throw JPOXJDOHelper.getJDOExceptionForJPOXException(jpe);
0317: }
0318: }
0319:
0320: /**
0321: * Method to evict all objects of the specified type (and optionaly its subclasses).
0322: * @param cls Type of persistable object
0323: * @param subclasses Whether to include subclasses
0324: */
0325: public synchronized void evictAll(boolean subclasses, Class cls) {
0326: try {
0327: objectMgr.evictObjects(cls, subclasses);
0328: } catch (JPOXException jpe) {
0329: // Convert any JPOX exceptions into what JDO expects
0330: throw JPOXJDOHelper.getJDOExceptionForJPOXException(jpe);
0331: }
0332: }
0333:
0334: /**
0335: * Method to evict an array of objects from L1 cache.
0336: * @param pcs The objects
0337: */
0338: public synchronized void evictAll(Object[] pcs) {
0339: evictAll(Arrays.asList(pcs));
0340: }
0341:
0342: /**
0343: * Method to evict a collection of objects from L1 cache.
0344: * @param pcs The objects
0345: * @throws JDOUserException thrown if some instances could not be evicted
0346: */
0347: public synchronized void evictAll(Collection pcs) {
0348: assertIsOpen();
0349: ArrayList failures = new ArrayList();
0350: Iterator i = pcs.iterator();
0351: while (i.hasNext()) {
0352: try {
0353: jdoEvict(i.next());
0354: } catch (JDOException e) {
0355: failures.add(e);
0356: }
0357: }
0358: if (!failures.isEmpty()) {
0359: throw new JDOUserException(LOCALISER.msg("011001"),
0360: (Exception[]) failures
0361: .toArray(new Exception[failures.size()]));
0362: }
0363: }
0364:
0365: /**
0366: * Method to evict all current objects from L1 cache.
0367: */
0368: public synchronized void evictAll() {
0369: assertIsOpen();
0370: objectMgr.evictAllObjects();
0371: }
0372:
0373: // --------------------------------- Refresh ----------------------------------------
0374:
0375: /**
0376: * JDO Convenience method to wrap any JPOX exceptions for the refresh process.
0377: * @param obj The object to refresh
0378: * @throws JDOUserException thrown if the object could not be refreshed
0379: */
0380: private void jdoRefresh(Object obj) {
0381: try {
0382: objectMgr.refreshObject(obj);
0383: } catch (JPOXException jpe) {
0384: // Convert any JPOX exceptions into what JDO expects
0385: throw JPOXJDOHelper.getJDOExceptionForJPOXException(jpe);
0386: }
0387: }
0388:
0389: /**
0390: * Method to do a refresh of an object.
0391: * @param obj The Object
0392: * @throws JDOUserException thrown if the object could not be refreshed
0393: */
0394: public synchronized void refresh(Object obj) {
0395: assertIsOpen();
0396: jdoRefresh(obj);
0397: }
0398:
0399: /**
0400: * Method to do a refresh of an array of objects.
0401: * @param pcs The Objects
0402: */
0403: public synchronized void refreshAll(Object[] pcs) {
0404: refreshAll(Arrays.asList(pcs));
0405: }
0406:
0407: /**
0408: * Method to do a refresh of a collection of objects.
0409: * @param pcs The Objects
0410: * @throws JDOUserException thrown if instances could not be refreshed.
0411: */
0412: public synchronized void refreshAll(Collection pcs) {
0413: assertIsOpen();
0414: ArrayList failures = new ArrayList();
0415: Iterator iter = pcs.iterator();
0416: while (iter.hasNext()) {
0417: try {
0418: jdoRefresh(iter.next());
0419: } catch (JDOException e) {
0420: failures.add(e);
0421: }
0422: }
0423: if (!failures.isEmpty()) {
0424: throw new JDOUserException(LOCALISER.msg("011002"),
0425: (Exception[]) failures
0426: .toArray(new Exception[failures.size()]));
0427: }
0428: }
0429:
0430: /**
0431: * Method to do a refresh of all objects.
0432: * @throws JDOUserException thrown if instances could not be refreshed.
0433: */
0434: public synchronized void refreshAll() {
0435: assertIsOpen();
0436: try {
0437: objectMgr.refreshAllObjects();
0438: } catch (JPOXException jpe) {
0439: throw JPOXJDOHelper.getJDOExceptionForJPOXException(jpe);
0440: }
0441: }
0442:
0443: /**
0444: * Method to do a refresh of objects that failed verification in the
0445: * exception.
0446: * @param exc The JDO exception containing the objects that failed
0447: * @since 1.1
0448: */
0449: public synchronized void refreshAll(JDOException exc) {
0450: Object obj = exc.getFailedObject();
0451: if (obj != null) {
0452: refresh(obj);
0453: }
0454:
0455: Throwable[] nested_excs = exc.getNestedExceptions();
0456: if (nested_excs != null) {
0457: for (int i = 0; i < nested_excs.length; i++) {
0458: if (nested_excs[i] instanceof JDOException) {
0459: refreshAll((JDOException) nested_excs[i]);
0460: }
0461: }
0462: }
0463: }
0464:
0465: // ------------------------------- Retrieve ------------------------------------------
0466:
0467: /**
0468: * JDO Convenience method to wrap any JPOX exceptions for the retrieve process.
0469: * @param obj The object to retrieve
0470: * @param fgOnly Just retrieve the current fetch group
0471: * @throws JDOUserException thrown if the object could not be retrieved
0472: */
0473: private void jdoRetrieve(Object obj, boolean fgOnly) {
0474: try {
0475: objectMgr.retrieveObject(obj, fgOnly);
0476: } catch (JPOXException jpe) {
0477: // Convert any JPOX exceptions into what JDO expects
0478: throw JPOXJDOHelper.getJDOExceptionForJPOXException(jpe);
0479: }
0480: }
0481:
0482: /**
0483: * Method to retrieve the fields of an object.
0484: * @param pc The object
0485: * @param fgOnly Whether to retrieve the current fetch group fields only
0486: */
0487: public synchronized void retrieve(Object pc, boolean fgOnly) {
0488: assertIsOpen();
0489: jdoRetrieve(pc, fgOnly);
0490: }
0491:
0492: /**
0493: * Method to retrieve the fields of an object.
0494: * @param pc The object
0495: */
0496: public synchronized void retrieve(Object pc) {
0497: retrieve(pc, false);
0498: }
0499:
0500: /**
0501: * Method to retrieve an array of objects.
0502: * @param pcs The objects
0503: */
0504: public synchronized void retrieveAll(Object[] pcs) {
0505: retrieveAll(Arrays.asList(pcs), false);
0506: }
0507:
0508: /**
0509: * Retrieve field values of instances from the store. This tells the
0510: * <code>PersistenceManager</code> that the application intends to use the
0511: * instances, and their field values should be retrieved. The fields in the
0512: * current fetch group must be retrieved, and the implementation might
0513: * retrieve more fields than the current fetch group.
0514: * <P>
0515: * The <code>PersistenceManager</code> might use policy information about
0516: * the class to retrieve associated instances.
0517: * @param pcs the instances
0518: * @param fgOnly whether to retrieve only the current fetch group fields
0519: */
0520: public void retrieveAll(Object[] pcs, boolean fgOnly) {
0521: retrieveAll(Arrays.asList(pcs), fgOnly);
0522: }
0523:
0524: /**
0525: * Retrieve field values of instances from the store.
0526: * As the equivalent method but arguments reversed for JDK1.5+.
0527: * @param fgOnly whether to retrieve only the current fetch group fields
0528: * @param pcs the instances
0529: * @since 1.2
0530: */
0531: public void retrieveAll(boolean fgOnly, Object[] pcs) {
0532: retrieveAll(Arrays.asList(pcs), fgOnly);
0533: }
0534:
0535: /**
0536: * Retrieve field values of instances from the store. This tells the
0537: * <code>PersistenceManager</code> that the application intends to use the
0538: * instances, and their field values should be retrieved. The fields in the
0539: * current fetch group must be retrieved, and the implementation might
0540: * retrieve more fields than the current fetch group.
0541: * <P>
0542: * The <code>PersistenceManager</code> might use policy information about
0543: * the class to retrieve associated instances.
0544: * @param pcs the instances
0545: * @param fgOnly whether to retrieve only the current fetch-group fields
0546: */
0547: public void retrieveAll(Collection pcs, boolean fgOnly) {
0548: assertIsOpen();
0549: ArrayList failures = new ArrayList();
0550: Iterator i = pcs.iterator();
0551: while (i.hasNext()) {
0552: try {
0553: jdoRetrieve(i.next(), fgOnly);
0554: } catch (RuntimeException e) {
0555: failures.add(e);
0556: }
0557: }
0558: if (!failures.isEmpty()) {
0559: throw new JDOUserException(LOCALISER.msg("011003"),
0560: (Exception[]) failures
0561: .toArray(new Exception[failures.size()]));
0562: }
0563: }
0564:
0565: /**
0566: * Method to retrieve a collection of objects. Throws a JDOUserException if
0567: * instances could not be retrieved.
0568: * @param pcs The objects
0569: */
0570: public synchronized void retrieveAll(Collection pcs) {
0571: retrieveAll(pcs.toArray(), false);
0572: }
0573:
0574: // ---------------------------------- Make Persistent ---------------------------------------
0575:
0576: /**
0577: * JDO Convenience method to wrap any JPOX exceptions for the makePersistent process.
0578: * @param obj The object to persist
0579: * @throws JDOUserException thrown if the object could not be persisted
0580: */
0581: private Object jdoMakePersistent(Object obj) {
0582: try {
0583: return objectMgr.persistObject(obj);
0584: } catch (JPOXException jpe) {
0585: // Convert any JPOX exceptions into what JDO expects
0586: throw JPOXJDOHelper.getJDOExceptionForJPOXException(jpe);
0587: }
0588: }
0589:
0590: /**
0591: * JDO method to persist an object.
0592: * Will also attach a previously detached object.
0593: * @param obj The object
0594: * @return The persisted object
0595: */
0596: public synchronized Object makePersistent(Object obj) {
0597: assertIsOpen();
0598: assertWritable();
0599: if (obj == null) {
0600: return null;
0601: }
0602:
0603: // Persist the object
0604: return jdoMakePersistent(obj);
0605: }
0606:
0607: /**
0608: * JDO method to make persistent an array of objects.
0609: * @param pcs The objects to persist
0610: */
0611: public synchronized Object[] makePersistentAll(Object[] pcs) {
0612: return makePersistentAll(Arrays.asList(pcs)).toArray();
0613: }
0614:
0615: /**
0616: * JDO method to make persistent a collection of objects.
0617: * Throws a JDOUserException if objects could not be made persistent.
0618: * @param pcs The objects to persist
0619: */
0620: public synchronized Collection makePersistentAll(Collection pcs) {
0621: assertIsOpen();
0622: assertWritable();
0623:
0624: List failures = null;
0625: Iterator i = pcs.iterator();
0626: Collection persistedPcs = new ArrayList();
0627: while (i.hasNext()) {
0628: try {
0629: Object persistedPc = jdoMakePersistent(i.next());
0630: persistedPcs.add(persistedPc);
0631: } catch (RuntimeException e) {
0632: if (failures == null) {
0633: failures = new ArrayList();
0634: }
0635: failures.add(e);
0636: }
0637: }
0638: if (failures != null) {
0639: throw new JDOUserException(LOCALISER.msg("011004"),
0640: (Exception[]) failures
0641: .toArray(new Exception[failures.size()]));
0642: }
0643:
0644: return persistedPcs;
0645: }
0646:
0647: // ------------------------------- Delete Persistent ------------------------------------------
0648:
0649: /**
0650: * JDO Convenience method to wrap any JPOX exceptions for the deletePersistent process.
0651: * @param obj The object to delete
0652: * @throws JDOUserException thrown if the object could not be deleted
0653: */
0654: private void jdoDeletePersistent(Object obj) {
0655: try {
0656: objectMgr.deleteObject(obj);
0657: } catch (JPOXException jpe) {
0658: // Convert any JPOX exceptions into what JDO expects
0659: throw JPOXJDOHelper.getJDOExceptionForJPOXException(jpe);
0660: }
0661: }
0662:
0663: /**
0664: * JDO method to delete an object from the datastore.
0665: * @param obj The object
0666: */
0667: public synchronized void deletePersistent(Object obj) {
0668: assertIsOpen();
0669: assertWritable();
0670:
0671: jdoDeletePersistent(obj);
0672: }
0673:
0674: /**
0675: * JDO method to delete an array of objects from the datastore.
0676: * @param pcs The objects
0677: */
0678: public synchronized void deletePersistentAll(Object[] pcs) {
0679: deletePersistentAll(Arrays.asList(pcs));
0680: }
0681:
0682: /**
0683: * JDO method to delete a collection of objects from the datastore.
0684: * Throws a JDOUserException if objects could not be deleted.
0685: * @param pcs The objects
0686: */
0687: public synchronized void deletePersistentAll(Collection pcs) {
0688: assertIsOpen();
0689: assertWritable();
0690:
0691: ArrayList failures = new ArrayList();
0692: Iterator i = pcs.iterator();
0693: while (i.hasNext()) {
0694: try {
0695: jdoDeletePersistent(i.next());
0696: } catch (RuntimeException e) {
0697: failures.add(e);
0698: }
0699: }
0700: if (!failures.isEmpty()) {
0701: throw new JDOUserException(LOCALISER.msg("011005"),
0702: (Exception[]) failures
0703: .toArray(new Exception[failures.size()]));
0704: }
0705: }
0706:
0707: // -------------------------------- Make Transient -----------------------------------------
0708:
0709: /**
0710: * JDO Convenience method to wrap any JPOX exceptions for the makeTransient process.
0711: * @param pc The object to make transient
0712: * @param state FetchPlanState
0713: * @throws JDOUserException thrown if the object could not be made transient
0714: */
0715: private void jdoMakeTransient(Object pc, FetchPlanState state) {
0716: try {
0717: objectMgr.makeObjectTransient(pc, state);
0718: } catch (JPOXException jpe) {
0719: // Convert any JPOX exceptions into what JDO expects
0720: throw JPOXJDOHelper.getJDOExceptionForJPOXException(jpe);
0721: }
0722: }
0723:
0724: /**
0725: * Method to make transient an object allowing fetching using the fetch plan.
0726: * @param pc The object
0727: * @param useFetchPlan Whether to make transient all objects in the fetch plan
0728: */
0729: public synchronized void makeTransient(Object pc,
0730: boolean useFetchPlan) {
0731: assertIsOpen();
0732:
0733: FetchPlanState state = null;
0734: if (useFetchPlan) {
0735: // Create a state object to carry the processing state info
0736: state = new FetchPlanState();
0737: }
0738: jdoMakeTransient(pc, state);
0739: }
0740:
0741: /**
0742: * Method to make transient an object.
0743: * This doesn't use the fetch plan and just makes the specified object transient.
0744: * @param pc The object
0745: */
0746: public synchronized void makeTransient(Object pc) {
0747: makeTransient(pc, false);
0748: }
0749:
0750: /**
0751: * Method to make transient an array of objects.
0752: * @param pcs The objects
0753: */
0754: public synchronized void makeTransientAll(Object[] pcs) {
0755: makeTransientAll(Arrays.asList(pcs));
0756: }
0757:
0758: /**
0759: * Method to make transient an array of objects.
0760: * @param pcs The objects
0761: * @param includeFetchPlan Whether to make transient all objects in the fetch plan
0762: */
0763: public synchronized void makeTransientAll(Object[] pcs,
0764: boolean includeFetchPlan) {
0765: makeTransientAll(Arrays.asList(pcs), includeFetchPlan);
0766: }
0767:
0768: /**
0769: * Method to make transient an array of objects.
0770: * @param includeFetchPlan Whether to make transient all objects in the fetch plan
0771: * @param pcs The objects
0772: */
0773: public synchronized void makeTransientAll(boolean includeFetchPlan,
0774: Object[] pcs) {
0775: makeTransientAll(Arrays.asList(pcs), includeFetchPlan);
0776: }
0777:
0778: /**
0779: * Method to make transient a collection of objects.
0780: * @param pcs The objects
0781: * @param useFetchPlan Whether to use the fetch plan when making transient
0782: * @throws JDOUserException thrown if objects could not be made transient.
0783: */
0784: public synchronized void makeTransientAll(Collection pcs,
0785: boolean useFetchPlan) {
0786: assertIsOpen();
0787: ArrayList failures = new ArrayList();
0788: Iterator i = pcs.iterator();
0789: FetchPlanState state = null;
0790: if (useFetchPlan) {
0791: // Create a state object to carry the processing state info
0792: state = new FetchPlanState();
0793: }
0794: while (i.hasNext()) {
0795: try {
0796: jdoMakeTransient(i.next(), state);
0797: } catch (RuntimeException e) {
0798: failures.add(e);
0799: }
0800: }
0801: if (!failures.isEmpty()) {
0802: throw new JDOUserException(LOCALISER.msg("011006"),
0803: (Exception[]) failures
0804: .toArray(new Exception[failures.size()]));
0805: }
0806: }
0807:
0808: /**
0809: * Method to make transient a collection of objects.
0810: * @param pcs The objects
0811: * @throws JDOUserException thrown if objects could not be made transient.
0812: */
0813: public synchronized void makeTransientAll(Collection pcs) {
0814: makeTransientAll(pcs, false);
0815: }
0816:
0817: // ----------------------------------- Make Transactional --------------------------------------
0818:
0819: /**
0820: * JDO Convenience method to wrap any JPOX exceptions for the makeTransactional process.
0821: * @param pc The object to make transactional
0822: * @throws JDOUserException thrown if the object could not be made transactional
0823: */
0824: private void jdoMakeTransactional(Object pc) {
0825: try {
0826: objectMgr.makeObjectTransactional(pc);
0827: } catch (JPOXException jpe) {
0828: // Convert any JPOX exceptions into what JDO expects
0829: throw JPOXJDOHelper.getJDOExceptionForJPOXException(jpe);
0830: }
0831: }
0832:
0833: /**
0834: * Method to make transactional an object.
0835: * @param pc The object
0836: */
0837: public synchronized void makeTransactional(Object pc) {
0838: assertIsOpen();
0839:
0840: jdoMakeTransactional(pc);
0841: }
0842:
0843: /**
0844: * Method to make transactional an array of objects.
0845: * @param pcs The objects
0846: */
0847: public synchronized void makeTransactionalAll(Object[] pcs) {
0848: makeTransactionalAll(Arrays.asList(pcs));
0849: }
0850:
0851: /**
0852: * Method to make transactional a collection of objects.
0853: * @param pcs The objects
0854: * @throws JDOUserException thrown if objects could not be made transactional
0855: */
0856: public synchronized void makeTransactionalAll(Collection pcs) {
0857: assertIsOpen();
0858: assertActiveTransaction();
0859:
0860: ArrayList failures = new ArrayList();
0861: Iterator i = pcs.iterator();
0862: while (i.hasNext()) {
0863: try {
0864: jdoMakeTransactional(i.next());
0865: } catch (RuntimeException e) {
0866: failures.add(e);
0867: }
0868: }
0869: if (!failures.isEmpty()) {
0870: throw new JDOUserException(LOCALISER.msg("011007"),
0871: (Exception[]) failures
0872: .toArray(new Exception[failures.size()]));
0873: }
0874: }
0875:
0876: // ------------------------------ Make NonTransactional -------------------------------------------
0877:
0878: /**
0879: * JDO Convenience method to wrap any JPOX exceptions for the makeNontransactional process.
0880: * @param obj The object to make nontransactional
0881: * @throws JDOUserException thrown if the object could not be made nontransactional
0882: */
0883: private void jdoMakeNontransactional(Object obj) {
0884: try {
0885: objectMgr.makeObjectNontransactional(obj);
0886: } catch (JPOXException jpe) {
0887: // Convert any JPOX exceptions into what JDO expects
0888: throw JPOXJDOHelper.getJDOExceptionForJPOXException(jpe);
0889: }
0890: }
0891:
0892: /**
0893: * Method to make nontransactional an object.
0894: * @param pc The object
0895: */
0896: public synchronized void makeNontransactional(Object pc) {
0897: assertIsOpen();
0898: if (pc == null) {
0899: return;
0900: }
0901:
0902: // for non transactional read, tx might be not active
0903: // TODO add verification if is non transactional read = true
0904: if (objectMgr.getTransaction().isActive()) {
0905: assertActiveTransaction();
0906: }
0907: // if !transactional and !persistent
0908: if (!((PersistenceCapable) pc).jdoIsTransactional()
0909: && !((PersistenceCapable) pc).jdoIsPersistent()) {
0910: throw new JDOUserException(LOCALISER.msg("011013"));
0911: }
0912: // if !transactional and persistent, do nothing
0913: if (!((PersistenceCapable) pc).jdoIsTransactional()
0914: && ((PersistenceCapable) pc).jdoIsPersistent()) {
0915: return;
0916: }
0917: jdoMakeNontransactional(pc);
0918: }
0919:
0920: /**
0921: * Method to make nontransactional an array of objects.
0922: * @param pcs The objects.
0923: */
0924: public synchronized void makeNontransactionalAll(Object[] pcs) {
0925: makeNontransactionalAll(Arrays.asList(pcs));
0926: }
0927:
0928: /**
0929: * Method to make nontransactional a collection of objects.
0930: * @param pcs The objects.
0931: * @throws JDOUserException thrown if objects could not be made nontransactional
0932: */
0933: public synchronized void makeNontransactionalAll(Collection pcs) {
0934: assertIsOpen();
0935: assertActiveTransaction();
0936:
0937: ArrayList failures = new ArrayList();
0938: Iterator i = pcs.iterator();
0939: while (i.hasNext()) {
0940: try {
0941: jdoMakeNontransactional(i.next());
0942: } catch (RuntimeException e) {
0943: failures.add(e);
0944: }
0945: }
0946: if (!failures.isEmpty()) {
0947: throw new JDOUserException(LOCALISER.msg("011008"),
0948: (Exception[]) failures
0949: .toArray(new Exception[failures.size()]));
0950: }
0951: }
0952:
0953: // ------------------------- Attach/Detach instances -----------------------
0954:
0955: /**
0956: * JDO Convenience method to wrap any JPOX exceptions for the detachCopy process.
0957: * @param obj The object to detach a copy of
0958: * @param state DetachState
0959: * @throws JDOUserException thrown if the object could not be detached
0960: */
0961: private Object jdoDetachCopy(Object obj, FetchPlanState state) {
0962: try {
0963: return objectMgr.detachObjectCopy(obj, state);
0964: } catch (JPOXException jpe) {
0965: // Convert any JPOX exceptions into what JDO expects
0966: throw JPOXJDOHelper.getJDOExceptionForJPOXException(jpe);
0967: }
0968: }
0969:
0970: /**
0971: * JDO method to detach a persistent object.
0972: * If the object is of class that is not detachable a transient copy will be returned.
0973: * If the object is not persistent it will be persisted first before detaching a copy.
0974: * @param pc The object
0975: * @return The detached object
0976: */
0977: public synchronized Object detachCopy(Object pc) {
0978: assertIsOpen();
0979: if (pc == null) {
0980: return null;
0981: }
0982:
0983: try {
0984: objectMgr.assertClassPersistable(pc.getClass());
0985: assertReadable("detachCopy");
0986:
0987: return jdoDetachCopy(pc, new DetachState(objectMgr
0988: .getApiAdapter()));
0989: } catch (JPOXException jpe) {
0990: throw JPOXJDOHelper.getJDOExceptionForJPOXException(jpe);
0991: }
0992: }
0993:
0994: /**
0995: * Detach the specified objects from the <code>PersistenceManager</code>.
0996: * The objects returned can be manipulated and re-attached with
0997: * {@link #makePersistentAll(Object[])}.
0998: * The detached instances will be unmanaged copies of the specified parameters,
0999: * and are suitable for serialization and manipulation outside of a JDO environment.
1000: * When detaching instances, only fields in the current {@link FetchPlan} will be
1001: * traversed. Thus, to detach a graph of objects, relations to other persistent
1002: * instances must either be in the <code>default-fetch-group</code>, or in the
1003: * current custom {@link FetchPlan}.
1004: * @param pcs the instances to detach
1005: * @return the detached instances
1006: */
1007: public synchronized Object[] detachCopyAll(Object[] pcs) {
1008: return detachCopyAll(Arrays.asList(pcs)).toArray();
1009: }
1010:
1011: /**
1012: * Detach the specified objects from the <code>PersistenceManager</code>.
1013: * @param pcs the instances to detach
1014: * @return the detached instances
1015: * @see #detachCopyAll(Object[])
1016: * @since JDO 2.0
1017: */
1018: public synchronized Collection detachCopyAll(Collection pcs) {
1019: assertIsOpen();
1020: assertReadable("detachCopyAll");
1021:
1022: // Detach the objects
1023: FetchPlanState state = new DetachState(objectMgr
1024: .getApiAdapter());
1025: List detacheds = new ArrayList();
1026: for (Iterator it = pcs.iterator(); it.hasNext();) {
1027: Object obj = it.next();
1028: if (obj == null) {
1029: detacheds.add(null);
1030: } else {
1031: detacheds.add(jdoDetachCopy(obj, state));
1032: }
1033: }
1034:
1035: return detacheds;
1036: }
1037:
1038: // --------------------------------- Queries ----------------------------------------
1039:
1040: /**
1041: * Construct an empty query instance.
1042: * @return The query
1043: */
1044: public synchronized Query newQuery() {
1045: return newQuery("javax.jdo.query.JDOQL", null);
1046: }
1047:
1048: /**
1049: * Construct a query instance from another query. The parameter might be a
1050: * serialized/restored Query instance from the same JDO vendor but a
1051: * different execution environment, or the parameter might be currently
1052: * bound to a PersistenceManager from the same JDO vendor. Any of the
1053: * elements Class, Filter, IgnoreCache flag, Import declarations, Variable
1054: * declarations, Parameter declarations, and Ordering from the parameter
1055: * Query are copied to the new Query instance, but a candidate Collection or
1056: * Extent element is discarded.
1057: * @param obj The object to use in the query
1058: * @return The query
1059: */
1060: public synchronized Query newQuery(Object obj) {
1061: if (obj != null && obj instanceof JDOQuery) {
1062: String language = ((JDOQuery) obj).getLanguage();
1063: return newQuery(language, obj);
1064: } else {
1065: // TODO What situation is this ?
1066: return newQuery(null, obj);
1067: }
1068: }
1069:
1070: /**
1071: * Construct a query instance using the specified Single-String query.
1072: * @param query The single-string query
1073: * @return The Query
1074: */
1075: public synchronized Query newQuery(String query) {
1076: return newQuery("javax.jdo.query.JDOQL", query);
1077: }
1078:
1079: /**
1080: * Construct a query instance using the specified language and the specified
1081: * query. The query instance will be of a class defined by the query language.
1082: * @param language The language parameter for the JDO Query language. This is by default
1083: * "javax.jdo.query.JDOQL", but in JDO 2.0 can also be "javax.jdo.query.SQL", or vendor provided languages.
1084: * @param query The query object
1085: * @return The query
1086: */
1087: public synchronized Query newQuery(String language, Object query) {
1088: assertIsOpen();
1089:
1090: if (language == null) {
1091: language = "javax.jdo.query.JDOQL";
1092: }
1093:
1094: // Check that our store supports the language
1095: if (!objectMgr.getStoreManager()
1096: .supportsQueryLanguage(language)) {
1097: throw new JDOUserException(LOCALISER
1098: .msg("011015", language));
1099: }
1100:
1101: org.jpox.store.query.Query internalQuery = null;
1102: try {
1103: if (query != null && query instanceof JDOQuery) {
1104: // Extract the internal query for generating the next query
1105: internalQuery = getObjectManager().getOMFContext()
1106: .getQueryManager().newQuery(language,
1107: objectMgr,
1108: ((JDOQuery) query).getInternalQuery());
1109: } else {
1110: internalQuery = getObjectManager().getOMFContext()
1111: .getQueryManager().newQuery(language,
1112: objectMgr, query);
1113: }
1114: } catch (JPOXException jpe) {
1115: throw JPOXJDOHelper.getJDOExceptionForJPOXException(jpe);
1116: }
1117: return new JDOQuery(this , internalQuery, language);
1118: }
1119:
1120: /**
1121: * Construct a query instance with the candidate class specified.
1122: * @param cls The class to query
1123: * @return The query
1124: */
1125: public synchronized Query newQuery(Class cls) {
1126: Query query = newQuery();
1127: query.setClass(cls);
1128: return query;
1129: }
1130:
1131: /**
1132: * Construct a query instance with the candidate Extent specified; the
1133: * candidate class is taken from the Extent.
1134: * @param cln The extent to query
1135: * @return The query
1136: */
1137: public synchronized Query newQuery(Extent cln) {
1138: Query query = newQuery();
1139: query.setClass(cln.getCandidateClass());
1140: query.setCandidates(cln);
1141: return query;
1142: }
1143:
1144: /**
1145: * Construct a query instance with the candidate class and candidate
1146: * Collection specified.
1147: * @param cls The class to query
1148: * @param cln The collection
1149: * @return The query
1150: */
1151: public synchronized Query newQuery(Class cls, Collection cln) {
1152: Query query = newQuery();
1153: query.setClass(cls);
1154: query.setCandidates(cln);
1155: return query;
1156: }
1157:
1158: /**
1159: * Construct a query instance with the candidate class and filter specified.
1160: * @param cls The class to query
1161: * @param filter A filter to apply
1162: * @return The query
1163: */
1164: public synchronized Query newQuery(Class cls, String filter) {
1165: Query query = newQuery();
1166: query.setClass(cls);
1167: query.setFilter(filter);
1168: return query;
1169: }
1170:
1171: /**
1172: * Construct a query instance with the candidate class, the candidate
1173: * Collection, and filter specified.
1174: * @param cls The class to query
1175: * @param cln A collection
1176: * @param filter A filter to apply
1177: * @return The query
1178: */
1179: public synchronized Query newQuery(Class cls, Collection cln,
1180: String filter) {
1181: Query query = newQuery();
1182: query.setClass(cls);
1183: query.setCandidates(cln);
1184: query.setFilter(filter);
1185: return query;
1186: }
1187:
1188: /**
1189: * Construct a query instance with the candidate Extent and filter
1190: * specified. The candidate class is taken from the Extent.
1191: * @param cln The extent to query
1192: * @param filter A filter to apply
1193: * @return The query
1194: */
1195: public synchronized Query newQuery(Extent cln, String filter) {
1196: Query query = newQuery();
1197: query.setClass(cln.getCandidateClass());
1198: query.setCandidates(cln);
1199: query.setFilter(filter);
1200: return query;
1201: }
1202:
1203: /**
1204: * Construct a query instance with the candidate class and the query name.
1205: * @param cls The class to query
1206: * @param queryName Name of the query.
1207: * @return The query
1208: */
1209: public synchronized Query newNamedQuery(Class cls, String queryName) {
1210: assertIsOpen();
1211:
1212: // Throw exception on incomplete input
1213: if (queryName == null) {
1214: throw new JDOUserException(LOCALISER.msg("011014",
1215: queryName, cls));
1216: }
1217:
1218: // Find the Query for the specified class
1219: ClassLoaderResolver clr = objectMgr.getClassLoaderResolver();
1220: QueryMetaData qmd = objectMgr.getMetaDataManager()
1221: .getMetaDataForQuery(cls, clr, queryName);
1222: if (qmd == null) {
1223: throw new JDOUserException(LOCALISER.msg("011014",
1224: queryName, cls));
1225: }
1226:
1227: // Create the Query
1228: Query query = newQuery(qmd.getLanguage().toString(), qmd
1229: .getQuery());
1230: if (cls != null) {
1231: query.setClass(cls);
1232: if (!objectMgr.getStoreManager()
1233: .managesClass(cls.getName())) {
1234: // Load the candidate class since not yet managed
1235: objectMgr.getStoreManager()
1236: .addClass(cls.getName(), clr);
1237: }
1238: }
1239:
1240: // Optional args that should only be used with SQL
1241: if (qmd.getLanguage() == QueryLanguage.JDOQL
1242: && (qmd.isUnique() || qmd.getResultClass() != null)) {
1243: throw new JDOUserException(LOCALISER.msg("011017",
1244: queryName));
1245: }
1246: if (qmd.isUnique()) {
1247: query.setUnique(true);
1248: }
1249: if (qmd.getResultClass() != null) {
1250: // Set the result class, allowing for it being in the same package as the candidate
1251: Class resultCls = null;
1252: try {
1253: resultCls = clr.classForName(qmd.getResultClass());
1254: } catch (ClassNotResolvedException cnre) {
1255: try {
1256: String resultClassName = cls.getPackage().getName()
1257: + "." + qmd.getResultClass();
1258: resultCls = clr.classForName(resultClassName);
1259: } catch (ClassNotResolvedException cnre2) {
1260: throw new JDOUserException(LOCALISER.msg("011018",
1261: queryName, qmd.getResultClass()));
1262: }
1263: }
1264: query.setResultClass(resultCls);
1265: }
1266:
1267: // Add any JPOX extensions
1268: if (qmd.getLanguage() == QueryLanguage.JPOXSQL) {
1269: // Apply any imports specified
1270: if (qmd.hasExtension("imports")) {
1271: query.declareImports(qmd
1272: .getValueForExtension("imports"));
1273: }
1274: // Apply any parameters specified
1275: if (qmd.hasExtension("parameters")) {
1276: query.declareParameters(qmd
1277: .getValueForExtension("parameters"));
1278: }
1279: }
1280: if (qmd.isUnmodifiable()) {
1281: query.setUnmodifiable();
1282: }
1283: if (qmd.getFetchPlanName() != null) {
1284: // Apply any named FetchPlan to the query
1285: FetchPlanMetaData fpmd = getObjectManager()
1286: .getMetaDataManager().getMetaDataForFetchPlan(
1287: qmd.getFetchPlanName());
1288: if (fpmd != null) {
1289: org.jpox.FetchPlan fp = new org.jpox.FetchPlan(apmf,
1290: clr);
1291: fp.removeGroup(org.jpox.FetchPlan.DEFAULT);
1292: FetchGroupMetaData[] fgmds = fpmd
1293: .getFetchGroupMetaData();
1294: for (int i = 0; i < fgmds.length; i++) {
1295: fp.addGroup(fgmds[i].getName());
1296: }
1297: fp.setMaxFetchDepth(fpmd.getMaxFetchDepth());
1298: fp.setFetchSize(fpmd.getFetchSize());
1299: JDOQuery jdoquery = (JDOQuery) query;
1300: jdoquery.getInternalQuery().setFetchPlan(fp);
1301: }
1302: }
1303:
1304: return query;
1305: }
1306:
1307: // ------------------------------- Extents ------------------------------------------
1308:
1309: /**
1310: * Extents are collections of datastore objects managed by the datastore,
1311: * not by explicit user operations on collections. Extent capability is a
1312: * boolean property of classes that are persistence capable. If an instance
1313: * of a class that has a managed extent is made persistent via reachability,
1314: * the instance is put into the extent implicitly.
1315: * @param pcClass The class to query
1316: * @param subclasses Whether to include subclasses in the query.
1317: * @return returns an Extent that contains all of the instances in the
1318: * parameter class, and if the subclasses flag is true, all of the instances
1319: * of the parameter class and its subclasses.
1320: */
1321: public synchronized Extent getExtent(Class pcClass,
1322: boolean subclasses) {
1323: return new JDOExtent(this , objectMgr.getExtent(pcClass,
1324: subclasses));
1325: }
1326:
1327: /**
1328: * Extents are collections of datastore objects managed by the datastore,
1329: * not by explicit user operations on collections. Extent capability is a
1330: * boolean property of classes that are persistence capable. If an instance
1331: * of a class that has a managed extent is made persistent via reachability,
1332: * the instance is put into the extent implicitly.
1333: * @param pcClass The class to query
1334: * @return returns an Extent that contains all of the instances in the
1335: * parameter class, and all of the instances of the parameter class and its
1336: * subclasses.
1337: * @since 1.1
1338: */
1339: public synchronized Extent getExtent(Class pcClass) {
1340: return getExtent(pcClass, true);
1341: }
1342:
1343: // ----------------------------- New Instances ----------------------------------
1344:
1345: /**
1346: * Method to generate an instance of an interface, abstract class, or concrete PC class.
1347: * @param persistenceCapable The class of the interface or abstract class, or concrete class defined in MetaData
1348: * @return The instance of this type
1349: */
1350: public Object newInstance(Class persistenceCapable) {
1351: try {
1352: return objectMgr.newInstance(persistenceCapable);
1353: } catch (JPOXException jpe) {
1354: throw JPOXJDOHelper.getJDOExceptionForJPOXException(jpe);
1355: }
1356: }
1357:
1358: /**
1359: * This method returns an object id instance corresponding to the pcClass and key arguments.
1360: * It has 2 modes of operation. Where SingleFieldIdentity is being used the key is the
1361: * value of the key field. For all other cases the key is the String form of the
1362: * object id instance.
1363: * @param pcClass Class of the PersistenceCapable to create the OID for.
1364: * @param key Value of the key for SingleFieldIdentity, or toString() for other cases
1365: * @return The new object-id instance
1366: */
1367: public Object newObjectIdInstance(Class pcClass, Object key) {
1368: try {
1369: return objectMgr.newObjectId(pcClass, key);
1370: } catch (JPOXException jpe) {
1371: return JPOXJDOHelper.getJDOExceptionForJPOXException(jpe);
1372: }
1373: }
1374:
1375: // ----------------------------- Object Retrieval by Id ----------------------------------
1376:
1377: /**
1378: * Accessor for the objects currently managed by this PM in the current transaction.
1379: * @return The managed objects
1380: */
1381: public Set getManagedObjects() {
1382: return objectMgr.getManagedObjects();
1383: }
1384:
1385: /**
1386: * Accessor for the objects currently managed by this PM in the current transaction.
1387: * @param classes Classes that we want objects for
1388: * @return The managed objects
1389: */
1390: public Set getManagedObjects(Class[] classes) {
1391: return objectMgr.getManagedObjects(classes);
1392: }
1393:
1394: /**
1395: * Accessor for the objects currently managed by this PM in the current transaction.
1396: * @param states States that we want objects for
1397: * @return The managed objects
1398: */
1399: public Set getManagedObjects(EnumSet states) {
1400: if (states == null) {
1401: return null;
1402: }
1403:
1404: String[] stateNames = new String[states.size()];
1405: Iterator iter = states.iterator();
1406: int i = 0;
1407: while (iter.hasNext()) {
1408: // Convert to strings to avoid using JDO class in Core
1409: ObjectState state = (ObjectState) iter.next();
1410: stateNames[i++] = state.toString();
1411: }
1412: return objectMgr.getManagedObjects(stateNames);
1413: }
1414:
1415: /**
1416: * Accessor for the objects currently managed by this PM in the current transaction.
1417: * @param states States that we want objects for
1418: * @param classes Classes that we want objects for
1419: * @return The managed objects
1420: */
1421: public Set getManagedObjects(EnumSet states, Class[] classes) {
1422: if (states == null) {
1423: return null;
1424: }
1425:
1426: String[] stateNames = new String[states.size()];
1427: Iterator iter = states.iterator();
1428: int i = 0;
1429: while (iter.hasNext()) {
1430: // Convert to strings to avoid using JDO class in Core
1431: ObjectState state = (ObjectState) iter.next();
1432: stateNames[i++] = state.toString();
1433: }
1434: return objectMgr.getManagedObjects(stateNames, classes);
1435: }
1436:
1437: /**
1438: * Accessor for an object given the object id.
1439: * @param id Id of the object.
1440: * @return The Object
1441: * @since 1.1
1442: */
1443: public synchronized Object getObjectById(Object id) {
1444: return getObjectById(id, true);
1445: }
1446:
1447: /**
1448: * Accessor for an object given the object id.
1449: * @param id Id of the object.
1450: * @param validate Whether to validate the object state
1451: * @return The Object
1452: */
1453: public synchronized Object getObjectById(Object id, boolean validate) {
1454: assertIsOpen();
1455: if (id == null) {
1456: throw new JDOUserException(LOCALISER.msg("011010"));
1457: }
1458:
1459: try {
1460: // Use inheritance checks according to persistence property
1461: // Really we should be able to assume that SingleFieldIdentity and datastore identity cases are
1462: // of the class defined by the identity itself since it contains the class name.
1463: boolean checkInheritance = getObjectManager()
1464: .getOMFContext().getPersistenceConfiguration()
1465: .getFindObjectCheckInheritance();
1466: return objectMgr.findObject(id, validate, checkInheritance,
1467: null);
1468: } catch (JPOXException jpe) {
1469: // Convert any JPOX exceptions into what JDO expects
1470: throw JPOXJDOHelper.getJDOExceptionForJPOXException(jpe);
1471: }
1472: }
1473:
1474: /**
1475: * Accessor for the objects given the object ids.
1476: * @param oids Ids of the objects.
1477: * @param validate Whether to validate the object state
1478: * @return The Objects with these ids (in the same order)
1479: * @since 1.1
1480: */
1481: public Collection getObjectsById(Collection oids, boolean validate) {
1482: assertIsOpen();
1483: if (oids == null || oids.size() == 0) {
1484: throw new JDOUserException(LOCALISER.msg("011011"));
1485: }
1486:
1487: Collection objects = new ArrayList(oids.size());
1488: Iterator iter = oids.iterator();
1489: while (iter.hasNext()) {
1490: Object oid = iter.next();
1491: // Just use getObjectById to get the object
1492: objects.add(getObjectById(oid, validate));
1493: }
1494: return objects;
1495: }
1496:
1497: /**
1498: * Accessor for the objects given the object ids.
1499: * @param validate Whether to validate the object state
1500: * @param oids Ids of the objects.
1501: * @return The Objects with these ids (in the same order)
1502: * @since 1.2
1503: */
1504: public Object[] getObjectsById(boolean validate, Object[] oids) {
1505: return getObjectsById(oids, validate);
1506: }
1507:
1508: /**
1509: * Accessor for the objects given the object ids.
1510: * @param oids Ids of the objects.
1511: * @param validate Whether to validate the object state
1512: * @return The Objects with these ids (in the same order)
1513: * @since 1.1
1514: */
1515: public Object[] getObjectsById(Object[] oids, boolean validate) {
1516: assertIsOpen();
1517: if (oids == null) {
1518: throw new JDOUserException(LOCALISER.msg("011011"));
1519: }
1520: Object[] objects = new Object[oids.length];
1521: for (int i = 0; i < oids.length; i++) {
1522: // Just use getObjectById to get the object
1523: objects[i] = getObjectById(oids[i], validate);
1524: }
1525: return objects;
1526: }
1527:
1528: /**
1529: * Accessor for the objects given the object ids, validating the objects.
1530: * @param oids Ids of the objects.
1531: * @return The Objects with these ids (in the same order)
1532: * @since 1.1
1533: */
1534: public Collection getObjectsById(Collection oids) {
1535: return getObjectsById(oids, true);
1536: }
1537:
1538: /**
1539: * Accessor for the objects given the object ids, validating the objects.
1540: * @param oids Ids of the objects.
1541: * @return The Objects with these ids (in the same order)
1542: * @since 1.1
1543: */
1544: public Object[] getObjectsById(Object[] oids) {
1545: return getObjectsById(oids, true);
1546: }
1547:
1548: /**
1549: * Convenience method that exactly matches the behavior of calling
1550: * pm.getObjectById (pm.newObjectIdInstance (cls, key), true).
1551: * @param cls Class of the PersistenceCapable
1552: * @param key Value of the key field for SingleFieldIdentity, or the string value of the key otherwise
1553: * @return The object for this id.
1554: * @since 1.1
1555: */
1556: public Object getObjectById(Class cls, Object key) {
1557: return getObjectById(newObjectIdInstance(cls, key), true);
1558: }
1559:
1560: /**
1561: * Accessor for an object id given the object.
1562: * @param pc The object
1563: * @return The Object id
1564: */
1565: public Object getObjectId(Object pc) {
1566: assertIsOpen();
1567: if (pc != null && pc instanceof PersistenceCapable) {
1568: PersistenceCapable p = (PersistenceCapable) pc;
1569: if (p.jdoIsPersistent() || p.jdoIsDetached()) {
1570: return p.jdoGetObjectId();
1571: }
1572: }
1573: return null;
1574: }
1575:
1576: /**
1577: * Accessor for the object id of a transactional object given the object.
1578: * @param pc The object
1579: * @return The Object id
1580: */
1581: public Object getTransactionalObjectId(Object pc) {
1582: assertIsOpen();
1583: return ((PersistenceCapable) pc).jdoGetTransactionalObjectId();
1584: }
1585:
1586: /**
1587: * Accessor for the class of the object id given the class of object.
1588: * @param cls The class name of the object
1589: * @return The class name of the object id
1590: */
1591: public Class getObjectIdClass(Class cls) {
1592: assertIsOpen();
1593: if (!getObjectManager().getOMFContext().getApiAdapter()
1594: .isPersistable(cls)
1595: || !hasPersistenceInformationForClass(cls)) {
1596: return null;
1597: }
1598:
1599: ClassLoaderResolver clr = objectMgr.getClassLoaderResolver();
1600: AbstractClassMetaData cmd = objectMgr.getMetaDataManager()
1601: .getMetaDataForClass(cls, clr);
1602: if (cmd.getIdentityType() == IdentityType.DATASTORE) {
1603: return objectMgr.getOMFContext()
1604: .getDatastoreIdentityClass();
1605: } else if (cmd.getIdentityType() == IdentityType.APPLICATION) {
1606: try {
1607: return this .objectMgr.getClassLoaderResolver()
1608: .classForName(
1609: objectMgr.getMetaDataManager()
1610: .getMetaDataForClass(cls, clr)
1611: .getObjectidClass(), null);
1612: } catch (ClassNotResolvedException e) {
1613: String msg = LOCALISER.msg("011019", cls.getName());
1614: JPOXLogger.JDO.error(msg);
1615: throw new JDOException(msg);
1616: }
1617: } else {
1618: if (cmd.isRequiresExtent()) {
1619: return objectMgr.getOMFContext()
1620: .getDatastoreIdentityClass();
1621: } else {
1622: return SCOID.class;
1623: }
1624: }
1625: }
1626:
1627: // ------------------------------------ User Objects -----------------------------------
1628:
1629: /**
1630: * Method to put a user object into the PersistenceManager. This is so that
1631: * multiple users can each have a user object for example. <I>The parameter
1632: * is not inspected or used in any way by the JDO implementation. </I>
1633: * @param key The key to store the user object under
1634: * @param value The object to store
1635: * @return The previous value for this key
1636: * @since 1.1
1637: */
1638: public synchronized Object putUserObject(Object key, Object value) {
1639: assertIsOpen();
1640: if (key == null) {
1641: return null;
1642: }
1643: if (userObjectMap == null) {
1644: userObjectMap = new HashMap();
1645: }
1646: if (value == null) {
1647: // Remove the object
1648: return userObjectMap.remove(key);
1649: } else {
1650: // Put the object
1651: return userObjectMap.put(key, value);
1652: }
1653: }
1654:
1655: /**
1656: * Method to get a user object from the PersistenceManager. This is for user
1657: * objects which are stored under a key. <I>The parameter is not inspected
1658: * or used in any way by the JDO implementation. </I>
1659: * @param key The key to store the user object under
1660: * @return The user object for that key
1661: * @since 1.1
1662: */
1663: public synchronized Object getUserObject(Object key) {
1664: assertIsOpen();
1665: if (key == null) {
1666: return null;
1667: }
1668: if (userObjectMap == null) {
1669: return null;
1670: }
1671: return userObjectMap.get(key);
1672: }
1673:
1674: /**
1675: * Method to remove a user object from the PersistenceManager. This is for
1676: * user objects which are stored under a key. <I>The parameter is not
1677: * inspected or used in any way by the JDO implementation. </I>
1678: * @param key The key whose uder object is to be removed.
1679: * @return The user object that was removed
1680: * @since 1.1
1681: */
1682: public synchronized Object removeUserObject(Object key) {
1683: assertIsOpen();
1684: if (key == null) {
1685: return null;
1686: }
1687: if (userObjectMap == null) {
1688: return null;
1689: }
1690: return userObjectMap.remove(key);
1691: }
1692:
1693: /**
1694: * The application might manage PersistenceManager instances by using an
1695: * associated object for bookkeeping purposes. These methods allow the user
1696: * to manage the associated object. <I>The parameter is not inspected or
1697: * used in any way by the JDO implementation. </I>
1698: * @param userObject The object
1699: */
1700: public synchronized void setUserObject(Object userObject) {
1701: assertIsOpen();
1702: this .userObject = userObject;
1703: }
1704:
1705: /**
1706: * The application might manage PersistenceManager instances by using an
1707: * associated object for bookkeeping purposes. These methods allow the user
1708: * to manage the associated object. <I>The parameter is not inspected or
1709: * used in any way by the JDO implementation. </I>
1710: * @return The user object
1711: */
1712: public synchronized Object getUserObject() {
1713: assertIsOpen();
1714: return userObject;
1715: }
1716:
1717: /**
1718: * This method flushes all dirty, new, and deleted instances to the
1719: * datastore. It has no effect if a transaction is not active. If a
1720: * datastore transaction is active, this method synchronizes the cache with
1721: * the datastore and reports any exceptions. If an optimistic transaction is
1722: * active, this method obtains a datastore connection and synchronizes the
1723: * cache with the datastore using this connection. The connection obtained
1724: * by this method is held until the end of the transaction.
1725: */
1726: public synchronized void flush() {
1727: try {
1728: // Flush all changes to the datastore without letting the store manager hold back
1729: objectMgr.flush();
1730: } catch (JPOXException jpe) {
1731: if (jpe instanceof JPOXOptimisticException) {
1732: // Optimistic exceptions so convert all nested into JDOOptimisticVerificationException and return as single
1733: Throwable[] nested = jpe.getNestedExceptions();
1734: JDOOptimisticVerificationException[] jdoNested = new JDOOptimisticVerificationException[nested.length];
1735: for (int i = 0; i < nested.length; i++) {
1736: jdoNested[i] = (JDOOptimisticVerificationException) JPOXJDOHelper
1737: .getJDOExceptionForJPOXException((JPOXException) nested[i]);
1738: }
1739: throw new JDOOptimisticVerificationException(jpe
1740: .getMessage(), jdoNested);
1741: } else {
1742: // Convert any JPOX exceptions into what JDO expects
1743: throw JPOXJDOHelper
1744: .getJDOExceptionForJPOXException(jpe);
1745: }
1746: }
1747: }
1748:
1749: /**
1750: * This method validates the cache with the datastore. It has no effect if a transaction
1751: * is not active. If a datastore transaction is active, this method verifies the consistency
1752: * of instances in the cache against the datastore. An implementation might flush instances
1753: * as if flush() were called, but it is not required to do so.
1754: * If an optimistic transaction is active, this method obtains a datastore connection
1755: * and verifies the consistency of the instances in the cache against the datastore. If any
1756: * inconsistencies are detected, a JDOOptimisticVerificationException is thrown. This
1757: * exception contains a nested JDOOptimisticVerificationException for each object
1758: * that failed the consistency check. No datastore resources acquired during the execution
1759: * of this method are held beyond the scope of this method.
1760: */
1761: public void checkConsistency() {
1762: assertIsOpen();
1763:
1764: // If transaction is not active do nothing
1765: if (!objectMgr.getTransaction().isActive()) {
1766: return;
1767: }
1768:
1769: if (objectMgr.getTransaction().getOptimistic()) {
1770: // TODO Implement checkConsistency() for optimistic transactions
1771: throw new JDOUserException(
1772: "checkConsistency() not yet implemented for optimistic transactions");
1773: } else {
1774: flush();
1775: }
1776: }
1777:
1778: // ------------------------------------- Sequence Management --------------------------------------
1779:
1780: /**
1781: * Method to retrieve a sequence by name. As per JDO2 spec section 12.14.
1782: * If the named sequence is not known, throws a JDOUserException.
1783: * @param sequenceName Fully qualified name of the sequence
1784: * @return The sequence
1785: */
1786: public Sequence getSequence(String sequenceName) {
1787: assertIsOpen();
1788:
1789: SequenceMetaData seqmd = objectMgr.getMetaDataManager()
1790: .getMetaDataForSequence(
1791: objectMgr.getClassLoaderResolver(),
1792: sequenceName);
1793: if (seqmd == null) {
1794: throw new JDOUserException(LOCALISER.msg("017000",
1795: sequenceName));
1796: }
1797:
1798: Sequence seq = null;
1799: if (seqmd.getFactoryClass() != null) {
1800: // User has specified a factory class
1801: seq = getAbstractPersistenceManagerFactory()
1802: .getSequenceForFactoryClass(seqmd.getFactoryClass());
1803: if (seq == null) {
1804: // Create a new instance of the factory class and obtain the Sequence
1805: Class factory = objectMgr.getClassLoaderResolver()
1806: .classForName(seqmd.getFactoryClass());
1807: if (factory == null) {
1808: throw new JDOUserException(LOCALISER.msg("017001",
1809: sequenceName, seqmd.getFactoryClass()));
1810: }
1811:
1812: Class[] argTypes = null;
1813: Object[] arguments = null;
1814: if (seqmd.getStrategy() != null) {
1815: argTypes = new Class[2];
1816: argTypes[0] = String.class;
1817: argTypes[1] = String.class;
1818: arguments = new Object[2];
1819: arguments[0] = seqmd.getName();
1820: arguments[1] = seqmd.getStrategy().toString();
1821: } else {
1822: argTypes = new Class[1];
1823: argTypes[0] = String.class;
1824: arguments = new Object[1];
1825: arguments[0] = seqmd.getName();
1826: }
1827:
1828: Method newInstanceMethod;
1829: try {
1830: // Obtain the sequence from the static "newInstance(...)" method
1831: newInstanceMethod = factory.getMethod(
1832: "newInstance", argTypes);
1833: seq = (Sequence) newInstanceMethod.invoke(null,
1834: arguments);
1835: } catch (Exception e) {
1836: throw new JDOUserException(LOCALISER.msg("017002",
1837: seqmd.getFactoryClass(), e.getMessage()));
1838: }
1839:
1840: // Register the sequence with the PMF
1841: getAbstractPersistenceManagerFactory()
1842: .addSequenceForFactoryClass(
1843: seqmd.getFactoryClass(), seq);
1844: }
1845: } else {
1846: seq = (Sequence) objectMgr.getStoreManager()
1847: .getJPOXSequence(objectMgr, seqmd);
1848: }
1849: return seq;
1850: }
1851:
1852: // ------------------------------------- Lifecycle Listeners --------------------------------------
1853:
1854: /**
1855: * Method to register a lifecycle listener as per JDO 2.0 spec 12.15.
1856: * @param listener The instance lifecycle listener to sends events to
1857: * @param classes The classes that it is interested in
1858: * @since 1.1
1859: */
1860: public void addInstanceLifecycleListener(
1861: InstanceLifecycleListener listener, Class[] classes) {
1862: objectMgr.addListener(listener, classes);
1863: }
1864:
1865: /**
1866: * Method to remove a currently registered lifecycle listener, as per JDO 2.0 spec 12.15.
1867: * @param listener The instance lifecycle listener to remove.
1868: * @since 1.1
1869: */
1870: public void removeInstanceLifecycleListener(
1871: InstanceLifecycleListener listener) {
1872: objectMgr.removeListener(listener);
1873: }
1874:
1875: // -------------------------------------- Utility methods ----------------------------------------
1876:
1877: /**
1878: * Method to assert if this Persistence Manager is open.
1879: * @throws JDOFatalUserException if the PM is closed.
1880: */
1881: protected void assertIsOpen() {
1882: if (isClosed()) {
1883: throw new JDOFatalUserException(LOCALISER.msg("011000"));
1884: }
1885: }
1886:
1887: /**
1888: * Method to assert if the current transaction is active.
1889: * Throws a TransactionNotActiveException if not active.
1890: */
1891: protected void assertActiveTransaction() {
1892: if (!objectMgr.getTransaction().isActive()) {
1893: throw new TransactionNotActiveException();
1894: }
1895: }
1896:
1897: /**
1898: * Method to assert if the current transaction is active or non transactional writes are allowed.
1899: * @throws a TransactionNotActiveException if not active and non transactional writes are disabled
1900: */
1901: protected void assertWritable() {
1902: if (!objectMgr.getTransaction().isActive()
1903: && !objectMgr.getTransaction()
1904: .getNontransactionalWrite()) {
1905: throw new TransactionNotActiveException();
1906: }
1907: }
1908:
1909: /**
1910: * Method to assert if no active transaction and nontransactionalRead is not set.
1911: * @throws JDOUserException if the tx is not active and no non-transactional read is available
1912: */
1913: protected void assertReadable(String operation) {
1914: if (!objectMgr.getTransaction().isActive()
1915: && !objectMgr.getTransaction()
1916: .getNontransactionalRead()) {
1917: throw new JDOUserException(LOCALISER.msg("011009",
1918: operation));
1919: }
1920: }
1921:
1922: /**
1923: * Utility method to check if the specified class has reachable metadata/annotations.
1924: * @param cls The class to check
1925: * @return Whether the class has reachable metadata/annotations.
1926: */
1927: protected boolean hasPersistenceInformationForClass(Class cls) {
1928: return objectMgr.hasPersistenceInformationForClass(cls);
1929: }
1930:
1931: /**
1932: * Accessor for a connection on the datastore. See JDO 2.0 spec section 12.16
1933: * @return The JDO connection to the datastore
1934: * @see javax.jdo.PersistenceManager#getDataStoreConnection()
1935: * @since 1.1
1936: */
1937: public JDOConnection getDataStoreConnection() {
1938: try {
1939: return (JDOConnection) objectMgr.getStoreManager()
1940: .getJPOXConnection(objectMgr);
1941: } catch (JPOXException jpe) {
1942: throw JPOXJDOHelper.getJDOExceptionForJPOXException(jpe);
1943: }
1944: }
1945: }
|