/** INTERNAL: Build and return a new element based on the specified element. */
  public Object buildElementFromElement(Object element, MergeManager mergeManager) {
    if (this.shouldMergeCascadeParts(mergeManager)) {
      ObjectChangeSet objectChangeSet = null;
      if (mergeManager.getSession().isUnitOfWork()) {
        UnitOfWorkChangeSet uowChangeSet =
            (UnitOfWorkChangeSet)
                ((UnitOfWorkImpl) mergeManager.getSession()).getUnitOfWorkChangeSet();
        if (uowChangeSet != null) {
          objectChangeSet = (ObjectChangeSet) uowChangeSet.getObjectChangeSetForClone(element);
        }
      }
      Object mergeElement = mergeManager.getObjectToMerge(element);
      mergeManager.mergeChanges(mergeElement, objectChangeSet);
    }

    return mergeManager.getTargetVersionOfSourceObject(element);
  }
  /**
   * Merge changes from the source to the target object. Make the necessary removals and adds and
   * map key modifications.
   */
  private void mergeChangesIntoObjectWithoutOrder(
      Object target, ChangeRecord changeRecord, Object source, MergeManager mergeManager) {
    EISCollectionChangeRecord sdkChangeRecord = (EISCollectionChangeRecord) changeRecord;
    ContainerPolicy cp = this.getContainerPolicy();
    AbstractSession session = mergeManager.getSession();

    Object targetCollection = null;
    if (sdkChangeRecord.getOwner().isNew()) {
      targetCollection = cp.containerInstance(sdkChangeRecord.getAdds().size());
    } else {
      targetCollection = this.getRealCollectionAttributeValueFromObject(target, session);
    }

    Vector removes = sdkChangeRecord.getRemoves();
    Vector adds = sdkChangeRecord.getAdds();
    Vector changedMapKeys = sdkChangeRecord.getChangedMapKeys();

    synchronized (targetCollection) {
      for (Enumeration stream = removes.elements(); stream.hasMoreElements(); ) {
        Object removeElement =
            this.buildRemovedElementFromChangeSet(stream.nextElement(), mergeManager);

        Object targetElement = null;
        for (Object iter = cp.iteratorFor(targetCollection); cp.hasNext(iter); ) {
          targetElement = cp.next(iter, session);
          if (this.compareElements(targetElement, removeElement, session)) {
            break; // matching element found - skip the rest of them
          }
        }
        if (targetElement != null) {
          // a matching element was found, remove it
          cp.removeFrom(targetElement, targetCollection, session);
        }
      }

      for (Enumeration stream = adds.elements(); stream.hasMoreElements(); ) {
        Object addElement = this.buildAddedElementFromChangeSet(stream.nextElement(), mergeManager);
        cp.addInto(addElement, targetCollection, session);
      }

      for (Enumeration stream = changedMapKeys.elements(); stream.hasMoreElements(); ) {
        Object changedMapKeyElement =
            this.buildAddedElementFromChangeSet(stream.nextElement(), mergeManager);
        Object originalElement =
            ((UnitOfWorkImpl) session).getOriginalVersionOfObject(changedMapKeyElement);
        cp.removeFrom(originalElement, targetCollection, session);
        cp.addInto(changedMapKeyElement, targetCollection, session);
      }
    }

    // reset the attribute to allow for set method to re-morph changes if the collection is not
    // being stored directly
    this.setRealAttributeValueInObject(target, targetCollection);
  }
  /** INTERNAL: Build and return a new element based on the change set. */
  public Object buildAddedElementFromChangeSet(Object changeSet, MergeManager mergeManager) {
    ObjectChangeSet objectChangeSet = (ObjectChangeSet) changeSet;

    if (this.shouldMergeCascadeParts(mergeManager)) {
      Object targetElement = null;
      if (mergeManager.shouldMergeChangesIntoDistributedCache()) {
        targetElement =
            objectChangeSet.getTargetVersionOfSourceObject(mergeManager.getSession(), true);
      } else {
        targetElement = objectChangeSet.getUnitOfWorkClone();
      }
      mergeManager.mergeChanges(targetElement, objectChangeSet);
    }

    return this.buildElementFromChangeSet(changeSet, mergeManager);
  }
  /**
   * INTERNAL: Merge changes from the source to the target object. Simply replace the entire target
   * collection.
   */
  public void mergeIntoObject(
      Object target, boolean isTargetUnInitialized, Object source, MergeManager mergeManager) {
    ContainerPolicy cp = this.getContainerPolicy();
    AbstractSession session = mergeManager.getSession();

    Object sourceCollection = this.getRealCollectionAttributeValueFromObject(source, session);
    Object targetCollection = cp.containerInstance(cp.sizeFor(sourceCollection));

    for (Object iter = cp.iteratorFor(sourceCollection); cp.hasNext(iter); ) {
      Object targetElement = this.buildElementFromElement(cp.next(iter, session), mergeManager);
      cp.addInto(targetElement, targetCollection, session);
    }

    // reset the attribute to allow for set method to re-morph changes if the collection is not
    // being stored directly
    this.setRealAttributeValueInObject(target, targetCollection);
  }
  /**
   * Merge changes from the source to the target object. Simply replace the entire target
   * collection.
   */
  private void mergeChangesIntoObjectWithOrder(
      Object target, ChangeRecord changeRecord, Object source, MergeManager mergeManager) {
    ContainerPolicy cp = this.getContainerPolicy();
    AbstractSession session = mergeManager.getSession();

    Vector changes = ((EISOrderedCollectionChangeRecord) changeRecord).getNewCollection();
    Object targetCollection = cp.containerInstance(changes.size());

    for (Enumeration stream = changes.elements(); stream.hasMoreElements(); ) {
      Object targetElement =
          this.buildAddedElementFromChangeSet(stream.nextElement(), mergeManager);
      cp.addInto(targetElement, targetCollection, session);
    }

    // reset the attribute to allow for set method to re-morph changes if the collection is not
    // being stored directly
    this.setRealAttributeValueInObject(target, targetCollection);
  }
 /** Build and return a new element based on the change set. */
 protected Object buildElementFromChangeSet(Object changeSet, MergeManager mergeManager) {
   return ((ObjectChangeSet) changeSet).getTargetVersionOfSourceObject(mergeManager.getSession());
 }