0001: /*
0002: $Header: /cvsroot/xorm/xorm/src/org/xorm/InterfaceManager.java,v 1.80 2004/05/19 19:58:57 wbiggs Exp $
0003:
0004: This file is part of XORM.
0005:
0006: XORM is free software; you can redistribute it and/or modify
0007: it under the terms of the GNU General Public License as published by
0008: the Free Software Foundation; either version 2 of the License, or
0009: (at your option) any later version.
0010:
0011: XORM is distributed in the hope that it will be useful,
0012: but WITHOUT ANY WARRANTY; without even the implied warranty of
0013: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
0014: GNU General Public License for more details.
0015:
0016: You should have received a copy of the GNU General Public License
0017: along with XORM; if not, write to the Free Software
0018: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0019: */
0020: package org.xorm;
0021:
0022: import java.util.ArrayList;
0023: import java.util.Collection;
0024: import java.util.Set;
0025: import java.util.HashSet;
0026: import java.util.Map;
0027: import java.util.Iterator;
0028: import java.util.WeakHashMap;
0029: import java.util.logging.Level;
0030: import java.util.logging.Logger;
0031:
0032: import org.xorm.cache.DataCache;
0033: import org.xorm.datastore.Column;
0034: import org.xorm.datastore.Row;
0035: import org.xorm.datastore.Table;
0036: import org.xorm.datastore.DataFetchGroup;
0037: import org.xorm.datastore.DatastoreDriver;
0038: import org.xorm.datastore.DriverException;
0039:
0040: import org.xorm.query.CodeParser;
0041: import org.xorm.query.CodeQuery;
0042: import org.xorm.query.DataQuery;
0043: import org.xorm.query.Operator;
0044: import org.xorm.query.QueryImpl;
0045: import org.xorm.query.QueryLanguage;
0046: import org.xorm.query.Selector;
0047: import org.xorm.query.SimpleCondition;
0048:
0049: import org.xorm.util.TypeConverter;
0050:
0051: import javax.jdo.Extent;
0052: import javax.jdo.InstanceCallbacks;
0053: import javax.jdo.PersistenceManager;
0054: import javax.jdo.PersistenceManagerFactory;
0055: import javax.jdo.Query;
0056: import javax.jdo.Transaction;
0057: import javax.jdo.JDODataStoreException;
0058: import javax.jdo.JDOFatalUserException;
0059: import javax.jdo.spi.JDOImplHelper;
0060: import javax.jdo.JDOObjectNotFoundException;
0061: import javax.jdo.JDOUserException;
0062: import javax.jdo.spi.PersistenceCapable;
0063:
0064: import net.sf.cglib.Enhancer;
0065: import net.sf.cglib.Factory;
0066:
0067: // TODO: make InterfaceManager have to know less about status codes of
0068: // InterfaceInvocationHandler
0069:
0070: /**
0071: * Roughly equivalent to JDO PersistenceManager. Developers should
0072: * always acquire an InterfaceManager as a
0073: * javax.jdo.PersistenceManager. The implementation details are
0074: * transparent to the use of the API. To use additional XORM
0075: * features, the org.xorm.XORM static methods are provided.
0076: */
0077: class InterfaceManager implements PersistenceManager, I15d {
0078: private static Logger logger = Logger.getLogger("org.xorm");
0079: private static final String JDOQL_LANGUAGE = "javax.jdo.query.JDOQL";
0080:
0081: private InterfaceManagerFactory factory;
0082: private Object transaction;
0083: private Object userObject;
0084: private boolean closed;
0085: private boolean multithreaded;
0086: private boolean ignoreCache;
0087:
0088: //need to hold onto this now to make transactions for the thread local case
0089: private Options jdoOptions;
0090:
0091: /**
0092: * Creates a new InterfaceManager. This method is called from the
0093: * InterfaceManagerFactory.
0094: */
0095: InterfaceManager(final InterfaceManagerFactory factory,
0096: final Options jdoOptions) {
0097: this .factory = factory;
0098: // Depending on option
0099: if (!factory.useThreadLocalTransactions()) {
0100: this .transaction = new TransactionImpl(this , factory
0101: .newDatastoreDriver(), jdoOptions);
0102: } else {
0103: this .jdoOptions = jdoOptions;
0104: this .transaction = new WeakHashMap();
0105: }
0106: }
0107:
0108: /**
0109: * Helper method that is called by all PersistenceManager
0110: * interface methods.
0111: */
0112: private void assertNotClosed() {
0113: if (closed) {
0114: throw new JDOFatalUserException(I18N.msg("E_PM_closed"));
0115: }
0116: }
0117:
0118: InterfaceManagerFactory getInterfaceManagerFactory() {
0119: return factory;
0120: }
0121:
0122: public PersistenceManagerFactory getPersistenceManagerFactory() {
0123: assertNotClosed();
0124: return factory;
0125: }
0126:
0127: /**
0128: * Returns the transaction associated with this InterfaceManager.
0129: * Merely retrieving the transaction does not change its state;
0130: * you must call begin(), commit(), etc.
0131: */
0132: public Transaction currentTransaction() {
0133: assertNotClosed();
0134:
0135: // Give users the option to use thread-local transactions
0136: // with a single PersistenceManager.
0137: Transaction txn = null;
0138: if (transaction instanceof WeakHashMap) {
0139: WeakHashMap threadTransactionMap = (WeakHashMap) transaction;
0140: Thread currentThread = Thread.currentThread();
0141: synchronized (threadTransactionMap) {
0142: txn = (Transaction) threadTransactionMap
0143: .get(currentThread);
0144: if (txn == null) {
0145: txn = new TransactionImpl(this , factory
0146: .newDatastoreDriver(), jdoOptions);
0147: threadTransactionMap.put(currentThread, txn);
0148: }
0149: }
0150: } else {
0151: txn = (Transaction) transaction;
0152: }
0153: return txn;
0154: }
0155:
0156: public Object getObjectById(Object object, boolean validate) {
0157: assertNotClosed();
0158: if (object instanceof ObjectId) {
0159: ObjectId objectId = (ObjectId) object;
0160: Class mappedClass = objectId.mappedClass;
0161: Object id = objectId.id;
0162:
0163: // Munge id if necessary
0164: ClassMapping mapping = factory.getModelMapping()
0165: .getClassMapping(mappedClass);
0166: Class datastoreClass = mapping.getDatastoreIdentityType();
0167: if (datastoreClass != null) {
0168: id = TypeConverter.convertToType(id, datastoreClass);
0169: }
0170: Object out = lookup(mapping, id);
0171:
0172: // If validate is set, transition the object from hollow:
0173: if (validate) {
0174: InterfaceInvocationHandler handler = InterfaceInvocationHandler
0175: .getHandler(out);
0176: handler.refresh(this );
0177: }
0178: return out;
0179: }
0180: throw new JDOUserException(I18N.msg("E_no_object_id"));
0181: }
0182:
0183: /**
0184: * Retrieves an object from the cache or from persistent storage
0185: * that is of the given type and has the matching object ID.
0186: * Called from getObjectById and from RelationshipProxy.iterator()
0187: */
0188: Object lookup(Class clazz, Object primaryKey) {
0189: ClassMapping classMapping = factory.getModelMapping()
0190: .getClassMapping(clazz);
0191: if (classMapping == null) {
0192: throw new JDOUserException(I18N.msg("E_no_class_mapping",
0193: clazz));
0194: }
0195: return lookup(classMapping, primaryKey);
0196: }
0197:
0198: // package-scope; used for performance reasons from InterfaceInvocationHandler when mapping is known
0199: /**
0200: * This is the primary method by which an object is acquired.
0201: * This method may return a hollow object that has not been validated.
0202: * Called from lookup(Class, Object) and from InterfaceInvocationHandler
0203: * .invokeGet().
0204: */
0205: Object lookup(ClassMapping classMapping, Object primaryKey) {
0206: // 1. Look in transactional scope
0207: TransactionImpl txn = (TransactionImpl) currentTransaction();
0208: useNontransactionalRead(); // asserts that there is an active transaction or nontransactional read is supported
0209: Object proxy = txn.get(classMapping.getMappedClass(),
0210: primaryKey);
0211: if (proxy != null)
0212: return proxy;
0213:
0214: // Try lookup in cache and datastore if non-transient
0215: if (primaryKey instanceof TransientKey) {
0216: return null;
0217: }
0218:
0219: // Return hollow object
0220: Row row = new Row(classMapping.getTable(), primaryKey);
0221: proxy = rowToProxy(classMapping, row);
0222: return proxy;
0223: }
0224:
0225: /**
0226: * Create a proxy instance representing a particular row in the datastore.
0227: */
0228: private Object rowToProxy(ClassMapping classMapping, Row row) {
0229: TransactionImpl txn = (TransactionImpl) currentTransaction();
0230: Object proxy = null;
0231:
0232: // Avoid two copies of the same object
0233: if (txn.isActive()) {
0234: proxy = txn.get(classMapping.getMappedClass(), row
0235: .getPrimaryKeyValue());
0236: }
0237: if (proxy == null) {
0238: InterfaceInvocationHandler handler = new InterfaceInvocationHandler(
0239: factory, classMapping, row);
0240: proxy = handler.newProxy();
0241: handler.enterTransaction(txn);
0242: }
0243: return proxy;
0244: }
0245:
0246: /**
0247: * Returns true if a nontransactional read should be performed.
0248: * If nontransactional read is not supported, but no transaction
0249: * is in progress, throws an exception.
0250: */
0251: private boolean useNontransactionalRead() {
0252: TransactionImpl txn = (TransactionImpl) currentTransaction();
0253: if (!txn.isActive()) {
0254: if (factory.getNontransactionalRead()) {
0255: return true;
0256: } else {
0257: throw new UnsupportedOperationException(I18N
0258: .msg("E_no_txn"));
0259: }
0260: }
0261: return false;
0262: }
0263:
0264: void addToCache(Row row) {
0265: DataCache cache = factory.getCache();
0266: if (cache != null) {
0267: // Don't need to clone anymore...cached flag instead
0268: //cache.add((Row) row.clone());
0269: cache.add(row);
0270: }
0271: }
0272:
0273: void addToCache(Collection rows) {
0274: DataCache cache = factory.getCache();
0275: if (cache != null) {
0276: Iterator i = rows.iterator();
0277: while (i.hasNext()) {
0278: Row row = (Row) i.next();
0279: // Don't need to clone anymore...cached flag instead
0280: //cache.add((Row) row.clone());
0281: cache.add(row);
0282: }
0283: }
0284: }
0285:
0286: Row getFromCache(Table table, Object primaryKey) {
0287: DataCache cache = factory.getCache();
0288: if (cache != null) {
0289: Row row = cache.get(table, primaryKey);
0290: return row;
0291: } else {
0292: return null;
0293: }
0294: }
0295:
0296: void removeFromCache(Row row) {
0297: DataCache cache = factory.getCache();
0298: if (cache != null) {
0299: cache.remove(row);
0300: }
0301: }
0302:
0303: /**
0304: * Retrieve a datastore row given its primary key.
0305: * This method first checks the local cache, then calls
0306: * DatastoreDriver.read(). If no matching row is found,
0307: * JDOObjectNotFoundException is thrown. Called from lookup() and from
0308: * InterfaceInvocationHandler.refresh().
0309: */
0310: Row lookupRow(ClassMapping classMapping, Object primaryKey) {
0311: Table table = classMapping.getTable();
0312:
0313: boolean useNontrans = useNontransactionalRead();
0314:
0315: // 1. Look in cache
0316: Row row = getFromCache(table, primaryKey);
0317: if (row == null) {
0318:
0319: // 2. Look in datastore
0320:
0321: // Get the DataFetchGroup to use.
0322: DataFetchGroup dfg = factory.getFetchGroupManager()
0323: .getDataFetchGroup(classMapping);
0324: Selector selector = new Selector(table,
0325: new SimpleCondition(table.getPrimaryKey(),
0326: Operator.EQUAL, primaryKey));
0327: selector.require(dfg);
0328: Collection rows = selectRows(selector);
0329: if (!rows.isEmpty()) {
0330: row = (Row) rows.iterator().next();
0331: } else {
0332: throw new JDOObjectNotFoundException();
0333: }
0334: }
0335: return row;
0336: }
0337:
0338: /**
0339: * Refreshes particular fields of a Row from the datastore.
0340: * This method does not affect the cache.
0341: */
0342: void refreshColumns(Row row, DataFetchGroup dfg) {
0343: Table table = row.getTable();
0344: boolean useNontrans = useNontransactionalRead();
0345:
0346: Collection rows = null;
0347: try {
0348: if (useNontrans) {
0349: ((TransactionImpl) currentTransaction()).begin(true);
0350: }
0351: Object primaryKey = row.getPrimaryKeyValue();
0352: Selector selector = new Selector(table,
0353: new SimpleCondition(table.getPrimaryKey(),
0354: Operator.EQUAL, primaryKey));
0355: selector.require(dfg);
0356: Set extraRows = new HashSet();
0357: rows = ((TransactionImpl) currentTransaction()).getDriver()
0358: .select(selector, extraRows);
0359: if (!rows.isEmpty()) {
0360: Row newFields = (Row) rows.iterator().next();
0361: // Determine which fields to copy
0362: Iterator i = dfg.getColumns().iterator();
0363: while (i.hasNext()) {
0364: Column c = (Column) i.next();
0365: row.setValue(c, newFields.getValue(c));
0366: }
0367: } else {
0368: throw new JDODataStoreException(I18N
0369: .msg("E_row_deleted"));
0370: }
0371: } catch (DriverException e) {
0372: throw new JDODataStoreException(I18N.msg("E_query_failed"),
0373: e);
0374: } finally {
0375: if (useNontrans) {
0376: currentTransaction().commit();
0377: }
0378: }
0379: }
0380:
0381: /**
0382: * Attempts to identify the primaryKey for the object.
0383: * Returns null if the object is not PersistenceCapable.
0384: */
0385: public Object getObjectId(Object object) {
0386: assertNotClosed();
0387: // TODO according to JDO spec, instanceof PersistenceCapable
0388: // is not sufficient
0389: if (!(object instanceof PersistenceCapable))
0390: return null;
0391: return ((PersistenceCapable) object).jdoGetObjectId();
0392: }
0393:
0394: /**
0395: * Marks an object as persistent so it may be saved to the datastore.
0396: */
0397: public void makePersistent(Object object) {
0398: assertNotClosed();
0399: if (!currentTransaction().isActive()) {
0400: throw new JDOUserException(I18N.msg("E_no_txn"));
0401: }
0402: PersistenceCapable pc = (PersistenceCapable) object;
0403: ObjectState handler = getObjectState(object);
0404: if (handler instanceof InterfaceInvocationHandler) {
0405: // XORM-specific case
0406: ((InterfaceInvocationHandler) handler).makePersistent(this );
0407: } else {
0408: PersistenceManager mgr = pc.jdoGetPersistenceManager();
0409: if (mgr != null) {
0410: if (mgr == this )
0411: return; // already managed
0412: else
0413: throw new JDOUserException(I18N.msg("E_wrong_PM"));
0414: }
0415: // Standard JDO object, make a StateManager for it
0416: handler.setPersistent(true);
0417: handler.setNew(true);
0418: // TODO THIS IS NOT FULLY IMPLEMENTED
0419: }
0420: }
0421:
0422: /**
0423: * Marks all items within a collection of objects as persistent.
0424: */
0425: public void makePersistentAll(Collection collection) {
0426: assertNotClosed();
0427: Iterator i = collection.iterator();
0428: while (i.hasNext()) {
0429: makePersistent(i.next());
0430: }
0431: }
0432:
0433: /**
0434: * Marks all items within an array of objects as persistent.
0435: */
0436: public void makePersistentAll(Object[] array) {
0437: assertNotClosed();
0438: for (int i = 0; i < array.length; i++) {
0439: makePersistent(array[i]);
0440: }
0441: }
0442:
0443: /**
0444: * The incoming object may be an instance of either a
0445: * reference-enhanced JDO class or a dynamically enhanced
0446: * cglib-generated class.
0447: */
0448: ObjectState getObjectState(Object object) {
0449: if (object instanceof Factory) {
0450: return (ObjectState) Enhancer.getMethodInterceptor(object);
0451: }
0452: // TODO instanceof check not sufficient
0453: if (object instanceof PersistenceCapable) {
0454: // look it up in hash of managed objects
0455: return StateManagerImpl.forPersistenceCapable(
0456: (PersistenceCapable) object, this );
0457: }
0458: return null;
0459: }
0460:
0461: // TODO incomplete
0462: public void makeTransactional(Object object) {
0463: assertNotClosed();
0464: ObjectState handler = getObjectState(object);
0465: if (handler instanceof InterfaceInvocationHandler) {
0466: ((InterfaceInvocationHandler) handler)
0467: .makeTransactional(this );
0468: }
0469: }
0470:
0471: public void makeTransactionalAll(Collection collection) {
0472: assertNotClosed();
0473: Iterator i = collection.iterator();
0474: while (i.hasNext()) {
0475: makeTransactional(i.next());
0476: }
0477: }
0478:
0479: public void makeTransactionalAll(Object[] array) {
0480: assertNotClosed();
0481: for (int i = 0; i < array.length; i++) {
0482: makeTransactional(array[i]);
0483: }
0484: }
0485:
0486: // TODO incomplete
0487: public void makeNontransactional(Object object) {
0488: assertNotClosed();
0489: TransactionImpl txn = (TransactionImpl) currentTransaction();
0490: if (txn.contains(object)) {
0491: txn.detach(object);
0492: }
0493: ObjectState handler = getObjectState(object);
0494: if (handler.isPersistent()) {
0495: handler
0496: .setStatus(handler.STATUS_PERSISTENT_NONTRANSACTIONAL);
0497: } else {
0498: handler.setStatus(handler.STATUS_TRANSIENT);
0499: }
0500: }
0501:
0502: public void makeNontransactionalAll(Collection collection) {
0503: assertNotClosed();
0504: Iterator i = collection.iterator();
0505: while (i.hasNext()) {
0506: makeNontransactional(i.next());
0507: }
0508: }
0509:
0510: public void makeNontransactionalAll(Object[] array) {
0511: assertNotClosed();
0512: for (int i = 0; i < array.length; i++) {
0513: makeNontransactional(array[i]);
0514: }
0515: }
0516:
0517: // TODO incomplete
0518: public void makeTransient(Object object) {
0519: assertNotClosed();
0520: TransactionImpl txn = (TransactionImpl) currentTransaction();
0521: if (!txn.contains(object)) {
0522: txn.attach(object);
0523: }
0524: ObjectState handler = getObjectState(object);
0525: handler.setStatus(handler.STATUS_TRANSIENT);
0526: }
0527:
0528: public void makeTransientAll(Collection collection) {
0529: assertNotClosed();
0530: Iterator i = collection.iterator();
0531: while (i.hasNext()) {
0532: makeTransient(i.next());
0533: }
0534: }
0535:
0536: public void makeTransientAll(Object[] array) {
0537: assertNotClosed();
0538: for (int i = 0; i < array.length; i++) {
0539: makeTransient(array[i]);
0540: }
0541: }
0542:
0543: public void deletePersistent(Object object) {
0544: assertNotClosed();
0545: InterfaceInvocationHandler handler = InterfaceInvocationHandler
0546: .getHandler(object);
0547: if (!handler.isPersistent()) {
0548: throw new JDOUserException(I18N
0549: .msg("E_delete_nonpersistent"));
0550: }
0551: if (this != handler.getInterfaceManager()) {
0552: throw new JDOUserException(I18N.msg("E_wrong_PM"));
0553: }
0554: TransactionImpl txn = (TransactionImpl) currentTransaction();
0555: if (!txn.contains(object)) {
0556: handler.enterTransaction(txn);
0557: }
0558: switch (handler.getStatus()) {
0559: case ObjectState.STATUS_PERSISTENT_NEW:
0560: if (object instanceof InstanceCallbacks) {
0561: ((InstanceCallbacks) object).jdoPreDelete();
0562: }
0563: handler.setStatus(handler.STATUS_PERSISTENT_NEW_DELETED);
0564: break;
0565: case ObjectState.STATUS_PERSISTENT_CLEAN:
0566: case ObjectState.STATUS_HOLLOW:
0567: case ObjectState.STATUS_PERSISTENT_NONTRANSACTIONAL:
0568: if (object instanceof InstanceCallbacks) {
0569: ((InstanceCallbacks) object).jdoPreDelete();
0570: }
0571: handler.setStatus(handler.STATUS_PERSISTENT_DELETED);
0572: break;
0573: }
0574: }
0575:
0576: public void deletePersistentAll(Collection collection) {
0577: assertNotClosed();
0578: Iterator i = collection.iterator();
0579: while (i.hasNext()) {
0580: deletePersistent(i.next());
0581: }
0582: }
0583:
0584: public void deletePersistentAll(Object[] array) {
0585: assertNotClosed();
0586: for (int i = 0; i < array.length; i++) {
0587: deletePersistent(array[i]);
0588: }
0589: }
0590:
0591: /**
0592: * Selects the rows from the datastore matching the selection criteria.
0593: * If no transaction is in progress, but nontransactionalRead is enabled,
0594: * begins and ends a datastore transaction in order to perform the
0595: * query. Before returning the collection of rows, this method adds
0596: * the query results and any extra rows read by the driver to the cache.
0597: */
0598: Collection selectRows(Selector selector) {
0599: boolean useNontrans = useNontransactionalRead();
0600:
0601: Collection rows = null;
0602: try {
0603: if (useNontrans) {
0604: ((TransactionImpl) currentTransaction()).begin(true);
0605: }
0606: Set extraRows = new HashSet();
0607: rows = ((TransactionImpl) currentTransaction()).getDriver()
0608: .select(selector, extraRows);
0609:
0610: // Put rows in the 2nd-level cache
0611: Table table = selector.getTable();
0612: addToCache(rows);
0613:
0614: // Put extraRows in the cache too
0615: addToCache(extraRows);
0616: } catch (DriverException e) {
0617: throw new JDODataStoreException(I18N.msg("E_query_failed"),
0618: e);
0619: } finally {
0620: if (useNontrans) {
0621: currentTransaction().commit();
0622: }
0623: }
0624:
0625: return rows;
0626: }
0627:
0628: /** Returns a query built using JDOQL. */
0629: public Query newQuery(Class clazz, String filter) {
0630: assertNotClosed();
0631: Query q = new QueryImpl(this );
0632: q.setClass(clazz);
0633: q.setFilter(filter);
0634: return q;
0635: }
0636:
0637: /**
0638: * Returns a query for the specified class. Without user
0639: * modification, when executed, returns all instances of the class.
0640: */
0641: public Query newQuery(Class clazz) {
0642: assertNotClosed();
0643: QueryImpl query = new QueryImpl(this );
0644: query.setClass(clazz);
0645: return query;
0646: }
0647:
0648: /**
0649: * Returns a query for the specified extent. Without user
0650: * modification, when executed, returns all instances of the class.
0651: * Note that XORM does not support subclasses at this time.
0652: */
0653: public Query newQuery(Extent extent) {
0654: assertNotClosed();
0655: QueryImpl query = new QueryImpl(this );
0656: query.setClass(extent.getCandidateClass());
0657: return query;
0658: }
0659:
0660: /**
0661: * Returns a query for the specified extent. Without user
0662: * modification, when executed, returns all instances of the class
0663: * that match the query filter (JDOQL expression). Note that XORM
0664: * does not support subclasses at this time.
0665: */
0666: public Query newQuery(Extent extent, String filter) {
0667: assertNotClosed();
0668: QueryImpl query = new QueryImpl(this );
0669: query.setClass(extent.getCandidateClass());
0670: query.setFilter(filter);
0671: return query;
0672: }
0673:
0674: int executeSizeQuery(Selector selector) {
0675: boolean useNontrans = useNontransactionalRead();
0676: int count = -1;
0677: try {
0678: if (useNontrans) {
0679: ((TransactionImpl) currentTransaction()).begin(true);
0680: }
0681: count = ((TransactionImpl) currentTransaction())
0682: .getDriver().count(selector);
0683: } catch (DriverException e) {
0684: throw new JDODataStoreException(I18N.msg("E_query_failed"),
0685: e);
0686: } finally {
0687: if (useNontrans) {
0688: currentTransaction().commit();
0689: }
0690: }
0691: return count;
0692: }
0693:
0694: /**
0695: * Retrieves the user-associated object.
0696: */
0697: public Object getUserObject() {
0698: assertNotClosed();
0699: return userObject;
0700: }
0701:
0702: /**
0703: * Allows the user to associate an arbitrary object with this
0704: * InterfaceManager.
0705: */
0706: public void setUserObject(Object userObject) {
0707: assertNotClosed();
0708: this .userObject = userObject;
0709: }
0710:
0711: /**
0712: * Reloads the fields of the object from the datastore.
0713: */
0714: public void refresh(Object object) {
0715: assertNotClosed();
0716:
0717: // Look up the backing row in the datastore
0718: InterfaceInvocationHandler handler = InterfaceInvocationHandler
0719: .getHandler(object);
0720:
0721: ClassMapping mapping = handler.getClassMapping();
0722: Table table = mapping.getTable();
0723:
0724: // Look in datastore
0725: Row row = null;
0726:
0727: DataFetchGroup dfg = new DataFetchGroup(table.getColumns());
0728: Selector selector = new Selector(table, new SimpleCondition(
0729: table.getPrimaryKey(), Operator.EQUAL, handler
0730: .getObjectId()));
0731: selector.require(dfg);
0732: Collection rows = selectRows(selector);
0733: if (!rows.isEmpty()) {
0734: row = (Row) rows.iterator().next();
0735: } else {
0736: throw new JDODataStoreException(I18N.msg("E_row_deleted"));
0737: }
0738: handler.resetRow(row);
0739: }
0740:
0741: /** Calls refresh() on all objects in the array. */
0742: public void refreshAll(Object[] array) {
0743: assertNotClosed();
0744: for (int i = 0; i < array.length; i++) {
0745: refresh(array[i]);
0746: }
0747: }
0748:
0749: /** Calls refresh() on all objects in the collection. */
0750: public void refreshAll(Collection collection) {
0751: assertNotClosed();
0752: Iterator i = collection.iterator();
0753: while (i.hasNext()) {
0754: refresh(i.next());
0755: }
0756: }
0757:
0758: /** Refreshes all objects in the transaction. */
0759: public void refreshAll() {
0760: assertNotClosed();
0761: ((TransactionImpl) currentTransaction()).refreshAll();
0762: }
0763:
0764: /**
0765: * Marks this InterfaceManager as closed. Closing an
0766: * InterfaceManager ensures that any datastore resources being
0767: * used will be disconnected. After a call to close(), all
0768: * methods of the PersistenceManager interface (with the exception
0769: * of isClosed()) will throw JDOFatalUserException. Calling close()
0770: * while a Transaction is active will throw a JDOUserException.
0771: */
0772: public synchronized void close() {
0773: assertNotClosed();
0774: closeImpl(true);
0775: closed = true;
0776: }
0777:
0778: private void closeImpl(boolean failIfActive) {
0779: if (transaction instanceof WeakHashMap) {
0780: WeakHashMap threadTransactionMap = (WeakHashMap) transaction;
0781: for (Iterator it = threadTransactionMap.values().iterator(); it
0782: .hasNext();) {
0783: TransactionImpl txn = (TransactionImpl) it.next();
0784: if (txn.isActive()) {
0785: if (failIfActive) {
0786: throw new JDOUserException(I18N
0787: .msg("E_open_txn"));
0788: }
0789: txn.closeImpl();
0790: }
0791: }
0792: } else {
0793: TransactionImpl txn = (TransactionImpl) transaction;
0794: if (txn.isActive()) {
0795: if (failIfActive) {
0796: throw new JDOUserException(I18N.msg("E_open_txn"));
0797: }
0798: txn.closeImpl();
0799: }
0800: }
0801: }
0802:
0803: /**
0804: * Returns true if this manager object has been closed.
0805: */
0806: public boolean isClosed() {
0807: return closed;
0808: }
0809:
0810: /**
0811: * Returns the Extent of the given class. Subclasses are not
0812: * supported yet.
0813: */
0814: public Extent getExtent(Class clazz, boolean subclasses) {
0815: assertNotClosed();
0816: return new ExtentImpl(this , clazz, subclasses);
0817: }
0818:
0819: // -------------- UNSUPPORTED JDO SPEC OPERATIONS -------------------
0820:
0821: /** This operation is not currently supported. */
0822: public void evict(Object object) {
0823: assertNotClosed();
0824: throw new UnsupportedOperationException();
0825: }
0826:
0827: /** This operation is not currently supported. */
0828: public void evictAll(Object[] array) {
0829: assertNotClosed();
0830: throw new UnsupportedOperationException();
0831: }
0832:
0833: /** This operation is not currently supported. */
0834: public void evictAll(Collection collection) {
0835: assertNotClosed();
0836: throw new UnsupportedOperationException();
0837: }
0838:
0839: /** This operation is not currently supported. */
0840: public void evictAll() {
0841: assertNotClosed();
0842: throw new UnsupportedOperationException();
0843: }
0844:
0845: /**
0846: * If the class parameter is not mapped in a *.jdo file,
0847: * returns null. Otherwise returns org.xorm.ObjectId.class.
0848: */
0849: public Class getObjectIdClass(Class clazz) {
0850: assertNotClosed();
0851: ClassMapping classMapping = factory.getModelMapping()
0852: .getClassMapping(clazz);
0853: return (classMapping == null) ? null : ObjectId.class;
0854: }
0855:
0856: /**
0857: * Indicates that this PersistenceManager will be used in a
0858: * multithreaded context. Currently this flag is not being used.
0859: */
0860: public void setMultithreaded(boolean multithreaded) {
0861: assertNotClosed();
0862: this .multithreaded = multithreaded;
0863: }
0864:
0865: /**
0866: * Returns the value of the multithreaded flag, which XORM
0867: * blithely ignores.
0868: */
0869: public boolean getMultithreaded() {
0870: assertNotClosed();
0871: return multithreaded;
0872: }
0873:
0874: /**
0875: * Sets the value of the ignoreCache flag. Currently this suggestion
0876: * is given little attention.
0877: */
0878: public void setIgnoreCache(boolean ignoreCache) {
0879: assertNotClosed();
0880: this .ignoreCache = ignoreCache;
0881: }
0882:
0883: /**
0884: * Returns the value of the ignoreCache flag. Not that it will
0885: * do you much good.
0886: */
0887: public boolean getIgnoreCache() {
0888: assertNotClosed();
0889: return ignoreCache;
0890: }
0891:
0892: /**
0893: * Creates a new query that the user must set values on
0894: * using the Query interface.
0895: */
0896: public Query newQuery() {
0897: assertNotClosed();
0898: return new QueryImpl(this );
0899: }
0900:
0901: /** Constructs a query by copying data from a previous query. */
0902: public Query newQuery(Object compiled) {
0903: assertNotClosed();
0904: if (compiled instanceof QueryImpl) {
0905: return new QueryImpl(this , (QueryImpl) compiled);
0906: }
0907: throw new UnsupportedOperationException();
0908: }
0909:
0910: /**
0911: * Known languages are "javax.jdo.query.JDOQL" (which takes a
0912: * String), "org.xorm.query.CodeQuery" (use CodeQuery.LANGUAGE), and
0913: * QueryLanguage.LANGUAGE.
0914: */
0915: public Query newQuery(String language, Object query) {
0916: assertNotClosed();
0917: if (QueryLanguage.LANGUAGE.equals(language)) {
0918: return new QueryImpl(this , (QueryLanguage) query);
0919: } else if (JDOQL_LANGUAGE.equals(language)) {
0920: return newQuery((Class) null, (String) query);
0921: } else if (CodeQuery.LANGUAGE.equals(language)) {
0922: // First try to get Expression directly.
0923: try {
0924: return new QueryImpl(this ,
0925: new CodeParser((Class) query));
0926: } catch (Throwable e) {
0927: // Code could not be turned into JDOQL.
0928: return new CodeQuery(this , (Class) query);
0929: }
0930: }
0931: throw new UnsupportedOperationException();
0932: }
0933:
0934: /** This operation is not currently supported. */
0935: public Query newQuery(Class clazz, Collection extent) {
0936: assertNotClosed();
0937: throw new UnsupportedOperationException();
0938: }
0939:
0940: /** This operation is not currently supported. */
0941: public Query newQuery(Class clazz, Collection extent, String filter) {
0942: assertNotClosed();
0943: throw new UnsupportedOperationException();
0944: }
0945:
0946: /**
0947: * Returns a new objectId corresponding to the given class and
0948: * String parameter.
0949: */
0950: public Object newObjectIdInstance(Class clazz, String arg) {
0951: assertNotClosed();
0952: return JDOImplHelper.getInstance().newObjectIdInstance(clazz,
0953: arg);
0954: }
0955:
0956: /**
0957: * At present, this is the same as getObjectId().
0958: * Changing an ObjectId is not supported.
0959: */
0960: public Object getTransactionalObjectId(Object object) {
0961: return getObjectId(object);
0962: }
0963:
0964: /** This operation is not currently supported. */
0965: public void retrieve(Object object) {
0966: assertNotClosed();
0967: throw new UnsupportedOperationException();
0968: }
0969:
0970: /** This operation is not currently supported. */
0971: public void retrieveAll(Collection collection) {
0972: retrieveAll(collection, false);
0973: }
0974:
0975: /** This operation is not currently supported. */
0976: public void retrieveAll(Collection collection, boolean dfgOnly) {
0977: assertNotClosed();
0978: Iterator i = collection.iterator();
0979: while (i.hasNext()) {
0980: retrieve(i.next());
0981: }
0982: }
0983:
0984: /** This operation is not currently supported. */
0985: public void retrieveAll(Object[] array) {
0986: retrieveAll(array, false);
0987: }
0988:
0989: /** This operation is not currently supported. */
0990: public void retrieveAll(Object[] array, boolean dfgOnly) {
0991: assertNotClosed();
0992: for (int i = 0; i < array.length; i++) {
0993: retrieve(array[i]);
0994: }
0995: }
0996:
0997: /**
0998: * When an InterfaceManager is garbage collected,
0999: * ensure that any active transactions are closed.
1000: */
1001: public void finalize() {
1002: if (!closed) {
1003: try {
1004: closeImpl(false);
1005: } catch (Exception e) {
1006: logger.severe(I18N.msg("W_mgr_finalize"));
1007: }
1008: }
1009: }
1010: }
|