use of org.eclipse.persistence.internal.sessions.DirectCollectionChangeRecord in project eclipselink by eclipse-ee4j.
the class DirectCollectionMapping method simpleRemoveFromCollectionChangeRecord.
protected void simpleRemoveFromCollectionChangeRecord(Object objectToRemove, Integer index, boolean isSet, ObjectChangeSet changeSet, AbstractSession session, boolean isChangeApplied) {
DirectCollectionChangeRecord collectionChangeRecord = (DirectCollectionChangeRecord) changeSet.getChangesForAttributeNamed(getAttributeName());
if (collectionChangeRecord == null) {
collectionChangeRecord = new DirectCollectionChangeRecord(changeSet);
collectionChangeRecord.setAttribute(getAttributeName());
collectionChangeRecord.setMapping(this);
changeSet.addChange(collectionChangeRecord);
Object collection = getRealAttributeValueFromObject(changeSet.getUnitOfWorkClone(), session);
if (this.listOrderField != null) {
List originalListCopy = new ArrayList((List) collection);
// index is not null because IndirectList does remove through indexOf.
if (isSet) {
originalListCopy.set(index, objectToRemove);
} else {
originalListCopy.add(index, objectToRemove);
}
collectionChangeRecord.setOriginalCollection(originalListCopy);
collectionChangeRecord.setLatestCollection(collection);
} else {
collectionChangeRecord.storeDatabaseCounts(collection, getContainerPolicy(), session);
collectionChangeRecord.setFirstToRemoveAlreadyOutCollection(isChangeApplied);
if (isSet) {
collectionChangeRecord.setFirstToAddAlreadyInCollection(isChangeApplied);
}
}
}
if (!collectionChangeRecord.isDeferred() && this.listOrderField == null) {
collectionChangeRecord.addRemoveChange(objectToRemove, 1);
}
}
use of org.eclipse.persistence.internal.sessions.DirectCollectionChangeRecord in project eclipselink by eclipse-ee4j.
the class DirectCollectionMapping method mergeChangesIntoObject.
/**
* INTERNAL:
* Merge changes from the source to the target object.
* Because this is a collection mapping, values are added to or removed from the
* collection based on the changeset
*/
@Override
public void mergeChangesIntoObject(Object target, ChangeRecord changeRecord, Object source, MergeManager mergeManager, AbstractSession targetSession) {
if (this.descriptor.getCachePolicy().isProtectedIsolation() && !this.isCacheable && !targetSession.isProtectedSession()) {
setAttributeValueInObject(target, this.indirectionPolicy.buildIndirectObject(new ValueHolder<>(null)));
return;
}
ContainerPolicy containerPolicy = getContainerPolicy();
Object valueOfTarget = null;
AbstractSession session = mergeManager.getSession();
DirectCollectionChangeRecord directCollectionChangeRecord = (DirectCollectionChangeRecord) changeRecord;
// Check to see if the target has an instantiated collection
if ((isAttributeValueInstantiated(target)) && (!changeRecord.getOwner().isNew())) {
if (isSynchronizeOnMerge) {
valueOfTarget = getRealCollectionAttributeValueFromObject(target, session);
} else {
valueOfTarget = containerPolicy.cloneFor(getRealCollectionAttributeValueFromObject(target, session));
}
} else {
// if not create an instance of the collection
valueOfTarget = containerPolicy.containerInstance(directCollectionChangeRecord.getAddObjectMap().size());
}
if (!isAttributeValueInstantiated(target)) {
if (mergeManager.shouldMergeChangesIntoDistributedCache()) {
return;
}
for (Object iterator = containerPolicy.iteratorFor(getRealCollectionAttributeValueFromObject(source, session)); containerPolicy.hasNext(iterator); ) {
containerPolicy.addInto(containerPolicy.next(iterator, session), valueOfTarget, session);
}
} else {
Object synchronizationTarget = valueOfTarget;
// not the wrapper as the clone synchs on the delegate, see bug#5685287.
if (valueOfTarget instanceof IndirectCollection) {
synchronizationTarget = ((IndirectCollection) valueOfTarget).getDelegateObject();
if (((DirectCollectionChangeRecord) changeRecord).orderHasBeenRepaired() && (valueOfTarget instanceof IndirectList)) {
((IndirectList) valueOfTarget).setIsListOrderBrokenInDb(false);
}
}
if (isSynchronizeOnMerge) {
synchronized (synchronizationTarget) {
mergeAddRemoveChanges(valueOfTarget, synchronizationTarget, directCollectionChangeRecord, mergeManager, session);
}
} else {
mergeAddRemoveChanges(valueOfTarget, synchronizationTarget, directCollectionChangeRecord, mergeManager, session);
}
}
setRealAttributeValueInObject(target, valueOfTarget);
}
use of org.eclipse.persistence.internal.sessions.DirectCollectionChangeRecord in project eclipselink by eclipse-ee4j.
the class DirectCollectionMapping method compareListsForChange.
/**
* INTERNAL:
* This method is used to calculate the differences between two Lists.
*/
public void compareListsForChange(List oldList, List newList, ChangeRecord changeRecord, AbstractSession session) {
// Maps objects (null included) in newList and oldList to an array of two Sets:
// the first one contains indexes of the object in oldList, the second - in newList.
// Contains only the objects for which the set of indexes in newList and oldList are different;
// only changed indexes appear in the sets (therefore the old index set and new index set don't intersect).
// Examples:
// obj was first (index 0) in oldList; first and second (indexes 0 and 1)in newList: obj -> {{}, {1}};
// obj was not in oldList; first in newList: obj -> {null, {0}};
// obj was first in oldList; not in newList: obj -> {{0}, null};
// obj was first and second in oldList; first in newList: obj -> {{1}, {}};
// Note the difference between null and empty set:
// empty set means there's at least one index (the same in oldList and newList - otherwise it would've been in the set);
// null means there's no indexes.
// That helps during deletion - if we know there is no remaining duplicates for the object to be removed
// we can delete it without checking its index (which allows delete several duplicates in one sql).
// Map entry sets with no new and no old indexes removed.
int nOldSize = oldList == null ? 0 : oldList.size();
int nNewSize = newList == null ? 0 : newList.size();
HashMap<Object, Set[]> changedIndexes = new HashMap<>(Math.max(nOldSize, nNewSize));
// for each object in oldList insert all its indexes in oldList into the old indexes set corresponding to each object.
if (oldList != null) {
for (int i = 0; i < nOldSize; i++) {
Object obj = oldList.get(i);
Set[] indexes = changedIndexes.get(obj);
if (indexes == null) {
// the first index found for the object.
indexes = new Set[] { new HashSet(), null };
changedIndexes.put(obj, indexes);
}
indexes[0].add(i);
}
}
// helper set to store objects for which entries into changedIndexes has been removed:
// if an entry for the object is created again, it will have an empty old indexes set (rather than null)
// to indicate that the object has been on the oldList, too.
HashSet removedFromChangedIndexes = new HashSet();
HashSet dummySet = new HashSet(0);
// if the object doesn't have the same index in oldList - insert the index into new indexes set.
if (newList != null) {
for (int i = 0; i < nNewSize; i++) {
Object obj = newList.get(i);
Set[] indexes = changedIndexes.get(obj);
if (indexes == null) {
// the first index found for the object - or was found and removed before.
if (removedFromChangedIndexes.contains(obj)) {
// the object also exists in oldList
indexes = new Set[] { dummySet, new HashSet() };
} else {
// the object does not exist in oldList
indexes = new Set[] { null, new HashSet() };
}
changedIndexes.put(obj, indexes);
// the object doesn't have this index in oldList - add the index to new indexes set.
indexes[1].add(i);
} else {
if (indexes[0] == null || !indexes[0].contains(i)) {
// the object doesn't have this index in oldList - add the index to new indexes set.
if (indexes[1] == null) {
indexes[1] = new HashSet();
}
indexes[1].add(i);
} else {
// the object has this index in oldList - remove the index from the old indexes set.
indexes[0].remove(i);
if (indexes[0].isEmpty()) {
// no old indexes left for the object.
if (indexes[1] == null || indexes[1].isEmpty()) {
// no new indexes left, too - remove the entry for the object.
changedIndexes.remove(obj);
// store the object in case it has another index on newList
removedFromChangedIndexes.add(obj);
}
}
}
}
}
}
((DirectCollectionChangeRecord) changeRecord).setChangedIndexes(changedIndexes);
((DirectCollectionChangeRecord) changeRecord).setOldSize(nOldSize);
((DirectCollectionChangeRecord) changeRecord).setNewSize(nNewSize);
}
use of org.eclipse.persistence.internal.sessions.DirectCollectionChangeRecord in project eclipselink by eclipse-ee4j.
the class DirectCollectionMapping method simpleAddToCollectionChangeRecord.
protected void simpleAddToCollectionChangeRecord(Object objectToAdd, Integer index, boolean isSet, ObjectChangeSet changeSet, AbstractSession session, boolean isChangeApplied) {
DirectCollectionChangeRecord collectionChangeRecord = (DirectCollectionChangeRecord) changeSet.getChangesForAttributeNamed(getAttributeName());
if (collectionChangeRecord == null) {
collectionChangeRecord = new DirectCollectionChangeRecord(changeSet);
collectionChangeRecord.setAttribute(getAttributeName());
collectionChangeRecord.setMapping(this);
changeSet.addChange(collectionChangeRecord);
Object collection = getRealAttributeValueFromObject(changeSet.getUnitOfWorkClone(), session);
if (this.listOrderField != null) {
List originalListCopy = new ArrayList((List) collection);
// collection already contains the added object - to bring it to the original state it should be removed
if (index == null) {
originalListCopy.remove(originalListCopy.size() - 1);
} else {
// intValue() is essential - otherwise invokes remove(Object)
originalListCopy.remove(index.intValue());
}
collectionChangeRecord.setOriginalCollection(originalListCopy);
collectionChangeRecord.setLatestCollection(collection);
} else {
collectionChangeRecord.storeDatabaseCounts(collection, getContainerPolicy(), session);
collectionChangeRecord.setFirstToAddAlreadyInCollection(isChangeApplied);
}
}
if (!collectionChangeRecord.isDeferred() && this.listOrderField == null) {
collectionChangeRecord.addAdditionChange(objectToAdd, 1);
}
}
use of org.eclipse.persistence.internal.sessions.DirectCollectionChangeRecord in project eclipselink by eclipse-ee4j.
the class DirectCollectionMapping method postUpdateWithChangeSet.
/**
* INTERNAL:
* Update private owned part.
*/
protected void postUpdateWithChangeSet(WriteObjectQuery writeQuery) throws DatabaseException {
ObjectChangeSet changeSet = writeQuery.getObjectChangeSet();
DirectCollectionChangeRecord changeRecord = (DirectCollectionChangeRecord) changeSet.getChangesForAttributeNamed(this.getAttributeName());
if (changeRecord == null) {
return;
}
for (int index = 0; index < getReferenceKeyFields().size(); index++) {
DatabaseField referenceKey = getReferenceKeyFields().get(index);
DatabaseField sourceKey = getSourceKeyFields().get(index);
Object sourceKeyValue = writeQuery.getTranslationRow().get(sourceKey);
writeQuery.getTranslationRow().put(referenceKey, sourceKeyValue);
}
for (Iterator iterator = changeRecord.getRemoveObjectMap().keySet().iterator(); iterator.hasNext(); ) {
Object object = iterator.next();
AbstractRecord thisRow = writeQuery.getTranslationRow().clone();
Object value = getFieldValue(object, writeQuery.getSession());
// Hey I might actually want to use an inner class here... ok array for now.
Object[] event = new Object[3];
event[0] = Delete;
if (value == null) {
// Bug 306075 - for deleting a null value from a collection
event[1] = getDeleteNullQuery();
} else {
thisRow.add(getDirectField(), value);
event[1] = getDeleteQuery();
}
event[2] = thisRow;
writeQuery.getSession().getCommitManager().addDataModificationEvent(this, event);
Integer count = (Integer) changeRecord.getCommitAddMap().get(object);
if (count != null) {
for (int counter = count; counter > 0; --counter) {
thisRow = writeQuery.getTranslationRow().clone();
thisRow.add(getDirectField(), value);
// Hey I might actually want to use an inner class here... ok array for now.
event = new Object[3];
event[0] = Insert;
event[1] = getInsertQuery();
event[2] = thisRow;
writeQuery.getSession().getCommitManager().addDataModificationEvent(this, event);
}
}
}
for (Iterator iterator = changeRecord.getAddObjectMap().keySet().iterator(); iterator.hasNext(); ) {
Object object = iterator.next();
Integer count = (Integer) changeRecord.getAddObjectMap().get(object);
for (int counter = count; counter > 0; --counter) {
AbstractRecord thisRow = writeQuery.getTranslationRow().clone();
Object value = object;
if (getValueConverter() != null) {
value = getValueConverter().convertObjectValueToDataValue(value, writeQuery.getSession());
}
thisRow.add(getDirectField(), value);
// Hey I might actually want to use an inner class here... ok array for now.
Object[] event = new Object[3];
event[0] = Insert;
event[1] = getInsertQuery();
event[2] = thisRow;
writeQuery.getSession().getCommitManager().addDataModificationEvent(this, event);
}
}
}
Aggregations