0001: /*
0002: * Copyright (c) 1998 - 2005 Versant Corporation
0003: * All rights reserved. This program and the accompanying materials
0004: * are made available under the terms of the Eclipse Public License v1.0
0005: * which accompanies this distribution, and is available at
0006: * http://www.eclipse.org/legal/epl-v10.html
0007: *
0008: * Contributors:
0009: * Versant Corporation - initial API and implementation
0010: */
0011: package com.versant.core.ejb;
0012:
0013: import com.versant.core.metadata.ModelMetaData;
0014: import com.versant.core.metadata.ClassMetaData;
0015: import com.versant.core.metadata.FetchGroup;
0016: import com.versant.core.metadata.FieldMetaData;
0017: import com.versant.core.jdo.*;
0018: import com.versant.core.storagemanager.StorageManager;
0019: import com.versant.core.storagemanager.ApplicationContext;
0020: import com.versant.core.common.*;
0021: import com.versant.core.ejb.common.EntrySet;
0022: import com.versant.core.ejb.common.IdentityEntry;
0023:
0024: import javax.jdo.*;
0025: import javax.jdo.spi.PersistenceCapable;
0026: import javax.persistence.EntityManager;
0027: import javax.persistence.Query;
0028: import javax.persistence.EntityNotFoundException;
0029: import javax.persistence.TransactionRequiredException;
0030: import javax.transaction.Synchronization;
0031: import java.util.*;
0032: import java.lang.reflect.Field;
0033: import java.sql.Connection;
0034:
0035: /**
0036: * Implementation of ejb3 EntityManager.
0037: */
0038: public class EntityManagerImp implements EntityManager, Transaction,
0039: ApplicationContext, PersistenceContext {
0040: public final StorageManager storageMan;
0041: ModelMetaData modelMetaData;
0042: private EMProxy proxy;
0043: /**
0044: * The objects that must be commited at the end of the tx.
0045: */
0046: private Set<StateManagerImp> txObjects = new HashSet<StateManagerImp>();
0047: private LocalCache cache = new LocalCache();
0048: /**
0049: * The list of instances that has been marked for delete in the current tx.
0050: */
0051: private final DeletePacket toBeDeleted;
0052: /**
0053: * This is used to transport the dirty stuff to the server.
0054: */
0055: public final StatesToStore storeOidStateContainer;
0056: private boolean txActive;
0057: /**
0058: * int val used for creating newoids
0059: */
0060: private int newOidCounter;
0061:
0062: public EntityManagerImp(StorageManager sm,
0063: ModelMetaData modelMetaData) {
0064: this .storageMan = sm;
0065: this .modelMetaData = modelMetaData;
0066: toBeDeleted = new DeletePacket(modelMetaData);
0067: storeOidStateContainer = new StatesToStore(modelMetaData);
0068: }
0069:
0070: public Transaction getTransaction() {
0071: return this ;
0072: }
0073:
0074: /**
0075: * The StorageManager calls this method to check if we need prefetched
0076: * data or not.
0077: */
0078: public boolean isStateRequired(OID oid, FetchGroup fetchGroup) {
0079: // State state = cache.getStateByOID(oid);
0080: // if (state != null) {
0081: // if (fetchGroup == null) {
0082: // fetchGroup = state.getClassMetaData().fetchGroups[0];
0083: // }
0084: // return !state.containsFetchGroup(fetchGroup);
0085: // }
0086: return true;
0087: }
0088:
0089: public void close() {
0090: }
0091:
0092: public void isOpen() {
0093: }
0094:
0095: /**
0096: * " If X is a new entity, it becomes managed. The entity X will be entered
0097: * into the database at or before transaction commit or as a result of the
0098: * flush operation .
0099: *
0100: * " If X is a preexisting managed entity, it is ignored by the persist
0101: * operation. However, the persist operation is cascaded to entities
0102: * referenced by X, if the relationships from X to these other entities
0103: * is annotated with the cascade=PERSIST or cascade=ALL annotation member
0104: * value.
0105: *
0106: * " If X is a removed entity, it becomes managed.
0107: *
0108: * " If X is a detached object, an IllegalArgumentException will be thrown
0109: * by the container (or the transaction commit will fail).
0110: *
0111: * " For all entities Y referenced by a relationship from X, if the
0112: * relationship to Y has been annotated with the cascade member
0113: * value cascade=PERSIST or cascade=ALL, the persist operation is
0114: * applied to Y.
0115: * @param entity
0116: */
0117: public void persist(Object entity) {
0118: if (entity == null)
0119: return;
0120: checkForActiveTransaction();
0121:
0122: //create a '==' based set
0123: final IdentityEntry tailPointer = new IdentityEntry("HEAD");
0124: EntrySet mergeSet = new EntrySet() {
0125: public IdentityEntry tail = tailPointer;
0126:
0127: public Entry createEntry(Object key) {
0128: IdentityEntry ne = new IdentityEntry(key);
0129: tail.nextEntry = ne;
0130: tail = ne;
0131: return ne;
0132: }
0133: };
0134:
0135: mergeSet.add(entity);
0136: for (IdentityEntry ie = tailPointer.nextEntry; ie != null; ie = ie.nextEntry) {
0137: persistImp(ie.getKey(), mergeSet);
0138: }
0139: }
0140:
0141: /**
0142: * Add all the OIDs and States in the container to the cache.
0143: */
0144: public void addToCache(StatesReturned container) {
0145: for (Iterator i = container.iterator(); i.hasNext();) {
0146: com.versant.core.common.EntrySet.Entry e = (com.versant.core.common.EntrySet.Entry) i
0147: .next();
0148: cache.add((OID) e.getKey(), (State) e.getValue());
0149: }
0150: }
0151:
0152: private void persistImp(Object entity, EntrySet mergeSet) {
0153: if (entity == null)
0154: return;
0155: LifeCycleStatus lfs = getLifeCycleStatus(entity);
0156: switch (lfs) {
0157: case NEW:
0158: manage(entity).persistReferences(mergeSet);
0159: break;
0160: case MANAGED:
0161: getStateManager((PersistenceCapable) entity)
0162: .persistReferences(mergeSet);
0163: break;
0164: case DETACHED:
0165: throw new IllegalArgumentException(
0166: "The supplied instance is a detached instance. "
0167: + "Please make use of the 'merge' operation.");
0168: }
0169: }
0170:
0171: /**
0172: * Check that an transaction is active.
0173: * @throws javax.persistence.TransactionRequiredException
0174: */
0175: private void checkForActiveTransaction() {
0176: if (!txActive)
0177: throw new TransactionRequiredException();
0178: }
0179:
0180: /**
0181: * Takes a new instance (ie not managed or detached) and manage it.
0182: * This is not a recursive operation.
0183: * @param entity
0184: */
0185: private StateManagerImp manage(Object entity) {
0186: StateManagerImp sm = new StateManagerImp(proxy, modelMetaData);
0187: sm.manageNew((PersistenceCapable) entity, cache,
0188: newOidCounter++);
0189: txObjects.add(sm);
0190: return sm;
0191: }
0192:
0193: /**
0194: * Look at the annotations and manage references reachable from this instance.
0195: * @param entity
0196: */
0197: private void manageReferences(Object entity) {
0198: //To change body of created methods use File | Settings | File Templates.
0199: }
0200:
0201: /**
0202: * Determine the status {@link LifeCycleStatus} of the supplied entity.
0203: * @param entity
0204: */
0205: public LifeCycleStatus getLifeCycleStatus(Object entity) {
0206: if (!(entity instanceof PersistenceCapable)) {
0207: throw new IllegalArgumentException(
0208: "The supplied instance '"
0209: + entity.getClass().getName()
0210: + "' is not a manageble type");
0211: }
0212: PersistenceCapable pc = (PersistenceCapable) entity;
0213: PersistenceManager pm = pc.jdoGetPersistenceManager();
0214: if (pm == null) {
0215: if ((entity instanceof VersantDetachable)
0216: && ((VersantDetachable) entity)
0217: .versantGetDetachedStateManager() != null) {
0218: return LifeCycleStatus.DETACHED;
0219: }
0220: return LifeCycleStatus.NEW;
0221: }
0222:
0223: if (pm != this ) {
0224: throw new IllegalArgumentException(
0225: "The supplied entity is not "
0226: + "managed does by this EntityManager");
0227: }
0228:
0229: StateManagerImp em = getStateManager(pc);
0230: if (em.isRemoved()) {
0231: return LifeCycleStatus.REMOVED;
0232: }
0233: return LifeCycleStatus.MANAGED;
0234: }
0235:
0236: private void detachOnCommit() {
0237: VersantDetachedStateManager vdsm = new VersantDetachedStateManager();
0238: Iterator iter = cache.getCacheIterator();
0239: while (iter.hasNext()) {
0240: LocalCache.CacheEntry entry = (LocalCache.CacheEntry) iter
0241: .next();
0242: if (entry.getValue() instanceof StateManagerImp) {
0243: ((StateManagerImp) entry.getValue())
0244: .detachOnCommit(vdsm);
0245: }
0246: }
0247: }
0248:
0249: /**
0250: * Try and obtain the entitymanager for the pc instance.
0251: */
0252: private StateManagerImp getStateManager(PersistenceCapable pc) {
0253: StateManagerImp em = null;
0254: try {
0255: Field f = pc.getClass().getDeclaredField("jdoStateManager");
0256: f.setAccessible(true);
0257: em = (StateManagerImp) f.get(pc);
0258: } catch (Exception e) {
0259: e.printStackTrace(System.out);
0260: }
0261: return em;
0262: }
0263:
0264: /**
0265: * " If X is a detached entity, it is copied onto a pre-existing managed
0266: * entity instance X' of the same identity or a new managed copy of X is created.
0267: *
0268: * " If X is a new entity instance, a new managed entity instance X' is created
0269: * and the state of X is copied into the new managed entity instance X'.
0270: *
0271: * " If X is a removed entity instance, an IllegalArgumentException will be
0272: * thrown by the container (or the transaction commit will fail).
0273: *
0274: * " If X is a managed entity, it is ignored by the merge operation, however,
0275: * the merge operation is cascaded to entities referenced by relationships
0276: * from X if these relationships have been annotated with the cascade member
0277: * value cascade=MERGE or cascade=ALL annotation.
0278: *
0279: * " For all entities Y referenced by relationships from X having the cascade
0280: * member value cascade=MERGE or cascade=ALL, Y is merged recursively as Y'.
0281: * For all such Y referenced by X, X' is set to reference Y'.
0282: * (Note that if X is managed then X is the same object as X'.)
0283: *
0284: * " If X is an entity merged to X', with a reference to another entity Y,
0285: * where cascade=MERGE or cascade=ALL is not specified, then navigation of
0286: * the same association from X' yields a reference to a managed object Y'
0287: * with the same persistent identity as Y.
0288: *
0289: * " Fields or properties of type java.sql.Blob and java.sql.Clob are
0290: * ignored by the merge operation.
0291: *
0292: * @param entity
0293: * @return the instance that the state was merged to
0294: */
0295: public <T> T merge(T entity) {
0296: //create a '==' based set
0297: final IdentityEntry tailPointer = new IdentityEntry("HEAD");
0298: EntrySet mergeSet = new EntrySet() {
0299: public IdentityEntry tail = tailPointer;
0300:
0301: public Entry createEntry(Object key) {
0302: IdentityEntry ne = new IdentityEntry(key);
0303: tail.nextEntry = ne;
0304: tail = ne;
0305: return ne;
0306: }
0307: };
0308:
0309: mergeSet.add(entity);
0310: T result = (T) mergeInternal(entity, mergeSet).pc;
0311: getStateManager((PersistenceCapable) result).mergeReferences(
0312: mergeSet);
0313:
0314: for (IdentityEntry ie = tailPointer.nextEntry.nextEntry; ie != null; ie = ie.nextEntry) {
0315: mergeInternal(ie.getKey(), mergeSet).mergeReferences(
0316: mergeSet);
0317: }
0318:
0319: return result;
0320: }
0321:
0322: /**
0323: * Merge in the provided entity.
0324: * @param entity
0325: * @param mergeSet
0326: * @return
0327: */
0328: public StateManagerImp mergeInternal(Object entity,
0329: EntrySet mergeSet) {
0330: IdentityEntry e = (IdentityEntry) mergeSet
0331: .addAndReturnEntry(entity);
0332: if (e.value != null) {
0333: return (StateManagerImp) e.value;
0334: }
0335: switch (getLifeCycleStatus(entity)) {
0336: case NEW:
0337: return (StateManagerImp) (e.value = manage(entity));
0338: case MANAGED:
0339: checkManagedBy(entity);
0340: return (StateManagerImp) (e.value = getStateManager((PersistenceCapable) entity));
0341: case DETACHED:
0342: VersantDetachable de = (VersantDetachable) entity;
0343: OID oid = extractOID(de.versantGetOID());
0344: StateManagerImp sm = getObjectById(oid);
0345:
0346: //check for version
0347: if (sm.cmd.optimisticLockingField != null
0348: && !de.versantGetVersion().equals(
0349: sm.getOptimisticLockingValue())) {
0350: throw new RuntimeException("Conncurrent update");
0351: }
0352:
0353: mergeFromDetached(de, sm);
0354: return (StateManagerImp) (e.value = sm);
0355: case REMOVED:
0356: throw new IllegalStateException(
0357: "'merge' operation not allowed on '"
0358: + getLifeCycleStatus(entity)
0359: + "' instances");
0360: default:
0361: throw BindingSupportImpl.getInstance().internal(
0362: "Unhandled lifecycle state '"
0363: + getLifeCycleStatus(entity) + "'");
0364:
0365: }
0366: }
0367:
0368: public <T> T mergeImp(T entity, EntrySet mergeSet) {
0369: switch (getLifeCycleStatus(entity)) {
0370: case NEW:
0371: return (T) manage(entity).mergeReferences(mergeSet).pc;
0372: case MANAGED:
0373: checkManagedBy(entity);
0374: return (T) getStateManager((PersistenceCapable) entity)
0375: .mergeReferences(mergeSet).pc;
0376: case DETACHED:
0377: VersantDetachable de = (VersantDetachable) entity;
0378: OID oid = extractOID(de.versantGetOID());
0379: StateManagerImp sm = getObjectById(oid);
0380:
0381: //check for version
0382: if (sm.cmd.optimisticLockingField != null
0383: && !de.versantGetVersion().equals(
0384: sm.getOptimisticLockingValue())) {
0385: throw new RuntimeException("Conncurrent update");
0386: }
0387: mergeFromDetached(de, sm);
0388: sm.mergeReferences(mergeSet);
0389: return (T) sm.pc;
0390: case REMOVED:
0391: throw new IllegalStateException(
0392: "'merge' operation not allowed on '"
0393: + getLifeCycleStatus(entity)
0394: + "' instances");
0395: default:
0396: throw BindingSupportImpl.getInstance().internal(
0397: "Unhandled lifecycle state '"
0398: + getLifeCycleStatus(entity) + "'");
0399:
0400: }
0401: }
0402:
0403: /**
0404: * Merge from the detached instance to the managed instance.
0405: */
0406: private void mergeFromDetached(VersantDetachable de,
0407: StateManagerImp sm) {
0408: //only copy its dirty fields
0409: if (de.versantIsDirty()) {
0410: VersantDetachedStateManager dsm = de
0411: .versantGetDetachedStateManager();
0412: AttachStateManager asm = new AttachStateManager();
0413: asm.setSm(sm);
0414: try {
0415: de.jdoReplaceStateManager(asm);
0416: FieldMetaData[] mFields = sm.cmd.managedFields;
0417: for (int i = 0; i < mFields.length; i++) {
0418: FieldMetaData mField = mFields[i];
0419: if (de.versantIsDirty(mField.managedFieldNo)) {
0420: de.jdoProvideField(mField.managedFieldNo);
0421: }
0422: }
0423: } finally {
0424: de.jdoReplaceStateManager(dsm);
0425: }
0426: }
0427: }
0428:
0429: /**
0430: * Create a managed instance that is of the same type as t and fill it with
0431: * the date from t
0432: * @param t
0433: * @return T managed instance created from t
0434: */
0435: private <T> T createManagedInstanceFrom(T t) {
0436: return null;
0437: }
0438:
0439: /**
0440: * Check that the managedVal is managedBy this EntityManager.
0441: * @param managedVal
0442: */
0443: private void checkManagedBy(Object managedVal) throws UserException {
0444: //To change body of created methods use File | Settings | File Templates.
0445: }
0446:
0447: /**
0448: * Return managed instance for supplied oid. If instance not found in
0449: * localCache then manage it.
0450: *
0451: * @param oid
0452: * @return
0453: */
0454: public StateManagerImp getObjectById(OID oid) {
0455: StateManagerImp sm = getSmFromCache(oid);
0456: if (sm == null) {
0457: ClassMetaData cmd = oid.getAvailableClassMetaData();
0458: StatesReturned sr = null;
0459: try {
0460: sr = storageMan.fetch(this , oid, null,
0461: cmd.fetchGroups[0], null);
0462: } catch (JDOObjectNotFoundException e) {
0463: throw throwEntityNotFound(oid);
0464: }
0465: sm = new StateManagerImp(proxy, modelMetaData);
0466: oid = sr.getDirectOID();
0467:
0468: sm.manage(oid, sr.get(oid), cache);
0469: }
0470: return sm;
0471: }
0472:
0473: public StateManagerImp manage(OID oid, State state) {
0474: StateManagerImp sm = new StateManagerImp(proxy, modelMetaData);
0475: sm.manage(oid, state, cache);
0476: return sm;
0477: }
0478:
0479: public void fetchState(StateManagerImp sm, FetchGroup fg) {
0480: StatesReturned sr = null;
0481: try {
0482: sr = storageMan.fetch(this , sm.oid, null, fg, null);
0483: } catch (JDOObjectNotFoundException e) {
0484: throw throwEntityNotFound(sm.oid);
0485: }
0486: sm.updateState(sr.get(sm.oid));
0487: }
0488:
0489: public Object getObjectByIdForState(OID oid, int stateFieldNo,
0490: int navClassIndex, OID fromOID) {
0491: try {
0492: PersistenceCapable pc = null;
0493: FieldMetaData fmd = fromOID.getAvailableClassMetaData().stateFields[stateFieldNo];
0494: if (fmd.embedded) {
0495: if (true)
0496: throw new RuntimeException();
0497: // //create a managed instance of the embedded reference
0498: // StateManagerImp sm = cache.get(fromOID);
0499: // if (fmd.nullIndicatorFmd != null) {
0500: // if (sm.state.isFieldNullorZero(fmd.nullIndicatorFmd.stateFieldNo)) {
0501: // return null;
0502: // }
0503: // }
0504: // EmbeddedStateManager embeddedSm = sm.createEmbeddedSM(fmd);
0505: // pc = embeddedSm.pc;
0506: } else {
0507: StateManagerImp sm = getObjectById(oid);
0508: pc = sm.pc;
0509: }
0510: return pc;
0511: } catch (Exception e) {
0512: handleException(e);
0513: return null;
0514: }
0515: }
0516:
0517: public OID extractOID(Object oid) {
0518: if (oid instanceof VersantOid) {
0519: return modelMetaData
0520: .convertJDOGenieOIDtoOID((VersantOid) oid);
0521: } else {
0522: return modelMetaData.convertFromAppIdToOID(oid);
0523: }
0524: }
0525:
0526: private OID convertNewToActual(OID oid) {
0527: if (!oid.isNew()) {
0528: oid.getAvailableClassMetaData();
0529: return oid;
0530: }
0531: return oid.getAvailableOID();
0532: }
0533:
0534: /**
0535: * Find a managed intance that represents the same id as the supplied
0536: * detached intance.
0537: * @param detached
0538: * @return
0539: */
0540: private <T> T findManagedInstanceforDetached(T detached) {
0541: return null;
0542: }
0543:
0544: public void remove(Object entity) {
0545: checkForActiveTransaction();
0546: LifeCycleStatus lfs = getLifeCycleStatus(entity);
0547: switch (lfs) {
0548: case DETACHED:
0549: case REMOVED:
0550: throw new IllegalArgumentException(
0551: "May not remove 'DETACHED' or 'REMOVED' instances");
0552: case MANAGED:
0553: StateManagerImp sm = getStateManager((PersistenceCapable) entity);
0554: sm.remove();
0555: break;
0556: case NEW:
0557:
0558: break;
0559: default:
0560: throw new RuntimeException("Unhandled lifecycle state: '"
0561: + lfs + "'");
0562: }
0563: }
0564:
0565: public Object find(String entityName, Object primaryKey) {
0566: return null;
0567: }
0568:
0569: public <T> T find(Class<T> entityClass, Object primaryKey) {
0570: ClassMetaData cmd = modelMetaData.getClassMetaData(entityClass);
0571: if (cmd == null) {
0572: throw new IllegalArgumentException("The class '"
0573: + entityClass.getName()
0574: + "' is not a persistable class");
0575: }
0576: OID oid = cmd.createOID(false).fillFromIDObject(primaryKey);
0577: StateManagerImp sm = getSmFromCache(oid);
0578: if (sm == null) {
0579: StatesReturned sr = null;
0580: try {
0581: sr = storageMan.fetch(this , oid, null,
0582: cmd.fetchGroups[0], null);
0583: } catch (JDOObjectNotFoundException e) {
0584: throw throwEntityNotFound(entityClass, primaryKey);
0585: }
0586: sm = new StateManagerImp(proxy, modelMetaData);
0587: oid = sr.getDirectOID();
0588: sm.manage(oid, sr.get(oid), cache);
0589: }
0590: return (T) sm.getPersistenceCapable();
0591: }
0592:
0593: private StateManagerImp getSmFromCache(OID oid) {
0594: Object o = cache.get(oid);
0595: if (o == null)
0596: return null;
0597: if (o instanceof StateManagerImp)
0598: return (StateManagerImp) o;
0599: if (o instanceof State) {
0600: return manage(oid, (State) o);
0601: }
0602: throw BindingSupportImpl.getInstance().internal(
0603: "Unhandled instance type '" + o.getClass().getName()
0604: + "' in local cache");
0605:
0606: }
0607:
0608: private static RuntimeException throwEntityNotFound(
0609: Class entityClass, Object primaryKey) {
0610: return new EntityNotFoundException("Entity '"
0611: + entityClass.getName() + "' with id '" + primaryKey
0612: + "' can not be found.");
0613: }
0614:
0615: private static RuntimeException throwEntityNotFound(OID oid) {
0616: return new EntityNotFoundException("Entity '"
0617: + oid.getAvailableClassMetaData().qname + "' with id '"
0618: + oid + "' can not be found.");
0619: }
0620:
0621: public void flush() {
0622: checkForActiveTransaction();
0623: StatesReturned sc = null;
0624: try {
0625: //prepare the sm's for to store the states
0626: prepareForStore(true);
0627: //send the state to the server
0628: sc = storageMan.store(storeOidStateContainer, toBeDeleted,
0629: false, StorageManager.STORE_OPTION_FLUSH, false);
0630: postStore(sc, true);
0631: } catch (Exception e) {
0632: handleException(e);
0633: } finally {
0634: if (sc != null) {
0635: sc.clear();
0636: }
0637: storeOidStateContainer.clear();
0638: toBeDeleted.clear();
0639: txObjects.clear();
0640: }
0641: }
0642:
0643: public void refresh(Object entity) {
0644: }
0645:
0646: public boolean contains(Object entity) {
0647: return false; //To change body of implemented methods use File | Settings | File Templates.
0648: }
0649:
0650: public Query createQuery(String ejbqlString) {
0651: return new VersantEjbQueryImp(proxy, ejbqlString);
0652: }
0653:
0654: public Query createNamedQuery(String name) {
0655: return null;
0656: }
0657:
0658: public Query createNativeQuery(String sqlString) {
0659: return null;
0660: }
0661:
0662: public Query createNativeQuery(String sqlString, Class resultClass) {
0663: return null;
0664: }
0665:
0666: public Query createNativeQuery(String sqlString,
0667: String resultSetMapping) {
0668: return null;
0669: }
0670:
0671: public void begin() {
0672: if (txActive) {
0673: throw new RuntimeException(
0674: "The transaction is alread active");
0675: }
0676: if (proxy != null) {
0677: throw new RuntimeException(
0678: "The em was not reset correctly at end of previous transaction.");
0679: }
0680: storageMan.begin(true);
0681: proxy = new EMProxy(this );
0682: txActive = true;
0683: }
0684:
0685: /**
0686: * Commit the active transaction. Everything must be detached at the end
0687: * of the operation. This would mean that the pc instance must contain the needed
0688: * data for it to be detached.
0689: */
0690: public void commit() {
0691: checkForActiveTransaction();
0692: StatesReturned sc = null;
0693: try {
0694: //prepare the sm's for to store the states
0695: prepareForStore(true);
0696: //send the state to the server
0697: sc = storageMan.store(storeOidStateContainer, toBeDeleted,
0698: false, StorageManager.STORE_OPTION_COMMIT, false);
0699: postStore(sc, false);
0700: txActive = false;
0701: } catch (Exception e) {
0702: handleException(e);
0703: } finally {
0704: if (proxy != null) {
0705: proxy.detach();
0706: proxy = null;
0707: }
0708: if (sc != null) {
0709: sc.clear();
0710: }
0711: storeOidStateContainer.clear();
0712: toBeDeleted.clear();
0713: txObjects.clear();
0714: }
0715: detachOnCommit();
0716: cache.clear();
0717: }
0718:
0719: private void postStore(StatesReturned sc, boolean flush) {
0720: //give each instance a change to
0721: for (Iterator<StateManagerImp> iterator = txObjects.iterator(); iterator
0722: .hasNext();) {
0723: iterator.next().postStore(sc, flush);
0724: }
0725: }
0726:
0727: /**
0728: * All public method must be wrapped with this.
0729: * @param e
0730: */
0731: private void handleException(Exception e) {
0732: e.printStackTrace(System.out);
0733: throw new RuntimeException(e);
0734: }
0735:
0736: /**
0737: * Prepare to store all dirty instances for a commit or flush. This finds
0738: * all reachable instances and invokes preStore lifecycle listeners and
0739: * jdoPreStore instance callbacks.
0740: */
0741: private void prepareForStore(boolean commit) {
0742: storeOidStateContainer.clear();
0743: toBeDeleted.clear();
0744: for (Iterator<StateManagerImp> iterator = txObjects.iterator(); iterator
0745: .hasNext();) {
0746: iterator.next().prepareCommitOrFlush(commit, toBeDeleted,
0747: storeOidStateContainer);
0748: }
0749: }
0750:
0751: public void rollback() {
0752: if (!txActive) {
0753: throw new RuntimeException("There is no active transaction");
0754: }
0755: if (proxy != null) {
0756: proxy.detach();
0757: }
0758: }
0759:
0760: public boolean isActive() {
0761: return txActive;
0762: }
0763:
0764: public void setNontransactionalRead(boolean b) {
0765: //To change body of implemented methods use File | Settings | File Templates.
0766: }
0767:
0768: public boolean getNontransactionalRead() {
0769: return false; //To change body of implemented methods use File | Settings | File Templates.
0770: }
0771:
0772: public void setNontransactionalWrite(boolean b) {
0773: //To change body of implemented methods use File | Settings | File Templates.
0774: }
0775:
0776: public boolean getNontransactionalWrite() {
0777: return false; //To change body of implemented methods use File | Settings | File Templates.
0778: }
0779:
0780: public void setRetainValues(boolean b) {
0781: //To change body of implemented methods use File | Settings | File Templates.
0782: }
0783:
0784: public boolean getRetainValues() {
0785: return false; //To change body of implemented methods use File | Settings | File Templates.
0786: }
0787:
0788: public void setRestoreValues(boolean b) {
0789: //To change body of implemented methods use File | Settings | File Templates.
0790: }
0791:
0792: public boolean getRestoreValues() {
0793: return false; //To change body of implemented methods use File | Settings | File Templates.
0794: }
0795:
0796: public void setOptimistic(boolean b) {
0797: //To change body of implemented methods use File | Settings | File Templates.
0798: }
0799:
0800: public boolean getOptimistic() {
0801: return false; //To change body of implemented methods use File | Settings | File Templates.
0802: }
0803:
0804: public void setSynchronization(Synchronization synchronization) {
0805: //To change body of implemented methods use File | Settings | File Templates.
0806: }
0807:
0808: public Synchronization getSynchronization() {
0809: return null; //To change body of implemented methods use File | Settings | File Templates.
0810: }
0811:
0812: public PersistenceManager getPersistenceManager() {
0813: return this ;
0814: }
0815:
0816: public boolean isClosed() {
0817: return false; //To change body of implemented methods use File | Settings | File Templates.
0818: }
0819:
0820: public Transaction currentTransaction() {
0821: return null; //To change body of implemented methods use File | Settings | File Templates.
0822: }
0823:
0824: public void evict(Object o) {
0825: //To change body of implemented methods use File | Settings | File Templates.
0826: }
0827:
0828: public void evictAll(Object[] objects) {
0829: //To change body of implemented methods use File | Settings | File Templates.
0830: }
0831:
0832: public void evictAll(Collection collection) {
0833: //To change body of implemented methods use File | Settings | File Templates.
0834: }
0835:
0836: public void evictAll() {
0837: //To change body of implemented methods use File | Settings | File Templates.
0838: }
0839:
0840: public void refreshAll(Object[] objects) {
0841: //To change body of implemented methods use File | Settings | File Templates.
0842: }
0843:
0844: public void refreshAll(Collection collection) {
0845: //To change body of implemented methods use File | Settings | File Templates.
0846: }
0847:
0848: public void refreshAll() {
0849: //To change body of implemented methods use File | Settings | File Templates.
0850: }
0851:
0852: public javax.jdo.Query newQuery() {
0853: return null; //To change body of implemented methods use File | Settings | File Templates.
0854: }
0855:
0856: public javax.jdo.Query newQuery(Object o) {
0857: return null; //To change body of implemented methods use File | Settings | File Templates.
0858: }
0859:
0860: public javax.jdo.Query newQuery(String s, Object o) {
0861: return null; //To change body of implemented methods use File | Settings | File Templates.
0862: }
0863:
0864: public javax.jdo.Query newQuery(Class aClass) {
0865: return null; //To change body of implemented methods use File | Settings | File Templates.
0866: }
0867:
0868: public javax.jdo.Query newQuery(Extent extent) {
0869: return null; //To change body of implemented methods use File | Settings | File Templates.
0870: }
0871:
0872: public javax.jdo.Query newQuery(Class aClass, Collection collection) {
0873: return null; //To change body of implemented methods use File | Settings | File Templates.
0874: }
0875:
0876: public javax.jdo.Query newQuery(Class aClass, String s) {
0877: return null; //To change body of implemented methods use File | Settings | File Templates.
0878: }
0879:
0880: public javax.jdo.Query newQuery(Class aClass,
0881: Collection collection, String s) {
0882: return null; //To change body of implemented methods use File | Settings | File Templates.
0883: }
0884:
0885: public javax.jdo.Query newQuery(Extent extent, String s) {
0886: return null; //To change body of implemented methods use File | Settings | File Templates.
0887: }
0888:
0889: public Extent getExtent(Class aClass, boolean b) {
0890: return null; //To change body of implemented methods use File | Settings | File Templates.
0891: }
0892:
0893: public Object getObjectById(Object o, boolean b) {
0894: if (o instanceof OID) {
0895: return getObjectById((OID) o);
0896: } else {
0897: throw BindingSupportImpl.getInstance().unsupported(
0898: "unsupported operation");
0899: }
0900: }
0901:
0902: public Object getObjectId(Object o) {
0903: return null; //To change body of implemented methods use File | Settings | File Templates.
0904: }
0905:
0906: public Object getTransactionalObjectId(Object o) {
0907: return null; //To change body of implemented methods use File | Settings | File Templates.
0908: }
0909:
0910: public Object newObjectIdInstance(Class aClass, String s) {
0911: return null; //To change body of implemented methods use File | Settings | File Templates.
0912: }
0913:
0914: public void makePersistent(Object o) {
0915: //To change body of implemented methods use File | Settings | File Templates.
0916: }
0917:
0918: public void makePersistentAll(Object[] objects) {
0919: //To change body of implemented methods use File | Settings | File Templates.
0920: }
0921:
0922: public void makePersistentAll(Collection collection) {
0923: //To change body of implemented methods use File | Settings | File Templates.
0924: }
0925:
0926: public void deletePersistent(Object o) {
0927: //To change body of implemented methods use File | Settings | File Templates.
0928: }
0929:
0930: public void deletePersistentAll(Object[] objects) {
0931: //To change body of implemented methods use File | Settings | File Templates.
0932: }
0933:
0934: public void deletePersistentAll(Collection collection) {
0935: //To change body of implemented methods use File | Settings | File Templates.
0936: }
0937:
0938: public void makeTransient(Object o) {
0939: //To change body of implemented methods use File | Settings | File Templates.
0940: }
0941:
0942: public void makeTransientAll(Object[] objects) {
0943: //To change body of implemented methods use File | Settings | File Templates.
0944: }
0945:
0946: public void makeTransientAll(Collection collection) {
0947: //To change body of implemented methods use File | Settings | File Templates.
0948: }
0949:
0950: public void makeTransactional(Object o) {
0951: //To change body of implemented methods use File | Settings | File Templates.
0952: }
0953:
0954: public void makeTransactionalAll(Object[] objects) {
0955: //To change body of implemented methods use File | Settings | File Templates.
0956: }
0957:
0958: public void makeTransactionalAll(Collection collection) {
0959: //To change body of implemented methods use File | Settings | File Templates.
0960: }
0961:
0962: public void makeNontransactional(Object o) {
0963: //To change body of implemented methods use File | Settings | File Templates.
0964: }
0965:
0966: public void makeNontransactionalAll(Object[] objects) {
0967: //To change body of implemented methods use File | Settings | File Templates.
0968: }
0969:
0970: public void makeNontransactionalAll(Collection collection) {
0971: //To change body of implemented methods use File | Settings | File Templates.
0972: }
0973:
0974: public void retrieve(Object o) {
0975: //To change body of implemented methods use File | Settings | File Templates.
0976: }
0977:
0978: public void retrieveAll(Collection collection) {
0979: //To change body of implemented methods use File | Settings | File Templates.
0980: }
0981:
0982: public void retrieveAll(Collection collection, boolean b) {
0983: //To change body of implemented methods use File | Settings | File Templates.
0984: }
0985:
0986: public void retrieveAll(Object[] objects) {
0987: //To change body of implemented methods use File | Settings | File Templates.
0988: }
0989:
0990: public void retrieveAll(Object[] objects, boolean b) {
0991: //To change body of implemented methods use File | Settings | File Templates.
0992: }
0993:
0994: public void setUserObject(Object o) {
0995: //To change body of implemented methods use File | Settings | File Templates.
0996: }
0997:
0998: public Object getUserObject() {
0999: return null; //To change body of implemented methods use File | Settings | File Templates.
1000: }
1001:
1002: public PersistenceManagerFactory getPersistenceManagerFactory() {
1003: return null; //To change body of implemented methods use File | Settings | File Templates.
1004: }
1005:
1006: public Class getObjectIdClass(Class aClass) {
1007: return null; //To change body of implemented methods use File | Settings | File Templates.
1008: }
1009:
1010: public void setMultithreaded(boolean b) {
1011: //To change body of implemented methods use File | Settings | File Templates.
1012: }
1013:
1014: public boolean getMultithreaded() {
1015: return false; //To change body of implemented methods use File | Settings | File Templates.
1016: }
1017:
1018: public void setIgnoreCache(boolean b) {
1019: //To change body of implemented methods use File | Settings | File Templates.
1020: }
1021:
1022: public boolean getIgnoreCache() {
1023: return false; //To change body of implemented methods use File | Settings | File Templates.
1024: }
1025:
1026: public void addToTxList(StateManagerImp sm) {
1027: if (txActive) {
1028: txObjects.add(sm);
1029: }
1030: }
1031:
1032: public boolean isInterceptDfgFieldAccess() {
1033: return false; //To change body of implemented methods use File | Settings | File Templates.
1034: }
1035:
1036: public void setInterceptDfgFieldAccess(
1037: boolean interceptDfgFieldAccess) {
1038: //To change body of implemented methods use File | Settings | File Templates.
1039: }
1040:
1041: public void cancelQueryExecution() {
1042: //To change body of implemented methods use File | Settings | File Templates.
1043: }
1044:
1045: public boolean isDirty() {
1046: return !txObjects.isEmpty();
1047: }
1048:
1049: public Object getObjectByIDString(String value, boolean toValidate) {
1050: return null; //To change body of implemented methods use File | Settings | File Templates.
1051: }
1052:
1053: public Object newObjectIdInstance(Class pcClass, String str,
1054: boolean resolved) {
1055: return null; //To change body of implemented methods use File | Settings | File Templates.
1056: }
1057:
1058: public Object getObjectByIDString(String value, boolean toValidate,
1059: boolean resolved) {
1060: return null; //To change body of implemented methods use File | Settings | File Templates.
1061: }
1062:
1063: public void loadFetchGroup(Object pc, String name) {
1064: //To change body of implemented methods use File | Settings | File Templates.
1065: }
1066:
1067: public void flush(boolean retainValues) {
1068: //To change body of implemented methods use File | Settings | File Templates.
1069: }
1070:
1071: public Connection getJdbcConnection(String datastore) {
1072: return null; //To change body of implemented methods use File | Settings | File Templates.
1073: }
1074:
1075: public String getConnectionURL(String dataStore) {
1076: return null; //To change body of implemented methods use File | Settings | File Templates.
1077: }
1078:
1079: public String getConnectionDriverName(String dataStore) {
1080: return null; //To change body of implemented methods use File | Settings | File Templates.
1081: }
1082:
1083: public void makeTransientRecursive(Object pc) {
1084: //To change body of implemented methods use File | Settings | File Templates.
1085: }
1086:
1087: public List versantAllDirtyInstances() {
1088: if (txObjects.isEmpty())
1089: return Collections.EMPTY_LIST;
1090: return new ArrayList(txObjects);
1091: }
1092:
1093: public void flushIfDepOn(int[] cmdBits) {
1094: flush();
1095: }
1096:
1097: public void setDatastoreTxLocking(int mode) {
1098: int policy;
1099: switch (mode) {
1100: case VersantPersistenceManager.LOCKING_NONE:
1101: policy = StorageManager.LOCK_POLICY_NONE;
1102: break;
1103: case VersantPersistenceManager.LOCKING_FIRST:
1104: policy = StorageManager.LOCK_POLICY_FIRST;
1105: break;
1106: case VersantPersistenceManager.LOCKING_ALL:
1107: policy = StorageManager.LOCK_POLICY_ALL;
1108: break;
1109: default:
1110: throw BindingSupportImpl.getInstance().invalidOperation(
1111: "Invalid datastoreTxLocking mode: " + mode);
1112: }
1113: storageMan.setLockingPolicy(policy);
1114: }
1115:
1116: public int getDatastoreTxLocking() {
1117: switch (storageMan.getLockingPolicy()) {
1118: case StorageManager.LOCK_POLICY_NONE:
1119: return VersantPersistenceManager.LOCKING_NONE;
1120: case StorageManager.LOCK_POLICY_FIRST:
1121: return VersantPersistenceManager.LOCKING_FIRST;
1122: case StorageManager.LOCK_POLICY_ALL:
1123: return VersantPersistenceManager.LOCKING_ALL;
1124: }
1125: return VersantPersistenceManager.LOCKING_NONE;
1126: }
1127:
1128: public Object getObjectByIdFromCache(Object oid) {
1129: return null;
1130: }
1131:
1132: public boolean isHollow(Object pc) {
1133: return false;
1134: }
1135:
1136: public boolean hasIdentity(Object pc) {
1137: return false;
1138: }
1139:
1140: public void logEvent(int level, String description, int ms) {
1141: //To change body of implemented methods use File | Settings | File Templates.
1142: }
1143:
1144: public int getObjectsById(Object[] oids, int length, Object[] data,
1145: int stateFieldNo, int classMetaDataIndex) {
1146: return 0; //To change body of implemented methods use File | Settings | File Templates.
1147: }
1148:
1149: public javax.jdo.Query versantNewNamedQuery(Class cls,
1150: String queryName) {
1151: return null; //To change body of implemented methods use File | Settings | File Templates.
1152: }
1153:
1154: public Collection versantDetachCopy(Collection pcs,
1155: String fetchGroup) {
1156: return null; //To change body of implemented methods use File | Settings | File Templates.
1157: }
1158:
1159: public boolean isCheckModelConsistencyOnCommit() {
1160: return false; //To change body of implemented methods use File | Settings | File Templates.
1161: }
1162:
1163: public void setCheckModelConsistencyOnCommit(boolean on) {
1164: //To change body of implemented methods use File | Settings | File Templates.
1165: }
1166:
1167: public void checkModelConsistency() {
1168: //To change body of implemented methods use File | Settings | File Templates.
1169: }
1170:
1171: public Collection versantAttachCopy(Collection detached,
1172: boolean makeTransactional) {
1173: return null; //To change body of implemented methods use File | Settings | File Templates.
1174: }
1175:
1176: public Collection versantAttachCopy(Collection detached,
1177: boolean makeTransactional, boolean shallow) {
1178: return null; //To change body of implemented methods use File | Settings | File Templates.
1179: }
1180:
1181: public void setPmCacheRefType(Object pc, int type) {
1182: //To change body of implemented methods use File | Settings | File Templates.
1183: }
1184:
1185: public void setPmCacheRefType(Object[] pcs, int type) {
1186: //To change body of implemented methods use File | Settings | File Templates.
1187: }
1188:
1189: public void setPmCacheRefType(Collection col, int type) {
1190: //To change body of implemented methods use File | Settings | File Templates.
1191: }
1192:
1193: public void setPmCacheRefType(int type) {
1194: //To change body of implemented methods use File | Settings | File Templates.
1195: }
1196:
1197: public int getPmCacheRefType() {
1198: return 0; //To change body of implemented methods use File | Settings | File Templates.
1199: }
1200:
1201: public void setRetainConnectionInOptTx(boolean on) {
1202: //To change body of implemented methods use File | Settings | File Templates.
1203: }
1204:
1205: public void evictFromL2CacheAfterCommit(Object o) {
1206: //To change body of implemented methods use File | Settings | File Templates.
1207: }
1208:
1209: public void evictAllFromL2CacheAfterCommit(Object[] a) {
1210: //To change body of implemented methods use File | Settings | File Templates.
1211: }
1212:
1213: public void evictAllFromL2CacheAfterCommit(Collection c) {
1214: //To change body of implemented methods use File | Settings | File Templates.
1215: }
1216:
1217: public void evictAllFromL2CacheAfterCommit(Class cls,
1218: boolean includeSubclasses) {
1219: //To change body of implemented methods use File | Settings | File Templates.
1220: }
1221:
1222: public void evictAllFromL2CacheAfterCommit() {
1223: //To change body of implemented methods use File | Settings | File Templates.
1224: }
1225:
1226: public Object getOptimisticLockingValue(Object o) {
1227: return null; //To change body of implemented methods use File | Settings | File Templates.
1228: }
1229:
1230: public void addLifecycleListener(LifecycleListener listener,
1231: Class[] classes) {
1232: //To change body of implemented methods use File | Settings | File Templates.
1233: }
1234:
1235: public void removeLifecycleListener(LifecycleListener listener) {
1236: //To change body of implemented methods use File | Settings | File Templates.
1237: }
1238:
1239: public OID getInternalOID(PersistenceCapable pc) {
1240: return getStateManager(pc).getOID();
1241: }
1242:
1243: public PCStateMan getInternalSM(PersistenceCapable pc) {
1244: throw new RuntimeException("NOT IMPLEMENTED");
1245: }
1246:
1247: public StorageManager getStorageManager() {
1248: return storageMan;
1249: }
1250:
1251: /**
1252: * TODO: move to base class
1253: * Convert all PC, VersantOid and objectid-class params to OIDs. This
1254: * makes it possible to pass an OID instead of a PC instance for PC
1255: * parameters.
1256: */
1257: public void convertPcParamsToOID(Object[] params) {
1258: if (params == null)
1259: return;
1260: int n = params.length;
1261: for (int i = 0; i < n; i++) {
1262: Object param = params[i];
1263: if (param == null)
1264: continue;
1265: if (param instanceof Collection) {
1266: List l = new ArrayList((Collection) param);
1267: for (int j = 0; j < l.size(); j++) {
1268: Object o = (Object) l.get(j);
1269: o = convertPcParamsToOIDImp(o, i);
1270: if (o instanceof OID) {
1271: l.set(j, o);
1272: }
1273: }
1274: params[i] = l;
1275: } else {
1276: params[i] = convertPcParamsToOIDImp(param, i);
1277: }
1278: }
1279: }
1280:
1281: private Object convertPcParamsToOIDImp(Object param, int paramIndex) {
1282: if (param == null)
1283: return param;
1284: if (param instanceof PersistenceCapable) {
1285: PersistenceCapable pc = (PersistenceCapable) param;
1286: if (pc.jdoGetPersistenceManager() != proxy) {
1287: if (pc.jdoGetPersistenceManager() != null) {
1288: throw BindingSupportImpl
1289: .getInstance()
1290: .invalidOperation(
1291: "PC parameter "
1292: + paramIndex
1293: + " is managed by "
1294: + pc
1295: .jdoGetPersistenceManager()
1296: + " (this is " + proxy
1297: + "): " + pc.getClass()
1298: + ": " + Utils.toString(pc));
1299: } else {
1300: throw BindingSupportImpl.getInstance()
1301: .invalidOperation(
1302: "PC parameter " + paramIndex
1303: + " is transient: "
1304: + pc.getClass() + ": "
1305: + Utils.toString(pc));
1306: }
1307: }
1308: param = getInternalOID((PersistenceCapable) param);
1309: } else if (param instanceof VersantOid) {
1310: // datastore identity OID parameter
1311: OID oid = modelMetaData
1312: .convertJDOGenieOIDtoOID((VersantOid) param);
1313: param = convertNewToActual(oid);
1314: } else {
1315: ClassMetaData cmd = modelMetaData
1316: .getClassMetaDataForObjectIdClass(param.getClass());
1317: if (cmd != null) { // app identity objectid-class parameter
1318: OID oid = cmd.createOID(false);
1319: oid.fillFromPK(param);
1320: param = oid;
1321: }
1322: }
1323: return param;
1324: }
1325: }
|