[Project] Extended documentation for:

- components
- queries
- realms
- services and commands
This commit is contained in:
Robert von Burg 2016-09-15 18:37:15 +02:00
parent b8834b9b82
commit 55fb3a53c8
7 changed files with 874 additions and 103 deletions

View File

@ -29,6 +29,7 @@ import li.strolch.policy.StrolchPolicy;
import li.strolch.privilege.base.PrivilegeException;
import li.strolch.privilege.handler.SystemUserAction;
import li.strolch.privilege.model.Restrictable;
import li.strolch.runtime.StrolchConstants;
/**
* <p>
@ -121,6 +122,21 @@ public abstract class Command implements Restrictable {
return this.container.getPrivilegeHandler().runAsSystem(username, action);
}
/**
* Performs the given {@link SystemUserAction} as the privileged system user
* {@link StrolchConstants#PRIVILEGED_SYSTEM_USER}. Returns the action for chaining calls
*
* @param action
* the action to perform
*
* @return the action performed for chaining calls
*
* @throws PrivilegeException
*/
protected <V extends SystemUserAction> V runPrivileged(V action) throws PrivilegeException {
return this.container.getPrivilegeHandler().runAsSystem(StrolchConstants.PRIVILEGED_SYSTEM_USER, action);
}
/**
* Returns the {@link StrolchTransaction} bound to this {@link Command}'s runtime
*

View File

@ -55,14 +55,19 @@
<p>Currently we have the following topics of discussion:</p>
<ul>
<li><a href="documentation_runtime.html">Strolch Runtime Configuration</a></li>
<li><a href="documentation_do_and_dont.html">Strolch Do and Dont</a></li>
</ul>
<p>Not yet written, but soon to come are:</p>
<ul>
<li><a href="documentation_transactions.html">Strolch transactions</a></li>
<li><a href="documentation_business_logic.html">Business Logic in Strolch</a></li>
<li><a href="documentation_runtime.html">Strolch Runtime Configuration</a></li>
<li><a href="documentation_realms.html">Strolch Realms</a></li>
<li><a href="documentation_components.html">Strolch Components</a></li>
<li><a href="documentation_services_and_commands.html">Strolch Services and Commands</a></li>
<li><a href="documentation_queries.html">Strolch Queries</a></li>
<!--
<li><a href="documentation_transactions.html">Strolch Transactions</a></li>
<li><a href="documentation_policies.html">Strolch Policies</a></li>
<li><a href="documentation_privileges.html">Strolch Privileges</a></li>
<li><a href="documentation_observers.html">Strolch Observers</a></li>
<li><a href="documentation_versioning.html">Strolch Versioning</a></li>
-->
</ul>
<!-- content here -->

View File

@ -1,96 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="google-site-verification" content="CPhbjooaiTdROm7Vs4E7kuHZvBfkeLUtonGgcVUbTL8"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="">
<meta name="author" content="">
<link rel="shortcut icon" href="ico/favicon.ico">
<title>Strolch: Business Logic</title>
<!-- Bootstrap core CSS -->
<link href="css/bootstrap.min.css" rel="stylesheet">
<!-- Custom styles for this template -->
<link href="css/custom.css" rel="stylesheet">
<!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries --><!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
<script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script><![endif]-->
</head>
<body>
<div class="navbar navbar-inverse navbar-fixed-top" role="navigation">
<div class="container">
<div class="navbar-header">
<a class="navbar-brand" href="index.html">Strolch</a>
</div>
<div class="collapse navbar-collapse">
<ul class="nav navbar-nav">
<li><a href="index.html">Overview</a></li>
<li><a href="api.html">API</a></li>
<li class="active"><a href="documentation.html">Documentation</a></li>
<li><a href="downloads.html">Downloads</a></li>
<li><a href="development.html">Development</a></li>
<li><a href="blog.html">Blog</a></li>
</ul>
</div>
<!--/.nav-collapse -->
</div>
</div>
<div class="container">
<div class="page-header">
<h1 class="page-title">Documentation: Business Logic</h1>
<p class="lead page-description">This page discusses how business logic should be implemented in Strolch.</p>
</div>
<div class="content">
<p>Writing business logic in Strolch</p>
<!-- content here -->
</div>
<!-- /.content -->
<div id="footer">
<div class="container">
<p class="text-muted">&copy; Strolch / <a href="mailto:eitch@eitchnet.ch">Robert von Burg</a> / Hosting by
<a href="http://www.eitchnet.ch">eitchnet.ch</a></p>
</div>
</div>
</div>
<!-- /.container -->
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<!-- Include all compiled plugins (below), or include individual files as needed -->
<script src="js/bootstrap.min.js"></script>
<!-- Piwik -->
<script type="text/javascript">
var _paq = _paq || [];
_paq.push(['trackPageView']);
_paq.push(['enableLinkTracking']);
(function () {
var u = (("https:" == document.location.protocol) ? "https" : "http") + "://piwik.eitchnet.ch/";
_paq.push(['setTrackerUrl', u + 'piwik.php']);
_paq.push(['setSiteId', 2]);
var d = document, g = d.createElement('script'), s = d.getElementsByTagName('script')[0];
g.type = 'text/javascript';
g.defer = true;
g.async = true;
g.src = u + 'piwik.js';
s.parentNode.insertBefore(g, s);
})();
</script>
<noscript><p><img src="http://piwik.eitchnet.ch/piwik.php?idsite=2" style="border:0;" alt=""/></p></noscript>
<!-- End Piwik Code -->
</body>
</html>

View File

@ -0,0 +1,208 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="google-site-verification" content="CPhbjooaiTdROm7Vs4E7kuHZvBfkeLUtonGgcVUbTL8"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="">
<meta name="author" content="">
<link rel="shortcut icon" href="ico/favicon.ico">
<title>Strolch: Components</title>
<!-- Bootstrap core CSS -->
<link href="css/bootstrap.min.css" rel="stylesheet">
<!-- Custom styles for this template -->
<link href="css/custom.css" rel="stylesheet">
<!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries --><!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
<script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script><![endif]-->
</head>
<body>
<div class="navbar navbar-inverse navbar-fixed-top" role="navigation">
<div class="container">
<div class="navbar-header">
<a class="navbar-brand" href="index.html">Strolch</a>
</div>
<div class="collapse navbar-collapse">
<ul class="nav navbar-nav">
<li><a href="index.html">Overview</a></li>
<li><a href="api.html">API</a></li>
<li class="active"><a href="documentation.html">Documentation</a></li>
<li><a href="downloads.html">Downloads</a></li>
<li><a href="development.html">Development</a></li>
<li><a href="blog.html">Blog</a></li>
</ul>
</div>
<!--/.nav-collapse -->
</div>
</div>
<div class="container">
<div class="page-header">
<h1 class="page-title">Documentation: Components</h1>
<p class="lead page-description">This page discusses Strolch Components</p>
</div>
<div class="content">
<p>A Strolch agent can be easily extended with arbitrary components. An agent is basically a container for
classes extending <code>StrolchComponent</code>. Theses classes mostly implement an interface which
describes the
operations that are supported by the component.</p>
<p>The following represents a list of the most used components:</p>
<ul>
<li><code>RealmHandler</code>: li.strolch.agent.impl.DefaultRealmHandler</li>
<li><code>PrivilegeHandler</code>: li.strolch.runtime.privilege.DefaultStrolchPrivilegeHandler</li>
<li><code>EnumHandler</code>: li.strolch.runtime.query.enums.DefaultEnumHandler</li>
<li><code>PolicyHandler</code>: li.strolch.policy.DefaultPolicyHandler</li>
<li><code>ServiceHandler</code>: li.strolch.service.api.DefaultServiceHandler</li>
<li><code>StrolchSessionHandler</code>: li.strolch.rest.DefaultStrolchSessionHandler</li>
<li><code>PersistenceHandler</code>: multiple implementations</li>
<li><code>PostInitializer</code>: project specific implementation</li>
<li><code>MailHandler</code>: li.strolch.handler.mail.SmtpMailHandler</li>
</ul>
<p>A component has a life-cycle, which is governed by the Agent's own life-cycle. The life-cycle is as
follows:</p>
<pre>
setup -> initialize -> start <-> stop -> destroy</pre>
<p>The setup step is used to instantiate the component, the initialize step is used to validate configuration
parameters, and the run step is used to start the component, i.e. start threads, etc. The stop step stops
these threads and also allows the component to be started again. The destroy step destroys the instance and
makes it unusable anymore, i.e. shutdown of the agent.</p>
<p>Each component has its own configuration parameters. A component is registered in the
<code>StrolchConfiguration.xml</code> file with a</p>
<ul>
<li>name</li>
<li>api class name</li>
<li>implementation class name</li>
<li>configuration parameters</li>
<li>any required dependencies</li>
</ul>
<p>The dependencies is an important feature as the dependencies of a component are always started before the
actual component.</p>
<p>By example of the <code>MailHandler</code> we shall show how a strolch component would be implemented.</p>
<p>First define an interface:</p>
<pre>
public interface MailHandler {
public void sendMail(String subject, String text, String recipient);
}
</pre>
<p>Then implement a concrete <code>MailHandler</code>:</p>
<pre>
public class SmtpMailHandler extends StrolchComponent implements MailHandler {
// instance fields with configuration properties to send the mail
public SmtpMailHandler(ComponentContainer container, String componentName) {
super(container, componentName);
}
@Override
public void initialize(ComponentConfiguration configuration) throws Exception {
// store any properties needed from the configuration
super.initialize(configuration);
}
@Override
public void sendMail(String subject, String text, String recipient) {
// send the e-mail using SMTP, or store in stack to send by thread
}
}
</pre>
<p>Now that the component is written, it must be registered on the component, so that it is loaded when the
agent is started. For this the <code>StrolchConfiguration.xml</code> file must be modified to include a
component element:</p>
<pre>
&lt;StrolchConfiguration&gt;
&lt;env id="dev"&gt;
...
&lt;Component&gt;
&lt;name&gt;MailHandler&lt;/name&gt;
&lt;api&gt;li.strolch.handler.mail.MailHandler&lt;/api&gt;
&lt;impl&gt;li.strolch.handler.mail.SmtpMailHandler&lt;/impl&gt;
&lt;Properties&gt;
&lt;username&gt;test&lt;/username&gt;
&lt;password&gt;test&lt;/password&gt;
&lt;hostName&gt;localhost&lt;/hostName&gt;
...
&lt;/Properties&gt;
&lt;/Component&gt;
...
&lt;/env&gt;
&lt;/StrolchConfiguration&gt;
</pre>
<p>Now when the agent is started, the component can be retrieved and used. E.g from inside a
<code>Service</code>:</p>
<pre>
MailHandler mailHandler = getComponent(MailHandler.class);
mailHandler.sendMail("My Subject", "Hello World", "test@test.ch");
</pre>
</pre>
<!-- content here -->
</div>
<!-- /.content -->
<div id="footer">
<div class="container">
<p class="text-muted">&copy; Strolch / <a href="mailto:eitch@eitchnet.ch">Robert von Burg</a> / Hosting by
<a href="http://www.eitchnet.ch">eitchnet.ch</a></p>
</div>
</div>
</div>
<!-- /.container -->
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<!-- Include all compiled plugins (below), or include individual files as needed -->
<script src="js/bootstrap.min.js"></script>
<!-- Piwik -->
<script type="text/javascript">
var _paq = _paq || [];
_paq.push(['trackPageView']);
_paq.push(['enableLinkTracking']);
(function () {
var u = (("https:" == document.location.protocol) ? "https" : "http") + "://piwik.eitchnet.ch/";
_paq.push(['setTrackerUrl', u + 'piwik.php']);
_paq.push(['setSiteId', 2]);
var d = document, g = d.createElement('script'), s = d.getElementsByTagName('script')[0];
g.type = 'text/javascript';
g.defer = true;
g.async = true;
g.src = u + 'piwik.js';
s.parentNode.insertBefore(g, s);
})();
</script>
<noscript><p><img src="http://piwik.eitchnet.ch/piwik.php?idsite=2" style="border:0;" alt=""/></p></noscript>
<!-- End Piwik Code -->
</body>
</html>

View File

@ -0,0 +1,201 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="google-site-verification" content="CPhbjooaiTdROm7Vs4E7kuHZvBfkeLUtonGgcVUbTL8"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="">
<meta name="author" content="">
<link rel="shortcut icon" href="ico/favicon.ico">
<title>Strolch: Queries</title>
<!-- Bootstrap core CSS -->
<link href="css/bootstrap.min.css" rel="stylesheet">
<!-- Custom styles for this template -->
<link href="css/custom.css" rel="stylesheet">
<!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries --><!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
<script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script><![endif]-->
</head>
<body>
<div class="navbar navbar-inverse navbar-fixed-top" role="navigation">
<div class="container">
<div class="navbar-header">
<a class="navbar-brand" href="index.html">Strolch</a>
</div>
<div class="collapse navbar-collapse">
<ul class="nav navbar-nav">
<li><a href="index.html">Overview</a></li>
<li><a href="api.html">API</a></li>
<li class="active"><a href="documentation.html">Documentation</a></li>
<li><a href="downloads.html">Downloads</a></li>
<li><a href="development.html">Development</a></li>
<li><a href="blog.html">Blog</a></li>
</ul>
</div>
<!--/.nav-collapse -->
</div>
</div>
<div class="container">
<div class="page-header">
<h1 class="page-title">Documentation: Queries</h1>
<p class="lead page-description">This page discusses Strolch Queries.</p>
</div>
<div class="content">
<p>As is custom for every framework, querying the model must be possible. Strolch queries are implemented using
the <code>StrolchQuery</code> interface and one of its concrete implementations: <code>ResourceQuery</code>,
<code>OrderQuery</code>,
<code>ActivityQuery</code>.</p>
<p>A Strolch element always has two identifiers: <code>Type</code> and <code>Id</code>. The type is important as
it classifies an element.
So if a car and a house would be modelled in Strolch, then those would both be a <code>Resource</code>, but
one of type
<code>Car</code> and the other of type <code>House</code>. Both would have different parameters.</p>
<p>Thus one of the inputs for every query is it's type, which is defined as the navigation. It is said that we
navigate to the Cars, or Houses. Thus when instantiating a ResourceQuery, pass the navigation to the type of
Resource as well. Same applies for Orders and Activities.</p>
<p>Further input for a StrolchQuery are the selections. These selections get translated into RDBMS
<code>WHERE</code>
clauses. Selections support boolean operations thus allowing for complex querying.</p>
<p>StrolchQueries also support Ordering and object transformation. Following classes provide the most used
scenarios:</p>
<ul>
<li><code>OrderById</code></li>
<li><code>OrderByName</code></li>
<li><code>OrderByParameter</code></li>
<li><code>*ToDomVisitor</code></li>
<li><code>*ToSaxVisitor</code></li>
<li><code>*ToJsonVisitor</code></li>
<li><code>*ToFlatJsonVisitor</code></li>
</ul>
<br/>
<p>Example: Query all resources of type Car:</p>
<pre>
try (StrolchTransaction tx = openTx()) {
ResourceQuery&lt;Resource&gt; query = ResourceQuery.query("Car");
query.withAny();
List&lt;Resource&gt; cars = tx.doQuery(query);
}</pre>
<br/>
<p>Example: Query all resources of type Car, order by Name and transform to JSON:</p>
<pre>
try (StrolchTransaction tx = openTx()) {
ResourceQuery&lt;JsonObject&gt; query = ResourceQuery.query("Car", new ResourceToJsonVisitor(),
new OrderByName());
query.withAny();
List&lt;JsonObject&gt; cars = tx.doQuery(query);
}</pre>
<br/>
<p>the previous example can also be written as follows:</p>
<pre>
try (StrolchTransaction tx = openTx()) {
ResourceQuery&lt;JsonObject&gt; query = new ResourceQuery<>();
query.setNavigation(new StrolchTypeNavigation("Car"));
query.setResourceVisitor(new ResourceToJsonVisitor());
query.withAny();
List&lt;JsonObject&gt; cars = tx.doQuery(query);
}</pre>
<br/>
<p>Example: Query all resources of type Car with color blue:</p>
<pre>
try (StrolchTransaction tx = openTx()) {
ResourceQuery&lt;Resource&gt; query = ResourceQuery.query("Car");
query.with(ParameterSelection.stringSelection("parameters", "color", "blue", StringMatchMode.es()));
List&lt;Resource&gt; cars = tx.doQuery(query);
}</pre>
<br/>
<p>Example: Query all resources of type Car which are not blue:</p>
<pre>
try (StrolchTransaction tx = openTx()) {
ResourceQuery&lt;Resource&gt; query = ResourceQuery.query("Car");
query.not(ParameterSelection.stringSelection("parameters", "color", "blue", StringMatchMode.es()));
List&lt;Resource&gt; cars = tx.doQuery(query);
}</pre>
<br/>
<p>Example: Query all resources of type Car with color blue or yellow:</p>
<pre>
try (StrolchTransaction tx = openTx()) {
ResourceQuery&lt;Resource&gt; query = ResourceQuery.query("Car");
query.or().with(
ParameterSelection.stringSelection("parameters", "color", "blue", StringMatchMode.es()),
ParameterSelection.stringSelection("parameters", "color", "yellow", StringMatchMode.es()));
List&lt;Resource&gt; cars = tx.doQuery(query);
}</pre>
<br/>
<p>Example: Query all resources of type Car with color blue or yellow owned by Jill:</p>
<pre>
try (StrolchTransaction tx = openTx()) {
ResourceQuery&lt;Resource&gt; query = ResourceQuery.query("Car");
StringParameterSelection owner = ParameterSelection.stringSelection("parameters", "owner", "Jill", StringMatchMode.es());
OrSelection colors = new OrSelection().with(
ParameterSelection.stringSelection("parameters", "color", "blue", StringMatchMode.es()),
ParameterSelection.stringSelection("parameters", "color", "yellow", StringMatchMode.es()));
query.and().with(owner, colors);
List&lt;Resource&gt; cars = tx.doQuery(query);
}</pre>
<!-- content here -->
</div>
<!-- /.content -->
<div id="footer">
<div class="container">
<p class="text-muted">&copy; Strolch / <a href="mailto:eitch@eitchnet.ch">Robert von Burg</a> / Hosting by
<a href="http://www.eitchnet.ch">eitchnet.ch</a></p>
</div>
</div>
</div>
<!-- /.container -->
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<!-- Include all compiled plugins (below), or include individual files as needed -->
<script src="js/bootstrap.min.js"></script>
<!-- Piwik -->
<script type="text/javascript">
var _paq = _paq || [];
_paq.push(['trackPageView']);
_paq.push(['enableLinkTracking']);
(function () {
var u = (("https:" == document.location.protocol) ? "https" : "http") + "://piwik.eitchnet.ch/";
_paq.push(['setTrackerUrl', u + 'piwik.php']);
_paq.push(['setSiteId', 2]);
var d = document, g = d.createElement('script'), s = d.getElementsByTagName('script')[0];
g.type = 'text/javascript';
g.defer = true;
g.async = true;
g.src = u + 'piwik.js';
s.parentNode.insertBefore(g, s);
})();
</script>
<noscript><p><img src="http://piwik.eitchnet.ch/piwik.php?idsite=2" style="border:0;" alt=""/></p></noscript>
<!-- End Piwik Code -->
</body>
</html>

View File

@ -0,0 +1,221 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="google-site-verification" content="CPhbjooaiTdROm7Vs4E7kuHZvBfkeLUtonGgcVUbTL8"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="">
<meta name="author" content="">
<link rel="shortcut icon" href="ico/favicon.ico">
<title>Strolch: Realms</title>
<!-- Bootstrap core CSS -->
<link href="css/bootstrap.min.css" rel="stylesheet">
<!-- Custom styles for this template -->
<link href="css/custom.css" rel="stylesheet">
<!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries --><!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
<script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script><![endif]-->
</head>
<body>
<div class="navbar navbar-inverse navbar-fixed-top" role="navigation">
<div class="container">
<div class="navbar-header">
<a class="navbar-brand" href="index.html">Strolch</a>
</div>
<div class="collapse navbar-collapse">
<ul class="nav navbar-nav">
<li><a href="index.html">Overview</a></li>
<li><a href="api.html">API</a></li>
<li class="active"><a href="documentation.html">Documentation</a></li>
<li><a href="downloads.html">Downloads</a></li>
<li><a href="development.html">Development</a></li>
<li><a href="blog.html">Blog</a></li>
</ul>
</div>
<!--/.nav-collapse -->
</div>
</div>
<div class="container">
<div class="page-header">
<h1 class="page-title">Documentation: Realms</h1>
<p class="lead page-description">This page discusses Strolch Realms</p>
</div>
<div class="content">
<p>Realms implement multi-mandate capabilities. A Strolch agent can have an arbitrary number of realms
configured and each realm has its own persistence configuration, allowing to separate mandates
completely.</p>
A realm can run in one of the following modes:
<ul>
<li>EMPTY <br/>
This is a transient data store mode, where no model changes are persisted - they are only kept in
memory. When the Strolch agent is started, this realm is empty as no data is loaded.
</li>
<li>TRANSIENT <br/>
This is the same as EMPTY, but with the difference that when the Strolch agent is started, a model file
is parsed and the in-memory realm is populated with the elements parsed from the model file.
</li>
<li>CACHED <br/>
In this mode, all data is stored in-memory, and any changes made are written back to the persistence
layer. This allows for fast in-memory qeuries, but makes sure no data is lost when the agent is
restarted.
</li>
<li>TRANSACTIONAL <br/>
In this mode no data is kept in-memory and every query, and element retrieval is passed to the
persistence layer to be retrieved from the underlying database. This is similar to typical Java
applications where JPA is used.
</li>
</ul>
<p>Realms are mostly hidden from a developer as a <code>StrolchTransaction</code> exposes all important
operations needed to
access Strolch objects. A developer will however need to configure the realms for their specific project. If
the project only requires one realm, then the <code>defaultRealm</code> can be used, where the developer
only is
required to configure the mode and any relevant model file.</p>
<p>If the mode is CACHED or TRANSACTIONAL, then the <code>PersistenceHandler</code> component is required to be
configured,
so that the DAOs know how to access the underlying database.</p>
<p>The configuration in the <code>StrolchConfiguration.xml</code> file is as follows:</p>
<pre>
&lt;StrolchConfiguration&gt;
&lt;env id="dev"&gt;
...
&lt;Component&gt;
&lt;name&gt;RealmHandler&lt;/name&gt;
&lt;api&gt;li.strolch.agent.api.RealmHandler&lt;/api&gt;
&lt;impl&gt;li.strolch.agent.impl.DefaultRealmHandler&lt;/impl&gt;
&lt;depends&gt;PrivilegeHandler&lt;/depends&gt;
&lt;!-- if CACHED or TRANSACTIONAL: --&gt;
&lt;!--depends&gt;PersistenceHandler&lt;/depends--&gt;
&lt;Properties&gt;
&lt;dataStoreMode&gt;EMPTY|TRANSIENT|CACHED|TRANSACTIONAL&lt;/dataStoreMode&gt;
&lt;dataStoreFile&gt;StrolchModel.xml&lt;/dataStoreFile&gt;
&lt;/Properties&gt;
&lt;/Component&gt;
...
&lt;/env&gt;
&lt;/StrolchConfiguration&gt;
</pre>
<p>A multi-realm configuration would be as follows. Note how the <code>defaultRealm</code> is still enabled, and
has its
configuration as before. Further the PostgreSQL <code>PersistenceHandler</code> is configured to show how
the realms are
connected to the persistence handler:</p>
<pre>
&lt;StrolchConfiguration&gt;
&lt;env id="dev"&gt;
...
&lt;Component&gt;
&lt;name&gt;RealmHandler&lt;/name&gt;
&lt;api&gt;li.strolch.agent.api.RealmHandler&lt;/api&gt;
&lt;impl&gt;li.strolch.agent.impl.DefaultRealmHandler&lt;/impl&gt;
&lt;depends&gt;PrivilegeHandler&lt;/depends&gt;
&lt;depends&gt;PersistenceHandler&lt;/depends&gt;
&lt;Properties&gt;
&lt;realms&gt;defaultRealm, cachedRealm, transactionalRealm&lt;/realms&gt;
&lt;dataStoreMode&gt;TRANSIENT&lt;/dataStoreMode&gt;
&lt;dataStoreFile&gt;DefaultRealm.xml&lt;/dataStoreFile&gt;
&lt;dataStoreMode.transactionalRealm&gt;TRANSACTIONAL&lt;/dataStoreMode.transactionalRealm&gt;
&lt;dataStoreMode.cachedRealm&gt;CACHED&lt;/dataStoreMode.cachedRealm&gt;
&lt;dataStoreMode.emptyRealm&gt;EMPTY&lt;/dataStoreMode.emptyRealm&gt;
&lt;/Properties&gt;
&lt;/Component&gt;
&lt;Component&gt;
&lt;name&gt;PersistenceHandler&lt;/name&gt;
&lt;api&gt;li.strolch.persistence.api.PersistenceHandler&lt;/api&gt;
&lt;impl&gt;li.strolch.persistence.postgresql.PostgreSqlPersistenceHandler&lt;/impl&gt;
&lt;Properties&gt;
&lt;allowSchemaCreation&gt;true&lt;/allowSchemaCreation&gt;
&lt;allowSchemaDrop&gt;true&lt;/allowSchemaDrop&gt;
&lt;db.url.transactionalRealm&gt;jdbc:postgresql://localhost/testdb1&lt;/db.url.transactionalRealm&gt;
&lt;db.username.transactionalRealm&gt;testuser1&lt;/db.username.transactionalRealm&gt;
&lt;db.password.transactionalRealm&gt;test&lt;/db.password.transactionalRealm&gt;
&lt;db.pool.maximumPoolSize.transactionalRealm&gt;1&lt;/db.pool.maximumPoolSize.transactionalRealm&gt;
&lt;db.url.cachedRealm&gt;jdbc:postgresql://localhost/testdb2&lt;/db.url.cachedRealm&gt;
&lt;db.username.cachedRealm&gt;testuser2&lt;/db.username.cachedRealm&gt;
&lt;db.password.cachedRealm&gt;test&lt;/db.password.cachedRealm&gt;
&lt;db.pool.maximumPoolSize.cachedRealm&gt;1&lt;/db.pool.maximumPoolSize.cachedRealm&gt;
&lt;/Properties&gt;
&lt;/Component&gt;
...
&lt;/env&gt;
&lt;/StrolchConfiguration&gt;
</pre>
<p>Accessing a realm is done in multiple ways. Important is to note, that a user should use the
<code>StrolchTransaction</code> object, instead of accessing the Realm directly.</p>
<p>Opening a transaction is done from a <code>Service</code> by calling one of the <code>openTx()</code>-methods.
Nevertheless, the realm can be accessed as follows:</p>
<pre>
ComponentContainer container = getAgent().getContainer();
StrolchRealm realm = container.getRealm(StrolchConstants.DEFAULT_REALM);
try(StrolchTransaction tx = realm.openTx()) {
Resource resource = tx.getResourceBy("TestType", "MyTestResource");
...
}
</pre>
<!-- content here -->
</div>
<!-- /.content -->
<div id="footer">
<div class="container">
<p class="text-muted">&copy; Strolch / <a href="mailto:eitch@eitchnet.ch">Robert von Burg</a> / Hosting by
<a href="http://www.eitchnet.ch">eitchnet.ch</a></p>
</div>
</div>
</div>
<!-- /.container -->
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<!-- Include all compiled plugins (below), or include individual files as needed -->
<script src="js/bootstrap.min.js"></script>
<!-- Piwik -->
<script type="text/javascript">
var _paq = _paq || [];
_paq.push(['trackPageView']);
_paq.push(['enableLinkTracking']);
(function () {
var u = (("https:" == document.location.protocol) ? "https" : "http") + "://piwik.eitchnet.ch/";
_paq.push(['setTrackerUrl', u + 'piwik.php']);
_paq.push(['setSiteId', 2]);
var d = document, g = d.createElement('script'), s = d.getElementsByTagName('script')[0];
g.type = 'text/javascript';
g.defer = true;
g.async = true;
g.src = u + 'piwik.js';
s.parentNode.insertBefore(g, s);
})();
</script>
<noscript><p><img src="http://piwik.eitchnet.ch/piwik.php?idsite=2" style="border:0;" alt=""/></p></noscript>
<!-- End Piwik Code -->
</body>
</html>

View File

@ -0,0 +1,216 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="google-site-verification" content="CPhbjooaiTdROm7Vs4E7kuHZvBfkeLUtonGgcVUbTL8"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="">
<meta name="author" content="">
<link rel="shortcut icon" href="ico/favicon.ico">
<title>Strolch: Services and Commands</title>
<!-- Bootstrap core CSS -->
<link href="css/bootstrap.min.css" rel="stylesheet">
<!-- Custom styles for this template -->
<link href="css/custom.css" rel="stylesheet">
<!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries --><!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
<script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script><![endif]-->
</head>
<body>
<div class="navbar navbar-inverse navbar-fixed-top" role="navigation">
<div class="container">
<div class="navbar-header">
<a class="navbar-brand" href="index.html">Strolch</a>
</div>
<div class="collapse navbar-collapse">
<ul class="nav navbar-nav">
<li><a href="index.html">Overview</a></li>
<li><a href="api.html">API</a></li>
<li class="active"><a href="documentation.html">Documentation</a></li>
<li><a href="downloads.html">Downloads</a></li>
<li><a href="development.html">Development</a></li>
<li><a href="blog.html">Blog</a></li>
</ul>
</div>
<!--/.nav-collapse -->
</div>
</div>
<div class="container">
<div class="page-header">
<h1 class="page-title">Documentation: Services and Commands</h1>
<p class="lead page-description">This page discusses Strolch's Services and Commands API</p>
</div>
<div class="content">
<p><code>Services</code> are written to implement a specific use-case. <code>Commands</code> are written to
implemente re-usable parts of a use-case. The use-case can be abstract e.g. <code>AddResourceService</code>
or very specific e.g.
<code>CreatePatientService</code>.</p>
<p>Should the use-case be re-usable in different scenarios, then commands should implement the logic, and the
services should then execute the commands. E.g. The <code>CreatePatientService</code> would use a
<code>CreatePatientResourceCommand</code> and then use an <code>AddResourceCommand</code> in a single
transaction, so that the task of
creating the actual Patient Resource can be re-used somewhere else.</p>
<p>Services extend the abstract class <code>AbstractService</code> and then implement the method
<code>internalDoService(ServiceArgument)</code>. AbstractService defines generic template arguments with
which the
concrete service can define a specific input ServiceArgument class and output ServiceResult class.</p>
<p>The AbstractService class has multiple helper methods:</p>
<ul>
<li><code>openTx():StrolchTransaction</code> - to open a transaction</li>
<li><code>runPrivileged()</code> - to perform a SystemUserAction</li>
<li><code>getComponent():V</code> - to retrieve a specific StrolchComponent</li>
</ul>
<p>there are more - check the JavaDocs</p>
<p>Commands extend the <code>Command</code> class and then implement the method <code>doCommand()</code>.
Commands have helper
methods:</p>
<ul>
<li><code>tx()</code> - to get the current transaction</li>
<li><code>getPolicy()</code> - to retrieve a policy instance</li>
<li><code>runPrivileged()</code> - to perform a SystemUserAction</li>
</ul>
<p>there are more - check the JavaDocs</p>
<p>The following code snippets shows how a Service and Command are used to perform the task of adding a new
Order. Note how:</p>
<ul>
<li>the Service opens the transaction</li>
<li>adds the command to the TX</li>
<li>calls <code>tx.commitOnClose()</code></li>
<li>the command validates its input</li>
<li>locks the object</li>
<li>performs the work</li>
<li>and implements an undo</li>
</ul>
<p>AddOrderService:</p>
<pre>
public class AddOrderService extends AbstractService&lt;AddOrderService.AddOrderArg, ServiceResult&gt; {
@Override
protected ServiceResult getResultInstance() {
return new ServiceResult();
}
@Override
protected ServiceResult internalDoService(AddOrderArg arg) {
try (StrolchTransaction tx = openTx(arg.realm)) {
AddOrderCommand command = new AddOrderCommand(getContainer(), tx);
command.setOrder(arg.order);
tx.addCommand(command);
tx.commitOnClose();
}
return ServiceResult.success();
}
public static class AddOrderArg extends ServiceArgument {
private static final long serialVersionUID = 1L;
public Order order;
}
}
</pre>
<p>AddOrderCommand:</p>
<pre>
public class AddOrderCommand extends Command {
private Order order;
public AddOrderCommand(ComponentContainer container, StrolchTransaction tx) {
super(container, tx);
}
public void setOrder(Order order) {
this.order = order;
}
@Override
public void validate() {
DBC.PRE.assertNotNull("Order may not be null!", this.order);
}
@Override
public void doCommand() {
tx().lock(this.order);
OrderMap orderMap = tx().getOrderMap();
if (orderMap.hasElement(tx(), this.order.getType(), this.order.getId())) {
String msg = MessageFormat.format("The Order {0} already exists!", this.order.getLocator());
throw new StrolchException(msg);
}
orderMap.add(tx(), this.order);
}
@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.remove(tx(), this.order);
}
}
}
</pre>
<!-- content here -->
</div>
<!-- /.content -->
<div id="footer">
<div class="container">
<p class="text-muted">&copy; Strolch / <a href="mailto:eitch@eitchnet.ch">Robert von Burg</a> / Hosting by
<a href="http://www.eitchnet.ch">eitchnet.ch</a></p>
</div>
</div>
</div>
<!-- /.container -->
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<!-- Include all compiled plugins (below), or include individual files as needed -->
<script src="js/bootstrap.min.js"></script>
<!-- Piwik -->
<script type="text/javascript">
var _paq = _paq || [];
_paq.push(['trackPageView']);
_paq.push(['enableLinkTracking']);
(function () {
var u = (("https:" == document.location.protocol) ? "https" : "http") + "://piwik.eitchnet.ch/";
_paq.push(['setTrackerUrl', u + 'piwik.php']);
_paq.push(['setSiteId', 2]);
var d = document, g = d.createElement('script'), s = d.getElementsByTagName('script')[0];
g.type = 'text/javascript';
g.defer = true;
g.async = true;
g.src = u + 'piwik.js';
s.parentNode.insertBefore(g, s);
})();
</script>
<noscript><p><img src="http://piwik.eitchnet.ch/piwik.php?idsite=2" style="border:0;" alt=""/></p></noscript>
<!-- End Piwik Code -->
</body>
</html>