Search in sources :

Example 6 with DirectCollectionChangeRecord

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);
    }
}
Also used : ArrayList(java.util.ArrayList) DirectCollectionChangeRecord(org.eclipse.persistence.internal.sessions.DirectCollectionChangeRecord) List(java.util.List) IndirectList(org.eclipse.persistence.indirection.IndirectList) ArrayList(java.util.ArrayList)

Example 7 with DirectCollectionChangeRecord

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);
}
Also used : OrderedListContainerPolicy(org.eclipse.persistence.internal.queries.OrderedListContainerPolicy) ContainerPolicy(org.eclipse.persistence.internal.queries.ContainerPolicy) DirectCollectionChangeRecord(org.eclipse.persistence.internal.sessions.DirectCollectionChangeRecord) ValueHolder(org.eclipse.persistence.indirection.ValueHolder) IndirectCollection(org.eclipse.persistence.indirection.IndirectCollection) IndirectList(org.eclipse.persistence.indirection.IndirectList) AbstractSession(org.eclipse.persistence.internal.sessions.AbstractSession)

Example 8 with DirectCollectionChangeRecord

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);
}
Also used : ObjectChangeSet(org.eclipse.persistence.internal.sessions.ObjectChangeSet) Set(java.util.Set) HashSet(java.util.HashSet) IdentityHashMap(java.util.IdentityHashMap) HashMap(java.util.HashMap) DirectCollectionChangeRecord(org.eclipse.persistence.internal.sessions.DirectCollectionChangeRecord) HashSet(java.util.HashSet)

Example 9 with DirectCollectionChangeRecord

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);
    }
}
Also used : ArrayList(java.util.ArrayList) DirectCollectionChangeRecord(org.eclipse.persistence.internal.sessions.DirectCollectionChangeRecord) List(java.util.List) IndirectList(org.eclipse.persistence.indirection.IndirectList) ArrayList(java.util.ArrayList)

Example 10 with DirectCollectionChangeRecord

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);
        }
    }
}
Also used : DatabaseField(org.eclipse.persistence.internal.helper.DatabaseField) ObjectChangeSet(org.eclipse.persistence.internal.sessions.ObjectChangeSet) Iterator(java.util.Iterator) DescriptorIterator(org.eclipse.persistence.internal.descriptors.DescriptorIterator) AbstractRecord(org.eclipse.persistence.internal.sessions.AbstractRecord) DirectCollectionChangeRecord(org.eclipse.persistence.internal.sessions.DirectCollectionChangeRecord)

Aggregations

DirectCollectionChangeRecord (org.eclipse.persistence.internal.sessions.DirectCollectionChangeRecord)11 IndirectList (org.eclipse.persistence.indirection.IndirectList)4 ObjectChangeSet (org.eclipse.persistence.internal.sessions.ObjectChangeSet)4 ArrayList (java.util.ArrayList)3 HashMap (java.util.HashMap)3 IdentityHashMap (java.util.IdentityHashMap)3 List (java.util.List)3 ContainerPolicy (org.eclipse.persistence.internal.queries.ContainerPolicy)3 OrderedListContainerPolicy (org.eclipse.persistence.internal.queries.OrderedListContainerPolicy)3 HashSet (java.util.HashSet)2 Iterator (java.util.Iterator)2 Set (java.util.Set)2 ValueHolder (org.eclipse.persistence.indirection.ValueHolder)2 DescriptorIterator (org.eclipse.persistence.internal.descriptors.DescriptorIterator)2 DatabaseField (org.eclipse.persistence.internal.helper.DatabaseField)2 AbstractRecord (org.eclipse.persistence.internal.sessions.AbstractRecord)2 PropertyChangeEvent (java.beans.PropertyChangeEvent)1 Map (java.util.Map)1 ChangeTracker (org.eclipse.persistence.descriptors.changetracking.ChangeTracker)1 CollectionChangeEvent (org.eclipse.persistence.descriptors.changetracking.CollectionChangeEvent)1