Ejemplo n.º 1
0
  /**
   * 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;
    }
  }