private void writeObject(ObjectOutputStream out) throws IOException { out.defaultWriteObject(); // Serialize local snapshots cache if (!isUsingSharedSnapshotCache()) { out.writeObject(objectStore.getDataRowCache()); } }
/** * Creates a new DataContext with parent DataChannel and ObjectStore. * * @since 1.2 */ public DataContext(DataChannel channel, ObjectStore objectStore) { // inject self as parent context if (objectStore != null) { this.objectStore = objectStore; objectStore.setContext(this); } if (channel != null) { attachToChannel(channel); } if (objectStore != null) { DataDomain domain = getParentDataDomain(); this.usingSharedSnaphsotCache = domain != null && objectStore.getDataRowCache() == domain.getSharedSnapshotCache(); } }
/** * If the parent channel is a DataContext, reverts local changes to make this context look like * the parent, if the parent channel is a DataDomain, reverts all changes. * * @since 1.2 */ @Override public void rollbackChangesLocally() { if (objectStore.hasChanges()) { GraphDiff diff = getObjectStore().getChanges(); getObjectStore().objectsRolledBack(); fireDataChannelRolledback(this, diff); } }
// serialization support private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { // TODO: most of this should be in the superclass, especially the code // connecting // super transient ivars // read non-transient properties in.defaultReadObject(); // deserialize local snapshots cache if (!isUsingSharedSnapshotCache()) { DataRowStore cache = (DataRowStore) in.readObject(); objectStore.setDataRowCache(cache); } // CayenneDataObjects have a transient DataContext // because at deserialize time the datacontext may need to be different // than the one at serialize time (for programmer defined reasons). // So, when a DataObject is resurrected because it's DataContext was // serialized, it will then set the objects DataContext to the correct // one // If deserialized "otherwise", it will not have a DataContext. synchronized (getObjectStore()) { Iterator<?> it = objectStore.getObjectIterator(); while (it.hasNext()) { Persistent object = (Persistent) it.next(); object.setObjectContext(this); } } // ... deferring initialization of transient properties of this context // till first // access, so that it can attach to Cayenne runtime using appropriate // thread // injector. }
/** * Reverts any changes that have occurred to objects registered with DataContext; also performs * cascading rollback of all parent DataContexts. */ @Override public void rollbackChanges() { if (objectStore.hasChanges()) { GraphDiff diff = getObjectStore().getChanges(); // call channel with changes BEFORE reverting them, so that any // interceptors // could record them if (channel != null) { channel.onSync(this, diff, DataChannel.ROLLBACK_CASCADE_SYNC); } getObjectStore().objectsRolledBack(); fireDataChannelRolledback(this, diff); } else { if (channel != null) { channel.onSync(this, new CompoundDiff(), DataChannel.ROLLBACK_CASCADE_SYNC); } } }
/** * Synchronizes with the parent channel, performing a flush or a commit. * * @since 1.2 */ GraphDiff flushToParent(boolean cascade) { if (this.getChannel() == null) { throw new CayenneRuntimeException("Cannot commit changes - channel is not set."); } int syncType = cascade ? DataChannel.FLUSH_CASCADE_SYNC : DataChannel.FLUSH_NOCASCADE_SYNC; ObjectStore objectStore = getObjectStore(); GraphDiff parentChanges = null; // prevent multiple commits occurring simultaneously synchronized (objectStore) { ObjectStoreGraphDiff changes = objectStore.getChanges(); boolean noop = isValidatingObjectsOnCommit() ? changes.validateAndCheckNoop() : changes.isNoop(); if (noop) { // need to clear phantom changes objectStore.postprocessAfterPhantomCommit(); } else { try { parentChanges = getChannel().onSync(this, changes, syncType); // note that this is a hack resulting from a fix to // CAY-766... To // support // valid object state in PostPersist callback, // 'postprocessAfterCommit' is // invoked by DataDomain.onSync(..). Unless the parent is // DataContext, // and // this method is not invoked!! As a result, PostPersist // will contain // temp // ObjectIds in nested contexts and perm ones in flat // contexts. // Pending better callback design ..... if (objectStore.hasChanges()) { objectStore.postprocessAfterCommit(parentChanges); } // this event is caught by peer nested DataContexts to // synchronize the // state fireDataChannelCommitted(this, changes); } // "catch" is needed to unwrap OptimisticLockExceptions catch (CayenneRuntimeException ex) { Throwable unwound = Util.unwindException(ex); if (unwound instanceof CayenneRuntimeException) { throw (CayenneRuntimeException) unwound; } else { throw new CayenneRuntimeException("Commit Exception", unwound); } } } // merge changes from parent as well as changes caused by lifecycle // event // callbacks/listeners... CompoundDiff diff = new CompoundDiff(); diff.addAll(objectStore.getLifecycleEventInducedChanges()); if (parentChanges != null) { diff.add(parentChanges); } // this event is caught by child DataContexts to update temporary // ObjectIds with permanent if (!diff.isNoop()) { fireDataChannelCommitted(getChannel(), diff); } return diff; } }