From 8525bbdf6a80f8fdb3045258d7f3dffc427d513a Mon Sep 17 00:00:00 2001 From: Reto Breitenmoser Date: Thu, 5 Oct 2017 10:38:03 +0200 Subject: [PATCH] [Fix] fixed check for duplicate objects in the cache --- .../utils/objectfilter/ObjectFilter.java | 128 +++++++++--------- 1 file changed, 67 insertions(+), 61 deletions(-) diff --git a/li.strolch.utils/src/main/java/li/strolch/utils/objectfilter/ObjectFilter.java b/li.strolch.utils/src/main/java/li/strolch/utils/objectfilter/ObjectFilter.java index 262058f74..8331053eb 100644 --- a/li.strolch.utils/src/main/java/li/strolch/utils/objectfilter/ObjectFilter.java +++ b/li.strolch.utils/src/main/java/li/strolch/utils/objectfilter/ObjectFilter.java @@ -16,12 +16,18 @@ package li.strolch.utils.objectfilter; 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.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 * version of the object is returned. @@ -121,17 +127,16 @@ public class ObjectFilter { * * * @param key - * the key to register the object with + * the key to register the object with * @param objectKey - * the key for the object + * the key for the object * @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) { if (ObjectFilter.logger.isDebugEnabled()) - ObjectFilter.logger - .debug(MessageFormat.format("add object {0} with key {1}", objectToAdd, key)); //$NON-NLS-1$ + ObjectFilter.logger.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. ObjectCache cached = this.cache.getElement(key, objectKey); @@ -147,9 +152,8 @@ public class ObjectFilter { 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.ADD.toString(), existingKey, key, - objectKey.toString())); + throw new IllegalArgumentException(MessageFormat.format(msg, Long.toString(id), + Operation.ADD.toString(), existingKey, key, objectKey.toString())); } // The object is in cache: update the version as required, keeping in mind that most @@ -198,22 +202,34 @@ public class ObjectFilter { * * * @param key - * the key to register the object with + * the key to register the object with * @param objectKey - * the key for the object + * the key for the object * @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) { if (ObjectFilter.logger.isDebugEnabled()) - ObjectFilter.logger - .debug(MessageFormat.format("update object {0} with key {1}", objectKey, key)); //$NON-NLS-1$ + ObjectFilter.logger.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. ObjectCache cached = this.cache.getElement(key, objectKey); + if (cached == null) { + List 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 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. // Hence, we add it now, with the current operation. ObjectCache cacheObj = new ObjectCache(dispenseID(), key, objectKey, objectToUpdate, Operation.MODIFY); @@ -221,14 +237,6 @@ public class ObjectFilter { } 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. Operation op = cached.getOperation(); switch (op) { @@ -272,17 +280,16 @@ public class ObjectFilter { * * * @param key - * the key to register the object with + * the key to register the object with * @param objectKey - * the key for the object + * the key for the object * @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) { if (ObjectFilter.logger.isDebugEnabled()) - ObjectFilter.logger - .debug(MessageFormat.format("remove object {0} with key {1}", objectKey, key)); //$NON-NLS-1$ + ObjectFilter.logger.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. ObjectCache cached = this.cache.getElement(key, objectKey); @@ -296,9 +303,8 @@ public class ObjectFilter { 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.REMOVE.toString(), existingKey, key, - objectKey.toString())); + throw new IllegalArgumentException(MessageFormat.format(msg, Long.toString(id), + Operation.REMOVE.toString(), existingKey, key, objectKey.toString())); } // 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. * * @param object - * The object that shall be registered for addition + * The object that shall be registered for addition */ public void add(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. * * @param objectKey - * the key for the object + * the key for the 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) { 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. * * @param object - * The object that shall be registered for updating + * The object that shall be registered for updating */ public void update(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. * * @param objectKey - * the key for the object + * the key for the 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) { 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. * * @param object - * The object that shall be registered for removal + * The object that shall be registered for removal */ public void remove(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. * * @param objectKey - * the key for the object + * the key for the 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) { remove(object.getClass().getName(), objectKey, object); @@ -398,9 +404,9 @@ public class ObjectFilter { * Returns the ObjectCache for the given key and objectKey * * @param key - * the key under which it was registered + * the key under which it was registered * @param objectKey - * the objectKey + * the objectKey * * @return the ObjectCache, or null */ @@ -412,11 +418,11 @@ public class ObjectFilter { * Returns the element with the given key and objectKey * * @param key - * the key under which it was registered + * the key under which it was registered * @param objectKey - * the objectKey + * the objectKey * @param - * the class to which to cast the element to + * the class to which to cast the element to * * @return the element, or null */ @@ -433,9 +439,9 @@ public class ObjectFilter { * Return true if the element with the given key and objectKey exist * * @param key - * the key under which it was registered + * the key under which it was registered * @param objectKey - * the objectKey + * the objectKey * * @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. * * @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. */ @@ -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. * * @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 - * 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. */ @@ -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. * * @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. */ @@ -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. * * @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 - * 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. */ @@ -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. * * @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. */ @@ -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. * * @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 - * 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. */ @@ -579,9 +585,9 @@ public class ObjectFilter { * Get all objects that were registered under the given key * * @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 - * 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. */ @@ -602,7 +608,7 @@ public class ObjectFilter { * Get all objects that of the given class * * @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 */ @@ -624,7 +630,7 @@ public class ObjectFilter { * is associated to the object. * * @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. */ @@ -642,7 +648,7 @@ public class ObjectFilter { * is associated to the object. * * @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. */