All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.persistence.internal.sessions.DirectCollectionChangeRecord Maven / Gradle / Ivy

There is a newer version: 4.0.2
Show newest version
/*
 * 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.internal.sessions;

import java.util.*;

import org.eclipse.persistence.internal.queries.ContainerPolicy;

/**
 * 

* Purpose: This class holds the record of the changes made to a collection attribute of * an object. *

* Description: Collections must be compared to each other and added and removed objects must * be recorded separately. */ public class DirectCollectionChangeRecord extends DeferrableChangeRecord implements org.eclipse.persistence.sessions.changesets.DirectCollectionChangeRecord { protected HashMap addObjectMap; protected HashMap removeObjectMap; /** * Contains the number of objects that must be inserted to once the value is removed * in the database as a delete where value = "value" will remove all instances * of that value in the database not just one. */ protected HashMap commitAddMap; /** * Used only in case listOrderField != null in the mapping. * Maps each object which has been added or removed or which order in the list has changed * to an array of two (non-intersecting) sets of indexes - old and new. */ protected Map changedIndexes; protected int oldSize; protected int newSize; protected boolean isFirstToAddAlreadyInCollection; protected boolean isFirstToRemoveAlreadyOutCollection; protected boolean isFirstToAdd = true; protected boolean isFirstToRemove = true; /** * Indicates whether IndirectList's order has been repaired. */ protected boolean orderHasBeenRepaired; /** * This default constructor. */ public DirectCollectionChangeRecord() { super(); } /** * This constructor returns a changeRecord representing the DirectCollection mapping. */ public DirectCollectionChangeRecord(ObjectChangeSet owner) { this.owner = owner; } /** * This method takes a map of primitive objects and adds them to the add list. * The map stores the number of times the object is in the list. */ public void addAdditionChange(HashMap additions, HashMap databaseCount) { Iterator enumtr = additions.keySet().iterator(); while (enumtr.hasNext()) { Object object = enumtr.next(); if (databaseCount.containsKey(object)){ getCommitAddMap().put(object, databaseCount.get(object)); } addAdditionChange(object, (Integer)additions.get(object)); } } /** * This method takes a single addition value and records it. */ public void addAdditionChange(Object key, Integer count){ if (getRemoveObjectMap().containsKey(key)) { int removeValue = ((Integer)getRemoveObjectMap().get(key)).intValue(); int addition = count.intValue(); int result = removeValue - addition; if (result > 0 ) { // more removes still getRemoveObjectMap().put(key, Integer.valueOf(result)); } else if (result < 0) { // more adds now getRemoveObjectMap().remove(key); getAddObjectMap().put(key, Integer.valueOf(Math.abs(result))); } else { // equal getRemoveObjectMap().remove(key); } } else { if (this.getAddObjectMap().containsKey(key)) { int addValue = ((Integer)this.getAddObjectMap().get(key)).intValue(); addValue += count.intValue(); this.getAddObjectMap().put(key, Integer.valueOf(addValue)); } else { this.getAddObjectMap().put(key, count); } } if(this.isFirstToAdd) { this.isFirstToAdd = false; if(this.isFirstToAddAlreadyInCollection) { return; } } // this is an attribute change track add keep count int addValue = count.intValue(); int commitValue = 0; if (getCommitAddMap().containsKey(key)) { commitValue = ((Integer)getCommitAddMap().get(key)).intValue(); } getCommitAddMap().put(key, Integer.valueOf(addValue + commitValue)); } /** * This method takes a hashtable of primitive objects and adds them to the remove list. * Each reference in the hashtable lists the number of this object that needs to be removed from the * collection. */ public void addRemoveChange(HashMap additions, HashMap databaseCount) { Iterator enumtr = additions.keySet().iterator(); while (enumtr.hasNext()) { Object object = enumtr.next(); if (databaseCount.containsKey(object)){ getCommitAddMap().put(object, databaseCount.get(object)); } addRemoveChange(object, (Integer)additions.get(object)); } } /** * This method takes a single remove change and integrates it with this changeset. */ public void addRemoveChange(Object key, Integer count){ if (getAddObjectMap().containsKey(key)) { int removeValue = ((Integer)getAddObjectMap().get(key)).intValue(); int addition = count.intValue(); int result = removeValue - addition; if (result > 0 ) { // more removes still getAddObjectMap().put(key, Integer.valueOf(result)); } else if (result < 0) { // more adds now getAddObjectMap().remove(key); getRemoveObjectMap().put(key, Integer.valueOf(Math.abs(result))); } else { // equal getAddObjectMap().remove(key); } } else { if (this.getRemoveObjectMap().containsKey(key)){ int addValue = ((Integer)this.getRemoveObjectMap().get(key)).intValue(); addValue += count.intValue(); this.getRemoveObjectMap().put(key, Integer.valueOf(addValue)); } else { this.getRemoveObjectMap().put(key, count); } } if(this.isFirstToRemove) { this.isFirstToRemove = false; if(this.isFirstToRemoveAlreadyOutCollection) { return; } } int removeValue = count.intValue(); int commitValue = 0; if (getCommitAddMap().containsKey(key)){ commitValue = ((Integer)getCommitAddMap().get(key)).intValue(); } getCommitAddMap().put(key, Integer.valueOf(commitValue - removeValue)); } /** * This method takes a hashtable of primitives and adds them to the commit list. * This count value provided is the number of instances that will need to be * inserted into the database once a remove has occurred. This is only set * once for each object type. */ public void setCommitAddition(Hashtable additions){ Enumeration enumtr = additions.keys(); while (enumtr.hasMoreElements()) { Object object = enumtr.nextElement(); getCommitAddMap().put(object, additions.get(object)); } } /** * This method will iterate over the collection and store the database counts for * the objects within the collection, this is used for minimal updates. */ public void storeDatabaseCounts(Object collection, ContainerPolicy containerPolicy, AbstractSession session){ Object iterator = containerPolicy.iteratorFor(collection); while (containerPolicy.hasNext(iterator)) { Object object = containerPolicy.next(iterator, session); incrementDatabaseCount(object); } } /** * Increment the count for object */ public void incrementDatabaseCount(Object object){ if (getCommitAddMap().containsKey(object)) { int count = ((Integer)getCommitAddMap().get(object)).intValue(); getCommitAddMap().put(object, Integer.valueOf(++count)); } else { getCommitAddMap().put(object, Integer.valueOf(1)); } } /** * Decrement the count for object */ public void decrementDatabaseCount(Object object){ if (getCommitAddMap().containsKey(object)) { int count = ((Integer)getCommitAddMap().get(object)).intValue(); if(count > 1) { getCommitAddMap().put(object, Integer.valueOf(--count)); } else { getCommitAddMap().remove(object); } } } /** * ADVANCED: * This method returns the list of added objects. */ public Vector getAddObjectList(){ Vector vector = new Vector(); for (Iterator iterator = getAddObjectMap().keySet().iterator(); iterator.hasNext();){ Object object = iterator.next(); int count = ((Integer)getAddObjectMap().get(object)).intValue(); while (count > 0){ vector.add(object); --count; } } return vector; } /** * This method returns the collection of objects that were added to the collection. */ public HashMap getAddObjectMap() { if (this.addObjectMap == null) { this.addObjectMap = new HashMap(1); } return addObjectMap; } /** * This method returns the collection of objects that were added to the collection. */ public HashMap getCommitAddMap() { if (this.commitAddMap == null) { this.commitAddMap = new HashMap(1); } return commitAddMap; } /** * ADVANCED: * This method returns the list of removed objects. */ public Vector getRemoveObjectList(){ Vector vector = new Vector(); for (Iterator iterator = getRemoveObjectMap().keySet().iterator(); iterator.hasNext();){ Object object = iterator.next(); int count = ((Integer)getRemoveObjectMap().get(object)).intValue(); while (count > 0){ vector.add(object); --count; } } return vector; } /** * This method returns the collection of objects that were removed from the collection. */ public HashMap getRemoveObjectMap() { if (this.removeObjectMap == null) { removeObjectMap = new HashMap(1); } return removeObjectMap; } /** * Returns true if the change set has changes. */ public boolean hasChanges() { return (!((this.addObjectMap == null || this.addObjectMap.isEmpty()) && (this.removeObjectMap == null || this.removeObjectMap.isEmpty()) && (this.changedIndexes == null || this.changedIndexes.isEmpty()))) || getOwner().isNew(); } /** * This method will be used to merge one record into another. */ public void mergeRecord(ChangeRecord mergeFromRecord, UnitOfWorkChangeSet mergeToChangeSet, UnitOfWorkChangeSet mergeFromChangeSet) { if (((DeferrableChangeRecord)mergeFromRecord).isDeferred()){ if (this.hasChanges()){ //merging into existing change record need to combine changes ((DeferrableChangeRecord)mergeFromRecord).getMapping().calculateDeferredChanges(mergeFromRecord, mergeToChangeSet.getSession()); }else{ this.isDeferred = true; this.originalCollection = ((DeferrableChangeRecord)mergeFromRecord).originalCollection; this.latestCollection = ((DeferrableChangeRecord)mergeFromRecord).latestCollection; return; } } HashMap addMapToMerge = ((DirectCollectionChangeRecord)mergeFromRecord).getAddObjectMap(); HashMap removeMapToMerge = ((DirectCollectionChangeRecord)mergeFromRecord).getRemoveObjectMap(); //merge additions for (Iterator iterator = addMapToMerge.keySet().iterator(); iterator.hasNext();){ Object added = iterator.next(); if (!((DirectCollectionChangeRecord)mergeFromRecord).getCommitAddMap().containsKey(added)){ // we have not recorded a change of this type in this class before so add it this.getCommitAddMap().put(added, ((DirectCollectionChangeRecord)mergeFromRecord).getCommitAddMap().get(added)); } this.addAdditionChange(added, (Integer)addMapToMerge.get(added)); } //merge removals for (Iterator iterator = removeMapToMerge.keySet().iterator(); iterator.hasNext();){ Object removed = iterator.next(); if (!((DirectCollectionChangeRecord)mergeFromRecord).getCommitAddMap().containsKey(removed)){ // we have not recorded a change of this type in this class before so add it this.getCommitAddMap().put(removed, Integer.valueOf(1)); } this.addRemoveChange(removed, (Integer)removeMapToMerge.get(removed)); } if(this.changedIndexes != null) { if(((DirectCollectionChangeRecord)mergeFromRecord).getChangedIndexes() != null) { Iterator> itEntries = ((DirectCollectionChangeRecord)mergeFromRecord).getChangedIndexes().entrySet().iterator(); while(itEntries.hasNext()) { Map.Entry entry = itEntries.next(); Object obj = entry.getValue(); Set[] indexes = entry.getValue(); if(this.changedIndexes.containsKey(obj)) { // we assuming that these are two consecutive change records: // oldIndexes[1] should be equal to newIndexes[0] ((Set[])(this.changedIndexes.get(obj)))[1] = indexes[1]; } else { this.changedIndexes.put(obj, indexes); } } this.newSize = ((DirectCollectionChangeRecord)mergeFromRecord).getNewSize(); } } else { if(((DirectCollectionChangeRecord)mergeFromRecord).getChangedIndexes() != null) { this.changedIndexes = new HashMap(((DirectCollectionChangeRecord)mergeFromRecord).getChangedIndexes()); this.oldSize = ((DirectCollectionChangeRecord)mergeFromRecord).getOldSize(); this.newSize = ((DirectCollectionChangeRecord)mergeFromRecord).getNewSize(); } } } /** * This method will be used to update the objectsChangeSets references */ public void updateReferences(UnitOfWorkChangeSet mergeToChangeSet, UnitOfWorkChangeSet mergeFromChangeSet) { //nothing for this record type to do as it does not reference any changesets } public static class NULL { // This is a placeholder for null instances. public NULL(){ } public boolean equals(Object object){ return object instanceof NULL; } } public void setFirstToAddAlreadyInCollection(boolean flag) { this.isFirstToAddAlreadyInCollection = flag; } public boolean isFirstToAddAlreadyInCollection() { return this.isFirstToAddAlreadyInCollection; } public void setFirstToRemoveAlreadyOutCollection(boolean flag) { this.isFirstToRemoveAlreadyOutCollection = flag; } public boolean isFirstToRemoveAlreadyOutCollection() { return this.isFirstToRemoveAlreadyOutCollection; } public void setChangedIndexes(Map changedIndexes) { this.changedIndexes = changedIndexes; } public Map getChangedIndexes() { return this.changedIndexes; } public void setOldSize(int size) { this.oldSize = size; } public int getOldSize() { return this.oldSize; } public void setNewSize(int size) { this.newSize = size; } public int getNewSize() { return this.newSize; } /** * Recreates the original state of the collection. */ public void internalRecreateOriginalCollection(Object currentCollection, AbstractSession session) { ContainerPolicy cp = this.mapping.getContainerPolicy(); if(this.removeObjectMap != null) { Iterator it = this.removeObjectMap.entrySet().iterator(); while(it.hasNext()) { Map.Entry entry = (Map.Entry)it.next(); Object obj = entry.getKey(); int n = (Integer)entry.getValue(); for(int i=0; i < n; i++) { cp.addInto(obj, currentCollection, session); } } } if(this.addObjectMap != null) { Iterator it = this.addObjectMap.entrySet().iterator(); while(it.hasNext()) { Map.Entry entry = (Map.Entry)it.next(); Object obj = entry.getKey(); int n = (Integer)entry.getValue(); for(int i=0; i < n; i++) { cp.removeFrom(obj, currentCollection, session); } } } } public void setOrderHasBeenRepaired(boolean hasBeenRepaired) { this.orderHasBeenRepaired = hasBeenRepaired; } public boolean orderHasBeenRepaired() { return this.orderHasBeenRepaired; } /** * Clears info about added / removed objects set by change tracker. */ public void clearChanges() { if(this.removeObjectMap != null) { this.removeObjectMap.clear(); } if(this.addObjectMap != null) { this.addObjectMap.clear(); } if(this.addObjectMap != null) { this.addObjectMap.clear(); } if(this.removeObjectMap != null) { this.removeObjectMap.clear(); } if(this.commitAddMap != null) { this.commitAddMap.clear(); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy