| /* |
| * Copyright (c) 1998, 2019 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; |
| |
| /** |
| * Change record used by DirectMapMapping. |
| * Only needs to track unique keys added/removed. |
| */ |
| public class DirectMapChangeRecord extends DeferrableChangeRecord { |
| protected HashMap addObjectsList; |
| protected HashMap removeObjectsList; |
| |
| public DirectMapChangeRecord() { |
| super(); |
| } |
| |
| public DirectMapChangeRecord(ObjectChangeSet owner) { |
| this.owner = owner; |
| } |
| |
| /** |
| * Returns true if the change set has changes. |
| */ |
| public boolean hasChanges() { |
| return (!((this.addObjectsList == null || this.addObjectsList.isEmpty()) && ((this.removeObjectsList == null || this.removeObjectsList.isEmpty())))) || getOwner().isNew(); |
| } |
| |
| /** |
| * This method will be used to merge one record into another. |
| */ |
| @Override |
| 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 |
| mergeFromRecord.getMapping().calculateDeferredChanges(mergeFromRecord, mergeToChangeSet.getSession()); |
| }else{ |
| this.isDeferred = true; |
| this.originalCollection = ((DeferrableChangeRecord)mergeFromRecord).originalCollection; |
| this.latestCollection = ((DeferrableChangeRecord)mergeFromRecord).latestCollection; |
| return; |
| } |
| } |
| Iterator addKeys = ((DirectMapChangeRecord)mergeFromRecord).getAddObjects().keySet().iterator(); |
| while (addKeys.hasNext()) { |
| Object key = addKeys.next(); |
| |
| if (!this.getAddObjects().containsKey(key)) { |
| if (this.getRemoveObjects().containsKey(key)) { |
| this.getRemoveObjects().remove(key); |
| } else { |
| this.getAddObjects().put(key, ((DirectMapChangeRecord)mergeFromRecord).getAddObjects().get(key)); |
| } |
| } |
| } |
| |
| Iterator removeKeys = ((DirectMapChangeRecord)mergeFromRecord).getRemoveObjects().keySet().iterator(); |
| while (removeKeys.hasNext()) { |
| Object key = removeKeys.next(); |
| |
| if (!this.getRemoveObjects().containsKey(key)) { |
| if (this.getAddObjects().containsKey(key)) { |
| this.getAddObjects().remove(key); |
| } else { |
| this.getRemoveObjects().put(key, ((DirectMapChangeRecord)mergeFromRecord).getRemoveObjects().get(key)); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Adds the items that were added to the collection. |
| */ |
| public void addAdditionChange(HashMap additions) { |
| if (getAddObjects().size() == 0) { |
| addObjectsList = additions; |
| return; |
| } |
| |
| for (Iterator i = additions.keySet().iterator(); i.hasNext(); ) { |
| Object key = i.next(); |
| if (getAddObjects().containsKey(key)) { |
| getAddObjects().put(key, additions.get(key)); |
| } else if (additions.get(key).equals(getAddObjects().get(key))) { |
| getAddObjects().put(key, additions.get(key)); |
| } |
| } |
| } |
| |
| /** |
| * Adds the items that were removed from the collection. |
| */ |
| public void addRemoveChange(HashMap subtractions) { |
| if (getRemoveObjects().size() == 0) { |
| this.removeObjectsList = subtractions; |
| return; |
| } |
| |
| for (Iterator i = subtractions.keySet().iterator(); i.hasNext(); ) { |
| Object key = i.next(); |
| if (!getRemoveObjects().containsKey(key)) { |
| getRemoveObjects().put(key, subtractions.get(key)); |
| } else if (subtractions.get(key).equals(getRemoveObjects().get(key))) { |
| getRemoveObjects().put(key, subtractions.get(key)); |
| } |
| } |
| } |
| |
| /** |
| * Adds the items that were added to the collection. |
| */ |
| public void addAdditionChange(Object key, Object value) { |
| if ( getRemoveObjects().containsKey(key) ) { |
| if ( value.equals(getRemoveObjects().get(key)) ) { |
| getRemoveObjects().remove(key); |
| }else { |
| getAddObjects().put(key, value); |
| } |
| } else { |
| getAddObjects().put(key, value); |
| } |
| } |
| |
| /** |
| * Adds the items that were removed from the collection. |
| */ |
| public void addRemoveChange(Object key, Object value) { |
| //if an entry already exists in the remove it must remain untill added |
| // as it contains the original removal. |
| if (getAddObjects().containsKey(key)) { |
| getAddObjects().remove(key); |
| } else if (!getRemoveObjects().containsKey(key)) { |
| getRemoveObjects().put(key, value); |
| } |
| } |
| |
| /** |
| * Sets the added items list. |
| */ |
| public void setAddObjects(HashMap addObjects) { |
| this.addObjectsList = addObjects; |
| } |
| |
| /** |
| * Returns the added items list. |
| */ |
| public HashMap getAddObjects() { |
| if (addObjectsList == null) { |
| addObjectsList = new HashMap(); |
| } |
| return addObjectsList; |
| } |
| |
| /** |
| * Sets the removed items list. |
| */ |
| public void setRemoveObjects(HashMap removeObjects) { |
| this.removeObjectsList = removeObjects; |
| } |
| |
| /** |
| * Returns the removed items list. |
| */ |
| public HashMap getRemoveObjects() { |
| if (removeObjectsList == null) { |
| removeObjectsList = new HashMap(); |
| } |
| |
| return removeObjectsList; |
| } |
| |
| /** |
| * This method will be used to update the objectsChangeSets references. |
| */ |
| @Override |
| public void updateReferences(UnitOfWorkChangeSet mergeToChangeSet, UnitOfWorkChangeSet mergeFromChangeSet) { |
| // Nothing for this record type to do as it does not reference any changesets. |
| } |
| |
| /** |
| * Recreates the original state of the collection. |
| */ |
| @Override |
| public void internalRecreateOriginalCollection(Object currentMap, AbstractSession session) { |
| ContainerPolicy cp = this.mapping.getContainerPolicy(); |
| if(this.removeObjectsList != null) { |
| Iterator it = this.removeObjectsList.entrySet().iterator(); |
| while(it.hasNext()) { |
| Map.Entry entry = (Map.Entry)it.next(); |
| cp.addInto(entry.getKey(), entry.getValue(), currentMap, session); |
| } |
| } |
| if(this.addObjectsList != null) { |
| Iterator it = this.addObjectsList.entrySet().iterator(); |
| while(it.hasNext()) { |
| Map.Entry entry = (Map.Entry)it.next(); |
| cp.removeFrom(entry.getKey(), entry.getValue(), currentMap, session); |
| } |
| } |
| } |
| |
| /** |
| * Clears info about added / removed objects set by change tracker. |
| */ |
| @Override |
| public void clearChanges() { |
| if(this.removeObjectsList != null) { |
| this.removeObjectsList.clear(); |
| } |
| if(this.addObjectsList != null) { |
| this.addObjectsList.clear(); |
| } |
| } |
| } |