[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:
parent
b2604f7ab5
commit
dad2f35b16
|
@ -25,7 +25,7 @@ import li.strolch.model.parameter.Parameter;
|
||||||
/**
|
/**
|
||||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||||
*/
|
*/
|
||||||
class ElementMapHelpers {
|
public class ElementMapHelpers {
|
||||||
|
|
||||||
public static void assertIsRefParam(String expectedInterpretation, Parameter<?> refP) {
|
public static void assertIsRefParam(String expectedInterpretation, Parameter<?> refP) {
|
||||||
|
|
||||||
|
|
|
@ -15,50 +15,21 @@
|
||||||
*/
|
*/
|
||||||
package li.strolch.persistence.api;
|
package li.strolch.persistence.api;
|
||||||
|
|
||||||
|
import static li.strolch.model.StrolchModelConstants.*;
|
||||||
import static li.strolch.model.Tags.AGENT;
|
import static li.strolch.model.Tags.AGENT;
|
||||||
|
|
||||||
import java.text.MessageFormat;
|
import java.text.MessageFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
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 org.slf4j.Logger;
|
import li.strolch.agent.api.*;
|
||||||
import org.slf4j.LoggerFactory;
|
import li.strolch.agent.impl.*;
|
||||||
|
|
||||||
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.exception.StrolchAccessDeniedException;
|
import li.strolch.exception.StrolchAccessDeniedException;
|
||||||
import li.strolch.exception.StrolchException;
|
import li.strolch.exception.StrolchException;
|
||||||
import li.strolch.exception.StrolchModelException;
|
import li.strolch.exception.StrolchModelException;
|
||||||
import li.strolch.handler.operationslog.LogMessage;
|
import li.strolch.handler.operationslog.LogMessage;
|
||||||
import li.strolch.handler.operationslog.LogSeverity;
|
import li.strolch.handler.operationslog.LogSeverity;
|
||||||
import li.strolch.handler.operationslog.OperationsLog;
|
import li.strolch.handler.operationslog.OperationsLog;
|
||||||
import li.strolch.model.GroupedParameterizedElement;
|
import li.strolch.model.*;
|
||||||
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.activity.Activity;
|
import li.strolch.model.activity.Activity;
|
||||||
import li.strolch.model.activity.IActivityElement;
|
import li.strolch.model.activity.IActivityElement;
|
||||||
import li.strolch.model.audit.AccessType;
|
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.query.StrolchQuery;
|
||||||
import li.strolch.model.timedstate.StrolchTimedState;
|
import li.strolch.model.timedstate.StrolchTimedState;
|
||||||
import li.strolch.model.timevalue.IValue;
|
import li.strolch.model.timevalue.IValue;
|
||||||
import li.strolch.model.visitor.ElementTypeVisitor;
|
|
||||||
import li.strolch.privilege.base.AccessDeniedException;
|
import li.strolch.privilege.base.AccessDeniedException;
|
||||||
import li.strolch.privilege.base.PrivilegeException;
|
import li.strolch.privilege.base.PrivilegeException;
|
||||||
import li.strolch.privilege.model.Certificate;
|
import li.strolch.privilege.model.Certificate;
|
||||||
import li.strolch.privilege.model.PrivilegeContext;
|
import li.strolch.privilege.model.PrivilegeContext;
|
||||||
|
import li.strolch.runtime.StrolchConstants;
|
||||||
import li.strolch.runtime.privilege.PrivilegeHandler;
|
import li.strolch.runtime.privilege.PrivilegeHandler;
|
||||||
import li.strolch.runtime.privilege.TransactedRestrictable;
|
import li.strolch.runtime.privilege.TransactedRestrictable;
|
||||||
import li.strolch.service.api.Command;
|
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.ExceptionHelper;
|
||||||
import li.strolch.utils.helper.StringHelper;
|
import li.strolch.utils.helper.StringHelper;
|
||||||
import li.strolch.utils.objectfilter.ObjectFilter;
|
import li.strolch.utils.objectfilter.ObjectFilter;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
@ -279,7 +252,12 @@ public abstract class AbstractTransaction implements StrolchTransaction {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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.realm.lock(locator);
|
||||||
this.lockedElements.add(locator);
|
this.lockedElements.add(locator);
|
||||||
}
|
}
|
||||||
|
@ -511,33 +489,52 @@ public abstract class AbstractTransaction implements StrolchTransaction {
|
||||||
throw new StrolchException(MessageFormat.format(msg, locator, stateOrBagOrActivity));
|
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
|
@Override
|
||||||
public Resource getResourceTemplate(String type) {
|
public Resource getResourceTemplate(String type) {
|
||||||
return getResourceMap().getTemplate(this, type);
|
return getResourceTemplate(type, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Resource getResourceTemplate(String type, boolean assertExists) throws StrolchException {
|
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);
|
return getResourceMap().getTemplate(this, type, assertExists);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Order getOrderTemplate(String type) {
|
public Order getOrderTemplate(String type) {
|
||||||
return getOrderMap().getTemplate(this, type);
|
return getOrderTemplate(type, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Order getOrderTemplate(String type, boolean assertExists) throws StrolchException {
|
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);
|
return getOrderMap().getTemplate(this, type, assertExists);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Activity getActivityTemplate(String type) {
|
public Activity getActivityTemplate(String type) {
|
||||||
return getActivityMap().getTemplate(this, type);
|
return getActivityTemplate(type, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Activity getActivityTemplate(String type, boolean assertExists) throws StrolchException {
|
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);
|
return getActivityMap().getTemplate(this, type, assertExists);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -548,31 +545,43 @@ public abstract class AbstractTransaction implements StrolchTransaction {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Order getOrderBy(String type, String id, boolean assertExists) throws StrolchException {
|
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);
|
return getOrderMap().getBy(this, type, id, assertExists);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Order getOrderBy(StringParameter refP) throws StrolchException {
|
public Order getOrderBy(StringParameter refP) throws StrolchException {
|
||||||
DBC.PRE.assertNotNull("refP", refP);
|
|
||||||
return getOrderBy(refP, false);
|
return getOrderBy(refP, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Order getOrderBy(StringParameter refP, boolean assertExists) throws StrolchException {
|
public Order getOrderBy(StringParameter refP, boolean assertExists) throws StrolchException {
|
||||||
DBC.PRE.assertNotNull("refP", refP);
|
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);
|
return getOrderMap().getBy(this, refP, assertExists);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Order> getOrdersBy(StringListParameter refP) throws StrolchException {
|
public List<Order> getOrdersBy(StringListParameter refP) throws StrolchException {
|
||||||
DBC.PRE.assertNotNull("refP", refP);
|
return getOrdersBy(refP, false);
|
||||||
return getOrderMap().getBy(this, refP, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Order> getOrdersBy(StringListParameter refP, boolean assertExists) throws StrolchException {
|
public List<Order> getOrdersBy(StringListParameter refP, boolean assertExists) throws StrolchException {
|
||||||
DBC.PRE.assertNotNull("refP", refP);
|
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
|
@Override
|
||||||
|
@ -582,36 +591,43 @@ public abstract class AbstractTransaction implements StrolchTransaction {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Resource getResourceBy(String type, String id, boolean assertExists) throws StrolchException {
|
public Resource getResourceBy(String type, String id, boolean assertExists) throws StrolchException {
|
||||||
Resource resource = getResourceMap().getBy(this, type, id);
|
Resource result = getElementFromFilter(Tags.RESOURCE, Resource.locatorFor(type, id));
|
||||||
if (assertExists && resource == null) {
|
if (result != null)
|
||||||
String msg = "No Resource exists with the id {0} with type {1}";
|
return result;
|
||||||
throw new StrolchException(MessageFormat.format(msg, id, type));
|
return getResourceMap().getBy(this, type, id, assertExists);
|
||||||
}
|
|
||||||
return resource;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Resource getResourceBy(StringParameter refP) throws StrolchException {
|
public Resource getResourceBy(StringParameter refP) throws StrolchException {
|
||||||
DBC.PRE.assertNotNull("refP", refP);
|
|
||||||
return getResourceBy(refP, false);
|
return getResourceBy(refP, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Resource getResourceBy(StringParameter refP, boolean assertExists) throws StrolchException {
|
public Resource getResourceBy(StringParameter refP, boolean assertExists) throws StrolchException {
|
||||||
DBC.PRE.assertNotNull("refP", refP);
|
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);
|
return getResourceMap().getBy(this, refP, assertExists);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Resource> getResourcesBy(StringListParameter refP) throws StrolchException {
|
public List<Resource> getResourcesBy(StringListParameter refP) throws StrolchException {
|
||||||
DBC.PRE.assertNotNull("refP", refP);
|
return getResourcesBy(refP, false);
|
||||||
return getResourceMap().getBy(this, refP, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Resource> getResourcesBy(StringListParameter refP, boolean assertExists) throws StrolchException {
|
public List<Resource> getResourcesBy(StringListParameter refP, boolean assertExists) throws StrolchException {
|
||||||
DBC.PRE.assertNotNull("refP", refP);
|
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
|
@Override
|
||||||
|
@ -621,36 +637,61 @@ public abstract class AbstractTransaction implements StrolchTransaction {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Activity getActivityBy(String type, String id, boolean assertExists) throws StrolchException {
|
public Activity getActivityBy(String type, String id, boolean assertExists) throws StrolchException {
|
||||||
Activity activity = getActivityMap().getBy(this, type, id);
|
Activity result = getElementFromFilter(Tags.ACTIVITY, Activity.locatorFor(type, id));
|
||||||
if (assertExists && activity == null) {
|
if (result != null)
|
||||||
String msg = "No Activity exists with the id {0} with type {1}";
|
return result;
|
||||||
throw new StrolchException(MessageFormat.format(msg, id, type));
|
return getActivityMap().getBy(this, type, id, assertExists);
|
||||||
}
|
|
||||||
return activity;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Activity getActivityBy(StringParameter refP) throws StrolchException {
|
public Activity getActivityBy(StringParameter refP) throws StrolchException {
|
||||||
DBC.PRE.assertNotNull("refP", refP);
|
|
||||||
return getActivityBy(refP, false);
|
return getActivityBy(refP, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Activity getActivityBy(StringParameter refP, boolean assertExists) throws StrolchException {
|
public Activity getActivityBy(StringParameter refP, boolean assertExists) throws StrolchException {
|
||||||
DBC.PRE.assertNotNull("refP", refP);
|
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);
|
return getActivityMap().getBy(this, refP, assertExists);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Activity> getActivitiesBy(StringListParameter refP) throws StrolchException {
|
public List<Activity> getActivitiesBy(StringListParameter refP) throws StrolchException {
|
||||||
DBC.PRE.assertNotNull("refP", refP);
|
return getActivitiesBy(refP, false);
|
||||||
return getActivityMap().getBy(this, refP, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Activity> getActivitiesBy(StringListParameter refP, boolean assertExists) throws StrolchException {
|
public List<Activity> getActivitiesBy(StringListParameter refP, boolean assertExists) throws StrolchException {
|
||||||
DBC.PRE.assertNotNull("refP", refP);
|
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() {
|
private ObjectFilter getObjectFilter() {
|
||||||
|
@ -670,55 +711,55 @@ public abstract class AbstractTransaction implements StrolchTransaction {
|
||||||
@Override
|
@Override
|
||||||
public void add(Resource resource) throws StrolchModelException {
|
public void add(Resource resource) throws StrolchModelException {
|
||||||
DBC.PRE.assertNotNull("resource must not be null", resource);
|
DBC.PRE.assertNotNull("resource must not be null", resource);
|
||||||
getObjectFilter().add(Tags.RESOURCE, resource);
|
getObjectFilter().add(Tags.RESOURCE, resource.getLocator(), resource);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void add(Order order) throws StrolchException {
|
public void add(Order order) throws StrolchException {
|
||||||
DBC.PRE.assertNotNull("order must not be null", order);
|
DBC.PRE.assertNotNull("order must not be null", order);
|
||||||
getObjectFilter().add(Tags.ORDER, order);
|
getObjectFilter().add(Tags.ORDER, order.getLocator(), order);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void add(Activity activity) throws StrolchException {
|
public void add(Activity activity) throws StrolchException {
|
||||||
DBC.PRE.assertNotNull("activity must not be null", activity);
|
DBC.PRE.assertNotNull("activity must not be null", activity);
|
||||||
getObjectFilter().add(Tags.ACTIVITY, activity);
|
getObjectFilter().add(Tags.ACTIVITY, activity.getLocator(), activity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void update(Resource resource) throws StrolchException {
|
public void update(Resource resource) throws StrolchException {
|
||||||
DBC.PRE.assertNotNull("resource must not be null", resource);
|
DBC.PRE.assertNotNull("resource must not be null", resource);
|
||||||
getObjectFilter().update(Tags.RESOURCE, resource);
|
getObjectFilter().update(Tags.RESOURCE, resource.getLocator(), resource);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void update(Order order) {
|
public void update(Order order) {
|
||||||
DBC.PRE.assertNotNull("order must not be null", order);
|
DBC.PRE.assertNotNull("order must not be null", order);
|
||||||
getObjectFilter().update(Tags.ORDER, order);
|
getObjectFilter().update(Tags.ORDER, order.getLocator(), order);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void update(Activity activity) throws StrolchException {
|
public void update(Activity activity) throws StrolchException {
|
||||||
DBC.PRE.assertNotNull("activity must not be null", activity);
|
DBC.PRE.assertNotNull("activity must not be null", activity);
|
||||||
getObjectFilter().update(Tags.ACTIVITY, activity);
|
getObjectFilter().update(Tags.ACTIVITY, activity.getLocator(), activity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void remove(Resource resource) throws StrolchException {
|
public void remove(Resource resource) throws StrolchException {
|
||||||
DBC.PRE.assertNotNull("resource must not be null", resource);
|
DBC.PRE.assertNotNull("resource must not be null", resource);
|
||||||
getObjectFilter().remove(Tags.RESOURCE, resource);
|
getObjectFilter().remove(Tags.RESOURCE, resource.getLocator(), resource);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void remove(Order order) throws StrolchException {
|
public void remove(Order order) throws StrolchException {
|
||||||
DBC.PRE.assertNotNull("order must not be null", order);
|
DBC.PRE.assertNotNull("order must not be null", order);
|
||||||
getObjectFilter().remove(Tags.ORDER, order);
|
getObjectFilter().remove(Tags.ORDER, order.getLocator(), order);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void remove(Activity activity) throws StrolchException {
|
public void remove(Activity activity) throws StrolchException {
|
||||||
DBC.PRE.assertNotNull("activity must not be null", activity);
|
DBC.PRE.assertNotNull("activity must not be null", activity);
|
||||||
getObjectFilter().remove(Tags.ACTIVITY, activity);
|
getObjectFilter().remove(Tags.ACTIVITY, activity.getLocator(), activity);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addModelChangeCommands() {
|
private void addModelChangeCommands() {
|
||||||
|
@ -923,6 +964,9 @@ public abstract class AbstractTransaction implements StrolchTransaction {
|
||||||
try {
|
try {
|
||||||
this.txResult.setState(TransactionState.CLOSING);
|
this.txResult.setState(TransactionState.CLOSING);
|
||||||
|
|
||||||
|
Thread.currentThread().getUncaughtExceptionHandler();
|
||||||
|
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
|
||||||
|
|
||||||
if (!this.commands.isEmpty()) {
|
if (!this.commands.isEmpty()) {
|
||||||
autoCloseableRollback();
|
autoCloseableRollback();
|
||||||
String msg = "There are commands registered on a read-only transaction. Changing to rollback! Did you forget to commit?";
|
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);
|
handleReadOnly(start, auditTrailDuration);
|
||||||
this.txResult.setState(TransactionState.CLOSED);
|
this.txResult.setState(TransactionState.CLOSED);
|
||||||
} catch (Exception e) {
|
} 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);
|
handleFailure(start, e);
|
||||||
this.txResult.setState(TransactionState.FAILED);
|
this.txResult.setState(TransactionState.FAILED);
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -1062,7 +1113,7 @@ public abstract class AbstractTransaction implements StrolchTransaction {
|
||||||
logger.error(sb.toString());
|
logger.error(sb.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void handleFailure(long closeStartNanos, Exception e) {
|
private void handleFailure(long closeStartNanos, Exception e) {
|
||||||
|
|
||||||
long end = System.nanoTime();
|
long end = System.nanoTime();
|
||||||
long txDuration = end - this.txResult.getStartNanos();
|
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$
|
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());
|
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() {
|
private boolean isAuditTrailEnabled() {
|
||||||
|
@ -1116,36 +1173,35 @@ public abstract class AbstractTransaction implements StrolchTransaction {
|
||||||
|
|
||||||
if (this.resourceMap != null) {
|
if (this.resourceMap != null) {
|
||||||
if (!this.resourceMap.getCreated().isEmpty())
|
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())
|
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())
|
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 != null) {
|
||||||
if (!this.orderMap.getCreated().isEmpty())
|
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())
|
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())
|
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 != null) {
|
||||||
if (!this.activityMap.getCreated().isEmpty())
|
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())
|
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())
|
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 observerHandler = this.realm.getObserverHandler();
|
||||||
observerHandler.notify(event);
|
observerHandler.notify(event);
|
||||||
|
|
||||||
long observerUpdateDuration = System.nanoTime() - observerUpdateStart;
|
return System.nanoTime() - observerUpdateStart;
|
||||||
return observerUpdateDuration;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isObserverUpdatesEnabled() {
|
private boolean isObserverUpdatesEnabled() {
|
||||||
|
@ -1166,26 +1222,26 @@ public abstract class AbstractTransaction implements StrolchTransaction {
|
||||||
|
|
||||||
if (this.orderMap != null) {
|
if (this.orderMap != null) {
|
||||||
if (this.realm.isAuditTrailEnabledForRead())
|
if (this.realm.isAuditTrailEnabledForRead())
|
||||||
auditsFor(audits, AccessType.READ, Tags.ORDER, this.orderMap.getRead());
|
auditsFor(audits, AccessType.READ, this.orderMap.getRead());
|
||||||
auditsFor(audits, AccessType.CREATE, Tags.ORDER, this.orderMap.getCreated());
|
auditsFor(audits, AccessType.CREATE, this.orderMap.getCreated());
|
||||||
auditsFor(audits, AccessType.UPDATE, Tags.ORDER, this.orderMap.getUpdated());
|
auditsFor(audits, AccessType.UPDATE, this.orderMap.getUpdated());
|
||||||
auditsFor(audits, AccessType.DELETE, Tags.ORDER, this.orderMap.getDeleted());
|
auditsFor(audits, AccessType.DELETE, this.orderMap.getDeleted());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.resourceMap != null) {
|
if (this.resourceMap != null) {
|
||||||
if (this.realm.isAuditTrailEnabledForRead())
|
if (this.realm.isAuditTrailEnabledForRead())
|
||||||
auditsFor(audits, AccessType.READ, Tags.RESOURCE, this.resourceMap.getRead());
|
auditsFor(audits, AccessType.READ, this.resourceMap.getRead());
|
||||||
auditsFor(audits, AccessType.CREATE, Tags.RESOURCE, this.resourceMap.getCreated());
|
auditsFor(audits, AccessType.CREATE, this.resourceMap.getCreated());
|
||||||
auditsFor(audits, AccessType.UPDATE, Tags.RESOURCE, this.resourceMap.getUpdated());
|
auditsFor(audits, AccessType.UPDATE, this.resourceMap.getUpdated());
|
||||||
auditsFor(audits, AccessType.DELETE, Tags.RESOURCE, this.resourceMap.getDeleted());
|
auditsFor(audits, AccessType.DELETE, this.resourceMap.getDeleted());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.activityMap != null) {
|
if (this.activityMap != null) {
|
||||||
if (this.realm.isAuditTrailEnabledForRead())
|
if (this.realm.isAuditTrailEnabledForRead())
|
||||||
auditsFor(audits, AccessType.READ, Tags.ACTIVITY, this.activityMap.getRead());
|
auditsFor(audits, AccessType.READ, this.activityMap.getRead());
|
||||||
auditsFor(audits, AccessType.CREATE, Tags.ACTIVITY, this.activityMap.getCreated());
|
auditsFor(audits, AccessType.CREATE, this.activityMap.getCreated());
|
||||||
auditsFor(audits, AccessType.UPDATE, Tags.ACTIVITY, this.activityMap.getUpdated());
|
auditsFor(audits, AccessType.UPDATE, this.activityMap.getUpdated());
|
||||||
auditsFor(audits, AccessType.DELETE, Tags.ACTIVITY, this.activityMap.getDeleted());
|
auditsFor(audits, AccessType.DELETE, this.activityMap.getDeleted());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.auditTrail != null && !isSuppressAuditsForAudits()) {
|
if (this.auditTrail != null && !isSuppressAuditsForAudits()) {
|
||||||
|
@ -1199,23 +1255,16 @@ public abstract class AbstractTransaction implements StrolchTransaction {
|
||||||
if (!audits.isEmpty())
|
if (!audits.isEmpty())
|
||||||
this.realm.getAuditTrail().addAll(this, audits);
|
this.realm.getAuditTrail().addAll(this, audits);
|
||||||
|
|
||||||
long auditTrailDuration = System.nanoTime() - auditTrailStart;
|
return System.nanoTime() - auditTrailStart;
|
||||||
return auditTrailDuration;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private <T extends StrolchRootElement> void auditsFor(List<Audit> audits,
|
private <T extends StrolchRootElement> void auditsFor(List<Audit> audits, AccessType accessType, Set<T> elements) {
|
||||||
AccessType accessType,
|
|
||||||
String elementType,
|
|
||||||
Set<T> elements) {
|
|
||||||
for (StrolchRootElement element : elements) {
|
for (StrolchRootElement element : elements) {
|
||||||
audits.add(auditFrom(accessType, element));
|
audits.add(auditFrom(accessType, element));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private <T extends StrolchRootElement> void auditsForAudits(List<Audit> audits,
|
private void auditsForAudits(List<Audit> audits, AccessType accessType, String elementType, Set<Audit> elements) {
|
||||||
AccessType accessType,
|
|
||||||
String elementType,
|
|
||||||
Set<Audit> elements) {
|
|
||||||
for (Audit element : elements) {
|
for (Audit element : elements) {
|
||||||
audits.add(auditFrom(accessType, elementType, StringHelper.DASH, element.getId().toString()));
|
audits.add(auditFrom(accessType, elementType, StringHelper.DASH, element.getId().toString()));
|
||||||
}
|
}
|
||||||
|
@ -1223,7 +1272,7 @@ public abstract class AbstractTransaction implements StrolchTransaction {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Audit auditFrom(AccessType accessType, StrolchRootElement element) {
|
public Audit auditFrom(AccessType accessType, StrolchRootElement element) {
|
||||||
String type = element.accept(new ElementTypeVisitor());
|
String type = element.getObjectType();
|
||||||
String subType = element.getType();
|
String subType = element.getType();
|
||||||
String id = element.getId();
|
String id = element.getId();
|
||||||
return auditFrom(accessType, type, subType, id);
|
return auditFrom(accessType, type, subType, id);
|
||||||
|
|
|
@ -75,8 +75,8 @@ import li.strolch.service.api.Command;
|
||||||
* <p>
|
* <p>
|
||||||
* A {@link StrolchTransaction} is always opened for a specific realm, should no specific realms be configured, then the
|
* A {@link StrolchTransaction} is always opened for a specific realm, should no specific realms be configured, then the
|
||||||
* {@link StrolchConstants#DEFAULT_REALM} is automatically created.
|
* {@link StrolchConstants#DEFAULT_REALM} is automatically created.
|
||||||
|
* </p>
|
||||||
* <p>
|
* <p>
|
||||||
*
|
|
||||||
* <p>
|
* <p>
|
||||||
* A {@link StrolchTransaction} takes care of the following:
|
* A {@link StrolchTransaction} takes care of the following:
|
||||||
* </p>
|
* </p>
|
||||||
|
@ -89,9 +89,8 @@ import li.strolch.service.api.Command;
|
||||||
* <li>updating observers</li>
|
* <li>updating observers</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
*
|
*
|
||||||
* @see AbstractTransaction
|
|
||||||
*
|
|
||||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
* @see AbstractTransaction
|
||||||
*/
|
*/
|
||||||
public interface StrolchTransaction extends AutoCloseable {
|
public interface StrolchTransaction extends AutoCloseable {
|
||||||
|
|
||||||
|
@ -186,7 +185,7 @@ public interface StrolchTransaction extends AutoCloseable {
|
||||||
* DO NOT CALL THIS METHOD. This interface implements {@link AutoCloseable} and transactions are expected to be used
|
* DO NOT CALL THIS METHOD. This interface implements {@link AutoCloseable} and transactions are expected to be used
|
||||||
* in a auto closing try block:
|
* in a auto closing try block:
|
||||||
* </p>
|
* </p>
|
||||||
*
|
* <p>
|
||||||
* <code>
|
* <code>
|
||||||
* StrolchAgent strolchAgent = getStrolchAgent();
|
* StrolchAgent strolchAgent = getStrolchAgent();
|
||||||
* StrolchRealm realm = strolchAgent.getContainer().getRealm("defaultRealm");
|
* StrolchRealm realm = strolchAgent.getContainer().getRealm("defaultRealm");
|
||||||
|
@ -195,7 +194,7 @@ public interface StrolchTransaction extends AutoCloseable {
|
||||||
* tx.commitOnClose();
|
* tx.commitOnClose();
|
||||||
* }
|
* }
|
||||||
* </code>
|
* </code>
|
||||||
*
|
* <p>
|
||||||
* After the block is closed, the transaction is automatically closed and all allocated resources are released
|
* After the block is closed, the transaction is automatically closed and all allocated resources are released
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
|
@ -230,7 +229,7 @@ public interface StrolchTransaction extends AutoCloseable {
|
||||||
* <p>
|
* <p>
|
||||||
* Performs all registered commands
|
* Performs all registered commands
|
||||||
* </p>
|
* </p>
|
||||||
*
|
* <p>
|
||||||
* <p>
|
* <p>
|
||||||
* This method does not release any locks, nor does it notify any observers
|
* This method does not release any locks, nor does it notify any observers
|
||||||
* </p>
|
* </p>
|
||||||
|
@ -352,7 +351,7 @@ public interface StrolchTransaction extends AutoCloseable {
|
||||||
*
|
*
|
||||||
* @throws StrolchLockException
|
* @throws StrolchLockException
|
||||||
*/
|
*/
|
||||||
public <T extends StrolchRootElement> void lock(Locator locator) throws StrolchLockException;
|
public void lock(Locator locator) throws StrolchLockException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Locks the given element and registers it on the transaction so the lock is released when the transaction is
|
* Locks the given element and registers it on the transaction so the lock is released when the transaction is
|
||||||
|
@ -394,7 +393,7 @@ public interface StrolchTransaction extends AutoCloseable {
|
||||||
* <li>{@link Command#validate()}</li>
|
* <li>{@link Command#validate()}</li>
|
||||||
* <li>{@link Command#doCommand()}</li>
|
* <li>{@link Command#doCommand()}</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
*
|
* <p>
|
||||||
* and if an exception occurs:
|
* and if an exception occurs:
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>{@link Command#undo()}</li>
|
* <li>{@link Command#undo()}</li>
|
||||||
|
@ -495,7 +494,6 @@ public interface StrolchTransaction extends AutoCloseable {
|
||||||
*
|
*
|
||||||
* @throws StrolchException
|
* @throws StrolchException
|
||||||
* if the element could not be found
|
* if the element could not be found
|
||||||
*
|
|
||||||
* @see #findElement(Locator, boolean)
|
* @see #findElement(Locator, boolean)
|
||||||
*/
|
*/
|
||||||
public <T extends StrolchElement> T findElement(Locator locator) throws StrolchException, ClassCastException;
|
public <T extends StrolchElement> T findElement(Locator locator) throws StrolchException, ClassCastException;
|
||||||
|
@ -504,13 +502,13 @@ public interface StrolchTransaction extends AutoCloseable {
|
||||||
* <p>
|
* <p>
|
||||||
* Used to find a {@link StrolchElement} by a {@link Locator}.
|
* Used to find a {@link StrolchElement} by a {@link Locator}.
|
||||||
* </p>
|
* </p>
|
||||||
*
|
* <p>
|
||||||
* <p>
|
* <p>
|
||||||
* A Locator has the form <i><ObjectClassType>/<Type>/<Id></i> - this is the least amount of path
|
* A Locator has the form <i><ObjectClassType>/<Type>/<Id></i> - this is the least amount of path
|
||||||
* elements to find an object. Thus to query a {@link Resource} of type "MyType" and the id "@1" use the following
|
* elements to find an object. Thus to query a {@link Resource} of type "MyType" and the id "@1" use the following
|
||||||
* path: <i>Resourcee/MyType/@1</i>
|
* path: <i>Resourcee/MyType/@1</i>
|
||||||
* </p>
|
* </p>
|
||||||
*
|
* <p>
|
||||||
* <p>
|
* <p>
|
||||||
* This method can also be used to find a deeper element, e.g. a specific {@link Parameter} on an
|
* This method can also be used to find a deeper element, e.g. a specific {@link Parameter} on an
|
||||||
* {@link ParameterBag} on an {@link Order}. This would be done as follows: <i>Order/MyType/Bag/@1/myParam</i>
|
* {@link ParameterBag} on an {@link Order}. This would be done as follows: <i>Order/MyType/Bag/@1/myParam</i>
|
||||||
|
@ -539,7 +537,7 @@ public interface StrolchTransaction extends AutoCloseable {
|
||||||
* Returns a copy of the {@link Resource} of Type {@link StrolchConstants#TEMPLATE} with the given type as id, or
|
* Returns a copy of the {@link Resource} of Type {@link StrolchConstants#TEMPLATE} with the given type as id, or
|
||||||
* null if it does not exist
|
* null if it does not exist
|
||||||
* </p>
|
* </p>
|
||||||
*
|
* <p>
|
||||||
* <p>
|
* <p>
|
||||||
* Templates are {@link StrolchRootElement StrolchRootElements} which have the type
|
* Templates are {@link StrolchRootElement StrolchRootElements} which have the type
|
||||||
* {@link StrolchConstants#TEMPLATE} and their id is the type of element for which it is a template. For instance
|
* {@link StrolchConstants#TEMPLATE} and their id is the type of element for which it is a template. For instance
|
||||||
|
@ -560,7 +558,7 @@ public interface StrolchTransaction extends AutoCloseable {
|
||||||
* Returns a copy of the {@link Resource} of Type {@link StrolchConstants#TEMPLATE} with the given type as id. If
|
* Returns a copy of the {@link Resource} of Type {@link StrolchConstants#TEMPLATE} with the given type as id. If
|
||||||
* <code>assertExists</code> is true, then an exception is thrown if the template does not exist does not exist
|
* <code>assertExists</code> is true, then an exception is thrown if the template does not exist does not exist
|
||||||
* </p>
|
* </p>
|
||||||
*
|
* <p>
|
||||||
* <p>
|
* <p>
|
||||||
* Templates are {@link StrolchRootElement StrolchRootElements} which have the type
|
* Templates are {@link StrolchRootElement StrolchRootElements} which have the type
|
||||||
* {@link StrolchConstants#TEMPLATE} and their id is the type of element for which it is a template. For instance
|
* {@link StrolchConstants#TEMPLATE} and their id is the type of element for which it is a template. For instance
|
||||||
|
@ -584,7 +582,7 @@ public interface StrolchTransaction extends AutoCloseable {
|
||||||
* Returns a copy of the {@link Order} of Type {@link StrolchConstants#TEMPLATE} with the given type as id, or null
|
* Returns a copy of the {@link Order} of Type {@link StrolchConstants#TEMPLATE} with the given type as id, or null
|
||||||
* if it does not exist
|
* if it does not exist
|
||||||
* </p>
|
* </p>
|
||||||
*
|
* <p>
|
||||||
* <p>
|
* <p>
|
||||||
* Templates are {@link StrolchRootElement StrolchRootElements} which have the type
|
* Templates are {@link StrolchRootElement StrolchRootElements} which have the type
|
||||||
* {@link StrolchConstants#TEMPLATE} and their id is the type of element for which it is a template. For instance
|
* {@link StrolchConstants#TEMPLATE} and their id is the type of element for which it is a template. For instance
|
||||||
|
@ -605,7 +603,7 @@ public interface StrolchTransaction extends AutoCloseable {
|
||||||
* Returns a copy of the {@link Order} of Type {@link StrolchConstants#TEMPLATE} with the given type as id. If
|
* Returns a copy of the {@link Order} of Type {@link StrolchConstants#TEMPLATE} with the given type as id. If
|
||||||
* <code>assertExists</code> is true, then an exception is thrown if the template does not exist does not exist
|
* <code>assertExists</code> is true, then an exception is thrown if the template does not exist does not exist
|
||||||
* </p>
|
* </p>
|
||||||
*
|
* <p>
|
||||||
* <p>
|
* <p>
|
||||||
* Templates are {@link StrolchRootElement StrolchRootElements} which have the type
|
* Templates are {@link StrolchRootElement StrolchRootElements} which have the type
|
||||||
* {@link StrolchConstants#TEMPLATE} and their id is the type of element for which it is a template. For instance
|
* {@link StrolchConstants#TEMPLATE} and their id is the type of element for which it is a template. For instance
|
||||||
|
@ -629,7 +627,7 @@ public interface StrolchTransaction extends AutoCloseable {
|
||||||
* Returns a copy of the {@link Activity} of Type {@link StrolchConstants#TEMPLATE} with the given type as id, or
|
* Returns a copy of the {@link Activity} of Type {@link StrolchConstants#TEMPLATE} with the given type as id, or
|
||||||
* null if it does not exist
|
* null if it does not exist
|
||||||
* </p>
|
* </p>
|
||||||
*
|
* <p>
|
||||||
* <p>
|
* <p>
|
||||||
* Templates are {@link StrolchRootElement StrolchRootElements} which have the type
|
* Templates are {@link StrolchRootElement StrolchRootElements} which have the type
|
||||||
* {@link StrolchConstants#TEMPLATE} and their id is the type of element for which it is a template. For instance
|
* {@link StrolchConstants#TEMPLATE} and their id is the type of element for which it is a template. For instance
|
||||||
|
@ -650,7 +648,7 @@ public interface StrolchTransaction extends AutoCloseable {
|
||||||
* Returns a copy of the {@link Activity} of Type {@link StrolchConstants#TEMPLATE} with the given type as id. If
|
* Returns a copy of the {@link Activity} of Type {@link StrolchConstants#TEMPLATE} with the given type as id. If
|
||||||
* <code>assertExists</code> is true, then an exception is thrown if the template does not exist does not exist
|
* <code>assertExists</code> is true, then an exception is thrown if the template does not exist does not exist
|
||||||
* </p>
|
* </p>
|
||||||
*
|
* <p>
|
||||||
* <p>
|
* <p>
|
||||||
* Templates are {@link StrolchRootElement StrolchRootElements} which have the type
|
* Templates are {@link StrolchRootElement StrolchRootElements} which have the type
|
||||||
* {@link StrolchConstants#TEMPLATE} and their id is the type of element for which it is a template. For instance
|
* {@link StrolchConstants#TEMPLATE} and their id is the type of element for which it is a template. For instance
|
||||||
|
@ -959,6 +957,42 @@ public interface StrolchTransaction extends AutoCloseable {
|
||||||
*/
|
*/
|
||||||
public List<Order> getOrdersBy(StringListParameter refP, boolean assertExists) throws StrolchException;
|
public List<Order> getOrdersBy(StringListParameter refP, boolean assertExists) throws StrolchException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the @{@link Resource} exists with the given type and ID
|
||||||
|
*
|
||||||
|
* @param type
|
||||||
|
* the type of Resource to check for
|
||||||
|
* @param id
|
||||||
|
* the ID of the Resource to check for
|
||||||
|
*
|
||||||
|
* @return true if the @{@link Resource} exists with the given type and ID
|
||||||
|
*/
|
||||||
|
public boolean hasResource(String type, String id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the @{@link Order} exists with the given type and ID
|
||||||
|
*
|
||||||
|
* @param type
|
||||||
|
* the type of Order to check for
|
||||||
|
* @param id
|
||||||
|
* the ID of the Order to check for
|
||||||
|
*
|
||||||
|
* @return true if the @{@link Order} exists with the given type and ID
|
||||||
|
*/
|
||||||
|
public boolean hasOrder(String type, String id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the @{@link Activity} exists with the given type and ID
|
||||||
|
*
|
||||||
|
* @param type
|
||||||
|
* the type of Activity to check for
|
||||||
|
* @param id
|
||||||
|
* the ID of the Activity to check for
|
||||||
|
*
|
||||||
|
* @return true if the @{@link Activity} exists with the given type and ID
|
||||||
|
*/
|
||||||
|
public boolean hasActivity(String type, String id);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds and thus persists the given {@link Resource} by calling the relevant {@link Command}
|
* Adds and thus persists the given {@link Resource} by calling the relevant {@link Command}
|
||||||
*
|
*
|
||||||
|
@ -1058,6 +1092,13 @@ public interface StrolchTransaction extends AutoCloseable {
|
||||||
*/
|
*/
|
||||||
public void remove(Activity activity) throws StrolchException;
|
public void remove(Activity activity) throws StrolchException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if this transaction has any registered elements or commands for persistence. E.g. {@link #add(Order)} or {@link #addCommand(Command)}, etc. were called
|
||||||
|
*
|
||||||
|
* @return true if this transaction needs to be committed to persist changes
|
||||||
|
*/
|
||||||
|
public boolean needsCommit();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Asserts that the current {@link Certificate} has access to the given element with the given operation
|
* Asserts that the current {@link Certificate} has access to the given element with the given operation
|
||||||
*
|
*
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -18,9 +18,6 @@ package li.strolch.service;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
import org.junit.Ignore;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import li.strolch.model.ModelGenerator;
|
import li.strolch.model.ModelGenerator;
|
||||||
import li.strolch.model.Order;
|
import li.strolch.model.Order;
|
||||||
import li.strolch.model.Resource;
|
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.api.ServiceResult;
|
||||||
import li.strolch.service.test.AbstractRealmServiceTest;
|
import li.strolch.service.test.AbstractRealmServiceTest;
|
||||||
import li.strolch.utils.dbc.DBC;
|
import li.strolch.utils.dbc.DBC;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
public class TxTest extends AbstractRealmServiceTest {
|
public class TxTest extends AbstractRealmServiceTest {
|
||||||
|
|
||||||
|
@ -53,7 +51,6 @@ public class TxTest extends AbstractRealmServiceTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@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() {
|
public void shouldNotAllowCommandsOnDoNothing() {
|
||||||
|
|
||||||
runServiceInAllRealmTypes(ReadonlyFailService.class, new ServiceArgument());
|
runServiceInAllRealmTypes(ReadonlyFailService.class, new ServiceArgument());
|
||||||
|
|
|
@ -27,28 +27,27 @@ import java.util.Set;
|
||||||
* <p>
|
* <p>
|
||||||
* Collection to store a tree with a depth of 3 elements. This solves having to always write the declaration:
|
* Collection to store a tree with a depth of 3 elements. This solves having to always write the declaration:
|
||||||
* </p>
|
* </p>
|
||||||
*
|
* <p>
|
||||||
* <pre>
|
* <pre>
|
||||||
* Map<String, Map<String, MyObject>> mapOfMaps = new HashMap<>;
|
* Map<String, Map<String, MyObject>> mapOfMaps = new HashMap<>;
|
||||||
* </pre>
|
* </pre>
|
||||||
*
|
* <p>
|
||||||
* <p>
|
* <p>
|
||||||
* As an example to persist a map of MyObject where the branches are String one would write it as follows:
|
* As an example to persist a map of MyObject where the branches are String one would write it as follows:
|
||||||
* </p>
|
* </p>
|
||||||
*
|
* <p>
|
||||||
* <pre>
|
* <pre>
|
||||||
* MapOfMaps<String, String, MyObject> mapOfMaps = new MapOfMaps<>();
|
* MapOfMaps<String, String, MyObject> mapOfMaps = new MapOfMaps<>();
|
||||||
* </pre>
|
* </pre>
|
||||||
*
|
*
|
||||||
*
|
|
||||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
|
||||||
*
|
|
||||||
* @param <T>
|
* @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>
|
* @param <U>
|
||||||
* The key to get a value (leaf)
|
* The key to get a value (leaf)
|
||||||
* @param <V>
|
* @param <V>
|
||||||
* The value stored in the tree (leaf)
|
* The value stored in the tree (leaf)
|
||||||
|
*
|
||||||
|
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||||
*/
|
*/
|
||||||
public class MapOfMaps<T, U, V> {
|
public class MapOfMaps<T, U, V> {
|
||||||
|
|
||||||
|
@ -58,6 +57,10 @@ public class MapOfMaps<T, U, V> {
|
||||||
this.mapOfMaps = new HashMap<>();
|
this.mapOfMaps = new HashMap<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public MapOfMaps(int initialSize) {
|
||||||
|
this.mapOfMaps = new HashMap<>(initialSize);
|
||||||
|
}
|
||||||
|
|
||||||
public Set<T> keySet() {
|
public Set<T> keySet() {
|
||||||
return this.mapOfMaps.keySet();
|
return this.mapOfMaps.keySet();
|
||||||
}
|
}
|
||||||
|
@ -74,11 +77,7 @@ public class MapOfMaps<T, U, V> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public V addElement(T t, U u, V v) {
|
public V addElement(T t, U u, V v) {
|
||||||
Map<U, V> map = this.mapOfMaps.get(t);
|
Map<U, V> map = this.mapOfMaps.computeIfAbsent(t, k -> new HashMap<>());
|
||||||
if (map == null) {
|
|
||||||
map = new HashMap<>();
|
|
||||||
this.mapOfMaps.put(t, map);
|
|
||||||
}
|
|
||||||
return map.put(u, v);
|
return map.put(u, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,11 +99,7 @@ public class MapOfMaps<T, U, V> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addMap(T t, Map<U, V> u) {
|
public void addMap(T t, Map<U, V> u) {
|
||||||
Map<U, V> map = this.mapOfMaps.get(t);
|
Map<U, V> map = this.mapOfMaps.computeIfAbsent(t, k -> new HashMap<>());
|
||||||
if (map == null) {
|
|
||||||
map = new HashMap<>();
|
|
||||||
this.mapOfMaps.put(t, map);
|
|
||||||
}
|
|
||||||
map.putAll(u);
|
map.putAll(u);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,9 +135,7 @@ public class MapOfMaps<T, U, V> {
|
||||||
|
|
||||||
public boolean containsElement(T t, U u) {
|
public boolean containsElement(T t, U u) {
|
||||||
Map<U, V> map = this.mapOfMaps.get(t);
|
Map<U, V> map = this.mapOfMaps.get(t);
|
||||||
if (map == null)
|
return map != null && map.containsKey(u);
|
||||||
return false;
|
|
||||||
return map.containsKey(u);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int sizeKeys() {
|
public int sizeKeys() {
|
||||||
|
@ -152,9 +145,8 @@ public class MapOfMaps<T, U, V> {
|
||||||
public int size() {
|
public int size() {
|
||||||
int size = 0;
|
int size = 0;
|
||||||
Set<Entry<T, Map<U, V>>> entrySet = this.mapOfMaps.entrySet();
|
Set<Entry<T, Map<U, V>>> entrySet = this.mapOfMaps.entrySet();
|
||||||
Iterator<Entry<T, Map<U, V>>> iter = entrySet.iterator();
|
for (Entry<T, Map<U, V>> anEntrySet : entrySet) {
|
||||||
while (iter.hasNext()) {
|
size += anEntrySet.getValue().size();
|
||||||
size += iter.next().getValue().size();
|
|
||||||
}
|
}
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,16 +60,22 @@ public class ObjectCache {
|
||||||
*/
|
*/
|
||||||
private Operation operation;
|
private Operation operation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* object The objectKey that shall be cached
|
||||||
|
*/
|
||||||
|
private Object objectKey;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* object The object that shall be cached
|
* object The object that shall be cached
|
||||||
*/
|
*/
|
||||||
private Object object;
|
private Object object;
|
||||||
|
|
||||||
@SuppressWarnings("nls")
|
@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.id = id;
|
||||||
this.key = key;
|
this.key = key;
|
||||||
|
this.objectKey = objectKey;
|
||||||
this.object = object;
|
this.object = object;
|
||||||
this.operation = operation;
|
this.operation = operation;
|
||||||
|
|
||||||
|
@ -82,7 +88,7 @@ public class ObjectCache {
|
||||||
sb.append(" OP: ");
|
sb.append(" OP: ");
|
||||||
sb.append(this.operation);
|
sb.append(this.operation);
|
||||||
sb.append(" / ");
|
sb.append(" / ");
|
||||||
sb.append(object.toString());
|
sb.append(objectKey.toString());
|
||||||
logger.debug(sb.toString());
|
logger.debug(sb.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -95,7 +101,8 @@ public class ObjectCache {
|
||||||
*/
|
*/
|
||||||
public void setObject(Object object) {
|
public void setObject(Object object) {
|
||||||
if (logger.isDebugEnabled()) {
|
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;
|
this.object = object;
|
||||||
}
|
}
|
||||||
|
@ -115,30 +122,22 @@ public class ObjectCache {
|
||||||
this.operation = newOperation;
|
this.operation = newOperation;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the id
|
|
||||||
*/
|
|
||||||
public long getId() {
|
public long getId() {
|
||||||
return this.id;
|
return this.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the key
|
|
||||||
*/
|
|
||||||
public String getKey() {
|
public String getKey() {
|
||||||
return this.key;
|
return this.key;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the operation
|
|
||||||
*/
|
|
||||||
public Operation getOperation() {
|
public Operation getOperation() {
|
||||||
return this.operation;
|
return this.operation;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public Object getObjectKey() {
|
||||||
* @return the object
|
return objectKey;
|
||||||
*/
|
}
|
||||||
|
|
||||||
public Object getObject() {
|
public Object getObject() {
|
||||||
return this.object;
|
return this.object;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,14 +16,9 @@
|
||||||
package li.strolch.utils.objectfilter;
|
package li.strolch.utils.objectfilter;
|
||||||
|
|
||||||
import java.text.MessageFormat;
|
import java.text.MessageFormat;
|
||||||
import java.util.Collection;
|
import java.util.*;
|
||||||
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 li.strolch.utils.collections.MapOfMaps;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
@ -81,17 +76,29 @@ public class ObjectFilter {
|
||||||
|
|
||||||
private static long id = ObjectCache.UNSET;
|
private static long id = ObjectCache.UNSET;
|
||||||
|
|
||||||
private final Map<Object, ObjectCache> cache;
|
private final MapOfMaps<String, Object, ObjectCache> cache;
|
||||||
private final Set<String> keySet;
|
private final Set<String> keySet;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default constructor initializing the filter
|
* Default constructor initializing the filter
|
||||||
*/
|
*/
|
||||||
public ObjectFilter() {
|
public ObjectFilter() {
|
||||||
this.cache = new HashMap<>(1);
|
this.cache = new MapOfMaps<>(1);
|
||||||
this.keySet = new HashSet<>(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.
|
* Register, under the given key, the addition of the given object.
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -115,30 +122,34 @@ public class ObjectFilter {
|
||||||
*
|
*
|
||||||
* @param key
|
* @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
|
* @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())
|
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.
|
// 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) {
|
if (cached == null) {
|
||||||
|
|
||||||
// The object has not yet been added to the cache.
|
// The object has not yet been added to the cache.
|
||||||
// Hence, we add it now, with the ADD operation.
|
// Hence, we add it now, with the ADD operation.
|
||||||
ObjectCache cacheObj = new ObjectCache(dispenseID(), key, objectToAdd, Operation.ADD);
|
ObjectCache cacheObj = new ObjectCache(dispenseID(), key, objectKey, objectToAdd, Operation.ADD);
|
||||||
this.cache.put(objectToAdd, cacheObj);
|
this.cache.addElement(key, objectKey, cacheObj);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
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.format(msg, Long.toString(id),
|
throw new IllegalArgumentException(MessageFormat
|
||||||
Operation.ADD.toString(), existingKey, key, objectToAdd.toString()));
|
.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
|
// 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$
|
throw new IllegalStateException("Stale State exception: Invalid + after +="); //$NON-NLS-1$
|
||||||
case REMOVE:
|
case REMOVE:
|
||||||
// replace key if necessary
|
// replace key if necessary
|
||||||
replaceKey(cached.getObject(), objectToAdd);
|
replaceKey(cached, objectKey, objectToAdd);
|
||||||
|
|
||||||
// update operation's object
|
// update operation's object
|
||||||
cached.setObject(objectToAdd);
|
cached.setObject(objectToAdd);
|
||||||
|
@ -166,18 +177,6 @@ public class ObjectFilter {
|
||||||
this.keySet.add(key);
|
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. *
|
* Register, under the given key, the update of the given object. *
|
||||||
* </p>
|
* </p>
|
||||||
|
@ -200,30 +199,34 @@ public class ObjectFilter {
|
||||||
*
|
*
|
||||||
* @param key
|
* @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
|
* @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())
|
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.
|
// 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) {
|
if (cached == null) {
|
||||||
|
|
||||||
// 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, objectToUpdate, Operation.MODIFY);
|
ObjectCache cacheObj = new ObjectCache(dispenseID(), key, objectKey, objectToUpdate, Operation.MODIFY);
|
||||||
this.cache.put(objectToUpdate, cacheObj);
|
this.cache.addElement(key, objectKey, cacheObj);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
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.format(msg, Long.toString(id),
|
throw new IllegalArgumentException(MessageFormat
|
||||||
Operation.MODIFY.toString(), existingKey, key, objectToUpdate.toString()));
|
.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.
|
||||||
|
@ -232,7 +235,7 @@ public class ObjectFilter {
|
||||||
case ADD:
|
case ADD:
|
||||||
case MODIFY:
|
case MODIFY:
|
||||||
// replace key if necessary
|
// replace key if necessary
|
||||||
replaceKey(cached.getObject(), objectToUpdate);
|
replaceKey(cached, objectKey, objectToUpdate);
|
||||||
|
|
||||||
// update operation's object
|
// update operation's object
|
||||||
cached.setObject(objectToUpdate);
|
cached.setObject(objectToUpdate);
|
||||||
|
@ -270,28 +273,32 @@ public class ObjectFilter {
|
||||||
*
|
*
|
||||||
* @param key
|
* @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
|
* @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())
|
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.
|
// 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) {
|
if (cached == null) {
|
||||||
// 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, objectToRemove, Operation.REMOVE);
|
ObjectCache cacheObj = new ObjectCache(dispenseID(), key, objectKey, objectToRemove, Operation.REMOVE);
|
||||||
this.cache.put(objectToRemove, cacheObj);
|
this.cache.addElement(key, objectKey, cacheObj);
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
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.format(msg, Long.toString(id),
|
throw new IllegalArgumentException(MessageFormat
|
||||||
Operation.REMOVE.toString(), existingKey, key, objectToRemove.toString()));
|
.format(msg, Long.toString(id), Operation.REMOVE.toString(), existingKey, key,
|
||||||
|
objectKey.toString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// The object is in cache: update the version as required.
|
// The object is in cache: update the version as required.
|
||||||
|
@ -300,11 +307,11 @@ public class ObjectFilter {
|
||||||
case ADD:
|
case ADD:
|
||||||
// this is a case where we're removing the object from the cache, since we are
|
// this is a case where we're removing the object from the cache, since we are
|
||||||
// removing it now and it was added previously.
|
// removing it now and it was added previously.
|
||||||
this.cache.remove(objectToRemove);
|
this.cache.removeElement(key, objectKey);
|
||||||
break;
|
break;
|
||||||
case MODIFY:
|
case MODIFY:
|
||||||
// replace key if necessary
|
// replace key if necessary
|
||||||
replaceKey(cached.getObject(), objectToRemove);
|
replaceKey(cached, objectKey, objectToRemove);
|
||||||
|
|
||||||
// update operation's object
|
// update operation's object
|
||||||
cached.setObject(objectToRemove);
|
cached.setObject(objectToRemove);
|
||||||
|
@ -321,48 +328,6 @@ public class ObjectFilter {
|
||||||
this.keySet.add(key);
|
this.keySet.add(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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.
|
||||||
*
|
*
|
||||||
|
@ -370,7 +335,19 @@ public class ObjectFilter {
|
||||||
* 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);
|
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
|
||||||
|
*/
|
||||||
|
public void add(Object objectKey, Object object) {
|
||||||
|
add(object.getClass().getName(), objectKey, object);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -380,7 +357,19 @@ public class ObjectFilter {
|
||||||
* 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);
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -390,46 +379,68 @@ public class ObjectFilter {
|
||||||
* 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);
|
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
|
* Register the removal of the given object. Since no key is provided, the class name is used as a key.
|
||||||
* as a key.
|
|
||||||
*
|
*
|
||||||
* @param objects
|
* @param objectKey
|
||||||
* The objects that shall be registered for addition
|
* the key for the object
|
||||||
|
* @param object
|
||||||
|
* The object that shall be registered for removal
|
||||||
*/
|
*/
|
||||||
public void addAll(List<Object> objects) {
|
public void remove(Object objectKey, Object object) {
|
||||||
for (Object addedObj : objects) {
|
remove(object.getClass().getName(), objectKey, object);
|
||||||
add(addedObj.getClass().getName(), addedObj);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register the updating of all objects in the list. Since no key is provided, the class name of each object is used
|
* Returns the ObjectCache for the given key and objectKey
|
||||||
* as a key.
|
|
||||||
*
|
*
|
||||||
* @param updateObjects
|
* @param key
|
||||||
* The objects that shall be registered for updating
|
* the key under which it was registered
|
||||||
|
* @param objectKey
|
||||||
|
* the objectKey
|
||||||
|
*
|
||||||
|
* @return the ObjectCache, or null
|
||||||
*/
|
*/
|
||||||
public void updateAll(List<Object> updateObjects) {
|
public ObjectCache getCache(String key, Object objectKey) {
|
||||||
for (Object update : updateObjects) {
|
return this.cache.getElement(key, objectKey);
|
||||||
update(update.getClass().getName(), update);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register the removal of all objects in the list. Since no key is provided, the class name of each object is used
|
* Returns the element with the given key and objectKey
|
||||||
* as a key.
|
|
||||||
*
|
*
|
||||||
* @param removedObjects
|
* @param key
|
||||||
* The objects that shall be registered for removal
|
* 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) {
|
public <V> V getElement(String key, Object objectKey) {
|
||||||
for (Object removed : removedObjects) {
|
ObjectCache cache = this.cache.getElement(key, objectKey);
|
||||||
remove(removed.getClass().getName(), removed);
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -442,9 +453,9 @@ public class ObjectFilter {
|
||||||
*/
|
*/
|
||||||
public List<Object> getAdded(String key) {
|
public List<Object> getAdded(String key) {
|
||||||
List<Object> addedObjects = new LinkedList<>();
|
List<Object> addedObjects = new LinkedList<>();
|
||||||
Collection<ObjectCache> allObjs = this.cache.values();
|
List<ObjectCache> allObjs = this.cache.getAllElements(key);
|
||||||
for (ObjectCache objectCache : allObjs) {
|
for (ObjectCache objectCache : allObjs) {
|
||||||
if (objectCache.getOperation() == Operation.ADD && (objectCache.getKey().equals(key))) {
|
if (objectCache.getOperation() == Operation.ADD) {
|
||||||
addedObjects.add(objectCache.getObject());
|
addedObjects.add(objectCache.getObject());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -461,11 +472,11 @@ public class ObjectFilter {
|
||||||
*
|
*
|
||||||
* @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.
|
||||||
*/
|
*/
|
||||||
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<>();
|
List<V> addedObjects = new LinkedList<>();
|
||||||
Collection<ObjectCache> allObjs = this.cache.values();
|
List<ObjectCache> allObjs = this.cache.getAllElements(key);
|
||||||
for (ObjectCache objectCache : allObjs) {
|
for (ObjectCache objectCache : allObjs) {
|
||||||
if (objectCache.getOperation() == Operation.ADD && (objectCache.getKey().equals(key))) {
|
if (objectCache.getOperation() == Operation.ADD) {
|
||||||
if (objectCache.getObject().getClass() == clazz) {
|
if (objectCache.getObject().getClass() == clazz) {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
V object = (V) objectCache.getObject();
|
V object = (V) objectCache.getObject();
|
||||||
|
@ -486,9 +497,9 @@ public class ObjectFilter {
|
||||||
*/
|
*/
|
||||||
public List<Object> getUpdated(String key) {
|
public List<Object> getUpdated(String key) {
|
||||||
List<Object> updatedObjects = new LinkedList<>();
|
List<Object> updatedObjects = new LinkedList<>();
|
||||||
Collection<ObjectCache> allObjs = this.cache.values();
|
List<ObjectCache> allObjs = this.cache.getAllElements(key);
|
||||||
for (ObjectCache objectCache : allObjs) {
|
for (ObjectCache objectCache : allObjs) {
|
||||||
if (objectCache.getOperation() == Operation.MODIFY && (objectCache.getKey().equals(key))) {
|
if (objectCache.getOperation() == Operation.MODIFY) {
|
||||||
updatedObjects.add(objectCache.getObject());
|
updatedObjects.add(objectCache.getObject());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -505,11 +516,11 @@ public class ObjectFilter {
|
||||||
*
|
*
|
||||||
* @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.
|
||||||
*/
|
*/
|
||||||
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<>();
|
List<V> updatedObjects = new LinkedList<>();
|
||||||
Collection<ObjectCache> allObjs = this.cache.values();
|
List<ObjectCache> allObjs = this.cache.getAllElements(key);
|
||||||
for (ObjectCache objectCache : allObjs) {
|
for (ObjectCache objectCache : allObjs) {
|
||||||
if (objectCache.getOperation() == Operation.MODIFY && (objectCache.getKey().equals(key))) {
|
if (objectCache.getOperation() == Operation.MODIFY) {
|
||||||
if (objectCache.getObject().getClass() == clazz) {
|
if (objectCache.getObject().getClass() == clazz) {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
V object = (V) objectCache.getObject();
|
V object = (V) objectCache.getObject();
|
||||||
|
@ -530,9 +541,9 @@ public class ObjectFilter {
|
||||||
*/
|
*/
|
||||||
public List<Object> getRemoved(String key) {
|
public List<Object> getRemoved(String key) {
|
||||||
List<Object> removedObjects = new LinkedList<>();
|
List<Object> removedObjects = new LinkedList<>();
|
||||||
Collection<ObjectCache> allObjs = this.cache.values();
|
List<ObjectCache> allObjs = this.cache.getAllElements(key);
|
||||||
for (ObjectCache objectCache : allObjs) {
|
for (ObjectCache objectCache : allObjs) {
|
||||||
if (objectCache.getOperation() == Operation.REMOVE && (objectCache.getKey().equals(key))) {
|
if (objectCache.getOperation() == Operation.REMOVE) {
|
||||||
removedObjects.add(objectCache.getObject());
|
removedObjects.add(objectCache.getObject());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -549,11 +560,11 @@ public class ObjectFilter {
|
||||||
*
|
*
|
||||||
* @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.
|
||||||
*/
|
*/
|
||||||
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<>();
|
List<V> removedObjects = new LinkedList<>();
|
||||||
Collection<ObjectCache> allObjs = this.cache.values();
|
List<ObjectCache> allObjs = this.cache.getAllElements(key);
|
||||||
for (ObjectCache objectCache : allObjs) {
|
for (ObjectCache objectCache : allObjs) {
|
||||||
if (objectCache.getOperation() == Operation.REMOVE && (objectCache.getKey().equals(key))) {
|
if (objectCache.getOperation() == Operation.REMOVE) {
|
||||||
if (objectCache.getObject().getClass() == clazz) {
|
if (objectCache.getObject().getClass() == clazz) {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
V object = (V) objectCache.getObject();
|
V object = (V) objectCache.getObject();
|
||||||
|
@ -574,18 +585,16 @@ public class ObjectFilter {
|
||||||
*
|
*
|
||||||
* @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.
|
||||||
*/
|
*/
|
||||||
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<>();
|
List<V> objects = new LinkedList<>();
|
||||||
Collection<ObjectCache> allObjs = this.cache.values();
|
List<ObjectCache> allObjs = this.cache.getAllElements(key);
|
||||||
for (ObjectCache objectCache : allObjs) {
|
for (ObjectCache objectCache : allObjs) {
|
||||||
if (objectCache.getKey().equals(key)) {
|
|
||||||
if (objectCache.getObject().getClass() == clazz) {
|
if (objectCache.getObject().getClass() == clazz) {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
V object = (V) objectCache.getObject();
|
V object = (V) objectCache.getObject();
|
||||||
objects.add(object);
|
objects.add(object);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return objects;
|
return objects;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -597,9 +606,9 @@ public class ObjectFilter {
|
||||||
*
|
*
|
||||||
* @return The list of all objects that of the given class
|
* @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<>();
|
List<V> objects = new LinkedList<>();
|
||||||
Collection<ObjectCache> allObjs = this.cache.values();
|
Collection<ObjectCache> allObjs = this.cache.getAllElements();
|
||||||
for (ObjectCache objectCache : allObjs) {
|
for (ObjectCache objectCache : allObjs) {
|
||||||
if (objectCache.getObject().getClass() == clazz) {
|
if (objectCache.getObject().getClass() == clazz) {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
|
@ -621,12 +630,10 @@ public class ObjectFilter {
|
||||||
*/
|
*/
|
||||||
public List<Object> getAll(String key) {
|
public List<Object> getAll(String key) {
|
||||||
List<Object> allObjects = new LinkedList<>();
|
List<Object> allObjects = new LinkedList<>();
|
||||||
Collection<ObjectCache> allObjs = this.cache.values();
|
List<ObjectCache> allObjs = this.cache.getAllElements(key);
|
||||||
for (ObjectCache objectCache : allObjs) {
|
for (ObjectCache objectCache : allObjs) {
|
||||||
if (objectCache.getKey().equals(key)) {
|
|
||||||
allObjects.add(objectCache.getObject());
|
allObjects.add(objectCache.getObject());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return allObjects;
|
return allObjects;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -640,14 +647,7 @@ public class ObjectFilter {
|
||||||
* @return The list of objects matching the given key.
|
* @return The list of objects matching the given key.
|
||||||
*/
|
*/
|
||||||
public List<ObjectCache> getCache(String key) {
|
public List<ObjectCache> getCache(String key) {
|
||||||
List<ObjectCache> allCache = new LinkedList<>();
|
return this.cache.getAllElements(key);
|
||||||
Collection<ObjectCache> allObjs = this.cache.values();
|
|
||||||
for (ObjectCache objectCache : allObjs) {
|
|
||||||
if (objectCache.getKey().equals(key)) {
|
|
||||||
allCache.add(objectCache);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return allCache;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -15,16 +15,12 @@
|
||||||
*/
|
*/
|
||||||
package li.strolch.utils.objectfilter;
|
package li.strolch.utils.objectfilter;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.*;
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
import static org.junit.Assert.fail;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import li.strolch.utils.objectfilter.ObjectFilter;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||||
*/
|
*/
|
||||||
|
@ -37,7 +33,7 @@ public class ObjectFilterTest {
|
||||||
Object myObj = new Object();
|
Object myObj = new Object();
|
||||||
|
|
||||||
ObjectFilter filter = new ObjectFilter();
|
ObjectFilter filter = new ObjectFilter();
|
||||||
filter.add(myObj);
|
filter.add(myObj, myObj);
|
||||||
|
|
||||||
testAssertions(filter, 1, 1, 1, 0, 0);
|
testAssertions(filter, 1, 1, 1, 0, 0);
|
||||||
}
|
}
|
||||||
|
@ -48,7 +44,7 @@ public class ObjectFilterTest {
|
||||||
Object myObj = new Object();
|
Object myObj = new Object();
|
||||||
|
|
||||||
ObjectFilter filter = new ObjectFilter();
|
ObjectFilter filter = new ObjectFilter();
|
||||||
filter.update(myObj);
|
filter.update(myObj, myObj);
|
||||||
|
|
||||||
testAssertions(filter, 1, 1, 0, 1, 0);
|
testAssertions(filter, 1, 1, 0, 1, 0);
|
||||||
}
|
}
|
||||||
|
@ -59,7 +55,7 @@ public class ObjectFilterTest {
|
||||||
Object myObj = new Object();
|
Object myObj = new Object();
|
||||||
|
|
||||||
ObjectFilter filter = new ObjectFilter();
|
ObjectFilter filter = new ObjectFilter();
|
||||||
filter.remove(myObj);
|
filter.remove(myObj, myObj);
|
||||||
|
|
||||||
testAssertions(filter, 1, 1, 0, 0, 1);
|
testAssertions(filter, 1, 1, 0, 0, 1);
|
||||||
}
|
}
|
||||||
|
@ -72,9 +68,9 @@ public class ObjectFilterTest {
|
||||||
Object objToRemove = new Object();
|
Object objToRemove = new Object();
|
||||||
|
|
||||||
ObjectFilter filter = new ObjectFilter();
|
ObjectFilter filter = new ObjectFilter();
|
||||||
filter.add(objToAdd);
|
filter.add(objToAdd, objToAdd);
|
||||||
filter.update(objToUpdate);
|
filter.update(objToUpdate, objToUpdate);
|
||||||
filter.remove(objToRemove);
|
filter.remove(objToRemove, objToRemove);
|
||||||
|
|
||||||
testAssertions(filter, 3, 1, 1, 1, 1);
|
testAssertions(filter, 3, 1, 1, 1, 1);
|
||||||
}
|
}
|
||||||
|
@ -85,9 +81,9 @@ public class ObjectFilterTest {
|
||||||
Object objToAddUpdateRemove = new Object();
|
Object objToAddUpdateRemove = new Object();
|
||||||
|
|
||||||
ObjectFilter filter = new ObjectFilter();
|
ObjectFilter filter = new ObjectFilter();
|
||||||
filter.add(objToAddUpdateRemove);
|
filter.add(objToAddUpdateRemove, objToAddUpdateRemove);
|
||||||
filter.update(objToAddUpdateRemove);
|
filter.update(objToAddUpdateRemove, objToAddUpdateRemove);
|
||||||
filter.remove(objToAddUpdateRemove);
|
filter.remove(objToAddUpdateRemove, objToAddUpdateRemove);
|
||||||
|
|
||||||
testAssertions(filter, 0, 1, 0, 0, 0);
|
testAssertions(filter, 0, 1, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
@ -98,10 +94,10 @@ public class ObjectFilterTest {
|
||||||
Object myObj = new Object();
|
Object myObj = new Object();
|
||||||
|
|
||||||
ObjectFilter filter = new ObjectFilter();
|
ObjectFilter filter = new ObjectFilter();
|
||||||
filter.add(myObj);
|
filter.add(myObj, myObj);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
filter.add(myObj);
|
filter.add(myObj, myObj);
|
||||||
fail("Should have failed adding twice!");
|
fail("Should have failed adding twice!");
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
assertEquals("Stale State exception: Invalid + after +", e.getMessage());
|
assertEquals("Stale State exception: Invalid + after +", e.getMessage());
|
||||||
|
@ -116,10 +112,10 @@ public class ObjectFilterTest {
|
||||||
Object myObj = new Object();
|
Object myObj = new Object();
|
||||||
|
|
||||||
ObjectFilter filter = new ObjectFilter();
|
ObjectFilter filter = new ObjectFilter();
|
||||||
filter.remove(myObj);
|
filter.remove(myObj, myObj);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
filter.remove(myObj);
|
filter.remove(myObj, myObj);
|
||||||
fail("Should have failed removing twice!");
|
fail("Should have failed removing twice!");
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
assertEquals("Stale State exception: Invalid - after -", e.getMessage());
|
assertEquals("Stale State exception: Invalid - after -", e.getMessage());
|
||||||
|
@ -134,8 +130,8 @@ public class ObjectFilterTest {
|
||||||
Object myObj = new Object();
|
Object myObj = new Object();
|
||||||
|
|
||||||
ObjectFilter filter = new ObjectFilter();
|
ObjectFilter filter = new ObjectFilter();
|
||||||
filter.update(myObj);
|
filter.update(myObj, myObj);
|
||||||
filter.update(myObj);
|
filter.update(myObj, myObj);
|
||||||
testAssertions(filter, 1, 1, 0, 1, 0);
|
testAssertions(filter, 1, 1, 0, 1, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,9 +141,9 @@ public class ObjectFilterTest {
|
||||||
Object myObj = new Object();
|
Object myObj = new Object();
|
||||||
|
|
||||||
ObjectFilter filter = new ObjectFilter();
|
ObjectFilter filter = new ObjectFilter();
|
||||||
filter.add(myObj);
|
filter.add(myObj, myObj);
|
||||||
filter.update(myObj);
|
filter.update(myObj, myObj);
|
||||||
filter.update(myObj);
|
filter.update(myObj, myObj);
|
||||||
testAssertions(filter, 1, 1, 1, 0, 0);
|
testAssertions(filter, 1, 1, 1, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,10 +152,10 @@ public class ObjectFilterTest {
|
||||||
Object myObj = new Object();
|
Object myObj = new Object();
|
||||||
|
|
||||||
ObjectFilter filter = new ObjectFilter();
|
ObjectFilter filter = new ObjectFilter();
|
||||||
filter.update(myObj);
|
filter.update(myObj, myObj);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
filter.add(myObj);
|
filter.add(myObj, myObj);
|
||||||
fail("Should have failed add after modify");
|
fail("Should have failed add after modify");
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
assertEquals("Stale State exception: Invalid + after +=", e.getMessage());
|
assertEquals("Stale State exception: Invalid + after +=", e.getMessage());
|
||||||
|
@ -173,8 +169,8 @@ public class ObjectFilterTest {
|
||||||
Object myObj = new Object();
|
Object myObj = new Object();
|
||||||
|
|
||||||
ObjectFilter filter = new ObjectFilter();
|
ObjectFilter filter = new ObjectFilter();
|
||||||
filter.remove(myObj);
|
filter.remove(myObj, myObj);
|
||||||
filter.add(myObj);
|
filter.add(myObj, myObj);
|
||||||
|
|
||||||
testAssertions(filter, 1, 1, 0, 1, 0);
|
testAssertions(filter, 1, 1, 0, 1, 0);
|
||||||
}
|
}
|
||||||
|
@ -184,10 +180,10 @@ public class ObjectFilterTest {
|
||||||
Object myObj = new Object();
|
Object myObj = new Object();
|
||||||
|
|
||||||
ObjectFilter filter = new ObjectFilter();
|
ObjectFilter filter = new ObjectFilter();
|
||||||
filter.remove(myObj);
|
filter.remove(myObj, myObj);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
filter.update(myObj);
|
filter.update(myObj, myObj);
|
||||||
fail("Should have failed modify after remove");
|
fail("Should have failed modify after remove");
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
assertEquals("Stale State exception: Invalid += after -", e.getMessage());
|
assertEquals("Stale State exception: Invalid += after -", e.getMessage());
|
||||||
|
@ -201,10 +197,10 @@ public class ObjectFilterTest {
|
||||||
Object myObj = new Object();
|
Object myObj = new Object();
|
||||||
|
|
||||||
ObjectFilter filter = new ObjectFilter();
|
ObjectFilter filter = new ObjectFilter();
|
||||||
filter.add(myObj);
|
filter.add(myObj, myObj);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
filter.update("different_key", myObj);
|
filter.update("different_key", myObj, myObj);
|
||||||
fail("Should have failed because of different key for already registered object");
|
fail("Should have failed because of different key for already registered object");
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
String msg = "Object may be present in the same filter instance only once, registered using one key only";
|
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);
|
assertEquals("Test objects are not equal!", obj1, obj2);
|
||||||
|
|
||||||
ObjectFilter filter = new ObjectFilter();
|
ObjectFilter filter = new ObjectFilter();
|
||||||
filter.remove(Object.class.getName(), obj1);
|
filter.remove(Object.class.getName(), obj1, obj1);
|
||||||
filter.add(Object.class.getName(), obj2);
|
filter.add(Object.class.getName(), obj2, obj2);
|
||||||
|
|
||||||
testAssertions(filter, 1, 1, 0, 1, 0);
|
testAssertions(filter, 1, 1, 0, 1, 0);
|
||||||
|
|
||||||
|
@ -241,8 +237,8 @@ public class ObjectFilterTest {
|
||||||
assertEquals("Test objects are not equal!", obj1, obj2);
|
assertEquals("Test objects are not equal!", obj1, obj2);
|
||||||
|
|
||||||
ObjectFilter filter = new ObjectFilter();
|
ObjectFilter filter = new ObjectFilter();
|
||||||
filter.add(Object.class.getName(), obj1);
|
filter.add(Object.class.getName(), obj1, obj1);
|
||||||
filter.update(Object.class.getName(), obj2);
|
filter.update(Object.class.getName(), obj2, obj2);
|
||||||
|
|
||||||
testAssertions(filter, 1, 1, 1, 0, 0);
|
testAssertions(filter, 1, 1, 1, 0, 0);
|
||||||
|
|
||||||
|
@ -260,8 +256,8 @@ public class ObjectFilterTest {
|
||||||
assertEquals("Test objects are not equal!", obj1, obj2);
|
assertEquals("Test objects are not equal!", obj1, obj2);
|
||||||
|
|
||||||
ObjectFilter filter = new ObjectFilter();
|
ObjectFilter filter = new ObjectFilter();
|
||||||
filter.update(Object.class.getName(), obj1);
|
filter.update(Object.class.getName(), obj1, obj1);
|
||||||
filter.update(Object.class.getName(), obj2);
|
filter.update(Object.class.getName(), obj2, obj2);
|
||||||
|
|
||||||
testAssertions(filter, 1, 1, 0, 1, 0);
|
testAssertions(filter, 1, 1, 0, 1, 0);
|
||||||
|
|
||||||
|
@ -279,8 +275,8 @@ public class ObjectFilterTest {
|
||||||
assertEquals("Test objects are not equal!", obj1, obj2);
|
assertEquals("Test objects are not equal!", obj1, obj2);
|
||||||
|
|
||||||
ObjectFilter filter = new ObjectFilter();
|
ObjectFilter filter = new ObjectFilter();
|
||||||
filter.update(Object.class.getName(), obj1);
|
filter.update(Object.class.getName(), obj1, obj1);
|
||||||
filter.remove(Object.class.getName(), obj2);
|
filter.remove(Object.class.getName(), obj2, obj2);
|
||||||
|
|
||||||
testAssertions(filter, 1, 1, 0, 0, 1);
|
testAssertions(filter, 1, 1, 0, 0, 1);
|
||||||
|
|
||||||
|
@ -296,8 +292,8 @@ public class ObjectFilterTest {
|
||||||
Object myObj = new Object();
|
Object myObj = new Object();
|
||||||
|
|
||||||
ObjectFilter filter = new ObjectFilter();
|
ObjectFilter filter = new ObjectFilter();
|
||||||
filter.add(myObj);
|
filter.add(myObj, myObj);
|
||||||
filter.remove(myObj);
|
filter.remove(myObj, myObj);
|
||||||
testAssertions(filter, 0, 1, 0, 0, 0);
|
testAssertions(filter, 0, 1, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -309,9 +305,9 @@ public class ObjectFilterTest {
|
||||||
Object myObj3 = new Object();
|
Object myObj3 = new Object();
|
||||||
|
|
||||||
ObjectFilter filter = new ObjectFilter();
|
ObjectFilter filter = new ObjectFilter();
|
||||||
filter.add(myObj1);
|
filter.add(myObj1, myObj1);
|
||||||
filter.update(myObj2);
|
filter.update(myObj2, myObj2);
|
||||||
filter.remove(myObj3);
|
filter.remove(myObj3, myObj3);
|
||||||
|
|
||||||
filter.clearCache();
|
filter.clearCache();
|
||||||
|
|
||||||
|
@ -326,9 +322,9 @@ public class ObjectFilterTest {
|
||||||
Object myObj3 = new Object();
|
Object myObj3 = new Object();
|
||||||
|
|
||||||
ObjectFilter filter = new ObjectFilter();
|
ObjectFilter filter = new ObjectFilter();
|
||||||
filter.add(myObj1);
|
filter.add(myObj1, myObj1);
|
||||||
filter.update(myObj2);
|
filter.update(myObj2, myObj2);
|
||||||
filter.remove(myObj3);
|
filter.remove(myObj3, myObj3);
|
||||||
|
|
||||||
testAssertions(filter, 3, 1, 1, 1, 1);
|
testAssertions(filter, 3, 1, 1, 1, 1);
|
||||||
|
|
||||||
|
@ -345,7 +341,7 @@ public class ObjectFilterTest {
|
||||||
Object myObj1 = new Object();
|
Object myObj1 = new Object();
|
||||||
|
|
||||||
ObjectFilter filter = new ObjectFilter();
|
ObjectFilter filter = new ObjectFilter();
|
||||||
filter.add(myObj1);
|
filter.add(myObj1, myObj1);
|
||||||
|
|
||||||
testAssertions(filter, 1, 1, 1, 0, 0);
|
testAssertions(filter, 1, 1, 1, 0, 0);
|
||||||
|
|
||||||
|
@ -360,7 +356,7 @@ public class ObjectFilterTest {
|
||||||
Object myObj1 = new Object();
|
Object myObj1 = new Object();
|
||||||
|
|
||||||
ObjectFilter filter = new ObjectFilter();
|
ObjectFilter filter = new ObjectFilter();
|
||||||
filter.update(myObj1);
|
filter.update(myObj1, myObj1);
|
||||||
|
|
||||||
testAssertions(filter, 1, 1, 0, 1, 0);
|
testAssertions(filter, 1, 1, 0, 1, 0);
|
||||||
|
|
||||||
|
@ -375,7 +371,7 @@ public class ObjectFilterTest {
|
||||||
Object myObj1 = new Object();
|
Object myObj1 = new Object();
|
||||||
|
|
||||||
ObjectFilter filter = new ObjectFilter();
|
ObjectFilter filter = new ObjectFilter();
|
||||||
filter.remove(myObj1);
|
filter.remove(myObj1, myObj1);
|
||||||
|
|
||||||
testAssertions(filter, 1, 1, 0, 0, 1);
|
testAssertions(filter, 1, 1, 0, 0, 1);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue