org.eclipse.persistence.eis.EISOrderedCollectionChangeRecord Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of org.eclipse.persistence.core Show documentation
Show all versions of org.eclipse.persistence.core Show documentation
EclipseLink build based upon Git transaction ecdf3c32c4
/*
* Copyright (c) 1998, 2018 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
// Contributors:
// Oracle - initial API and implementation from Oracle TopLink
package org.eclipse.persistence.eis;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.persistence.internal.sessions.CollectionChangeRecord;
import org.eclipse.persistence.internal.sessions.ObjectChangeSet;
import org.eclipse.persistence.mappings.DatabaseMapping;
/**
* INTERNAL:
* Capture the changes for an ordered collection where
* the entire collection is simply replaced if it has changed.
*/
public class EISOrderedCollectionChangeRecord extends CollectionChangeRecord implements org.eclipse.persistence.sessions.changesets.EISOrderedCollectionChangeRecord {
/** The added stuff. */
private List adds;
/** The indexes into the new collection of the elements that were added. */
private int[] addIndexes;
/** The moved stuff. */
private List moves;
/** The index pairs of the elements that were moved (before and after indexes). */
private int[][] moveIndexPairs;
/** The removed stuff. */
private List removes;
/** The indexes into the old collection of the elements that were removed. */
private int[] removeIndexes;
/**
* Construct a ChangeRecord that can be used to represent the changes to
* an ordered collection.
*/
public EISOrderedCollectionChangeRecord(ObjectChangeSet owner, String attributeName, DatabaseMapping mapping) {
super();
this.owner = owner;
this.attribute = attributeName;
this.mapping = mapping;
}
/**
* Add an added change set.
*/
public void addAddedChangeSet(Object changeSet, int index) {
getAdds().add(changeSet);
setAddIndexes(this.addTo(index, getAddIndexes()));
}
/**
* Add an moved change set.
*/
public void addMovedChangeSet(Object changeSet, int oldIndex, int newIndex) {
getMoves().add(changeSet);
int[] pair = new int[2];
pair[0] = oldIndex;
pair[1] = newIndex;
setMoveIndexPairs(this.addTo(pair, getMoveIndexPairs()));
}
/**
* Add an removed change set.
*/
public void addRemovedChangeSet(Object changeSet, int index) {
getRemoves().add(changeSet);
setRemoveIndexes(this.addTo(index, getRemoveIndexes()));
}
/**
* Add the int to the end of the array.
* Return the new array.
*/
private int[] addTo(int newInt, int[] oldArray) {
int oldCount = oldArray.length;
int[] newArray = new int[oldCount + 1];
System.arraycopy(oldArray, 0, newArray, 0, oldCount);
newArray[oldCount] = newInt;// zero-based index
return newArray;
}
/**
* Add the int[] to the end of the array.
* Return the new array.
*/
private int[][] addTo(int[] newInts, int[][] oldArray) {
int oldCount = oldArray.length;
int[][] newArray = new int[oldCount + 1][];
System.arraycopy(oldArray, 0, newArray, 0, oldCount);
newArray[oldCount] = newInts;// zero-based index
return newArray;
}
/**
* Return the specified add.
*/
private Object getAdd(int index) {
return this.getAdds().get(index);
}
/**
* ADVANCED:
* Return the indexes into the new collection of
* the elements that were added.
*/
public int[] getAddIndexes() {
if (addIndexes == null) {
addIndexes = new int[0];
}
return addIndexes;
}
/**
* ADVANCED:
* Return the entries for all the elements added to the new collection.
* The contents of this collection is determined by the mapping that
* populated it
*/
public List getAdds() {
if (adds == null) {
adds = new ArrayList(2);// keep it as small as possible
}
return adds;
}
/**
* Return the index in the adds of the specified change set,
* without triggering the instantiation of the collection.
*/
private int getAddsIndexOf(Object changeSet) {
if (adds == null) {
return -1;
}
return adds.indexOf(changeSet);
}
/**
* Return the number of adds, without triggering
* the instantiation of the collection.
*/
private int getAddsSize() {
if (adds == null) {
return 0;
}
return adds.size();
}
/**
* Return the specified move.
*/
private Object getMove(int index) {
return this.getMoves().get(index);
}
/**
* Return the specified "before" move index.
*/
private int getBeforeMoveIndex(int index) {
int[][] pairs = getMoveIndexPairs();
return pairs[index][0];
}
/**
* ADVANCED:
* Return the indexes of the elements that were simply moved
* within the collection.
* Each element in the outer array is another two-element
* array where the first entry [0] is the index of the object in
* the old collection and the second entry [1] is the index
* of the object in the new collection. These two indexes
* can be equal.
*/
public int[][] getMoveIndexPairs() {
if (moveIndexPairs == null) {
moveIndexPairs = new int[0][0];
}
return moveIndexPairs;
}
/**
* ADVANCED:
* Return the entries for all the elements that were simply shuffled
* within the collection.
* The contents of this collection is determined by the mapping that
* populated it
*/
public List getMoves() {
if (moves == null) {
moves = new ArrayList(2);// keep it as small as possible
}
return moves;
}
/**
* Return the index in the moves of the specified change set,
* without triggering the instantiation of the collection.
*/
private int getMovesIndexOf(Object changeSet) {
if (moves == null) {
return -1;
}
return moves.indexOf(changeSet);
}
/**
* Return the number of moves, without triggering
* the instantiation of the collection.
*/
private int getMovesSize() {
if (moves == null) {
return 0;
}
return moves.size();
}
/**
* ADVANCED:
* Return the entries for all the elements in the new collection.
* The contents of this collection is determined by the mapping that
* populated it
*/
public List getNewCollection() {
int newSize = getNewCollectionSize();
List newCollection = new ArrayList(newSize);
int[] localAddIndexes = addIndexes;
if (localAddIndexes == null) {
localAddIndexes = new int[0];
}
int[][] localMoveIndexPairs = moveIndexPairs;
if (localMoveIndexPairs == null) {
localMoveIndexPairs = new int[0][0];
}
int addIndex = 0;
int moveIndex = 0;
for (int i = 0; i < newSize; i++) {
if ((addIndex < localAddIndexes.length) && (localAddIndexes[addIndex] == i)) {
newCollection.add(this.getAdd(addIndex));
addIndex++;
continue;
}
if ((moveIndex < localMoveIndexPairs.length) && (localMoveIndexPairs[moveIndex][1] == i)) {
newCollection.add(this.getMove(moveIndex));
moveIndex++;
continue;
}
throw new IllegalStateException(String.valueOf(i));
}
return newCollection;
}
/**
* Return the number of elements in the new collection,
* without triggering the instantiation of the collections.
*/
private int getNewCollectionSize() {
return this.getAddsSize() + this.getMovesSize();
}
/**
* Return the specified remove index.
*/
private int getRemoveIndex(int index) {
return this.getRemoveIndexes()[index];
}
/**
* ADVANCED:
* Return the indexes into the old collection of
* the elements that were removed.
*/
public int[] getRemoveIndexes() {
if (removeIndexes == null) {
removeIndexes = new int[0];
}
return removeIndexes;
}
/**
* ADVANCED:
* Return the entries for all the elements removed from the old collection.
* The contents of this collection is determined by the mapping that
* populated it
*/
public List getRemoves() {
if (removes == null) {
removes = new ArrayList(2);// keep it as small as possible
}
return removes;
}
/**
* Return the index in the removes of the specified change set,
* without triggering the instantiation of the collection.
*/
private int getRemovesIndexOf(Object changeSet) {
if (removes == null) {
return -1;
}
return removes.indexOf(changeSet);
}
/**
* Return whether any adds have been recorded with the change record.
* Directly reference the instance variable, so as to not trigger the lazy instantiation.
*/
private boolean hasAdds() {
return (addIndexes != null) && (addIndexes.length != 0);
}
/**
* Return whether any changes have been recorded with the change record.
*/
public boolean hasChanges() {
if (this.hasAdds() || this.hasRemoves() || this.getOwner().isNew()) {
return true;
}
// BUG#.... the moves always contain everything, must check if any indexes are different.
if (hasMoves()) {
for (int index = 0; index < moveIndexPairs.length; index++) {
if (moveIndexPairs[index][0] != moveIndexPairs[index][1]) {
return true;
}
}
}
return false;
}
/**
* Return whether any moves have been recorded with the change record.
* Directly reference the instance variable, so as to not trigger the lazy instantiation.
*/
private boolean hasMoves() {
return (moveIndexPairs != null) && (moveIndexPairs.length != 0);
}
/**
* Return whether any removes have been recorded with the change record.
* Directly reference the instance variable, so as to not trigger the lazy instantiation.
*/
private boolean hasRemoves() {
return (removeIndexes != null) && (removeIndexes.length != 0);
}
/**
* Remove the specified slot from the array.
* Return the new array.
*/
private int[] removeFrom(int removeIndex, int[] oldArray) {
int oldCount = oldArray.length;
int[] newArray = new int[oldCount - 1];
System.arraycopy(oldArray, 0, newArray, 0, removeIndex);
System.arraycopy(oldArray, removeIndex + 1, newArray, removeIndex, oldCount - removeIndex - 1);
return newArray;
}
/**
* Remove the specified slot from the array.
* Return the new array.
*/
private int[][] removeFrom(int removeIndex, int[][] oldArray) {
int oldCount = oldArray.length;
int[][] newArray = new int[oldCount - 1][];
System.arraycopy(oldArray, 0, newArray, 0, removeIndex);
System.arraycopy(oldArray, removeIndex + 1, newArray, removeIndex, oldCount - removeIndex - 1);
return newArray;
}
/**
* The specified change set was added earlier;
* cancel it out.
*/
private void cancelAddedChangeSet(Object changeSet) {
int changeSetIndex = this.getAddsIndexOf(changeSet);
if (changeSetIndex == -1) {
throw new IllegalStateException(changeSet.toString());
}
this.getAdds().remove(changeSetIndex);
this.setAddIndexes(this.removeFrom(changeSetIndex, this.getAddIndexes()));
}
/**
* Attempt to remove the specified change set
* from the collection of moved change sets.
* Return true if the change set was moved earlier
* and was successfully removed.
*/
private boolean removeMovedChangeSet(Object changeSet) {
int changeSetIndex = this.getMovesIndexOf(changeSet);
if (changeSetIndex == -1) {
return false;
}
this.getMoves().remove(changeSetIndex);
int beforeMoveIndex = this.getBeforeMoveIndex(changeSetIndex);
this.setMoveIndexPairs(this.removeFrom(changeSetIndex, this.getMoveIndexPairs()));
// now move the change set over to the collection of removes
this.addRemovedChangeSet(changeSet, beforeMoveIndex);
return true;
}
/**
* Attempt to restore the specified change set.
* Return true if the change set was removed earlier
* and was successfully restored to the end of
* the collection.
*/
private boolean restoreRemovedChangeSet(Object changeSet) {
int changeSetIndex = this.getRemovesIndexOf(changeSet);
if (changeSetIndex == -1) {
return false;
}
this.getRemoves().remove(changeSetIndex);
int removeIndex = this.getRemoveIndex(changeSetIndex);
this.setRemoveIndexes(this.removeFrom(changeSetIndex, this.getRemoveIndexes()));
// now move the change set over to the collection of moves
this.addMovedChangeSet(changeSet, removeIndex, this.getNewCollectionSize());
return true;
}
/**
* Set the indexes into the new collection of
* the elements that were added.
*/
private void setAddIndexes(int[] addIndexes) {
this.addIndexes = addIndexes;
}
/**
* Set the indexes of the elements that were moved.
*/
private void setMoveIndexPairs(int[][] moveIndexPairs) {
this.moveIndexPairs = moveIndexPairs;
}
/**
* Set the indexes into the old collection of
* the elements that were removed.
*/
private void setRemoveIndexes(int[] removeIndexes) {
this.removeIndexes = removeIndexes;
}
/**
* Add a change set after it has been applied.
*/
public void simpleAddChangeSet(Object changeSet) {
// check whether the change set was removed earlier
if (!this.restoreRemovedChangeSet(changeSet)) {
// the change set is tacked on the end of the new collection
this.addAddedChangeSet(changeSet, this.getNewCollectionSize());
}
}
/**
* Remove a change set after it has been applied.
*/
public void simpleRemoveChangeSet(Object changeSet) {
// the change set must have been either moved or added earlier
if (!this.removeMovedChangeSet(changeSet)) {
this.cancelAddedChangeSet(changeSet);
}
}
}