[Fix] fixed check for duplicate objects in the cache

This commit is contained in:
Reto Breitenmoser 2017-10-05 10:38:03 +02:00
parent 4087608e1a
commit 8525bbdf6a
1 changed files with 67 additions and 61 deletions

View File

@ -16,12 +16,18 @@
package li.strolch.utils.objectfilter; package li.strolch.utils.objectfilter;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.*; import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import li.strolch.utils.collections.MapOfMaps;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import li.strolch.utils.collections.MapOfMaps;
/** /**
* This class implements a filter where modifications to an object are collected, and only the most recent action and * This class implements a filter where modifications to an object are collected, and only the most recent action and
* version of the object is returned. * version of the object is returned.
@ -121,17 +127,16 @@ public class ObjectFilter {
* </table> * </table>
* *
* @param key * @param key
* the key to register the object with * the key to register the object with
* @param objectKey * @param objectKey
* the key for the object * the key for the object
* @param objectToAdd * @param objectToAdd
* The object for which addition shall be registered. * The object for which addition shall be registered.
*/ */
public void add(String key, Object objectKey, Object objectToAdd) { public void add(String key, Object objectKey, Object objectToAdd) {
if (ObjectFilter.logger.isDebugEnabled()) if (ObjectFilter.logger.isDebugEnabled())
ObjectFilter.logger ObjectFilter.logger.debug(MessageFormat.format("add object {0} with key {1}", objectToAdd, key)); //$NON-NLS-1$
.debug(MessageFormat.format("add object {0} with key {1}", objectToAdd, key)); //$NON-NLS-1$
// BEWARE: you fix a bug here, be sure to update BOTH tables on the logic. // BEWARE: you fix a bug here, be sure to update BOTH tables on the logic.
ObjectCache cached = this.cache.getElement(key, objectKey); ObjectCache cached = this.cache.getElement(key, objectKey);
@ -147,9 +152,8 @@ public class ObjectFilter {
String existingKey = cached.getKey(); String existingKey = cached.getKey();
if (!existingKey.equals(key)) { if (!existingKey.equals(key)) {
String msg = "Invalid key provided for object with transaction ID {0} and operation {1}: existing key is {2}, new key is {3}. Object may be present in the same filter instance only once, registered using one key only. Object:{4}"; //$NON-NLS-1$ String msg = "Invalid key provided for object with transaction ID {0} and operation {1}: existing key is {2}, new key is {3}. Object may be present in the same filter instance only once, registered using one key only. Object:{4}"; //$NON-NLS-1$
throw new IllegalArgumentException(MessageFormat throw new IllegalArgumentException(MessageFormat.format(msg, Long.toString(id),
.format(msg, Long.toString(id), Operation.ADD.toString(), existingKey, key, Operation.ADD.toString(), existingKey, key, objectKey.toString()));
objectKey.toString()));
} }
// The object is in cache: update the version as required, keeping in mind that most // The object is in cache: update the version as required, keeping in mind that most
@ -198,22 +202,34 @@ public class ObjectFilter {
* </table> * </table>
* *
* @param key * @param key
* the key to register the object with * the key to register the object with
* @param objectKey * @param objectKey
* the key for the object * the key for the object
* @param objectToUpdate * @param objectToUpdate
* The object for which update shall be registered. * The object for which update shall be registered.
*/ */
public void update(String key, Object objectKey, Object objectToUpdate) { public void update(String key, Object objectKey, Object objectToUpdate) {
if (ObjectFilter.logger.isDebugEnabled()) if (ObjectFilter.logger.isDebugEnabled())
ObjectFilter.logger ObjectFilter.logger.debug(MessageFormat.format("update object {0} with key {1}", objectKey, key)); //$NON-NLS-1$
.debug(MessageFormat.format("update object {0} with key {1}", objectKey, key)); //$NON-NLS-1$
// BEWARE: you fix a bug here, be sure to update BOTH tables on the logic. // BEWARE: you fix a bug here, be sure to update BOTH tables on the logic.
ObjectCache cached = this.cache.getElement(key, objectKey); ObjectCache cached = this.cache.getElement(key, objectKey);
if (cached == null) { if (cached == null) {
List<ObjectCache> allElements = this.cache.getAllElements();
// check if the object is already in the cache with an other key
if (allElements.stream().anyMatch(oCache -> oCache.getObject().equals(objectToUpdate))) {
String msg = "Invalid key provided for object with transaction ID {0} and operation {1}: existing key is {2}, new key is {3}. Object may be present in the same filter instance only once, registered using one key only. Object:{4}"; //$NON-NLS-1$
Optional<ObjectCache> duplicateObj = allElements.stream()
.filter(oCache -> oCache.getObject().equals(objectToUpdate)).findFirst();
throw new IllegalArgumentException(MessageFormat.format(msg, Long.toString(id),
Operation.MODIFY.toString(), duplicateObj.get().getKey(), key, objectToUpdate.toString()));
}
// The object got an ID during this run, but was not added to this cache. // The object got an ID during this run, but was not added to this cache.
// Hence, we add it now, with the current operation. // Hence, we add it now, with the current operation.
ObjectCache cacheObj = new ObjectCache(dispenseID(), key, objectKey, objectToUpdate, Operation.MODIFY); ObjectCache cacheObj = new ObjectCache(dispenseID(), key, objectKey, objectToUpdate, Operation.MODIFY);
@ -221,14 +237,6 @@ public class ObjectFilter {
} else { } else {
String existingKey = cached.getKey();
if (!existingKey.equals(key)) {
String msg = "Invalid key provided for object with transaction ID {0} and operation {1}: existing key is {2}, new key is {3}. Object may be present in the same filter instance only once, registered using one key only. Object:{4}"; //$NON-NLS-1$
throw new IllegalArgumentException(MessageFormat
.format(msg, Long.toString(id), Operation.MODIFY.toString(), existingKey, key,
objectToUpdate.toString()));
}
// The object is in cache: update the version as required. // The object is in cache: update the version as required.
Operation op = cached.getOperation(); Operation op = cached.getOperation();
switch (op) { switch (op) {
@ -272,17 +280,16 @@ public class ObjectFilter {
* </table> * </table>
* *
* @param key * @param key
* the key to register the object with * the key to register the object with
* @param objectKey * @param objectKey
* the key for the object * the key for the object
* @param objectToRemove * @param objectToRemove
* The object for which removal shall be registered. * The object for which removal shall be registered.
*/ */
public void remove(String key, Object objectKey, Object objectToRemove) { public void remove(String key, Object objectKey, Object objectToRemove) {
if (ObjectFilter.logger.isDebugEnabled()) if (ObjectFilter.logger.isDebugEnabled())
ObjectFilter.logger ObjectFilter.logger.debug(MessageFormat.format("remove object {0} with key {1}", objectKey, key)); //$NON-NLS-1$
.debug(MessageFormat.format("remove object {0} with key {1}", objectKey, key)); //$NON-NLS-1$
// BEWARE: you fix a bug here, be sure to update BOTH tables on the logic. // BEWARE: you fix a bug here, be sure to update BOTH tables on the logic.
ObjectCache cached = this.cache.getElement(key, objectKey); ObjectCache cached = this.cache.getElement(key, objectKey);
@ -296,9 +303,8 @@ public class ObjectFilter {
String existingKey = cached.getKey(); String existingKey = cached.getKey();
if (!existingKey.equals(key)) { if (!existingKey.equals(key)) {
String msg = "Invalid key provided for object with transaction ID {0} and operation {1}: existing key is {2}, new key is {3}. Object may be present in the same filter instance only once, registered using one key only. Object:{4}"; //$NON-NLS-1$ String msg = "Invalid key provided for object with transaction ID {0} and operation {1}: existing key is {2}, new key is {3}. Object may be present in the same filter instance only once, registered using one key only. Object:{4}"; //$NON-NLS-1$
throw new IllegalArgumentException(MessageFormat throw new IllegalArgumentException(MessageFormat.format(msg, Long.toString(id),
.format(msg, Long.toString(id), Operation.REMOVE.toString(), existingKey, key, Operation.REMOVE.toString(), existingKey, key, objectKey.toString()));
objectKey.toString()));
} }
// The object is in cache: update the version as required. // The object is in cache: update the version as required.
@ -332,7 +338,7 @@ public class ObjectFilter {
* Register the addition of the given object. Since no key is provided, the class name is used as a key. * Register the addition of the given object. Since no key is provided, the class name is used as a key.
* *
* @param object * @param object
* The object that shall be registered for addition * The object that shall be registered for addition
*/ */
public void add(Object object) { public void add(Object object) {
add(object.getClass().getName(), object, object); add(object.getClass().getName(), object, object);
@ -342,9 +348,9 @@ public class ObjectFilter {
* Register the addition of the given object. Since no key is provided, the class name is used as a key. * Register the addition of the given object. Since no key is provided, the class name is used as a key.
* *
* @param objectKey * @param objectKey
* the key for the object * the key for the object
* @param object * @param object
* The object that shall be registered for addition * The object that shall be registered for addition
*/ */
public void add(Object objectKey, Object object) { public void add(Object objectKey, Object object) {
add(object.getClass().getName(), objectKey, object); add(object.getClass().getName(), objectKey, object);
@ -354,7 +360,7 @@ public class ObjectFilter {
* Register the update of the given object. Since no key is provided, the class name is used as a key. * Register the update of the given object. Since no key is provided, the class name is used as a key.
* *
* @param object * @param object
* The object that shall be registered for updating * The object that shall be registered for updating
*/ */
public void update(Object object) { public void update(Object object) {
update(object.getClass().getName(), object, object); update(object.getClass().getName(), object, object);
@ -364,9 +370,9 @@ public class ObjectFilter {
* Register the update of the given object. Since no key is provided, the class name is used as a key. * Register the update of the given object. Since no key is provided, the class name is used as a key.
* *
* @param objectKey * @param objectKey
* the key for the object * the key for the object
* @param object * @param object
* The object that shall be registered for updating * The object that shall be registered for updating
*/ */
public void update(Object objectKey, Object object) { public void update(Object objectKey, Object object) {
update(object.getClass().getName(), objectKey, object); update(object.getClass().getName(), objectKey, object);
@ -376,7 +382,7 @@ public class ObjectFilter {
* Register the removal of the given object. Since no key is provided, the class name is used as a key. * Register the removal of the given object. Since no key is provided, the class name is used as a key.
* *
* @param object * @param object
* The object that shall be registered for removal * The object that shall be registered for removal
*/ */
public void remove(Object object) { public void remove(Object object) {
remove(object.getClass().getName(), object, object); remove(object.getClass().getName(), object, object);
@ -386,9 +392,9 @@ public class ObjectFilter {
* Register the removal of the given object. Since no key is provided, the class name is used as a key. * Register the removal of the given object. Since no key is provided, the class name is used as a key.
* *
* @param objectKey * @param objectKey
* the key for the object * the key for the object
* @param object * @param object
* The object that shall be registered for removal * The object that shall be registered for removal
*/ */
public void remove(Object objectKey, Object object) { public void remove(Object objectKey, Object object) {
remove(object.getClass().getName(), objectKey, object); remove(object.getClass().getName(), objectKey, object);
@ -398,9 +404,9 @@ public class ObjectFilter {
* Returns the ObjectCache for the given key and objectKey * Returns the ObjectCache for the given key and objectKey
* *
* @param key * @param key
* the key under which it was registered * the key under which it was registered
* @param objectKey * @param objectKey
* the objectKey * the objectKey
* *
* @return the ObjectCache, or null * @return the ObjectCache, or null
*/ */
@ -412,11 +418,11 @@ public class ObjectFilter {
* Returns the element with the given key and objectKey * Returns the element with the given key and objectKey
* *
* @param key * @param key
* the key under which it was registered * the key under which it was registered
* @param objectKey * @param objectKey
* the objectKey * the objectKey
* @param <V> * @param <V>
* the class to which to cast the element to * the class to which to cast the element to
* *
* @return the element, or null * @return the element, or null
*/ */
@ -433,9 +439,9 @@ public class ObjectFilter {
* Return true if the element with the given key and objectKey exist * Return true if the element with the given key and objectKey exist
* *
* @param key * @param key
* the key under which it was registered * the key under which it was registered
* @param objectKey * @param objectKey
* the objectKey * the objectKey
* *
* @return true if the element with the given key and objectKey exist * @return true if the element with the given key and objectKey exist
*/ */
@ -447,7 +453,7 @@ public class ObjectFilter {
* Get all objects that were registered under the given key and that have as a resulting final action an addition. * Get all objects that were registered under the given key and that have as a resulting final action an addition.
* *
* @param key * @param key
* The registration key of the objects to match * The registration key of the objects to match
* *
* @return The list of all objects registered under the given key and that need to be added. * @return The list of all objects registered under the given key and that need to be added.
*/ */
@ -466,9 +472,9 @@ public class ObjectFilter {
* Get all objects that were registered under the given key and that have as a resulting final action an addition. * Get all objects that were registered under the given key and that have as a resulting final action an addition.
* *
* @param clazz * @param clazz
* The class type of the object to be retrieved, that acts as an additional filter criterion. * The class type of the object to be retrieved, that acts as an additional filter criterion.
* @param key * @param key
* The registration key of the objects to match * The registration key of the objects to match
* *
* @return The list of all objects registered under the given key and that need to be added. * @return The list of all objects registered under the given key and that need to be added.
*/ */
@ -491,7 +497,7 @@ public class ObjectFilter {
* Get all objects that were registered under the given key and that have as a resulting final action an update. * Get all objects that were registered under the given key and that have as a resulting final action an update.
* *
* @param key * @param key
* registration key of the objects to match * registration key of the objects to match
* *
* @return The list of all objects registered under the given key and that need to be updated. * @return The list of all objects registered under the given key and that need to be updated.
*/ */
@ -510,9 +516,9 @@ public class ObjectFilter {
* Get all objects that were registered under the given key and that have as a resulting final action an update. * Get all objects that were registered under the given key and that have as a resulting final action an update.
* *
* @param clazz * @param clazz
* The class type of the object to be retrieved, that acts as an additional filter criterion. * The class type of the object to be retrieved, that acts as an additional filter criterion.
* @param key * @param key
* registration key of the objects to match * registration key of the objects to match
* *
* @return The list of all objects registered under the given key and that need to be updated. * @return The list of all objects registered under the given key and that need to be updated.
*/ */
@ -535,7 +541,7 @@ public class ObjectFilter {
* Get all objects that were registered under the given key that have as a resulting final action their removal. * Get all objects that were registered under the given key that have as a resulting final action their removal.
* *
* @param key * @param key
* The registration key of the objects to match * The registration key of the objects to match
* *
* @return The list of object registered under the given key that have, as a final action, removal. * @return The list of object registered under the given key that have, as a final action, removal.
*/ */
@ -554,9 +560,9 @@ public class ObjectFilter {
* Get all objects that were registered under the given key that have as a resulting final action their removal. * Get all objects that were registered under the given key that have as a resulting final action their removal.
* *
* @param clazz * @param clazz
* The class type of the object to be retrieved, that acts as an additional filter criterion. * The class type of the object to be retrieved, that acts as an additional filter criterion.
* @param key * @param key
* The registration key of the objects to match * The registration key of the objects to match
* *
* @return The list of object registered under the given key that have, as a final action, removal. * @return The list of object registered under the given key that have, as a final action, removal.
*/ */
@ -579,9 +585,9 @@ public class ObjectFilter {
* Get all objects that were registered under the given key * Get all objects that were registered under the given key
* *
* @param clazz * @param clazz
* The class type of the object to be retrieved, that acts as an additional filter criterion. * The class type of the object to be retrieved, that acts as an additional filter criterion.
* @param key * @param key
* The registration key of the objects to match * The registration key of the objects to match
* *
* @return The list of object registered under the given key that have, as a final action, removal. * @return The list of object registered under the given key that have, as a final action, removal.
*/ */
@ -602,7 +608,7 @@ public class ObjectFilter {
* Get all objects that of the given class * Get all objects that of the given class
* *
* @param clazz * @param clazz
* The class type of the object to be retrieved, that acts as an additional filter criterion. * The class type of the object to be retrieved, that acts as an additional filter criterion.
* *
* @return The list of all objects that of the given class * @return The list of all objects that of the given class
*/ */
@ -624,7 +630,7 @@ public class ObjectFilter {
* is associated to the object. * is associated to the object.
* *
* @param key * @param key
* The registration key for which the objects shall be retrieved * The registration key for which the objects shall be retrieved
* *
* @return The list of objects matching the given key. * @return The list of objects matching the given key.
*/ */
@ -642,7 +648,7 @@ public class ObjectFilter {
* is associated to the object. * is associated to the object.
* *
* @param key * @param key
* The registration key for which the objects shall be retrieved * The registration key for which the objects shall be retrieved
* *
* @return The list of objects matching the given key. * @return The list of objects matching the given key.
*/ */