[Major] Multiple changes to StrolchTransaction:

New:
- needsCommit() -> return true if objects or commands are registered
- hasResource()
- hasOrder()
- hasActivity()

Changes:
- When tx.add(), update() or remove() is called, then get*Template(),  or get*By() check the internal cache and thus e.g. a new resource is immediately available.
- the has*()-methods also check the internal cache, thus the need to get the underlying maps should now no longe be required in normal TX use.
This commit is contained in:
Robert von Burg 2017-10-04 13:07:42 +02:00
parent b2604f7ab5
commit dad2f35b16
9 changed files with 1082 additions and 680 deletions

View File

@ -25,7 +25,7 @@ import li.strolch.model.parameter.Parameter;
/**
* @author Robert von Burg <eitch@eitchnet.ch>
*/
class ElementMapHelpers {
public class ElementMapHelpers {
public static void assertIsRefParam(String expectedInterpretation, Parameter<?> refP) {

View File

@ -15,50 +15,21 @@
*/
package li.strolch.persistence.api;
import static li.strolch.model.StrolchModelConstants.*;
import static li.strolch.model.Tags.AGENT;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.ResourceBundle;
import java.util.Set;
import java.util.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import li.strolch.agent.api.ActivityMap;
import li.strolch.agent.api.AuditTrail;
import li.strolch.agent.api.ComponentContainer;
import li.strolch.agent.api.ObserverEvent;
import li.strolch.agent.api.ObserverHandler;
import li.strolch.agent.api.OrderMap;
import li.strolch.agent.api.ResourceMap;
import li.strolch.agent.api.StrolchAgent;
import li.strolch.agent.api.StrolchLockException;
import li.strolch.agent.api.StrolchRealm;
import li.strolch.agent.impl.AuditingActivityMap;
import li.strolch.agent.impl.AuditingAuditMapFacade;
import li.strolch.agent.impl.AuditingOrderMap;
import li.strolch.agent.impl.AuditingResourceMap;
import li.strolch.agent.impl.InternalStrolchRealm;
import li.strolch.agent.api.*;
import li.strolch.agent.impl.*;
import li.strolch.exception.StrolchAccessDeniedException;
import li.strolch.exception.StrolchException;
import li.strolch.exception.StrolchModelException;
import li.strolch.handler.operationslog.LogMessage;
import li.strolch.handler.operationslog.LogSeverity;
import li.strolch.handler.operationslog.OperationsLog;
import li.strolch.model.GroupedParameterizedElement;
import li.strolch.model.Locator;
import li.strolch.model.Order;
import li.strolch.model.ParameterBag;
import li.strolch.model.Resource;
import li.strolch.model.StrolchElement;
import li.strolch.model.StrolchRootElement;
import li.strolch.model.Tags;
import li.strolch.model.*;
import li.strolch.model.activity.Activity;
import li.strolch.model.activity.IActivityElement;
import li.strolch.model.audit.AccessType;
@ -73,11 +44,11 @@ import li.strolch.model.query.ResourceQuery;
import li.strolch.model.query.StrolchQuery;
import li.strolch.model.timedstate.StrolchTimedState;
import li.strolch.model.timevalue.IValue;
import li.strolch.model.visitor.ElementTypeVisitor;
import li.strolch.privilege.base.AccessDeniedException;
import li.strolch.privilege.base.PrivilegeException;
import li.strolch.privilege.model.Certificate;
import li.strolch.privilege.model.PrivilegeContext;
import li.strolch.runtime.StrolchConstants;
import li.strolch.runtime.privilege.PrivilegeHandler;
import li.strolch.runtime.privilege.TransactedRestrictable;
import li.strolch.service.api.Command;
@ -85,6 +56,8 @@ import li.strolch.utils.dbc.DBC;
import li.strolch.utils.helper.ExceptionHelper;
import li.strolch.utils.helper.StringHelper;
import li.strolch.utils.objectfilter.ObjectFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author Robert von Burg <eitch@eitchnet.ch>
@ -279,7 +252,12 @@ public abstract class AbstractTransaction implements StrolchTransaction {
}
@Override
public <T extends StrolchRootElement> void lock(Locator locator) throws StrolchLockException {
public boolean needsCommit() {
return !this.objectFilter.isEmpty() || !this.commands.isEmpty() || !this.flushedCommands.isEmpty();
}
@Override
public void lock(Locator locator) throws StrolchLockException {
this.realm.lock(locator);
this.lockedElements.add(locator);
}
@ -511,33 +489,52 @@ public abstract class AbstractTransaction implements StrolchTransaction {
throw new StrolchException(MessageFormat.format(msg, locator, stateOrBagOrActivity));
}
private <V> V getElementFromFilter(String key, Locator locator) {
if (this.objectFilter == null)
return null;
return this.objectFilter.getElement(key, locator);
}
private boolean hasElementInFilter(String key, Locator locator) {
return this.objectFilter != null && this.objectFilter.hasElement(key, locator);
}
@Override
public Resource getResourceTemplate(String type) {
return getResourceMap().getTemplate(this, type);
return getResourceTemplate(type, false);
}
@Override
public Resource getResourceTemplate(String type, boolean assertExists) throws StrolchException {
Resource element = getElementFromFilter(Tags.RESOURCE, Resource.locatorFor(StrolchConstants.TEMPLATE, type));
if (element != null)
return element;
return getResourceMap().getTemplate(this, type, assertExists);
}
@Override
public Order getOrderTemplate(String type) {
return getOrderMap().getTemplate(this, type);
return getOrderTemplate(type, false);
}
@Override
public Order getOrderTemplate(String type, boolean assertExists) throws StrolchException {
Order element = getElementFromFilter(Tags.ORDER, Order.locatorFor(StrolchConstants.TEMPLATE, type));
if (element != null)
return element;
return getOrderMap().getTemplate(this, type, assertExists);
}
@Override
public Activity getActivityTemplate(String type) {
return getActivityMap().getTemplate(this, type);
return getActivityTemplate(type, false);
}
@Override
public Activity getActivityTemplate(String type, boolean assertExists) throws StrolchException {
Activity element = getElementFromFilter(Tags.ACTIVITY, Activity.locatorFor(StrolchConstants.TEMPLATE, type));
if (element != null)
return element;
return getActivityMap().getTemplate(this, type, assertExists);
}
@ -548,31 +545,43 @@ public abstract class AbstractTransaction implements StrolchTransaction {
@Override
public Order getOrderBy(String type, String id, boolean assertExists) throws StrolchException {
Order element = getElementFromFilter(Tags.ORDER, Order.locatorFor(type, id));
if (element != null)
return element;
return getOrderMap().getBy(this, type, id, assertExists);
}
@Override
public Order getOrderBy(StringParameter refP) throws StrolchException {
DBC.PRE.assertNotNull("refP", refP);
return getOrderBy(refP, false);
}
@Override
public Order getOrderBy(StringParameter refP, boolean assertExists) throws StrolchException {
DBC.PRE.assertNotNull("refP", refP);
ElementMapHelpers.assertIsRefParam(INTERPRETATION_ORDER_REF, refP);
Order element = getElementFromFilter(Tags.ORDER, Order.locatorFor(refP.getUom(), refP.getValue()));
if (element != null)
return element;
return getOrderMap().getBy(this, refP, assertExists);
}
@Override
public List<Order> getOrdersBy(StringListParameter refP) throws StrolchException {
DBC.PRE.assertNotNull("refP", refP);
return getOrderMap().getBy(this, refP, false);
return getOrdersBy(refP, false);
}
@Override
public List<Order> getOrdersBy(StringListParameter refP, boolean assertExists) throws StrolchException {
DBC.PRE.assertNotNull("refP", refP);
return getOrderMap().getBy(this, refP, assertExists);
ElementMapHelpers.assertIsRefParam(INTERPRETATION_ORDER_REF, refP);
List<Order> elements = new ArrayList<>();
for (String id : refP.getValue()) {
Order element = getOrderBy(refP.getUom(), id, assertExists);
if (element != null)
elements.add(element);
}
return elements;
}
@Override
@ -582,36 +591,43 @@ public abstract class AbstractTransaction implements StrolchTransaction {
@Override
public Resource getResourceBy(String type, String id, boolean assertExists) throws StrolchException {
Resource resource = getResourceMap().getBy(this, type, id);
if (assertExists && resource == null) {
String msg = "No Resource exists with the id {0} with type {1}";
throw new StrolchException(MessageFormat.format(msg, id, type));
}
return resource;
Resource result = getElementFromFilter(Tags.RESOURCE, Resource.locatorFor(type, id));
if (result != null)
return result;
return getResourceMap().getBy(this, type, id, assertExists);
}
@Override
public Resource getResourceBy(StringParameter refP) throws StrolchException {
DBC.PRE.assertNotNull("refP", refP);
return getResourceBy(refP, false);
}
@Override
public Resource getResourceBy(StringParameter refP, boolean assertExists) throws StrolchException {
DBC.PRE.assertNotNull("refP", refP);
ElementMapHelpers.assertIsRefParam(INTERPRETATION_RESOURCE_REF, refP);
Resource element = getElementFromFilter(Tags.RESOURCE, Resource.locatorFor(refP.getUom(), refP.getValue()));
if (element != null)
return element;
return getResourceMap().getBy(this, refP, assertExists);
}
@Override
public List<Resource> getResourcesBy(StringListParameter refP) throws StrolchException {
DBC.PRE.assertNotNull("refP", refP);
return getResourceMap().getBy(this, refP, false);
return getResourcesBy(refP, false);
}
@Override
public List<Resource> getResourcesBy(StringListParameter refP, boolean assertExists) throws StrolchException {
DBC.PRE.assertNotNull("refP", refP);
return getResourceMap().getBy(this, refP, assertExists);
ElementMapHelpers.assertIsRefParam(INTERPRETATION_RESOURCE_REF, refP);
List<Resource> elements = new ArrayList<>();
for (String id : refP.getValue()) {
Resource element = getResourceBy(refP.getUom(), id, assertExists);
if (element != null)
elements.add(element);
}
return elements;
}
@Override
@ -621,36 +637,61 @@ public abstract class AbstractTransaction implements StrolchTransaction {
@Override
public Activity getActivityBy(String type, String id, boolean assertExists) throws StrolchException {
Activity activity = getActivityMap().getBy(this, type, id);
if (assertExists && activity == null) {
String msg = "No Activity exists with the id {0} with type {1}";
throw new StrolchException(MessageFormat.format(msg, id, type));
}
return activity;
Activity result = getElementFromFilter(Tags.ACTIVITY, Activity.locatorFor(type, id));
if (result != null)
return result;
return getActivityMap().getBy(this, type, id, assertExists);
}
@Override
public Activity getActivityBy(StringParameter refP) throws StrolchException {
DBC.PRE.assertNotNull("refP", refP);
return getActivityBy(refP, false);
}
@Override
public Activity getActivityBy(StringParameter refP, boolean assertExists) throws StrolchException {
DBC.PRE.assertNotNull("refP", refP);
ElementMapHelpers.assertIsRefParam(INTERPRETATION_ACTIVITY_REF, refP);
Activity element = getElementFromFilter(Tags.ACTIVITY, Activity.locatorFor(refP.getUom(), refP.getValue()));
if (element != null)
return element;
return getActivityMap().getBy(this, refP, assertExists);
}
@Override
public List<Activity> getActivitiesBy(StringListParameter refP) throws StrolchException {
DBC.PRE.assertNotNull("refP", refP);
return getActivityMap().getBy(this, refP, false);
return getActivitiesBy(refP, false);
}
@Override
public List<Activity> getActivitiesBy(StringListParameter refP, boolean assertExists) throws StrolchException {
DBC.PRE.assertNotNull("refP", refP);
return getActivityMap().getBy(this, refP, assertExists);
ElementMapHelpers.assertIsRefParam(INTERPRETATION_ACTIVITY_REF, refP);
List<Activity> elements = new ArrayList<>();
for (String id : refP.getValue()) {
Activity element = getActivityBy(refP.getUom(), id, assertExists);
if (element != null)
elements.add(element);
}
return elements;
}
@Override
public boolean hasResource(String type, String id) {
boolean inFilter = hasElementInFilter(Tags.RESOURCE, Resource.locatorFor(type, id));
return inFilter || getResourceMap().hasElement(this, type, id);
}
@Override
public boolean hasOrder(String type, String id) {
boolean inFilter = hasElementInFilter(Tags.ORDER, Order.locatorFor(type, id));
return inFilter || getOrderMap().hasElement(this, type, id);
}
@Override
public boolean hasActivity(String type, String id) {
boolean inFilter = hasElementInFilter(Tags.ACTIVITY, Activity.locatorFor(type, id));
return inFilter || getActivityMap().hasElement(this, type, id);
}
private ObjectFilter getObjectFilter() {
@ -670,55 +711,55 @@ public abstract class AbstractTransaction implements StrolchTransaction {
@Override
public void add(Resource resource) throws StrolchModelException {
DBC.PRE.assertNotNull("resource must not be null", resource);
getObjectFilter().add(Tags.RESOURCE, resource);
getObjectFilter().add(Tags.RESOURCE, resource.getLocator(), resource);
}
@Override
public void add(Order order) throws StrolchException {
DBC.PRE.assertNotNull("order must not be null", order);
getObjectFilter().add(Tags.ORDER, order);
getObjectFilter().add(Tags.ORDER, order.getLocator(), order);
}
@Override
public void add(Activity activity) throws StrolchException {
DBC.PRE.assertNotNull("activity must not be null", activity);
getObjectFilter().add(Tags.ACTIVITY, activity);
getObjectFilter().add(Tags.ACTIVITY, activity.getLocator(), activity);
}
@Override
public void update(Resource resource) throws StrolchException {
DBC.PRE.assertNotNull("resource must not be null", resource);
getObjectFilter().update(Tags.RESOURCE, resource);
getObjectFilter().update(Tags.RESOURCE, resource.getLocator(), resource);
}
@Override
public void update(Order order) {
DBC.PRE.assertNotNull("order must not be null", order);
getObjectFilter().update(Tags.ORDER, order);
getObjectFilter().update(Tags.ORDER, order.getLocator(), order);
}
@Override
public void update(Activity activity) throws StrolchException {
DBC.PRE.assertNotNull("activity must not be null", activity);
getObjectFilter().update(Tags.ACTIVITY, activity);
getObjectFilter().update(Tags.ACTIVITY, activity.getLocator(), activity);
}
@Override
public void remove(Resource resource) throws StrolchException {
DBC.PRE.assertNotNull("resource must not be null", resource);
getObjectFilter().remove(Tags.RESOURCE, resource);
getObjectFilter().remove(Tags.RESOURCE, resource.getLocator(), resource);
}
@Override
public void remove(Order order) throws StrolchException {
DBC.PRE.assertNotNull("order must not be null", order);
getObjectFilter().remove(Tags.ORDER, order);
getObjectFilter().remove(Tags.ORDER, order.getLocator(), order);
}
@Override
public void remove(Activity activity) throws StrolchException {
DBC.PRE.assertNotNull("activity must not be null", activity);
getObjectFilter().remove(Tags.ACTIVITY, activity);
getObjectFilter().remove(Tags.ACTIVITY, activity.getLocator(), activity);
}
private void addModelChangeCommands() {
@ -923,6 +964,9 @@ public abstract class AbstractTransaction implements StrolchTransaction {
try {
this.txResult.setState(TransactionState.CLOSING);
Thread.currentThread().getUncaughtExceptionHandler();
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
if (!this.commands.isEmpty()) {
autoCloseableRollback();
String msg = "There are commands registered on a read-only transaction. Changing to rollback! Did you forget to commit?";
@ -943,6 +987,13 @@ public abstract class AbstractTransaction implements StrolchTransaction {
handleReadOnly(start, auditTrailDuration);
this.txResult.setState(TransactionState.CLOSED);
} catch (Exception e) {
this.txResult.setState(TransactionState.ROLLING_BACK);
try {
undoCommands();
rollback();
} catch (Exception e1) {
logger.error("Failed to rollback after exception", e);
}
handleFailure(start, e);
this.txResult.setState(TransactionState.FAILED);
} finally {
@ -1062,7 +1113,7 @@ public abstract class AbstractTransaction implements StrolchTransaction {
logger.error(sb.toString());
}
protected void handleFailure(long closeStartNanos, Exception e) {
private void handleFailure(long closeStartNanos, Exception e) {
long end = System.nanoTime();
long txDuration = end - this.txResult.getStartNanos();
@ -1099,7 +1150,13 @@ public abstract class AbstractTransaction implements StrolchTransaction {
String msg = "Strolch Transaction for realm {0} failed due to {1}\n{2}"; //$NON-NLS-1$
msg = MessageFormat.format(msg, getRealmName(), ExceptionHelper.getExceptionMessage(e), sb.toString());
throw new StrolchTransactionException(msg, e);
StrolchTransactionException ex = new StrolchTransactionException(msg, e);
if (this.closeStrategy == TransactionCloseStrategy.COMMIT)
throw ex;
else
logger.error("Transaction failed in non-commit mode! Logging TX exception, so exception is not suppressed.",
ex);
}
private boolean isAuditTrailEnabled() {
@ -1116,36 +1173,35 @@ public abstract class AbstractTransaction implements StrolchTransaction {
if (this.resourceMap != null) {
if (!this.resourceMap.getCreated().isEmpty())
event.added.addList(Tags.RESOURCE, new ArrayList<StrolchRootElement>(this.resourceMap.getCreated()));
event.added.addList(Tags.RESOURCE, new ArrayList<>(this.resourceMap.getCreated()));
if (!this.resourceMap.getUpdated().isEmpty())
event.updated.addList(Tags.RESOURCE, new ArrayList<StrolchRootElement>(this.resourceMap.getUpdated()));
event.updated.addList(Tags.RESOURCE, new ArrayList<>(this.resourceMap.getUpdated()));
if (!this.resourceMap.getDeleted().isEmpty())
event.removed.addList(Tags.RESOURCE, new ArrayList<StrolchRootElement>(this.resourceMap.getDeleted()));
event.removed.addList(Tags.RESOURCE, new ArrayList<>(this.resourceMap.getDeleted()));
}
if (this.orderMap != null) {
if (!this.orderMap.getCreated().isEmpty())
event.added.addList(Tags.ORDER, new ArrayList<StrolchRootElement>(this.orderMap.getCreated()));
event.added.addList(Tags.ORDER, new ArrayList<>(this.orderMap.getCreated()));
if (!this.orderMap.getUpdated().isEmpty())
event.updated.addList(Tags.ORDER, new ArrayList<StrolchRootElement>(this.orderMap.getUpdated()));
event.updated.addList(Tags.ORDER, new ArrayList<>(this.orderMap.getUpdated()));
if (!this.orderMap.getDeleted().isEmpty())
event.removed.addList(Tags.ORDER, new ArrayList<StrolchRootElement>(this.orderMap.getDeleted()));
event.removed.addList(Tags.ORDER, new ArrayList<>(this.orderMap.getDeleted()));
}
if (this.activityMap != null) {
if (!this.activityMap.getCreated().isEmpty())
event.added.addList(Tags.ACTIVITY, new ArrayList<StrolchRootElement>(this.activityMap.getCreated()));
event.added.addList(Tags.ACTIVITY, new ArrayList<>(this.activityMap.getCreated()));
if (!this.activityMap.getUpdated().isEmpty())
event.updated.addList(Tags.ACTIVITY, new ArrayList<StrolchRootElement>(this.activityMap.getUpdated()));
event.updated.addList(Tags.ACTIVITY, new ArrayList<>(this.activityMap.getUpdated()));
if (!this.activityMap.getDeleted().isEmpty())
event.removed.addList(Tags.ACTIVITY, new ArrayList<StrolchRootElement>(this.activityMap.getDeleted()));
event.removed.addList(Tags.ACTIVITY, new ArrayList<>(this.activityMap.getDeleted()));
}
ObserverHandler observerHandler = this.realm.getObserverHandler();
observerHandler.notify(event);
long observerUpdateDuration = System.nanoTime() - observerUpdateStart;
return observerUpdateDuration;
return System.nanoTime() - observerUpdateStart;
}
private boolean isObserverUpdatesEnabled() {
@ -1166,26 +1222,26 @@ public abstract class AbstractTransaction implements StrolchTransaction {
if (this.orderMap != null) {
if (this.realm.isAuditTrailEnabledForRead())
auditsFor(audits, AccessType.READ, Tags.ORDER, this.orderMap.getRead());
auditsFor(audits, AccessType.CREATE, Tags.ORDER, this.orderMap.getCreated());
auditsFor(audits, AccessType.UPDATE, Tags.ORDER, this.orderMap.getUpdated());
auditsFor(audits, AccessType.DELETE, Tags.ORDER, this.orderMap.getDeleted());
auditsFor(audits, AccessType.READ, this.orderMap.getRead());
auditsFor(audits, AccessType.CREATE, this.orderMap.getCreated());
auditsFor(audits, AccessType.UPDATE, this.orderMap.getUpdated());
auditsFor(audits, AccessType.DELETE, this.orderMap.getDeleted());
}
if (this.resourceMap != null) {
if (this.realm.isAuditTrailEnabledForRead())
auditsFor(audits, AccessType.READ, Tags.RESOURCE, this.resourceMap.getRead());
auditsFor(audits, AccessType.CREATE, Tags.RESOURCE, this.resourceMap.getCreated());
auditsFor(audits, AccessType.UPDATE, Tags.RESOURCE, this.resourceMap.getUpdated());
auditsFor(audits, AccessType.DELETE, Tags.RESOURCE, this.resourceMap.getDeleted());
auditsFor(audits, AccessType.READ, this.resourceMap.getRead());
auditsFor(audits, AccessType.CREATE, this.resourceMap.getCreated());
auditsFor(audits, AccessType.UPDATE, this.resourceMap.getUpdated());
auditsFor(audits, AccessType.DELETE, this.resourceMap.getDeleted());
}
if (this.activityMap != null) {
if (this.realm.isAuditTrailEnabledForRead())
auditsFor(audits, AccessType.READ, Tags.ACTIVITY, this.activityMap.getRead());
auditsFor(audits, AccessType.CREATE, Tags.ACTIVITY, this.activityMap.getCreated());
auditsFor(audits, AccessType.UPDATE, Tags.ACTIVITY, this.activityMap.getUpdated());
auditsFor(audits, AccessType.DELETE, Tags.ACTIVITY, this.activityMap.getDeleted());
auditsFor(audits, AccessType.READ, this.activityMap.getRead());
auditsFor(audits, AccessType.CREATE, this.activityMap.getCreated());
auditsFor(audits, AccessType.UPDATE, this.activityMap.getUpdated());
auditsFor(audits, AccessType.DELETE, this.activityMap.getDeleted());
}
if (this.auditTrail != null && !isSuppressAuditsForAudits()) {
@ -1199,23 +1255,16 @@ public abstract class AbstractTransaction implements StrolchTransaction {
if (!audits.isEmpty())
this.realm.getAuditTrail().addAll(this, audits);
long auditTrailDuration = System.nanoTime() - auditTrailStart;
return auditTrailDuration;
return System.nanoTime() - auditTrailStart;
}
private <T extends StrolchRootElement> void auditsFor(List<Audit> audits,
AccessType accessType,
String elementType,
Set<T> elements) {
private <T extends StrolchRootElement> void auditsFor(List<Audit> audits, AccessType accessType, Set<T> elements) {
for (StrolchRootElement element : elements) {
audits.add(auditFrom(accessType, element));
}
}
private <T extends StrolchRootElement> void auditsForAudits(List<Audit> audits,
AccessType accessType,
String elementType,
Set<Audit> elements) {
private void auditsForAudits(List<Audit> audits, AccessType accessType, String elementType, Set<Audit> elements) {
for (Audit element : elements) {
audits.add(auditFrom(accessType, elementType, StringHelper.DASH, element.getId().toString()));
}
@ -1223,7 +1272,7 @@ public abstract class AbstractTransaction implements StrolchTransaction {
@Override
public Audit auditFrom(AccessType accessType, StrolchRootElement element) {
String type = element.accept(new ElementTypeVisitor());
String type = element.getObjectType();
String subType = element.getType();
String id = element.getId();
return auditFrom(accessType, type, subType, id);

View File

@ -0,0 +1,328 @@
/*
* Copyright 2015 Robert von Burg <eitch@eitchnet.ch>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package li.strolch.service;
import static li.strolch.model.ModelGenerator.BAG_ID;
import static org.junit.Assert.*;
import java.util.Arrays;
import java.util.List;
import li.strolch.agent.api.StrolchAgent;
import li.strolch.model.ModelGenerator;
import li.strolch.model.Order;
import li.strolch.model.Resource;
import li.strolch.model.activity.Activity;
import li.strolch.model.activity.TimeOrdering;
import li.strolch.model.parameter.StringListParameter;
import li.strolch.model.parameter.StringParameter;
import li.strolch.persistence.api.StrolchTransaction;
import li.strolch.runtime.StrolchConstants;
import li.strolch.service.api.AbstractService;
import li.strolch.service.api.ServiceArgument;
import li.strolch.service.api.ServiceResult;
import li.strolch.service.test.AbstractRealmServiceTest;
import org.junit.Test;
public class TxExtendedTest extends AbstractRealmServiceTest {
@Test
public void shouldCommit() {
runServiceInAllRealmTypes(CommitService.class, new ServiceArgument());
}
@Test
public void shouldRollback() {
runServiceInAllRealmTypes(RollbackService.class, new ServiceArgument());
}
public static class CommitService extends AbstractService<ServiceArgument, ServiceResult> {
private static final long serialVersionUID = 1L;
@Override
protected ServiceResult getResultInstance() {
return new ServiceResult();
}
@Override
public ServiceArgument getArgumentInstance() {
return new ServiceArgument();
}
@Override
protected ServiceResult internalDoService(ServiceArgument arg) throws Exception {
String type = "MyType";
String resId = StrolchAgent.getUniqueId();
Resource resource = ModelGenerator.createResource(resId, resId, type);
Resource resource1 = ModelGenerator.createResource(resId + "1", resId + "1", type);
Resource resource2 = ModelGenerator.createResource(resId + "2", resId + "2", type);
Resource resource3 = ModelGenerator.createResource(resId + "3", resId + "3", type);
StringListParameter resRefsP = new StringListParameter("refP", "Ref P",
Arrays.asList(resource1.getId(), resource2.getId(), resource3.getId()));
resRefsP.setInterpretation(StrolchConstants.INTERPRETATION_RESOURCE_REF);
resRefsP.setUom(type);
resource.addParameter(BAG_ID, resRefsP);
StringParameter resRefP = new StringParameter("refP", "Ref P", resource.getId());
resRefP.setInterpretation(StrolchConstants.INTERPRETATION_RESOURCE_REF);
resRefP.setUom(type);
resource1.addParameter(BAG_ID, resRefP.getClone());
resource2.addParameter(BAG_ID, resRefP.getClone());
resource3.addParameter(BAG_ID, resRefP.getClone());
String orderId = StrolchAgent.getUniqueId();
Order order = ModelGenerator.createOrder(orderId, orderId, type);
Order order1 = ModelGenerator.createOrder(orderId + "1", orderId + "1", type);
Order order2 = ModelGenerator.createOrder(orderId + "2", orderId + "2", type);
Order order3 = ModelGenerator.createOrder(orderId + "3", orderId + "3", type);
StringListParameter orderRefsP = new StringListParameter("refP", "Ref P",
Arrays.asList(order1.getId(), order2.getId(), order3.getId()));
orderRefsP.setInterpretation(StrolchConstants.INTERPRETATION_ORDER_REF);
orderRefsP.setUom(type);
order.addParameter(BAG_ID, orderRefsP);
StringParameter orderRefP = new StringParameter("refP", "Ref P", order.getId());
orderRefP.setInterpretation(StrolchConstants.INTERPRETATION_ORDER_REF);
orderRefP.setUom(type);
order1.addParameter(BAG_ID, orderRefP.getClone());
order2.addParameter(BAG_ID, orderRefP.getClone());
order3.addParameter(BAG_ID, orderRefP.getClone());
String activityId = StrolchAgent.getUniqueId();
Activity activity = ModelGenerator.createActivity(activityId, activityId, type, TimeOrdering.SERIES);
Activity activity1 = ModelGenerator
.createActivity(activityId + "1", activityId + "1", type, TimeOrdering.SERIES);
Activity activity2 = ModelGenerator
.createActivity(activityId + "2", activityId + "2", type, TimeOrdering.SERIES);
Activity activity3 = ModelGenerator
.createActivity(activityId + "3", activityId + "3", type, TimeOrdering.SERIES);
StringListParameter actRefsP = new StringListParameter("refP", "Ref P",
Arrays.asList(activity1.getId(), activity2.getId(), activity3.getId()));
actRefsP.setInterpretation(StrolchConstants.INTERPRETATION_ACTIVITY_REF);
actRefsP.setUom(type);
activity.addParameter(BAG_ID, actRefsP);
StringParameter actRefP = new StringParameter("refP", "Ref P", activity.getId());
actRefP.setInterpretation(StrolchConstants.INTERPRETATION_ACTIVITY_REF);
actRefP.setUom(type);
activity1.addParameter(BAG_ID, actRefP.getClone());
activity2.addParameter(BAG_ID, actRefP.getClone());
activity3.addParameter(BAG_ID, actRefP.getClone());
try (StrolchTransaction tx = openTx(arg.realm)) {
// resource
assertNull(tx.getResourceBy(type, resId));
assertFalse(tx.hasResource(type, resId));
assertEquals(0, tx.getResourcesBy(resRefsP).size());
tx.add(resource);
tx.add(resource1);
tx.add(resource2);
tx.add(resource3);
tx.update(resource3);
assertNotNull(tx.getResourceBy(type, resId));
assertTrue(tx.hasResource(type, resId));
List<Resource> resourcesBy = tx.getResourcesBy(resRefsP);
assertEquals(3, resourcesBy.size());
for (Resource res : resourcesBy) {
assertEquals(resource, tx.getResourceBy(res.getParameter(BAG_ID, "refP")));
}
// order
assertNull(tx.getOrderBy(type, orderId));
assertFalse(tx.hasOrder(type, orderId));
assertEquals(0, tx.getOrdersBy(orderRefsP).size());
tx.add(order);
tx.add(order1);
tx.add(order2);
tx.add(order3);
tx.update(order3);
assertNotNull(tx.getOrderBy(type, orderId));
assertTrue(tx.hasOrder(type, orderId));
List<Order> ordersBy = tx.getOrdersBy(orderRefsP);
assertEquals(3, ordersBy.size());
for (Order o : ordersBy) {
assertEquals(order, tx.getOrderBy(o.getParameter(BAG_ID, "refP")));
}
// activity
assertNull(tx.getActivityBy(type, activityId));
assertFalse(tx.hasActivity(type, activityId));
assertEquals(0, tx.getActivitiesBy(actRefsP).size());
tx.add(activity);
tx.add(activity1);
tx.add(activity2);
tx.add(activity3);
tx.update(activity3);
assertNotNull(tx.getActivityBy(type, activityId));
assertTrue(tx.hasActivity(type, activityId));
List<Activity> activitiesBy = tx.getActivitiesBy(actRefsP);
assertEquals(3, activitiesBy.size());
for (Activity a : activitiesBy) {
assertEquals(activity, tx.getActivityBy(a.getParameter(BAG_ID, "refP")));
}
tx.commitOnClose();
}
// now make sure the new resource exists
try (StrolchTransaction tx = openTx(arg.realm)) {
assertNotNull(tx.getResourceBy(type, resource.getId()));
assertNotNull(tx.getOrderBy(type, order.getId()));
assertNotNull(tx.getActivityBy(type, activity.getId()));
}
try (StrolchTransaction tx = openTx(arg.realm)) {
tx.remove(resource);
tx.remove(order);
tx.remove(activity);
tx.commitOnClose();
}
try (StrolchTransaction tx = openTx(arg.realm)) {
assertNull(tx.getResourceBy(type, resource.getId()));
assertNull(tx.getOrderBy(type, order.getId()));
assertNull(tx.getActivityBy(type, activity.getId()));
}
return ServiceResult.success();
}
}
public static class RollbackService extends AbstractService<ServiceArgument, ServiceResult> {
private static final long serialVersionUID = 1L;
@Override
protected ServiceResult getResultInstance() {
return new ServiceResult();
}
@Override
public ServiceArgument getArgumentInstance() {
return new ServiceArgument();
}
@Override
protected ServiceResult internalDoService(ServiceArgument arg) throws Exception {
String type = "MyType";
String resId = StrolchAgent.getUniqueId();
Resource resource = ModelGenerator.createResource(resId, resId, type);
Resource resource1 = ModelGenerator.createResource(resId + "1", resId + "1", type);
Resource resource2 = ModelGenerator.createResource(resId + "2", resId + "2", type);
Resource resource3 = ModelGenerator.createResource(resId + "3", resId + "3", type);
StringListParameter resRefP = new StringListParameter("refP", "Ref P",
Arrays.asList(resource1.getId(), resource2.getId(), resource3.getId()));
resRefP.setInterpretation(StrolchConstants.INTERPRETATION_RESOURCE_REF);
resRefP.setUom(type);
resource.addParameter(BAG_ID, resRefP);
String orderId = StrolchAgent.getUniqueId();
Order order = ModelGenerator.createOrder(orderId, orderId, type);
Order order1 = ModelGenerator.createOrder(orderId + "1", orderId + "1", type);
Order order2 = ModelGenerator.createOrder(orderId + "2", orderId + "2", type);
Order order3 = ModelGenerator.createOrder(orderId + "3", orderId + "3", type);
StringListParameter orderRefP = new StringListParameter("refP", "Ref P",
Arrays.asList(order1.getId(), order2.getId(), order3.getId()));
orderRefP.setInterpretation(StrolchConstants.INTERPRETATION_ORDER_REF);
orderRefP.setUom(type);
order.addParameter(BAG_ID, orderRefP);
String activityId = StrolchAgent.getUniqueId();
Activity activity = ModelGenerator.createActivity(activityId, activityId, type, TimeOrdering.SERIES);
Activity activity1 = ModelGenerator
.createActivity(activityId + "1", activityId + "1", type, TimeOrdering.SERIES);
Activity activity2 = ModelGenerator
.createActivity(activityId + "2", activityId + "2", type, TimeOrdering.SERIES);
Activity activity3 = ModelGenerator
.createActivity(activityId + "3", activityId + "3", type, TimeOrdering.SERIES);
StringListParameter actRefP = new StringListParameter("refP", "Ref P",
Arrays.asList(activity1.getId(), activity2.getId(), activity3.getId()));
actRefP.setInterpretation(StrolchConstants.INTERPRETATION_ACTIVITY_REF);
actRefP.setUom(type);
activity.addParameter(BAG_ID, actRefP);
try (StrolchTransaction tx = openTx(arg.realm)) {
// resource
assertNull(tx.getResourceBy(type, resId));
assertFalse(tx.hasResource(type, resId));
assertEquals(0, tx.getResourcesBy(resRefP).size());
tx.add(resource);
tx.add(resource1);
tx.add(resource2);
tx.add(resource3);
assertNotNull(tx.getResourceBy(type, resId));
assertTrue(tx.hasResource(type, resId));
assertEquals(3, tx.getResourcesBy(resRefP).size());
// order
assertNull(tx.getOrderBy(type, orderId));
assertFalse(tx.hasOrder(type, orderId));
assertEquals(0, tx.getOrdersBy(orderRefP).size());
tx.add(order);
tx.add(order1);
tx.add(order2);
tx.add(order3);
assertNotNull(tx.getOrderBy(type, orderId));
assertTrue(tx.hasOrder(type, orderId));
assertEquals(3, tx.getOrdersBy(orderRefP).size());
// activity
assertNull(tx.getActivityBy(type, activityId));
assertFalse(tx.hasActivity(type, activityId));
assertEquals(0, tx.getActivitiesBy(actRefP).size());
tx.add(activity);
tx.add(activity1);
tx.add(activity2);
tx.add(activity3);
assertNotNull(tx.getActivityBy(type, activityId));
assertTrue(tx.hasActivity(type, activityId));
assertEquals(3, tx.getActivitiesBy(actRefP).size());
tx.rollbackOnClose();
}
// now make sure the new resource does not exist
try (StrolchTransaction tx = openTx(arg.realm)) {
assertNull(tx.getResourceBy(type, resource.getId()));
assertNull(tx.getResourceBy(type, resource1.getId()));
assertNull(tx.getResourceBy(type, resource2.getId()));
assertNull(tx.getResourceBy(type, resource3.getId()));
assertNull(tx.getOrderBy(type, order.getId()));
assertNull(tx.getOrderBy(type, order1.getId()));
assertNull(tx.getOrderBy(type, order2.getId()));
assertNull(tx.getOrderBy(type, order3.getId()));
assertNull(tx.getActivityBy(type, activity.getId()));
assertNull(tx.getActivityBy(type, activity1.getId()));
assertNull(tx.getActivityBy(type, activity2.getId()));
assertNull(tx.getActivityBy(type, activity3.getId()));
}
return ServiceResult.success();
}
}
}

View File

@ -18,9 +18,6 @@ package li.strolch.service;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import org.junit.Ignore;
import org.junit.Test;
import li.strolch.model.ModelGenerator;
import li.strolch.model.Order;
import li.strolch.model.Resource;
@ -31,6 +28,7 @@ import li.strolch.service.api.ServiceArgument;
import li.strolch.service.api.ServiceResult;
import li.strolch.service.test.AbstractRealmServiceTest;
import li.strolch.utils.dbc.DBC;
import org.junit.Test;
public class TxTest extends AbstractRealmServiceTest {
@ -53,7 +51,6 @@ public class TxTest extends AbstractRealmServiceTest {
}
@Test
@Ignore("We have to re-think this. It does not work, throwing an exception if commands are registered on a read-only TX as then we don't know if we want to roll back or not - we probably need a ROLLBACK_ON_ERROR or something")
public void shouldNotAllowCommandsOnDoNothing() {
runServiceInAllRealmTypes(ReadonlyFailService.class, new ServiceArgument());

View File

@ -27,28 +27,27 @@ import java.util.Set;
* <p>
* Collection to store a tree with a depth of 3 elements. This solves having to always write the declaration:
* </p>
*
* <p>
* <pre>
* Map&lt;String, Map&lt;String, MyObject&gt;&gt; mapOfMaps = new HashMap&lt;&gt;;
* </pre>
*
* <p>
* <p>
* As an example to persist a map of MyObject where the branches are String one would write it as follows:
* </p>
*
* <p>
* <pre>
* MapOfMaps&lt;String, String, MyObject&gt; mapOfMaps = new MapOfMaps&lt;&gt;();
* </pre>
*
*
* @author Robert von Burg &lt;eitch@eitchnet.ch&gt;
*
*
* @param <T>
* The key to a map with U as the key and V as the value
* The key to a map with U as the key and V as the value
* @param <U>
* The key to get a value (leaf)
* The key to get a value (leaf)
* @param <V>
* The value stored in the tree (leaf)
* The value stored in the tree (leaf)
*
* @author Robert von Burg &lt;eitch@eitchnet.ch&gt;
*/
public class MapOfMaps<T, U, V> {
@ -58,6 +57,10 @@ public class MapOfMaps<T, U, V> {
this.mapOfMaps = new HashMap<>();
}
public MapOfMaps(int initialSize) {
this.mapOfMaps = new HashMap<>(initialSize);
}
public Set<T> keySet() {
return this.mapOfMaps.keySet();
}
@ -74,11 +77,7 @@ public class MapOfMaps<T, U, V> {
}
public V addElement(T t, U u, V v) {
Map<U, V> map = this.mapOfMaps.get(t);
if (map == null) {
map = new HashMap<>();
this.mapOfMaps.put(t, map);
}
Map<U, V> map = this.mapOfMaps.computeIfAbsent(t, k -> new HashMap<>());
return map.put(u, v);
}
@ -100,11 +99,7 @@ public class MapOfMaps<T, U, V> {
}
public void addMap(T t, Map<U, V> u) {
Map<U, V> map = this.mapOfMaps.get(t);
if (map == null) {
map = new HashMap<>();
this.mapOfMaps.put(t, map);
}
Map<U, V> map = this.mapOfMaps.computeIfAbsent(t, k -> new HashMap<>());
map.putAll(u);
}
@ -140,9 +135,7 @@ public class MapOfMaps<T, U, V> {
public boolean containsElement(T t, U u) {
Map<U, V> map = this.mapOfMaps.get(t);
if (map == null)
return false;
return map.containsKey(u);
return map != null && map.containsKey(u);
}
public int sizeKeys() {
@ -152,9 +145,8 @@ public class MapOfMaps<T, U, V> {
public int size() {
int size = 0;
Set<Entry<T, Map<U, V>>> entrySet = this.mapOfMaps.entrySet();
Iterator<Entry<T, Map<U, V>>> iter = entrySet.iterator();
while (iter.hasNext()) {
size += iter.next().getValue().size();
for (Entry<T, Map<U, V>> anEntrySet : entrySet) {
size += anEntrySet.getValue().size();
}
return size;
}

View File

@ -32,7 +32,7 @@ import org.slf4j.LoggerFactory;
* <li>A reference to the current state of the object</li>
* <li>An identifier of the operation that needs to be performed on this</li>
* </ul>
*
*
* @author Michael Gatto &lt;michael@gatto.ch&gt;
* @author Robert von Burg &lt;eitch@eitchnet.ch&gt;
*/
@ -60,16 +60,22 @@ public class ObjectCache {
*/
private Operation operation;
/**
* object The objectKey that shall be cached
*/
private Object objectKey;
/**
* object The object that shall be cached
*/
private Object object;
@SuppressWarnings("nls")
public ObjectCache(long id, String key, Object object, Operation operation) {
public ObjectCache(long id, String key, Object objectKey, Object object, Operation operation) {
this.id = id;
this.key = key;
this.objectKey = objectKey;
this.object = object;
this.operation = operation;
@ -82,29 +88,30 @@ public class ObjectCache {
sb.append(" OP: ");
sb.append(this.operation);
sb.append(" / ");
sb.append(object.toString());
sb.append(objectKey.toString());
logger.debug(sb.toString());
}
}
/**
* Set the new object version of this cache.
*
*
* @param object
* the object to set
* the object to set
*/
public void setObject(Object object) {
if (logger.isDebugEnabled()) {
logger.debug(MessageFormat.format("Updating ID {0} to value {1}", this.id, object.toString())); //$NON-NLS-1$
logger.debug(
MessageFormat.format("Updating ID {0} to value {1}", this.id, object.toString())); //$NON-NLS-1$
}
this.object = object;
}
/**
* Change the operation to execute for this object.
*
*
* @param newOperation
* the operation to set
* the operation to set
*/
public void setOperation(Operation newOperation) {
if (logger.isDebugEnabled()) {
@ -115,30 +122,22 @@ public class ObjectCache {
this.operation = newOperation;
}
/**
* @return the id
*/
public long getId() {
return this.id;
}
/**
* @return the key
*/
public String getKey() {
return this.key;
}
/**
* @return the operation
*/
public Operation getOperation() {
return this.operation;
}
/**
* @return the object
*/
public Object getObjectKey() {
return objectKey;
}
public Object getObject() {
return this.object;
}

View File

@ -16,14 +16,9 @@
package li.strolch.utils.objectfilter;
import java.text.MessageFormat;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.*;
import li.strolch.utils.collections.MapOfMaps;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -71,7 +66,7 @@ import org.slf4j.LoggerFactory;
* <td>Err!</td>
* </tr>
* </table>
*
*
* @author Michael Gatto &lt;michael@gatto.ch&gt; (initial version)
* @author Robert von Burg &lt;eitch@eitchnet.ch&gt; (minor modifications, refactorings)
*/
@ -81,17 +76,29 @@ public class ObjectFilter {
private static long id = ObjectCache.UNSET;
private final Map<Object, ObjectCache> cache;
private final MapOfMaps<String, Object, ObjectCache> cache;
private final Set<String> keySet;
/**
* Default constructor initializing the filter
*/
public ObjectFilter() {
this.cache = new HashMap<>(1);
this.cache = new MapOfMaps<>(1);
this.keySet = new HashSet<>(1);
}
private void replaceKey(ObjectCache cached, Object newObjectKey, Object newObject) {
if (cached.getObjectKey() != newObjectKey) {
if (ObjectFilter.logger.isDebugEnabled()) {
String msg = "Replacing key for object as they are not the same reference: old: {0} / new: {1}"; //$NON-NLS-1$
msg = MessageFormat.format(msg, cached.getObjectKey(), newObjectKey);
ObjectFilter.logger.warn(msg);
}
ObjectCache objectCache = this.cache.removeElement(cached.getKey(), cached.getObjectKey());
this.cache.addElement(objectCache.getKey(), newObjectKey, objectCache);
}
}
/**
* Register, under the given key, the addition of the given object.
* <p>
@ -112,33 +119,37 @@ public class ObjectFilter {
* <td>Update(O2)</td>
* </tr>
* </table>
*
*
* @param key
* the key to register the object with
* the key to register the object with
* @param objectKey
* 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 objectToAdd) {
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.get(objectToAdd);
ObjectCache cached = this.cache.getElement(key, objectKey);
if (cached == null) {
// The object has not yet been added to the cache.
// Hence, we add it now, with the ADD operation.
ObjectCache cacheObj = new ObjectCache(dispenseID(), key, objectToAdd, Operation.ADD);
this.cache.put(objectToAdd, cacheObj);
ObjectCache cacheObj = new ObjectCache(dispenseID(), key, objectKey, objectToAdd, Operation.ADD);
this.cache.addElement(key, objectKey, cacheObj);
} 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.ADD.toString(), existingKey, key, objectToAdd.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
@ -151,7 +162,7 @@ public class ObjectFilter {
throw new IllegalStateException("Stale State exception: Invalid + after +="); //$NON-NLS-1$
case REMOVE:
// replace key if necessary
replaceKey(cached.getObject(), objectToAdd);
replaceKey(cached, objectKey, objectToAdd);
// update operation's object
cached.setObject(objectToAdd);
@ -166,18 +177,6 @@ public class ObjectFilter {
this.keySet.add(key);
}
private void replaceKey(Object oldObject, Object newObject) {
if (oldObject != newObject) {
if (ObjectFilter.logger.isDebugEnabled()) {
String msg = "Replacing key for object as they are not the same reference: old: {0} / new: {1}"; //$NON-NLS-1$
msg = MessageFormat.format(msg, oldObject, newObject);
ObjectFilter.logger.warn(msg);
}
ObjectCache objectCache = this.cache.remove(oldObject);
this.cache.put(newObject, objectCache);
}
}
/**
* Register, under the given key, the update of the given object. *
* </p>
@ -197,33 +196,37 @@ public class ObjectFilter {
* <td>Err!</td>
* </tr>
* </table>
*
*
* @param key
* the key to register the object with
* the key to register the object with
* @param objectKey
* 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 objectToUpdate) {
public void update(String key, Object objectKey, Object objectToUpdate) {
if (ObjectFilter.logger.isDebugEnabled())
ObjectFilter.logger.debug(MessageFormat.format("update object {0} with key {1}", objectToUpdate, 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.get(objectToUpdate);
ObjectCache cached = this.cache.getElement(key, objectKey);
if (cached == null) {
// 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, objectToUpdate, Operation.MODIFY);
this.cache.put(objectToUpdate, cacheObj);
ObjectCache cacheObj = new ObjectCache(dispenseID(), key, objectKey, objectToUpdate, Operation.MODIFY);
this.cache.addElement(key, objectKey, cacheObj);
} 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()));
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.
@ -232,7 +235,7 @@ public class ObjectFilter {
case ADD:
case MODIFY:
// replace key if necessary
replaceKey(cached.getObject(), objectToUpdate);
replaceKey(cached, objectKey, objectToUpdate);
// update operation's object
cached.setObject(objectToUpdate);
@ -267,31 +270,35 @@ public class ObjectFilter {
* <td>Err!</td>
* </tr>
* </table>
*
*
* @param key
* the key to register the object with
* the key to register the object with
* @param objectKey
* 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 objectToRemove) {
public void remove(String key, Object objectKey, Object objectToRemove) {
if (ObjectFilter.logger.isDebugEnabled())
ObjectFilter.logger.debug(MessageFormat.format("remove object {0} with key {1}", objectToRemove, 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.get(objectToRemove);
ObjectCache cached = this.cache.getElement(key, objectKey);
if (cached == null) {
// 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, objectToRemove, Operation.REMOVE);
this.cache.put(objectToRemove, cacheObj);
ObjectCache cacheObj = new ObjectCache(dispenseID(), key, objectKey, objectToRemove, Operation.REMOVE);
this.cache.addElement(key, objectKey, cacheObj);
} 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.REMOVE.toString(), existingKey, key, objectToRemove.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.
@ -300,11 +307,11 @@ public class ObjectFilter {
case ADD:
// this is a case where we're removing the object from the cache, since we are
// removing it now and it was added previously.
this.cache.remove(objectToRemove);
this.cache.removeElement(key, objectKey);
break;
case MODIFY:
// replace key if necessary
replaceKey(cached.getObject(), objectToRemove);
replaceKey(cached, objectKey, objectToRemove);
// update operation's object
cached.setObject(objectToRemove);
@ -322,129 +329,133 @@ public class ObjectFilter {
}
/**
* Register, under the given key, the addition of the given list of objects.
*
* @param key
* the key to register the objects with
* @param addedObjects
* The objects for which addition shall be registered.
* 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
*/
public void addAll(String key, Collection<Object> addedObjects) {
for (Object addObj : addedObjects) {
add(key, addObj);
}
}
/**
* Register, under the given key, the update of the given list of objects.
*
* @param key
* the key to register the objects with
* @param updatedObjects
* The objects for which update shall be registered.
*/
public void updateAll(String key, Collection<Object> updatedObjects) {
for (Object update : updatedObjects) {
update(key, update);
}
}
/**
* Register, under the given key, the removal of the given list of objects.
*
* @param key
* the key to register the objects with
* @param removedObjects
* The objects for which removal shall be registered.
*/
public void removeAll(String key, Collection<Object> removedObjects) {
for (Object removed : removedObjects) {
remove(key, removed);
}
public void add(Object object) {
add(object.getClass().getName(), object, object);
}
/**
* 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
* @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);
public void add(Object objectKey, Object object) {
add(object.getClass().getName(), objectKey, object);
}
/**
* 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);
update(object.getClass().getName(), object, object);
}
/**
* 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
* @param object
* The object that shall be registered for updating
*/
public void update(Object objectKey, Object object) {
update(object.getClass().getName(), objectKey, object);
}
/**
* 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);
remove(object.getClass().getName(), object, object);
}
/**
* Register the addition of all objects in the list. Since no key is provided, the class name of each object is used
* as a key.
*
* @param objects
* The objects that shall be registered for addition
* 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
* @param object
* The object that shall be registered for removal
*/
public void addAll(List<Object> objects) {
for (Object addedObj : objects) {
add(addedObj.getClass().getName(), addedObj);
}
public void remove(Object objectKey, Object object) {
remove(object.getClass().getName(), objectKey, object);
}
/**
* Register the updating of all objects in the list. Since no key is provided, the class name of each object is used
* as a key.
*
* @param updateObjects
* The objects that shall be registered for updating
* Returns the ObjectCache for the given key and objectKey
*
* @param key
* the key under which it was registered
* @param objectKey
* the objectKey
*
* @return the ObjectCache, or null
*/
public void updateAll(List<Object> updateObjects) {
for (Object update : updateObjects) {
update(update.getClass().getName(), update);
}
public ObjectCache getCache(String key, Object objectKey) {
return this.cache.getElement(key, objectKey);
}
/**
* Register the removal of all objects in the list. Since no key is provided, the class name of each object is used
* as a key.
*
* @param removedObjects
* The objects that shall be registered for removal
* Returns the element with the given key and objectKey
*
* @param key
* the key under which it was registered
* @param objectKey
* the objectKey
* @param <V>
* the class to which to cast the element to
*
* @return the element, or null
*/
public void removeAll(List<Object> removedObjects) {
for (Object removed : removedObjects) {
remove(removed.getClass().getName(), removed);
}
public <V> V getElement(String key, Object objectKey) {
ObjectCache cache = this.cache.getElement(key, objectKey);
if (cache == null)
return null;
@SuppressWarnings("unchecked")
V element = (V) cache.getObject();
return element;
}
/**
* Return true if the element with the given key and objectKey exist
*
* @param key
* the key under which it was registered
* @param objectKey
* the objectKey
*
* @return true if the element with the given key and objectKey exist
*/
public boolean hasElement(String key, Object objectKey) {
return this.cache.containsElement(key, objectKey);
}
/**
* 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.
*/
public List<Object> getAdded(String key) {
List<Object> addedObjects = new LinkedList<>();
Collection<ObjectCache> allObjs = this.cache.values();
List<ObjectCache> allObjs = this.cache.getAllElements(key);
for (ObjectCache objectCache : allObjs) {
if (objectCache.getOperation() == Operation.ADD && (objectCache.getKey().equals(key))) {
if (objectCache.getOperation() == Operation.ADD) {
addedObjects.add(objectCache.getObject());
}
}
@ -453,19 +464,19 @@ 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.
*/
public <V extends Object> List<V> getAdded(Class<V> clazz, String key) {
public <V> List<V> getAdded(Class<V> clazz, String key) {
List<V> addedObjects = new LinkedList<>();
Collection<ObjectCache> allObjs = this.cache.values();
List<ObjectCache> allObjs = this.cache.getAllElements(key);
for (ObjectCache objectCache : allObjs) {
if (objectCache.getOperation() == Operation.ADD && (objectCache.getKey().equals(key))) {
if (objectCache.getOperation() == Operation.ADD) {
if (objectCache.getObject().getClass() == clazz) {
@SuppressWarnings("unchecked")
V object = (V) objectCache.getObject();
@ -478,17 +489,17 @@ 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.
*/
public List<Object> getUpdated(String key) {
List<Object> updatedObjects = new LinkedList<>();
Collection<ObjectCache> allObjs = this.cache.values();
List<ObjectCache> allObjs = this.cache.getAllElements(key);
for (ObjectCache objectCache : allObjs) {
if (objectCache.getOperation() == Operation.MODIFY && (objectCache.getKey().equals(key))) {
if (objectCache.getOperation() == Operation.MODIFY) {
updatedObjects.add(objectCache.getObject());
}
}
@ -497,19 +508,19 @@ 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.
*/
public <V extends Object> List<V> getUpdated(Class<V> clazz, String key) {
public <V> List<V> getUpdated(Class<V> clazz, String key) {
List<V> updatedObjects = new LinkedList<>();
Collection<ObjectCache> allObjs = this.cache.values();
List<ObjectCache> allObjs = this.cache.getAllElements(key);
for (ObjectCache objectCache : allObjs) {
if (objectCache.getOperation() == Operation.MODIFY && (objectCache.getKey().equals(key))) {
if (objectCache.getOperation() == Operation.MODIFY) {
if (objectCache.getObject().getClass() == clazz) {
@SuppressWarnings("unchecked")
V object = (V) objectCache.getObject();
@ -522,17 +533,17 @@ 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.
*/
public List<Object> getRemoved(String key) {
List<Object> removedObjects = new LinkedList<>();
Collection<ObjectCache> allObjs = this.cache.values();
List<ObjectCache> allObjs = this.cache.getAllElements(key);
for (ObjectCache objectCache : allObjs) {
if (objectCache.getOperation() == Operation.REMOVE && (objectCache.getKey().equals(key))) {
if (objectCache.getOperation() == Operation.REMOVE) {
removedObjects.add(objectCache.getObject());
}
}
@ -541,19 +552,19 @@ 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.
*/
public <V extends Object> List<V> getRemoved(Class<V> clazz, String key) {
public <V> List<V> getRemoved(Class<V> clazz, String key) {
List<V> removedObjects = new LinkedList<>();
Collection<ObjectCache> allObjs = this.cache.values();
List<ObjectCache> allObjs = this.cache.getAllElements(key);
for (ObjectCache objectCache : allObjs) {
if (objectCache.getOperation() == Operation.REMOVE && (objectCache.getKey().equals(key))) {
if (objectCache.getOperation() == Operation.REMOVE) {
if (objectCache.getObject().getClass() == clazz) {
@SuppressWarnings("unchecked")
V object = (V) objectCache.getObject();
@ -566,24 +577,22 @@ 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.
*/
public <V extends Object> List<V> getAll(Class<V> clazz, String key) {
public <V> List<V> getAll(Class<V> clazz, String key) {
List<V> objects = new LinkedList<>();
Collection<ObjectCache> allObjs = this.cache.values();
List<ObjectCache> allObjs = this.cache.getAllElements(key);
for (ObjectCache objectCache : allObjs) {
if (objectCache.getKey().equals(key)) {
if (objectCache.getObject().getClass() == clazz) {
@SuppressWarnings("unchecked")
V object = (V) objectCache.getObject();
objects.add(object);
}
if (objectCache.getObject().getClass() == clazz) {
@SuppressWarnings("unchecked")
V object = (V) objectCache.getObject();
objects.add(object);
}
}
return objects;
@ -591,15 +600,15 @@ 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
*/
public <V extends Object> List<V> getAll(Class<V> clazz) {
public <V> List<V> getAll(Class<V> clazz) {
List<V> objects = new LinkedList<>();
Collection<ObjectCache> allObjs = this.cache.values();
Collection<ObjectCache> allObjs = this.cache.getAllElements();
for (ObjectCache objectCache : allObjs) {
if (objectCache.getObject().getClass() == clazz) {
@SuppressWarnings("unchecked")
@ -613,19 +622,17 @@ public class ObjectFilter {
/**
* Get all the objects that were processed in this transaction, that were registered under the given key. No action
* 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.
*/
public List<Object> getAll(String key) {
List<Object> allObjects = new LinkedList<>();
Collection<ObjectCache> allObjs = this.cache.values();
List<ObjectCache> allObjs = this.cache.getAllElements(key);
for (ObjectCache objectCache : allObjs) {
if (objectCache.getKey().equals(key)) {
allObjects.add(objectCache.getObject());
}
allObjects.add(objectCache.getObject());
}
return allObjects;
}
@ -633,26 +640,19 @@ public class ObjectFilter {
/**
* Get all the objects that were processed in this transaction, that were registered under the given key. No action
* 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.
*/
public List<ObjectCache> getCache(String key) {
List<ObjectCache> allCache = new LinkedList<>();
Collection<ObjectCache> allObjs = this.cache.values();
for (ObjectCache objectCache : allObjs) {
if (objectCache.getKey().equals(key)) {
allCache.add(objectCache);
}
}
return allCache;
return this.cache.getAllElements(key);
}
/**
* Return the set of keys that are currently present in the object filter.
*
*
* @return The set containing the keys of that have been added to the filter.
*/
public Set<String> keySet() {

View File

@ -15,16 +15,12 @@
*/
package li.strolch.utils.objectfilter;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.junit.Assert.*;
import java.util.List;
import org.junit.Test;
import li.strolch.utils.objectfilter.ObjectFilter;
/**
* @author Robert von Burg &lt;eitch@eitchnet.ch&gt;
*/
@ -37,7 +33,7 @@ public class ObjectFilterTest {
Object myObj = new Object();
ObjectFilter filter = new ObjectFilter();
filter.add(myObj);
filter.add(myObj, myObj);
testAssertions(filter, 1, 1, 1, 0, 0);
}
@ -48,7 +44,7 @@ public class ObjectFilterTest {
Object myObj = new Object();
ObjectFilter filter = new ObjectFilter();
filter.update(myObj);
filter.update(myObj, myObj);
testAssertions(filter, 1, 1, 0, 1, 0);
}
@ -59,7 +55,7 @@ public class ObjectFilterTest {
Object myObj = new Object();
ObjectFilter filter = new ObjectFilter();
filter.remove(myObj);
filter.remove(myObj, myObj);
testAssertions(filter, 1, 1, 0, 0, 1);
}
@ -72,9 +68,9 @@ public class ObjectFilterTest {
Object objToRemove = new Object();
ObjectFilter filter = new ObjectFilter();
filter.add(objToAdd);
filter.update(objToUpdate);
filter.remove(objToRemove);
filter.add(objToAdd, objToAdd);
filter.update(objToUpdate, objToUpdate);
filter.remove(objToRemove, objToRemove);
testAssertions(filter, 3, 1, 1, 1, 1);
}
@ -85,9 +81,9 @@ public class ObjectFilterTest {
Object objToAddUpdateRemove = new Object();
ObjectFilter filter = new ObjectFilter();
filter.add(objToAddUpdateRemove);
filter.update(objToAddUpdateRemove);
filter.remove(objToAddUpdateRemove);
filter.add(objToAddUpdateRemove, objToAddUpdateRemove);
filter.update(objToAddUpdateRemove, objToAddUpdateRemove);
filter.remove(objToAddUpdateRemove, objToAddUpdateRemove);
testAssertions(filter, 0, 1, 0, 0, 0);
}
@ -98,10 +94,10 @@ public class ObjectFilterTest {
Object myObj = new Object();
ObjectFilter filter = new ObjectFilter();
filter.add(myObj);
filter.add(myObj, myObj);
try {
filter.add(myObj);
filter.add(myObj, myObj);
fail("Should have failed adding twice!");
} catch (RuntimeException e) {
assertEquals("Stale State exception: Invalid + after +", e.getMessage());
@ -116,10 +112,10 @@ public class ObjectFilterTest {
Object myObj = new Object();
ObjectFilter filter = new ObjectFilter();
filter.remove(myObj);
filter.remove(myObj, myObj);
try {
filter.remove(myObj);
filter.remove(myObj, myObj);
fail("Should have failed removing twice!");
} catch (RuntimeException e) {
assertEquals("Stale State exception: Invalid - after -", e.getMessage());
@ -134,8 +130,8 @@ public class ObjectFilterTest {
Object myObj = new Object();
ObjectFilter filter = new ObjectFilter();
filter.update(myObj);
filter.update(myObj);
filter.update(myObj, myObj);
filter.update(myObj, myObj);
testAssertions(filter, 1, 1, 0, 1, 0);
}
@ -145,9 +141,9 @@ public class ObjectFilterTest {
Object myObj = new Object();
ObjectFilter filter = new ObjectFilter();
filter.add(myObj);
filter.update(myObj);
filter.update(myObj);
filter.add(myObj, myObj);
filter.update(myObj, myObj);
filter.update(myObj, myObj);
testAssertions(filter, 1, 1, 1, 0, 0);
}
@ -156,10 +152,10 @@ public class ObjectFilterTest {
Object myObj = new Object();
ObjectFilter filter = new ObjectFilter();
filter.update(myObj);
filter.update(myObj, myObj);
try {
filter.add(myObj);
filter.add(myObj, myObj);
fail("Should have failed add after modify");
} catch (RuntimeException e) {
assertEquals("Stale State exception: Invalid + after +=", e.getMessage());
@ -173,8 +169,8 @@ public class ObjectFilterTest {
Object myObj = new Object();
ObjectFilter filter = new ObjectFilter();
filter.remove(myObj);
filter.add(myObj);
filter.remove(myObj, myObj);
filter.add(myObj, myObj);
testAssertions(filter, 1, 1, 0, 1, 0);
}
@ -184,10 +180,10 @@ public class ObjectFilterTest {
Object myObj = new Object();
ObjectFilter filter = new ObjectFilter();
filter.remove(myObj);
filter.remove(myObj, myObj);
try {
filter.update(myObj);
filter.update(myObj, myObj);
fail("Should have failed modify after remove");
} catch (RuntimeException e) {
assertEquals("Stale State exception: Invalid += after -", e.getMessage());
@ -201,10 +197,10 @@ public class ObjectFilterTest {
Object myObj = new Object();
ObjectFilter filter = new ObjectFilter();
filter.add(myObj);
filter.add(myObj, myObj);
try {
filter.update("different_key", myObj);
filter.update("different_key", myObj, myObj);
fail("Should have failed because of different key for already registered object");
} catch (RuntimeException e) {
String msg = "Object may be present in the same filter instance only once, registered using one key only";
@ -222,8 +218,8 @@ public class ObjectFilterTest {
assertEquals("Test objects are not equal!", obj1, obj2);
ObjectFilter filter = new ObjectFilter();
filter.remove(Object.class.getName(), obj1);
filter.add(Object.class.getName(), obj2);
filter.remove(Object.class.getName(), obj1, obj1);
filter.add(Object.class.getName(), obj2, obj2);
testAssertions(filter, 1, 1, 0, 1, 0);
@ -241,8 +237,8 @@ public class ObjectFilterTest {
assertEquals("Test objects are not equal!", obj1, obj2);
ObjectFilter filter = new ObjectFilter();
filter.add(Object.class.getName(), obj1);
filter.update(Object.class.getName(), obj2);
filter.add(Object.class.getName(), obj1, obj1);
filter.update(Object.class.getName(), obj2, obj2);
testAssertions(filter, 1, 1, 1, 0, 0);
@ -260,8 +256,8 @@ public class ObjectFilterTest {
assertEquals("Test objects are not equal!", obj1, obj2);
ObjectFilter filter = new ObjectFilter();
filter.update(Object.class.getName(), obj1);
filter.update(Object.class.getName(), obj2);
filter.update(Object.class.getName(), obj1, obj1);
filter.update(Object.class.getName(), obj2, obj2);
testAssertions(filter, 1, 1, 0, 1, 0);
@ -279,8 +275,8 @@ public class ObjectFilterTest {
assertEquals("Test objects are not equal!", obj1, obj2);
ObjectFilter filter = new ObjectFilter();
filter.update(Object.class.getName(), obj1);
filter.remove(Object.class.getName(), obj2);
filter.update(Object.class.getName(), obj1, obj1);
filter.remove(Object.class.getName(), obj2, obj2);
testAssertions(filter, 1, 1, 0, 0, 1);
@ -296,8 +292,8 @@ public class ObjectFilterTest {
Object myObj = new Object();
ObjectFilter filter = new ObjectFilter();
filter.add(myObj);
filter.remove(myObj);
filter.add(myObj, myObj);
filter.remove(myObj, myObj);
testAssertions(filter, 0, 1, 0, 0, 0);
}
@ -309,9 +305,9 @@ public class ObjectFilterTest {
Object myObj3 = new Object();
ObjectFilter filter = new ObjectFilter();
filter.add(myObj1);
filter.update(myObj2);
filter.remove(myObj3);
filter.add(myObj1, myObj1);
filter.update(myObj2, myObj2);
filter.remove(myObj3, myObj3);
filter.clearCache();
@ -326,9 +322,9 @@ public class ObjectFilterTest {
Object myObj3 = new Object();
ObjectFilter filter = new ObjectFilter();
filter.add(myObj1);
filter.update(myObj2);
filter.remove(myObj3);
filter.add(myObj1, myObj1);
filter.update(myObj2, myObj2);
filter.remove(myObj3, myObj3);
testAssertions(filter, 3, 1, 1, 1, 1);
@ -345,7 +341,7 @@ public class ObjectFilterTest {
Object myObj1 = new Object();
ObjectFilter filter = new ObjectFilter();
filter.add(myObj1);
filter.add(myObj1, myObj1);
testAssertions(filter, 1, 1, 1, 0, 0);
@ -360,7 +356,7 @@ public class ObjectFilterTest {
Object myObj1 = new Object();
ObjectFilter filter = new ObjectFilter();
filter.update(myObj1);
filter.update(myObj1, myObj1);
testAssertions(filter, 1, 1, 0, 1, 0);
@ -375,7 +371,7 @@ public class ObjectFilterTest {
Object myObj1 = new Object();
ObjectFilter filter = new ObjectFilter();
filter.remove(myObj1);
filter.remove(myObj1, myObj1);
testAssertions(filter, 1, 1, 0, 0, 1);