/*
* Copyright (c) 2012 EMC Corporation
* All Rights Reserved
*/
package com.emc.storageos.db.client.model;
import java.util.*;
/**
* Abstract base for map that tracks changes
*/
public abstract class AbstractChangeTrackingSetMap<K> extends HashMap<String, AbstractChangeTrackingSet<K>> {
private HashSet<String> _changed; // added or modified
/**
* Default constructor
*/
public AbstractChangeTrackingSetMap() {
}
/**
* Constructs a new map with the same mappings as source
*
* @param source
*/
public AbstractChangeTrackingSetMap(Map<String, AbstractChangeTrackingSet<K>> source) {
super(source);
}
/**
* Get modified keys set
*
* @return modified keys set
*/
public Set<String> getChangedKeySet() {
if (_changed == null) {
return null;
}
return Collections.unmodifiableSet(_changed);
}
/**
* Mark a row as changed
*
* @param key
*/
private void setValueChanged(String key) {
if (_changed == null) {
_changed = new HashSet<String>();
}
_changed.add(key);
}
/**
* Get the Set value for a key, if key doesn't exist creates a new Set
*
* @param key
* @return
*/
private AbstractChangeTrackingSet<K> getValue(String key) {
if (super.containsKey(key)) {
return super.get(key);
} else {
AbstractChangeTrackingSet<K> val = createSetInstance();
super.put(key, val);
setValueChanged(key);
return val;
}
}
/**
* Get the Set value for a key, if key doesn't exist returns null
*
* @param key
* @return
*/
protected AbstractChangeTrackingSet<K> getValueNoCreate(String key) {
return (super.get(key));
}
@Override
public AbstractChangeTrackingSet<K> put(String key, AbstractChangeTrackingSet<K> values) {
getValue(key).addAll(values);
return getValue(key);
}
/**
* Incrementally adds entry into the setmap
*
* @param key
* @param value
*/
public void put(String key, K value) {
getValue(key).add(value);
setValueChanged(key);
}
/**
* Incrementally removes an entry into the setmap
*
* @param key
* @param value
*/
public void remove(String key, K value) {
if (super.get(key) != null) {
super.get(key).remove(value);
setValueChanged(key);
}
}
/**
* Adds entry into hashmap, not tracked as a change
*
* @param key
* @param value
*/
public void putNoTrack(String key, String value) {
if (!super.containsKey(key)) {
super.put(key, createSetInstance());
}
super.get(key).addNoTrack(value);
}
/**
* Remove an entry without tracking
*
* @param key
* @param value
*/
public void removeNoTrack(String key, String value) {
AbstractChangeTrackingSet<K> set = super.get(key);
if (set != null) {
set.removeNoTrack(value);
if (set.isEmpty()) {
super.remove(key);
}
}
}
/**
* Remove a key from the map
*
* @param key
*/
public void remove(String key) {
if (super.containsKey(key)) {
AbstractChangeTrackingSet<K> trackingSet = super.get(key);
trackingSet.clear();
setValueChanged(key);
}
}
/**
* Removes all entries in the map.
*/
@Override
public void clear() {
Iterator<String> keys = super.keySet().iterator();
while (keys.hasNext()) {
remove(keys.next());
}
}
/**
* replace current entries with the ones passed in
*
* @param newEntries
*/
public void replace(Map<String, AbstractChangeTrackingSet<K>> newEntries) {
if (newEntries == null || (newEntries.isEmpty())) {
clear();
return;
}
Set<String> keys = super.keySet();
List<String> removedKeys = new ArrayList();
for (String key : keys) {
if (!newEntries.containsKey(key)) {
removedKeys.add(key);
}
}
for (String key : removedKeys) {
remove(key);
}
Set<Map.Entry<String, AbstractChangeTrackingSet<K>>> entries = newEntries.entrySet();
String key = null;
for (Map.Entry<String, AbstractChangeTrackingSet<K>> entry : entries) {
key = entry.getKey();
getValue(key).replace(entry.getValue());
setValueChanged(key);
}
}
/**
* Create an instance of the Set
*
* @return
*/
public abstract AbstractChangeTrackingSet<K> createSetInstance();
/**
* Returns the Set value for the key, null if the key doesn't exist
*
* @param key
* @return
*/
public abstract AbstractChangeTrackingSet<K> get(String key);
}