Modifying a read only element causes an exception. Retrieving elements from the TX, or directly from the ElementMap returns a clone, so nothing changes there. But elements returned by a query will have their readOnly flag set, thus if these are modified, then they need to be cloned first.
New:
- needsCommit() -> return true if objects or commands are registered
- hasResource()
- hasOrder()
- hasActivity()
Changes:
- When tx.add(), update() or remove() is called, then get*Template(), or get*By() check the internal cache and thus e.g. a new resource is immediately available.
- the has*()-methods also check the internal cache, thus the need to get the underlying maps should now no longe be required in normal TX use.
Now execution is always performed asynchronously for each Action and an
Activity should be added to the ExecutionHandler by calling
.addForExecution(), so that it is executed later even if an action
couldn't be executed to it being reserved (for instance).
If a column definition exists as follows:
<Parameter Id="minQuantity" Name="Min Quantity" Type="String"
Interpretation="Resource-Ref" Uom="Storage"
Value="$search:parent:Bags/parameters/minQuantity" />
Then a search is done by looking on this element, and all "parent"
elements where the parent relation is defined by the parameter with the
id "parent". The first instance of the Parameter "minQuantity" is used
as the value for the report.
Create a Report as follows:
<Resource Id="stockReport" Name="Stock Report" Type="Report">
<ParameterBag Id="parameters" Name="parameters" Type="Parameters">
<Parameter Id="objectType" Name="Object Type" Type="String"
Interpretation="Resource-Ref" Uom="Slot" Value="Slot" />
</ParameterBag>
<ParameterBag Id="columns" Name="Display Columns" Type="Display">
<Parameter Id="location" Name="Location" Type="String"
Interpretation="Resource-Ref" Uom="Location" Value="$name" />
<Parameter Id="storage" Name="Storage" Type="String"
Interpretation="Resource-Ref" Uom="Storage" Value="$name" />
<Parameter Id="section" Name="Section" Type="String"
Interpretation="Resource-Ref" Uom="Section" Value="$name" />
<Parameter Id="slot" Name="Slot" Type="String"
Interpretation="Resource-Ref" Uom="Slot" Value="$name" />
<Parameter Id="product" Name="Product" Type="String"
Interpretation="Resource-Ref" Uom="Product" Value="$name" />
<Parameter Id="quantity" Name="Quantity" Type="String"
Interpretation="Resource-Ref" Uom="Slot"
Value="Bags/parameters/quantity" />
<Parameter Id="maxQuantity" Name="Quantity" Type="String"
Interpretation="Resource-Ref" Uom="Slot"
Value="Bags/parameters/maxQuantity" />
</ParameterBag>
<ParameterBag Id="joins" Name="Joins" Type="Joins">
<Parameter Id="Product" Name="Product" Type="String"
Interpretation="Resource-Ref" Uom="Product" Value="Slot" />
<Parameter Id="Section" Name="Section" Type="String"
Interpretation="Resource-Ref" Uom="Section" Value="Slot" />
<Parameter Id="Storage" Name="Storage" Type="String"
Interpretation="Resource-Ref" Uom="Storage" Value="Section" />
<Parameter Id="Location" Name="Location" Type="String"
Interpretation="Resource-Ref" Uom="Location" Value="Storage" />
</ParameterBag>
</Resource>
This creates a report for objects of type Slot, where a Join is done on
multiple objects:
Slot
-> Product
-> Section
-> Storage
-> Location
Thus the columns can then be fetched from different joing objects. The
joing is done by searching for a Parameter on the joined object on the
ParameterBag "relations". See the example XML on how this is done.
Or ask eitch@eitchnet.ch to write a proper documentation =))
Filtering is missing, and will be added later
This is required because in certain instances it is important to lock
the object before retrieving it, otherwise if, for instance in
execution, we would need to fetch, lock and re-fetch to be sure we have
the latest object.
In moste of the Update*Commands this is not important as we perform a
list commit wins, where the client wants their version to be persisted.
Later a optimistic locking can be performed in that the given version
must be the latest, otherwise an exception would be thrown
Should a command be undone, then some commands performed an undo,
although they didn't perform their work, this led to an inconsistent
data model. I.e. AddResourceCommand would fail because the resource
already existed and an undo would lead to the existing object being
removed
Once again it is clear how bad singletons are. One test killed the
timer, thus all other tests failed. Now the DelayedExecutionTimer is
retrieved from the ExecutionHandler and is called DelayedExecutionTimer
with a default implementation of SimpleDurationExecutionTimer
instantiated by the EventBasedExecutionHandler
Using the DurationExecution:
<Activity Id="produceBicycle" Name="Activity" Type="ToStock"
TimeOrdering="Series">
<ParameterBag Name="objectives" Id="Objectives" Type="Objectives">
<Parameter Name="Duration" Id="duration" Value="PT0.01S"
Type="Duration" />
</ParameterBag>
<Action Id="produce" Name="Produce" ResourceId="bicycle"
ResourceType="Product" Type="Produce" />
</Activity>
IActivityElement now has a new method .findParameter() to search up the
activity hierarchy to find the element
Simplified the API, removed the privileged user - now always use the
agent system user for running system actions. One method has no return
value and one has a return value. Now it is easy to perform a system
action using:
runAsAgent(ctx -> {
// do work
});
String result = runAsAgentWithResult(ctx -> {
// do work
return "done";
});
// execute a SystemAction
runAsAgent(action);
// execute a SystemActionWithResult
String result = runAsAgentWithResult(actionWithResult);
Simplified the API, removed the privileged user - now always use the
agent system user for running system actions. One method has no return
value and one has a return value. Now it is easy to perform a system
action using:
runAsAgent(ctx -> {
// do work
});
String result = runAsAgentWithResult(ctx -> {
// do work
return "done";
});
// execute a SystemAction
runAsAgent(action);
// execute a SystemActionWithResult
String result = runAsAgentWithResult(actionWithResult);
- built in User Challenge feature (currently only console)
- extended REST API to allow user to initiate a challenge and then use
the challenge to authenticate for a one time change password session
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
So now users and roles are in their own files. This makes it far easier
to add new privileges without needing to take care if the user changed
their data.
- execption handling is done in the ComponentContainerStateHandler
- clients now not need to worry about exceptions which would make them
rethrow anyhow as a runtime exception
Now a SystemUserAction is defined as follows:
<Privilege name="ch.eitchnet.privilege.handler.SystemUserAction"
policy="DefaultPrivilege">
<Allow>li.strolch.agent.impl.StartRealms</Allow>
</Privilege>
elements is created programmatically and the time and values of the
changes is set by the programmmer. Note, that the persistence and xml
serialization is not implemented yet.
The version handling with code and data migrations was messed up. The
migration version was set after the data migration and then the code
migration used this value for further processing. Now there are two
attributes for the migration version (code and data). The files for the
data migration and the classes for the code migration have now
individual versions.
- now the currentVersions are queried later, because only after the
realm handler is started, can we query the current version.
- this lead to only parsing the migrations at initialize
- and thus in start querying the versions and performing the required
migrations
- If a code migration is run programmatically, then in some migrations
shouldn't fail if a realm is missing -> the realm might not be available
in a certain environment
- We have to re-think this. It does not work, throwing an exception if
commands are registered on a read-only TX as then we don't know if we
want to roll back or not - we probably need a ROLLBACK_ON_ERROR or
something, indicating that we are preparing a non-read-only TX.
- Now if you need to perform commands to carry on in your transaction,
you can simply use the tx.flush()-method.
- Should something go wrong, then even after a tx.flush() one can call
throw tx.fail("Reason") or tx.rollbackOnClose()
- So sadly just auto closing a TX using try-resource from Java7 is a bad idea.
- Doing that leads to problems when an exception is thrown, then the close is called (duh) but this leads to commit being called.
- Since the Java language does not offer a decent way to detect if the close is being called in the context of an exception i was forced to add a tx.commitOnClose() and tx.rollbackOnClose().
- The default is that when a TX is opened, then the close strategy is rollback; the API user must call tx.commitOnClose() before the TX is closed by the braces, or as late as possible, to make sure that if an exception is thrown the transaction is rolled back, and not committed.
- The API was also extended with a tx.fail(msg):StrolchTransactionException so that if the implementor detects an unrecoverable error, one can write: throw tx.fail(“my reason”);
This was sadly an unavoidable late 1.0.0 change
When a TX is closed, all locked objects are unlocked. The but originated from multiple commands being performed for the same object, thus the object was locked multiple times i.e. the lock counter was >1. Now added a releaseLock() method which is called by the TX when the TX is closed so that the lock counter is really 0 and the lock is released.
- Added tests for this situation
- documented the LockHandler
- Now we can use Version to see if current version is greater than
- Fixed bug where version checking didn't check for app
- TODO is still open to handle migration with intermediary steps