[Major] Implemented opt-in versioning
Now all root elements have a version, and if the realm has versioning enabled, then actions through the ElementMap lead to new versions being created. There are also methods to revert/undo changes to an object. Some tests are still failing, this will be fixed later
This commit is contained in:
parent
219eb26182
commit
9dc09515e9
|
@ -23,33 +23,106 @@ import li.strolch.model.StrolchRootElement;
|
|||
import li.strolch.model.parameter.Parameter;
|
||||
import li.strolch.model.parameter.StringListParameter;
|
||||
import li.strolch.model.parameter.StringParameter;
|
||||
import li.strolch.persistence.api.StrolchDao;
|
||||
import li.strolch.persistence.api.StrolchPersistenceException;
|
||||
import li.strolch.persistence.api.StrolchTransaction;
|
||||
import li.strolch.runtime.StrolchConstants;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* The {@link ElementMap} is the entry point to the Strolch model. Any access to Strolch objects is done using the
|
||||
* {@link ElementMap}. A concrete {@link ElementMap} instance uses the given {@link StrolchTransaction} to access the a
|
||||
* {@link StrolchDao} and perform the relevant operation.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* <b>Note:</b>
|
||||
* </p>
|
||||
*
|
||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||
*
|
||||
* @param <T>
|
||||
* the object instance being managed
|
||||
*/
|
||||
public interface ElementMap<T extends StrolchRootElement> {
|
||||
|
||||
/**
|
||||
* Returns true if the underlying persistence layer has elements with the given type
|
||||
*
|
||||
* @param tx
|
||||
* the open {@link StrolchTransaction}
|
||||
* @param type
|
||||
* the type of element to check for
|
||||
*
|
||||
* @return true if the underlying persistence layer has elements with the given type
|
||||
*/
|
||||
public boolean hasType(StrolchTransaction tx, String type);
|
||||
|
||||
/**
|
||||
* Returns true if the underlying persistence layer has an element with the given type and ID
|
||||
*
|
||||
* @param tx
|
||||
* the open {@link StrolchTransaction}
|
||||
* @param type
|
||||
* the type of element to check for
|
||||
* @param id
|
||||
* the ID of the element to check for
|
||||
*
|
||||
* @return true if the underlying persistence layer has an element with the given type and ID
|
||||
*/
|
||||
public boolean hasElement(StrolchTransaction tx, String type, String id);
|
||||
|
||||
/**
|
||||
* Returns the number of elements regardless of type in the underlying persistence layer
|
||||
*
|
||||
* @param tx
|
||||
* the open {@link StrolchTransaction}
|
||||
*
|
||||
* @return the number of elements regardless of type in the underlying persistence layer
|
||||
*/
|
||||
public long querySize(StrolchTransaction tx);
|
||||
|
||||
/**
|
||||
* Returns the number of elements of the given type in the underlying persistence layer
|
||||
*
|
||||
* @param tx
|
||||
* the open {@link StrolchTransaction}
|
||||
* @param type
|
||||
* the type of element for which the number of elements is to be queried
|
||||
*
|
||||
* @return the number of elements of the given type in the underlying persistence layer
|
||||
*/
|
||||
public long querySize(StrolchTransaction tx, String type);
|
||||
|
||||
/**
|
||||
* Returns the element with the type "Template" and the id = type
|
||||
* Returns a copy of the element with the type "Template" and the id = type
|
||||
*
|
||||
* @param tx
|
||||
* the open {@link StrolchTransaction}
|
||||
* @param type
|
||||
* The template id to return
|
||||
*
|
||||
* @return the template, or null if it does not exist
|
||||
*/
|
||||
public T getTemplate(StrolchTransaction tx, String type);
|
||||
|
||||
/**
|
||||
* Returns a copy of the element with the type "Template" and the id = type
|
||||
*
|
||||
* @param tx
|
||||
* the open {@link StrolchTransaction}
|
||||
* @param type
|
||||
* The template id to return
|
||||
* @param assertExists
|
||||
* if true, and element does not exist, then a {@link StrolchException} is thrown
|
||||
*
|
||||
* @return the template, or null if it does not exist
|
||||
*
|
||||
* @throws StrolchException
|
||||
* if the template does not exist
|
||||
*/
|
||||
public T getTemplate(StrolchTransaction tx, String type, boolean assertExists) throws StrolchException;
|
||||
|
||||
/**
|
||||
* Retrieves the element with the given type and id, or null if it does not exist
|
||||
*
|
||||
|
@ -64,6 +137,63 @@ public interface ElementMap<T extends StrolchRootElement> {
|
|||
*/
|
||||
public T getBy(StrolchTransaction tx, String type, String id);
|
||||
|
||||
/**
|
||||
* Retrieves the element with the given type and id, or null if it does not exist
|
||||
*
|
||||
* @param tx
|
||||
* the open transaction
|
||||
* @param type
|
||||
* the type of the element to retrieve
|
||||
* @param id
|
||||
* the id of the element to retrieve
|
||||
* @param assertExists
|
||||
* if true, and element does not exist, then a {@link StrolchException} is thrown
|
||||
*
|
||||
* @return the element with the type and id, or null if it does not exist
|
||||
*
|
||||
* @throws StrolchException
|
||||
* if the element does not exist
|
||||
*/
|
||||
public T getBy(StrolchTransaction tx, String type, String id, boolean assertExists) throws StrolchException;
|
||||
|
||||
/**
|
||||
* Retrieves the specific version of the element with the given type and id, or null if it does not exist
|
||||
*
|
||||
* @param tx
|
||||
* the open transaction
|
||||
* @param type
|
||||
* the type of the element to retrieve
|
||||
* @param id
|
||||
* the id of the element to retrieve
|
||||
* @param version
|
||||
* the version to get
|
||||
*
|
||||
* @return the element with the type and id, or null if it does not exist
|
||||
*/
|
||||
public T getBy(StrolchTransaction tx, String type, String id, int version);
|
||||
|
||||
/**
|
||||
* Retrieves the specific version of the element with the given type and id, or null if it does not exist
|
||||
*
|
||||
* @param tx
|
||||
* the open transaction
|
||||
* @param type
|
||||
* the type of the element to retrieve
|
||||
* @param id
|
||||
* the id of the element to retrieve
|
||||
* @param version
|
||||
* the version to get
|
||||
* @param assertExists
|
||||
* if true, and element does not exist, then a {@link StrolchException} is thrown
|
||||
*
|
||||
* @return the element with the type and id, or null if it does not exist
|
||||
*
|
||||
* @throws StrolchException
|
||||
* if the element does not exist
|
||||
*/
|
||||
public T getBy(StrolchTransaction tx, String type, String id, int version, boolean assertExists)
|
||||
throws StrolchException;
|
||||
|
||||
/**
|
||||
* Returns the element which is referenced by the given {@link StringParameter}. A reference {@link Parameter} must
|
||||
* have its interpretation set to the element type being referenced e.g. s
|
||||
|
@ -105,29 +235,264 @@ public interface ElementMap<T extends StrolchRootElement> {
|
|||
*/
|
||||
public List<T> getBy(StrolchTransaction tx, StringListParameter refP, boolean assertExists) throws StrolchException;
|
||||
|
||||
/**
|
||||
* Queries and returns all the versions of the element with the given type and ID
|
||||
*
|
||||
* @param tx
|
||||
* the {@link StrolchTransaction} instance
|
||||
* @param type
|
||||
* the type of the element to be queried
|
||||
* @param id
|
||||
* the id of the element to be queried
|
||||
*
|
||||
* @return all the versions of the element with the given type and ID
|
||||
*/
|
||||
public List<T> getVersionsFor(StrolchTransaction tx, String type, String id);
|
||||
|
||||
/**
|
||||
* Returns all elements in the underlying persistence layer regardless of type
|
||||
*
|
||||
* @param tx
|
||||
* the {@link StrolchTransaction} instance
|
||||
*
|
||||
* @return all elements in the underlying persistence layer regardless of type
|
||||
*/
|
||||
public List<T> getAllElements(StrolchTransaction tx);
|
||||
|
||||
/**
|
||||
* Returns all elements in the underlying persistence layer of the given type
|
||||
*
|
||||
* @param tx
|
||||
* the {@link StrolchTransaction} instance
|
||||
*
|
||||
* @param type
|
||||
* the type of the elements to retrieve
|
||||
*
|
||||
* @return all elements in the underlying persistence layer of the given type
|
||||
*/
|
||||
public List<T> getElementsBy(StrolchTransaction tx, String type);
|
||||
|
||||
/**
|
||||
* Returns all the types known in the underlying persistence layer
|
||||
*
|
||||
* @param tx
|
||||
* the {@link StrolchTransaction} instance
|
||||
*
|
||||
* @return all the types known in the underlying persistence layer
|
||||
*/
|
||||
public Set<String> getTypes(StrolchTransaction tx);
|
||||
|
||||
/**
|
||||
* Returns all keys/IDs of all elements in the underlying persistence layer, regardless of type
|
||||
*
|
||||
* @param tx
|
||||
* the {@link StrolchTransaction} instance
|
||||
*
|
||||
* @return all keys/IDs of all elements in the underlying persistence layer, regardless of type
|
||||
*/
|
||||
public Set<String> getAllKeys(StrolchTransaction tx);
|
||||
|
||||
/**
|
||||
* Returns all keys/IDs of all elements in the underlying persistence layer, of the given type
|
||||
*
|
||||
* @param tx
|
||||
* the {@link StrolchTransaction} instance
|
||||
* @param type
|
||||
* the type of the element to retrieve the keys for
|
||||
*
|
||||
* @return all keys/IDs of all elements in the underlying persistence layer, of the given type
|
||||
*/
|
||||
public Set<String> getKeysBy(StrolchTransaction tx, String type);
|
||||
|
||||
public void add(StrolchTransaction tx, T element);
|
||||
/**
|
||||
* Adds the given element to the underlying persistence layer. The element may not already exist
|
||||
*
|
||||
* @param tx
|
||||
* the {@link StrolchTransaction} instance
|
||||
* @param element
|
||||
* the element to add
|
||||
*
|
||||
* @throws StrolchPersistenceException
|
||||
* if an element already exists with the same ID
|
||||
*/
|
||||
public void add(StrolchTransaction tx, T element) throws StrolchPersistenceException;
|
||||
|
||||
public void addAll(StrolchTransaction tx, List<T> elements);
|
||||
/**
|
||||
* Adds the given elements to the underlying persistence layer. None of the elements may already exist
|
||||
*
|
||||
* @param tx
|
||||
* the {@link StrolchTransaction} instance
|
||||
* @param elements
|
||||
* the elements to add
|
||||
*
|
||||
* @throws StrolchPersistenceException
|
||||
* if an element already exists with the same ID
|
||||
*/
|
||||
public void addAll(StrolchTransaction tx, List<T> elements) throws StrolchPersistenceException;
|
||||
|
||||
public T update(StrolchTransaction tx, T element);
|
||||
/**
|
||||
* Updates the existing element
|
||||
*
|
||||
* @param tx
|
||||
* the {@link StrolchTransaction} instance
|
||||
* @param element
|
||||
* the element to update
|
||||
*
|
||||
* @return the replaced element
|
||||
*
|
||||
* @throws StrolchPersistenceException
|
||||
* if the element does not exist
|
||||
*/
|
||||
public void update(StrolchTransaction tx, T element) throws StrolchPersistenceException;
|
||||
|
||||
public List<T> updateAll(StrolchTransaction tx, List<T> elements);
|
||||
/**
|
||||
* Updates all the existing elements
|
||||
*
|
||||
* @param tx
|
||||
* the {@link StrolchTransaction} instance
|
||||
* @param elements
|
||||
* the elements to update
|
||||
*
|
||||
* @return the replaced elements
|
||||
*
|
||||
* @throws StrolchPersistenceException
|
||||
* if any of the elements don't yet exist
|
||||
*/
|
||||
public void updateAll(StrolchTransaction tx, List<T> elements) throws StrolchPersistenceException;
|
||||
|
||||
public void remove(StrolchTransaction tx, T element);
|
||||
/**
|
||||
* Removes the given element
|
||||
*
|
||||
* @param tx
|
||||
* the {@link StrolchTransaction} instance
|
||||
* @param element
|
||||
* the element to be removed
|
||||
*
|
||||
* @throws StrolchPersistenceException
|
||||
* if the element does not exist
|
||||
*/
|
||||
public void remove(StrolchTransaction tx, T element) throws StrolchPersistenceException;
|
||||
|
||||
public void removeAll(StrolchTransaction tx, List<T> elements);
|
||||
/**
|
||||
* Removes the given elements
|
||||
*
|
||||
* @param tx
|
||||
* the {@link StrolchTransaction} instance
|
||||
* @param elements
|
||||
* the elements to be removed
|
||||
*
|
||||
* @throws StrolchPersistenceException
|
||||
* if any of the elements don't yet exist
|
||||
*/
|
||||
public void removeAll(StrolchTransaction tx, List<T> elements) throws StrolchPersistenceException;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Removes all elements regardless of the type
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* <b>Note:</b> This method ignores versioning. Do NOT call this method unless you want to clear the model!
|
||||
* </p>
|
||||
*
|
||||
* @param tx
|
||||
* the {@link StrolchTransaction} instance
|
||||
*
|
||||
* @return the number of elements removed
|
||||
*/
|
||||
public long removeAll(StrolchTransaction tx);
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Removes all elements of the given type
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* <b>Note:</b> This method ignores versioning. Do NOT call this method unless you want to clear the model!
|
||||
* </p>
|
||||
*
|
||||
* @param tx
|
||||
* the {@link StrolchTransaction} instance
|
||||
* @param type
|
||||
* the type of elements to remove
|
||||
*
|
||||
* @return the number of elements removed
|
||||
*/
|
||||
public long removeAllBy(StrolchTransaction tx, String type);
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Undoes the given version by reverting to the previous version of the element given. If the element given is the
|
||||
* first version, then the element is removed. If the previous version exists, then it is reverted to it. If the
|
||||
* given element does not exist, nor it's previous version, then a {@link StrolchPersistenceException} is thrown
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* <b>Note:</b> This method should only be used in the same transaction where the element was created to undo a
|
||||
* change in the same transaction. If there is a requirement to revert to a previous version, then the
|
||||
* {@link #revertToVersion(StrolchTransaction, StrolchRootElement)} method.
|
||||
* </p>
|
||||
*
|
||||
* @param tx
|
||||
* the {@link StrolchTransaction} instance
|
||||
* @param element
|
||||
* the element which is to be reverted to a previous version
|
||||
*
|
||||
* @throws StrolchException
|
||||
* if the version does not exist, if this version is not the latest version, if the previous version is
|
||||
* missing or other problems arise
|
||||
*/
|
||||
public void undoVersion(StrolchTransaction tx, T element) throws StrolchException;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Reverts to the given version of the specified element. This method will retrieve the given version of the
|
||||
* specified element, then set a new version on that element which is an increment of the current latest version and
|
||||
* store this new version. The new element is then returned for convenience.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* <b>Note:</b> This is the method which should be called when a change should be reverted. This method gurantees
|
||||
* that the history is not changed and that a new version is saved but with the version of the element specified.
|
||||
* </p>
|
||||
*
|
||||
* @param tx
|
||||
* the {@link StrolchTransaction} instance
|
||||
* @param element
|
||||
* the version of the element to revert to
|
||||
*
|
||||
* @return the new version of the element
|
||||
*
|
||||
* @throws StrolchException
|
||||
* if the version does not exist
|
||||
*/
|
||||
public T revertToVersion(StrolchTransaction tx, T element) throws StrolchException;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Reverts to the given version of the specified element. This method will retrieve the given version of the
|
||||
* specified element, then set a new version on that element which is an increment of the current latest version and
|
||||
* store this new version. The new element is then returned for convenience.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* <b>Note:</b> This is the method which should be called when a change should be reverted. This method gurantees
|
||||
* that the history is not changed and that a new version is saved but with the version of the element specified.
|
||||
* </p>
|
||||
*
|
||||
* @param tx
|
||||
* the {@link StrolchTransaction} instance
|
||||
* @param type
|
||||
* the type of the element to revert to
|
||||
* @param id
|
||||
* the id of the element to revert to
|
||||
* @param version
|
||||
* the version of the specified element to revert to
|
||||
*
|
||||
* @return the new version of the element
|
||||
*
|
||||
* @throws StrolchException
|
||||
* if the version does not exist
|
||||
*/
|
||||
public T revertToVersion(StrolchTransaction tx, String type, String id, int version) throws StrolchException;
|
||||
}
|
||||
|
|
|
@ -45,5 +45,7 @@ public interface StrolchRealm {
|
|||
|
||||
public boolean isUpdateObservers();
|
||||
|
||||
public boolean isVersioningEnabled();
|
||||
|
||||
public ObserverHandler getObserverHandler();
|
||||
}
|
||||
|
|
|
@ -137,7 +137,15 @@ public class AuditingElementMapFacade<T extends StrolchRootElement> implements E
|
|||
@Override
|
||||
public T getTemplate(StrolchTransaction tx, String type) {
|
||||
T template = this.elementMap.getTemplate(tx, type);
|
||||
if (this.observeAccessReads)
|
||||
if (this.observeAccessReads && template != null)
|
||||
this.read.add(template);
|
||||
return template;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T getTemplate(StrolchTransaction tx, String type, boolean assertExists) throws StrolchException {
|
||||
T template = this.elementMap.getTemplate(tx, type, assertExists);
|
||||
if (this.observeAccessReads && template != null)
|
||||
this.read.add(template);
|
||||
return template;
|
||||
}
|
||||
|
@ -145,7 +153,32 @@ public class AuditingElementMapFacade<T extends StrolchRootElement> implements E
|
|||
@Override
|
||||
public T getBy(StrolchTransaction tx, String type, String id) {
|
||||
T element = this.elementMap.getBy(tx, type, id);
|
||||
if (this.observeAccessReads)
|
||||
if (this.observeAccessReads && element != null)
|
||||
this.read.add(element);
|
||||
return element;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T getBy(StrolchTransaction tx, String type, String id, boolean assertExists) throws StrolchException {
|
||||
T element = this.elementMap.getBy(tx, type, id, assertExists);
|
||||
if (this.observeAccessReads && element != null)
|
||||
this.read.add(element);
|
||||
return element;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T getBy(StrolchTransaction tx, String type, String id, int version) {
|
||||
T element = this.elementMap.getBy(tx, type, id, version);
|
||||
if (this.observeAccessReads && element != null)
|
||||
this.read.add(element);
|
||||
return element;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T getBy(StrolchTransaction tx, String type, String id, int version, boolean assertExists)
|
||||
throws StrolchException {
|
||||
T element = this.elementMap.getBy(tx, type, id, version, assertExists);
|
||||
if (this.observeAccessReads && element != null)
|
||||
this.read.add(element);
|
||||
return element;
|
||||
}
|
||||
|
@ -153,23 +186,32 @@ public class AuditingElementMapFacade<T extends StrolchRootElement> implements E
|
|||
@Override
|
||||
public T getBy(StrolchTransaction tx, StringParameter refP, boolean assertExists) throws StrolchException {
|
||||
T element = this.elementMap.getBy(tx, refP, assertExists);
|
||||
if (this.observeAccessReads)
|
||||
if (this.observeAccessReads && element != null)
|
||||
this.read.add(element);
|
||||
return element;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<T> getBy(StrolchTransaction tx, StringListParameter refP, boolean assertExists) throws StrolchException {
|
||||
public List<T> getBy(StrolchTransaction tx, StringListParameter refP, boolean assertExists)
|
||||
throws StrolchException {
|
||||
List<T> elements = this.elementMap.getBy(tx, refP, assertExists);
|
||||
if (this.observeAccessReads)
|
||||
if (this.observeAccessReads && !elements.isEmpty())
|
||||
this.read.addAll(elements);
|
||||
return elements;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<T> getVersionsFor(StrolchTransaction tx, String type, String id) {
|
||||
List<T> versions = this.elementMap.getVersionsFor(tx, type, id);
|
||||
if (this.observeAccessReads && !versions.isEmpty())
|
||||
this.read.add(versions.get(versions.size() - 1));
|
||||
return versions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<T> getAllElements(StrolchTransaction tx) {
|
||||
List<T> elements = this.elementMap.getAllElements(tx);
|
||||
if (this.observeAccessReads)
|
||||
if (this.observeAccessReads && !elements.isEmpty())
|
||||
this.read.addAll(elements);
|
||||
return elements;
|
||||
}
|
||||
|
@ -177,7 +219,7 @@ public class AuditingElementMapFacade<T extends StrolchRootElement> implements E
|
|||
@Override
|
||||
public List<T> getElementsBy(StrolchTransaction tx, String type) {
|
||||
List<T> elements = this.elementMap.getElementsBy(tx, type);
|
||||
if (this.observeAccessReads)
|
||||
if (this.observeAccessReads && !elements.isEmpty())
|
||||
this.read.addAll(elements);
|
||||
return elements;
|
||||
}
|
||||
|
@ -210,18 +252,15 @@ public class AuditingElementMapFacade<T extends StrolchRootElement> implements E
|
|||
}
|
||||
|
||||
@Override
|
||||
public T update(StrolchTransaction tx, T element) {
|
||||
T replaced = this.elementMap.update(tx, element);
|
||||
public void update(StrolchTransaction tx, T element) {
|
||||
this.elementMap.update(tx, element);
|
||||
this.updated.add(element);
|
||||
return replaced;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<T> updateAll(StrolchTransaction tx, List<T> elements) {
|
||||
List<T> replaced = this.elementMap.updateAll(tx, elements);
|
||||
public void updateAll(StrolchTransaction tx, List<T> elements) {
|
||||
this.elementMap.updateAll(tx, elements);
|
||||
this.updated.addAll(elements);
|
||||
return replaced;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -255,4 +294,27 @@ public class AuditingElementMapFacade<T extends StrolchRootElement> implements E
|
|||
|
||||
return removed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T revertToVersion(StrolchTransaction tx, String type, String id, int version) throws StrolchException {
|
||||
T element = this.elementMap.revertToVersion(tx, type, id, version);
|
||||
this.updated.add(element);
|
||||
return element;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T revertToVersion(StrolchTransaction tx, T element) throws StrolchException {
|
||||
T revertedElement = this.elementMap.revertToVersion(tx, element);
|
||||
this.updated.add(revertedElement);
|
||||
return revertedElement;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void undoVersion(StrolchTransaction tx, T element) throws StrolchException {
|
||||
this.elementMap.undoVersion(tx, element);
|
||||
if (element.getVersion().isFirstVersion())
|
||||
this.deleted.add(element);
|
||||
else
|
||||
this.updated.add(element);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ import static li.strolch.model.StrolchModelConstants.INTERPRETATION_ACTIVITY_REF
|
|||
import java.util.List;
|
||||
|
||||
import li.strolch.agent.api.ActivityMap;
|
||||
import li.strolch.agent.api.StrolchRealm;
|
||||
import li.strolch.model.activity.Activity;
|
||||
import li.strolch.model.parameter.Parameter;
|
||||
import li.strolch.model.query.ActivityQuery;
|
||||
|
@ -31,9 +32,10 @@ public class CachedActivityMap extends CachedElementMap<Activity> implements Act
|
|||
|
||||
private ActivityDao cachedDao;
|
||||
|
||||
public CachedActivityMap() {
|
||||
super();
|
||||
this.cachedDao = new InMemoryActivityDao();
|
||||
public CachedActivityMap(StrolchRealm realm) {
|
||||
super(realm);
|
||||
// the cached DAO should not have versioning enabled
|
||||
this.cachedDao = new InMemoryActivityDao(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -16,23 +16,27 @@
|
|||
package li.strolch.agent.impl;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import li.strolch.agent.api.ElementMap;
|
||||
import li.strolch.agent.api.StrolchRealm;
|
||||
import li.strolch.exception.StrolchException;
|
||||
import li.strolch.model.StrolchRootElement;
|
||||
import li.strolch.model.Version;
|
||||
import li.strolch.model.parameter.Parameter;
|
||||
import li.strolch.model.parameter.StringListParameter;
|
||||
import li.strolch.model.parameter.StringParameter;
|
||||
import li.strolch.persistence.api.StrolchDao;
|
||||
import li.strolch.persistence.api.StrolchPersistenceException;
|
||||
import li.strolch.persistence.api.StrolchTransaction;
|
||||
import li.strolch.runtime.StrolchConstants;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||
*/
|
||||
|
@ -40,6 +44,16 @@ public abstract class CachedElementMap<T extends StrolchRootElement> implements
|
|||
|
||||
private static final Logger logger = LoggerFactory.getLogger(CachedElementMap.class);
|
||||
|
||||
private StrolchRealm realm;
|
||||
|
||||
public CachedElementMap(StrolchRealm realm) {
|
||||
this.realm = realm;
|
||||
}
|
||||
|
||||
protected StrolchRealm getRealm() {
|
||||
return this.realm;
|
||||
}
|
||||
|
||||
protected abstract StrolchDao<T> getCachedDao();
|
||||
|
||||
protected abstract StrolchDao<T> getDbDao(StrolchTransaction tx);
|
||||
|
@ -66,62 +80,110 @@ public abstract class CachedElementMap<T extends StrolchRootElement> implements
|
|||
|
||||
@Override
|
||||
public synchronized T getTemplate(StrolchTransaction tx, String type) {
|
||||
return getBy(tx, StrolchConstants.TEMPLATE, type);
|
||||
return getTemplate(tx, type, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T getTemplate(StrolchTransaction tx, String type, boolean assertExists) {
|
||||
T t = getCachedDao().queryBy(StrolchConstants.TEMPLATE, type);
|
||||
if (assertExists && t == null) {
|
||||
String msg = "The template for type {0} does not exist!"; //$NON-NLS-1$
|
||||
throw new StrolchException(MessageFormat.format(msg, type));
|
||||
}
|
||||
|
||||
if (t == null)
|
||||
return null;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
T clone = (T) t.getClone();
|
||||
clone.setVersion(t.getVersion());
|
||||
return clone;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized T getBy(StrolchTransaction tx, String type, String id) {
|
||||
return getCachedDao().queryBy(type, id);
|
||||
return getBy(tx, type, id, false);
|
||||
}
|
||||
|
||||
protected abstract void assertIsRefParam(Parameter<?> refP);
|
||||
@Override
|
||||
public T getBy(StrolchTransaction tx, String type, String id, boolean assertExists) throws StrolchException {
|
||||
T t = getCachedDao().queryBy(type, id);
|
||||
if (assertExists && t == null) {
|
||||
String msg = "The element for type {0} and id {1} does not exist!"; //$NON-NLS-1$
|
||||
throw new StrolchException(MessageFormat.format(msg, type, id));
|
||||
}
|
||||
|
||||
if (t == null)
|
||||
return null;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
T clone = (T) t.getClone();
|
||||
clone.setVersion(t.getVersion());
|
||||
return clone;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T getBy(StrolchTransaction tx, String type, String id, int version) {
|
||||
return getBy(tx, type, id, version, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T getBy(StrolchTransaction tx, String type, String id, int version, boolean assertExists)
|
||||
throws StrolchException {
|
||||
T t = getDbDao(tx).queryBy(type, id, version);
|
||||
if (assertExists && t == null) {
|
||||
String msg = "The element for type {0} and id {1} and version {2} does not exist!"; //$NON-NLS-1$
|
||||
msg = MessageFormat.format(msg, type, id, version);
|
||||
throw new StrolchException(msg);
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T getBy(StrolchTransaction tx, StringParameter refP, boolean assertExists) throws StrolchException {
|
||||
assertIsRefParam(refP);
|
||||
String type = refP.getUom();
|
||||
String id = refP.getValue();
|
||||
T element = getBy(tx, type, id);
|
||||
if (assertExists && element == null) {
|
||||
String msg = "The element for refP {0} with id {1} does not exist!"; //$NON-NLS-1$
|
||||
msg = MessageFormat.format(msg, refP.getLocator(), id);
|
||||
throw new StrolchException(msg);
|
||||
}
|
||||
return element;
|
||||
return getBy(tx, type, id, assertExists);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<T> getBy(StrolchTransaction tx, StringListParameter refP, boolean assertExists) throws StrolchException {
|
||||
public List<T> getBy(StrolchTransaction tx, StringListParameter refP, boolean assertExists)
|
||||
throws StrolchException {
|
||||
assertIsRefParam(refP);
|
||||
|
||||
List<T> elements = new ArrayList<>();
|
||||
String type = refP.getUom();
|
||||
List<String> ids = refP.getValue();
|
||||
|
||||
for (String id : ids) {
|
||||
T element = getBy(tx, type, id);
|
||||
if (element != null) {
|
||||
elements.add(element);
|
||||
} else if (assertExists) {
|
||||
if (assertExists && element == null) {
|
||||
String msg = "The element for refP {0} with id {1} does not exist!"; //$NON-NLS-1$
|
||||
msg = MessageFormat.format(msg, refP.getLocator(), id);
|
||||
throw new StrolchException(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ids.stream().map(id -> getBy(tx, type, id, assertExists)).filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
return elements;
|
||||
@Override
|
||||
public List<T> getVersionsFor(StrolchTransaction tx, String type, String id) {
|
||||
return getDbDao(tx).queryVersionsFor(type, id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized List<T> getAllElements(StrolchTransaction tx) {
|
||||
return getCachedDao().queryAll();
|
||||
List<T> all = getCachedDao().queryAll();
|
||||
return all.stream().map(t -> {
|
||||
@SuppressWarnings("unchecked")
|
||||
T clone = (T) t.getClone();
|
||||
clone.setVersion(t.getVersion());
|
||||
return clone;
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized List<T> getElementsBy(StrolchTransaction tx, String type) {
|
||||
return getCachedDao().queryAll(type);
|
||||
List<T> all = getCachedDao().queryAll(type);
|
||||
return all.stream().map(t -> {
|
||||
@SuppressWarnings("unchecked")
|
||||
T clone = (T) t.getClone();
|
||||
clone.setVersion(t.getVersion());
|
||||
return clone;
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -139,14 +201,6 @@ public abstract class CachedElementMap<T extends StrolchRootElement> implements
|
|||
return getCachedDao().queryKeySet(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void add(StrolchTransaction tx, T element) {
|
||||
// first perform cached change
|
||||
getCachedDao().save(element);
|
||||
// last is to perform DB changes
|
||||
getDbDao(tx).save(element);
|
||||
}
|
||||
|
||||
/**
|
||||
* Special method used when starting the container to cache the values. Not to be used anywhere else but from the
|
||||
* {@link CachedRealm}
|
||||
|
@ -158,27 +212,28 @@ public abstract class CachedElementMap<T extends StrolchRootElement> implements
|
|||
getCachedDao().save(element);
|
||||
}
|
||||
|
||||
// TODO for update we should return the updated elements, or remove the return value
|
||||
|
||||
@Override
|
||||
public synchronized T update(StrolchTransaction tx, T element) {
|
||||
public synchronized void add(StrolchTransaction tx, T element) {
|
||||
if (realm.isVersioningEnabled())
|
||||
Version.updateVersionFor(element, tx.getCertificate().getUsername(), false);
|
||||
else
|
||||
Version.setInitialVersionFor(element, tx.getCertificate().getUsername());
|
||||
|
||||
// first perform cached change
|
||||
getCachedDao().update(element);
|
||||
getCachedDao().save(element);
|
||||
// last is to perform DB changes
|
||||
getDbDao(tx).update(element);
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void remove(StrolchTransaction tx, T element) {
|
||||
// first perform cached change
|
||||
getCachedDao().remove(element);
|
||||
getDbDao(tx).remove(element);
|
||||
getDbDao(tx).save(element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void addAll(StrolchTransaction tx, List<T> elements) {
|
||||
for (T element : elements) {
|
||||
if (realm.isVersioningEnabled())
|
||||
Version.updateVersionFor(element, tx.getCertificate().getUsername(), false);
|
||||
else
|
||||
Version.setInitialVersionFor(element, tx.getCertificate().getUsername());
|
||||
}
|
||||
|
||||
// first perform cached change
|
||||
getCachedDao().saveAll(elements);
|
||||
// last is to perform DB changes
|
||||
|
@ -186,21 +241,79 @@ public abstract class CachedElementMap<T extends StrolchRootElement> implements
|
|||
}
|
||||
|
||||
@Override
|
||||
public synchronized List<T> updateAll(StrolchTransaction tx, List<T> elements) {
|
||||
public synchronized void update(StrolchTransaction tx, T element) {
|
||||
if (realm.isVersioningEnabled())
|
||||
Version.updateVersionFor(element, tx.getCertificate().getUsername(), false);
|
||||
else
|
||||
Version.setInitialVersionFor(element, tx.getCertificate().getUsername());
|
||||
|
||||
// first perform cached change
|
||||
getCachedDao().update(element);
|
||||
// last is to perform DB changes
|
||||
getDbDao(tx).update(element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void updateAll(StrolchTransaction tx, List<T> elements) {
|
||||
for (T t : elements) {
|
||||
if (realm.isVersioningEnabled())
|
||||
Version.updateVersionFor(t, tx.getCertificate().getUsername(), false);
|
||||
else
|
||||
Version.setInitialVersionFor(t, tx.getCertificate().getUsername());
|
||||
}
|
||||
|
||||
// first perform cached change
|
||||
getCachedDao().updateAll(elements);
|
||||
// last is to perform DB changes
|
||||
getDbDao(tx).updateAll(elements);
|
||||
}
|
||||
|
||||
return elements;
|
||||
@Override
|
||||
public synchronized void remove(StrolchTransaction tx, T element) {
|
||||
if (realm.isVersioningEnabled())
|
||||
Version.updateVersionFor(element, tx.getCertificate().getUsername(), true);
|
||||
else
|
||||
Version.setInitialVersionFor(element, tx.getCertificate().getUsername());
|
||||
|
||||
if (this.realm.isVersioningEnabled()) {
|
||||
|
||||
// first perform cached change
|
||||
getCachedDao().update(element);
|
||||
// last is to perform DB changes
|
||||
getDbDao(tx).update(element);
|
||||
|
||||
} else {
|
||||
|
||||
// first perform cached change
|
||||
getCachedDao().remove(element);
|
||||
// last is to perform DB changes
|
||||
getDbDao(tx).remove(element);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void removeAll(StrolchTransaction tx, List<T> elements) {
|
||||
// first perform cached change
|
||||
getCachedDao().removeAll(elements);
|
||||
// last is to perform DB changes
|
||||
getDbDao(tx).removeAll(elements);
|
||||
for (T t : elements) {
|
||||
if (realm.isVersioningEnabled())
|
||||
Version.updateVersionFor(t, tx.getCertificate().getUsername(), true);
|
||||
else
|
||||
Version.setInitialVersionFor(t, tx.getCertificate().getUsername());
|
||||
}
|
||||
|
||||
if (this.realm.isVersioningEnabled()) {
|
||||
|
||||
// first perform cached change
|
||||
getCachedDao().updateAll(elements);
|
||||
// last is to perform DB changes
|
||||
getDbDao(tx).updateAll(elements);
|
||||
|
||||
} else {
|
||||
|
||||
// first perform cached change
|
||||
getCachedDao().removeAll(elements);
|
||||
// last is to perform DB changes
|
||||
getDbDao(tx).removeAll(elements);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -232,4 +345,63 @@ public abstract class CachedElementMap<T extends StrolchRootElement> implements
|
|||
|
||||
return removed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T revertToVersion(StrolchTransaction tx, T element) throws StrolchException {
|
||||
return revertToVersion(tx, element.getType(), element.getId(), element.getVersion().getVersion());
|
||||
}
|
||||
|
||||
@Override
|
||||
public T revertToVersion(StrolchTransaction tx, String type, String id, int version) throws StrolchException {
|
||||
if (!this.realm.isVersioningEnabled()) {
|
||||
throw new StrolchPersistenceException("Can not und a version if versioning is not enabled!");
|
||||
}
|
||||
|
||||
// get the current and specified version
|
||||
T current = getBy(tx, type, id, true);
|
||||
T versionT = getBy(tx, type, id, version, true);
|
||||
|
||||
// create the new version
|
||||
@SuppressWarnings("unchecked")
|
||||
T clone = (T) versionT.getClone();
|
||||
clone.setVersion(current.getVersion().next(tx.getCertificate().getUsername(), false));
|
||||
|
||||
// save the new version
|
||||
getCachedDao().update(clone);
|
||||
getDbDao(tx).update(clone);
|
||||
|
||||
// and return new version
|
||||
return clone;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void undoVersion(StrolchTransaction tx, T element) throws StrolchException {
|
||||
if (!this.realm.isVersioningEnabled()) {
|
||||
throw new StrolchPersistenceException("Can not und a version if versioning is not enabled!");
|
||||
}
|
||||
|
||||
String type = element.getType();
|
||||
String id = element.getId();
|
||||
|
||||
Version elementVersion = element.getVersion();
|
||||
|
||||
// make sure the given element is the latest version
|
||||
T current = getBy(tx, type, id, true);
|
||||
if (!current.getVersion().equals(elementVersion)) {
|
||||
String msg = "Can not undo the version {0} as it is not the latest!"; //$NON-NLS-1$
|
||||
msg = MessageFormat.format(msg, elementVersion);
|
||||
throw new StrolchException(msg);
|
||||
}
|
||||
|
||||
if (elementVersion.isFirstVersion()) {
|
||||
getCachedDao().remove(element);
|
||||
getDbDao(tx).remove(element);
|
||||
} else {
|
||||
T previous = getBy(tx, type, id, elementVersion.getPreviousVersion(), false);
|
||||
getCachedDao().update(previous);
|
||||
getDbDao(tx).removeVersion(current);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void assertIsRefParam(Parameter<?> refP);
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ import static li.strolch.model.StrolchModelConstants.INTERPRETATION_ORDER_REF;
|
|||
import java.util.List;
|
||||
|
||||
import li.strolch.agent.api.OrderMap;
|
||||
import li.strolch.agent.api.StrolchRealm;
|
||||
import li.strolch.model.Order;
|
||||
import li.strolch.model.parameter.Parameter;
|
||||
import li.strolch.model.query.OrderQuery;
|
||||
|
@ -31,9 +32,10 @@ public class CachedOrderMap extends CachedElementMap<Order> implements OrderMap
|
|||
|
||||
private OrderDao cachedDao;
|
||||
|
||||
public CachedOrderMap() {
|
||||
super();
|
||||
this.cachedDao = new InMemoryOrderDao();
|
||||
public CachedOrderMap(StrolchRealm realm) {
|
||||
super(realm);
|
||||
// the cached DAO should not have versioning enabled
|
||||
this.cachedDao = new InMemoryOrderDao(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -95,17 +95,14 @@ public class CachedRealm extends InternalStrolchRealm {
|
|||
super.initialize(container, configuration);
|
||||
|
||||
this.persistenceHandler = container.getComponent(PersistenceHandler.class);
|
||||
this.resourceMap = new CachedResourceMap();
|
||||
this.orderMap = new CachedOrderMap();
|
||||
this.activityMap = new CachedActivityMap();
|
||||
this.resourceMap = new CachedResourceMap(this);
|
||||
this.orderMap = new CachedOrderMap(this);
|
||||
this.activityMap = new CachedActivityMap(this);
|
||||
|
||||
if (isAuditTrailEnabled()) {
|
||||
if (isAuditTrailEnabled())
|
||||
this.auditTrail = new CachedAuditTrail();
|
||||
logger.info("Enabling AuditTrail for realm " + getRealm()); //$NON-NLS-1$
|
||||
} else {
|
||||
else
|
||||
this.auditTrail = new NoStrategyAuditTrail();
|
||||
logger.info("AuditTrail is disabled for realm " + getRealm()); //$NON-NLS-1$
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -20,6 +20,7 @@ import static li.strolch.model.StrolchModelConstants.INTERPRETATION_RESOURCE_REF
|
|||
import java.util.List;
|
||||
|
||||
import li.strolch.agent.api.ResourceMap;
|
||||
import li.strolch.agent.api.StrolchRealm;
|
||||
import li.strolch.model.Resource;
|
||||
import li.strolch.model.parameter.Parameter;
|
||||
import li.strolch.model.query.ResourceQuery;
|
||||
|
@ -31,9 +32,10 @@ public class CachedResourceMap extends CachedElementMap<Resource> implements Res
|
|||
|
||||
private ResourceDao cachedDao;
|
||||
|
||||
public CachedResourceMap() {
|
||||
super();
|
||||
this.cachedDao = new InMemoryResourceDao();
|
||||
public CachedResourceMap(StrolchRealm realm) {
|
||||
super(realm);
|
||||
// the cached DAO should not have versioning enabled
|
||||
this.cachedDao = new InMemoryResourceDao(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -39,6 +39,7 @@ public class DefaultRealmHandler extends StrolchComponent implements RealmHandle
|
|||
public static final String PROP_ENABLE_AUDIT_TRAIL = "enableAuditTrail"; //$NON-NLS-1$
|
||||
public static final String PROP_ENABLE_AUDIT_TRAIL_FOR_READ = "enableAuditTrailForRead"; //$NON-NLS-1$
|
||||
public static final String PROP_ENABLE_OBSERVER_UPDATES = "enableObserverUpdates"; //$NON-NLS-1$
|
||||
public static final String PROP_ENABLE_VERSIONING = "enableVersioning"; //$NON-NLS-1$
|
||||
public static final String PREFIX_DATA_STORE_MODE = "dataStoreMode"; //$NON-NLS-1$
|
||||
public static final String PREFIX_DATA_STORE_FILE = "dataStoreFile"; //$NON-NLS-1$
|
||||
public static final String PROP_REALMS = "realms"; //$NON-NLS-1$
|
||||
|
@ -76,9 +77,11 @@ public class DefaultRealmHandler extends StrolchComponent implements RealmHandle
|
|||
this.realms = new HashMap<>();
|
||||
String[] realms = configuration.getStringArray(PROP_REALMS, StrolchConstants.DEFAULT_REALM);
|
||||
for (String realmName : realms) {
|
||||
|
||||
String dataStoreModeKey = StrolchConstants.makeRealmKey(realmName, PREFIX_DATA_STORE_MODE);
|
||||
String realmMode = configuration.getString(dataStoreModeKey, null);
|
||||
DataStoreMode dataStoreMode = DataStoreMode.parseDataStoreMode(realmMode);
|
||||
|
||||
InternalStrolchRealm realm = dataStoreMode.createRealm(realmName);
|
||||
this.realms.put(realmName, realm);
|
||||
}
|
||||
|
|
|
@ -27,7 +27,6 @@ import li.strolch.persistence.api.StrolchTransaction;
|
|||
import li.strolch.persistence.inmemory.InMemoryPersistence;
|
||||
import li.strolch.privilege.model.Certificate;
|
||||
import li.strolch.privilege.model.PrivilegeContext;
|
||||
import li.strolch.runtime.StrolchConstants;
|
||||
import li.strolch.runtime.configuration.ComponentConfiguration;
|
||||
import li.strolch.utils.dbc.DBC;
|
||||
|
||||
|
@ -86,18 +85,15 @@ public class EmptyRealm extends InternalStrolchRealm {
|
|||
@Override
|
||||
public void initialize(ComponentContainer container, ComponentConfiguration configuration) {
|
||||
super.initialize(container, configuration);
|
||||
this.persistenceHandler = new InMemoryPersistence(container.getPrivilegeHandler());
|
||||
this.resourceMap = new TransactionalResourceMap();
|
||||
this.orderMap = new TransactionalOrderMap();
|
||||
this.persistenceHandler = new InMemoryPersistence(container.getPrivilegeHandler(), isVersioningEnabled());
|
||||
this.resourceMap = new TransactionalResourceMap(this);
|
||||
this.orderMap = new TransactionalOrderMap(this);
|
||||
this.activityMap = new TransactionalActivityMap(this);
|
||||
|
||||
String enableAuditKey = StrolchConstants.makeRealmKey(getRealm(), DefaultRealmHandler.PROP_ENABLE_AUDIT_TRAIL);
|
||||
if (configuration.getBoolean(enableAuditKey, Boolean.FALSE)) {
|
||||
if (isAuditTrailEnabled())
|
||||
this.auditTrail = new TransactionalAuditTrail();
|
||||
logger.info("Enabling AuditTrail for realm " + getRealm()); //$NON-NLS-1$
|
||||
} else {
|
||||
else
|
||||
this.auditTrail = new NoStrategyAuditTrail();
|
||||
logger.info("AuditTrail is disabled for realm " + getRealm()); //$NON-NLS-1$
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -15,9 +15,17 @@
|
|||
*/
|
||||
package li.strolch.agent.impl;
|
||||
|
||||
import static li.strolch.agent.impl.DefaultRealmHandler.PROP_ENABLE_AUDIT_TRAIL;
|
||||
import static li.strolch.agent.impl.DefaultRealmHandler.PROP_ENABLE_AUDIT_TRAIL_FOR_READ;
|
||||
import static li.strolch.agent.impl.DefaultRealmHandler.PROP_ENABLE_OBSERVER_UPDATES;
|
||||
import static li.strolch.agent.impl.DefaultRealmHandler.PROP_ENABLE_VERSIONING;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import li.strolch.agent.api.ActivityMap;
|
||||
import li.strolch.agent.api.AuditTrail;
|
||||
import li.strolch.agent.api.ComponentContainer;
|
||||
|
@ -32,9 +40,6 @@ import li.strolch.runtime.StrolchConstants;
|
|||
import li.strolch.runtime.configuration.ComponentConfiguration;
|
||||
import li.strolch.utils.dbc.DBC;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||
*/
|
||||
|
@ -47,6 +52,7 @@ public abstract class InternalStrolchRealm implements StrolchRealm {
|
|||
private LockHandler lockHandler;
|
||||
private boolean auditTrailEnabled;
|
||||
private boolean auditTrailEnabledForRead;
|
||||
private boolean versioningEnabled;
|
||||
private boolean updateObservers;
|
||||
private ObserverHandler observerHandler;
|
||||
|
||||
|
@ -78,26 +84,51 @@ public abstract class InternalStrolchRealm implements StrolchRealm {
|
|||
|
||||
public void initialize(ComponentContainer container, ComponentConfiguration configuration) {
|
||||
|
||||
String propTryLockTimeUnit = StrolchConstants.makeRealmKey(this.realm, PROP_TRY_LOCK_TIME_UNIT);
|
||||
String propTryLockTime = StrolchConstants.makeRealmKey(this.realm, PROP_TRY_LOCK_TIME);
|
||||
logger.info("Initializing Realm " + getRealm() + "...");
|
||||
|
||||
String enableAuditKey = StrolchConstants.makeRealmKey(getRealm(), DefaultRealmHandler.PROP_ENABLE_AUDIT_TRAIL);
|
||||
// audits
|
||||
String enableAuditKey = StrolchConstants.makeRealmKey(getRealm(), PROP_ENABLE_AUDIT_TRAIL);
|
||||
this.auditTrailEnabled = configuration.getBoolean(enableAuditKey, Boolean.FALSE);
|
||||
|
||||
String enableAuditForReadKey = StrolchConstants.makeRealmKey(getRealm(),
|
||||
DefaultRealmHandler.PROP_ENABLE_AUDIT_TRAIL_FOR_READ);
|
||||
// audits for read
|
||||
String enableAuditForReadKey = StrolchConstants.makeRealmKey(getRealm(), PROP_ENABLE_AUDIT_TRAIL_FOR_READ);
|
||||
this.auditTrailEnabledForRead = configuration.getBoolean(enableAuditForReadKey, Boolean.FALSE);
|
||||
|
||||
String updateObserversKey = StrolchConstants.makeRealmKey(getRealm(),
|
||||
DefaultRealmHandler.PROP_ENABLE_OBSERVER_UPDATES);
|
||||
// observer updates
|
||||
String updateObserversKey = StrolchConstants.makeRealmKey(getRealm(), PROP_ENABLE_OBSERVER_UPDATES);
|
||||
this.updateObservers = configuration.getBoolean(updateObserversKey, Boolean.FALSE);
|
||||
if (this.updateObservers)
|
||||
this.observerHandler = new DefaultObserverHandler();
|
||||
|
||||
// lock timeout
|
||||
String propTryLockTimeUnit = StrolchConstants.makeRealmKey(this.realm, PROP_TRY_LOCK_TIME_UNIT);
|
||||
String propTryLockTime = StrolchConstants.makeRealmKey(this.realm, PROP_TRY_LOCK_TIME);
|
||||
TimeUnit timeUnit = TimeUnit.valueOf(configuration.getString(propTryLockTimeUnit, TimeUnit.SECONDS.name()));
|
||||
long time = configuration.getLong(propTryLockTime, 10);
|
||||
logger.info(MessageFormat.format("Using a locking try timeout of {0}s", timeUnit.toSeconds(time))); //$NON-NLS-1$
|
||||
this.lockHandler = new DefaultLockHandler(this.realm, timeUnit, time);
|
||||
|
||||
// versioning
|
||||
String enableVersioningKey = StrolchConstants.makeRealmKey(getRealm(), PROP_ENABLE_VERSIONING);
|
||||
this.versioningEnabled = configuration.getBoolean(enableVersioningKey, Boolean.FALSE);
|
||||
|
||||
if (this.auditTrailEnabled)
|
||||
logger.info("Enabling AuditTrail for realm " + getRealm()); //$NON-NLS-1$
|
||||
else
|
||||
logger.info("AuditTrail not enabled for realm " + getRealm()); //$NON-NLS-1$
|
||||
if (this.auditTrailEnabledForRead)
|
||||
logger.info("Enabling AuditTrail for read for realm " + getRealm()); //$NON-NLS-1$
|
||||
else
|
||||
logger.info("AuditTrail not enabled for read for realm " + getRealm()); //$NON-NLS-1$
|
||||
if (this.updateObservers)
|
||||
logger.info("Enabling Observer Updates for realm " + getRealm()); //$NON-NLS-1$
|
||||
else
|
||||
logger.info("Observer Updates not enabled for realm " + getRealm()); //$NON-NLS-1$
|
||||
if (this.versioningEnabled)
|
||||
logger.info("Enabling Versioning for realm " + getRealm()); //$NON-NLS-1$
|
||||
else
|
||||
logger.info("Versioning not enabled for realm " + getRealm()); //$NON-NLS-1$
|
||||
|
||||
logger.info(MessageFormat.format("Using a locking try timeout of {0}s", timeUnit.toSeconds(time))); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -115,6 +146,11 @@ public abstract class InternalStrolchRealm implements StrolchRealm {
|
|||
return this.updateObservers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVersioningEnabled() {
|
||||
return this.versioningEnabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObserverHandler getObserverHandler() {
|
||||
if (!this.updateObservers)
|
||||
|
|
|
@ -20,6 +20,7 @@ import static li.strolch.model.StrolchModelConstants.INTERPRETATION_ACTIVITY_REF
|
|||
import java.util.List;
|
||||
|
||||
import li.strolch.agent.api.ActivityMap;
|
||||
import li.strolch.agent.api.StrolchRealm;
|
||||
import li.strolch.model.activity.Activity;
|
||||
import li.strolch.model.parameter.Parameter;
|
||||
import li.strolch.model.query.ActivityQuery;
|
||||
|
@ -28,6 +29,10 @@ import li.strolch.persistence.api.StrolchTransaction;
|
|||
|
||||
public class TransactionalActivityMap extends TransactionalElementMap<Activity> implements ActivityMap {
|
||||
|
||||
public TransactionalActivityMap(StrolchRealm realm) {
|
||||
super(realm);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void assertIsRefParam(Parameter<?> refP) {
|
||||
ElementMapHelpers.assertIsRefParam(INTERPRETATION_ACTIVITY_REF, refP);
|
||||
|
|
|
@ -63,7 +63,7 @@ public class TransactionalAuditTrail implements AuditTrail {
|
|||
public Audit getBy(StrolchTransaction tx, String type, Long id) {
|
||||
return getDao(tx).queryBy(type, id);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<Audit> getAllElements(StrolchTransaction tx, String type, DateRange dateRange) {
|
||||
return getDao(tx).queryAll(type, dateRange);
|
||||
|
|
|
@ -16,17 +16,21 @@
|
|||
package li.strolch.agent.impl;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import li.strolch.agent.api.ElementMap;
|
||||
import li.strolch.agent.api.StrolchRealm;
|
||||
import li.strolch.exception.StrolchException;
|
||||
import li.strolch.model.StrolchRootElement;
|
||||
import li.strolch.model.Version;
|
||||
import li.strolch.model.parameter.Parameter;
|
||||
import li.strolch.model.parameter.StringListParameter;
|
||||
import li.strolch.model.parameter.StringParameter;
|
||||
import li.strolch.persistence.api.StrolchDao;
|
||||
import li.strolch.persistence.api.StrolchPersistenceException;
|
||||
import li.strolch.persistence.api.StrolchTransaction;
|
||||
import li.strolch.runtime.StrolchConstants;
|
||||
|
||||
|
@ -37,6 +41,16 @@ import li.strolch.runtime.StrolchConstants;
|
|||
*/
|
||||
public abstract class TransactionalElementMap<T extends StrolchRootElement> implements ElementMap<T> {
|
||||
|
||||
private StrolchRealm realm;
|
||||
|
||||
public TransactionalElementMap(StrolchRealm realm) {
|
||||
this.realm = realm;
|
||||
}
|
||||
|
||||
protected StrolchRealm getRealm() {
|
||||
return this.realm;
|
||||
}
|
||||
|
||||
protected abstract StrolchDao<T> getDao(StrolchTransaction tx);
|
||||
|
||||
@Override
|
||||
|
@ -61,62 +75,160 @@ public abstract class TransactionalElementMap<T extends StrolchRootElement> impl
|
|||
|
||||
@Override
|
||||
public T getTemplate(StrolchTransaction tx, String type) {
|
||||
return getBy(tx, StrolchConstants.TEMPLATE, type);
|
||||
return getTemplate(tx, type, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T getTemplate(StrolchTransaction tx, String type, boolean assertExists) throws StrolchException {
|
||||
T t = getBy(tx, StrolchConstants.TEMPLATE, type);
|
||||
if (assertExists && t == null) {
|
||||
String msg = "The template for type {0} does not exist!"; //$NON-NLS-1$
|
||||
msg = MessageFormat.format(msg, type);
|
||||
throw new StrolchException(msg);
|
||||
}
|
||||
|
||||
if (t == null)
|
||||
return null;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
T clone = (T) t.getClone();
|
||||
clone.setVersion(t.getVersion());
|
||||
return clone;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T getBy(StrolchTransaction tx, String type, String id) {
|
||||
return getDao(tx).queryBy(type, id);
|
||||
return getBy(tx, type, id, false);
|
||||
}
|
||||
|
||||
protected abstract void assertIsRefParam(Parameter<?> refP);
|
||||
@Override
|
||||
public T getBy(StrolchTransaction tx, String type, String id, boolean assertExists) throws StrolchException {
|
||||
T t = getDao(tx).queryBy(type, id);
|
||||
if (assertExists && t == null) {
|
||||
String msg = "The element for type {0} and id {1} does not exist!"; //$NON-NLS-1$
|
||||
msg = MessageFormat.format(msg, type, id);
|
||||
throw new StrolchException(msg);
|
||||
}
|
||||
|
||||
if (t == null)
|
||||
return null;
|
||||
|
||||
if (!this.realm.getMode().isTransient())
|
||||
return t;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
T clone = (T) t.getClone();
|
||||
clone.setVersion(t.getVersion());
|
||||
return clone;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T getBy(StrolchTransaction tx, String type, String id, int version) {
|
||||
return getBy(tx, type, id, version, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T getBy(StrolchTransaction tx, String type, String id, int version, boolean assertExists)
|
||||
throws StrolchException {
|
||||
T t = getDao(tx).queryBy(type, id, version);
|
||||
if (assertExists && t == null) {
|
||||
String msg = "The element for type {0} and id {1} and version {2} does not exist!"; //$NON-NLS-1$
|
||||
msg = MessageFormat.format(msg, type, id, version);
|
||||
throw new StrolchException(msg);
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T getBy(StrolchTransaction tx, StringParameter refP, boolean assertExists) throws StrolchException {
|
||||
assertIsRefParam(refP);
|
||||
String type = refP.getUom();
|
||||
String id = refP.getValue();
|
||||
T element = getBy(tx, type, id);
|
||||
if (assertExists && element == null) {
|
||||
T t = getBy(tx, type, id);
|
||||
if (assertExists && t == null) {
|
||||
String msg = "The element for refP {0} with id {1} does not exist!"; //$NON-NLS-1$
|
||||
msg = MessageFormat.format(msg, refP.getLocator(), id);
|
||||
throw new StrolchException(msg);
|
||||
}
|
||||
return element;
|
||||
|
||||
if (t == null)
|
||||
return null;
|
||||
|
||||
if (!this.realm.getMode().isTransient())
|
||||
return t;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
T clone = (T) t.getClone();
|
||||
clone.setVersion(t.getVersion());
|
||||
return clone;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<T> getBy(StrolchTransaction tx, StringListParameter refP, boolean assertExists) throws StrolchException {
|
||||
public List<T> getBy(StrolchTransaction tx, StringListParameter refP, boolean assertExists)
|
||||
throws StrolchException {
|
||||
assertIsRefParam(refP);
|
||||
|
||||
List<T> elements = new ArrayList<>();
|
||||
String type = refP.getUom();
|
||||
List<String> ids = refP.getValue();
|
||||
|
||||
for (String id : ids) {
|
||||
T element = getBy(tx, type, id);
|
||||
if (element != null) {
|
||||
elements.add(element);
|
||||
} else if (assertExists) {
|
||||
if (assertExists && element == null) {
|
||||
String msg = "The element for refP {0} with id {1} does not exist!"; //$NON-NLS-1$
|
||||
msg = MessageFormat.format(msg, refP.getLocator(), id);
|
||||
throw new StrolchException(msg);
|
||||
}
|
||||
return ids.stream().map(id -> {
|
||||
T t = getBy(tx, type, id);
|
||||
if (assertExists && t == null) {
|
||||
String msg = "The element for refP {0} with id {1} does not exist!"; //$NON-NLS-1$
|
||||
msg = MessageFormat.format(msg, refP.getLocator(), id);
|
||||
throw new StrolchException(msg);
|
||||
}
|
||||
}
|
||||
return t;
|
||||
}).filter(Objects::nonNull).map(t -> {
|
||||
if (!this.realm.getMode().isTransient()) {
|
||||
return t;
|
||||
} else {
|
||||
@SuppressWarnings("unchecked")
|
||||
T clone = (T) t.getClone();
|
||||
clone.setVersion(t.getVersion());
|
||||
return clone;
|
||||
}
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
return elements;
|
||||
@Override
|
||||
public List<T> getVersionsFor(StrolchTransaction tx, String type, String id) {
|
||||
return getDao(tx).queryVersionsFor(type, id).stream().map(t -> {
|
||||
@SuppressWarnings("unchecked")
|
||||
T clone = (T) t.getClone();
|
||||
clone.setVersion(t.getVersion());
|
||||
return clone;
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<T> getAllElements(StrolchTransaction tx) {
|
||||
return getDao(tx).queryAll();
|
||||
List<T> all = getDao(tx).queryAll();
|
||||
|
||||
if (this.realm.getMode().isTransient())
|
||||
return all;
|
||||
|
||||
return all.stream().map(t -> {
|
||||
@SuppressWarnings("unchecked")
|
||||
T clone = (T) t.getClone();
|
||||
clone.setVersion(t.getVersion());
|
||||
return clone;
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<T> getElementsBy(StrolchTransaction tx, String type) {
|
||||
return getDao(tx).queryAll(type);
|
||||
List<T> all = getDao(tx).queryAll(type);
|
||||
|
||||
if (this.realm.getMode().isTransient())
|
||||
return all;
|
||||
|
||||
return all.stream().map(t -> {
|
||||
@SuppressWarnings("unchecked")
|
||||
T clone = (T) t.getClone();
|
||||
clone.setVersion(t.getVersion());
|
||||
return clone;
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -136,34 +248,73 @@ public abstract class TransactionalElementMap<T extends StrolchRootElement> impl
|
|||
|
||||
@Override
|
||||
public void add(StrolchTransaction tx, T element) {
|
||||
if (realm.isVersioningEnabled())
|
||||
Version.updateVersionFor(element, tx.getCertificate().getUsername(), false);
|
||||
else
|
||||
Version.setInitialVersionFor(element, tx.getCertificate().getUsername());
|
||||
|
||||
getDao(tx).save(element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T update(StrolchTransaction tx, T element) {
|
||||
getDao(tx).update(element);
|
||||
return element;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(StrolchTransaction tx, T element) {
|
||||
getDao(tx).remove(element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addAll(StrolchTransaction tx, List<T> elements) {
|
||||
for (T element : elements) {
|
||||
if (realm.isVersioningEnabled())
|
||||
Version.updateVersionFor(element, tx.getCertificate().getUsername(), false);
|
||||
else
|
||||
Version.setInitialVersionFor(element, tx.getCertificate().getUsername());
|
||||
}
|
||||
|
||||
getDao(tx).saveAll(elements);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<T> updateAll(StrolchTransaction tx, List<T> elements) {
|
||||
public void update(StrolchTransaction tx, T element) {
|
||||
if (realm.isVersioningEnabled())
|
||||
Version.updateVersionFor(element, tx.getCertificate().getUsername(), false);
|
||||
else
|
||||
Version.setInitialVersionFor(element, tx.getCertificate().getUsername());
|
||||
|
||||
getDao(tx).update(element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateAll(StrolchTransaction tx, List<T> elements) {
|
||||
for (T element : elements) {
|
||||
if (realm.isVersioningEnabled())
|
||||
Version.updateVersionFor(element, tx.getCertificate().getUsername(), false);
|
||||
else
|
||||
Version.setInitialVersionFor(element, tx.getCertificate().getUsername());
|
||||
}
|
||||
|
||||
getDao(tx).updateAll(elements);
|
||||
return elements;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(StrolchTransaction tx, T element) {
|
||||
if (this.realm.isVersioningEnabled()) {
|
||||
Version.updateVersionFor(element, tx.getCertificate().getUsername(), true);
|
||||
getDao(tx).update(element);
|
||||
} else {
|
||||
Version.setInitialVersionFor(element, tx.getCertificate().getUsername());
|
||||
getDao(tx).remove(element);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAll(StrolchTransaction tx, List<T> elements) {
|
||||
getDao(tx).removeAll(elements);
|
||||
for (T element : elements) {
|
||||
if (realm.isVersioningEnabled())
|
||||
Version.updateVersionFor(element, tx.getCertificate().getUsername(), true);
|
||||
else
|
||||
Version.setInitialVersionFor(element, tx.getCertificate().getUsername());
|
||||
}
|
||||
|
||||
if (this.realm.isVersioningEnabled()) {
|
||||
getDao(tx).updateAll(elements);
|
||||
} else {
|
||||
getDao(tx).removeAll(elements);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -175,4 +326,50 @@ public abstract class TransactionalElementMap<T extends StrolchRootElement> impl
|
|||
public long removeAllBy(StrolchTransaction tx, String type) {
|
||||
return getDao(tx).removeAllBy(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T revertToVersion(StrolchTransaction tx, T element) throws StrolchException {
|
||||
return revertToVersion(tx, element.getType(), element.getId(), element.getVersion().getVersion());
|
||||
}
|
||||
|
||||
@Override
|
||||
public T revertToVersion(StrolchTransaction tx, String type, String id, int version) throws StrolchException {
|
||||
if (!this.realm.isVersioningEnabled()) {
|
||||
throw new StrolchPersistenceException("Can not revert to a version if versioning is not enabled!");
|
||||
}
|
||||
|
||||
// get the current and specified version
|
||||
T current = getBy(tx, type, id, true);
|
||||
T versionT = getBy(tx, type, id, version, true);
|
||||
|
||||
// create the new version
|
||||
@SuppressWarnings("unchecked")
|
||||
T clone = (T) versionT.getClone();
|
||||
clone.setVersion(current.getVersion().next(tx.getCertificate().getUsername(), false));
|
||||
|
||||
// save the new version
|
||||
getDao(tx).update(clone);
|
||||
|
||||
// and return new version
|
||||
return clone;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void undoVersion(StrolchTransaction tx, T element) throws StrolchException {
|
||||
if (!this.realm.isVersioningEnabled()) {
|
||||
throw new StrolchPersistenceException("Can not undo a version if versioning is not enabled!");
|
||||
}
|
||||
|
||||
// make sure the given element is the latest version
|
||||
T current = getBy(tx, element.getType(), element.getId(), true);
|
||||
if (!current.getVersion().equals(element.getVersion())) {
|
||||
String msg = "Can not undo the version {0} as it is not the latest {1}!"; //$NON-NLS-1$
|
||||
msg = MessageFormat.format(msg, element.getVersion(), current.getVersion());
|
||||
throw new StrolchException(msg);
|
||||
}
|
||||
|
||||
getDao(tx).removeVersion(current);
|
||||
}
|
||||
|
||||
protected abstract void assertIsRefParam(Parameter<?> refP);
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ import static li.strolch.model.StrolchModelConstants.INTERPRETATION_ORDER_REF;
|
|||
import java.util.List;
|
||||
|
||||
import li.strolch.agent.api.OrderMap;
|
||||
import li.strolch.agent.api.StrolchRealm;
|
||||
import li.strolch.model.Order;
|
||||
import li.strolch.model.parameter.Parameter;
|
||||
import li.strolch.model.query.OrderQuery;
|
||||
|
@ -28,6 +29,10 @@ import li.strolch.persistence.api.StrolchTransaction;
|
|||
|
||||
public class TransactionalOrderMap extends TransactionalElementMap<Order> implements OrderMap {
|
||||
|
||||
public TransactionalOrderMap(StrolchRealm realm) {
|
||||
super(realm);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void assertIsRefParam(Parameter<?> refP) {
|
||||
ElementMapHelpers.assertIsRefParam(INTERPRETATION_ORDER_REF, refP);
|
||||
|
|
|
@ -85,16 +85,14 @@ public class TransactionalRealm extends InternalStrolchRealm {
|
|||
@Override
|
||||
public void initialize(ComponentContainer container, ComponentConfiguration configuration) {
|
||||
super.initialize(container, configuration);
|
||||
this.resourceMap = new TransactionalResourceMap();
|
||||
this.orderMap = new TransactionalOrderMap();
|
||||
this.activityMap = new TransactionalActivityMap();
|
||||
this.resourceMap = new TransactionalResourceMap(this);
|
||||
this.orderMap = new TransactionalOrderMap(this);
|
||||
this.activityMap = new TransactionalActivityMap(this);
|
||||
|
||||
if (isAuditTrailEnabled()) {
|
||||
this.auditTrail = new TransactionalAuditTrail();
|
||||
logger.info("Enabling AuditTrail for realm " + getRealm()); //$NON-NLS-1$
|
||||
} else {
|
||||
this.auditTrail = new NoStrategyAuditTrail();
|
||||
logger.info("AuditTrail is disabled for realm " + getRealm()); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
this.persistenceHandler = container.getComponent(PersistenceHandler.class);
|
||||
|
@ -122,8 +120,8 @@ public class TransactionalRealm extends InternalStrolchRealm {
|
|||
|
||||
long duration = System.nanoTime() - start;
|
||||
String durationS = StringHelper.formatNanoDuration(duration);
|
||||
logger.info(MessageFormat.format(
|
||||
"Initialized Transactional Maps for realm {0} took {1}.", getRealm(), durationS)); //$NON-NLS-1$
|
||||
logger.info(
|
||||
MessageFormat.format("Initialized Transactional Maps for realm {0} took {1}.", getRealm(), durationS)); //$NON-NLS-1$
|
||||
logger.info(MessageFormat.format("There are {0} Orders", nrOfOrders)); //$NON-NLS-1$
|
||||
logger.info(MessageFormat.format("There are {0} Resources", nrOfResources)); //$NON-NLS-1$
|
||||
logger.info(MessageFormat.format("There are {0} Activities", nrOfActivities)); //$NON-NLS-1$
|
||||
|
|
|
@ -20,6 +20,7 @@ import static li.strolch.model.StrolchModelConstants.INTERPRETATION_RESOURCE_REF
|
|||
import java.util.List;
|
||||
|
||||
import li.strolch.agent.api.ResourceMap;
|
||||
import li.strolch.agent.api.StrolchRealm;
|
||||
import li.strolch.model.Resource;
|
||||
import li.strolch.model.parameter.Parameter;
|
||||
import li.strolch.model.query.ResourceQuery;
|
||||
|
@ -28,6 +29,10 @@ import li.strolch.persistence.api.StrolchTransaction;
|
|||
|
||||
public class TransactionalResourceMap extends TransactionalElementMap<Resource> implements ResourceMap {
|
||||
|
||||
public TransactionalResourceMap(StrolchRealm realm) {
|
||||
super(realm);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void assertIsRefParam(Parameter<?> refP) {
|
||||
ElementMapHelpers.assertIsRefParam(INTERPRETATION_RESOURCE_REF, refP);
|
||||
|
|
|
@ -103,18 +103,15 @@ public class TransientRealm extends InternalStrolchRealm {
|
|||
|
||||
this.modelFile = configuration.getDataFile(key, null, configuration.getRuntimeConfiguration(), true);
|
||||
|
||||
this.persistenceHandler = new InMemoryPersistence(container.getPrivilegeHandler());
|
||||
this.resourceMap = new TransactionalResourceMap();
|
||||
this.orderMap = new TransactionalOrderMap();
|
||||
this.activityMap = new TransactionalActivityMap();
|
||||
this.persistenceHandler = new InMemoryPersistence(container.getPrivilegeHandler(), isVersioningEnabled());
|
||||
this.resourceMap = new TransactionalResourceMap(this);
|
||||
this.orderMap = new TransactionalOrderMap(this);
|
||||
this.activityMap = new TransactionalActivityMap(this);
|
||||
|
||||
if (isAuditTrailEnabled()) {
|
||||
if (isAuditTrailEnabled())
|
||||
this.auditTrail = new TransactionalAuditTrail();
|
||||
logger.info("Enabling AuditTrail for realm " + getRealm()); //$NON-NLS-1$
|
||||
} else {
|
||||
else
|
||||
this.auditTrail = new NoStrategyAuditTrail();
|
||||
logger.info("AuditTrail is disabled for realm " + getRealm()); //$NON-NLS-1$
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -49,7 +49,6 @@ import li.strolch.model.Resource;
|
|||
import li.strolch.model.StrolchElement;
|
||||
import li.strolch.model.StrolchRootElement;
|
||||
import li.strolch.model.Tags;
|
||||
import li.strolch.model.Version;
|
||||
import li.strolch.model.activity.Activity;
|
||||
import li.strolch.model.audit.AccessType;
|
||||
import li.strolch.model.audit.Audit;
|
||||
|
@ -67,7 +66,6 @@ import li.strolch.model.visitor.ElementTypeVisitor;
|
|||
import li.strolch.privilege.base.PrivilegeException;
|
||||
import li.strolch.privilege.model.Certificate;
|
||||
import li.strolch.privilege.model.PrivilegeContext;
|
||||
import li.strolch.runtime.StrolchConstants;
|
||||
import li.strolch.runtime.privilege.PrivilegeHandler;
|
||||
import li.strolch.service.api.Command;
|
||||
import li.strolch.utils.dbc.DBC;
|
||||
|
@ -86,7 +84,6 @@ public abstract class AbstractTransaction implements StrolchTransaction {
|
|||
private boolean suppressUpdates;
|
||||
private boolean suppressAudits;
|
||||
private boolean suppressDoNothingLogging;
|
||||
private boolean versioningEnabled;
|
||||
private TransactionResult txResult;
|
||||
|
||||
private List<Command> commands;
|
||||
|
@ -147,7 +144,7 @@ public abstract class AbstractTransaction implements StrolchTransaction {
|
|||
return this.realm.getRealm();
|
||||
}
|
||||
|
||||
protected StrolchRealm getRealm() {
|
||||
public StrolchRealm getRealm() {
|
||||
return this.realm;
|
||||
}
|
||||
|
||||
|
@ -211,16 +208,6 @@ public abstract class AbstractTransaction implements StrolchTransaction {
|
|||
return this.suppressAudits;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVersioningEnabled(boolean versioningEnabled) {
|
||||
this.versioningEnabled = versioningEnabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVersioningEnabled() {
|
||||
return this.versioningEnabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSuppressDoNothingLogging() {
|
||||
return suppressDoNothingLogging;
|
||||
|
@ -231,6 +218,11 @@ public abstract class AbstractTransaction implements StrolchTransaction {
|
|||
this.suppressDoNothingLogging = quietDoNothing;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVersioningEnabled() {
|
||||
return this.realm.isVersioningEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends StrolchRootElement> void lock(T element) throws StrolchLockException {
|
||||
this.realm.lock(element);
|
||||
|
@ -407,22 +399,22 @@ public abstract class AbstractTransaction implements StrolchTransaction {
|
|||
|
||||
@Override
|
||||
public Resource getResourceTemplate(String type) {
|
||||
return getResourceBy(StrolchConstants.TEMPLATE, type);
|
||||
return getResourceMap().getTemplate(this, type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Resource getResourceTemplate(String type, boolean assertExists) throws StrolchException {
|
||||
return getResourceBy(StrolchConstants.TEMPLATE, type, assertExists);
|
||||
return getResourceMap().getTemplate(this, type, assertExists);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Order getOrderTemplate(String type) {
|
||||
return getOrderBy(StrolchConstants.TEMPLATE, type);
|
||||
return getOrderMap().getTemplate(this, type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Order getOrderTemplate(String type, boolean assertExists) throws StrolchException {
|
||||
return getOrderBy(StrolchConstants.TEMPLATE, type, assertExists);
|
||||
return getOrderMap().getTemplate(this, type, assertExists);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -432,12 +424,7 @@ public abstract class AbstractTransaction implements StrolchTransaction {
|
|||
|
||||
@Override
|
||||
public Order getOrderBy(String type, String id, boolean assertExists) throws StrolchException {
|
||||
Order order = getOrderMap().getBy(this, type, id);
|
||||
if (assertExists && order == null) {
|
||||
String msg = "No Order exists with the id {0} with type {1}";
|
||||
throw new StrolchException(MessageFormat.format(msg, id, type));
|
||||
}
|
||||
return order;
|
||||
return getOrderMap().getBy(this, type, id, assertExists);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -580,21 +567,25 @@ public abstract class AbstractTransaction implements StrolchTransaction {
|
|||
|
||||
} catch (Exception e) {
|
||||
this.txResult.setState(TransactionState.ROLLING_BACK);
|
||||
|
||||
try {
|
||||
undoCommands();
|
||||
} catch (Exception e2) {
|
||||
} catch (Exception ex) {
|
||||
logger.error("Failed to commit transaction and then undo commands due to " + ex.getMessage(), ex);
|
||||
try {
|
||||
rollback(this.txResult);
|
||||
handleRollback(start);
|
||||
} catch (Exception e1) {
|
||||
logger.error("Failed to roll back after failing to undo commands: " + e1.getMessage(), e1); //$NON-NLS-1$
|
||||
} catch (Exception exc) {
|
||||
logger.error("Failed to roll back after failing to undo commands: " + exc.getMessage(), exc); //$NON-NLS-1$
|
||||
}
|
||||
handleFailure(start, e);
|
||||
handleFailure(start, ex);
|
||||
}
|
||||
|
||||
try {
|
||||
rollback(this.txResult);
|
||||
handleRollback(start);
|
||||
} catch (Exception e1) {
|
||||
} catch (Exception ex) {
|
||||
logger.error("Failed to commit transaction and then rollback due to " + ex.getMessage(), ex);
|
||||
handleFailure(start, e);
|
||||
}
|
||||
|
||||
|
@ -843,6 +834,8 @@ public abstract class AbstractTransaction implements StrolchTransaction {
|
|||
|
||||
List<Audit> audits = new ArrayList<>();
|
||||
|
||||
// this is bad... doesn't account for a created and deleted in same TX...
|
||||
|
||||
if (this.orderMap != null) {
|
||||
if (this.realm.isAuditTrailEnabledForRead())
|
||||
auditsFor(audits, AccessType.READ, Tags.ORDER, this.orderMap.getRead());
|
||||
|
@ -916,15 +909,6 @@ public abstract class AbstractTransaction implements StrolchTransaction {
|
|||
return audit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateVersionFor(StrolchRootElement element, boolean deleted) {
|
||||
if (this.versioningEnabled) {
|
||||
int v = element.getVersion() == null ? 0 : element.getVersion().getVersion() + 1;
|
||||
Version version = new Version(element.getLocator(), v, this.certificate.getUsername(), deleted);
|
||||
element.setVersion(version);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls {@link Command#validate()} on all registered command. This is done before we perform any commands and thus
|
||||
* no rollback needs be done due to invalid input for a command
|
||||
|
@ -943,8 +927,8 @@ public abstract class AbstractTransaction implements StrolchTransaction {
|
|||
ListIterator<Command> iter = this.commands.listIterator();
|
||||
while (iter.hasNext()) {
|
||||
Command command = iter.next();
|
||||
command.doCommand();
|
||||
this.flushedCommands.add(command);
|
||||
command.doCommand();
|
||||
iter.remove();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,41 +21,263 @@ import java.util.Set;
|
|||
import li.strolch.model.StrolchRootElement;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* This data access object is used to access {@link StrolchRootElement} from the underlying persistence layer. Objects
|
||||
* in Strolch are always referenced by a type and an ID. The type is a categorisation/grouping of the objects, while the
|
||||
* ID is a unique identifier of the object. The ID must be unique, even for multiple groups.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* The DAO must support versioning. i.e. if versioning is enabled, then if an object is updated or removed, the existing
|
||||
* version is not modified, but a new version is persisted so that rollbacks can be done
|
||||
* </p>
|
||||
*
|
||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||
*
|
||||
* @param <T>
|
||||
* the object instance being queried from the underlying persistence layer
|
||||
*/
|
||||
public interface StrolchDao<T extends StrolchRootElement> {
|
||||
|
||||
/**
|
||||
* Queries the set of IDs for all elements, regardless of types from the underlying persistence layer.
|
||||
*
|
||||
* @return the set of IDs for all elements
|
||||
*/
|
||||
public Set<String> queryKeySet();
|
||||
|
||||
/**
|
||||
* Returns true if an element exists with the given type and id in the underlying persistence layer
|
||||
*
|
||||
* @param type
|
||||
* the type of elements
|
||||
* @param id
|
||||
* the id of the element to return
|
||||
*
|
||||
* @return true if an element exists with the given type and id
|
||||
*/
|
||||
public boolean hasElement(String type, String id);
|
||||
|
||||
/**
|
||||
* Returns the number of elements in the underlying persistence layer, regardless of type
|
||||
*
|
||||
* @return the number of elements in the underlying persistence layer
|
||||
*/
|
||||
public long querySize();
|
||||
|
||||
/**
|
||||
* Returns the number of elements in the underlying persistence layer for the given type
|
||||
*
|
||||
* @return the number of elements in the underlying persistence layer for the given type
|
||||
*/
|
||||
public long querySize(String type);
|
||||
|
||||
/**
|
||||
* Queries the set of IDs for the elements with the given type
|
||||
*
|
||||
* @return the set of IDs for the elements with the given type
|
||||
*/
|
||||
public Set<String> queryKeySet(String type);
|
||||
|
||||
/**
|
||||
* Queries the current list of types from the underlying persistence layer
|
||||
*
|
||||
* @return the list of types
|
||||
*/
|
||||
public Set<String> queryTypes();
|
||||
|
||||
/**
|
||||
* Queries the latest version of the element with the given type and ID
|
||||
*
|
||||
* @param type
|
||||
* the type of the element to be queried
|
||||
* @param id
|
||||
* the id of the element to be queried
|
||||
*
|
||||
* @return the element with the given type and ID, or null if it does not exist
|
||||
*/
|
||||
public T queryBy(String type, String id);
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Queries a specific version of the element with the given type and ID.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* <b>Note:</b> If you want to query the latest version, then use the method with out the version parameter
|
||||
* </p>
|
||||
*
|
||||
* @param type
|
||||
* the type of the element to be queried
|
||||
* @param id
|
||||
* the id of the element to be queried
|
||||
* @param version
|
||||
* the version of the element to be returned
|
||||
*
|
||||
* @return the element with the given type and ID, or null if it does not exist
|
||||
*/
|
||||
public T queryBy(String type, String id, int version);
|
||||
|
||||
/**
|
||||
* Queries and returns all the versions of the element with the given type and ID
|
||||
*
|
||||
* @param type
|
||||
* the type of the element to be queried
|
||||
* @param id
|
||||
* the id of the element to be queried
|
||||
*
|
||||
* @return all the versions of the element with the given type and ID
|
||||
*/
|
||||
public List<T> queryVersionsFor(String type, String id);
|
||||
|
||||
/**
|
||||
* Queries and returns all elements regardless of type
|
||||
*
|
||||
* @return all elements regardless of type
|
||||
*/
|
||||
public List<T> queryAll();
|
||||
|
||||
/**
|
||||
* Queries and returns all elements of the given type
|
||||
*
|
||||
* @param type
|
||||
* the type of element to return
|
||||
*
|
||||
* @return all elements of the given type
|
||||
*/
|
||||
public List<T> queryAll(String type);
|
||||
|
||||
public void save(T element);
|
||||
/**
|
||||
* Persists the given element. The element must not yet exist
|
||||
*
|
||||
* @param element
|
||||
* the element to be persisted
|
||||
*
|
||||
* @throws StrolchPersistenceException
|
||||
* if the element already exists
|
||||
*/
|
||||
public void save(T element) throws StrolchPersistenceException;
|
||||
|
||||
public void saveAll(List<T> elements);
|
||||
/**
|
||||
* Persists the given list of elements. None of the elements may already exists
|
||||
*
|
||||
* @param elements
|
||||
* the list of elements to be persisted
|
||||
*
|
||||
* @throws StrolchPersistenceException
|
||||
* if any of the elements already exist
|
||||
*/
|
||||
public void saveAll(List<T> elements) throws StrolchPersistenceException;
|
||||
|
||||
public void update(T element);
|
||||
/**
|
||||
* Updates the given element. The element must already exist
|
||||
*
|
||||
* @param element
|
||||
* the element to be updated
|
||||
*
|
||||
* @throws StrolchPersistenceException
|
||||
* if the element does not exist
|
||||
*/
|
||||
public void update(T element) throws StrolchPersistenceException;
|
||||
|
||||
public void updateAll(List<T> elements);
|
||||
/**
|
||||
* Updates the given list of elements. Each element must already exist
|
||||
*
|
||||
* @param elements
|
||||
* the elements to be updated
|
||||
*
|
||||
* @throws StrolchPersistenceException
|
||||
* if any of the elements do not exist
|
||||
*/
|
||||
public void updateAll(List<T> elements) throws StrolchPersistenceException;
|
||||
|
||||
public void remove(T element);
|
||||
/**
|
||||
* <p>
|
||||
* Removes the given element from the underlying persistence layer
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* <b>Note:</b> This method deletes the given object including its versions! Do not call this method if you want to
|
||||
* use versioning!
|
||||
* </p>
|
||||
*
|
||||
* @param element
|
||||
* the element to be removed
|
||||
*
|
||||
* @throws StrolchPersistenceException
|
||||
* if the element does not exist
|
||||
*/
|
||||
public void remove(T element) throws StrolchPersistenceException;
|
||||
|
||||
public void removeAll(List<T> elements);
|
||||
/**
|
||||
* <p>
|
||||
* Removes the given elements from the underlying persistence layer
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* <b>Note:</b> This method deletes the given objects including their versions! Do not call this method if you want
|
||||
* to use versioning!
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* @param elements
|
||||
* the elements to be removed
|
||||
*
|
||||
* @throws StrolchPersistenceException
|
||||
* if any of the elements do not exist
|
||||
*/
|
||||
public void removeAll(List<T> elements) throws StrolchPersistenceException;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Removes all elements regardless of type from the underlying persistence layer
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* <b>Note:</b> This method does not support versioning. This method completely removes all objects regardless of
|
||||
* type and their versions!
|
||||
* </p>
|
||||
*
|
||||
* @return the number of elements removed
|
||||
*
|
||||
* @throws StrolchPersistenceException
|
||||
*/
|
||||
public long removeAll();
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Removes all elements of the given type from the underlying persistence layer
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* <b>Note:</b> This method does not support versioning. This method completely removes all objects of the given
|
||||
* type and their versions!
|
||||
* </p>
|
||||
*
|
||||
* @param type
|
||||
* the type of element to remove
|
||||
*
|
||||
* @return the number of elements removed
|
||||
*/
|
||||
public long removeAllBy(String type);
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Removes the given version of the given element from the underlying persistence layer. The version must be the
|
||||
* latest version and thus always deletes the newest version. To delete multiple versions call this method multiple
|
||||
* times. To remove it completely, call the {@link #remove(StrolchRootElement)} method.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* <b>Note:</b> This element given must be the current latest version!
|
||||
* </p>
|
||||
*
|
||||
* @param element
|
||||
* the latest version of the element to be removed
|
||||
*
|
||||
* @throws StrolchPersistenceException
|
||||
* if the element/version does not exist
|
||||
*/
|
||||
public void removeVersion(T element) throws StrolchPersistenceException;
|
||||
|
||||
}
|
||||
|
|
|
@ -279,19 +279,6 @@ public interface StrolchTransaction extends AutoCloseable {
|
|||
*/
|
||||
public boolean isSuppressAudits();
|
||||
|
||||
/**
|
||||
*
|
||||
* @param versioningEnabled
|
||||
*/
|
||||
public void setVersioningEnabled(boolean versioningEnabled);
|
||||
|
||||
/**
|
||||
* Returns true if versioning of objects is enabled
|
||||
*
|
||||
* @return true if versioning of objects is enabled
|
||||
*/
|
||||
public boolean isVersioningEnabled();
|
||||
|
||||
/**
|
||||
* If the given argument is true, then logging of a {@link TransactionCloseStrategy#DO_NOTHING} will be suppressed
|
||||
*
|
||||
|
@ -307,6 +294,13 @@ public interface StrolchTransaction extends AutoCloseable {
|
|||
*/
|
||||
boolean isSuppressDoNothingLogging();
|
||||
|
||||
/**
|
||||
* Returns true if versioning is enabled on the {@link StrolchRealm} for which this transaction has been opened
|
||||
*
|
||||
* @return true if versioning is enabled
|
||||
*/
|
||||
boolean isVersioningEnabled();
|
||||
|
||||
/**
|
||||
* Locks the given element and registers it on the transaction so the lock is released when the transaction is
|
||||
* closed
|
||||
|
@ -376,21 +370,6 @@ public interface StrolchTransaction extends AutoCloseable {
|
|||
*/
|
||||
public Audit auditFrom(AccessType accessType, StrolchRootElement element);
|
||||
|
||||
/**
|
||||
* Creates a new version for the given element. If the element has no version yet, then the result will be version
|
||||
* 0, otherwise the version will be an increment to the current version
|
||||
*
|
||||
* @param element
|
||||
* the element for which to create a new version
|
||||
* @param deleted
|
||||
* if true, then the version will be marked as deleted, i.e. this object was removed from the element
|
||||
* maps
|
||||
*
|
||||
* @return the new version, which is either an increment of the existing version on the element, or it will be
|
||||
* version 0
|
||||
*/
|
||||
public void updateVersionFor(StrolchRootElement element, boolean deleted);
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Performs the given {@link OrderQuery} and each returned {@link Order} is passed through the {@link OrderVisitor}
|
||||
|
|
|
@ -25,6 +25,10 @@ import li.strolch.runtime.query.inmemory.InMemoryQuery;
|
|||
|
||||
public class InMemoryActivityDao extends InMemoryDao<Activity> implements ActivityDao {
|
||||
|
||||
public InMemoryActivityDao(boolean versioningEnabled) {
|
||||
super(versioningEnabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <U> List<U> doQuery(ActivityQuery<U> activityQuery) {
|
||||
InMemoryActivityQueryVisitor visitor = new InMemoryActivityQueryVisitor();
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
package li.strolch.persistence.inmemory;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
|
@ -29,25 +30,32 @@ import li.strolch.persistence.api.StrolchPersistenceException;
|
|||
|
||||
public class InMemoryDao<T extends StrolchRootElement> implements StrolchDao<T> {
|
||||
|
||||
private Map<String, Map<String, T>> elementMap;
|
||||
private Map<String, Map<String, ArrayDeque<T>>> elementMap;
|
||||
private boolean versioningEnabled;
|
||||
|
||||
public InMemoryDao() {
|
||||
public InMemoryDao(boolean versioningEnabled) {
|
||||
this.versioningEnabled = versioningEnabled;
|
||||
this.elementMap = new HashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean hasElement(String type, String id) {
|
||||
Map<String, T> byType = this.elementMap.get(type);
|
||||
Map<String, ArrayDeque<T>> byType = this.elementMap.get(type);
|
||||
if (byType == null)
|
||||
return false;
|
||||
return byType.containsKey(id);
|
||||
|
||||
ArrayDeque<T> list = byType.get(id);
|
||||
if (list == null)
|
||||
return false;
|
||||
|
||||
return !list.getLast().getVersion().isDeleted();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized long querySize() {
|
||||
long size = 0;
|
||||
for (String type : this.elementMap.keySet()) {
|
||||
Map<String, T> byType = this.elementMap.get(type);
|
||||
Map<String, ArrayDeque<T>> byType = this.elementMap.get(type);
|
||||
size += byType.size();
|
||||
}
|
||||
return size;
|
||||
|
@ -55,7 +63,7 @@ public class InMemoryDao<T extends StrolchRootElement> implements StrolchDao<T>
|
|||
|
||||
@Override
|
||||
public synchronized long querySize(String type) {
|
||||
Map<String, T> byType = this.elementMap.get(type);
|
||||
Map<String, ArrayDeque<T>> byType = this.elementMap.get(type);
|
||||
if (byType == null)
|
||||
return 0;
|
||||
return byType.size();
|
||||
|
@ -63,21 +71,19 @@ public class InMemoryDao<T extends StrolchRootElement> implements StrolchDao<T>
|
|||
|
||||
@Override
|
||||
public synchronized Set<String> queryKeySet() {
|
||||
|
||||
Set<String> keySet = new HashSet<>();
|
||||
for (String type : this.elementMap.keySet()) {
|
||||
Map<String, T> byType = this.elementMap.get(type);
|
||||
Map<String, ArrayDeque<T>> byType = this.elementMap.get(type);
|
||||
for (String id : byType.keySet()) {
|
||||
keySet.add(id);
|
||||
}
|
||||
}
|
||||
|
||||
return keySet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized Set<String> queryKeySet(String type) {
|
||||
Map<String, T> byType = this.elementMap.get(type);
|
||||
Map<String, ArrayDeque<T>> byType = this.elementMap.get(type);
|
||||
if (byType == null)
|
||||
return new HashSet<>(0);
|
||||
return new HashSet<>(byType.keySet());
|
||||
|
@ -90,19 +96,58 @@ public class InMemoryDao<T extends StrolchRootElement> implements StrolchDao<T>
|
|||
|
||||
@Override
|
||||
public synchronized T queryBy(String type, String id) {
|
||||
Map<String, T> byType = this.elementMap.get(type);
|
||||
Map<String, ArrayDeque<T>> byType = this.elementMap.get(type);
|
||||
if (byType == null)
|
||||
return null;
|
||||
return byType.get(id);
|
||||
ArrayDeque<T> list = byType.get(id);
|
||||
if (list == null)
|
||||
return null;
|
||||
|
||||
T t = list.getLast();
|
||||
if (t.getVersion() != null && t.getVersion().isDeleted())
|
||||
return null;
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized T queryBy(String type, String id, int version) {
|
||||
Map<String, ArrayDeque<T>> byType = this.elementMap.get(type);
|
||||
if (byType == null)
|
||||
return null;
|
||||
ArrayDeque<T> list = byType.get(id);
|
||||
if (list == null)
|
||||
return null;
|
||||
|
||||
for (T t : list) {
|
||||
if (t.getVersion().getVersion() == version)
|
||||
return t;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized List<T> queryVersionsFor(String type, String id) {
|
||||
Map<String, ArrayDeque<T>> byType = this.elementMap.get(type);
|
||||
if (byType == null)
|
||||
return null;
|
||||
ArrayDeque<T> list = byType.get(id);
|
||||
if (list == null)
|
||||
return new ArrayList<>();
|
||||
return new ArrayList<>(list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized List<T> queryAll() {
|
||||
List<T> elements = new ArrayList<>();
|
||||
for (String type : this.elementMap.keySet()) {
|
||||
Map<String, T> byType = this.elementMap.get(type);
|
||||
Map<String, ArrayDeque<T>> byType = this.elementMap.get(type);
|
||||
for (String id : byType.keySet()) {
|
||||
elements.add(byType.get(id));
|
||||
ArrayDeque<T> list = byType.get(id);
|
||||
T last = list.getLast();
|
||||
if (last.getVersion() == null || !last.getVersion().isDeleted())
|
||||
elements.add(last);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -111,27 +156,43 @@ public class InMemoryDao<T extends StrolchRootElement> implements StrolchDao<T>
|
|||
|
||||
@Override
|
||||
public synchronized List<T> queryAll(String type) {
|
||||
Map<String, T> byType = this.elementMap.get(type);
|
||||
Map<String, ArrayDeque<T>> byType = this.elementMap.get(type);
|
||||
if (byType == null)
|
||||
return new ArrayList<>(0);
|
||||
return new ArrayList<>(byType.values());
|
||||
|
||||
List<T> elements = new ArrayList<>();
|
||||
for (ArrayDeque<T> list : byType.values()) {
|
||||
T last = list.getLast();
|
||||
if (last.getVersion() == null || !last.getVersion().isDeleted())
|
||||
elements.add(last);
|
||||
}
|
||||
|
||||
return elements;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void save(T element) {
|
||||
Map<String, T> byType = this.elementMap.get(element.getType());
|
||||
Map<String, ArrayDeque<T>> byType = this.elementMap.get(element.getType());
|
||||
if (byType == null) {
|
||||
byType = new HashMap<>();
|
||||
this.elementMap.put(element.getType(), byType);
|
||||
}
|
||||
|
||||
if (byType.containsKey(element.getId())) {
|
||||
ArrayDeque<T> list = byType.get(element.getId());
|
||||
|
||||
// only allow add for existing id, if the existing one is "deleted"
|
||||
if (list != null && !list.getLast().getVersion().isDeleted()) {
|
||||
String msg = "An element already exists with the id {0}. Elements of the same class must always have a unique id, regardless of their type!"; //$NON-NLS-1$
|
||||
msg = MessageFormat.format(msg, element.getId());
|
||||
throw new StrolchPersistenceException(msg);
|
||||
}
|
||||
|
||||
byType.put(element.getId(), element);
|
||||
if (list == null) {
|
||||
list = new ArrayDeque<>();
|
||||
byType.put(element.getId(), list);
|
||||
}
|
||||
|
||||
list.addLast(element);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -143,13 +204,24 @@ public class InMemoryDao<T extends StrolchRootElement> implements StrolchDao<T>
|
|||
|
||||
@Override
|
||||
public synchronized void update(T element) {
|
||||
Map<String, T> byType = this.elementMap.get(element.getType());
|
||||
Map<String, ArrayDeque<T>> byType = this.elementMap.get(element.getType());
|
||||
if (byType == null) {
|
||||
byType = new HashMap<>();
|
||||
this.elementMap.put(element.getType(), byType);
|
||||
String msg = "The element does not yet exist with the type {0} and id {1}. Use add() for new objects!"; //$NON-NLS-1$
|
||||
msg = MessageFormat.format(msg, element.getType(), element.getId());
|
||||
throw new StrolchPersistenceException(msg);
|
||||
}
|
||||
|
||||
byType.put(element.getId(), element);
|
||||
ArrayDeque<T> list = byType.get(element.getId());
|
||||
if (list == null) {
|
||||
String msg = "The element does not yet exist with the type {0} and id {1}. Use add() for new objects!"; //$NON-NLS-1$
|
||||
msg = MessageFormat.format(msg, element.getType(), element.getId());
|
||||
throw new StrolchPersistenceException(msg);
|
||||
}
|
||||
|
||||
if (!this.versioningEnabled)
|
||||
list.clear();
|
||||
|
||||
list.addLast(element);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -161,7 +233,7 @@ public class InMemoryDao<T extends StrolchRootElement> implements StrolchDao<T>
|
|||
|
||||
@Override
|
||||
public synchronized void remove(T element) {
|
||||
Map<String, T> byType = this.elementMap.get(element.getType());
|
||||
Map<String, ArrayDeque<T>> byType = this.elementMap.get(element.getType());
|
||||
if (byType != null) {
|
||||
byType.remove(element.getId());
|
||||
|
||||
|
@ -184,7 +256,7 @@ public class InMemoryDao<T extends StrolchRootElement> implements StrolchDao<T>
|
|||
|
||||
Set<String> keySet = new HashSet<>(this.elementMap.keySet());
|
||||
for (String type : keySet) {
|
||||
Map<String, T> byType = this.elementMap.remove(type);
|
||||
Map<String, ArrayDeque<T>> byType = this.elementMap.remove(type);
|
||||
removed += byType.size();
|
||||
byType.clear();
|
||||
}
|
||||
|
@ -194,11 +266,42 @@ public class InMemoryDao<T extends StrolchRootElement> implements StrolchDao<T>
|
|||
|
||||
@Override
|
||||
public synchronized long removeAllBy(String type) {
|
||||
Map<String, T> byType = this.elementMap.remove(type);
|
||||
Map<String, ArrayDeque<T>> byType = this.elementMap.remove(type);
|
||||
if (byType == null)
|
||||
return 0;
|
||||
long removed = byType.size();
|
||||
byType.clear();
|
||||
return removed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void removeVersion(T element) throws StrolchPersistenceException {
|
||||
|
||||
Map<String, ArrayDeque<T>> byType = this.elementMap.get(element.getType());
|
||||
if (byType == null) {
|
||||
String msg = "The element does not yet exist with the type {0}!"; //$NON-NLS-1$
|
||||
msg = MessageFormat.format(msg, element.getType());
|
||||
throw new StrolchPersistenceException(msg);
|
||||
}
|
||||
|
||||
ArrayDeque<T> list = byType.get(element.getId());
|
||||
if (list == null) {
|
||||
String msg = "The element does not yet exist with the type {0} and id {1}!"; //$NON-NLS-1$
|
||||
msg = MessageFormat.format(msg, element.getType(), element.getId());
|
||||
throw new StrolchPersistenceException(msg);
|
||||
}
|
||||
|
||||
T last = list.getLast();
|
||||
if (!last.getVersion().equals(element.getVersion())) {
|
||||
String msg = "The current version {0} is not the same as the version to remove {1}!"; //$NON-NLS-1$
|
||||
msg = MessageFormat.format(msg, last.getVersion(), element.getVersion());
|
||||
throw new StrolchPersistenceException(msg);
|
||||
}
|
||||
|
||||
list.removeLast();
|
||||
|
||||
if (list.isEmpty()) {
|
||||
byType.remove(element.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,10 @@ import li.strolch.runtime.query.inmemory.InMemoryQuery;
|
|||
|
||||
public class InMemoryOrderDao extends InMemoryDao<Order> implements OrderDao {
|
||||
|
||||
public InMemoryOrderDao(boolean versioningEnabled) {
|
||||
super(versioningEnabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <U> List<U> doQuery(OrderQuery<U> orderQuery) {
|
||||
InMemoryOrderQueryVisitor visitor = new InMemoryOrderQueryVisitor();
|
||||
|
|
|
@ -30,11 +30,13 @@ import li.strolch.runtime.privilege.PrivilegeHandler;
|
|||
|
||||
public class InMemoryPersistence implements PersistenceHandler {
|
||||
|
||||
private boolean versioningEnabled;
|
||||
private Map<String, DaoCache> daoCache;
|
||||
private PrivilegeHandler privilegeHandler;
|
||||
|
||||
public InMemoryPersistence(PrivilegeHandler privilegeHandler) {
|
||||
public InMemoryPersistence(PrivilegeHandler privilegeHandler, boolean versioningEnabled) {
|
||||
this.privilegeHandler = privilegeHandler;
|
||||
this.versioningEnabled = versioningEnabled;
|
||||
this.daoCache = new HashMap<>();
|
||||
}
|
||||
|
||||
|
@ -75,7 +77,8 @@ public class InMemoryPersistence implements PersistenceHandler {
|
|||
private synchronized DaoCache getDaoCache(StrolchTransaction tx) {
|
||||
DaoCache daoCache = this.daoCache.get(tx.getRealmName());
|
||||
if (daoCache == null) {
|
||||
daoCache = new DaoCache(new InMemoryOrderDao(), new InMemoryResourceDao(), new InMemoryActivityDao(),
|
||||
daoCache = new DaoCache(new InMemoryOrderDao(this.versioningEnabled),
|
||||
new InMemoryResourceDao(this.versioningEnabled), new InMemoryActivityDao(this.versioningEnabled),
|
||||
new InMemoryAuditDao());
|
||||
this.daoCache.put(tx.getRealmName(), daoCache);
|
||||
}
|
||||
|
|
|
@ -25,6 +25,10 @@ import li.strolch.runtime.query.inmemory.InMemoryResourceQueryVisitor;
|
|||
|
||||
public class InMemoryResourceDao extends InMemoryDao<Resource> implements ResourceDao {
|
||||
|
||||
public InMemoryResourceDao(boolean versioningEnabled) {
|
||||
super(versioningEnabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <U> List<U> doQuery(ResourceQuery<U> resourceQuery) {
|
||||
InMemoryResourceQueryVisitor visitor = new InMemoryResourceQueryVisitor();
|
||||
|
|
|
@ -50,6 +50,7 @@ public class ComponentContainerTest {
|
|||
public static final String PATH_CACHED_CONTAINER = "src/test/resources/cachedtest";
|
||||
public static final String PATH_EMPTY_CONTAINER = "src/test/resources/emptytest";
|
||||
public static final String PATH_MINIMAL_CONTAINER = "src/test/resources/minimaltest";
|
||||
public static final String PATH_VERSIONING_CONTAINER = "src/test/resources/versioningtest";
|
||||
|
||||
public static final String PATH_REALM_RUNTIME = "target/realmtest/";
|
||||
public static final String PATH_TRANSIENT_RUNTIME = "target/transienttest/";
|
||||
|
|
|
@ -0,0 +1,319 @@
|
|||
/*
|
||||
* Copyright 2013 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.runtime.query.inmemory;
|
||||
|
||||
import static li.strolch.model.query.ParameterSelection.booleanSelection;
|
||||
import static li.strolch.model.query.ParameterSelection.floatListSelection;
|
||||
import static li.strolch.model.query.ParameterSelection.floatSelection;
|
||||
import static li.strolch.model.query.ParameterSelection.integerListSelection;
|
||||
import static li.strolch.model.query.ParameterSelection.longListSelection;
|
||||
import static li.strolch.model.query.ParameterSelection.stringListSelection;
|
||||
import static li.strolch.model.query.ParameterSelection.stringSelection;
|
||||
import static li.strolch.utils.StringMatchMode.ci;
|
||||
import static li.strolch.utils.StringMatchMode.es;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import li.strolch.model.ModelGenerator;
|
||||
import li.strolch.model.Order;
|
||||
import li.strolch.model.ParameterBag;
|
||||
import li.strolch.model.State;
|
||||
import li.strolch.model.Version;
|
||||
import li.strolch.model.parameter.BooleanParameter;
|
||||
import li.strolch.model.parameter.FloatListParameter;
|
||||
import li.strolch.model.parameter.FloatParameter;
|
||||
import li.strolch.model.parameter.IntegerListParameter;
|
||||
import li.strolch.model.parameter.LongListParameter;
|
||||
import li.strolch.model.parameter.StringListParameter;
|
||||
import li.strolch.model.parameter.StringParameter;
|
||||
import li.strolch.model.query.IdSelection;
|
||||
import li.strolch.model.query.NameSelection;
|
||||
import li.strolch.model.query.OrderQuery;
|
||||
import li.strolch.model.query.ParameterSelection;
|
||||
import li.strolch.persistence.inmemory.InMemoryOrderDao;
|
||||
|
||||
/**
|
||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||
*/
|
||||
@SuppressWarnings("nls")
|
||||
public class InMemoryOrderQueryTest {
|
||||
|
||||
protected InMemoryOrderDao daoInstance() {
|
||||
return new InMemoryOrderDao(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldQueryById() {
|
||||
|
||||
List<Order> orders = getOrders();
|
||||
InMemoryOrderDao dao = daoInstance();
|
||||
dao.saveAll(orders);
|
||||
|
||||
OrderQuery<Order> orderQuery = OrderQuery.query("MyType1");
|
||||
orderQuery.with(new IdSelection("@1"));
|
||||
|
||||
List<Order> result = dao.doQuery(orderQuery);
|
||||
assertEquals(1, result.size());
|
||||
assertEquals("@1", result.get(0).getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldQueryByIdOr() {
|
||||
|
||||
List<Order> orders = getOrders();
|
||||
InMemoryOrderDao dao = daoInstance();
|
||||
dao.saveAll(orders);
|
||||
|
||||
OrderQuery<Order> orderQuery = OrderQuery.query("MyType2");
|
||||
orderQuery.or().with(new IdSelection("@3"), new IdSelection("@4"));
|
||||
|
||||
List<Order> result = dao.doQuery(orderQuery);
|
||||
assertEquals(2, result.size());
|
||||
assertEquals("@3", result.get(0).getId());
|
||||
assertEquals("@4", result.get(1).getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldQueryByIdAnd() {
|
||||
|
||||
List<Order> orders = getOrders();
|
||||
InMemoryOrderDao dao = daoInstance();
|
||||
dao.saveAll(orders);
|
||||
|
||||
OrderQuery<Order> orderQuery = OrderQuery.query("MyType2");
|
||||
orderQuery.and().with(new IdSelection("@3"), new NameSelection("Res 3", es()));
|
||||
|
||||
List<Order> result = dao.doQuery(orderQuery);
|
||||
assertEquals(1, result.size());
|
||||
assertEquals("@3", result.get(0).getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldNotQueryByIdAnd() {
|
||||
|
||||
List<Order> orders = getOrders();
|
||||
InMemoryOrderDao dao = daoInstance();
|
||||
dao.saveAll(orders);
|
||||
|
||||
OrderQuery<Order> orderQuery = OrderQuery.query("MyType1");
|
||||
orderQuery.and().with(new IdSelection("@3"), new NameSelection("@4", es()));
|
||||
|
||||
List<Order> result = dao.doQuery(orderQuery);
|
||||
assertEquals(0, result.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldQueryByParameter() {
|
||||
|
||||
List<Order> orders = getOrders();
|
||||
orders.add(getBallOrder());
|
||||
InMemoryOrderDao dao = daoInstance();
|
||||
dao.saveAll(orders);
|
||||
|
||||
OrderQuery<Order> ballQuery = OrderQuery.query("Ball");
|
||||
ballQuery.and().with(
|
||||
//
|
||||
stringSelection("parameters", "color", "red", es()),
|
||||
booleanSelection("parameters", "forChildren", true), floatSelection("parameters", "diameter", 22.0));
|
||||
|
||||
List<Order> result = dao.doQuery(ballQuery);
|
||||
assertEquals(1, result.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldQueryByListParameter() {
|
||||
|
||||
List<Order> orders = getOrders();
|
||||
orders.add(getBallOrder());
|
||||
InMemoryOrderDao dao = daoInstance();
|
||||
dao.saveAll(orders);
|
||||
|
||||
OrderQuery<Order> ballQuery;
|
||||
List<Order> result;
|
||||
|
||||
// string list
|
||||
{
|
||||
ballQuery = OrderQuery.query("Ball");
|
||||
ballQuery.and().with(stringListSelection("parameters", "stringListValues", Arrays.asList("a", "z")));
|
||||
result = dao.doQuery(ballQuery);
|
||||
assertEquals(0, result.size());
|
||||
|
||||
ballQuery = OrderQuery.query("Ball");
|
||||
ballQuery.and().with(stringListSelection("parameters", "stringListValues", Arrays.asList("a")));
|
||||
result = dao.doQuery(ballQuery);
|
||||
assertEquals(1, result.size());
|
||||
|
||||
ballQuery = OrderQuery.query("Ball");
|
||||
ballQuery.and().with(stringListSelection("parameters", "stringListValues", Arrays.asList("c", "b", "a")));
|
||||
result = dao.doQuery(ballQuery);
|
||||
assertEquals(1, result.size());
|
||||
}
|
||||
|
||||
// integer list
|
||||
{
|
||||
ballQuery = OrderQuery.query("Ball");
|
||||
ballQuery.and().with(integerListSelection("parameters", "intListValues", Arrays.asList(1, 5)));
|
||||
result = dao.doQuery(ballQuery);
|
||||
assertEquals(0, result.size());
|
||||
|
||||
ballQuery = OrderQuery.query("Ball");
|
||||
ballQuery.and().with(integerListSelection("parameters", "intListValues", Arrays.asList(1)));
|
||||
result = dao.doQuery(ballQuery);
|
||||
assertEquals(1, result.size());
|
||||
|
||||
ballQuery = OrderQuery.query("Ball");
|
||||
ballQuery.and().with(integerListSelection("parameters", "intListValues", Arrays.asList(3, 2, 1)));
|
||||
result = dao.doQuery(ballQuery);
|
||||
assertEquals(1, result.size());
|
||||
}
|
||||
|
||||
// float list
|
||||
{
|
||||
ballQuery = OrderQuery.query("Ball");
|
||||
ballQuery.and().with(floatListSelection("parameters", "floatListValues", Arrays.asList(4.0, 8.0)));
|
||||
result = dao.doQuery(ballQuery);
|
||||
assertEquals(0, result.size());
|
||||
|
||||
ballQuery = OrderQuery.query("Ball");
|
||||
ballQuery.and().with(floatListSelection("parameters", "floatListValues", Arrays.asList(4.0)));
|
||||
result = dao.doQuery(ballQuery);
|
||||
assertEquals(1, result.size());
|
||||
|
||||
ballQuery = OrderQuery.query("Ball");
|
||||
ballQuery.and().with(floatListSelection("parameters", "floatListValues", Arrays.asList(6.2, 5.1, 4.0)));
|
||||
result = dao.doQuery(ballQuery);
|
||||
assertEquals(1, result.size());
|
||||
}
|
||||
|
||||
// long list
|
||||
{
|
||||
ballQuery = OrderQuery.query("Ball");
|
||||
ballQuery.and().with(longListSelection("parameters", "longListValues", Arrays.asList(8L, 11L)));
|
||||
result = dao.doQuery(ballQuery);
|
||||
assertEquals(0, result.size());
|
||||
|
||||
ballQuery = OrderQuery.query("Ball");
|
||||
ballQuery.and().with(longListSelection("parameters", "longListValues", Arrays.asList(8L)));
|
||||
result = dao.doQuery(ballQuery);
|
||||
assertEquals(1, result.size());
|
||||
|
||||
ballQuery = OrderQuery.query("Ball");
|
||||
ballQuery.and().with(longListSelection("parameters", "longListValues", Arrays.asList(10L, 9L, 8L)));
|
||||
result = dao.doQuery(ballQuery);
|
||||
assertEquals(1, result.size());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldQueryByNullParameter1() {
|
||||
List<Order> orders = getOrders();
|
||||
orders.add(getBallOrder());
|
||||
InMemoryOrderDao dao = daoInstance();
|
||||
dao.saveAll(orders);
|
||||
|
||||
OrderQuery<Order> ballQuery = OrderQuery.query("Ball");
|
||||
ballQuery.and().with( //
|
||||
ParameterSelection.nullSelection("parameters", "color"));
|
||||
|
||||
List<Order> result = dao.doQuery(ballQuery);
|
||||
assertEquals(0, result.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldQueryByNullParameter2() {
|
||||
List<Order> orders = getOrders();
|
||||
orders.add(getBallOrder());
|
||||
InMemoryOrderDao dao = daoInstance();
|
||||
dao.saveAll(orders);
|
||||
|
||||
OrderQuery<Order> ballQuery = OrderQuery.query("Ball");
|
||||
ballQuery.and().with( //
|
||||
ParameterSelection.nullSelection("parameters", "weight"));
|
||||
|
||||
List<Order> result = dao.doQuery(ballQuery);
|
||||
assertEquals(1, result.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldQueryByNullParameter3() {
|
||||
List<Order> orders = getOrders();
|
||||
orders.add(getBallOrder());
|
||||
InMemoryOrderDao dao = daoInstance();
|
||||
dao.saveAll(orders);
|
||||
|
||||
OrderQuery<Order> ballQuery = OrderQuery.query("Ball");
|
||||
ballQuery.and().with( //
|
||||
ParameterSelection.nullSelection("parameters", "weight"));
|
||||
|
||||
List<Order> result = dao.doQuery(ballQuery);
|
||||
assertEquals(1, result.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldQueryByName() {
|
||||
|
||||
List<Order> orders = getOrders();
|
||||
orders.add(getBallOrder());
|
||||
InMemoryOrderDao dao = daoInstance();
|
||||
dao.saveAll(orders);
|
||||
|
||||
OrderQuery<Order> ballQuery = OrderQuery.query("Ball");
|
||||
ballQuery.with(new NameSelection("ball ", ci()));
|
||||
|
||||
List<Order> result = dao.doQuery(ballQuery);
|
||||
assertEquals(1, result.size());
|
||||
}
|
||||
|
||||
private Order getBallOrder() {
|
||||
Order o1 = new Order("childrensBall", "Ball 1", "Ball");
|
||||
o1.setVersion(new Version(o1.getLocator(), 0, "ModelGenerator", false));
|
||||
ParameterBag bag = new ParameterBag("parameters", "Ball Details", "Parameters");
|
||||
bag.addParameter(new StringParameter("color", "Color", "red"));
|
||||
bag.addParameter(new BooleanParameter("forChildren", "Color", true));
|
||||
bag.addParameter(new FloatParameter("diameter", "Color", 22.0));
|
||||
bag.addParameter(
|
||||
new StringListParameter("stringListValues", "List of String Values", Arrays.asList("a", "b", "c")));
|
||||
bag.addParameter(new IntegerListParameter("intListValues", "List of Integer Values", Arrays.asList(1, 2, 3)));
|
||||
bag.addParameter(
|
||||
new FloatListParameter("floatListValues", "List of Float Values", Arrays.asList(4.0, 5.1, 6.2)));
|
||||
bag.addParameter(new LongListParameter("longListValues", "List of Long Values", Arrays.asList(8L, 9L, 10L)));
|
||||
o1.addParameterBag(bag);
|
||||
return o1;
|
||||
}
|
||||
|
||||
private List<Order> getOrders() {
|
||||
Order res1 = ModelGenerator.createOrder("@1", "Res 1", "MyType1", new Date(), State.CREATED);
|
||||
Order res2 = ModelGenerator.createOrder("@2", "Res 2", "MyType1", new Date(), State.CREATED);
|
||||
Order res3 = ModelGenerator.createOrder("@3", "Res 3", "MyType2", new Date(), State.CREATED);
|
||||
Order res4 = ModelGenerator.createOrder("@4", "Res 4", "MyType2", new Date(), State.CREATED);
|
||||
Order res5 = ModelGenerator.createOrder("@5", "Res 5", "MyType3", new Date(), State.CREATED);
|
||||
Order res6 = ModelGenerator.createOrder("@6", "Res 6", "MyType3", new Date(), State.CREATED);
|
||||
List<Order> orders = new ArrayList<>();
|
||||
orders.add(res1);
|
||||
orders.add(res2);
|
||||
orders.add(res3);
|
||||
orders.add(res4);
|
||||
orders.add(res5);
|
||||
orders.add(res6);
|
||||
return orders;
|
||||
}
|
||||
}
|
|
@ -13,7 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package li.strolch.persistence.inmemory;
|
||||
package li.strolch.runtime.query.inmemory;
|
||||
|
||||
import li.strolch.agent.api.ComponentContainer;
|
||||
import li.strolch.agent.api.StrolchComponent;
|
||||
|
@ -24,6 +24,7 @@ import li.strolch.persistence.api.OrderDao;
|
|||
import li.strolch.persistence.api.PersistenceHandler;
|
||||
import li.strolch.persistence.api.ResourceDao;
|
||||
import li.strolch.persistence.api.StrolchTransaction;
|
||||
import li.strolch.persistence.inmemory.InMemoryPersistence;
|
||||
import li.strolch.privilege.model.Certificate;
|
||||
import li.strolch.runtime.configuration.ComponentConfiguration;
|
||||
|
||||
|
@ -44,7 +45,7 @@ public class InMemoryPersistenceHandler extends StrolchComponent implements Pers
|
|||
|
||||
@Override
|
||||
public void initialize(ComponentConfiguration configuration) throws Exception {
|
||||
this.persistence = new InMemoryPersistence(getContainer().getPrivilegeHandler());
|
||||
this.persistence = new InMemoryPersistence(getContainer().getPrivilegeHandler(), false);
|
||||
super.initialize(configuration);
|
||||
}
|
||||
|
|
@ -1,18 +1,3 @@
|
|||
/*
|
||||
* Copyright 2013 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.runtime.query.inmemory;
|
||||
|
||||
import static li.strolch.model.query.ParameterSelection.booleanSelection;
|
||||
|
@ -28,14 +13,14 @@ import static org.junit.Assert.assertEquals;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import li.strolch.model.ModelGenerator;
|
||||
import li.strolch.model.Order;
|
||||
import li.strolch.model.ParameterBag;
|
||||
import li.strolch.model.Resource;
|
||||
import li.strolch.model.State;
|
||||
import li.strolch.model.Version;
|
||||
import li.strolch.model.parameter.BooleanParameter;
|
||||
import li.strolch.model.parameter.FloatListParameter;
|
||||
import li.strolch.model.parameter.FloatParameter;
|
||||
|
@ -45,39 +30,21 @@ import li.strolch.model.parameter.StringListParameter;
|
|||
import li.strolch.model.parameter.StringParameter;
|
||||
import li.strolch.model.query.IdSelection;
|
||||
import li.strolch.model.query.NameSelection;
|
||||
import li.strolch.model.query.OrderQuery;
|
||||
import li.strolch.model.query.ParameterSelection;
|
||||
import li.strolch.model.query.ResourceQuery;
|
||||
import li.strolch.persistence.inmemory.InMemoryOrderDao;
|
||||
import li.strolch.persistence.inmemory.InMemoryResourceDao;
|
||||
|
||||
import org.junit.Test;
|
||||
public class InMemoryResourceQueryTest {
|
||||
|
||||
/**
|
||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||
*/
|
||||
@SuppressWarnings("nls")
|
||||
public class InMemoryQueryTest {
|
||||
|
||||
@Test
|
||||
public void shouldQueryOrderById() {
|
||||
|
||||
List<Order> orders = getOrders();
|
||||
InMemoryOrderDao dao = new InMemoryOrderDao();
|
||||
dao.saveAll(orders);
|
||||
|
||||
OrderQuery<Order> orderQuery = OrderQuery.query("MyType1");
|
||||
orderQuery.with(new IdSelection("@1"));
|
||||
List<Order> result = dao.doQuery(orderQuery);
|
||||
assertEquals(1, result.size());
|
||||
assertEquals("@1", result.get(0).getId());
|
||||
protected InMemoryResourceDao daoInstance() {
|
||||
return new InMemoryResourceDao(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldQueryResourceById() {
|
||||
public void shouldQueryById() {
|
||||
|
||||
List<Resource> resources = getResources();
|
||||
InMemoryResourceDao dao = new InMemoryResourceDao();
|
||||
InMemoryResourceDao dao = daoInstance();
|
||||
dao.saveAll(resources);
|
||||
|
||||
ResourceQuery<Resource> resourceQuery = ResourceQuery.query("MyType1");
|
||||
|
@ -89,10 +56,10 @@ public class InMemoryQueryTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void shouldQueryResourceByIdOr() {
|
||||
public void shouldQueryByIdOr() {
|
||||
|
||||
List<Resource> resources = getResources();
|
||||
InMemoryResourceDao dao = new InMemoryResourceDao();
|
||||
InMemoryResourceDao dao = daoInstance();
|
||||
dao.saveAll(resources);
|
||||
|
||||
ResourceQuery<Resource> resourceQuery = ResourceQuery.query("MyType2");
|
||||
|
@ -105,10 +72,10 @@ public class InMemoryQueryTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void shouldQueryResourceByIdAnd() {
|
||||
public void shouldQueryByIdAnd() {
|
||||
|
||||
List<Resource> resources = getResources();
|
||||
InMemoryResourceDao dao = new InMemoryResourceDao();
|
||||
InMemoryResourceDao dao = daoInstance();
|
||||
dao.saveAll(resources);
|
||||
|
||||
ResourceQuery<Resource> resourceQuery = ResourceQuery.query("MyType2");
|
||||
|
@ -120,10 +87,10 @@ public class InMemoryQueryTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void shouldNotQueryResourceByIdAnd() {
|
||||
public void shouldNotQueryByIdAnd() {
|
||||
|
||||
List<Resource> resources = getResources();
|
||||
InMemoryResourceDao dao = new InMemoryResourceDao();
|
||||
InMemoryResourceDao dao = daoInstance();
|
||||
dao.saveAll(resources);
|
||||
|
||||
ResourceQuery<Resource> resourceQuery = ResourceQuery.query("MyType1");
|
||||
|
@ -138,7 +105,7 @@ public class InMemoryQueryTest {
|
|||
|
||||
List<Resource> resources = getResources();
|
||||
resources.add(getBallResource());
|
||||
InMemoryResourceDao dao = new InMemoryResourceDao();
|
||||
InMemoryResourceDao dao = daoInstance();
|
||||
dao.saveAll(resources);
|
||||
|
||||
ResourceQuery<Resource> ballQuery = ResourceQuery.query("Ball");
|
||||
|
@ -156,7 +123,7 @@ public class InMemoryQueryTest {
|
|||
|
||||
List<Resource> resources = getResources();
|
||||
resources.add(getBallResource());
|
||||
InMemoryResourceDao dao = new InMemoryResourceDao();
|
||||
InMemoryResourceDao dao = daoInstance();
|
||||
dao.saveAll(resources);
|
||||
|
||||
ResourceQuery<Resource> ballQuery;
|
||||
|
@ -239,7 +206,7 @@ public class InMemoryQueryTest {
|
|||
public void shouldQueryByNullParameter1() {
|
||||
List<Resource> resources = getResources();
|
||||
resources.add(getBallResource());
|
||||
InMemoryResourceDao dao = new InMemoryResourceDao();
|
||||
InMemoryResourceDao dao = daoInstance();
|
||||
dao.saveAll(resources);
|
||||
|
||||
ResourceQuery<Resource> ballQuery = ResourceQuery.query("Ball");
|
||||
|
@ -254,7 +221,7 @@ public class InMemoryQueryTest {
|
|||
public void shouldQueryByNullParameter2() {
|
||||
List<Resource> resources = getResources();
|
||||
resources.add(getBallResource());
|
||||
InMemoryResourceDao dao = new InMemoryResourceDao();
|
||||
InMemoryResourceDao dao = daoInstance();
|
||||
dao.saveAll(resources);
|
||||
|
||||
ResourceQuery<Resource> ballQuery = ResourceQuery.query("Ball");
|
||||
|
@ -269,7 +236,7 @@ public class InMemoryQueryTest {
|
|||
public void shouldQueryByNullParameter3() {
|
||||
List<Resource> resources = getResources();
|
||||
resources.add(getBallResource());
|
||||
InMemoryResourceDao dao = new InMemoryResourceDao();
|
||||
InMemoryResourceDao dao = daoInstance();
|
||||
dao.saveAll(resources);
|
||||
|
||||
ResourceQuery<Resource> ballQuery = ResourceQuery.query("Ball");
|
||||
|
@ -285,7 +252,7 @@ public class InMemoryQueryTest {
|
|||
|
||||
List<Resource> resources = getResources();
|
||||
resources.add(getBallResource());
|
||||
InMemoryResourceDao dao = new InMemoryResourceDao();
|
||||
InMemoryResourceDao dao = daoInstance();
|
||||
dao.saveAll(resources);
|
||||
|
||||
ResourceQuery<Resource> ballQuery = ResourceQuery.query("Ball");
|
||||
|
@ -297,14 +264,16 @@ public class InMemoryQueryTest {
|
|||
|
||||
private Resource getBallResource() {
|
||||
Resource res1 = new Resource("childrensBall", "Ball 1", "Ball");
|
||||
res1.setVersion(new Version(res1.getLocator(), 0, "ModelGenerator", false));
|
||||
ParameterBag bag = new ParameterBag("parameters", "Ball Details", "Parameters");
|
||||
bag.addParameter(new StringParameter("color", "Color", "red"));
|
||||
bag.addParameter(new BooleanParameter("forChildren", "Color", true));
|
||||
bag.addParameter(new FloatParameter("diameter", "Color", 22.0));
|
||||
bag.addParameter(new StringListParameter("stringListValues", "List of String Values", Arrays.asList("a", "b",
|
||||
"c")));
|
||||
bag.addParameter(
|
||||
new StringListParameter("stringListValues", "List of String Values", Arrays.asList("a", "b", "c")));
|
||||
bag.addParameter(new IntegerListParameter("intListValues", "List of Integer Values", Arrays.asList(1, 2, 3)));
|
||||
bag.addParameter(new FloatListParameter("floatListValues", "List of Float Values", Arrays.asList(4.0, 5.1, 6.2)));
|
||||
bag.addParameter(
|
||||
new FloatListParameter("floatListValues", "List of Float Values", Arrays.asList(4.0, 5.1, 6.2)));
|
||||
bag.addParameter(new LongListParameter("longListValues", "List of Long Values", Arrays.asList(8L, 9L, 10L)));
|
||||
res1.addParameterBag(bag);
|
||||
return res1;
|
||||
|
@ -324,23 +293,11 @@ public class InMemoryQueryTest {
|
|||
resources.add(res4);
|
||||
resources.add(res5);
|
||||
resources.add(res6);
|
||||
|
||||
for (Resource resource : resources) {
|
||||
resource.setVersion(new Version(resource.getLocator(), 0, "Test", false));
|
||||
}
|
||||
|
||||
return resources;
|
||||
}
|
||||
|
||||
private List<Order> getOrders() {
|
||||
Order res1 = ModelGenerator.createOrder("@1", "Res 1", "MyType1", new Date(), State.CREATED);
|
||||
Order res2 = ModelGenerator.createOrder("@2", "Res 2", "MyType1", new Date(), State.CREATED);
|
||||
Order res3 = ModelGenerator.createOrder("@3", "Res 3", "MyType2", new Date(), State.CREATED);
|
||||
Order res4 = ModelGenerator.createOrder("@4", "Res 4", "MyType2", new Date(), State.CREATED);
|
||||
Order res5 = ModelGenerator.createOrder("@5", "Res 5", "MyType3", new Date(), State.CREATED);
|
||||
Order res6 = ModelGenerator.createOrder("@6", "Res 6", "MyType3", new Date(), State.CREATED);
|
||||
List<Order> orders = new ArrayList<>();
|
||||
orders.add(res1);
|
||||
orders.add(res2);
|
||||
orders.add(res3);
|
||||
orders.add(res4);
|
||||
orders.add(res5);
|
||||
orders.add(res6);
|
||||
return orders;
|
||||
}
|
||||
}
|
|
@ -44,7 +44,7 @@
|
|||
<Component>
|
||||
<name>PersistenceHandler</name>
|
||||
<api>li.strolch.persistence.api.PersistenceHandler</api>
|
||||
<impl>li.strolch.persistence.inmemory.InMemoryPersistenceHandler</impl>
|
||||
<impl>li.strolch.runtime.query.inmemory.InMemoryPersistenceHandler</impl>
|
||||
</Component>
|
||||
</env>
|
||||
</StrolchConfiguration>
|
|
@ -19,7 +19,7 @@
|
|||
<Component>
|
||||
<name>PersistenceHandler</name>
|
||||
<api>li.strolch.persistence.api.PersistenceHandler</api>
|
||||
<impl>li.strolch.persistence.inmemory.InMemoryPersistenceHandler</impl>
|
||||
<impl>li.strolch.runtime.query.inmemory.InMemoryPersistenceHandler</impl>
|
||||
</Component>
|
||||
<Component>
|
||||
<name>RealmHandler</name>
|
||||
|
|
|
@ -45,7 +45,7 @@
|
|||
<Component>
|
||||
<name>PersistenceHandler</name>
|
||||
<api>li.strolch.persistence.api.PersistenceHandler</api>
|
||||
<impl>li.strolch.persistence.inmemory.InMemoryPersistenceHandler</impl>
|
||||
<impl>li.strolch.runtime.query.inmemory.InMemoryPersistenceHandler</impl>
|
||||
</Component>
|
||||
</env>
|
||||
</StrolchConfiguration>
|
|
@ -0,0 +1,32 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Privilege>
|
||||
|
||||
<Container>
|
||||
|
||||
<Parameters>
|
||||
<!-- parameters for the container itself -->
|
||||
<Parameter name="autoPersistOnUserChangesData" value="true" />
|
||||
</Parameters>
|
||||
|
||||
<EncryptionHandler class="li.strolch.privilege.handler.DefaultEncryptionHandler">
|
||||
<Parameters>
|
||||
<Parameter name="hashAlgorithm" value="SHA-256" />
|
||||
</Parameters>
|
||||
</EncryptionHandler>
|
||||
|
||||
<PersistenceHandler class="li.strolch.privilege.handler.XmlPersistenceHandler">
|
||||
<Parameters>
|
||||
<Parameter name="usersXmlFile" value="PrivilegeUsers.xml" />
|
||||
<Parameter name="rolesXmlFile" value="PrivilegeRoles.xml" />
|
||||
</Parameters>
|
||||
</PersistenceHandler>
|
||||
|
||||
</Container>
|
||||
|
||||
<Policies>
|
||||
<Policy name="DefaultPrivilege" class="li.strolch.privilege.policy.DefaultPrivilege" />
|
||||
<Policy name="RoleAccessPrivilege" class="li.strolch.privilege.policy.RoleAccessPrivilege" />
|
||||
<Policy name="UserAccessPrivilege" class="li.strolch.privilege.policy.UserAccessPrivilege" />
|
||||
</Policies>
|
||||
|
||||
</Privilege>
|
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Roles>
|
||||
<Role name="agent">
|
||||
<Privilege name="li.strolch.privilege.handler.SystemUserAction" policy="DefaultPrivilege">
|
||||
<Allow>li.strolch.agent.impl.StartRealms</Allow>
|
||||
</Privilege>
|
||||
</Role>
|
||||
<Role name="AppUser">
|
||||
<Privilege name="li.strolch.service.api.Service" policy="DefaultPrivilege">
|
||||
<AllAllowed>true</AllAllowed>
|
||||
</Privilege>
|
||||
<Privilege name="li.strolch.model.query.StrolchQuery" policy="DefaultPrivilege">
|
||||
<AllAllowed>true</AllAllowed>
|
||||
</Privilege>
|
||||
</Role>
|
||||
</Roles>
|
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Users>
|
||||
<User userId="1" username="agent">
|
||||
<State>SYSTEM</State>
|
||||
<Roles>
|
||||
<Role>agent</Role>
|
||||
</Roles>
|
||||
</User>
|
||||
<User userId="2" username="test" password="9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08">
|
||||
<Firstname>Application</Firstname>
|
||||
<Lastname>Administrator</Lastname>
|
||||
<State>ENABLED</State>
|
||||
<Locale>en_GB</Locale>
|
||||
<Roles>
|
||||
<Role>AppUser</Role>
|
||||
</Roles>
|
||||
</User>
|
||||
</Users>
|
|
@ -0,0 +1,46 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<StrolchConfiguration>
|
||||
<env id="dev">
|
||||
<Runtime>
|
||||
<applicationName>StrolchRuntimeTest</applicationName>
|
||||
<Properties>
|
||||
<verbose>true</verbose>
|
||||
</Properties>
|
||||
</Runtime>
|
||||
<Component>
|
||||
<name>PrivilegeHandler</name>
|
||||
<api>li.strolch.runtime.privilege.PrivilegeHandler</api>
|
||||
<impl>li.strolch.runtime.privilege.DefaultStrolchPrivilegeHandler</impl>
|
||||
<Properties>
|
||||
<privilegeConfigFile>PrivilegeConfig.xml</privilegeConfigFile>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component>
|
||||
<name>RealmHandler</name>
|
||||
<api>li.strolch.agent.api.RealmHandler</api>
|
||||
<impl>li.strolch.agent.impl.DefaultRealmHandler</impl>
|
||||
<depends>PrivilegeHandler</depends>
|
||||
<Properties>
|
||||
<enableVersioning>true</enableVersioning>
|
||||
<dataStoreMode>TRANSIENT</dataStoreMode>
|
||||
<dataStoreFile>StrolchModel.xml</dataStoreFile>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component>
|
||||
<name>ServiceHandler</name>
|
||||
<api>li.strolch.runtime.configuration.model.ServiceHandlerTest</api>
|
||||
<impl>li.strolch.runtime.configuration.model.ServiceHandlerTestImpl</impl>
|
||||
<depends>RealmHandler</depends>
|
||||
<Properties>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component>
|
||||
<name>PostInitializer</name>
|
||||
<api>li.strolch.runtime.configuration.model.PostInitializerTest</api>
|
||||
<impl>li.strolch.runtime.configuration.model.PostInitializerTestImpl</impl>
|
||||
<depends>ServiceHandler</depends>
|
||||
<Properties>
|
||||
</Properties>
|
||||
</Component>
|
||||
</env>
|
||||
</StrolchConfiguration>
|
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
||||
<StrolchModel>
|
||||
<Order Id="MyTestOrder" Name="Test Name" Type="TestType" Date="2013-11-20T07:42:57.699+01:00" State="CREATED">
|
||||
<ParameterBag Id="@bag01" Name="Test Bag" Type="TestBag">
|
||||
<Parameter Id="@param7" Name="StringList Param" Type="StringList" Value="Hello;World" />
|
||||
<Parameter Id="@param6" Name="Date Param" Type="Date" Value="2012-11-30T18:12:05.628+01:00" />
|
||||
<Parameter Id="@param5" Name="String Param" Type="String" Value="Strolch" />
|
||||
<Parameter Id="@param4" Name="Long Param" Type="Long" Value="4453234566" />
|
||||
<Parameter Id="@param3" Name="Integer Param" Type="Integer" Value="77" />
|
||||
<Parameter Id="@param2" Name="Float Param" Type="Float" Value="44.3" />
|
||||
<Parameter Id="@param1" Name="Boolean Param" Type="Boolean" Value="true" />
|
||||
</ParameterBag>
|
||||
</Order>
|
||||
</StrolchModel>
|
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
||||
<StrolchModel>
|
||||
<Resource Id="MyTestResource" Name="Test Name" Type="TestType">
|
||||
<ParameterBag Id="@bag01" Name="Test Bag" Type="TestBag">
|
||||
<Parameter Id="@param7" Name="StringList Param" Type="StringList" Value="Hello;World" />
|
||||
<Parameter Id="@param6" Name="Date Param" Type="Date" Value="2012-11-30T18:12:05.628+01:00" />
|
||||
<Parameter Id="@param5" Name="String Param" Type="String" Value="Strolch" />
|
||||
<Parameter Id="@param4" Name="Long Param" Type="Long" Value="4453234566" />
|
||||
<Parameter Id="@param3" Name="Integer Param" Type="Integer" Value="77" />
|
||||
<Parameter Id="@param2" Name="Float Param" Type="Float" Value="44.3" />
|
||||
<Parameter Id="@param1" Name="Boolean Param" Type="Boolean" Value="true" />
|
||||
</ParameterBag>
|
||||
</Resource>
|
||||
</StrolchModel>
|
|
@ -0,0 +1,29 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<StrolchModel>
|
||||
<Resource Id="TestType" Name="TestType Template" Type="Template">
|
||||
<ParameterBag Id="@bag01" Name="Test Bag" Type="TestBag">
|
||||
<Parameter Id="@param7" Name="StringList Param" Type="StringList" Value="Hello;World" />
|
||||
<Parameter Id="@param6" Name="Date Param" Type="Date" Value="2012-11-30T18:12:05.628+01:00" />
|
||||
<Parameter Id="@param5" Name="String Param" Type="String" Value="Strolch" />
|
||||
<Parameter Id="@param4" Name="Long Param" Type="Long" Value="4453234566" />
|
||||
<Parameter Id="@param3" Name="Integer Param" Type="Integer" Value="77" />
|
||||
<Parameter Id="@param2" Name="Float Param" Type="Float" Value="44.3" />
|
||||
<Parameter Id="@param1" Name="Boolean Param" Type="Boolean" Value="true" />
|
||||
</ParameterBag>
|
||||
</Resource>
|
||||
<Order Id="MyTestOrder" Name="MyTestOrder Template" Type="Template">
|
||||
<ParameterBag Id="@bag01" Name="Test Bag" Type="TestBag">
|
||||
<Parameter Id="@param7" Name="StringList Param" Type="StringList" Value="Hello;World" />
|
||||
<Parameter Id="@param6" Name="Date Param" Type="Date" Value="2012-11-30T18:12:05.628+01:00" />
|
||||
<Parameter Id="@param5" Name="String Param" Type="String" Value="Strolch" />
|
||||
<Parameter Id="@param4" Name="Long Param" Type="Long" Value="4453234566" />
|
||||
<Parameter Id="@param3" Name="Integer Param" Type="Integer" Value="77" />
|
||||
<Parameter Id="@param2" Name="Float Param" Type="Float" Value="44.3" />
|
||||
<Parameter Id="@param1" Name="Boolean Param" Type="Boolean" Value="true" />
|
||||
</ParameterBag>
|
||||
</Order>
|
||||
|
||||
<IncludeFile file="Resources.xml" />
|
||||
<IncludeFile file="Orders.xml" />
|
||||
|
||||
</StrolchModel>
|
|
@ -22,6 +22,7 @@ import java.util.Iterator;
|
|||
import java.util.List;
|
||||
|
||||
import li.strolch.exception.StrolchException;
|
||||
import li.strolch.utils.dbc.DBC;
|
||||
import li.strolch.utils.helper.StringHelper;
|
||||
|
||||
/**
|
||||
|
@ -126,6 +127,11 @@ public class Locator {
|
|||
this.pathElements = Collections.unmodifiableList(fullPath);
|
||||
}
|
||||
|
||||
public String get(int part) {
|
||||
DBC.PRE.assertTrue("Part outside of locator range: " + part, part < this.pathElements.size());
|
||||
return this.pathElements.get(part);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the immutable list of path elements making up this locator
|
||||
*
|
||||
|
@ -155,7 +161,7 @@ public class Locator {
|
|||
public Locator append(List<String> subPathElements) {
|
||||
return new Locator(this.pathElements, subPathElements);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a new {@link Locator} where the given sub path is appended to the locator
|
||||
*
|
||||
|
|
|
@ -346,6 +346,33 @@ public class ModelGenerator {
|
|||
return orders;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a list of {@link Activity Activities} with the given values and adds a {@link ParameterBag} by calling
|
||||
* {@link #createParameterBag(String, String, String)}
|
||||
*
|
||||
* @param idStart
|
||||
* id range start
|
||||
* @param count
|
||||
* the number of elements to create
|
||||
* @param idPrefix
|
||||
* the prefix to generate IDs for the {@link Activity Activities}
|
||||
* @param name
|
||||
* the name of the {@link Activity}
|
||||
* @param type
|
||||
* the type of the {@link Activity}
|
||||
*
|
||||
* @return the list of newly created {@link Activity Activities}
|
||||
*/
|
||||
|
||||
public static List<Activity> createActivities(int idStart, int count, String idPrefix, String name, String type) {
|
||||
List<Activity> activities = new ArrayList<>();
|
||||
for (int i = 0; i < count; i++) {
|
||||
String id = StringHelper.normalizeLength(String.valueOf((i + idStart)), 8, true, '0');
|
||||
activities.add(createActivity(idPrefix + id, name + " " + i, type));
|
||||
}
|
||||
return activities;
|
||||
}
|
||||
|
||||
public static Activity createActivity(String id, String name, String type) {
|
||||
|
||||
Activity rootActivity = new Activity(id, name, type);
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
*/
|
||||
package li.strolch.model;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Date;
|
||||
|
||||
import li.strolch.exception.StrolchPolicyException;
|
||||
|
@ -86,8 +87,11 @@ public class Order extends GroupedParameterizedElement implements StrolchRootEle
|
|||
|
||||
@Override
|
||||
public void setVersion(Version version) throws IllegalArgumentException, IllegalStateException {
|
||||
if (this.version != null)
|
||||
this.version.validateIsNext(version);
|
||||
if (version != null && !getLocator().equals(version.getLocator())) {
|
||||
String msg = "Illegal version as locator is not same: Element: {0} Version: {1}";
|
||||
throw new IllegalArgumentException(MessageFormat.format(msg, getLocator(), version));
|
||||
}
|
||||
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
*/
|
||||
package li.strolch.model;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
|
@ -66,8 +67,11 @@ public class Resource extends GroupedParameterizedElement implements StrolchRoot
|
|||
|
||||
@Override
|
||||
public void setVersion(Version version) throws IllegalArgumentException, IllegalStateException {
|
||||
if (this.version != null)
|
||||
this.version.validateIsNext(version);
|
||||
if (version != null && !getLocator().equals(version.getLocator())) {
|
||||
String msg = "Illegal version as locator is not same: Element: {0} Version: {1}";
|
||||
throw new IllegalArgumentException(MessageFormat.format(msg, getLocator(), version));
|
||||
}
|
||||
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
|
@ -140,6 +144,7 @@ public class Resource extends GroupedParameterizedElement implements StrolchRoot
|
|||
@Override
|
||||
public Resource getClone() {
|
||||
Resource clone = new Resource();
|
||||
|
||||
super.fillClone(clone);
|
||||
|
||||
if (this.timedStateMap != null) {
|
||||
|
|
|
@ -34,23 +34,16 @@ public interface StrolchRootElement extends StrolchElement, PolicyContainer, Par
|
|||
|
||||
/**
|
||||
* <p>
|
||||
* Sets the version of this object.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* <b>Note:</b> If the version is set, then the new version must have the {@link Version#getVersion()} be an
|
||||
* increment to the current version!
|
||||
* Sets the version of this object
|
||||
* </p>
|
||||
*
|
||||
* @param version
|
||||
* the version to set
|
||||
*
|
||||
* @throws IllegalArgumentException
|
||||
* if the given version's locator is not equal to the current version's locator
|
||||
* @throws IllegalStateException
|
||||
* if the given version is not the next version (an increment)
|
||||
* if the given version's locator is not equal to the current element's locator
|
||||
*/
|
||||
public void setVersion(Version version) throws IllegalArgumentException, IllegalStateException;
|
||||
public void setVersion(Version version) throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Visitor pattern accept method. Takes a {@link StrolchRootElementVisitor} to visit this element
|
||||
|
|
|
@ -20,6 +20,10 @@ import li.strolch.utils.dbc.DBC;
|
|||
* A version has a flag <code>delete</code> which, if true, designates that this version was removed
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* A {@link Version} is immutable
|
||||
* </p>
|
||||
*
|
||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||
*/
|
||||
public class Version {
|
||||
|
@ -34,12 +38,12 @@ public class Version {
|
|||
* Creates a new version instance with the given values. The creation date is now.
|
||||
*
|
||||
* @param version
|
||||
* the integer version which must be > 0 and should be incremented for each new version of an object
|
||||
* the integer version which must be >= 0 and should be incremented for each new version of an object
|
||||
* @param createdBy
|
||||
* the username of the creator of this object
|
||||
*/
|
||||
public Version(Locator locator, int version, String createdBy, boolean deleted) {
|
||||
DBC.PRE.assertTrue("Version must by > 0", version > 0);
|
||||
DBC.PRE.assertTrue("Version must by >= 0", version >= 0);
|
||||
DBC.PRE.assertNotNull("locator must be set!", locator);
|
||||
DBC.PRE.assertNotNull("createdBy must be set!", createdBy);
|
||||
this.locator = locator;
|
||||
|
@ -54,7 +58,7 @@ public class Version {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the integer version, which is > 0
|
||||
* Returns the integer version, which is >= 0
|
||||
*
|
||||
* @return the version
|
||||
*/
|
||||
|
@ -123,7 +127,7 @@ public class Version {
|
|||
}
|
||||
|
||||
/**
|
||||
* Validates that the given argument is an increment to this version
|
||||
* Validates that the given argument is a newer version to this version
|
||||
*
|
||||
* @param other
|
||||
* the other version to check
|
||||
|
@ -133,14 +137,14 @@ public class Version {
|
|||
* @throws IllegalStateException
|
||||
* if the given argument is not the next version
|
||||
*/
|
||||
public void validateIsNext(Version other) throws IllegalArgumentException, IllegalStateException {
|
||||
public void validateIsNewer(Version other) throws IllegalArgumentException, IllegalStateException {
|
||||
if (!this.locator.equals(other.locator)) {
|
||||
String msg = "Other version {0} is not for same object: {1}";
|
||||
throw new IllegalArgumentException(MessageFormat.format(msg, other, this.version));
|
||||
}
|
||||
|
||||
if (other.version != this.version + 1) {
|
||||
String msg = "Other version: {0} is not an increment to this version: {1}";
|
||||
if (this.version >= other.version) {
|
||||
String msg = "Other version: {0} is a newer version of this version: {1}";
|
||||
throw new IllegalArgumentException(MessageFormat.format(msg, other, this.version));
|
||||
}
|
||||
}
|
||||
|
@ -161,4 +165,80 @@ public class Version {
|
|||
builder.append("]");
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next version, i.e. this version incremented by 1
|
||||
*
|
||||
* @param username
|
||||
* the username to set
|
||||
* @param deleted
|
||||
* the deleted flag to set
|
||||
*
|
||||
* @return the next version
|
||||
*/
|
||||
public Version next(String username, boolean deleted) {
|
||||
return new Version(this.locator, getNextVersion(), username, deleted);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the initial version = 0 for the given element which is also set to not deleted
|
||||
*
|
||||
* @param element
|
||||
* the element for which to create a new version
|
||||
* @param username
|
||||
* the username of the user who created this version of the object
|
||||
*/
|
||||
public static void setInitialVersionFor(StrolchRootElement element, String username) {
|
||||
Version version = new Version(element.getLocator(), 0, username, false);
|
||||
element.setVersion(version);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a new version on the given element. If the element has no version yet, then the result will be version 0,
|
||||
* otherwise the version will be an increment to the current version
|
||||
*
|
||||
* @param element
|
||||
* the element for which to create a new version
|
||||
* @param username
|
||||
* the username of the user who created this version of the object
|
||||
* @param deleted
|
||||
* if true, then the version will be marked as deleted, i.e. this object was removed from the element
|
||||
* maps
|
||||
*/
|
||||
public static void updateVersionFor(StrolchRootElement element, String username, boolean deleted) {
|
||||
int v = element.getVersion() == null ? 0 : element.getVersion().getVersion() + 1;
|
||||
Version version = new Version(element.getLocator(), v, username, deleted);
|
||||
element.setVersion(version);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + (this.deleted ? 1231 : 1237);
|
||||
result = prime * result + ((this.locator == null) ? 0 : this.locator.hashCode());
|
||||
result = prime * result + this.version;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
Version other = (Version) obj;
|
||||
if (this.deleted != other.deleted)
|
||||
return false;
|
||||
if (this.locator == null) {
|
||||
if (other.locator != null)
|
||||
return false;
|
||||
} else if (!this.locator.equals(other.locator))
|
||||
return false;
|
||||
if (this.version != other.version)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
*/
|
||||
package li.strolch.model.activity;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
|
@ -78,8 +79,12 @@ public class Activity extends GroupedParameterizedElement
|
|||
public void setVersion(Version version) throws IllegalArgumentException, IllegalStateException {
|
||||
if (!this.isRootElement())
|
||||
throw new IllegalStateException("Can't set the version on non root of " + getLocator());
|
||||
if (this.version != null)
|
||||
this.version.validateIsNext(version);
|
||||
|
||||
if (version != null && !getLocator().equals(version.getLocator())) {
|
||||
String msg = "Illegal version as locator is not same: Element: {0} Version: {1}";
|
||||
throw new IllegalArgumentException(MessageFormat.format(msg, getLocator(), version));
|
||||
}
|
||||
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
|
@ -260,6 +265,7 @@ public class Activity extends GroupedParameterizedElement
|
|||
@Override
|
||||
public Activity getClone() {
|
||||
Activity clone = new Activity();
|
||||
|
||||
super.fillClone(clone);
|
||||
|
||||
if (this.elements == null)
|
||||
|
|
|
@ -18,6 +18,7 @@ package li.strolch.model.visitor;
|
|||
import li.strolch.model.Order;
|
||||
import li.strolch.model.Resource;
|
||||
import li.strolch.model.Tags;
|
||||
import li.strolch.model.activity.Activity;
|
||||
|
||||
/**
|
||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||
|
@ -33,4 +34,9 @@ public class ElementTypeVisitor implements StrolchRootElementVisitor<String> {
|
|||
public String visitResource(Resource resource) {
|
||||
return Tags.RESOURCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String visitActivity(Activity activity) {
|
||||
return Tags.ACTIVITY;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ package li.strolch.model.visitor;
|
|||
|
||||
import li.strolch.model.Order;
|
||||
import li.strolch.model.Resource;
|
||||
import li.strolch.model.activity.Activity;
|
||||
|
||||
/**
|
||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||
|
@ -26,4 +27,6 @@ public interface StrolchRootElementVisitor<T> extends StrolchVisitor {
|
|||
public T visitOrder(Order order);
|
||||
|
||||
public T visitResource(Resource resource);
|
||||
|
||||
public T visitActivity(Activity activity);
|
||||
}
|
||||
|
|
|
@ -21,8 +21,10 @@ import java.sql.PreparedStatement;
|
|||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.SQLXML;
|
||||
import java.sql.Timestamp;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.List;
|
||||
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
|
@ -30,6 +32,9 @@ import javax.xml.parsers.SAXParser;
|
|||
import javax.xml.parsers.SAXParserFactory;
|
||||
import javax.xml.transform.sax.SAXResult;
|
||||
|
||||
import org.xml.sax.ContentHandler;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import li.strolch.model.Tags;
|
||||
import li.strolch.model.activity.Activity;
|
||||
import li.strolch.model.query.ActivityQuery;
|
||||
|
@ -39,9 +44,6 @@ import li.strolch.model.xml.XmlModelSaxReader;
|
|||
import li.strolch.persistence.api.ActivityDao;
|
||||
import li.strolch.persistence.api.StrolchPersistenceException;
|
||||
|
||||
import org.xml.sax.ContentHandler;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
@SuppressWarnings("nls")
|
||||
public class PostgreSqlActivityDao extends PostgresqlDao<Activity> implements ActivityDao {
|
||||
|
||||
|
@ -68,22 +70,22 @@ public class PostgreSqlActivityDao extends PostgresqlDao<Activity> implements Ac
|
|||
SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
|
||||
parser.parse(binaryStream, new XmlModelSaxReader(listener));
|
||||
} catch (SQLException | IOException | SAXException | ParserConfigurationException e) {
|
||||
throw new StrolchPersistenceException(MessageFormat.format(
|
||||
"Failed to extract Activity from sqlxml value for {0} / {1}", id, type), e);
|
||||
throw new StrolchPersistenceException(
|
||||
MessageFormat.format("Failed to extract Activity from sqlxml value for {0} / {1}", id, type), e);
|
||||
}
|
||||
|
||||
if (listener.getActivities().size() == 0)
|
||||
throw new StrolchPersistenceException(MessageFormat.format(
|
||||
"No Activity parsed from sqlxml value for {0} / {1}", id, type));
|
||||
throw new StrolchPersistenceException(
|
||||
MessageFormat.format("No Activity parsed from sqlxml value for {0} / {1}", id, type));
|
||||
if (listener.getActivities().size() > 1)
|
||||
throw new StrolchPersistenceException(MessageFormat.format(
|
||||
"Multiple Activities parsed from sqlxml value for {0} / {1}", id, type));
|
||||
throw new StrolchPersistenceException(
|
||||
MessageFormat.format("Multiple Activities parsed from sqlxml value for {0} / {1}", id, type));
|
||||
|
||||
return listener.getActivities().get(0);
|
||||
}
|
||||
|
||||
protected SQLXML createSqlXml(Activity activity, PreparedStatement preparedStatement) throws SQLException,
|
||||
SAXException {
|
||||
protected SQLXML createSqlXml(Activity activity, PreparedStatement preparedStatement)
|
||||
throws SQLException, SAXException {
|
||||
SQLXML sqlxml = tx().getConnection().createSQLXML();
|
||||
SAXResult saxResult = sqlxml.setResult(SAXResult.class);
|
||||
ContentHandler contentHandler = saxResult.getHandler();
|
||||
|
@ -95,14 +97,29 @@ public class PostgreSqlActivityDao extends PostgresqlDao<Activity> implements Ac
|
|||
|
||||
@Override
|
||||
protected void internalSave(final Activity activity) {
|
||||
String sql = "insert into " + getTableName() + " (id, name, type, asxml) values (?, ?, ?, ?)";
|
||||
|
||||
String sql = "insert into " + getTableName()
|
||||
+ " (id, version, created_by, created_at, deleted, latest, name, type, asxml) values (?, ?, ?, ?, ?, true, ?, ?, ?)";
|
||||
|
||||
try (PreparedStatement preparedStatement = tx().getConnection().prepareStatement(sql)) {
|
||||
|
||||
// id
|
||||
preparedStatement.setString(1, activity.getId());
|
||||
preparedStatement.setString(2, activity.getName());
|
||||
preparedStatement.setString(3, activity.getType());
|
||||
|
||||
// version
|
||||
preparedStatement.setInt(2, activity.getVersion().getVersion());
|
||||
preparedStatement.setString(3, activity.getVersion().getCreatedBy());
|
||||
preparedStatement.setTimestamp(4, new Timestamp(activity.getVersion().getCreatedAt().getTime()),
|
||||
Calendar.getInstance());
|
||||
preparedStatement.setBoolean(5, activity.getVersion().isDeleted());
|
||||
|
||||
// attributes
|
||||
preparedStatement.setString(6, activity.getName());
|
||||
preparedStatement.setString(7, activity.getType());
|
||||
|
||||
SQLXML sqlxml = createSqlXml(activity, preparedStatement);
|
||||
preparedStatement.setSQLXML(4, sqlxml);
|
||||
preparedStatement.setSQLXML(8, sqlxml);
|
||||
|
||||
try {
|
||||
int modCount = preparedStatement.executeUpdate();
|
||||
if (modCount != 1) {
|
||||
|
@ -118,19 +135,79 @@ public class PostgreSqlActivityDao extends PostgresqlDao<Activity> implements Ac
|
|||
throw new StrolchPersistenceException(MessageFormat.format("Failed to insert Activity {0} due to {1}",
|
||||
activity.getLocator(), e.getLocalizedMessage()), e);
|
||||
}
|
||||
|
||||
if (activity.getVersion().isFirstVersion()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// and set the previous version to not be latest anymore
|
||||
sql = "update " + getTableName() + " SET latest = false WHERE id = ? AND version = ?";
|
||||
try (PreparedStatement preparedStatement = tx().getConnection().prepareStatement(sql)) {
|
||||
|
||||
// primary key
|
||||
preparedStatement.setString(1, activity.getId());
|
||||
preparedStatement.setInt(2, activity.getVersion().getPreviousVersion());
|
||||
|
||||
int modCount = preparedStatement.executeUpdate();
|
||||
if (modCount != 1) {
|
||||
String msg = "Expected to update 1 previous element with id {0} and version {1} but SQL statement modified {2} elements!";
|
||||
msg = MessageFormat.format(msg, activity.getId(), activity.getVersion().getPreviousVersion(), modCount);
|
||||
throw new StrolchPersistenceException(msg);
|
||||
}
|
||||
|
||||
} catch (SQLException e) {
|
||||
throw new StrolchPersistenceException(
|
||||
MessageFormat.format("Failed to update previous version of Activity {0} due to {1}",
|
||||
activity.getVersion(), e.getLocalizedMessage()),
|
||||
e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void internalUpdate(final Activity activity) {
|
||||
String sql = "update " + getTableName() + " set name = ?, type = ?, asxml = ? where id = ? ";
|
||||
|
||||
// with versioning we save a new object
|
||||
if (tx().getRealm().isVersioningEnabled()) {
|
||||
internalSave(activity);
|
||||
return;
|
||||
}
|
||||
|
||||
// make sure is first version when versioning is not enabled
|
||||
if (!activity.getVersion().isFirstVersion()) {
|
||||
throw new StrolchPersistenceException(MessageFormat.format(
|
||||
"Versioning is not enabled, so version must always be 0 to perform an update, but it is {0}",
|
||||
activity.getVersion()));
|
||||
}
|
||||
|
||||
// and also not marked as deleted!
|
||||
if (activity.getVersion().isDeleted()) {
|
||||
throw new StrolchPersistenceException(
|
||||
MessageFormat.format("Versioning is not enabled, so version can not be marked as deleted for {0}",
|
||||
activity.getVersion()));
|
||||
}
|
||||
|
||||
String sql = "update " + getTableName()
|
||||
+ " set created_by = ?, created_at = ?, deleted = ?, latest = true, name = ?, type = ?, asxml = ? where id = ? and version = ?";
|
||||
|
||||
try (PreparedStatement preparedStatement = tx().getConnection().prepareStatement(sql)) {
|
||||
|
||||
preparedStatement.setString(1, activity.getName());
|
||||
preparedStatement.setString(2, activity.getType());
|
||||
preparedStatement.setString(4, activity.getId());
|
||||
// version
|
||||
preparedStatement.setString(1, activity.getVersion().getCreatedBy());
|
||||
preparedStatement.setTimestamp(2, new Timestamp(activity.getVersion().getCreatedAt().getTime()),
|
||||
Calendar.getInstance());
|
||||
preparedStatement.setBoolean(3, activity.getVersion().isDeleted());
|
||||
|
||||
// attributes
|
||||
preparedStatement.setString(4, activity.getName());
|
||||
preparedStatement.setString(5, activity.getType());
|
||||
|
||||
SQLXML sqlxml = createSqlXml(activity, preparedStatement);
|
||||
preparedStatement.setSQLXML(3, sqlxml);
|
||||
preparedStatement.setSQLXML(6, sqlxml);
|
||||
|
||||
// primary key
|
||||
preparedStatement.setString(7, activity.getId());
|
||||
preparedStatement.setInt(8, activity.getVersion().getVersion());
|
||||
|
||||
try {
|
||||
int modCount = preparedStatement.executeUpdate();
|
||||
if (modCount != 1) {
|
||||
|
|
|
@ -45,7 +45,7 @@ import li.strolch.persistence.api.OrderDao;
|
|||
import li.strolch.persistence.api.StrolchPersistenceException;
|
||||
|
||||
@SuppressWarnings("nls")
|
||||
public class PostgreSqlOrderDao extends PostgresqlXmlDao<Order> implements OrderDao {
|
||||
public class PostgreSqlOrderDao extends PostgresqlDao<Order> implements OrderDao {
|
||||
|
||||
public static final String ORDERS = "orders";
|
||||
|
||||
|
@ -96,17 +96,31 @@ public class PostgreSqlOrderDao extends PostgresqlXmlDao<Order> implements Order
|
|||
|
||||
@Override
|
||||
protected void internalSave(final Order order) {
|
||||
|
||||
String sql = "insert into " + getTableName()
|
||||
+ " (id, name, type, state, date, asxml) values (?, ?, ?, ?::order_state, ?, ?)";
|
||||
+ " (id, version, created_by, created_at, deleted, latest, name, type, state, date, asxml) values (?, ?, ?, ?, ?, true, ?, ?, ?::order_state, ?, ?)";
|
||||
|
||||
try (PreparedStatement preparedStatement = tx().getConnection().prepareStatement(sql)) {
|
||||
|
||||
// id
|
||||
preparedStatement.setString(1, order.getId());
|
||||
preparedStatement.setString(2, order.getName());
|
||||
preparedStatement.setString(3, order.getType());
|
||||
preparedStatement.setString(4, order.getState().name());
|
||||
preparedStatement.setTimestamp(5, new Timestamp(order.getDate().getTime()), Calendar.getInstance());
|
||||
|
||||
// version
|
||||
preparedStatement.setInt(2, order.getVersion().getVersion());
|
||||
preparedStatement.setString(3, order.getVersion().getCreatedBy());
|
||||
preparedStatement.setTimestamp(4, new Timestamp(order.getVersion().getCreatedAt().getTime()),
|
||||
Calendar.getInstance());
|
||||
preparedStatement.setBoolean(5, order.getVersion().isDeleted());
|
||||
|
||||
// attributes
|
||||
preparedStatement.setString(6, order.getName());
|
||||
preparedStatement.setString(7, order.getType());
|
||||
preparedStatement.setString(8, order.getState().name());
|
||||
preparedStatement.setTimestamp(9, new Timestamp(order.getDate().getTime()), Calendar.getInstance());
|
||||
|
||||
SQLXML sqlxml = createSqlXml(order, preparedStatement);
|
||||
preparedStatement.setSQLXML(6, sqlxml);
|
||||
preparedStatement.setSQLXML(10, sqlxml);
|
||||
|
||||
try {
|
||||
int modCount = preparedStatement.executeUpdate();
|
||||
if (modCount != 1) {
|
||||
|
@ -120,29 +134,87 @@ public class PostgreSqlOrderDao extends PostgresqlXmlDao<Order> implements Order
|
|||
|
||||
} catch (SQLException | SAXException e) {
|
||||
throw new StrolchPersistenceException(MessageFormat.format("Failed to insert Order {0} due to {1}",
|
||||
order.getLocator(), e.getLocalizedMessage()), e);
|
||||
order.getVersion(), e.getLocalizedMessage()), e);
|
||||
}
|
||||
|
||||
if (order.getVersion().isFirstVersion()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// and set the previous version to not be latest anymore
|
||||
sql = "update " + getTableName() + " SET latest = false WHERE id = ? AND version = ?";
|
||||
try (PreparedStatement preparedStatement = tx().getConnection().prepareStatement(sql)) {
|
||||
|
||||
// primary key
|
||||
preparedStatement.setString(1, order.getId());
|
||||
preparedStatement.setInt(2, order.getVersion().getPreviousVersion());
|
||||
|
||||
int modCount = preparedStatement.executeUpdate();
|
||||
if (modCount != 1) {
|
||||
String msg = "Expected to update 1 previous element with id {0} and version {1} but SQL statement modified {2} elements!";
|
||||
msg = MessageFormat.format(msg, order.getId(), order.getVersion().getPreviousVersion(), modCount);
|
||||
throw new StrolchPersistenceException(msg);
|
||||
}
|
||||
|
||||
} catch (SQLException e) {
|
||||
throw new StrolchPersistenceException(
|
||||
MessageFormat.format("Failed to update previous version of Order {0} due to {1}",
|
||||
order.getVersion(), e.getLocalizedMessage()),
|
||||
e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void internalUpdate(final Order order) {
|
||||
|
||||
// with versioning we save a new object
|
||||
if (tx().getRealm().isVersioningEnabled()) {
|
||||
internalSave(order);
|
||||
return;
|
||||
}
|
||||
|
||||
// make sure is first version when versioning is not enabled
|
||||
if (!order.getVersion().isFirstVersion()) {
|
||||
throw new StrolchPersistenceException(MessageFormat.format(
|
||||
"Versioning is not enabled, so version must always be 0 to perform an update, but it is {0}",
|
||||
order.getVersion()));
|
||||
}
|
||||
|
||||
// and also not marked as deleted!
|
||||
if (order.getVersion().isDeleted()) {
|
||||
throw new StrolchPersistenceException(MessageFormat.format(
|
||||
"Versioning is not enabled, so version can not be marked as deleted for {0}", order.getVersion()));
|
||||
}
|
||||
|
||||
// now we update the existing object
|
||||
String sql = "update " + getTableName()
|
||||
+ " set name = ?, type = ?, state = ?::order_state, date = ?, asxml = ? where id = ? ";
|
||||
+ " set created_by = ?, created_at = ?, deleted = ?, latest = true, name = ?, type = ?, state = ?::order_state, date = ?, asxml = ? where id = ? and version = ?";
|
||||
try (PreparedStatement preparedStatement = tx().getConnection().prepareStatement(sql)) {
|
||||
|
||||
preparedStatement.setString(1, order.getName());
|
||||
preparedStatement.setString(2, order.getType());
|
||||
preparedStatement.setString(3, order.getState().name());
|
||||
preparedStatement.setTimestamp(4, new Timestamp(order.getDate().getTime()), Calendar.getInstance());
|
||||
preparedStatement.setString(6, order.getId());
|
||||
// version
|
||||
preparedStatement.setString(1, order.getVersion().getCreatedBy());
|
||||
preparedStatement.setTimestamp(2, new Timestamp(order.getVersion().getCreatedAt().getTime()),
|
||||
Calendar.getInstance());
|
||||
preparedStatement.setBoolean(3, order.getVersion().isDeleted());
|
||||
|
||||
// attributes
|
||||
preparedStatement.setString(4, order.getName());
|
||||
preparedStatement.setString(5, order.getType());
|
||||
preparedStatement.setString(6, order.getState().name());
|
||||
preparedStatement.setTimestamp(7, new Timestamp(order.getDate().getTime()), Calendar.getInstance());
|
||||
|
||||
SQLXML sqlxml = createSqlXml(order, preparedStatement);
|
||||
preparedStatement.setSQLXML(5, sqlxml);
|
||||
preparedStatement.setSQLXML(8, sqlxml);
|
||||
|
||||
// primary key
|
||||
preparedStatement.setString(9, order.getId());
|
||||
preparedStatement.setInt(10, order.getVersion().getVersion());
|
||||
|
||||
try {
|
||||
int modCount = preparedStatement.executeUpdate();
|
||||
if (modCount != 1) {
|
||||
String msg = "Expected to update 1 element with id {0} but SQL statement modified {1} elements!";
|
||||
msg = MessageFormat.format(msg, order.getId(), modCount);
|
||||
String msg = "Expected to update 1 element with id {0} and version {1} but SQL statement modified {2} elements!";
|
||||
msg = MessageFormat.format(msg, order.getId(), order.getVersion().getVersion(), modCount);
|
||||
throw new StrolchPersistenceException(msg);
|
||||
}
|
||||
} finally {
|
||||
|
|
|
@ -100,7 +100,7 @@ public abstract class PostgreSqlQueryVisitor
|
|||
return this.sqlAsString;
|
||||
}
|
||||
|
||||
this.sql.append("type = ? AND\n");
|
||||
this.sql.append("type = ? AND latest = true AND\n");
|
||||
this.sql.append(this.sb.toString());
|
||||
|
||||
appendOrdering();
|
||||
|
|
|
@ -21,8 +21,10 @@ import java.sql.PreparedStatement;
|
|||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.SQLXML;
|
||||
import java.sql.Timestamp;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.List;
|
||||
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
|
@ -30,6 +32,9 @@ import javax.xml.parsers.SAXParser;
|
|||
import javax.xml.parsers.SAXParserFactory;
|
||||
import javax.xml.transform.sax.SAXResult;
|
||||
|
||||
import org.xml.sax.ContentHandler;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import li.strolch.model.Resource;
|
||||
import li.strolch.model.Tags;
|
||||
import li.strolch.model.query.ResourceQuery;
|
||||
|
@ -39,9 +44,6 @@ import li.strolch.model.xml.XmlModelSaxReader;
|
|||
import li.strolch.persistence.api.ResourceDao;
|
||||
import li.strolch.persistence.api.StrolchPersistenceException;
|
||||
|
||||
import org.xml.sax.ContentHandler;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
@SuppressWarnings("nls")
|
||||
public class PostgreSqlResourceDao extends PostgresqlDao<Resource> implements ResourceDao {
|
||||
|
||||
|
@ -68,16 +70,16 @@ public class PostgreSqlResourceDao extends PostgresqlDao<Resource> implements Re
|
|||
SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
|
||||
parser.parse(binaryStream, new XmlModelSaxReader(listener));
|
||||
} catch (SQLException | IOException | SAXException | ParserConfigurationException e) {
|
||||
throw new StrolchPersistenceException(MessageFormat.format(
|
||||
"Failed to extract Resource from sqlxml value for {0} / {1}", id, type), e);
|
||||
throw new StrolchPersistenceException(
|
||||
MessageFormat.format("Failed to extract Resource from sqlxml value for {0} / {1}", id, type), e);
|
||||
}
|
||||
|
||||
if (listener.getResources().size() == 0)
|
||||
throw new StrolchPersistenceException(MessageFormat.format(
|
||||
"No Resource parsed from sqlxml value for {0} / {1}", id, type));
|
||||
throw new StrolchPersistenceException(
|
||||
MessageFormat.format("No Resource parsed from sqlxml value for {0} / {1}", id, type));
|
||||
if (listener.getResources().size() > 1)
|
||||
throw new StrolchPersistenceException(MessageFormat.format(
|
||||
"Multiple Resources parsed from sqlxml value for {0} / {1}", id, type));
|
||||
throw new StrolchPersistenceException(
|
||||
MessageFormat.format("Multiple Resources parsed from sqlxml value for {0} / {1}", id, type));
|
||||
|
||||
return listener.getResources().get(0);
|
||||
}
|
||||
|
@ -94,14 +96,26 @@ public class PostgreSqlResourceDao extends PostgresqlDao<Resource> implements Re
|
|||
|
||||
@Override
|
||||
protected void internalSave(final Resource res) {
|
||||
String sql = "insert into " + getTableName() + " (id, name, type, asxml) values (?, ?, ?, ?)";
|
||||
String sql = "insert into " + getTableName()
|
||||
+ " (id, version, created_by, created_at, deleted, latest, name, type, asxml) values (?, ?, ?, ?, ?, true, ?, ?, ?)";
|
||||
try (PreparedStatement preparedStatement = tx().getConnection().prepareStatement(sql)) {
|
||||
|
||||
// id
|
||||
preparedStatement.setString(1, res.getId());
|
||||
preparedStatement.setString(2, res.getName());
|
||||
preparedStatement.setString(3, res.getType());
|
||||
|
||||
// version
|
||||
preparedStatement.setInt(2, res.getVersion().getVersion());
|
||||
preparedStatement.setString(3, res.getVersion().getCreatedBy());
|
||||
preparedStatement.setTimestamp(4, new Timestamp(res.getVersion().getCreatedAt().getTime()),
|
||||
Calendar.getInstance());
|
||||
preparedStatement.setBoolean(5, res.getVersion().isDeleted());
|
||||
|
||||
// attributes
|
||||
preparedStatement.setString(6, res.getName());
|
||||
preparedStatement.setString(7, res.getType());
|
||||
|
||||
SQLXML sqlxml = createSqlXml(res, preparedStatement);
|
||||
preparedStatement.setSQLXML(4, sqlxml);
|
||||
preparedStatement.setSQLXML(8, sqlxml);
|
||||
try {
|
||||
int modCount = preparedStatement.executeUpdate();
|
||||
if (modCount != 1) {
|
||||
|
@ -117,24 +131,82 @@ public class PostgreSqlResourceDao extends PostgresqlDao<Resource> implements Re
|
|||
throw new StrolchPersistenceException(MessageFormat.format("Failed to insert Resource {0} due to {1}",
|
||||
res.getLocator(), e.getLocalizedMessage()), e);
|
||||
}
|
||||
|
||||
if (res.getVersion().isFirstVersion()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// and set the previous version to not be latest anymore
|
||||
sql = "update " + getTableName() + " SET latest = false WHERE id = ? AND version = ?";
|
||||
try (PreparedStatement preparedStatement = tx().getConnection().prepareStatement(sql)) {
|
||||
|
||||
// primary key
|
||||
preparedStatement.setString(1, res.getId());
|
||||
preparedStatement.setInt(2, res.getVersion().getPreviousVersion());
|
||||
|
||||
int modCount = preparedStatement.executeUpdate();
|
||||
if (modCount != 1) {
|
||||
String msg = "Expected to update 1 previous element with id {0} and version {1} but SQL statement modified {2} elements!";
|
||||
msg = MessageFormat.format(msg, res.getId(), res.getVersion().getPreviousVersion(), modCount);
|
||||
throw new StrolchPersistenceException(msg);
|
||||
}
|
||||
|
||||
} catch (SQLException e) {
|
||||
throw new StrolchPersistenceException(MessageFormat.format("Failed to insert Resource {0} due to {1}",
|
||||
res.getLocator(), e.getLocalizedMessage()), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void internalUpdate(final Resource resource) {
|
||||
String sql = "update " + getTableName() + " set name = ?, type = ?, asxml = ? where id = ? ";
|
||||
|
||||
// with versioning we save a new object
|
||||
if (tx().getRealm().isVersioningEnabled()) {
|
||||
internalSave(resource);
|
||||
return;
|
||||
}
|
||||
|
||||
// make sure is first version when versioning is not enabled
|
||||
if (!resource.getVersion().isFirstVersion()) {
|
||||
throw new StrolchPersistenceException(MessageFormat.format(
|
||||
"Versioning is not enabled, so version must always be 0 to perform an update, but it is {0}",
|
||||
resource.getVersion()));
|
||||
}
|
||||
|
||||
// and also not marked as deleted!
|
||||
if (resource.getVersion().isDeleted()) {
|
||||
throw new StrolchPersistenceException(
|
||||
MessageFormat.format("Versioning is not enabled, so version can not be marked as deleted for {0}",
|
||||
resource.getVersion()));
|
||||
}
|
||||
|
||||
// now we update the existing object
|
||||
String sql = "update " + getTableName()
|
||||
+ " set created_by = ?, created_at = ?, deleted = ?, latest = true, name = ?, type = ?, asxml = ? where id = ? and version = ?";
|
||||
try (PreparedStatement preparedStatement = tx().getConnection().prepareStatement(sql)) {
|
||||
|
||||
preparedStatement.setString(1, resource.getName());
|
||||
preparedStatement.setString(2, resource.getType());
|
||||
preparedStatement.setString(4, resource.getId());
|
||||
// version
|
||||
preparedStatement.setString(1, resource.getVersion().getCreatedBy());
|
||||
preparedStatement.setTimestamp(2, new Timestamp(resource.getVersion().getCreatedAt().getTime()),
|
||||
Calendar.getInstance());
|
||||
preparedStatement.setBoolean(3, resource.getVersion().isDeleted());
|
||||
|
||||
// attributes
|
||||
preparedStatement.setString(4, resource.getName());
|
||||
preparedStatement.setString(5, resource.getType());
|
||||
|
||||
SQLXML sqlxml = createSqlXml(resource, preparedStatement);
|
||||
preparedStatement.setSQLXML(3, sqlxml);
|
||||
preparedStatement.setSQLXML(6, sqlxml);
|
||||
|
||||
// primary key
|
||||
preparedStatement.setString(7, resource.getId());
|
||||
preparedStatement.setInt(8, resource.getVersion().getVersion());
|
||||
|
||||
try {
|
||||
int modCount = preparedStatement.executeUpdate();
|
||||
if (modCount != 1) {
|
||||
String msg = "Expected to update 1 element with id {0} but SQL statement modified {1} elements!";
|
||||
msg = MessageFormat.format(msg, resource.getId(), modCount);
|
||||
String msg = "Expected to update 1 element with id {0} and version {1} but SQL statement modified {2} elements!";
|
||||
msg = MessageFormat.format(msg, resource.getId(), resource.getVersion().getVersion(), modCount);
|
||||
throw new StrolchPersistenceException(msg);
|
||||
}
|
||||
} finally {
|
||||
|
|
|
@ -17,6 +17,9 @@ package li.strolch.persistence.postgresql;
|
|||
|
||||
import java.sql.Connection;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import li.strolch.agent.api.StrolchRealm;
|
||||
import li.strolch.persistence.api.AbstractTransaction;
|
||||
import li.strolch.persistence.api.ActivityDao;
|
||||
|
@ -28,9 +31,6 @@ import li.strolch.persistence.api.TransactionResult;
|
|||
import li.strolch.privilege.model.Certificate;
|
||||
import li.strolch.runtime.privilege.PrivilegeHandler;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class PostgreSqlStrolchTransaction extends AbstractTransaction {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(PostgreSqlStrolchTransaction.class);
|
||||
|
@ -56,6 +56,8 @@ public class PostgreSqlStrolchTransaction extends AbstractTransaction {
|
|||
this.orderDao.commit(txResult);
|
||||
if (this.resourceDao != null)
|
||||
this.resourceDao.commit(txResult);
|
||||
if (this.activityDao != null)
|
||||
this.activityDao.commit(txResult);
|
||||
|
||||
// don't commit the connection, this is done in postCommit when we close the connection
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ import li.strolch.persistence.api.TransactionResult;
|
|||
@SuppressWarnings("nls")
|
||||
public abstract class PostgresqlDao<T extends StrolchRootElement> implements StrolchDao<T> {
|
||||
|
||||
protected PostgreSqlStrolchTransaction tx;
|
||||
private PostgreSqlStrolchTransaction tx;
|
||||
protected List<DaoCommand> commands;
|
||||
|
||||
public PostgresqlDao(PostgreSqlStrolchTransaction tx) {
|
||||
|
@ -179,6 +179,18 @@ public abstract class PostgresqlDao<T extends StrolchRootElement> implements Str
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public T queryBy(String type, String id, int version) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<T> queryVersionsFor(String type, String id) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<T> queryAll() {
|
||||
|
||||
|
@ -225,73 +237,55 @@ public abstract class PostgresqlDao<T extends StrolchRootElement> implements Str
|
|||
|
||||
@Override
|
||||
public void save(final T res) {
|
||||
this.commands.add(new DaoCommand() {
|
||||
@Override
|
||||
public void doComand(TransactionResult txResult) {
|
||||
internalSave(res);
|
||||
txResult.incCreated(1);
|
||||
}
|
||||
this.commands.add(txResult -> {
|
||||
internalSave(res);
|
||||
txResult.incCreated(1);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveAll(final List<T> elements) {
|
||||
this.commands.add(new DaoCommand() {
|
||||
@Override
|
||||
public void doComand(TransactionResult txResult) {
|
||||
for (T element : elements) {
|
||||
internalSave(element);
|
||||
}
|
||||
txResult.incCreated(elements.size());
|
||||
this.commands.add(txResult -> {
|
||||
for (T element : elements) {
|
||||
internalSave(element);
|
||||
}
|
||||
txResult.incCreated(elements.size());
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(final T element) {
|
||||
this.commands.add(new DaoCommand() {
|
||||
@Override
|
||||
public void doComand(TransactionResult txResult) {
|
||||
internalUpdate(element);
|
||||
txResult.incUpdated(1);
|
||||
}
|
||||
this.commands.add(txResult -> {
|
||||
internalUpdate(element);
|
||||
txResult.incUpdated(1);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateAll(final List<T> elements) {
|
||||
this.commands.add(new DaoCommand() {
|
||||
@Override
|
||||
public void doComand(TransactionResult txResult) {
|
||||
for (T element : elements) {
|
||||
internalUpdate(element);
|
||||
}
|
||||
txResult.incUpdated(elements.size());
|
||||
this.commands.add(txResult -> {
|
||||
for (T element : elements) {
|
||||
internalUpdate(element);
|
||||
}
|
||||
txResult.incUpdated(elements.size());
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(final T element) {
|
||||
this.commands.add(new DaoCommand() {
|
||||
@Override
|
||||
public void doComand(TransactionResult txResult) {
|
||||
internalRemove(element);
|
||||
txResult.incDeleted(1);
|
||||
}
|
||||
this.commands.add(txResult -> {
|
||||
internalRemove(element);
|
||||
txResult.incDeleted(1);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAll(final List<T> elements) {
|
||||
this.commands.add(new DaoCommand() {
|
||||
@Override
|
||||
public void doComand(TransactionResult txResult) {
|
||||
for (T element : elements) {
|
||||
internalRemove(element);
|
||||
}
|
||||
txResult.incDeleted(elements.size());
|
||||
this.commands.add(txResult -> {
|
||||
for (T element : elements) {
|
||||
internalRemove(element);
|
||||
}
|
||||
txResult.incDeleted(elements.size());
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -300,12 +294,9 @@ public abstract class PostgresqlDao<T extends StrolchRootElement> implements Str
|
|||
|
||||
final long toRemove = querySize();
|
||||
|
||||
this.commands.add(new DaoCommand() {
|
||||
@Override
|
||||
public void doComand(TransactionResult txResult) {
|
||||
internalRemoveAll(toRemove);
|
||||
txResult.incDeleted(toRemove);
|
||||
}
|
||||
this.commands.add(txResult -> {
|
||||
internalRemoveAll(toRemove);
|
||||
txResult.incDeleted(toRemove);
|
||||
});
|
||||
|
||||
return toRemove;
|
||||
|
@ -316,17 +307,20 @@ public abstract class PostgresqlDao<T extends StrolchRootElement> implements Str
|
|||
|
||||
final long toRemove = querySize(type);
|
||||
|
||||
this.commands.add(new DaoCommand() {
|
||||
@Override
|
||||
public void doComand(TransactionResult txResult) {
|
||||
internalRemoveAllBy(toRemove, type);
|
||||
txResult.incDeleted(toRemove);
|
||||
}
|
||||
this.commands.add(txResult -> {
|
||||
internalRemoveAllBy(toRemove, type);
|
||||
txResult.incDeleted(toRemove);
|
||||
});
|
||||
|
||||
return toRemove;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeVersion(T element) throws StrolchPersistenceException {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param element
|
||||
*/
|
||||
|
@ -366,8 +360,8 @@ public abstract class PostgresqlDao<T extends StrolchRootElement> implements Str
|
|||
}
|
||||
|
||||
} catch (SQLException e) {
|
||||
throw new StrolchPersistenceException(MessageFormat.format("Failed to remove all elements due to {0}",
|
||||
e.getLocalizedMessage()), e);
|
||||
throw new StrolchPersistenceException(
|
||||
MessageFormat.format("Failed to remove all elements due to {0}", e.getLocalizedMessage()), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -383,8 +377,8 @@ public abstract class PostgresqlDao<T extends StrolchRootElement> implements Str
|
|||
}
|
||||
|
||||
} catch (SQLException e) {
|
||||
throw new StrolchPersistenceException(MessageFormat.format(
|
||||
"Failed to remove all elements of type {0} due to {1}", type, e.getLocalizedMessage()), e);
|
||||
throw new StrolchPersistenceException(MessageFormat
|
||||
.format("Failed to remove all elements of type {0} due to {1}", type, e.getLocalizedMessage()), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
package li.strolch.persistence.postgresql;
|
||||
|
||||
import java.sql.SQLXML;
|
||||
|
||||
import li.strolch.model.StrolchRootElement;
|
||||
|
||||
public abstract class PostgresqlXmlDao<T extends StrolchRootElement> extends PostgresqlDao<T> {
|
||||
|
||||
public PostgresqlXmlDao(PostgreSqlStrolchTransaction tx) {
|
||||
super(tx);
|
||||
}
|
||||
|
||||
protected abstract T parseFromXml(String id, String type, SQLXML xml);
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
|
||||
DROP TABLE IF EXISTS resources;
|
||||
DROP TABLE IF EXISTS orders;
|
||||
DROP TABLE IF EXISTS activities;
|
||||
|
||||
DROP TABLE IF EXISTS audits;
|
||||
|
||||
DROP TABLE IF EXISTS db_version;
|
||||
|
||||
DROP TYPE IF EXISTS order_state;
|
||||
DROP TYPE IF EXISTS access_type;
|
|
@ -0,0 +1,131 @@
|
|||
|
||||
-- DB_VERSION
|
||||
CREATE TABLE IF NOT EXISTS db_version (
|
||||
id serial primary key not null,
|
||||
app varchar(255) not null,
|
||||
version varchar(255) not null,
|
||||
description varchar(255) not null,
|
||||
created timestamp with time zone not null
|
||||
);
|
||||
|
||||
-- RESOURCES
|
||||
CREATE TABLE IF NOT EXISTS resources (
|
||||
id varchar(255) not null,
|
||||
version integer not null,
|
||||
created_by varchar(255) not null,
|
||||
created_at timestamp with time zone not null,
|
||||
deleted boolean not null,
|
||||
latest boolean not null,
|
||||
name varchar(255) not null,
|
||||
type varchar(255) not null,
|
||||
asxml xml not null,
|
||||
|
||||
PRIMARY KEY (id, version)
|
||||
);
|
||||
|
||||
-- ORDERS
|
||||
CREATE TYPE order_state AS ENUM ('CREATED', 'OPEN', 'EXECUTION', 'CLOSED');
|
||||
|
||||
CREATE TABLE IF NOT EXISTS orders (
|
||||
id varchar(255) not null,
|
||||
version integer not null,
|
||||
created_by varchar(255) not null,
|
||||
created_at timestamp with time zone not null,
|
||||
deleted boolean,
|
||||
latest boolean not null,
|
||||
name varchar(255),
|
||||
type varchar(255),
|
||||
state order_state,
|
||||
date timestamp with time zone,
|
||||
asxml xml not null,
|
||||
|
||||
PRIMARY KEY (id, version)
|
||||
);
|
||||
|
||||
-- ACTIVITIES
|
||||
CREATE TABLE IF NOT EXISTS activities (
|
||||
id varchar(255) not null,
|
||||
version integer not null,
|
||||
created_by varchar(255) not null,
|
||||
created_at timestamp with time zone not null,
|
||||
deleted boolean not null,
|
||||
latest boolean not null,
|
||||
name varchar(255) not null,
|
||||
type varchar(255) not null,
|
||||
asxml xml not null,
|
||||
|
||||
PRIMARY KEY (id, version)
|
||||
);
|
||||
|
||||
-- AUDITS
|
||||
CREATE TYPE access_type AS ENUM ('READ', 'CREATE', 'UPDATE', 'DELETE');
|
||||
CREATE TABLE IF NOT EXISTS audits (
|
||||
id bigint PRIMARY KEY,
|
||||
username varchar(255) NOT NULL,
|
||||
firstname varchar(255) NOT NULL,
|
||||
lastname varchar(255) NOT NULL,
|
||||
date timestamp with time zone NOT NULL,
|
||||
|
||||
element_type varchar(255) NOT NULL,
|
||||
element_sub_type varchar(255) NOT NULL,
|
||||
element_accessed varchar(255) NOT NULL,
|
||||
new_version timestamp with time zone,
|
||||
|
||||
action varchar(255) NOT NULL,
|
||||
access_type access_type NOT NULL
|
||||
);
|
||||
|
||||
-- set version
|
||||
INSERT INTO db_version
|
||||
(version, app, description, created)
|
||||
values(
|
||||
'0.1.0',
|
||||
'strolch',
|
||||
'Initial schema version',
|
||||
CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
INSERT INTO db_version
|
||||
(version, app, description, created)
|
||||
values(
|
||||
'0.2.0',
|
||||
'strolch',
|
||||
'Added new table for audits',
|
||||
CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
INSERT INTO db_version
|
||||
(version, app, description, created)
|
||||
values(
|
||||
'0.2.1',
|
||||
'strolch',
|
||||
'Added new column app to table table version',
|
||||
CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
INSERT INTO db_version
|
||||
(version, app, description, created)
|
||||
values(
|
||||
'0.3.0',
|
||||
'strolch',
|
||||
'Added new column element_sub_type to table audits',
|
||||
CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
INSERT INTO db_version
|
||||
(version, app, description, created)
|
||||
values(
|
||||
'0.4.0',
|
||||
'strolch',
|
||||
'Added new table activities',
|
||||
CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
INSERT INTO db_version
|
||||
(version, app, description, created)
|
||||
values(
|
||||
'0.5.0',
|
||||
'strolch',
|
||||
'Added versioning to root elements',
|
||||
CURRENT_TIMESTAMP
|
||||
);
|
|
@ -0,0 +1,72 @@
|
|||
|
||||
-- add version columns
|
||||
ALTER TABLE resources ADD COLUMN version integer;
|
||||
ALTER TABLE resources ADD COLUMN created_by varchar(255);
|
||||
ALTER TABLE resources ADD COLUMN created_at timestamp with time zone;
|
||||
ALTER TABLE resources ADD COLUMN deleted boolean;
|
||||
ALTER TABLE resources ADD COLUMN latest boolean;
|
||||
|
||||
ALTER TABLE orders ADD COLUMN version integer;
|
||||
ALTER TABLE orders ADD COLUMN created_by varchar(255);
|
||||
ALTER TABLE orders ADD COLUMN created_at timestamp with time zone;
|
||||
ALTER TABLE orders ADD COLUMN deleted boolean;
|
||||
ALTER TABLE orders ADD COLUMN latest boolean;
|
||||
|
||||
ALTER TABLE activities ADD COLUMN version integer;
|
||||
ALTER TABLE activities ADD COLUMN created_by varchar(255);
|
||||
ALTER TABLE activities ADD COLUMN created_at timestamp with time zone;
|
||||
ALTER TABLE activities ADD COLUMN deleted boolean;
|
||||
ALTER TABLE activities ADD COLUMN latest boolean;
|
||||
|
||||
-- set initial values for new columns
|
||||
UPDATE resources SET version = 0 where version IS NULL;
|
||||
UPDATE resources SET created_by = 'MIGRATION' where version IS NULL;
|
||||
UPDATE resources SET created_at = CURRENT_TIMESTAMP where version IS NULL;
|
||||
UPDATE resources SET deleted = false where version IS NULL;
|
||||
|
||||
UPDATE orders SET version = 0 where version IS NULL;
|
||||
UPDATE orders SET created_by = 'MIGRATION' where version IS NULL;
|
||||
UPDATE orders SET created_at = CURRENT_TIMESTAMP where version IS NULL;
|
||||
UPDATE orders SET deleted = false where version IS NULL;
|
||||
|
||||
UPDATE activities SET version = 0 where version IS NULL;
|
||||
UPDATE activities SET created_by = 'MIGRATION' where version IS NULL;
|
||||
UPDATE activities SET created_at = CURRENT_TIMESTAMP where version IS NULL;
|
||||
UPDATE activities SET deleted = false where version IS NULL;
|
||||
|
||||
-- make columns not null
|
||||
ALTER TABLE resources ALTER COLUMN version SET NOT NULL;
|
||||
ALTER TABLE resources ALTER COLUMN created_by SET NOT NULL;
|
||||
ALTER TABLE resources ALTER COLUMN created_at SET NOT NULL;
|
||||
ALTER TABLE resources ALTER COLUMN latest SET NOT NULL;
|
||||
ALTER TABLE resources ALTER COLUMN deleted SET NOT NULL;
|
||||
|
||||
ALTER TABLE orders ALTER COLUMN version SET NOT NULL;
|
||||
ALTER TABLE orders ALTER COLUMN created_by SET NOT NULL;
|
||||
ALTER TABLE orders ALTER COLUMN created_at SET NOT NULL;
|
||||
ALTER TABLE orders ALTER COLUMN latest SET NOT NULL;
|
||||
ALTER TABLE orders ALTER COLUMN deleted SET NOT NULL;
|
||||
|
||||
ALTER TABLE activities ALTER COLUMN version SET NOT NULL;
|
||||
ALTER TABLE activities ALTER COLUMN created_by SET NOT NULL;
|
||||
ALTER TABLE activities ALTER COLUMN created_at SET NOT NULL;
|
||||
ALTER TABLE activities ALTER COLUMN latest SET NOT NULL;
|
||||
ALTER TABLE activities ALTER COLUMN deleted SET NOT NULL;
|
||||
|
||||
-- change primary key to id, version
|
||||
ALTER TABLE resources DROP CONSTRAINT resources_pkey;
|
||||
ALTER TABLE orders DROP CONSTRAINT orders_pkey;
|
||||
ALTER TABLE activities DROP CONSTRAINT activities_pkey;
|
||||
|
||||
ALTER TABLE resources ADD CONSTRAINT resources_pkey PRIMARY KEY (id, version);
|
||||
ALTER TABLE orders ADD CONSTRAINT orders_pkey PRIMARY KEY (id, version);
|
||||
ALTER TABLE activities ADD CONSTRAINT activities_pkey PRIMARY KEY (id, version);
|
||||
|
||||
INSERT INTO db_version
|
||||
(version, app, description, created)
|
||||
values(
|
||||
'0.5.0',
|
||||
'strolch',
|
||||
'Added versioning to root elements',
|
||||
CURRENT_TIMESTAMP
|
||||
);
|
|
@ -1,2 +1,2 @@
|
|||
# Property file defining what the currently expected version is supposed to be
|
||||
db_version=0.4.0
|
||||
db_version=0.5.0
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
<depends>PrivilegeHandler</depends>
|
||||
<depends>PersistenceHandler</depends>
|
||||
<Properties>
|
||||
<dataStoreMode>TRANSACTIONAL</dataStoreMode>
|
||||
<dataStoreMode>CACHED</dataStoreMode>
|
||||
<enableAuditTrail>true</enableAuditTrail>
|
||||
<enableObserverUpdates>true</enableObserverUpdates>
|
||||
</Properties>
|
||||
|
|
|
@ -22,6 +22,7 @@ import java.util.Set;
|
|||
|
||||
import li.strolch.model.StrolchRootElement;
|
||||
import li.strolch.persistence.api.StrolchDao;
|
||||
import li.strolch.persistence.api.StrolchPersistenceException;
|
||||
import li.strolch.persistence.api.StrolchTransaction;
|
||||
import li.strolch.xmlpers.api.PersistenceTransaction;
|
||||
import li.strolch.xmlpers.objref.IdOfSubTypeRef;
|
||||
|
@ -104,6 +105,18 @@ public abstract class AbstractDao<T extends StrolchRootElement> implements Strol
|
|||
return t;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T queryBy(String type, String id, int version) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<T> queryVersionsFor(String type, String id) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<T> queryAll() {
|
||||
List<T> objects = new ArrayList<>();
|
||||
|
@ -163,4 +176,10 @@ public abstract class AbstractDao<T extends StrolchRootElement> implements Strol
|
|||
SubTypeRef typeRef = getTypeRef(type);
|
||||
return this.tx.getObjectDao().removeAllBy(typeRef);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeVersion(T element) throws StrolchPersistenceException {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("not yet implemented!");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ import li.strolch.utils.dbc.DBC;
|
|||
public class RemoveOrderCommand extends Command {
|
||||
|
||||
private Order order;
|
||||
private boolean removed;
|
||||
|
||||
/**
|
||||
* @param tx
|
||||
|
@ -65,14 +66,16 @@ public class RemoveOrderCommand extends Command {
|
|||
}
|
||||
|
||||
orderMap.remove(tx(), this.order);
|
||||
this.removed = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void undo() {
|
||||
if (this.order != null && tx().isRollingBack()) {
|
||||
OrderMap orderMap = tx().getOrderMap();
|
||||
if (!orderMap.hasElement(tx(), this.order.getType(), this.order.getId()))
|
||||
orderMap.add(tx(), this.order);
|
||||
if (this.order != null && tx().isRollingBack() && this.removed) {
|
||||
if (tx().isVersioningEnabled())
|
||||
tx().getOrderMap().undoVersion(tx(), this.order);
|
||||
else
|
||||
tx().getOrderMap().add(tx(), this.order);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ import li.strolch.utils.dbc.DBC;
|
|||
public class RemoveResourceCommand extends Command {
|
||||
|
||||
private Resource resource;
|
||||
private boolean removed;
|
||||
|
||||
/**
|
||||
* @param tx
|
||||
|
@ -65,14 +66,16 @@ public class RemoveResourceCommand extends Command {
|
|||
}
|
||||
|
||||
resourceMap.remove(tx(), this.resource);
|
||||
this.removed = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void undo() {
|
||||
if (this.resource != null && tx().isRollingBack()) {
|
||||
ResourceMap resourceMap = tx().getResourceMap();
|
||||
if (!resourceMap.hasElement(tx(), this.resource.getType(), this.resource.getId()))
|
||||
resourceMap.add(tx(), this.resource);
|
||||
if (this.resource != null && tx().isRollingBack() && this.removed) {
|
||||
if (tx().isVersioningEnabled())
|
||||
tx().getResourceMap().undoVersion(tx(), this.resource);
|
||||
else
|
||||
tx().getResourceMap().add(tx(), this.resource);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
package li.strolch.command;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import li.strolch.agent.api.ComponentContainer;
|
||||
|
@ -32,7 +33,8 @@ import li.strolch.utils.dbc.DBC;
|
|||
public class UpdateOrderCollectionCommand extends Command {
|
||||
|
||||
private List<Order> orders;
|
||||
private List<Order> replacedElements;
|
||||
private List<Order> replaced;
|
||||
private boolean updated;
|
||||
|
||||
/**
|
||||
* @param tx
|
||||
|
@ -62,22 +64,32 @@ public class UpdateOrderCollectionCommand extends Command {
|
|||
}
|
||||
|
||||
OrderMap orderMap = tx().getOrderMap();
|
||||
this.replaced = new ArrayList<>();
|
||||
for (Order order : this.orders) {
|
||||
if (!orderMap.hasElement(tx(), order.getType(), order.getId())) {
|
||||
Order o = orderMap.getBy(tx(), order.getType(), order.getId());
|
||||
if (o == null) {
|
||||
String msg = "The Order {0} can not be updated as it does not exist!";
|
||||
msg = MessageFormat.format(msg, order.getLocator());
|
||||
throw new StrolchException(msg);
|
||||
}
|
||||
|
||||
this.replaced.add(o);
|
||||
}
|
||||
|
||||
this.replacedElements = orderMap.updateAll(tx(), this.orders);
|
||||
orderMap.updateAll(tx(), this.orders);
|
||||
this.updated = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void undo() {
|
||||
if (this.replacedElements != null && tx().isRollingBack()) {
|
||||
OrderMap orderMap = tx().getOrderMap();
|
||||
orderMap.updateAll(tx(), this.replacedElements);
|
||||
if (this.updated && tx().isRollingBack()) {
|
||||
if (tx().isVersioningEnabled()) {
|
||||
for (Order order : this.orders) {
|
||||
tx().getOrderMap().undoVersion(tx(), order);
|
||||
}
|
||||
} else {
|
||||
tx().getOrderMap().updateAll(tx(), this.replaced);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,7 +31,8 @@ import li.strolch.utils.dbc.DBC;
|
|||
public class UpdateOrderCommand extends Command {
|
||||
|
||||
private Order order;
|
||||
private Order replacedElement;
|
||||
private Order replaced;
|
||||
private boolean updated;
|
||||
|
||||
/**
|
||||
* @param tx
|
||||
|
@ -59,19 +60,24 @@ public class UpdateOrderCommand extends Command {
|
|||
tx().lock(this.order);
|
||||
|
||||
OrderMap orderMap = tx().getOrderMap();
|
||||
if (!orderMap.hasElement(tx(), this.order.getType(), this.order.getId())) {
|
||||
String msg = "The Order {0} can not be updated as it does not exist!";
|
||||
this.replaced = orderMap.getBy(tx(), this.order.getType(), this.order.getId());
|
||||
if (this.replaced == null) {
|
||||
String msg = "The Order {0} can not be updated as it does not exist!!";
|
||||
msg = MessageFormat.format(msg, this.order.getLocator());
|
||||
throw new StrolchException(msg);
|
||||
}
|
||||
|
||||
this.replacedElement = orderMap.update(tx(), this.order);
|
||||
orderMap.update(tx(), this.order);
|
||||
this.updated = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void undo() {
|
||||
if (this.replacedElement != null && tx().isRollingBack()) {
|
||||
tx().getOrderMap().update(tx(), this.replacedElement);
|
||||
if (this.updated && tx().isRollingBack()) {
|
||||
if (tx().isVersioningEnabled())
|
||||
tx().getOrderMap().undoVersion(tx(), this.order);
|
||||
else
|
||||
tx().getOrderMap().update(tx(), this.replaced);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
package li.strolch.command;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import li.strolch.agent.api.ComponentContainer;
|
||||
|
@ -32,7 +33,8 @@ import li.strolch.utils.dbc.DBC;
|
|||
public class UpdateResourceCollectionCommand extends Command {
|
||||
|
||||
private List<Resource> resources;
|
||||
private List<Resource> replacedElements;
|
||||
private List<Resource> replaced;
|
||||
private boolean updated;
|
||||
|
||||
/**
|
||||
* @param tx
|
||||
|
@ -62,22 +64,32 @@ public class UpdateResourceCollectionCommand extends Command {
|
|||
}
|
||||
|
||||
ResourceMap resourceMap = tx().getResourceMap();
|
||||
this.replaced = new ArrayList<>();
|
||||
for (Resource resource : this.resources) {
|
||||
if (!resourceMap.hasElement(tx(), resource.getType(), resource.getId())) {
|
||||
Resource r = resourceMap.getBy(tx(), resource.getType(), resource.getId());
|
||||
if (r == null) {
|
||||
String msg = "The Resource {0} can not be updated as it does not exist!";
|
||||
msg = MessageFormat.format(msg, resource.getLocator());
|
||||
throw new StrolchException(msg);
|
||||
}
|
||||
|
||||
this.replaced.add(r);
|
||||
}
|
||||
|
||||
this.replacedElements = resourceMap.updateAll(tx(), this.resources);
|
||||
resourceMap.updateAll(tx(), this.resources);
|
||||
this.updated = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void undo() {
|
||||
if (this.replacedElements != null && tx().isRollingBack()) {
|
||||
ResourceMap resourceMap = tx().getResourceMap();
|
||||
resourceMap.updateAll(tx(), this.replacedElements);
|
||||
if (this.updated && tx().isRollingBack()) {
|
||||
if (tx().isVersioningEnabled()) {
|
||||
for (Resource resource : this.resources) {
|
||||
tx().getResourceMap().undoVersion(tx(), resource);
|
||||
}
|
||||
} else {
|
||||
tx().getResourceMap().updateAll(tx(), this.replaced);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,7 +31,8 @@ import li.strolch.utils.dbc.DBC;
|
|||
public class UpdateResourceCommand extends Command {
|
||||
|
||||
private Resource resource;
|
||||
private Resource replacedElement;
|
||||
private Resource replaced;
|
||||
private boolean updated;
|
||||
|
||||
/**
|
||||
* @param tx
|
||||
|
@ -59,19 +60,24 @@ public class UpdateResourceCommand extends Command {
|
|||
tx().lock(this.resource);
|
||||
|
||||
ResourceMap resourceMap = tx().getResourceMap();
|
||||
if (!resourceMap.hasElement(tx(), this.resource.getType(), this.resource.getId())) {
|
||||
this.replaced = resourceMap.getBy(tx(), this.resource.getType(), this.resource.getId());
|
||||
if (this.replaced == null) {
|
||||
String msg = "The Resource {0} can not be updated as it does not exist!!";
|
||||
msg = MessageFormat.format(msg, this.resource.getLocator());
|
||||
throw new StrolchException(msg);
|
||||
}
|
||||
|
||||
this.replacedElement = resourceMap.update(tx(), this.resource);
|
||||
resourceMap.update(tx(), this.resource);
|
||||
this.updated = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void undo() {
|
||||
if (this.replacedElement != null && tx().isRollingBack()) {
|
||||
tx().getResourceMap().update(tx(), this.replacedElement);
|
||||
if (this.updated && tx().isRollingBack()) {
|
||||
if (tx().isVersioningEnabled())
|
||||
tx().getResourceMap().undoVersion(tx(), this.resource);
|
||||
else
|
||||
tx().getResourceMap().update(tx(), this.replaced);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ package li.strolch.command.parameter;
|
|||
import java.text.MessageFormat;
|
||||
|
||||
import li.strolch.agent.api.ComponentContainer;
|
||||
import li.strolch.command.visitor.UndoUpdateElementVisitor;
|
||||
import li.strolch.command.visitor.UpdateElementVisitor;
|
||||
import li.strolch.model.ParameterizedElement;
|
||||
import li.strolch.model.StrolchRootElement;
|
||||
|
@ -34,7 +35,6 @@ public class AddParameterCommand extends Command {
|
|||
|
||||
private ParameterizedElement element;
|
||||
private Parameter<?> parameter;
|
||||
private StrolchRootElement replacedElement;
|
||||
|
||||
/**
|
||||
* @param container
|
||||
|
@ -79,7 +79,7 @@ public class AddParameterCommand extends Command {
|
|||
tx().lock(rootElement);
|
||||
|
||||
this.element.addParameter(this.parameter);
|
||||
this.replacedElement = new UpdateElementVisitor(tx()).update(rootElement);
|
||||
new UpdateElementVisitor(tx()).update(rootElement);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -87,11 +87,8 @@ public class AddParameterCommand extends Command {
|
|||
if (this.parameter != null) {
|
||||
if (this.element.hasParameter(this.parameter.getId())) {
|
||||
this.element.removeParameter(this.parameter.getId());
|
||||
new UndoUpdateElementVisitor(tx()).undo(this.element.getRootElement());
|
||||
}
|
||||
}
|
||||
|
||||
if (this.replacedElement != null && this.element != this.replacedElement) {
|
||||
new UpdateElementVisitor(tx()).update(this.replacedElement);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ package li.strolch.command.parameter;
|
|||
import java.text.MessageFormat;
|
||||
|
||||
import li.strolch.agent.api.ComponentContainer;
|
||||
import li.strolch.command.visitor.UndoUpdateElementVisitor;
|
||||
import li.strolch.command.visitor.UpdateElementVisitor;
|
||||
import li.strolch.model.ParameterizedElement;
|
||||
import li.strolch.model.StrolchRootElement;
|
||||
|
@ -36,7 +37,6 @@ public class RemoveParameterCommand extends Command {
|
|||
private String parameterId;
|
||||
|
||||
private Parameter<?> removedParameter;
|
||||
private StrolchRootElement replacedElement;
|
||||
|
||||
/**
|
||||
* @param container
|
||||
|
@ -81,17 +81,14 @@ public class RemoveParameterCommand extends Command {
|
|||
tx().lock(rootElement);
|
||||
|
||||
this.removedParameter = this.element.removeParameter(this.parameterId);
|
||||
this.replacedElement = new UpdateElementVisitor(tx()).update(rootElement);
|
||||
new UpdateElementVisitor(tx()).update(rootElement);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void undo() {
|
||||
if (this.removedParameter != null) {
|
||||
this.element.addParameter(this.removedParameter);
|
||||
}
|
||||
|
||||
if (this.replacedElement != null && this.element != this.replacedElement) {
|
||||
new UpdateElementVisitor(tx()).update(this.replacedElement);
|
||||
new UndoUpdateElementVisitor(tx()).undo(this.removedParameter.getRootElement());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
package li.strolch.command.parameter;
|
||||
|
||||
import li.strolch.agent.api.ComponentContainer;
|
||||
import li.strolch.command.visitor.UndoUpdateElementVisitor;
|
||||
import li.strolch.command.visitor.UpdateElementVisitor;
|
||||
import li.strolch.model.StrolchRootElement;
|
||||
import li.strolch.model.parameter.Parameter;
|
||||
|
@ -46,7 +47,7 @@ public class SetParameterCommand extends Command {
|
|||
private Integer oldIndex;
|
||||
private String oldValueAsString;
|
||||
|
||||
private StrolchRootElement replacedElement;
|
||||
private boolean updated;
|
||||
|
||||
/**
|
||||
* @param container
|
||||
|
@ -151,7 +152,8 @@ public class SetParameterCommand extends Command {
|
|||
}
|
||||
|
||||
if (hasChanges()) {
|
||||
this.replacedElement = new UpdateElementVisitor(tx()).update(rootElement);
|
||||
new UpdateElementVisitor(tx()).update(rootElement);
|
||||
this.updated = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -185,8 +187,9 @@ public class SetParameterCommand extends Command {
|
|||
visitor.setValue(this.parameter, this.oldValueAsString);
|
||||
}
|
||||
|
||||
if (hasChanges() && this.replacedElement != null && this.replacedElement != this.parameter.getRootElement()) {
|
||||
new UpdateElementVisitor(tx()).update(this.replacedElement);
|
||||
if (hasChanges() && this.updated) {
|
||||
StrolchRootElement rootElement = this.parameter.getRootElement();
|
||||
new UndoUpdateElementVisitor(tx()).undo(rootElement);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Copyright 2013 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.command.visitor;
|
||||
|
||||
import li.strolch.model.Order;
|
||||
import li.strolch.model.Resource;
|
||||
import li.strolch.model.StrolchRootElement;
|
||||
import li.strolch.model.activity.Activity;
|
||||
import li.strolch.model.visitor.StrolchRootElementVisitor;
|
||||
import li.strolch.persistence.api.StrolchTransaction;
|
||||
|
||||
/**
|
||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||
*/
|
||||
public class UndoUpdateElementVisitor implements StrolchRootElementVisitor<Void> {
|
||||
|
||||
private StrolchTransaction tx;
|
||||
|
||||
public UndoUpdateElementVisitor(StrolchTransaction tx) {
|
||||
this.tx = tx;
|
||||
}
|
||||
|
||||
public Void undo(StrolchRootElement rootElement) {
|
||||
return rootElement.accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitOrder(Order order) {
|
||||
if (tx.isVersioningEnabled())
|
||||
this.tx.getOrderMap().undoVersion(this.tx, order);
|
||||
else
|
||||
this.tx.getOrderMap().update(this.tx, order);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitResource(Resource resource) {
|
||||
if (tx.isVersioningEnabled())
|
||||
this.tx.getResourceMap().undoVersion(this.tx, resource);
|
||||
else
|
||||
this.tx.getResourceMap().update(this.tx, resource);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitActivity(Activity activity) {
|
||||
if (tx.isVersioningEnabled())
|
||||
this.tx.getActivityMap().undoVersion(this.tx, activity);
|
||||
else
|
||||
this.tx.getActivityMap().update(this.tx, activity);
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -18,13 +18,14 @@ package li.strolch.command.visitor;
|
|||
import li.strolch.model.Order;
|
||||
import li.strolch.model.Resource;
|
||||
import li.strolch.model.StrolchRootElement;
|
||||
import li.strolch.model.activity.Activity;
|
||||
import li.strolch.model.visitor.StrolchRootElementVisitor;
|
||||
import li.strolch.persistence.api.StrolchTransaction;
|
||||
|
||||
/**
|
||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||
*/
|
||||
public class UpdateElementVisitor implements StrolchRootElementVisitor<StrolchRootElement> {
|
||||
public class UpdateElementVisitor implements StrolchRootElementVisitor<Void> {
|
||||
|
||||
private StrolchTransaction tx;
|
||||
|
||||
|
@ -32,17 +33,25 @@ public class UpdateElementVisitor implements StrolchRootElementVisitor<StrolchRo
|
|||
this.tx = tx;
|
||||
}
|
||||
|
||||
public StrolchRootElement update(StrolchRootElement rootElement) {
|
||||
public Void update(StrolchRootElement rootElement) {
|
||||
return rootElement.accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StrolchRootElement visitOrder(Order order) {
|
||||
return this.tx.getOrderMap().update(this.tx, order);
|
||||
public Void visitOrder(Order order) {
|
||||
this.tx.getOrderMap().update(this.tx, order);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StrolchRootElement visitResource(Resource resource) {
|
||||
return this.tx.getResourceMap().update(this.tx, resource);
|
||||
public Void visitResource(Resource resource) {
|
||||
this.tx.getResourceMap().update(this.tx, resource);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitActivity(Activity activity) {
|
||||
this.tx.getActivityMap().update(this.tx, activity);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,9 +22,16 @@ import static li.strolch.service.test.AbstractRealmServiceTest.REALM_TRANSIENT;
|
|||
import static li.strolch.service.test.AbstractRealmServiceTest.RUNTIME_PATH;
|
||||
import static li.strolch.service.test.AbstractRealmServiceTest.dropSchema;
|
||||
import static li.strolch.service.test.AbstractRealmServiceTest.importFromXml;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import li.strolch.agent.api.ComponentContainer;
|
||||
import li.strolch.agent.api.StrolchRealm;
|
||||
import li.strolch.persistence.api.StrolchTransaction;
|
||||
|
@ -33,12 +40,6 @@ import li.strolch.service.api.Command;
|
|||
import li.strolch.service.api.ServiceHandler;
|
||||
import li.strolch.testbase.runtime.RuntimeMock;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
|
||||
/**
|
||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||
*/
|
||||
|
@ -48,9 +49,6 @@ public abstract class AbstractRealmCommandTest {
|
|||
|
||||
protected static Certificate certificate;
|
||||
|
||||
@Rule
|
||||
public ExpectedException expectedException = ExpectedException.none();
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() throws Exception {
|
||||
|
||||
|
@ -80,17 +78,27 @@ public abstract class AbstractRealmCommandTest {
|
|||
|
||||
protected abstract Command getCommandInstance(ComponentContainer container, StrolchTransaction tx);
|
||||
|
||||
protected void doCommandAsFail(String realmName) {
|
||||
this.expectedException.expect(RuntimeException.class);
|
||||
this.expectedException.expectMessage("Fail on purpose after do command!");
|
||||
protected abstract void validateAfterCommand(ComponentContainer container, StrolchTransaction tx);
|
||||
|
||||
protected abstract void validateAfterCommandFailed(ComponentContainer container, StrolchTransaction tx);
|
||||
|
||||
protected void doCommandAsFail(String realmName) {
|
||||
StrolchRealm realm = runtimeMock.getContainer().getRealm(realmName);
|
||||
boolean caught = false;
|
||||
try (StrolchTransaction tx = realm.openTx(certificate, "test")) {
|
||||
Command command = getCommandInstance(runtimeMock.getContainer(), tx);
|
||||
FailCommandFacade commandFacade = new FailCommandFacade(runtimeMock.getContainer(), tx, command);
|
||||
|
||||
tx.addCommand(commandFacade);
|
||||
tx.commitOnClose();
|
||||
} catch (RuntimeException e) {
|
||||
assertThat(e.getMessage(), containsString("Fail on purpose after do command!"));
|
||||
caught = true;
|
||||
}
|
||||
assertTrue(caught);
|
||||
|
||||
try (StrolchTransaction tx = realm.openTx(certificate, "test")) {
|
||||
validateAfterCommandFailed(runtimeMock.getContainer(), tx);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -101,21 +109,28 @@ public abstract class AbstractRealmCommandTest {
|
|||
tx.addCommand(command);
|
||||
tx.commitOnClose();
|
||||
}
|
||||
|
||||
try (StrolchTransaction tx = realm.openTx(certificate, "test")) {
|
||||
validateAfterCommand(runtimeMock.getContainer(), tx);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldFailCommandTransient() {
|
||||
public void shouldDoCommandTransient() {
|
||||
doCommandAsFail(REALM_TRANSIENT);
|
||||
doCommand(REALM_TRANSIENT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldFailCommandCached() {
|
||||
public void shouldDoCommandCached() {
|
||||
doCommandAsFail(REALM_CACHED);
|
||||
doCommand(REALM_CACHED);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldFailCommandTransactional() {
|
||||
public void shouldDoCommandTransactional() {
|
||||
doCommandAsFail(REALM_TRANSACTIONAL);
|
||||
doCommand(REALM_TRANSACTIONAL);
|
||||
}
|
||||
|
||||
private class FailCommandFacade extends Command {
|
||||
|
|
|
@ -15,17 +15,20 @@
|
|||
*/
|
||||
package li.strolch.command;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Before;
|
||||
|
||||
import li.strolch.agent.api.ComponentContainer;
|
||||
import li.strolch.model.ModelGenerator;
|
||||
import li.strolch.model.Order;
|
||||
import li.strolch.persistence.api.StrolchTransaction;
|
||||
import li.strolch.service.api.Command;
|
||||
|
||||
import org.junit.Before;
|
||||
|
||||
/**
|
||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||
*/
|
||||
|
@ -48,4 +51,18 @@ public class AddOrderCollectionCommandTest extends AbstractRealmCommandTest {
|
|||
command.setOrders(this.orders);
|
||||
return command;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void validateAfterCommand(ComponentContainer container, StrolchTransaction tx) {
|
||||
for (Order order : orders) {
|
||||
assertTrue(tx.getOrderMap().hasElement(tx, order.getType(), order.getId()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void validateAfterCommandFailed(ComponentContainer container, StrolchTransaction tx) {
|
||||
for (Order order : orders) {
|
||||
assertFalse(tx.getOrderMap().hasElement(tx, order.getType(), order.getId()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,14 +15,17 @@
|
|||
*/
|
||||
package li.strolch.command;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import org.junit.Before;
|
||||
|
||||
import li.strolch.agent.api.ComponentContainer;
|
||||
import li.strolch.model.ModelGenerator;
|
||||
import li.strolch.model.Order;
|
||||
import li.strolch.persistence.api.StrolchTransaction;
|
||||
import li.strolch.service.api.Command;
|
||||
|
||||
import org.junit.Before;
|
||||
|
||||
/**
|
||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||
*/
|
||||
|
@ -42,4 +45,14 @@ public class AddOrderCommandTest extends AbstractRealmCommandTest {
|
|||
command.setOrder(this.order);
|
||||
return command;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void validateAfterCommand(ComponentContainer container, StrolchTransaction tx) {
|
||||
assertTrue(tx.getOrderMap().hasElement(tx, this.order.getType(), this.order.getId()));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void validateAfterCommandFailed(ComponentContainer container, StrolchTransaction tx) {
|
||||
assertFalse(tx.getOrderMap().hasElement(tx, this.order.getType(), this.order.getId()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,17 +15,20 @@
|
|||
*/
|
||||
package li.strolch.command;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Before;
|
||||
|
||||
import li.strolch.agent.api.ComponentContainer;
|
||||
import li.strolch.model.ModelGenerator;
|
||||
import li.strolch.model.Resource;
|
||||
import li.strolch.persistence.api.StrolchTransaction;
|
||||
import li.strolch.service.api.Command;
|
||||
|
||||
import org.junit.Before;
|
||||
|
||||
/**
|
||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||
*/
|
||||
|
@ -48,4 +51,18 @@ public class AddResourceCollectionCommandTest extends AbstractRealmCommandTest {
|
|||
command.setResources(this.resources);
|
||||
return command;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void validateAfterCommand(ComponentContainer container, StrolchTransaction tx) {
|
||||
for (Resource resource : resources) {
|
||||
assertTrue(tx.getResourceMap().hasElement(tx, resource.getType(), resource.getId()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void validateAfterCommandFailed(ComponentContainer container, StrolchTransaction tx) {
|
||||
for (Resource resource : resources) {
|
||||
assertFalse(tx.getResourceMap().hasElement(tx, resource.getType(), resource.getId()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,14 +15,17 @@
|
|||
*/
|
||||
package li.strolch.command;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import org.junit.Before;
|
||||
|
||||
import li.strolch.agent.api.ComponentContainer;
|
||||
import li.strolch.model.ModelGenerator;
|
||||
import li.strolch.model.Resource;
|
||||
import li.strolch.persistence.api.StrolchTransaction;
|
||||
import li.strolch.service.api.Command;
|
||||
|
||||
import org.junit.Before;
|
||||
|
||||
/**
|
||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||
*/
|
||||
|
@ -42,4 +45,14 @@ public class AddResourceCommandTest extends AbstractRealmCommandTest {
|
|||
command.setResource(this.resource);
|
||||
return command;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void validateAfterCommand(ComponentContainer container, StrolchTransaction tx) {
|
||||
assertTrue(tx.getResourceMap().hasElement(tx, this.resource.getType(), this.resource.getId()));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void validateAfterCommandFailed(ComponentContainer container, StrolchTransaction tx) {
|
||||
assertFalse(tx.getResourceMap().hasElement(tx, this.resource.getType(), this.resource.getId()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,9 +15,14 @@
|
|||
*/
|
||||
package li.strolch.command;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Before;
|
||||
|
||||
import li.strolch.agent.api.ComponentContainer;
|
||||
import li.strolch.model.Locator;
|
||||
import li.strolch.model.Order;
|
||||
|
@ -25,8 +30,6 @@ import li.strolch.model.Tags;
|
|||
import li.strolch.persistence.api.StrolchTransaction;
|
||||
import li.strolch.service.api.Command;
|
||||
|
||||
import org.junit.Before;
|
||||
|
||||
/**
|
||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||
*/
|
||||
|
@ -54,4 +57,18 @@ public class RemoveOrderCollectionCommandTest extends AbstractRealmCommandTest {
|
|||
command.setOrders(orders);
|
||||
return command;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void validateAfterCommand(ComponentContainer container, StrolchTransaction tx) {
|
||||
for (Locator locator : locators) {
|
||||
assertFalse(tx.getOrderMap().hasElement(tx, locator.get(1), locator.get(2)));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void validateAfterCommandFailed(ComponentContainer container, StrolchTransaction tx) {
|
||||
for (Locator locator : locators) {
|
||||
assertTrue(tx.getOrderMap().hasElement(tx, locator.get(1), locator.get(2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,11 @@
|
|||
*/
|
||||
package li.strolch.command;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import org.junit.Before;
|
||||
|
||||
import li.strolch.agent.api.ComponentContainer;
|
||||
import li.strolch.model.Locator;
|
||||
import li.strolch.model.Order;
|
||||
|
@ -22,8 +27,6 @@ import li.strolch.model.Tags;
|
|||
import li.strolch.persistence.api.StrolchTransaction;
|
||||
import li.strolch.service.api.Command;
|
||||
|
||||
import org.junit.Before;
|
||||
|
||||
/**
|
||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||
*/
|
||||
|
@ -45,4 +48,14 @@ public class RemoveOrderCommandTest extends AbstractRealmCommandTest {
|
|||
command.setOrder(order);
|
||||
return command;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void validateAfterCommand(ComponentContainer container, StrolchTransaction tx) {
|
||||
assertFalse(tx.getOrderMap().hasElement(tx, "TestType", "@3"));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void validateAfterCommandFailed(ComponentContainer container, StrolchTransaction tx) {
|
||||
assertTrue(tx.getOrderMap().hasElement(tx, "TestType", "@3"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,9 +15,14 @@
|
|||
*/
|
||||
package li.strolch.command;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Before;
|
||||
|
||||
import li.strolch.agent.api.ComponentContainer;
|
||||
import li.strolch.model.Locator;
|
||||
import li.strolch.model.Resource;
|
||||
|
@ -25,8 +30,6 @@ import li.strolch.model.Tags;
|
|||
import li.strolch.persistence.api.StrolchTransaction;
|
||||
import li.strolch.service.api.Command;
|
||||
|
||||
import org.junit.Before;
|
||||
|
||||
/**
|
||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||
*/
|
||||
|
@ -54,4 +57,18 @@ public class RemoveResourceCollectionCommandTest extends AbstractRealmCommandTes
|
|||
command.setResources(resources);
|
||||
return command;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void validateAfterCommand(ComponentContainer container, StrolchTransaction tx) {
|
||||
for (Locator locator : locators) {
|
||||
assertFalse(tx.getResourceMap().hasElement(tx, locator.get(1), locator.get(2)));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void validateAfterCommandFailed(ComponentContainer container, StrolchTransaction tx) {
|
||||
for (Locator locator : locators) {
|
||||
assertTrue(tx.getResourceMap().hasElement(tx, locator.get(1), locator.get(2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,11 @@
|
|||
*/
|
||||
package li.strolch.command;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import org.junit.Before;
|
||||
|
||||
import li.strolch.agent.api.ComponentContainer;
|
||||
import li.strolch.model.Locator;
|
||||
import li.strolch.model.Resource;
|
||||
|
@ -22,8 +27,6 @@ import li.strolch.model.Tags;
|
|||
import li.strolch.persistence.api.StrolchTransaction;
|
||||
import li.strolch.service.api.Command;
|
||||
|
||||
import org.junit.Before;
|
||||
|
||||
/**
|
||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||
*/
|
||||
|
@ -45,4 +48,14 @@ public class RemoveResourceCommandTest extends AbstractRealmCommandTest {
|
|||
command.setResource(resource);
|
||||
return command;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void validateAfterCommand(ComponentContainer container, StrolchTransaction tx) {
|
||||
assertFalse(tx.getResourceMap().hasElement(tx, "Enumeration", "sex"));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void validateAfterCommandFailed(ComponentContainer container, StrolchTransaction tx) {
|
||||
assertTrue(tx.getResourceMap().hasElement(tx, "Enumeration", "sex"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,17 +15,19 @@
|
|||
*/
|
||||
package li.strolch.command;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Before;
|
||||
|
||||
import li.strolch.agent.api.ComponentContainer;
|
||||
import li.strolch.model.ModelGenerator;
|
||||
import li.strolch.model.Order;
|
||||
import li.strolch.persistence.api.StrolchTransaction;
|
||||
import li.strolch.service.api.Command;
|
||||
|
||||
import org.junit.Before;
|
||||
|
||||
/**
|
||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||
*/
|
||||
|
@ -36,6 +38,7 @@ public class UpdateOrderCollectionCommandTest extends AbstractRealmCommandTest {
|
|||
@Before
|
||||
public void before() {
|
||||
this.orders = new ArrayList<>();
|
||||
// we create elements with the same id as already exists!
|
||||
this.orders.add(ModelGenerator.createOrder("@1", "Modified Test Order", "TestType"));
|
||||
this.orders.add(ModelGenerator.createOrder("@2", "Modified Test Order", "TestType"));
|
||||
this.orders.add(ModelGenerator.createOrder("@3", "Modified Test Order", "TestType"));
|
||||
|
@ -48,4 +51,20 @@ public class UpdateOrderCollectionCommandTest extends AbstractRealmCommandTest {
|
|||
command.setOrders(this.orders);
|
||||
return command;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void validateAfterCommand(ComponentContainer container, StrolchTransaction tx) {
|
||||
for (Order order : orders) {
|
||||
Order o = tx.getOrderBy(order.getType(), order.getId());
|
||||
assertEquals("Modified Test Order", o.getName());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void validateAfterCommandFailed(ComponentContainer container, StrolchTransaction tx) {
|
||||
for (Order order : orders) {
|
||||
Order o = tx.getOrderBy(order.getType(), order.getId());
|
||||
assertEquals("Test Name", o.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,4 +42,16 @@ public class UpdateOrderCommandTest extends AbstractRealmCommandTest {
|
|||
command.setOrder(this.order);
|
||||
return command;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void validateAfterCommand(ComponentContainer container, StrolchTransaction tx) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void validateAfterCommandFailed(ComponentContainer container, StrolchTransaction tx) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,17 +15,19 @@
|
|||
*/
|
||||
package li.strolch.command;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Before;
|
||||
|
||||
import li.strolch.agent.api.ComponentContainer;
|
||||
import li.strolch.model.ModelGenerator;
|
||||
import li.strolch.model.Resource;
|
||||
import li.strolch.persistence.api.StrolchTransaction;
|
||||
import li.strolch.service.api.Command;
|
||||
|
||||
import org.junit.Before;
|
||||
|
||||
/**
|
||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||
*/
|
||||
|
@ -48,4 +50,20 @@ public class UpdateResourceCollectionCommandTest extends AbstractRealmCommandTes
|
|||
command.setResources(this.resources);
|
||||
return command;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void validateAfterCommand(ComponentContainer container, StrolchTransaction tx) {
|
||||
for (Resource resource : this.resources) {
|
||||
Resource r = tx.getResourceBy(resource.getType(), resource.getId());
|
||||
assertEquals("Modified Enumeration", r.getName());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void validateAfterCommandFailed(ComponentContainer container, StrolchTransaction tx) {
|
||||
for (Resource resource : this.resources) {
|
||||
Resource r = tx.getResourceBy(resource.getType(), resource.getId());
|
||||
assertEquals(r.getId(), r.getName().toLowerCase());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,4 +42,16 @@ public class UpdateResourceCommandTest extends AbstractRealmCommandTest {
|
|||
command.setResource(this.resource);
|
||||
return command;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void validateAfterCommand(ComponentContainer container, StrolchTransaction tx) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void validateAfterCommandFailed(ComponentContainer container, StrolchTransaction tx) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,11 @@
|
|||
*/
|
||||
package li.strolch.command.parameter;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import org.junit.Before;
|
||||
|
||||
import li.strolch.agent.api.ComponentContainer;
|
||||
import li.strolch.command.AbstractRealmCommandTest;
|
||||
import li.strolch.model.Locator;
|
||||
|
@ -24,8 +29,6 @@ import li.strolch.model.parameter.Parameter;
|
|||
import li.strolch.persistence.api.StrolchTransaction;
|
||||
import li.strolch.service.api.Command;
|
||||
|
||||
import org.junit.Before;
|
||||
|
||||
/**
|
||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||
*/
|
||||
|
@ -50,4 +53,16 @@ public class AddParameterCommandTest extends AbstractRealmCommandTest {
|
|||
command.setParameter(this.parameter);
|
||||
return command;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void validateAfterCommand(ComponentContainer container, StrolchTransaction tx) {
|
||||
ParameterizedElement element = tx.findElement(this.locator);
|
||||
assertTrue(element.hasParameter(this.parameter.getId()));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void validateAfterCommandFailed(ComponentContainer container, StrolchTransaction tx) {
|
||||
ParameterizedElement element = tx.findElement(this.locator);
|
||||
assertFalse(element.hasParameter(this.parameter.getId()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,11 @@
|
|||
*/
|
||||
package li.strolch.command.parameter;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import org.junit.Before;
|
||||
|
||||
import li.strolch.agent.api.ComponentContainer;
|
||||
import li.strolch.command.AbstractRealmCommandTest;
|
||||
import li.strolch.model.Locator;
|
||||
|
@ -22,8 +27,6 @@ import li.strolch.model.ParameterizedElement;
|
|||
import li.strolch.persistence.api.StrolchTransaction;
|
||||
import li.strolch.service.api.Command;
|
||||
|
||||
import org.junit.Before;
|
||||
|
||||
/**
|
||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||
*/
|
||||
|
@ -48,4 +51,16 @@ public class RemoveParameterCommandTest extends AbstractRealmCommandTest {
|
|||
command.setParameterId(this.parameterId);
|
||||
return command;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void validateAfterCommand(ComponentContainer container, StrolchTransaction tx) {
|
||||
ParameterizedElement element = tx.findElement(this.locator);
|
||||
assertFalse(element.hasParameter(this.parameterId));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void validateAfterCommandFailed(ComponentContainer container, StrolchTransaction tx) {
|
||||
ParameterizedElement element = tx.findElement(this.locator);
|
||||
assertTrue(element.hasParameter(this.parameterId));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,10 @@
|
|||
*/
|
||||
package li.strolch.command.parameter;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import org.junit.Before;
|
||||
|
||||
import li.strolch.agent.api.ComponentContainer;
|
||||
import li.strolch.command.AbstractRealmCommandTest;
|
||||
import li.strolch.model.Locator;
|
||||
|
@ -22,8 +26,6 @@ import li.strolch.model.parameter.Parameter;
|
|||
import li.strolch.persistence.api.StrolchTransaction;
|
||||
import li.strolch.service.api.Command;
|
||||
|
||||
import org.junit.Before;
|
||||
|
||||
/**
|
||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||
*/
|
||||
|
@ -31,6 +33,7 @@ public class SetParameterCommandTest extends AbstractRealmCommandTest {
|
|||
|
||||
private Locator locator;
|
||||
private String valueAsString;
|
||||
private String originalValue;
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
|
@ -42,10 +45,23 @@ public class SetParameterCommandTest extends AbstractRealmCommandTest {
|
|||
protected Command getCommandInstance(ComponentContainer container, StrolchTransaction tx) {
|
||||
|
||||
Parameter<?> parameter = tx.findElement(this.locator);
|
||||
this.originalValue = parameter.getValueAsString();
|
||||
|
||||
SetParameterCommand command = new SetParameterCommand(container, tx);
|
||||
command.setValueAsString(this.valueAsString);
|
||||
command.setParameter(parameter);
|
||||
return command;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void validateAfterCommand(ComponentContainer container, StrolchTransaction tx) {
|
||||
Parameter<?> parameter = tx.findElement(this.locator);
|
||||
assertEquals(this.valueAsString, parameter.getValueAsString());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void validateAfterCommandFailed(ComponentContainer container, StrolchTransaction tx) {
|
||||
Parameter<?> parameter = tx.findElement(this.locator);
|
||||
assertEquals(this.originalValue, parameter.getValueAsString());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,15 +15,15 @@
|
|||
*/
|
||||
package li.strolch.testbase.runtime;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import li.strolch.persistence.api.StrolchTransaction;
|
||||
import li.strolch.privilege.model.Certificate;
|
||||
import li.strolch.runtime.StrolchConstants;
|
||||
import li.strolch.runtime.privilege.PrivilegeHandler;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public abstract class AbstractModelTest {
|
||||
|
||||
protected static final Logger logger = LoggerFactory.getLogger(AbstractModelTest.class);
|
||||
|
@ -97,9 +97,43 @@ public abstract class AbstractModelTest {
|
|||
testRunner.runBulkOperationTests();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldCreateActivities() {
|
||||
|
||||
ActivityModelTestRunner testRunner = new ActivityModelTestRunner(getRuntimeMock(), this.realmName);
|
||||
testRunner.runCreateActivityTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldQueryActivitySizes() {
|
||||
|
||||
ActivityModelTestRunner testRunner = new ActivityModelTestRunner(getRuntimeMock(), this.realmName);
|
||||
testRunner.runQuerySizeTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldActivityCrud() {
|
||||
|
||||
ActivityModelTestRunner testRunner = new ActivityModelTestRunner(getRuntimeMock(), this.realmName);
|
||||
testRunner.runCrudTests();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldActivityPerformBulkOperations() {
|
||||
|
||||
ActivityModelTestRunner testRunner = new ActivityModelTestRunner(getRuntimeMock(), this.realmName);
|
||||
testRunner.runBulkOperationTests();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldTestAudits() {
|
||||
AuditModelTestRunner testRunner = new AuditModelTestRunner(getRuntimeMock(), this.realmName);
|
||||
testRunner.runTestForAudits();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldTestVersioning() {
|
||||
VersioningTestRunner testRunner = new VersioningTestRunner(getRuntimeMock());
|
||||
testRunner.runTestsForVersioning();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,276 @@
|
|||
/*
|
||||
* 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.testbase.runtime;
|
||||
|
||||
import static li.strolch.model.ModelGenerator.BAG_ID;
|
||||
import static li.strolch.model.ModelGenerator.PARAM_STRING_ID;
|
||||
import static li.strolch.model.ModelGenerator.createActivities;
|
||||
import static li.strolch.model.ModelGenerator.createActivity;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import li.strolch.agent.api.ActivityMap;
|
||||
import li.strolch.agent.impl.DataStoreMode;
|
||||
import li.strolch.model.activity.Activity;
|
||||
import li.strolch.model.parameter.Parameter;
|
||||
import li.strolch.persistence.api.StrolchTransaction;
|
||||
import li.strolch.privilege.model.Certificate;
|
||||
import li.strolch.runtime.privilege.PrivilegeHandler;
|
||||
|
||||
@SuppressWarnings("nls")
|
||||
public class ActivityModelTestRunner {
|
||||
|
||||
private static final String ID = "@testActivity";
|
||||
private static final String NAME = "Test Activity";
|
||||
private static final String TYPE = "Produce";
|
||||
|
||||
private RuntimeMock runtimeMock;
|
||||
private String realmName;
|
||||
private Certificate certificate;
|
||||
|
||||
public ActivityModelTestRunner(RuntimeMock runtimeMock, String realmName) {
|
||||
this.runtimeMock = runtimeMock;
|
||||
this.realmName = realmName;
|
||||
|
||||
PrivilegeHandler privilegeHandler = runtimeMock.getContainer().getPrivilegeHandler();
|
||||
this.certificate = privilegeHandler.authenticate("test", "test".getBytes());
|
||||
}
|
||||
|
||||
public void runCreateActivityTest() {
|
||||
|
||||
// create
|
||||
Activity newActivity = createActivity("MyTestActivity", "Test Name", "TestType"); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
|
||||
try (StrolchTransaction tx = this.runtimeMock.getRealm(this.realmName).openTx(this.certificate, "test");) {
|
||||
tx.getActivityMap().add(tx, newActivity);
|
||||
tx.commitOnClose();
|
||||
}
|
||||
}
|
||||
|
||||
public void runQuerySizeTest() {
|
||||
|
||||
// remove all
|
||||
try (StrolchTransaction tx = this.runtimeMock.getRealm(this.realmName).openTx(this.certificate, "test");) {
|
||||
tx.getActivityMap().removeAll(tx, tx.getActivityMap().getAllElements(tx));
|
||||
tx.commitOnClose();
|
||||
}
|
||||
|
||||
// create three activities
|
||||
Activity activity1 = createActivity("myTestActivity1", "Test Name", "QTestType1"); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
|
||||
Activity activity2 = createActivity("myTestActivity2", "Test Name", "QTestType2"); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
|
||||
Activity activity3 = createActivity("myTestActivity3", "Test Name", "QTestType3"); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
|
||||
try (StrolchTransaction tx = this.runtimeMock.getRealm(this.realmName).openTx(this.certificate, "test");) {
|
||||
tx.getActivityMap().add(tx, activity1);
|
||||
tx.getActivityMap().add(tx, activity2);
|
||||
tx.getActivityMap().add(tx, activity3);
|
||||
tx.commitOnClose();
|
||||
}
|
||||
|
||||
// query size
|
||||
try (StrolchTransaction tx = this.runtimeMock.getRealm(this.realmName).openTx(this.certificate, "test");) {
|
||||
long size = tx.getActivityMap().querySize(tx);
|
||||
assertEquals("Should have three objects", 3, size);
|
||||
|
||||
size = tx.getActivityMap().querySize(tx, "QTestType1");
|
||||
assertEquals("Should have only one object of type 'QTestType1'", 1, size);
|
||||
|
||||
size = tx.getActivityMap().querySize(tx, "QTestType2");
|
||||
assertEquals("Should have only one object of type 'QTestType1'", 1, size);
|
||||
|
||||
size = tx.getActivityMap().querySize(tx, "QTestType3");
|
||||
assertEquals("Should have only one object of type 'QTestType1'", 1, size);
|
||||
|
||||
size = tx.getActivityMap().querySize(tx, "NonExistingType");
|
||||
assertEquals("Should have zero objects of type 'NonExistingType'", 0, size);
|
||||
}
|
||||
}
|
||||
|
||||
public void runCrudTests() {
|
||||
|
||||
// create
|
||||
Activity newActivity = createActivity(ID, NAME, TYPE);
|
||||
try (StrolchTransaction tx = this.runtimeMock.getRealm(this.realmName).openTx(this.certificate, "test");) {
|
||||
tx.getActivityMap().add(tx, newActivity);
|
||||
tx.commitOnClose();
|
||||
}
|
||||
|
||||
// read
|
||||
Activity readActivity = null;
|
||||
try (StrolchTransaction tx = this.runtimeMock.getRealm(this.realmName).openTx(this.certificate, "test");) {
|
||||
readActivity = tx.getActivityMap().getBy(tx, TYPE, ID);
|
||||
}
|
||||
assertNotNull("Should read Activity with id " + ID, readActivity);
|
||||
|
||||
// update
|
||||
Parameter<String> sParam = readActivity.getParameter(BAG_ID, PARAM_STRING_ID);
|
||||
String newStringValue = "Giddiya!";
|
||||
sParam.setValue(newStringValue);
|
||||
try (StrolchTransaction tx = this.runtimeMock.getRealm(this.realmName).openTx(this.certificate, "test");) {
|
||||
tx.getActivityMap().update(tx, readActivity);
|
||||
tx.commitOnClose();
|
||||
}
|
||||
|
||||
// read updated
|
||||
Activity updatedActivity = null;
|
||||
try (StrolchTransaction tx = this.runtimeMock.getRealm(this.realmName).openTx(this.certificate, "test");) {
|
||||
updatedActivity = tx.getActivityMap().getBy(tx, TYPE, ID);
|
||||
}
|
||||
assertNotNull("Should read Activity with id " + ID, updatedActivity);
|
||||
if (this.runtimeMock.getRealm(this.realmName).getMode() != DataStoreMode.CACHED)
|
||||
assertFalse("Objects can't be the same reference after re-reading!", readActivity == updatedActivity);
|
||||
Parameter<String> updatedParam = readActivity.getParameter(BAG_ID, PARAM_STRING_ID);
|
||||
assertEquals(newStringValue, updatedParam.getValue());
|
||||
|
||||
// delete
|
||||
try (StrolchTransaction tx = this.runtimeMock.getRealm(this.realmName).openTx(this.certificate, "test");) {
|
||||
tx.getActivityMap().remove(tx, readActivity);
|
||||
tx.commitOnClose();
|
||||
}
|
||||
|
||||
// fail to re-read
|
||||
try (StrolchTransaction tx = this.runtimeMock.getRealm(this.realmName).openTx(this.certificate, "test");) {
|
||||
Activity activity = tx.getActivityMap().getBy(tx, TYPE, ID);
|
||||
assertNull("Should no read Activity with id " + ID, activity);
|
||||
}
|
||||
}
|
||||
|
||||
public void runBulkOperationTests() {
|
||||
|
||||
// create 15 activities
|
||||
List<Activity> activities = new ArrayList<>();
|
||||
activities.addAll(createActivities(activities.size(), 5, "@", "My Activity", "MyType1"));
|
||||
activities.addAll(createActivities(activities.size(), 5, "@", "Other Activity", "MyType2"));
|
||||
activities.addAll(createActivities(activities.size(), 5, "@", "Further Activity", "MyType3"));
|
||||
|
||||
// sort them so we know which activity our objects are
|
||||
Comparator<Activity> comparator = new Comparator<Activity>() {
|
||||
@Override
|
||||
public int compare(Activity o1, Activity o2) {
|
||||
return o1.getId().compareTo(o2.getId());
|
||||
}
|
||||
};
|
||||
Collections.sort(activities, comparator);
|
||||
|
||||
// first clear the map, so that we have a clean state
|
||||
try (StrolchTransaction tx = this.runtimeMock.getRealm(this.realmName).openTx(this.certificate, "test")) {
|
||||
ActivityMap activityMap = tx.getActivityMap();
|
||||
activityMap.removeAll(tx, activityMap.getAllElements(tx));
|
||||
tx.commitOnClose();
|
||||
}
|
||||
|
||||
{
|
||||
// make sure it is empty
|
||||
try (StrolchTransaction tx = this.runtimeMock.getRealm(this.realmName).openTx(this.certificate, "test")) {
|
||||
ActivityMap activityMap = tx.getActivityMap();
|
||||
assertEquals(0, activityMap.querySize(tx));
|
||||
}
|
||||
|
||||
// now add some activities
|
||||
try (StrolchTransaction tx = this.runtimeMock.getRealm(this.realmName).openTx(this.certificate, "test")) {
|
||||
tx.getActivityMap().addAll(tx, activities);
|
||||
tx.commitOnClose();
|
||||
}
|
||||
|
||||
// make sure we have our expected size
|
||||
try (StrolchTransaction tx = this.runtimeMock.getRealm(this.realmName).openTx(this.certificate, "test")) {
|
||||
ActivityMap activityMap = tx.getActivityMap();
|
||||
assertEquals(activities.size(), activityMap.querySize(tx));
|
||||
assertEquals(5, activityMap.querySize(tx, "MyType3"));
|
||||
}
|
||||
|
||||
// now use the remove all by type
|
||||
try (StrolchTransaction tx = this.runtimeMock.getRealm(this.realmName).openTx(this.certificate, "test")) {
|
||||
tx.getActivityMap().removeAllBy(tx, "MyType3");
|
||||
tx.commitOnClose();
|
||||
}
|
||||
|
||||
// again make sure we have our expected size
|
||||
try (StrolchTransaction tx = this.runtimeMock.getRealm(this.realmName).openTx(this.certificate, "test")) {
|
||||
ActivityMap activityMap = tx.getActivityMap();
|
||||
assertEquals(activities.size() - 5, activityMap.querySize(tx));
|
||||
assertEquals(0, activityMap.querySize(tx, "MyType3"));
|
||||
}
|
||||
|
||||
// now use the remove all
|
||||
try (StrolchTransaction tx = this.runtimeMock.getRealm(this.realmName).openTx(this.certificate, "test")) {
|
||||
long removed = tx.getActivityMap().removeAll(tx);
|
||||
assertEquals(activities.size() - 5, removed);
|
||||
tx.commitOnClose();
|
||||
}
|
||||
|
||||
// again make sure we have our expected size
|
||||
try (StrolchTransaction tx = this.runtimeMock.getRealm(this.realmName).openTx(this.certificate, "test")) {
|
||||
ActivityMap activityMap = tx.getActivityMap();
|
||||
assertEquals(0, activityMap.querySize(tx));
|
||||
}
|
||||
}
|
||||
|
||||
// remove the version
|
||||
activities.forEach(t -> t.setVersion(null));
|
||||
|
||||
// now add all again
|
||||
try (StrolchTransaction tx = this.runtimeMock.getRealm(this.realmName).openTx(this.certificate, "test")) {
|
||||
tx.getActivityMap().addAll(tx, activities);
|
||||
tx.commitOnClose();
|
||||
}
|
||||
|
||||
Set<String> expectedTypes = new HashSet<>();
|
||||
expectedTypes.add("MyType1");
|
||||
expectedTypes.add("MyType2");
|
||||
expectedTypes.add("MyType3");
|
||||
|
||||
try (StrolchTransaction tx = this.runtimeMock.getRealm(this.realmName).openTx(this.certificate, "test")) {
|
||||
List<Activity> allActivities = tx.getActivityMap().getAllElements(tx);
|
||||
Collections.sort(allActivities, comparator);
|
||||
assertEquals(activities, allActivities);
|
||||
}
|
||||
|
||||
try (StrolchTransaction tx = this.runtimeMock.getRealm(this.realmName).openTx(this.certificate, "test")) {
|
||||
ActivityMap activityMap = tx.getActivityMap();
|
||||
|
||||
Set<String> types = activityMap.getTypes(tx);
|
||||
assertEquals(expectedTypes, types);
|
||||
|
||||
Set<String> keySet = activityMap.getAllKeys(tx);
|
||||
assertEquals(15, keySet.size());
|
||||
|
||||
for (String type : types) {
|
||||
Set<String> idsByType = activityMap.getKeysBy(tx, type);
|
||||
assertEquals(5, idsByType.size());
|
||||
|
||||
List<Activity> activitiesByType = activityMap.getElementsBy(tx, type);
|
||||
assertEquals(5, activitiesByType.size());
|
||||
}
|
||||
}
|
||||
|
||||
try (StrolchTransaction tx = this.runtimeMock.getRealm(this.realmName).openTx(this.certificate, "test")) {
|
||||
Activity activity = tx.getActivityMap().getBy(tx, "MyType1", "@00000001");
|
||||
assertNotNull(activity);
|
||||
activity = tx.getActivityMap().getBy(tx, "MyType2", "@00000006");
|
||||
assertNotNull(activity);
|
||||
activity = tx.getActivityMap().getBy(tx, "MyType3", "@00000011");
|
||||
assertNotNull(activity);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -226,6 +226,9 @@ public class OrderModelTestRunner {
|
|||
}
|
||||
}
|
||||
|
||||
// remove the version
|
||||
orders.forEach(t -> t.setVersion(null));
|
||||
|
||||
// now add all again
|
||||
try (StrolchTransaction tx = this.runtimeMock.getRealm(this.realmName).openTx(this.certificate, "test")) {
|
||||
tx.getOrderMap().addAll(tx, orders);
|
||||
|
|
|
@ -226,6 +226,8 @@ public class ResourceModelTestRunner {
|
|||
}
|
||||
}
|
||||
|
||||
resources.forEach(t -> t.setVersion(null));
|
||||
|
||||
// now add all again
|
||||
try (StrolchTransaction tx = this.runtimeMock.getRealm(this.realmName).openTx(this.certificate, "test")) {
|
||||
tx.getResourceMap().addAll(tx, resources);
|
||||
|
|
|
@ -0,0 +1,195 @@
|
|||
package li.strolch.testbase.runtime;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import li.strolch.agent.api.ComponentContainer;
|
||||
import li.strolch.model.ModelGenerator;
|
||||
import li.strolch.model.Resource;
|
||||
import li.strolch.persistence.api.StrolchTransaction;
|
||||
import li.strolch.privilege.model.Certificate;
|
||||
import li.strolch.runtime.privilege.PrivilegeHandler;
|
||||
|
||||
public class VersioningTestRunner {
|
||||
|
||||
private RuntimeMock runtimeMock;
|
||||
private Certificate certificate;
|
||||
|
||||
public VersioningTestRunner(RuntimeMock runtimeMock) {
|
||||
this.runtimeMock = runtimeMock;
|
||||
|
||||
PrivilegeHandler privilegeHandler = runtimeMock.getContainer().getPrivilegeHandler();
|
||||
this.certificate = privilegeHandler.authenticate("test", "test".getBytes());
|
||||
}
|
||||
|
||||
public void runTestsForVersioning() {
|
||||
|
||||
ComponentContainer container = runtimeMock.getContainer();
|
||||
|
||||
// initialize by adding a resource
|
||||
try (StrolchTransaction tx = container.getRealm(certificate).openTx(certificate, VersioningTestRunner.class)) {
|
||||
Resource res1 = ModelGenerator.createResource("MyTestResource", "Test Name", "TestType");
|
||||
tx.getResourceMap().add(tx, res1);
|
||||
// must be first version
|
||||
assertEquals(0, res1.getVersion().getVersion());
|
||||
tx.commitOnClose();
|
||||
}
|
||||
|
||||
// first make sure that the we can't change anything without updating the model
|
||||
try (StrolchTransaction tx = container.getRealm(certificate).openTx(certificate, VersioningTestRunner.class)) {
|
||||
Resource res1 = tx.getResourceBy("TestType", "MyTestResource", true);
|
||||
// must be first version
|
||||
assertEquals(0, res1.getVersion().getVersion());
|
||||
res1.setName("Something");
|
||||
|
||||
tx.commitOnClose();
|
||||
}
|
||||
try (StrolchTransaction tx = container.getRealm(certificate).openTx(certificate, VersioningTestRunner.class)) {
|
||||
Resource res1 = tx.getResourceBy("TestType", "MyTestResource", true);
|
||||
assertEquals("Test Name", res1.getName());
|
||||
|
||||
tx.commitOnClose();
|
||||
}
|
||||
|
||||
// now do a change
|
||||
try (StrolchTransaction tx = container.getRealm(certificate).openTx(certificate, VersioningTestRunner.class)) {
|
||||
Resource res1 = tx.getResourceBy("TestType", "MyTestResource", true);
|
||||
res1.setName("Something");
|
||||
tx.getResourceMap().update(tx, res1);
|
||||
|
||||
tx.commitOnClose();
|
||||
}
|
||||
try (StrolchTransaction tx = container.getRealm(certificate).openTx(certificate, VersioningTestRunner.class)) {
|
||||
Resource res1 = tx.getResourceBy("TestType", "MyTestResource", true);
|
||||
assertEquals("Something", res1.getName());
|
||||
// version must be incremented
|
||||
assertEquals(1, res1.getVersion().getVersion());
|
||||
|
||||
tx.commitOnClose();
|
||||
}
|
||||
|
||||
// now revert the change
|
||||
try (StrolchTransaction tx = container.getRealm(certificate).openTx(certificate, VersioningTestRunner.class)) {
|
||||
Resource revertedVersion = tx.getResourceMap().revertToVersion(tx, "TestType", "MyTestResource", 0);
|
||||
assertEquals("Test Name", revertedVersion.getName());
|
||||
// version must be incremented
|
||||
assertEquals(2, revertedVersion.getVersion().getVersion());
|
||||
|
||||
tx.commitOnClose();
|
||||
}
|
||||
try (StrolchTransaction tx = container.getRealm(certificate).openTx(certificate, VersioningTestRunner.class)) {
|
||||
Resource res1 = tx.getResourceBy("TestType", "MyTestResource", true);
|
||||
assertEquals("Test Name", res1.getName());
|
||||
// version must be incremented
|
||||
assertEquals(2, res1.getVersion().getVersion());
|
||||
|
||||
tx.commitOnClose();
|
||||
}
|
||||
|
||||
// undo a version in same TX
|
||||
try (StrolchTransaction tx = container.getRealm(certificate).openTx(certificate, VersioningTestRunner.class)) {
|
||||
Resource res1 = tx.getResourceBy("TestType", "MyTestResource", true);
|
||||
|
||||
// create a new version:
|
||||
res1.setName("Version 3");
|
||||
tx.getResourceMap().update(tx, res1);
|
||||
// version must be incremented
|
||||
assertEquals(3, res1.getVersion().getVersion());
|
||||
|
||||
// now undo
|
||||
tx.getResourceMap().undoVersion(tx, res1);
|
||||
|
||||
// and validate we have again version 2
|
||||
res1 = tx.getResourceBy("TestType", "MyTestResource", true);
|
||||
assertEquals("Test Name", res1.getName());
|
||||
assertEquals(2, res1.getVersion().getVersion());
|
||||
|
||||
tx.commitOnClose();
|
||||
}
|
||||
try (StrolchTransaction tx = container.getRealm(certificate).openTx(certificate, VersioningTestRunner.class)) {
|
||||
Resource res1 = tx.getResourceBy("TestType", "MyTestResource", true);
|
||||
assertEquals("Test Name", res1.getName());
|
||||
// version must be incremented
|
||||
assertEquals(2, res1.getVersion().getVersion());
|
||||
|
||||
tx.commitOnClose();
|
||||
}
|
||||
|
||||
// undo all versions
|
||||
try (StrolchTransaction tx = container.getRealm(certificate).openTx(certificate, VersioningTestRunner.class)) {
|
||||
Resource res1;
|
||||
|
||||
// undo three times as we have version 0, 1, 2
|
||||
res1 = tx.getResourceBy("TestType", "MyTestResource", true);
|
||||
assertEquals(2, res1.getVersion().getVersion());
|
||||
tx.getResourceMap().undoVersion(tx, res1);
|
||||
|
||||
res1 = tx.getResourceBy("TestType", "MyTestResource", true);
|
||||
assertEquals(1, res1.getVersion().getVersion());
|
||||
tx.getResourceMap().undoVersion(tx, res1);
|
||||
|
||||
res1 = tx.getResourceBy("TestType", "MyTestResource", true);
|
||||
assertEquals(0, res1.getVersion().getVersion());
|
||||
tx.getResourceMap().undoVersion(tx, res1);
|
||||
|
||||
// and validate all are deleted
|
||||
assertFalse(tx.getResourceMap().hasElement(tx, "TestType", "MyTestResource"));
|
||||
|
||||
tx.commitOnClose();
|
||||
}
|
||||
|
||||
// do a deletion
|
||||
try (StrolchTransaction tx = container.getRealm(certificate).openTx(certificate, VersioningTestRunner.class)) {
|
||||
Resource res1 = ModelGenerator.createResource("ball", "Red Ball", "Ball");
|
||||
assertNull(res1.getVersion());
|
||||
|
||||
tx.getResourceMap().add(tx, res1);
|
||||
assertEquals(0, res1.getVersion().getVersion());
|
||||
|
||||
tx.commitOnClose();
|
||||
}
|
||||
try (StrolchTransaction tx = container.getRealm(certificate).openTx(certificate, VersioningTestRunner.class)) {
|
||||
Resource res1 = tx.getResourceBy("Ball", "ball", true);
|
||||
assertEquals("Red Ball", res1.getName());
|
||||
|
||||
tx.getResourceMap().remove(tx, res1);
|
||||
// version must be incremented
|
||||
assertEquals(1, res1.getVersion().getVersion());
|
||||
|
||||
res1 = tx.getResourceBy("Ball", "ball");
|
||||
assertNull(res1);
|
||||
|
||||
assertFalse(tx.getResourceMap().hasElement(tx, "Ball", "ball"));
|
||||
|
||||
tx.commitOnClose();
|
||||
}
|
||||
|
||||
// restore a version manually
|
||||
try (StrolchTransaction tx = container.getRealm(certificate).openTx(certificate, VersioningTestRunner.class)) {
|
||||
Resource res1 = tx.getResourceBy("Ball", "ball");
|
||||
assertNull(res1);
|
||||
|
||||
List<Resource> versions = tx.getResourceMap().getVersionsFor(tx, "Ball", "ball");
|
||||
assertEquals(2, versions.size());
|
||||
|
||||
res1 = versions.get(versions.size() - 1);
|
||||
assertTrue(res1.getVersion().isDeleted());
|
||||
tx.getResourceMap().add(tx, res1);
|
||||
assertEquals(2, res1.getVersion().getVersion());
|
||||
|
||||
tx.commitOnClose();
|
||||
}
|
||||
try (StrolchTransaction tx = container.getRealm(certificate).openTx(certificate, VersioningTestRunner.class)) {
|
||||
Resource res1 = tx.getResourceBy("Ball", "ball");
|
||||
assertNotNull(res1);
|
||||
assertEquals(2, res1.getVersion().getVersion());
|
||||
|
||||
tx.commitOnClose();
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue