diff --git a/ch.eitchnet.utils b/ch.eitchnet.utils
index cde6eb652..401052a5e 160000
--- a/ch.eitchnet.utils
+++ b/ch.eitchnet.utils
@@ -1 +1 @@
-Subproject commit cde6eb652ec2c12ce22c8cb21a16589d56f8a49f
+Subproject commit 401052a5ea5844673615ba4c255b6faa96000adc
diff --git a/li.strolch.agent/src/main/java/li/strolch/agent/api/LockHandler.java b/li.strolch.agent/src/main/java/li/strolch/agent/api/LockHandler.java
index 8136efd81..794daee1f 100644
--- a/li.strolch.agent/src/main/java/li/strolch/agent/api/LockHandler.java
+++ b/li.strolch.agent/src/main/java/li/strolch/agent/api/LockHandler.java
@@ -51,8 +51,10 @@ public interface LockHandler {
*
* @param element
* the element for which a {@link Lock} on its {@link Locator} is to be created and/or locked
+ *
+ * @throws StrolchLockException
*/
- public void lock(StrolchRootElement element);
+ public void lock(StrolchRootElement element) throws StrolchLockException;
/**
*
@@ -67,8 +69,10 @@ public interface LockHandler {
*
* @param element
* the element for which the current/last {@link Lock} is to be unlocked
+ *
+ * @throws StrolchLockException
*/
- public void unlock(StrolchRootElement element);
+ public void unlock(StrolchRootElement element) throws StrolchLockException;
/**
* Releases the lock on the given element, by unlocking all locks, i.e. after this method is called, no lock will be
@@ -76,6 +80,8 @@ public interface LockHandler {
*
* @param element
* the element for which the {@link Lock} on the {@link Locator} is to be released
+ *
+ * @throws StrolchLockException
*/
- public void releaseLock(StrolchRootElement element);
+ public void releaseLock(StrolchRootElement element) throws StrolchLockException;
}
diff --git a/li.strolch.agent/src/main/java/li/strolch/agent/api/StrolchLockException.java b/li.strolch.agent/src/main/java/li/strolch/agent/api/StrolchLockException.java
new file mode 100644
index 000000000..94d0ecade
--- /dev/null
+++ b/li.strolch.agent/src/main/java/li/strolch/agent/api/StrolchLockException.java
@@ -0,0 +1,19 @@
+package li.strolch.agent.api;
+
+import li.strolch.exception.StrolchException;
+
+/**
+ * @author Robert von Burg
+ */
+public class StrolchLockException extends StrolchException {
+
+ private static final long serialVersionUID = 1L;
+
+ public StrolchLockException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public StrolchLockException(String message) {
+ super(message);
+ }
+}
diff --git a/li.strolch.agent/src/main/java/li/strolch/agent/impl/DefaultLockHandler.java b/li.strolch.agent/src/main/java/li/strolch/agent/impl/DefaultLockHandler.java
index bd2458f51..0b25e83c5 100644
--- a/li.strolch.agent/src/main/java/li/strolch/agent/impl/DefaultLockHandler.java
+++ b/li.strolch.agent/src/main/java/li/strolch/agent/impl/DefaultLockHandler.java
@@ -22,7 +22,7 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
import li.strolch.agent.api.LockHandler;
-import li.strolch.exception.StrolchException;
+import li.strolch.agent.api.StrolchLockException;
import li.strolch.model.Locator;
import li.strolch.model.StrolchRootElement;
@@ -60,7 +60,7 @@ public class DefaultLockHandler implements LockHandler {
}
@Override
- public void lock(StrolchRootElement element) {
+ public void lock(StrolchRootElement element) throws StrolchLockException {
Locator locator = element.getLocator();
ReentrantLock lock = this.lockMap.get(locator);
if (lock == null) {
@@ -72,7 +72,7 @@ public class DefaultLockHandler implements LockHandler {
}
@Override
- public void unlock(StrolchRootElement element) {
+ public void unlock(StrolchRootElement element) throws StrolchLockException {
Locator locator = element.getLocator();
ReentrantLock lock = this.lockMap.get(locator);
if (lock == null || !lock.isHeldByCurrentThread()) {
@@ -83,7 +83,7 @@ public class DefaultLockHandler implements LockHandler {
}
@Override
- public void releaseLock(StrolchRootElement element) {
+ public void releaseLock(StrolchRootElement element) throws StrolchLockException {
Locator locator = element.getLocator();
ReentrantLock lock = this.lockMap.get(locator);
if (lock == null || !lock.isHeldByCurrentThread()) {
@@ -96,28 +96,33 @@ public class DefaultLockHandler implements LockHandler {
/**
* @see java.util.concurrent.locks.ReentrantLock#tryLock(long, TimeUnit)
*/
- private void lock(TimeUnit timeUnit, long tryLockTime, ReentrantLock lock, StrolchRootElement element) {
+ private void lock(TimeUnit timeUnit, long tryLockTime, ReentrantLock lock, StrolchRootElement element)
+ throws StrolchLockException {
try {
if (!lock.tryLock(tryLockTime, timeUnit)) {
String msg = "Failed to acquire lock after {0}s for {1}"; //$NON-NLS-1$
msg = MessageFormat.format(msg, timeUnit.toSeconds(tryLockTime), element.getLocator());
- throw new StrolchException(msg);
+ throw new StrolchLockException(msg);
}
if (logger.isDebugEnabled())
logger.debug("locked " + toString()); //$NON-NLS-1$
} catch (InterruptedException e) {
- throw new StrolchException("Thread interrupted: " + e.getMessage(), e); //$NON-NLS-1$
+ throw new StrolchLockException(e.getMessage(), e); //$NON-NLS-1$
}
}
/**
* @see java.util.concurrent.locks.ReentrantLock#unlock()
*/
- private void unlock(ReentrantLock lock) {
- lock.unlock();
- if (logger.isDebugEnabled())
- logger.debug("unlocking " + toString()); //$NON-NLS-1$
+ private void unlock(ReentrantLock lock) throws StrolchLockException {
+ try {
+ lock.unlock();
+ if (logger.isDebugEnabled())
+ logger.debug("unlocking " + toString()); //$NON-NLS-1$
+ } catch (IllegalMonitorStateException e) {
+ throw new StrolchLockException(e.getMessage(), e); //$NON-NLS-1$
+ }
}
/**
diff --git a/li.strolch.agent/src/main/java/li/strolch/persistence/api/AbstractTransaction.java b/li.strolch.agent/src/main/java/li/strolch/persistence/api/AbstractTransaction.java
index 6436b3cb5..9ec9ae206 100644
--- a/li.strolch.agent/src/main/java/li/strolch/persistence/api/AbstractTransaction.java
+++ b/li.strolch.agent/src/main/java/li/strolch/persistence/api/AbstractTransaction.java
@@ -27,6 +27,7 @@ import li.strolch.agent.api.ObserverHandler;
import li.strolch.agent.api.OrderMap;
import li.strolch.agent.api.ResourceMap;
import li.strolch.agent.api.StrolchAgent;
+import li.strolch.agent.api.StrolchLockException;
import li.strolch.agent.api.StrolchRealm;
import li.strolch.agent.impl.AuditingAuditMapFacade;
import li.strolch.agent.impl.AuditingOrderMap;
@@ -60,6 +61,7 @@ import li.strolch.model.timevalue.IValue;
import li.strolch.model.visitor.NoStrategyOrderVisitor;
import li.strolch.model.visitor.NoStrategyResourceVisitor;
import li.strolch.persistence.inmemory.InMemoryTransaction;
+import li.strolch.runtime.StrolchConstants;
import li.strolch.runtime.privilege.PrivilegeHandler;
import li.strolch.service.api.Command;
@@ -159,45 +161,35 @@ public abstract class AbstractTransaction implements StrolchTransaction {
this.closeStrategy.close(this);
}
- /**
- * @param suppressUpdates
- * the suppressUpdates to set
- */
+ @Override
public void setSuppressUpdates(boolean suppressUpdates) {
this.suppressUpdates = suppressUpdates;
}
- /**
- * @return the suppressUpdates
- */
+ @Override
public boolean isSuppressUpdates() {
return this.suppressUpdates;
}
- /**
- * @param suppressAudits
- * the suppressAudits to set
- */
+ @Override
public void setSuppressAudits(boolean suppressAudits) {
this.suppressAudits = suppressAudits;
}
- /**
- * @return the suppressAudits
- */
+ @Override
public boolean isSuppressAudits() {
return this.suppressAudits;
}
@Override
- public void lock(T element) {
+ public void lock(T element) throws StrolchLockException {
this.realm.lock(element);
this.lockedElements.add(element);
}
@Override
- public void unlock(T element) {
- this.realm.unlock(element);
+ public void releaseLock(T element) throws StrolchLockException {
+ this.realm.releaseLock(element);
this.lockedElements.remove(element);
}
@@ -361,6 +353,26 @@ public abstract class AbstractTransaction implements StrolchTransaction {
throw new StrolchException(MessageFormat.format(msg, locator, stateOrBag));
}
+ @Override
+ public Resource getResourceTemplate(String type) {
+ return getResourceBy(StrolchConstants.TEMPLATE, type);
+ }
+
+ @Override
+ public Resource getResourceTemplate(String type, boolean assertExists) throws StrolchException {
+ return getResourceBy(StrolchConstants.TEMPLATE, type, assertExists);
+ }
+
+ @Override
+ public Order getOrderTemplate(String type) {
+ return getOrderBy(StrolchConstants.TEMPLATE, type);
+ }
+
+ @Override
+ public Order getOrderTemplate(String type, boolean assertExists) throws StrolchException {
+ return getOrderBy(StrolchConstants.TEMPLATE, type, assertExists);
+ }
+
@Override
public Order getOrderBy(String type, String id) {
return getOrderBy(type, id, false);
diff --git a/li.strolch.agent/src/main/java/li/strolch/persistence/api/StrolchTransaction.java b/li.strolch.agent/src/main/java/li/strolch/persistence/api/StrolchTransaction.java
index 188d64103..1edd1aa80 100644
--- a/li.strolch.agent/src/main/java/li/strolch/persistence/api/StrolchTransaction.java
+++ b/li.strolch.agent/src/main/java/li/strolch/persistence/api/StrolchTransaction.java
@@ -20,6 +20,10 @@ import java.util.List;
import li.strolch.agent.api.AuditTrail;
import li.strolch.agent.api.OrderMap;
import li.strolch.agent.api.ResourceMap;
+import li.strolch.agent.api.StrolchComponent;
+import li.strolch.agent.api.StrolchLockException;
+import li.strolch.agent.api.StrolchRealm;
+import li.strolch.agent.impl.DataStoreMode;
import li.strolch.exception.StrolchException;
import li.strolch.model.Locator;
import li.strolch.model.Order;
@@ -29,6 +33,7 @@ import li.strolch.model.Resource;
import li.strolch.model.ResourceVisitor;
import li.strolch.model.StrolchElement;
import li.strolch.model.StrolchRootElement;
+import li.strolch.model.Tags;
import li.strolch.model.audit.AccessType;
import li.strolch.model.audit.Audit;
import li.strolch.model.audit.AuditQuery;
@@ -41,55 +46,341 @@ import li.strolch.model.query.ResourceQuery;
import li.strolch.runtime.StrolchConstants;
import li.strolch.service.api.Command;
+/**
+ *
+ * {@link StrolchTransaction} is the central element in Strolch. It gives the developer access to the Strolch model and
+ * performs all the required actions to keep the model consistent etc.
+ *
+ *
+ *
+ * A Strolch transaction is performed as follows as it is an {@link AutoCloseable} implementation
+ *
+ *
+ * StrolchAgent strolchAgent = getStrolchAgent();
+ * StrolchRealm realm = strolchAgent.getContainer().getRealm(StrolchConstants.DEFAULT_REALM);
+ * try(StrolchTransaction tx = realm.openTx(certificate, getClass())){
+ * // do work e.g. add commands
+ * }
+ *
+ *
+ *
+ * A {@link StrolchTransaction} is always opened for a specific realm, should no specific realms be configured, then the
+ * {@link StrolchConstants#DEFAULT_REALM} is automatically created.
+ *
+ *
+ *
+ * A {@link StrolchTransaction} takes care of the following:
+ *
+ *
+ * - Opening and closing database connections
+ * - Releasing locks to strolch elements, if {@link #lock(StrolchRootElement)} is used
+ * - Performing Commands correctly
+ * - exception handling
+ * - auditing
+ * - updating observers
+ *
+ *
+ * @see AbstractTransaction
+ *
+ * @author Robert von Burg
+ */
public interface StrolchTransaction extends AutoCloseable {
+ /**
+ * Returns the name of the {@link StrolchRealm} for which this transaction was opened
+ *
+ * @return the name of the {@link StrolchRealm} for which this transaction was opened
+ */
public String getRealmName();
+ /**
+ * Returns a reference to the {@link AuditTrail} for the {@link StrolchRealm} for which this transaction was opened
+ *
+ * @return the {@link AuditTrail}
+ */
+ public AuditTrail getAuditTrail();
+
+ /**
+ * Returns a reference to the {@link ResourceMap} for the {@link StrolchRealm} for which this transaction was opened
+ *
+ * @return the {@link ResourceMap}
+ */
+ public ResourceMap getResourceMap();
+
+ /**
+ * Returns a reference to the {@link OrderMap} for the {@link StrolchRealm} for which this transaction was opened
+ *
+ * @return the {@link OrderMap}
+ */
+ public OrderMap getOrderMap();
+
+ /**
+ * Returns the {@link PersistenceHandler}. If the {@link StrolchRealm} is not running in
+ * {@link DataStoreMode#TRANSIENT} mode, then the {@link PersistenceHandler} will be a {@link StrolchComponent},
+ * otherwise it will be the internal in memory persistence handler
+ *
+ * @return the {@link PersistenceHandler}
+ */
+ public PersistenceHandler getPersistenceHandler();
+
+ /**
+ * Sets the strategy to be used when closing the transaction when {@link #close()} is called. The default is
+ * {@link TransactionCloseStrategy#COMMIT}, but if the user of the transaction decides it wants to use a different
+ * strategy, then it may set it using this method
+ *
+ * @param closeStrategy
+ * the new {@link TransactionCloseStrategy} to use
+ */
public void setCloseStrategy(TransactionCloseStrategy closeStrategy);
+ /**
+ * If the currently set close strategy is {@link TransactionCloseStrategy#COMMIT}, then when the transaction is
+ * closed, this method is called and all registered {@link Command} are performed, locks on objects are released and
+ * any other resources are released
+ */
public void autoCloseableCommit();
+ /**
+ * If the currently set close strategy is {@link TransactionCloseStrategy#ROLLBACK}, then when the transaction is
+ * closed, no further actions are performed and any {@link Command} which were performed have their
+ * {@link Command#undo()} method called and any DB connections are also rolled back
+ */
public void autoCloseableRollback();
+ /**
+ *
+ * DO NOT CALL THIS METHOD. This interface implements {@link AutoCloseable} and transactions are expected to be used
+ * in a auto closing try block:
+ *
+ *
+ *
+ * StrolchAgent strolchAgent = getStrolchAgent();
+ * StrolchRealm realm = strolchAgent.getContainer().getRealm("defaultRealm");
+ * try(StrolchTransaction tx = realm.openTx(certificate, getClass())){
+ * // do work
+ * }
+ *
+ *
+ * After the block is closed, the transaction is automatically closed and all allocated resources are released
+ */
@Override
public void close() throws StrolchPersistenceException;
+ /**
+ * @return true if the transaction is still open, i.e. not being closed or rolling back, committing, etc.
+ */
public boolean isOpen();
+ /**
+ * @return true if the transaction is in the process of rolling back all changes
+ */
public boolean isRollingBack();
+ /**
+ * @return true if the transaction is in the process of committing the changes
+ */
public boolean isCommitting();
+ /**
+ * @return if the transaction has committed all changes
+ */
public boolean isCommitted();
+ /**
+ * @return if the transaction has rolled back all changes
+ */
public boolean isRolledBack();
- public AuditTrail getAuditTrail();
+ /**
+ * If the given argument is true, then no observer updates are performed
+ *
+ * @param suppressUpdates
+ * true to suppress the updates, false to enable them
+ */
+ public void setSuppressUpdates(boolean suppressUpdates);
- public ResourceMap getResourceMap();
+ /**
+ * Returns true if the observer updates are currently suppressed
+ *
+ * @return true if the observer updates are currently suppressed
+ */
+ public boolean isSuppressUpdates();
- public OrderMap getOrderMap();
+ /**
+ * If the given argument is true, then no {@link Audit Audits} are written
+ *
+ * @param suppressAudits
+ * true to suppress writing {@link Audit Audits}, false to enable them
+ */
+ public void setSuppressAudits(boolean suppressAudits);
- public PersistenceHandler getPersistenceHandler();
+ /**
+ * Returns true if writing {@link Audit Audits} is currently suppressed
+ *
+ * @return true if writing {@link Audit Audits} is currently suppressed
+ */
+ public boolean isSuppressAudits();
- public void lock(T element);
+ /**
+ * Locks the given element and registers it on the transaction so the lock is released when the transaction is
+ * closed
+ *
+ * @param element
+ * the element to lock
+ *
+ * @throws StrolchLockException
+ */
+ public void lock(T element) throws StrolchLockException;
- public void unlock(T element);
+ /**
+ * Releases the lock of the given element so that even though the transaction is still open, another
+ * thread/transaction can lock the element
+ *
+ * @param element
+ * the element for which the lock is to be released
+ *
+ * @throws StrolchLockException
+ */
+ public void releaseLock(T element) throws StrolchLockException;
+ /**
+ * Adds the given {@link Command} to the transaction. Using this method guarantees that a {@link Command} is
+ * executed properly:
+ *
+ * - {@link Command#validate()}
+ * - {@link Command#doCommand()}
+ *
+ *
+ * and if an exception occurs:
+ *
+ * - {@link Command#undo()}
+ *
+ *
+ * @param command
+ */
public void addCommand(Command command);
+ /**
+ * Helper method to create an {@link Audit} with the given arguments. The audit can then be saved by calling
+ * {@link AuditTrail#add(StrolchTransaction, Audit)}
+ *
+ * @param accessType
+ * the type of access
+ * @param elementType
+ * the element type, i.e. s {@link Tags#RESOURCE}, {@link Tags#ORDER}
+ * @param id
+ * the id of the element audited
+ *
+ * @return the new audit
+ */
public Audit auditFrom(AccessType accessType, String elementType, String id);
+ /**
+ *
+ * Performs the given {@link OrderQuery} returning the resulting list of {@link Order Orders}.
+ *
+ *
+ *
+ * Note: Should the result be mapped to different objects, then use
+ * {@link #doQuery(OrderQuery, OrderVisitor)}
+ *
+ *
+ * @param query
+ * the query to perform
+ *
+ * @return the result list, never null
+ */
public List doQuery(OrderQuery query);
+ /**
+ *
+ * Performs the given {@link OrderQuery} and each returned {@link Order} is passed through the {@link OrderVisitor}
+ * and the return value of the visitor is added to the return list
+ *
+ *
+ *
+ * This method is intended for situations where the query result should not be {@link Order} but some other object
+ * type. For instance in a restful API, the result might have to be mapped to a POJO, thus using this method can
+ * perform the mapping step for you
+ *
+ *
+ * @param query
+ * the query to perform
+ *
+ * @return the result list of elements as returned by the {@link OrderVisitor}, never null
+ */
public List doQuery(OrderQuery query, OrderVisitor orderVisitor);
+ /**
+ *
+ * Performs the given {@link ResourceQuery} returning the resulting list of {@link Resource Resources}.
+ *
+ *
+ *
+ * Note: Should the result be mapped to different objects, then use
+ * {@link #doQuery(ResourceQuery, ResourceVisitor)}
+ *
+ *
+ * @param query
+ * the query to perform
+ *
+ * @return the result list, never null
+ */
public List doQuery(ResourceQuery query);
+ /**
+ *
+ * Performs the given {@link ResourceQuery} and each returned {@link Resource} is passed through the
+ * {@link ResourceVisitor} and the return value of the visitor is added to the return list
+ *
+ *
+ *
+ * This method is intended for situations where the query result should not be {@link Resource} but some other
+ * object type. For instance in a restful API, the result might have to be mapped to a POJO, thus using this method
+ * can perform the mapping step for you
+ *
+ *
+ * @param query
+ * the query to perform
+ *
+ * @return the result list of elements as returned by the {@link ResourceVisitor}, never null
+ */
public List doQuery(ResourceQuery query, ResourceVisitor resourceVisitor);
+ /**
+ *
+ * Performs the given {@link AuditQuery} returning the resulting list of {@link Audit Audits}.
+ *
+ *
+ *
+ * Note: Should the result be mapped to different objects, then use
+ * {@link #doQuery(AuditQuery, AuditVisitor)}
+ *
+ *
+ * @param query
+ * the query to perform
+ *
+ * @return the result list, never null
+ */
public List doQuery(AuditQuery query);
+ /**
+ *
+ * Performs the given {@link AuditQuery} and each returned {@link Audit} is passed through the {@link AuditVisitor}
+ * and the return value of the visitor is added to the return list
+ *
+ *
+ *
+ * This method is intended for situations where the query result should not be {@link Audit} but some other object
+ * type. For instance in a restful API, the result might have to be mapped to a POJO, thus using this method can
+ * perform the mapping step for you
+ *
+ *
+ * @param query
+ * the query to perform
+ *
+ * @return the result list of elements as returned by the {@link AuditVisitor}, never null
+ */
public List doQuery(AuditQuery query, AuditVisitor auditVisitor);
/**
@@ -121,6 +412,96 @@ public interface StrolchTransaction extends AutoCloseable {
*/
public T findElement(Locator locator) throws StrolchException, ClassCastException;
+ /**
+ *
+ * Returns the {@link Resource} of Type {@link StrolchConstants#TEMPLATE} with the given type as id, or null if it
+ * does not exist
+ *
+ *
+ *
+ * Templates are {@link StrolchRootElement StrolchRootElements} which have the type
+ * {@link StrolchConstants#TEMPLATE} and their id is the type of element for which it is a template. For instance
+ * when creating a {@link Resource} of type Person
then having a template with the id
+ * Person
helps creating new Person resources; get the resource and then create a clone:
+ * {@link Resource#getClone()}
+ *
+ *
+ * @param type
+ * the id of the {@link Resource} template
+ *
+ * @return the {@link Resource} template with the given id, or null if it does not exist
+ */
+ public Resource getResourceTemplate(String type);
+
+ /**
+ *
+ * Returns the {@link Resource} of Type {@link StrolchConstants#TEMPLATE} with the given type as id. If
+ * assertExists
is true, then an exception is thrown if the template does not exist does not exist
+ *
+ *
+ *
+ * Templates are {@link StrolchRootElement StrolchRootElements} which have the type
+ * {@link StrolchConstants#TEMPLATE} and their id is the type of element for which it is a template. For instance
+ * when creating a {@link Resource} of type Person
then having a template with the id
+ * Person
helps creating new Person resources; get the resource and then create a clone:
+ * {@link Resource#getClone()}
+ *
+ *
+ * @param type
+ * the id of the {@link Resource} template
+ *
+ * @return the {@link Resource} template with the given id, or if assertExists
is true, then an
+ * exception is thrown if the resource does not exist
+ *
+ * @throws StrolchException
+ */
+ public Resource getResourceTemplate(String type, boolean assertExists) throws StrolchException;
+
+ /**
+ *
+ * Returns the {@link Order} of Type {@link StrolchConstants#TEMPLATE} with the given type as id, or null if it does
+ * not exist
+ *
+ *
+ *
+ * Templates are {@link StrolchRootElement StrolchRootElements} which have the type
+ * {@link StrolchConstants#TEMPLATE} and their id is the type of element for which it is a template. For instance
+ * when creating an {@link Order} of type PurchaseOrder
then having a template with the id
+ * PurchaseOrder
helps creating new PurchaseOrder orders; get the order and then create a clone:
+ * {@link Order#getClone()}
+ *
+ *
+ * @param type
+ * the id of the {@link Order} template
+ *
+ * @return the {@link Order} template with the given id, or null if it does not exist
+ */
+ public Order getOrderTemplate(String type);
+
+ /**
+ *
+ * Returns the {@link Order} of Type {@link StrolchConstants#TEMPLATE} with the given type as id. If
+ * assertExists
is true, then an exception is thrown if the template does not exist does not exist
+ *
+ *
+ *
+ * Templates are {@link StrolchRootElement StrolchRootElements} which have the type
+ * {@link StrolchConstants#TEMPLATE} and their id is the type of element for which it is a template. For instance
+ * when creating an {@link Order} of type PurchaseOrder
then having a template with the id
+ * PurchaseOrder
helps creating new PurchaseOrder orders; get the order and then create a clone:
+ * {@link Order#getClone()}
+ *
+ *
+ * @param type
+ * the id of the {@link Order} template
+ *
+ * @return the {@link Order} template with the given id, or if assertExists
is true, then an exception
+ * is thrown if the order does not exist
+ *
+ * @throws StrolchException
+ */
+ public Order getOrderTemplate(String type, boolean assertExists) throws StrolchException;
+
/**
* Returns the {@link Resource} with the given type and id, or null if it does not exist
*