[Project] Removed website, after moving to github pages

This commit is contained in:
Robert von Burg 2021-07-12 17:33:15 +02:00
parent ce73a39c59
commit 35bf3ca68e
55 changed files with 0 additions and 16919 deletions

View File

@ -1,5 +0,0 @@
target/
.project
.settings
.classpath
*.iml

View File

@ -1,201 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
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.

View File

@ -1,4 +0,0 @@
li.strolch.website
==================
This project contains the sources to create Strolch's website at www.strolch.li

View File

@ -1,30 +0,0 @@
<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>li.strolch</groupId>
<artifactId>li.strolch</artifactId>
<version>1.6.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>li.strolch.website</artifactId>
<packaging>pom</packaging>
<name>li.strolch.website</name>
<description>Strolch's Website</description>
<build>
<plugins>
<plugin>
<groupId>org.sonatype.plugins</groupId>
<artifactId>nexus-staging-maven-plugin</artifactId>
<configuration>
<skipNexusStagingDeployMojo>true</skipNexusStagingDeployMojo>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -1,511 +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: API</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 class="active"><a href="api.html">API</a></li>
<li><a href="documentation.html">Documentation</a></li>
<li><a href="plc.html">PLC</a></li>
<li><a href="tutorial.html">Tutorial</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">Strolch API</h1>
<p class="lead page-description">This page describes the Strolch API.</p>
</div>
<div class="content">
<h2>Overview</h2>
<p>The Strolch API revolves around the <i>StrolchTransaction</i> object. The main concept is to implement your
use cases in <i>Service</i> implementations. You open a transaction using the <i>openTx(String)</i>-method
and then perform the use case by adding your <i>Command</i> instances to the transaction.</p>
<p>Transactions are opened on a <i>StrolchRealm</i>. The realms are used to separate mandates in a single
runtime instance of Strolch. Each realm has its own <i>ResourceMap</i>, <i>OrderMap</i>, <i>ActivityMap</i>
instances from which the TX retrieves the elements.</p>
<h2>Model</h2>
<p>The Strolch model is implemented in the project li.strolch.model.</p>
<p>The Strolch model consists of three root level elements: <i>Resource</i>, <i>Order</i> and <i>Activity</i>.
Each element has at least the following attributes:</p>
<ul>
<li>Id &rarr; the element's id</li>
<li>Name &rarr; the element's name</li>
<li>Type &rarr; the element's type</li>
</ul>
<p>Each root element can have any number of <i>ParameterBag</i> instances on it, which in turn can have any
number of <i>Parameters</i> on it. Accessing these objects is always done by their IDs. Strolch root elements
are always stored in the respective <i>ElementMaps</i> in their Strolch realm. Thus accessing a certain
parameter from a <i>Resource</i> would look like this:</p>
<pre class="pre-scrollable">
try (StrolchTransaction tx = openTx(realmName)) {
Resource resource = tx.getResourceBy("TestType", "MyTestResource");
DateParameter dateP = resource.getParameter("@bag01", "@param6");
Date date = dateP.getValue();
logger.info("@param6 date is " + date);
}</pre>
XML Presentation of Strolch's top level elements of <i>Resources</i>:
<pre class="pre-scrollable">
&lt;!-- Resource instance --&gt;
&lt;Resource Id="MyTestResource" Name="Test Name" Type="TestType"&gt;
&lt;ParameterBag Id="@bag01" Name="Test Bag" Type="TestBag"&gt;
&lt;Parameter Id="@param7" Name="StringList Param" Type="StringList" Value="Hello;World" /&gt;
&lt;Parameter Id="@param6" Name="Date Param" Type="Date" Value="2012-11-30T18:12:05.628+01:00" /&gt;
&lt;Parameter Id="@param5" Name="String Param" Type="String" Value="Strolch" /&gt;
&lt;/ParameterBag&gt;
&lt;ParameterBag Id="@bag02" Name="Test Bag" Type="TestBag"&gt;
&lt;Parameter Id="@param4" Name="Long Param" Type="Long" Value="4453234566" /&gt;
&lt;Parameter Id="@param3" Name="Integer Param" Type="Integer" Value="77" /&gt;
&lt;Parameter Id="@param2" Name="Float Param" Type="Float" Value="44.3" /&gt;
&lt;Parameter Id="@param1" Name="Boolean Param" Type="Boolean" Value="true" /&gt;
&lt;/ParameterBag&gt;
&lt;TimedState Id="@integerState" Name="Integer State" Type="IntegerState"&gt;
&lt;Value Time="0" Value="1" /&gt;
&lt;Value Time="1" Value="2" /&gt;
&lt;Value Time="2" Value="3" /&gt;
&lt;TimedState>
&lt;/Resource&gt;</pre>
XML Presentation of Strolch's top level elements of <i>Orders</i>:
<pre class="pre-scrollable">
&lt;!-- Order instance --&gt;
&lt;Order Id="MyTestOrder" Name="Test Name" Type="TestType" Date="2013-11-20T07:42:57.699Z" State="CREATED"&gt;
&lt;ParameterBag Id="@bag01" Name="Test Bag" Type="TestBag"&gt;
&lt;Parameter Id="@param7" Name="StringList Param" Type="StringList" Value="Hello;World" /&gt;
&lt;Parameter Id="@param6" Name="Date Param" Type="Date" Value="2012-11-30T18:12:05.628+01:00" /&gt;
&lt;Parameter Id="@param5" Name="String Param" Type="String" Value="Strolch" /&gt;
&lt;/ParameterBag&gt;
&lt;ParameterBag Id="@bag02" Name="Test Bag" Type="TestBag"&gt;
&lt;Parameter Id="@param4" Name="Long Param" Type="Long" Value="4453234566" /&gt;
&lt;Parameter Id="@param3" Name="Integer Param" Type="Integer" Value="77" /&gt;
&lt;Parameter Id="@param2" Name="Float Param" Type="Float" Value="44.3" /&gt;
&lt;Parameter Id="@param1" Name="Boolean Param" Type="Boolean" Value="true" /&gt;
&lt;/ParameterBag&gt;
&lt;/Order&gt;</pre>
XML Presentation of Strolch's top level elements of <i>Activities</i>:
<pre class="pre-scrollable">
&lt;!-- Activity instance --&gt;
&lt;Activity Id="bicycleProduction" Name="Bicycle Production" Type="Series"&gt;
&lt;Activity Id="componentProduction" Name="Production of components" Type="Series"&gt;
&lt;Action Id="consumeGears" Name="Gears"
ResourceId="gears" ResourceType="Article" Type="Consume"&gt;
&lt;ParameterBag Id="objectives" Name="Production goals" Type="Objectives"&gt;
&lt;Parameter Id="quantity" Name="Quantity" Type="Float" Value="1" /&gt;
&lt;Parameter Id="duration" Name="Duration" Type="Duration" Value="PT0S" /&gt;
&lt;/ParameterBag&gt;
&lt;/Action&gt;
&lt;Activity Id="frameProduction" Name="Production frame" Type="Series"&gt;
&lt;Action Id="produce" Name="Production frame"
ResourceId="frameProduction" ResourceType="Machine" Type="Use"&gt;
&lt;ParameterBag Id="objectives" Name="Production goals" Type="Objectives"&gt;
&lt;Parameter Id="quantity" Name="Quantity" Type="Float" Value="1" /&gt;
&lt;Parameter Id="duration" Name="Duration" Type="Duration" Value="PT5M" /&gt;
&lt;/ParameterBag&gt;
&lt;/Action&gt;
&lt;Action Id="toStock" Name="Frame ToStock"
ResourceId="frame" ResourceType="Article" Type="Produce"&gt;
&lt;ParameterBag Id="objectives" Name="Production goals" Type="Objectives"&gt;
&lt;Parameter Id="quantity" Name="Quantity" Type="Float" Value="1" /&gt;
&lt;Parameter Id="duration" Name="Duration" Type="Duration" Value="PT1M" /&gt;
&lt;/ParameterBag&gt;
&lt;/Action&gt;
&lt;/Activity&gt;
&lt;Activity Id="brakeProduction" Type="Series" Name="Herstellen Bremsen" TimeOrdering="Series"&gt;
&lt;Action Id="produce" Name="Production saddle"
ResourceId="saddleProduction" ResourceType="Machine" Type="Use"&gt;
&lt;ParameterBag Id="objectives" Name="Production goals" Type="Objectives"&gt;
&lt;Parameter Id="quantity" Name="Quantity" Type="Float" Value="1" /&gt;
&lt;Parameter Id="duration" Name="Duration" Type="Duration" Value="PT5M" /&gt;
&lt;/ParameterBag&gt;
&lt;/Action&gt;
&lt;Action Id="toStock" Name="Saddle ToStock"
ResourceId="frame" ResourceType="Article" Type="Produce"&gt;
&lt;ParameterBag Id="objectives" Name="Production goals" Type="Objectives"&gt;
&lt;Parameter Id="quantity" Name="Quantity" Type="Float" Value="1" /&gt;
&lt;Parameter Id="duration" Name="Duration" Type="Duration" Value="PT1M" /&gt;
&lt;/ParameterBag&gt;
&lt;/Action&gt;
&lt;/Activity&gt;
&lt;/Activity&gt;
&lt;Action Id="assembly" Name="Bicycle assemble"
ResourceId="bicycleAssembly" ResourceType="Assembly" Type="Use"&gt;
&lt;ParameterBag Id="objectives" Name="Production goals" Type="Objectives"&gt;
&lt;Parameter Id="quantity" Name="Quantity" Type="Float" Value="1" /&gt;
&lt;Parameter Id="duration" Name="Duration" Type="Duration" Value="PT5M" /&gt;
&lt;/ParameterBag&gt;
&lt;/Action&gt;
&lt;Action Id="toStock" Name="Bicycle to stock"
ResourceId="bicycle" ResourceType="Product" Type="Produce"&gt;
&lt;ParameterBag Id="objectives" Name="Production goals" Type="Objectives"&gt;
&lt;Parameter Id="quantity" Name="Quantity" Type="Float" Value="1" /&gt;
&lt;Parameter Id="duration" Name="Duration" Type="Duration" Value="PT1M" /&gt;
&lt;/ParameterBag&gt;
&lt;/Action&gt;
&lt;/Activity&gt;</pre>
<h2>Realms</h2>
Strolch realms implement the multi-client capability which is thus baked right into the Strolch runtime. When
configuring a Strolch runtime, realms are configured and for each realm the data store mode is set. Each realm
has its own persistence configuration and can thus run in one of the 4 modes that the Strolch agent implements:
<ul>
<li>EMPTY
<p>This is a transient data store mode, where no model changes are persisted, but they are only kept in
memory. When the Strolch agent is started, this realm stays empty as no data is loaded.</p></li>
<li>TRANSIENT
<p>This is the same as EMPTY, but with the difference that when the Strolch agent is started, an XML
file is parsed and the in memory realm is populated with the elements parsed from that XML file.</p>
</li>
<li>CACHED
<p>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 quries, but makes sure no data is lost when the agent is
restarted.</p></li>
</ul>
<p>Strolch Realms are also responsible for opening Transactions, as these are bound to the persistence layer
configured for this realm. At runtime, a realm is then accessed from the ComponentContainer:</p>
<pre class="pre-scrollable">
ComponentContainer container = getAgent().getContainer();
StrolchRealm realm = container.getRealm(StrolchConstants.DEFAULT_REALM);
try(StrolchTransaction tx = realm.openTx()) {
Resource resource = tx.getResourceBy("TestType", "MyTestResource");
...
}</pre>
In a Service implementation there is a convenience method, so that this is as simple as calling <i>openTx(String)</i>.
<h2>Services and Commands</h2>
<p>In the motivation section, it was discusses that writing business logic is what developing is about and a
reason why Strolch is a different approach to the Java EE ecosystem. So this is where Services and Commands
come into play, and tries to make writing business logic a first class citizen.</p>
<p>Services are to be used once for each use case. Services are not re-used or called by other services.
Services open transactions are implement the calling of the re-usable commands. Thus when writing projects
using Strolch, the first thing to do after configuring the runtime environment for your situation, Services
will be implemented.</p>
<p>Commands on the other hand are re-usable and should be implemented in such a way, that they encapsulate the
use case's different actions. Commands are then passed to a transaction for execution and, when the
transaction is committed, will be executed. Commands also implement undoing its operation in the case of
exceptions. Strolch transactions handle the life-cycle of a command. A further function of Commands is to
lock the relevant Strolch elements before execution.</p>
<p>A typical Service and Command implementation would look as follows:</p>
<pre class="pre-scrollable">
public class SetParameterService extends AbstractService&lt;SetParameterArg, ServiceResult&gt; {
public static final long serialVersionUID = 1L;
@Override
protected ServiceResult internalDoService(SetParameterArg arg) {
// open a new transaction
try (StrolchTransaction tx = openTx(arg.realm)) {
// find parameter to modify
Parameter&lt;?&gt; parameter = tx.findElement(arg.locator);
// instantiate the command
SetParameterCommand command = new SetParameterCommand(tx);
// set the arguments
command.setParameter(parameter);
command.setName(arg.name);
command.setInterpretation(arg.interpretation);
command.setUom(arg.uom);
command.setHidden(arg.hidden);
command.setIndex(arg.index);
command.setValueAsString(arg.valueAsString);
// add the command to the transaction
tx.addCommand(command);
// only now do we say we want to commit so that a rollback works nicely
tx.commitOnClose();
}
// return the execution result of the service
return ServiceResult.success();
}
/**
* The argument class for this service
*/
public static class SetParameterArg extends ServiceArgument {
public static final long serialVersionUID = 1L;
public Locator locator;
public String name;
public String interpretation;
public String uom;
public Boolean hidden;
public Integer index;
public String valueAsString;
}
@Override
protected ServiceResult getResultInstance() {
return new ServiceResult();
}
}
</pre>
<pre class="pre-scrollable">
public class SetParameterCommand extends Command {
// input fields
private Parameter&lt;?&gt; parameter;
private String valueAsString;
// undo fields
private String oldValueAsString;
private StrolchRootElement replacedElement;
/**
* @param container
* @param tx
*/
public SetParameterCommand(StrolchTransaction tx) {
super(tx);
}
// setters for input ...
// getters for output ...
@Override
public void validate() {
DBC.PRE.assertNotNull("Parameter may not be null!", this.parameter);
}
@Override
public void doCommand() {
// lock the element to be modified
StrolchRootElement rootElement = this.parameter.getRootElement();
tx().lock(rootElement);
// perform changes
if (this.valueAsString != null) {
this.oldValueAsString = this.parameter.getValueAsString();
SetParameterValueVisitor visitor = new SetParameterValueVisitor();
visitor.setValue(this.parameter, this.valueAsString);
}
// update root element
if (hasChanges()) {
replacedElement = new UpdateElementVisitor(tx()).update(rootElement);
}
}
private boolean hasChanges() {
return this.oldValueAsString != null || this.oldName != null || this.oldInterpretation != null
|| this.oldUom != null || this.oldHidden != null || this.oldIndex != null;
}
@Override
public void undo() {
// undo changes
if (this.oldValueAsString != null) {
SetParameterValueVisitor visitor = new SetParameterValueVisitor();
visitor.setValue(this.parameter, this.oldValueAsString);
}
// update root element
if (hasChanges()
&amp;&amp; this.replacedElement != null
&amp;&amp; this.replacedElement != this.parameter.getRootElement()) {
new UpdateElementVisitor(tx()).update(replacedElement);
}
}
}
}</pre>
<h2>Code</h2>
<p>The Strolch code can be retrieved from GitHub, where the code is hosted. Each commit triggers a continuous
integration build, so that we are sure no tests are broken. The CI is viewable at
<a href="https://ci.4trees.ch" target="_blank">4trees CI Server</a>.</p>
<p>Strolch is divided up into different projects on GitHub so that these projects can be developed, or bugfixed
independently and not all parts are required in every context.</p>
<p><a href="https://github.com/4treesCH/strolch" target="_blank">Strolch on GitHub</a></p>
<h3>Main Strolch components</h3>
<ul>
<li><a href="https://github.com/4treesCH/strolch/tree/master/li.strolch.model">li.strolch.model</a>
<p>This project implements the Strolch model. This is where you will find the different elements that
can store data at runtime e.g. <i>Resources</i>, <i>Orders</i> and <i>Activities</i></p></li>
<li><a href="https://github.com/4treesCH/strolch/tree/master/li.strolch.agent">li.strolch.agent</a>
<p>The agent is the Strolch runtime and is the component which implements the core Agent functionality.
That is:</p>
<ul>
<li>Provide the Agent instance which loads the configuration and is the entry point to the runtime
</li>
<li>Provide the ComponentContainer instance from which the registered components can be accessed
</li>
<li>Configure and maintain the realms, which implement the multi-client capability</li>
<li>Provide a default ServiceHandler to perform Services at runtime</li>
<li>Implements the realms which each can operate in different modes data store modes: CACHED,
TRANSIENT
</li>
</ul>
</li>
<li><a href="https://github.com/4treesCH/strolch/tree/master/li.strolch.service">li.strolch.service</a>
<p>Implements the basic Services and the re-usable Commands:</p>
<ul>
<li>CRUD Services and Commands to modify the model</li>
<li>Commands to import and export the model to XML</li>
<li>Further services and commands...</li>
</ul>
</li>
</ul>
<h3>Additional components</h3>
<ul>
<li><a href="https://github.com/4treesCH/strolch/tree/master/li.strolch.persistence.postgresql">li.strolch.persistence.postgresql</a>
<p>Implements a PostgreSQL persistence layer so that the Strolch model can be persisted to a PostgreSQL
RDBMS when the realm is configured to have a data store mode of CACHED.</p>
</li>
<li><a href="https://github.com/4treesCH/strolch/tree/master/li.strolch.persistence.xml">li.strolch.persistence.xml</a>
<p>Implements an XML persistence layer so that the Strolch model can be persisted to XML files when the
realm is configured to have a data store mode of CACHED.</p>
</li>
<li><a href="https://github.com/4treesCH/strolch/tree/master/li.strolch.rest">li.strolch.rest</a>
<p>Implements a Restful API to communicate with the Strolch runtime from clients and external
systems.</p>
</li>
</ul>
<h3>Meta projects</h3>
<ul>
<li><a href="https://github.com/4treesCH/strolch/tree/master/li.strolch.bom">li.strolch.bom</a>
<p>This bill of material is a Maven project which, when imported in one's own Strolch project, pulls in
all required dependencies needed to set up a minimal working Strolch environment.</p>
</li>
<li><a href="https://github.com/4treesCH/strolch/tree/master/li.strolch.testbase">li.strolch.testbase</a>
<p>Implements a test base so that writing tests for Strolch is easy. It provides a RuntimeMock, which
handles setting up and tearing down Strolch runtimes during tests.</p>
</li>
</ul>
<h3>Example projects</h3>
<ul>
<li><a href="https://github.com/4treesCH/strolch/tree/develop/strolch_minimal_rest" target="_blank">strolch_minimal_rest</a>
<p>A minimal project to get started using REST with Strolch.</p>
</li>
<li><a href="https://github.com/4treesCH/strolch-bookshop" target="_blank">Strolch Bookshop</a>
<p>An example implentation of services etc. where we show how to use Strolch by implementing a simple
book shop.</p>
</li>
</ul>
<h2>Development</h2>
<p>To start getting involved with Strolch Development, or create your own applications using Strolch, then see
the <a href="development.html">development page</a></p>
</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 xsd 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

@ -1,707 +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: Blog</title>
<!-- Bootstrap core CSS -->
<link href="css/bootstrap.min.css" rel="stylesheet">
<!-- Custom styles for this template -->
<link href="css/custom.css" rel="stylesheet">
<link href="css/blog.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><a href="documentation.html">Documentation</a></li>
<li><a href="plc.html">PLC</a></li>
<li><a href="tutorial.html">Tutorial</a></li>
<li><a href="downloads.html">Downloads</a></li>
<li><a href="development.html">Development</a></li>
<li class="active"><a href="blog.html">Blog</a></li>
</ul>
</div>
<!--/.nav-collapse -->
</div>
</div>
<div class="container">
<div class="page-header">
<h1 class="page-title">The Strolch Blog</h1>
<p class="lead page-description">The official Strolch blog with news, ideas, and thoughts on using Strolch.</p>
</div>
<!-- container for whole blog -->
<div class="row">
<!-- blog items -->
<div class="col-sm-8 blog-main">
<!-- blog post -->
<div class="blog-post">
<h2 class="blog-post-title">Strolch Reports</h2>
<p class="blog-post-meta">30. June 2017 by <a href="#">Robert</a></p>
<p>Strolch can do reports!</p>
<hr>
<p>A feature we haven't written about yet is the report API. Strolch has it's own API to generate
reports of data, and since we have a generic model, we use <code>Resource</code> of type
<code>Report</code> to define them.</p>
<p>Go check out the <a href="documentation-reports.html">documentation</a> and then enjoy using this
easy way to deliver the reports your peers require.</p>
</div>
<!-- /.blog-post -->
<!-- blog post -->
<div class="blog-post">
<h2 class="blog-post-title">Strolch Searches</h2>
<p class="blog-post-meta">23. June 2017 by <a href="#">Robert</a></p>
<p>Strolch queries are deprecated!</p>
<hr>
<p>Strolch has had once again many changes, and fixes etc. One important thing to note is that we have
removed support for transactional mode and have rewritten how models are searched. Thus the search
API was born.</p>
<p>Go check out the <a href="documentation-searches.html">Strolch Search</a> documentation and then go
rewrite your searches =)).</p>
<p>Strolch tag <a href="http://search.maven.org/#search%7Cga%7C1%7Cstrolch" target="_blank">1.6.51</a>
has all those juicy changes!</p>
</div>
<!-- /.blog-post -->
<!-- blog post -->
<div class="blog-post">
<h2 class="blog-post-title">Wow, the many changes!</h2>
<p class="blog-post-meta">21. March, 2017 by <a href="#">Robert</a></p>
<p>So many changes, and so long no update - not good!</p>
<hr>
<p>Oh boy, have we forgotten to update you all on the latest awesome features in Strolch! There are over
<a href="https://github.com/4treesCH/strolch/compare/1.3.0...develop">123 commits</a> since the last
tag 1.3.0, so that alone merits a new blog post.</p>
<p>Currently the latest tag is 1.5.5, but this version is actually already quite old, as it was created
on 31. January 2017 and there are 53 new commits ahead of the tag.</p>
<p>Enough of all the commits, lets get to the new features:</p>
<ul>
<li>Added new generic report creator</li>
<li>Added Activity.TimeOrdering and updated Model XSD</li>
<li>Implemented State Model on Activity/Actions</li>
<li>Implemented execution of Activities</li>
<li>Implemented EventBasedExecutionHandler</li>
<li>Added StrolchXmlParser to quickly parse from a file</li>
<li>Add Activity.remove(String) to remove an element</li>
<li>Refactored LockHandler to use Locator</li>
<li>Added Activity.getActionsWithState(State)</li>
<li>Moved *ToFlat and *FromFlat Json Visitors to strolch model</li>
<li>Added StrolchElementQuery.internal()</li>
<li>Added Parameter.clearValue() and list parameters use , as sep</li>
<li>Json Tags are now in Tags.Json and are drinking camel-case</li>
<li>Moved PrivilegeAddUserService to command, added tests</li>
<li>Lots of JavaDoc updates</li>
<li>Refactored code for REST Inspector to use gson</li>
<li>Added inspector REST api for activities</li>
<li>Inspector now has offset/limit for queries</li>
<li>Added new StringMapArgument for StrolchServices</li>
<li>Added missing activity observer calls in AbstractTransaction</li>
<li>Added StringMapResult to use as a ServiceResult</li>
<li>Removed many visitors and implemented proper visitor pattern...</li>
<li>Don't log stack trace if certificate does not exist</li>
<li>SmtpMailer now understands whitelists for override</li>
<li>Fixed locator finding for Activity and Action</li>
<li>Fixed undo logic for general commands</li>
</ul>
<p>To summarize, <b>execution</b> and <b>reporting</b> are the two new features that make Strolch really
awesome! We use execution to perform a number of actions on a remote device connected to a Strolch
agent through WebSockets. This allows serial and parallel execution of actions and of course locking
of concurrently used resources.</p>
<p>In an enterprise world reports can never be missed, so we needed an API to create reports. Of course
that API was created in a way that all things are done in Strolch: generically. Thus a report is
created as a Resource, defining the report object, columns and any relevant joins.</p>
<p>And one of the really cool things is that we have started with a UI for Strolch. There is now an <a
href="https://github.com/4treesCH/strolch-wc-inspector">Inspector</a> with which the entire data
model of a running agent can be seen. This inspector is built using Polymer and WebComponents and
thus can be easily embedded in your application.</p>
<p>To facilitate the authentication of a user for the inspector, an
<a href="https://github.com/4treesCH/strolch-wc-auth">authentication component</a> was created as
well. And of course i18n can't be forgotten, so there is a component for
<a href="https://github.com/4treesCH/strolch-wc-localize-behavior">that</a> too.</p>
<p>To simplify tasks in a web project, there is also a <a href="https://github.com/4treesCH/strolchjs">StrolchJs</a>
repository where certain Strolch specific things are handled e.g. querying the authenticated user's
roles etc.</p>
<p>The release of the next Strolch version isn't defined yet, as we are internally building a project on
all these changes and with the release 1.0.0 of that project (which will be soon), we shall perform
the next release of Strolch.</p>
<p>Until then, happy coding!</p>
</div>
<!-- /.blog-post -->
<!-- blog post -->
<div class="blog-post">
<h2 class="blog-post-title">Strolch now on Maven Central</h2>
<p class="blog-post-meta">22. September, 2016 by <a href="#">Robert</a></p>
<p>Release Version 1.3.0 released and deployed to Maven Central</p>
<hr>
<p>We have released a new version of Strolch so that you can now go and use the the latest features in
Strolch.</p>
<p>Further we have now deployed Strolch to Maven Central, so it is easier than ever to use Strolch in
your projects. No need to download first or use a special repository - just define the dependencies
as you would any other dependency.</p>
<p>Some of the new features:</p>
<ul>
<li>Marshallers for JSON</li>
<li>Versioning built into Strolch</li>
<li>Implemented password reset API for Privilege</li>
<li>New Component MailHandler</li>
<li>New ToFlatJsonVisitor for simple marshalling in REST APIs</li>
<li>Added CRUD Commands and Services for Activities</li>
<li>Further additional bugfixes</li>
</ul>
<p>Strolch has also been moved to another <a target="_blank" href="https://github.com/4treesCH/strolch">organisation</a>
on GitHub, so if you're compiling Strolch from source, please update your GIT remote configurations.
</p>
<p>Have fun using the latest and greatest version of Strolch!</p>
</div>
<!-- /.blog-post -->
<!-- blog post -->
<div class="blog-post">
<h2 class="blog-post-title">Versioning of objects</h2>
<p class="blog-post-meta">8. August, 2016 by <a href="#">Robert</a></p>
<p>Opt-In versioning of objects</p>
<hr>
<p>A major new feature has landed in Strolch. Now, using opt-in, it is possible to have all changes to
the object model be versioned. This means that any change to <code>Order</code>,
<code>Resource</code> or <code>Activity</code> is automatically versioned and one can then revert to
this version later on.</p>
<p>This will make it far easier to implement undo operations in applications since it is an inherent
part of the lifecycle of objects in Strolch.</p>
<p>Since Strolch is supposed to be used also in small footprint hardware, this option is opt-in.</p>
<p>A side affect of this new feature is that we have for the time being not ported the XML persistence
layer. If this is required, then someone drop us a note and we'll check on it.</p>
<p>So now go ahead and add <code>&lt;enableVersioning&gt;true&lt;/enableVersioning&gt;</code> to your
Realm so that versioning is enabled.</p>
</div>
<!-- /.blog-post -->
<!-- blog post -->
<div class="blog-post">
<h2 class="blog-post-title">Release 1.2.0</h2>
<p class="blog-post-meta">4. July, 2016 by <a href="#">Robert</a></p>
<p>Release of Strolch 1.2.0</p>
<hr>
<p>A few months ago we informed of the soon to be released version 1.1.0. Well, we decided to jump to
1.2.0 because we did some refactorings. All the eitchnet projects have been melted into Strolch and
thus now it's all one nice package. This will result in simpler development and less constraints on
APIs between the two projects.</p>
<p>Other than that, not much changed, but we are continually working on Strolch, so go grab your latest
copy and have fun coding!</p>
</div>
<!-- /.blog-post -->
<!-- blog post -->
<div class="blog-post">
<h2 class="blog-post-title">Strolch Update</h2>
<p class="blog-post-meta">April 9, 2016 by <a href="#">Robert</a></p>
<p>Long due update on Strolch development.</p>
<hr>
<p>Although we have been rather quiet in the last couple of months, anyone viewing Strolch's commit log,
will see that we certainly didn't halt Strolch development.</p>
<p>We have been hard at work, using Strolch in projects, which required many new features and fixes. The
commit log shows as of today over 180 commits since the release tag 1.0.0.</p>
<p>Some of the most exciting changes are:</p>
<ul>
<li>REST API to query model, incl. privilege management.</li>
<li>JSON marshalling of all elements.</li>
<li>Added <code>Policies</code></li>
<li>Added persisting of user sessions.</li>
<li>New JavaScript based UI to view Strolch's model. This is an initial version and more UI elements
and functions will follow.
</li>
<li>Basic planning engine functionality.</li>
</ul>
<p>Further new features and changes are:</p>
<ul>
<li>Implemented a REST API to the privilege management - Now users can be added, changed, etc. via
call to the appropriate URL under <code>../strolch/privilege/*</code>.
</li>
<li>Implemented a REST API to query the user sessions. Incl. invalidating sessions to forcefully
logout users.
</li>
<li>Implemented a REST API to query <code>Audits</code>.</li>
<li>Implemented REST API to query <code>Orders</code>, <code>Resources</code> and
<code>Activities</code>/<code>Actions</code></li>
<li>Implemented REST API to update <code>Resources</code> and <code>Orders</code> from XML</li>
<li>REST API to authenticate now adds a cookie, so authorization is much simpler.</li>
<li>Added convenience methods in <code>Service</code> and <code>Command</code> to easily perform
system user actions.
</li>
<li>Added audits for login/logout of users.</li>
<li>Added audits for changes to privilege management.</li>
<li>PostgreSQL persistence layer now uses <a href="https://github.com/brettwooldridge/HikariCP">HikariCP</a>
for connection pooling.
</li>
<li>Implemented a performance test project</li>
<li>Added new Parameters of type <code>IntegerList</code>, <code>FloatList</code> and
<code>LongList</code>.
</li>
<li>Added feature to ignore a realm on DB init.</li>
<li>Implemented core planning functionality.</li>
<li>Added <code>strolch_minimal</code> and <code>strolch_minimal_rest</code> projects to easily get
started.
</li>
<li>Query API now has built in ordering.</li>
<li>Added <code>Policy</code> to all root elements.</li>
<li>Added new planning web app project. This is a test application for demoing the planning engine
functionality of Strolch.
</li>
<li>Adding the persisting and reloading of user sessions, so that a new start of Strolch does not
logout users.
</li>
<li>Implemented to JSON visitors for all root elements.</li>
</ul>
<p>So, although we've been rather quiet on the blog and on social media, we have not been quiet in
Strolch's development. We are planning to release version 1.1.0 soon, so stay tuned!</p>
</div>
<!-- /.blog-post -->
<!-- blog post -->
<div class="blog-post">
<h2 class="blog-post-title">Activities: Beginning of the planning engine</h2>
<p class="blog-post-meta">July 8, 2015 by <a href="#">Robert</a></p>
<p>The ground work of the Strolch planning engine has been laid.</p>
<hr>
<p>One of the core ideas in building Strolch was to create a planning engine. The planning engine would
work in combination of <code>Order</code> objects representing customer orders, <code>Resource</code>
objects representing machines, human resources, etc., and <code>Activity</code>/<code>Action</code>
hierarchies defining a workflow.</p>
<p>With the latest couple of commits to Strolch we have now added Activities and a basic planning of
Actions onto Resources. Activities have an ordered list of <code>IActivityElement</code> which allows
creating an arbitrary deep tree structure of Activity and Action elements.</p>
<p>Action objects have a list of <code>IValueChange</code> objects which define the start, end and
further value changes over time on a referenced Resource. Thus planning an Activity is done by
iterating the Activity hierarchy and for every Action selecting a relevant Resource and then then
applying the changes of the Action on to the referenced <code>TimeState</code> on the Resource.</p>
<p>This implementation is currently very simple as it ignores all constraints which a Resource might
have. In further development we shall implement a <code>Violation</code> model so that UIs can be
built to visualize the over-use of Resources.</p>
<p>In even further steps we would then start implementing algorithms to not just apply the changes onto
a Resource, but to actually search the Resource for time slots when the value changes would not
violate any constraints applied to the resource.</p>
<p>We are very much looking forward to these new features. Stay tuned for your updates - even though
they do take their time to arrive =).</p>
</div>
<!-- /.blog-post -->
<!-- blog post -->
<div class="blog-post">
<h2 class="blog-post-title">Strolch Documentation</h2>
<p class="blog-post-meta">April 6, 2015 by <a href="#">Robert</a></p>
<p>Any good software has some decent documentation explaining concepts, best practices and gives
examples.</p>
<hr>
<p>So this post is to announce that there is now a new page on Strolch's website with a bit of
documentation. This first documentation explains the Strolch runtime and some of the do and don't in
Strolch code.</p>
<p>Bear with us, writing documentation takes time and can be outdated quickly, so we will make an effort
to keep everything up to date and add more documentation, but this is a start.</p>
<p>So go ahead and read the <a href="documentation.html">documentation</a> , and if you haven't already,
also read the rest of the website which should give some more insight into the <a href="index.html">what</a>,
<a href="index.html">why</a> and <a href="api.html">how</a> of Strolch.</p>
</div>
<!-- /.blog-post -->
<!-- blog post -->
<div class="blog-post">
<h2 class="blog-post-title">Strolch Release 1.0.0</h2>
<p class="blog-post-meta">March 31, 2015 by <a href="#">Robert</a></p>
<p>Finally Version 1.0.0 of Strolch has been released and can be <a href="downloads.html">downloaded</a>
immediately.</p>
<hr>
<p>Before 1.0.0 could be released, some major changes were decided, all driven by the first big project
using Strolch as its underlying stack. Those changes were minor, and really major, but should make
Strolch better and was important for the first release.</p>
<p>Here is a list of the most interesting changes:</p>
<ul>
<li>Java 8 - Strolch was ported to Java 8. This gives a lot of cool features: The stream API,
lambdas, the new time API, etc.
</li>
<li>TX refactoring: Strolch transactions are instances of <code>Closeable</code> so that they are
closed using a try-with-resource block in Java7. The change that was required was to not auto
commit. Now a TX is read-only and one has to set the auto commit as the last statement. See <a
href="https://github.com/4treesCH/strolch/commit/46ccb921dfa94f140cbaa3f459c2e434c913d720">this</a>
commit for more information.
</li>
<li>Added a <code>tx.flush()</code> to allow an implementation to flush part of a transaction, this
feature is vital to perform parts of a transaction before deciding if the TX should be
committed.
</li>
<li>Fixed the issue where data store mode <code>CACHED</code> performed <code>TRANSACTIONAL</code>
queries, instead of staying in-memory.
</li>
<li><code>ParameterSelection.stringListSelection()</code> uses a <code>StringMatchMode</code>
instead of just <code>equals()</code></li>
<li><code>ParameterSelection.dateRangeSelection()</code> uses a <code>DateRange</code> instead of
just <code>equals()</code></li>
<li>Added the <code>MigrationsHandler</code> to use to perform code migrations of production data
bases where data shouldn't go lost.
</li>
<li>And many more...</li>
</ul>
<p>Strolch 1.1.0 is already in development and can also be downloaded from the download page. Here you
can see the current change list on
<a href="https://github.com/4treesCH/strolch/compare/1.0.0...develop">GitHub</a>. For instance heavy
work has been done to implement privilege management by adding a REST API. Looking forward to a
wonderful next Strolch release.</p>
</div>
<!-- /.blog-post -->
<!-- blog post -->
<div class="blog-post">
<h2 class="blog-post-title">DurationParameter and other minor changes: Release 1.0.0-RC4</h2>
<p class="blog-post-meta">October 9, 2014 by <a href="#">Robert</a></p>
<p>New <code>DurationParameter</code> and additional minor changes: Release of 1.0.0-RC4 which can be
downloaded on the <a href="downloads.html">download</a> page.</p>
<hr>
<p>While implementing a use case in a Strolch based application it was detected that an essential
parameter type was missing, the <code>DurationParameter</code>. This parameter currently stores the
value as a long in memory and serializes to
<a href="http://en.wikipedia.org/wiki/ISO_8601#Durations">ISO8601</a>. As soon as we move Strolch to
Java8, we will change this to use the <code>Period</code> class in the new Java8 date and time API.
</p>
<p>In addition to the new parameter, a couple of other changes were made:</p>
<ul>
<li>32c1785 [Major] Added Session timeout handling</li>
<li>d55371e [Minor] fixed component version descriptions</li>
<li>c1cdfbb [Bugfix] added missing cloning of StringSetTimedState in Resources</li>
<li>8f50a15 [Major] changed XML format of time value of TimedStates to be ISO8601</li>
<li>5fbbe50 [Bugfix] fix NPE when cloning Resources with no state vars</li>
<li>b77f4b2 [New] added TimeVariable.clear()-method</li>
<li>Updated sub-module ch.eitchnet.utils to 906d24d</li>
<li>Updated sub-module ch.eitchnet.privilege to aa16887</li>
</ul>
<p>So, Strolch 1.0.0-RC4 is out the door, go ahead and <a href="downloads.html">try it out</a>.</p>
</div>
<!-- /.blog-post -->
<!-- blog post -->
<div class="blog-post">
<h2 class="blog-post-title">DB Initialization: Release 1.0.0-RC3</h2>
<p class="blog-post-meta">August 24, 2014 by <a href="#">Robert</a></p>
<p>Important feature <i>Database Initialization</i> added: Release of 1.0.0-RC3 which can be downloaded
on the <a href="downloads.html">download</a> page.</p>
<hr>
<p>When living <i>continuous integration</i> and <i>continuous delivery</i>, it is vital that things
like database migrations and initialization are performed in a controlled, but automatic way.</p>
<p>A Strolch-based application is using the PostgreSQL persistence layer. The implementation understands
the concepts of migration, and validating the database schema, but currently a mechanism to
automatically initialize the database with a minimal set of data was missing.</p>
<p>Migrating a database for Strolch is mostly a one time thing. The object model in Strolch is quite
static, so there is seldom a need to migrate the database. Domain specific changes, i.e. new
Resources, or adding Parameters to Resources, is not a schema change. Thus, instead of going the way
other frameworks go, e.g. Ruby on Rails, we built the data initialization right into the <code>PersistenceHandler</code>.
</p>
<p>Now if the PostgreSQL <code>PersistenceHandler</code> creates the schema, then it might also
initialize the minimal set of data. For this to work, the <code>PersistenceHandler</code> checks if
the flags <code>allowSchemaCreation</code>, <code>allowSchemaDrop</code> and <code>allowDbInitOnSchemaCreate</code>.
If those flags are enabled, and the schema was created during initialization, then the database is
also initialized with the contents of the XML file configured under key <code>dataStoreFile</code> of
the relevant <code>Realm</code>.</p>
<p>The database initialization is done as a system user action which must have the name <code>db_initializer</code>.
This is another fail-safe, so that on a production system, this user can simply be deleted.</p>
<p>So, Strolch 1.0.0-RC3 is out the door, go ahead and <a href="downloads.html">try it out</a>.</p>
</div>
<!-- /.blog-post -->
<!-- blog post -->
<div class="blog-post">
<h2 class="blog-post-title">Release 1.0.0-RC2</h2>
<p class="blog-post-meta">August 22, 2014 by <a href="#">Robert</a></p>
<p>Scratch that RC1, here is the brand new 1.0.0-RC2 which can be downloaded on the
<a href="downloads.html">download</a> page.</p>
<hr>
<p>So, as expected there were a few bugs, for instance the Strolch tutorial apps didn't start, so now i
fixed those and released an RC2. Go <a href="downloads.html">get it</a> and give it a try!</p>
</div>
<!-- /.blog-post -->
<!-- blog post -->
<div class="blog-post">
<h2 class="blog-post-title">Release 1.0.0-RC1</h2>
<p class="blog-post-meta">August 20, 2014 by <a href="#">Robert</a></p>
<p>With the Go-Live of a Strolch-based application around the corner, it is time to release Version
1.0.0 of Strolch. To this affect we have now released version 1.0.0-RC1 which can be downloaded on
the <a href="downloads.html">download</a> page.</p>
<hr>
<h3>Story</h3>
<p>Strolch as a component based software agent has been two years in the making. The concepts in Strolch
have been taken from a proprietary planning, scheduling and controlling software agent, which was,
and is been, used in industrial automation, logistics and production. Strolch was created to bring
the concepts, which were working well for small teams to go-live with large projects in short to
medium time-frames to the open source world.</p>
<p>Strolch was completely rewritten using the key concepts of a parameterized object model and a
component based agent but remembering which clutches the original implementation had, thus trying to
eradicate those without bringing in new ones. It might not be perfect in version 1.0.0, but it is a
starting point form which to carry on from.</p>
<h3>Features</h3>
<p>Strolch isn't feature complete by a long shot, but it sure has got many features which make it
useable in a concrete project, thus making sure it is not vaporware =)</p>
<p>The following is a list of key features, many of which were driven by concrete project
requirements:</p>
<ul>
<li>Separate containers for models (mandates)</li>
<li>Parameterized model with full
<a href="http://en.wikipedia.org/wiki/Create,_read,_update_and_delete">CRUD</a> for Resource and
Order objects
</li>
<li>Timed values on Resources to map values by time</li>
<li>Built-in versioning of model - configurable by Realm</li>
<li>Transparent runtime modes: TRANSIENT, CACHED, TRANSACTIONAL<sup>*</sup></li>
<li>Service and Command pattern for reusing functionality</li>
<li><a href="https://github.com/4treesCH/ch.eitchnet.xmlpers">XML File based persistence
layer</a><sup>*</sup></li>
<li><a href="http://www.postgresql.org/">PostgreSQL</a> persistence layer<sup>*</sup></li>
<li>Querying using a <a href="http://en.wikipedia.org/wiki/Fluent_API">fluent API</a></li>
<li>Services to import and export a model to XML</li>
<li>Integrated authentication and authorization to validate user privileges using
<a href="https://github.com/4treesCH/ch.eitchnet.privilege">Privilege</a></li>
<li>Ready to use <a href="http://en.wikipedia.org/wiki/Observer_pattern">Observer</a> pattern</li>
<li>(currently) Read-only <a href="http://en.wikipedia.org/wiki/Restful">REST</a> API to access the
agent model remotely
</li>
<li>Configurable environments</li>
<li>Opt-in audit trail (including read access, and the audits themselves)</li>
<li>Basic components required to
<a href="https://github.com/4treesCH/ch.eitchnet.utils/tree/master/src/main/java/ch/eitchnet/communication">communicate</a>
with external devices using TCP/IP
</li>
</ul>
<p>With the light weight implementation, where there are basically no third party libraries required for
the normal runtime, Strolch has a minimal foot print which allows it to run on small devices for
instance a <a href="http://beagleboard.org/Products/BeagleBone+Black">BeagleBone Black</a>. Using the
in-memory mode, it is an easy feat to set up test environments with little to no further requirements
than the JVM.</p>
<h3>Future</h3>
<p>So what is planned for the future? Although Strolch has quite a few interesting features, it is by no
way feature complete. The greatest wish is for Strolch to become a community driven platform, so many
new features will arise in the future, but at least one major future feature which will be tackled in
the near future and will certainly drive the next major release is a planning and scheduling engine
using a <a href="http://en.wikipedia.org/wiki/Gantt_chart">Gantt</a> chart to visualize the schedule.
</p>
<p>The planning engine will use the timed values on Resources extensively to create a planning engine on
which Workflows can be placed and allowing to detect violations and bottlenecks.</p>
<p>An extension of the planning of the scheduling engine will allow more than just placing Workflows on
Resources, but actually searching groups of Resources for a time slot of when to place tasks. This
will allow to use capacity constraints to plan and schedule workflows using different algorithms, and
respecting calendars etc.</p>
<p>Further time will be spent on giving Strolch it's own UI. Currently the idea is to use
<a href="http://www.polymer-project.org/">Google's Polymer</a> to implement the UI, thus creating
reusable widgets that can be used in projects.</p>
<h3>Take it for a spin</h3>
<p>So, now the important part is for new users to start using Strolch for their own projects. Go ahead,
check out the <a href="downloads.html">Downloads</a> page for the latest release and then checkout
the two tutorial applications to get yourself up to speed!</p>
<p>Don't hesitate to send us feedback or questions, we will be delighted to help you get your
Strolch-based application up and running, or provide feedback to your concerns!</p>
<h3>Developers</h3>
<p>Robert von Burg<br /> Reto Breitenmoser<br /> Dr. Martin Smock<br /></p>
<p><sup>*</sup> Currently Transactional mode is missing concrete implementation for querying for the XML
persistence</p>
</div>
<!-- /.blog-post -->
<!-- pagination -->
<ul class="pager">
<li><a href="#">Previous</a></li>
<li><a href="#">Next</a></li>
</ul>
</div>
<!-- /.blog-main -->
<!-- sidebar -->
<div-- class="col-sm-3 col-sm-offset-1 blog-sidebar">
<div class="sidebar-module sidebar-module-inset">
<h4>About</h4>
<p>Strolch is an open source component based software agent written in Java and can be compared, in a
light sense, with the Java EE stack: Strolch takes care of persistence, implements Services for use
cases, Commands as re-usable algorithms and has a parameterized data model.</p>
</div>
<!--div class="sidebar-module">
<h4>Archives</h4>
<ol class="list-unstyled">
<li><a href="#">August 2014</a></li>
< ! - -
<li><a href="#">February 2014</a></li>
<li><a href="#">January 2014</a></li>
<li><a href="#">December 2013</a></li>
<li><a href="#">November 2013</a></li>
<li><a href="#">October 2013</a></li>
<li><a href="#">September 2013</a></li>
<li><a href="#">August 2013</a></li>
<li><a href="#">July 2013</a></li>
<li><a href="#">June 2013</a></li>
<li><a href="#">May 2013</a></li>
<li><a href="#">April 2013</a></li>
- - >
</ol>
</div-->
<div class="sidebar-module">
<h4>Elsewhere</h4>
<ol class="list-unstyled">
<li><a href="https://github.com/4treesCH">GitHub</a></li>
<li><a href="https://twitter.com/eitchme">Twitter</a></li>
<li><a href="https://www.facebook.com/strolch.li">Facebook</a></li>
<li><a href="https://plus.google.com/u/0/communities/100208129798096060842">Google+</a></li>
</ol>
</div>
</div>
<!-- /.blog-sidebar -->
</div>
<!-- /.row -->
<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 xsd 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

@ -1,124 +0,0 @@
/*
* Globals
*/
/*
* Override Bootstrap's default container.
*/
/*
* Masthead for nav
*/
.blog-masthead {
background-color: #428bca;
-webkit-box-shadow: inset 0 -2px 5px rgba(0,0,0,.1);
box-shadow: inset 0 -2px 5px rgba(0,0,0,.1);
}
/* Nav links */
.blog-nav-item {
position: relative;
display: inline-block;
padding: 10px;
font-weight: 500;
color: #cdddeb;
}
.blog-nav-item:hover,
.blog-nav-item:focus {
color: #fff;
text-decoration: none;
}
/* Active state gets a caret at the bottom */
.blog-nav .active {
color: #fff;
}
.blog-nav .active:after {
position: absolute;
bottom: 0;
left: 50%;
width: 0;
height: 0;
margin-left: -5px;
vertical-align: middle;
content: " ";
border-right: 5px solid transparent;
border-bottom: 5px solid;
border-left: 5px solid transparent;
}
/*
* Main column and sidebar layout
*/
.blog-main {
line-height: 1.5;
}
.blog-sidebar {
margin-top: 100px;
}
/* Sidebar modules for boxing content */
.sidebar-module {
padding: 15px;
margin: 0 -15px 15px;
}
.sidebar-module-inset {
padding: 15px;
background-color: #f5f5f5;
border-radius: 4px;
}
.sidebar-module-inset p:last-child,
.sidebar-module-inset ul:last-child,
.sidebar-module-inset ol:last-child {
margin-bottom: 0;
}
/* Pagination */
.pager {
margin-bottom: 60px;
text-align: left;
}
.pager > li > a {
width: 140px;
padding: 10px 20px;
text-align: center;
border-radius: 30px;
}
/*
* Blog posts
*/
.blog-post {
margin-bottom: 60px;
}
.blog-post-title {
margin-bottom: 5px;
font-size: 2.0em;
}
.blog-post-meta {
margin-bottom: 20px;
color: #999;
}
/*
* Footer
*/
.blog-footer {
padding: 40px 0;
color: #999;
text-align: center;
background-color: #f9f9f9;
border-top: 1px solid #e5e5e5;
}
.blog-footer p:last-child {
margin-bottom: 0;
}

View File

@ -1,347 +0,0 @@
/*!
* Bootstrap v3.1.1 (http://getbootstrap.com)
* Copyright 2011-2014 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
*/
.btn-default,
.btn-primary,
.btn-success,
.btn-info,
.btn-warning,
.btn-danger {
text-shadow: 0 -1px 0 rgba(0, 0, 0, .2);
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075);
}
.btn-default:active,
.btn-primary:active,
.btn-success:active,
.btn-info:active,
.btn-warning:active,
.btn-danger:active,
.btn-default.active,
.btn-primary.active,
.btn-success.active,
.btn-info.active,
.btn-warning.active,
.btn-danger.active {
-webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
}
.btn:active,
.btn.active {
background-image: none;
}
.btn-default {
text-shadow: 0 1px 0 #fff;
background-image: -webkit-linear-gradient(top, #fff 0%, #e0e0e0 100%);
background-image: linear-gradient(to bottom, #fff 0%, #e0e0e0 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
background-repeat: repeat-x;
border-color: #dbdbdb;
border-color: #ccc;
}
.btn-default:hover,
.btn-default:focus {
background-color: #e0e0e0;
background-position: 0 -15px;
}
.btn-default:active,
.btn-default.active {
background-color: #e0e0e0;
border-color: #dbdbdb;
}
.btn-primary {
background-image: -webkit-linear-gradient(top, #428bca 0%, #2d6ca2 100%);
background-image: linear-gradient(to bottom, #428bca 0%, #2d6ca2 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff2d6ca2', GradientType=0);
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
background-repeat: repeat-x;
border-color: #2b669a;
}
.btn-primary:hover,
.btn-primary:focus {
background-color: #2d6ca2;
background-position: 0 -15px;
}
.btn-primary:active,
.btn-primary.active {
background-color: #2d6ca2;
border-color: #2b669a;
}
.btn-success {
background-image: -webkit-linear-gradient(top, #5cb85c 0%, #419641 100%);
background-image: linear-gradient(to bottom, #5cb85c 0%, #419641 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
background-repeat: repeat-x;
border-color: #3e8f3e;
}
.btn-success:hover,
.btn-success:focus {
background-color: #419641;
background-position: 0 -15px;
}
.btn-success:active,
.btn-success.active {
background-color: #419641;
border-color: #3e8f3e;
}
.btn-info {
background-image: -webkit-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);
background-image: linear-gradient(to bottom, #5bc0de 0%, #2aabd2 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
background-repeat: repeat-x;
border-color: #28a4c9;
}
.btn-info:hover,
.btn-info:focus {
background-color: #2aabd2;
background-position: 0 -15px;
}
.btn-info:active,
.btn-info.active {
background-color: #2aabd2;
border-color: #28a4c9;
}
.btn-warning {
background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);
background-image: linear-gradient(to bottom, #f0ad4e 0%, #eb9316 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
background-repeat: repeat-x;
border-color: #e38d13;
}
.btn-warning:hover,
.btn-warning:focus {
background-color: #eb9316;
background-position: 0 -15px;
}
.btn-warning:active,
.btn-warning.active {
background-color: #eb9316;
border-color: #e38d13;
}
.btn-danger {
background-image: -webkit-linear-gradient(top, #d9534f 0%, #c12e2a 100%);
background-image: linear-gradient(to bottom, #d9534f 0%, #c12e2a 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
background-repeat: repeat-x;
border-color: #b92c28;
}
.btn-danger:hover,
.btn-danger:focus {
background-color: #c12e2a;
background-position: 0 -15px;
}
.btn-danger:active,
.btn-danger.active {
background-color: #c12e2a;
border-color: #b92c28;
}
.thumbnail,
.img-thumbnail {
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
}
.dropdown-menu > li > a:hover,
.dropdown-menu > li > a:focus {
background-color: #e8e8e8;
background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);
background-repeat: repeat-x;
}
.dropdown-menu > .active > a,
.dropdown-menu > .active > a:hover,
.dropdown-menu > .active > a:focus {
background-color: #357ebd;
background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%);
background-image: linear-gradient(to bottom, #428bca 0%, #357ebd 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);
background-repeat: repeat-x;
}
.navbar-default {
background-image: -webkit-linear-gradient(top, #fff 0%, #f8f8f8 100%);
background-image: linear-gradient(to bottom, #fff 0%, #f8f8f8 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
background-repeat: repeat-x;
border-radius: 4px;
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075);
}
.navbar-default .navbar-nav > .active > a {
background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f3f3f3 100%);
background-image: linear-gradient(to bottom, #ebebeb 0%, #f3f3f3 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff3f3f3', GradientType=0);
background-repeat: repeat-x;
-webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075);
box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075);
}
.navbar-brand,
.navbar-nav > li > a {
text-shadow: 0 1px 0 rgba(255, 255, 255, .25);
}
.navbar-inverse {
background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222 100%);
background-image: linear-gradient(to bottom, #3c3c3c 0%, #222 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
background-repeat: repeat-x;
}
.navbar-inverse .navbar-nav > .active > a {
background-image: -webkit-linear-gradient(top, #222 0%, #282828 100%);
background-image: linear-gradient(to bottom, #222 0%, #282828 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff282828', GradientType=0);
background-repeat: repeat-x;
-webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25);
box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25);
}
.navbar-inverse .navbar-brand,
.navbar-inverse .navbar-nav > li > a {
text-shadow: 0 -1px 0 rgba(0, 0, 0, .25);
}
.navbar-static-top,
.navbar-fixed-top,
.navbar-fixed-bottom {
border-radius: 0;
}
.alert {
text-shadow: 0 1px 0 rgba(255, 255, 255, .2);
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05);
}
.alert-success {
background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);
background-image: linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);
background-repeat: repeat-x;
border-color: #b2dba1;
}
.alert-info {
background-image: -webkit-linear-gradient(top, #d9edf7 0%, #b9def0 100%);
background-image: linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);
background-repeat: repeat-x;
border-color: #9acfea;
}
.alert-warning {
background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);
background-image: linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);
background-repeat: repeat-x;
border-color: #f5e79e;
}
.alert-danger {
background-image: -webkit-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);
background-image: linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);
background-repeat: repeat-x;
border-color: #dca7a7;
}
.progress {
background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);
background-image: linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);
background-repeat: repeat-x;
}
.progress-bar {
background-image: -webkit-linear-gradient(top, #428bca 0%, #3071a9 100%);
background-image: linear-gradient(to bottom, #428bca 0%, #3071a9 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3071a9', GradientType=0);
background-repeat: repeat-x;
}
.progress-bar-success {
background-image: -webkit-linear-gradient(top, #5cb85c 0%, #449d44 100%);
background-image: linear-gradient(to bottom, #5cb85c 0%, #449d44 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);
background-repeat: repeat-x;
}
.progress-bar-info {
background-image: -webkit-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);
background-image: linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);
background-repeat: repeat-x;
}
.progress-bar-warning {
background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);
background-image: linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);
background-repeat: repeat-x;
}
.progress-bar-danger {
background-image: -webkit-linear-gradient(top, #d9534f 0%, #c9302c 100%);
background-image: linear-gradient(to bottom, #d9534f 0%, #c9302c 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);
background-repeat: repeat-x;
}
.list-group {
border-radius: 4px;
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
}
.list-group-item.active,
.list-group-item.active:hover,
.list-group-item.active:focus {
text-shadow: 0 -1px 0 #3071a9;
background-image: -webkit-linear-gradient(top, #428bca 0%, #3278b3 100%);
background-image: linear-gradient(to bottom, #428bca 0%, #3278b3 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3278b3', GradientType=0);
background-repeat: repeat-x;
border-color: #3278b3;
}
.panel {
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .05);
box-shadow: 0 1px 2px rgba(0, 0, 0, .05);
}
.panel-default > .panel-heading {
background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);
background-repeat: repeat-x;
}
.panel-primary > .panel-heading {
background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%);
background-image: linear-gradient(to bottom, #428bca 0%, #357ebd 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);
background-repeat: repeat-x;
}
.panel-success > .panel-heading {
background-image: -webkit-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);
background-image: linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);
background-repeat: repeat-x;
}
.panel-info > .panel-heading {
background-image: -webkit-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);
background-image: linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);
background-repeat: repeat-x;
}
.panel-warning > .panel-heading {
background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);
background-image: linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);
background-repeat: repeat-x;
}
.panel-danger > .panel-heading {
background-image: -webkit-linear-gradient(top, #f2dede 0%, #ebcccc 100%);
background-image: linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);
background-repeat: repeat-x;
}
.well {
background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);
background-image: linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);
background-repeat: repeat-x;
border-color: #dcdcdc;
-webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1);
box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1);
}
/*# sourceMappingURL=bootstrap-theme.css.map */

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,49 +0,0 @@
/*
* Globals
*/
/*
* Override Bootstrap's default container.
*/
.content {
padding: 0px 2em 3em;
}
blockquote {
font-size: 1.0em;
}
@media (min-width: 1200px) {
.container {
width: 970px;
}
}
.page-header {
padding-top: 20px;
}
.page-title {
margin-top: 30px;
margin-bottom: 0;
font-size: 2.2em;
font-weight: normal;
}
.page-description {
padding-top: 20px;
font-size: 1.6em;
color: #999;
}
#footer {
font-size: 0.8em;
}
.image {
display: block;
margin-left: auto;
margin-right: auto;
margin-bottom: 10px;
}

View File

@ -1,14 +0,0 @@
.release, .snapshot {
float: left;
padding: 20px;
}
.release {
width: 350px;
}
.snapshot {
width: 350px;
}
.previousRelease {
clear: both;
}

View File

@ -1,199 +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: Development</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><a href="documentation.html">Documentation</a></li>
<li><a href="plc.html">PLC</a></li>
<li><a href="tutorial.html">Tutorial</a></li>
<li><a href="downloads.html">Downloads</a></li>
<li class="active"><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">Development</h1>
<p class="lead page-description">This page describes how to setup the development environment.</p>
</div>
<div class="content">
<h2>Prerequisites</h2>
To start developing Strolch you need an installed:
<ul>
<li>Java JDK 8</li>
<li>Apache Maven 3</li>
</ul>
<h2>Building Strolch</h2>
<p>Setting up Strolch is just a few lines:</p>
<pre class="pre">
git clone https://github.com/4treesCH/strolch.git
cd strolch
mvn clean install -DskipTests</pre>
<p><b>Note:</b> To run the tests you will need to configure the PostgreSQL Databases. See the README in the
module.</p>
<p>After running the Maven build, you will have a full build of all Strolch projects. Now you can start
modifying the projects, and add your own features, or, far more interesting, start developing your projects
using the Strolch agent.</p>
<h2>Creating a Strolch App</h2>
<p>To create your own Strolch App, you can use Maven's archetype generation. There are two versions, one is a
simple Java App which you can use to directly access the Strolch runtime, and the second is to create a Java
Web App, which is the usual way to run Strolch runtimes.</p>
<p><b>Note:</b> you need to have installed Strolch to your local maven repo, otherwise the archetype won't be
available.</p>
<h3>Creating a simple Java Strolch App</h3>
<p>The following shows the maven command to create the new maven project. Note that you should replace the
placeholders in the brackets:</p>
<pre>
mvn archetype:generate \
-DarchetypeGroupId=li.strolch \
-DarchetypeArtifactId=li.strolch.mvn.archetype.main \
-DarchetypeVersion=1.6.0-SNAPSHOT \
-DgroupId=&lt;my.groupid&gt; \
-DartifactId=&lt;my-artifactId&gt; \
-Dversion=&lt;my.version&gt; \
-DappName="&lt;my app name&gt;"</pre>
<p>You change into the directory of the new project and then build the project by calling:</p>
<pre>
cd &lt;my-artifactId&gt;
mvn clean package</pre>
<p>Start the program using:</p>
<pre>
mvn exec:java</pre>
<p>Happy coding =))</p>
<h3>Creating a Java Strolch Web App</h3>
<p>The following shows the maven command to create the new maven project. Note that you should replace the
placeholders in the brackets:</p>
<pre>
mvn archetype:generate \
-DarchetypeGroupId=li.strolch \
-DarchetypeArtifactId=li.strolch.mvn.archetype.webapp \
-DarchetypeVersion=1.6.0-SNAPSHOT \
-DgroupId=&lt;my.groupid&gt; \
-DartifactId=&lt;my-artifactId&gt; \
-Dversion=&lt;my.version&gt; \
-DappName="&lt;my app name&gt;"</pre>
<h4>Install the web dependencies</h4>
<p>The Strolch Web App uses <a href="https://nodejs.org/download/release/v11.15.0/">NodeJS v11.x</a> to build
the web dependencies. Please download the relevant platform's package, unpack it, and add the
<code>bin</code> directory to your path variable. </p>
<p>Once NodeJS is installed, then you can prepare the web dependencies:</p>
<pre>
cd src/main/webapp/
npm install gulp -g
npm install
gulp</pre>
<p><b>Note:</b> Whenever the <code>bower.json</code> is changed then you should again call <code>npm
install</code>
inside the webapp folder.</p>
<h4>Building the WAR</h4>
<p>Building the WAR uses the <code>package</code> maven goal, but to have the optimized WAR use the <code>release</code>
profile:</p>
<pre>
mvn clean package -Prelease</pre>
<p>Happy coding =))</p>
<!-- content here -->
<h3>Tools used</h3>
The following tools are used to develop Strolch and Strolch-based projects:
<ul class="list-unstyled">
<li><a href="https://www.jetbrains.com/idea/download/#section=linux"><img style="height: 50px"
class="img-thumbnail"
src="https://upload.wikimedia.org/wikipedia/commons/d/d5/IntelliJ_IDEA_Logo.svg"
alt="IntelliJ IDEA" /></a></li>
<li><a href="https://maven.apache.org/"><img width="250"
style="height: 50px; margin-top: 10px"
class="img-thumbnail"
src="http://maven.apache.org/images/maventxt_logo_200.gif"
alt="Apache Maven 3.0" /></a></li>
<li><a href="http://git-scm.com/"><img style="height: 50px; margin-top: 10px"
class="img-thumbnail"
src="http://git-scm.com/images/logo@2x.png"
alt="git scm" /></a></li>
</ul>
</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 xsd 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

@ -1,159 +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: Architecture</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="plc.html">PLC</a></li>
<li><a href="tutorial.html">Tutorial</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: Architecture</h1>
<p class="lead page-description">This page discusses the architecture of a Strolch Agent</p>
</div>
<div class="content">
<h2>Birds View</h2>
<p>A Strolch agent's architecture can be seen as a simple three-tier architecture. The presentation layer is
mostly a web frontend, where the communication with the agent is done via REST API calls.</p>
<p>The agent itself implements the business logic using Services, Commands, Queries etc.</p>
<p>The agent can communicate with other 3rd systems using any API, where it is preferred to use JSON over
REST.</p>
<p>The agent can use a standard RDBMS as a storage system, where currently DAOs have been implemented only for
PostgreSQL. Should it be required, then any JDBC cabable RDBMS can be used, as no PostgreSQL specific SQL
commands are used.</p>
<p>The following diagram helps visualize this:</p>
<img src="images/Strolch-Bird-View.svg" class="img-responsive center-block" alt="Strolch Agent Bird View">
<br />
<h2>Squirrel View</h2>
<p>The following diagram shows a more detailed view of the architecture of a Strolch Agent.</p>
<img src="images/Strolch-Squirrel-View.svg"
class="img-responsive center-block"
alt="Strolch Agent Squirrel View">
<br />
<p>A Strolch agent consists of the following main parts:</p>
<ul>
<li>REST Endpoints &rarr; expose an API to access the Strolch agent outside of the Java VM</li>
<li>Services and Commands &rarr; implements business logic</li>
<li>Searches &rarr; implements specific queries against the Strolch model</li>
<li>Components &rarr; Implements additional logic, which is best implement as a component. E.g. active
components which have threads, etc.
</li>
<li>Realms &rarr; implements multi-tenant capabilities</li>
</ul>
<p>In addition to the main parts, Strolch contains inherit capabilities, which gives Strolch unique features
when compared to other Java Frameworks:</p>
<ul>
<li>Policies &rarr; Policies allow injecting different algorithms. All root elements can store Policy
definitions, so that a service can delegate to a Policy and thus behave differently, depending on the
element being accessed.
</li>
<li>Transactions &rarr; Transactions handle locking/unlocking of objects, updating the model and are the
central API for the developer.
</li>
<li>Privileges &rarr; Strolch is user agnostic and any action, i.e. Service, Query, etc. is authorized
against the authenticated user.
</li>
<li>Observers &rarr; modifications to the model are propagated to listeners using the observer pattern.</li>
<li>Audits &rarr; Every access (read, modify) of the model are audited</li>
<li>Versioning &rarr; modifications to objects are versioned and thus can be rolled back at a later time.
</li>
</ul>
<!-- 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 xsd 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

@ -1,209 +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: 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="plc.html">PLC</a></li>
<li><a href="tutorial.html">Tutorial</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 xsd 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

@ -1,123 +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: Do and Don't</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="plc.html">PLC</a></li>
<li><a href="tutorial.html">Tutorial</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: Do and Don't</h1>
<p class="lead page-description">This page discusses things you should and shouldn't do when using Strolch.</p>
</div>
<div class="content">
<p>Dos and Don'ts</p>
<ul>
<li>1 <code>Service</code> per use-case, should mostly delegate to <code>Commands</code>.</li>
<li><code>Commands</code> implement use-cases or parts of it, and are thus reusable.</li>
<li>Subclass <code>ResourceSearch</code>, <code>OrderSearch</code> and <code>ActivitySearch</code> when
implementing use-case specific search - this allows privilege checking.
</li>
<li>One Transaction at a time - no TX inside of another TX.</li>
<li>Commands are added to TXs and performed on close: <code>tx.addCommand(Command)</code> and then <code>tx.commitOnClose()</code>
</li>
<li>Use <code>tx.flush() if you need to perform first some work and then as late as possible call <code>tx.commitOnClose()</code></code>
</li>
<li>Only access <code>ElementMap</code>s if really no other way, mostly use <code>tx.get*By()</code>, <code>tx.findBy()</code>
and queries - if a specific get is missing, then add the method to <code>StrolchTransaction</code> and
send a pull request!
</li>
<li>Use <code>tx.stream*()</code> methods to iterate over all elements, if you don't want to use a search.
</li>
<li>Don't write logic in REST API beans. Delegate to other services, making your code reusable!</li>
<li>Transform to JSON using the <code>StrolchElementToJsonVisitor</code>.</li>
<li>References between objects is done by adding a <code>ParameterBag</code> with the id
<code>relations</code> to the object and then <code>StringParameters</code> with the value being the ID,
the UOM set to the type of element being referenced and the Interpretation set to the class type being
referenced.
</li>
</ul>
<!-- 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 xsd 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

@ -1,391 +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: Model</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="plc.html">PLC</a></li>
<li><a href="tutorial.html">Tutorial</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: Model</h1>
<p class="lead page-description">This page discusses Strolch's model</p>
</div>
<div class="content">
<p>Before we dive into the entire model, let's show an example and how it would be modelled in Strolch and use
in Strolch:</p>
<img class="image" src="images/strolch-model-example.png" alt="Strolch model example">
<p>A possible model would look as follows:</p>
<pre>
&lt;?xml version="1.0" encoding="UTF-8" ?&gt;
&lt;StrolchModel xmlns="https://strolch.li/xsd/StrolchModel-1.6.xsd"&gt;
&lt;Resource Id="Product" Name="Product Template" Type="Template"&gt;
&lt;ParameterBag Id="parameters" Name="Parameters" Type="Parameters"&gt;
&lt;Parameter Id="description" Name="Description" Type="String" Value=""/&gt;
&lt;Parameter Id="color" Name="Color" Type="String" Value=""/&gt;
&lt;Parameter Id="form" Name="Form" Type="String" Value=""/&gt;
&lt;/ParameterBag&gt;
&lt;ParameterBag Id="relations" Name="Relations" Type="Relations"&gt;
&lt;Parameter Id="articles" Name="Articles" Type="StringList" Interpretation="Resource-Ref" Uom="Article" Value=""/&gt;
&lt;/ParameterBag&gt;
&lt;/Resource&gt;
&lt;Resource Id="Article" Name="Article Template" Type="Template"&gt;
&lt;ParameterBag Id="parameters" Name="Parameters" Type="Parameters"&gt;
&lt;Parameter Id="description" Name="Description" Type="String" Value=""/&gt;
&lt;Parameter Id="barcode" Name="Barcode" Type="String" Value=""/&gt;
&lt;/ParameterBag&gt;
&lt;ParameterBag Id="relations" Name="Relations" Type="Relations"&gt;
&lt;Parameter Id="product" Name="Product" Type="String" Interpretation="Resource-Ref" Uom="Product" Value=""/&gt;
&lt;/ParameterBag&gt;
&lt;/Resource&gt;
&lt;Resource Id="Customer" Name="Customer Template" Type="Template"&gt;
&lt;ParameterBag Id="address" Name="Address" Type="Address"&gt;
&lt;Parameter Id="street" Name="Street" Type="String" Value=""/&gt;
&lt;Parameter Id="zip" Name="Zip" Type="String" Value=""/&gt;
&lt;Parameter Id="city" Name="City" Type="String" Value=""/&gt;
&lt;Parameter Id="country" Name="Country" Type="String" Value=""/&gt;
&lt;/ParameterBag&gt;
&lt;/Resource&gt;
&lt;Order Id="Order" Name="Order" Type="Template"&gt;
&lt;ParameterBag Id="quantities" Name="Quantities per Article Id" Type="Quantities"&gt;
&lt;Parameter Id="quantity" Name="Quantity" Type="Float" Value="0"/&gt;
&lt;/ParameterBag&gt;
&lt;ParameterBag Id="relations" Name="Relations" Type="Relations"&gt;
&lt;Parameter Id="articles" Name="Articles" Type="StringList" Interpretation="Resource-Ref" Uom="Article" Value=""/&gt;
&lt;Parameter Id="customer" Name="Customer" Type="String" Interpretation="Resource-Ref" Uom="Customer" Value=""/&gt;
&lt;/ParameterBag&gt;
&lt;/Order&gt;
&lt;/StrolchModel&gt;</pre>
<p>Let's go through this model:</p>
<ul>
<li><p>In the above model we see that the <code>id</code> and <code>name</code> fields are always on the
element, and thus aren't added as parameters. Further most elements have a <code>parameters</code>
ParameterBag, with one or more parameters, modelling the fields.</p></li>
<li><p>Note that in this example the <code>Type</code> of all the elements is <code>Template</code>. Strolch
has API support to create a clone of these elements, so that they have a unique ID, and the proper
type for persistence.</p>
</li>
<li><p>The <code>Product</code> element has three parameters: <code>description</code>, <code>color</code>
and <code>form</code>. In this case they are all of type String. Further the <code>relations</code>
ParameterBag defines the relationships, i.e. the product knows its articles. Note how the relation is
first defined in a <code>relations</code> ParameterBag and that the Parameter has <code>Interpretation="Resource-Ref"
Uom="Product"</code>
attributes. Strolch has API support for this, making it trivial to retrieve a dependency.</p></li>
<li><p>The <code>Article</code> element has two parameters <code>description</code> and <code>barcode</code>.
Further it has a reference to its Product.</p></li>
<li>The <code>Order</code> element doesn't model the <code>date</code> and <code>state</code> fields as
parameters, as these are inherently part of an Order element. The Order does define two references to
<code>customer</code> and <code>articles</code>. A special case is the <code>quantities</code>
ParameterBag. This bag of parameters is used to store the per article quantity for this order. With
ParameterBags, you can eliminate the use of simple aggregate classes, as is commonly used in
object-oriented programming.
</li>
<li>The <code>Customer</code> element models a <code>address</code> ParameterBag to store the address of a
customer. Using a separate bag allows for further more direct fields to stored on the default <code>parameters</code>
bag.
</li>
</ul>
<p>Now that we have a basic understanding of te model, it is of far more interest in how to create and interact
with these elements at runtime. The following listing will perform simple operations:</p>
<pre>
try (StrolchTransaction tx = runtimeMock.openUserTx(certificate, false)) {
/*
* create a new product
*/
Resource dafalgan = tx.getResourceTemplate("Product", true);
dafalgan.setName("Dafalgan 100mg");
dafalgan.getParameter("description", true).setValue("Dafalgan is for pain.");
dafalgan.getParameter("color", true).setValue("Yellow");
dafalgan.getParameter("form", true).setValue("flat");
StringListParameter articlesP = dafalgan.getRelationsParam("articles", true);
/*
* create articles
*/
Resource dafalgan1 = tx.getResourceTemplate("Article", true);
dafalgan1.setName("Dafalgan 100mg 10 pce");
dafalgan1.getParameter("description", true).setValue("This is pack with 10 pieces.");
dafalgan1.getParameter("barcode", true).setValue("654654");
Resource dafalgan2 = tx.getResourceTemplate("Article", true);
dafalgan2.setName("Dafalgan 100mg 20 pce");
dafalgan2.getParameter("description", true).setValue("This is pack with 20 pieces.");
dafalgan2.getParameter("barcode", true).setValue("654655");
/*
* add reference to product
*/
dafalgan1.getRelationParam("product").setValue(dafalgan.getId());
articlesP.addValue(dafalgan1.getId());
dafalgan2.getRelationParam("product").setValue(dafalgan.getId());
articlesP.addValue(dafalgan2.getId());
/*
* create a new customer
*/
Resource customer1 = tx.getResourceTemplate("Customer", true);
customer1.setName("John Doe");
// set address
ParameterBag addressBag = customer1.getParameterBag("address", true);
addressBag.getParameter("street", true).setValue("Main Str. 1");
addressBag.getParameter("zip", true).setValue("1234");
addressBag.getParameter("city", true).setValue("Hometown");
addressBag.getParameter("country", true).setValue("Switzerland");
/*
* create a new order
*/
Order order = tx.getOrderTemplate("Order", true);
order.setName("Order for " + customer1.getName());
order.setDate(LocalDate.of(2021, 2, 1));
order.setState(State.PLANNED);
// store reference to customer
order.getRelationParam("customer", true).setValue(customer1.getId());
StringListParameter orderArticlesP = order.getRelationsParam("articles", true);
ParameterBag quantitiesBag = order.getParameterBag("quantities", true);
FloatParameter quantityT = quantitiesBag.removeParameter("quantity");
// order quantity of 20 for Dafalgan 1
FloatParameter q1P = quantityT.getClone();
q1P.setId(dafalgan1.getId());
q1P.setValue(20);
quantitiesBag.addParameter(q1P);
orderArticlesP.addValue(dafalgan1.getId());
// set order quantity of 10 for Dafalgan 2
FloatParameter q2P = quantityT.getClone();
orderArticlesP.addValue(dafalgan2.getId());
q2P.setId(dafalgan2.getId());
q2P.setValue(20);
quantitiesBag.addParameter(q2P);
// keep IDs for later use
dafalganId = dafalgan.getId();
dafalgan1Id = dafalgan1.getId();
dafalgan2Id = dafalgan2.getId();
customerId = customer1.getId();
orderId = order.getId();
/*
* persist
*/
tx.add(dafalgan);
tx.add(dafalgan1);
tx.add(dafalgan2);
tx.add(customer1);
tx.add(order);
// commit
tx.commitOnClose();
}
try (StrolchTransaction tx = runtimeMock.openUserTx(certificate, true)) {
// get order
Order order = tx.getOrderBy("Order", orderId, true);
assertNotNull(orderId);
assertEquals("Order for John Doe", order.getName());
// get customer
Resource customer = tx.getResourceByRelation(order, "customer", true);
assertNotNull(customer);
assertEquals("John Doe", customer.getName());
// get articles
List&lt;Resource&gt; articles = tx.getResourcesByRelation(order, "articles", true);
assertEquals(2, articles.size());
// get products
List&lt;Resource&gt; products = articles.stream().map(a -&gt; tx.getResourceByRelation(a, "product", true))
.distinct().collect(Collectors.toList());
assertEquals(1, products.size());
// search for all orders in state PLANNED and with customer
List&lt;Order&gt; orders = new OrderSearch().types("Order").stateIsIn(State.PLANNED)
.where(ExpressionsSupport.relationParam("customer").isEqualTo(customerId)).search(tx).toList();
assertEquals(1, orders.size());
}</pre>
<p><b>Note:</b> Checkout
<a href="https://github.com/4treesCH/strolch/blob/develop/li.strolch.service/src/test/resources/transienttest/data/example-model.xml">example-model.xml</a>
and
<a href="https://github.com/4treesCH/strolch/blob/develop/li.strolch.service/src/test/java/li/strolch/service/SimpleModelTest.java">SimpleModelTest.java</a>
for these examples. </p>
<p>There is a XML Schema which defines the model in XML:
<a href="xsd/StrolchModel-1.6.xsd">StrolchModel-1.6.xsd</a>
</p>
Here is an example of all the possible elements in Strolch:
<pre>
&lt;StrolchModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://strolch.li/xsd/StrolchModel-1.6.xsd"
xsi:schemaLocation="https://strolch.li/xsd/StrolchModel-1.6.xsd StrolchModel-1.6.xsd"&gt;
&lt;IncludeFile file="Include1.xml"/&gt;
&lt;Order Id="@test1" Name="Test Order" Type="Order"&gt;
&lt;Version Version="0" CreatedBy="test" CreatedAt="2012-11-30T18:12:05.628+01:00" Deleted="false"/&gt;
&lt;ParameterBag Id="@bag01" Name="Test Bag" Type="TestBag"&gt;
&lt;Parameter Id="@param1" Name="Boolean Param" Type="Boolean" Value="true"/&gt;
&lt;/ParameterBag&gt;
&lt;ParameterBag Id="@bag01" Name="Test Bag" Type="TestBag"&gt;
&lt;Parameter Id="@param1" Name="Boolean Param" Type="Boolean" Value="true"/&gt;
&lt;/ParameterBag&gt;
&lt;Policies&gt;
&lt;Policy Type="PlanningPolicy" Value="key:SimplePlanning"/&gt;
&lt;Policy Type="ConfirmationPolicy" Value="key:NoConfirmation"/&gt;
&lt;/Policies&gt;
&lt;/Order&gt;
&lt;Resource Id="MyTestResource" Name="Test Name" Type="TestType"&gt;
&lt;Version Version="0" CreatedBy="test" CreatedAt="2012-11-30T18:12:05.628+01:00" Deleted="false"/&gt;
&lt;ParameterBag Id="@bag01" Name="Test Bag 01" Type="TestBag"&gt;
&lt;Parameter Id="@param1" Name="Boolean Param" Type="Boolean" Value="true"/&gt;
&lt;/ParameterBag&gt;
&lt;ParameterBag Id="@bag02" Name="Test Bag 02" Type="TestBag"&gt;
&lt;Parameter Id="@param1" Name="Boolean Param" Type="Boolean" Value="true"/&gt;
&lt;/ParameterBag&gt;
&lt;TimedState Id="@booleanState" Name="Boolean State" Type="Boolean"&gt;
&lt;Value Time="1970-01-01T00:02:00.000+01:00" Value="false"/&gt;
&lt;/TimedState&gt;
&lt;Policies&gt;
&lt;Policy Type="PlanningPolicy" Value="key:SimplePlanning"/&gt;
&lt;Policy Type="ConfirmationPolicy" Value="key:NoConfirmation"/&gt;
&lt;/Policies&gt;
&lt;/Resource&gt;
&lt;Activity Id="activity_1" Name="Activity" Type="parentType" TimeOrdering="Series"&gt;
&lt;Version Version="0" CreatedBy="test" CreatedAt="2012-11-30T18:12:05.628+01:00" Deleted="false"/&gt;
&lt;ParameterBag Id="@bag01" Name="Test Bag" Type="TestBag"&gt;
&lt;Parameter Id="@param1" Name="Boolean Param" Type="Boolean" Value="true"/&gt;
&lt;/ParameterBag&gt;
&lt;Policies&gt;
&lt;Policy Type="PlanningPolicy" Value="key:SimplePlanning"/&gt;
&lt;Policy Type="ConfirmationPolicy" Value="key:NoConfirmation"/&gt;
&lt;/Policies&gt;
&lt;Action Id="action_1" Name="Action 1" ResourceId="dummyId" ResourceType="dummyType" State="Created" Type="Use"&gt;
&lt;ParameterBag Id="@bag01" Name="Test Bag" Type="TestBag"&gt;
&lt;Parameter Id="@param1" Name="Boolean Param" Type="Boolean" Value="true"/&gt;
&lt;/ParameterBag&gt;
&lt;Policies&gt;
&lt;Policy Type="PlanningPolicy" Value="key:SimplePlanning"/&gt;
&lt;Policy Type="ConfirmationPolicy" Value="key:NoConfirmation"/&gt;
&lt;/Policies&gt;
&lt;ValueChange StateId="dummyId" Time="2012-11-30T18:12:05.628+01:00" Value="5" Type="Integer"/&gt;
&lt;ValueChange StateId="dummyId" Time="2012-11-30T18:12:06.628+01:00" Value="6" Type="Integer"/&gt;
&lt;/Action&gt;
&lt;Activity Id="child_activity" Name="Child Activity" Type="childType" TimeOrdering="Series"&gt;
&lt;ParameterBag Id="@bag01" Name="Test Bag" Type="TestBag"&gt;
&lt;Parameter Id="@param1" Name="Boolean Param" Type="Boolean" Value="true"/&gt;
&lt;/ParameterBag&gt;
&lt;Policies&gt;
&lt;Policy Type="PlanningPolicy" Value="key:SimplePlanning"/&gt;
&lt;Policy Type="ConfirmationPolicy" Value="key:NoConfirmation"/&gt;
&lt;/Policies&gt;
&lt;Action Id="action_2" Name="Action 2" ResourceId="dummyId" ResourceType="dummyType" State="Planned"
Type="Use"&gt;
&lt;ValueChange StateId="dummyId" Time="2012-11-30T18:12:05.628+01:00" Value="5" Type="Integer"/&gt;
&lt;ValueChange StateId="dummyId" Time="2012-11-30T18:12:06.628+01:00" Value="6" Type="Integer"/&gt;
&lt;/Action&gt;
&lt;Action Id="action_3" Name="Action 3" ResourceId="dummyId" ResourceType="dummyType" State="Created"
Type="Use"/&gt;
&lt;/Activity&gt;
&lt;/Activity&gt;
&lt;/StrolchModel&gt;</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 xsd 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

@ -1,151 +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: Observers</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="plc.html">PLC</a></li>
<li><a href="tutorial.html">Tutorial</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: Observers</h1>
<p class="lead page-description">This page discusses the Strolch Observers</p>
</div>
<div class="content">
<p>All changes done in a Strolch transaction are recorded and then propagated to any registered observers.</p>
<p>The observer feature is opt-in and is configured for each realm. In the <code>StrolchConfiguration.xml</code>
file enable observers by adding the <code>enableObserverUpdates</code> propery per realm:</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;Properties&gt;
&lt;realms&gt;defaultRealm, otherRealm&lt;/realms&gt;
&lt;enableObserverUpdates&gt;true&lt;/enableObserverUpdates&gt;
&lt;dataStoreMode&gt;TRANSIENT&lt;/dataStoreMode&gt;
&lt;dataStoreFile&gt;StrolchModel.xml&lt;/dataStoreFile&gt;
&lt;enableObserverUpdates.otherRealm&gt;true&lt;/enableObserverUpdates.otherRealm&gt;
&lt;dataStoreMode.otherRealm&gt;TRANSIENT&lt;/dataStoreMode.otherRealm&gt;
&lt;dataStoreFile.otherRealm&gt;StrolchModel.xml&lt;/dataStoreFile.otherRealm&gt;
&lt;/Properties&gt;
&lt;/Component&gt;
&lt;/env&gt;
...
&lt;/StrolchConfiguration&gt;</pre>
<br />
<p>Registering for updates is done by registering an <code>Observer</code> on the <code>ObserverHandler</code>
of the realm itself:</p>
<pre>
ObserverHandler observerHandler = container.getRealm(StrolchConstants.DEFAULT_REALM).getObserverHandler();
observerHandler.registerObserver(Tags.RESOURCE, new Observer() {
@Override
public void update(String key, List&lt;StrolchRootElement&gt; elements) {
logger.info(elements.size() + " resources were updated!");
}
@Override
public void remove(String key, List&lt;StrolchRootElement&gt; elements) {
logger.info(elements.size() + " resources were removed!");
}
@Override
public void add(String key, List&lt;StrolchRootElement&gt; elements) {
logger.info(elements.size() + " resources were added!");
}
});</pre>
<br />
<p>Observer updates can be suppressed on the transaction by calling <code>tx.setSuppressUpdates()</code></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 xsd 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

@ -1,179 +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: Policies</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="plc.html">PLC</a></li>
<li><a href="tutorial.html">Tutorial</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: Policies</h1>
<p class="lead page-description">This page discusses the Strolch policies</p>
</div>
<div class="content">
<p>Policies are an integral part when writing business logic in Strolch. In many cases it would suffice to write
all such logic in <code>Services</code> and <code>Commands</code>, but as soon as behaviour can change,
depending on the element being accessed, then this would quickly lead to many if/else blocks.</p>
<p>Since writing large if/else blocks is not maintanable in the long run, Strolch offers a different approach.
All Strolch elements can store Policy definitions. This is a simple key/value store where the key defines the
type of policy, and the value references the policy to use.</p>
<p>Currently there are two ways to reference a policy in Strolch, either via a key which defines a further
lookup in the <code>PolicyHandler</code>, or directly as the name of the class to instantiate.</p>
<p>Using policies in Strolch gives the additional possibility of easily changing the behaviour at runtime, as a
Service and/or Command would delegate the behaviour to the currently configured policy on the releveant
element.</p>
<p>Policies are implemented by defining an abstract class and extends <code>StrolchPolicy</code>. This abstract
class then defines the API of the actual policy. A concrete class then extends this abstract class and
implements the concrete methods.</p>
<p>Policies are registered on Resources, Orders, Activities and Actions. The following shows defining two
policies on a Resource, a PlanningPolicy, an ExecutionPolicy in XML:</p>
<pre>
&lt;Resource ...&gt;
...
&lt;Policies&gt;
&lt;Policy Type="PlanningPolicy" Value="key:SimplePlanning" /&gt;
&lt;Policy Type="ExecutionPolicy" Value="java:li.strolch.policytest.TestSimulatedExecutionPolicy" /&gt;
&lt;/Policies&gt;
&lt;/Resource&gt;</pre>
<p><b>Note</b> how the PlanningPolicy has a value of <code>key:SimplePlanning</code> and the ExecutionPolicy
defines a reference to an actual class.</p>
<br />
<p>To use the PolicyHandler, it must be configured in the StrolchConfiguration.xml as follows:</p>
<pre>
&lt;Component>
&lt;name>PolicyHandler&lt;/name&gt;
&lt;api&gt;li.strolch.policy.PolicyHandler&lt;/api&gt;
&lt;impl&gt;li.strolch.policy.DefaultPolicyHandler&lt;/impl&gt;
&lt;Properties&gt;
&lt;readPolicyFile&gt;true&lt;/readPolicyFile&gt;
&lt;policyConfigFile&gt;StrolchPolicies.xml&lt;/policyConfigFile&gt;
&lt;/Properties&gt;
&lt;/Component&gt;</pre>
<br />
<p>And this policy handler implementation requires a file where the lookups for the policies is defined,
e.g.:</p>
<pre>
&lt;StrolchPolicies&gt;
&lt;PolicyType Type="PlanningPolicy" Api="li.strolch.policytest.TestPlanningPolicy"&gt;
&lt;Policy Key="SimplePlanning" Class="li.strolch.policytest.TestSimplePlanningPolicy" /&gt;
&lt;/PolicyType&gt;
&lt;PolicyType Type="ConfirmationPolicy" Api="li.strolch.policytest.TestConfirmationPolicy"&gt;
&lt;Policy Key="NoConfirmation" Class="li.strolch.policytest.TestNoConfirmationPolicy" /&gt;
&lt;/PolicyType&gt;
&lt;/StrolchPolicies&gt;</pre>
<br />
<p>Now at runtime we can access the policies:</p>
<pre>
PolicyHandler policyHandler = getComponent(PolicyHandler.class);
try (StrolchTransaction tx = openTx()) {
Resource res = tx.getResourceBy("TestType", "MyTestResource");
PolicyDefs policyDefs = res.getPolicyDefs();
PolicyDef planningPolicyDef = policyDefs.getPolicyDef("PlanningPolicy");
PlanningPolicy planningPolicy = policyHandler.getPolicy(planningPolicyDef, tx);
planningPolicy.plan(...);
PolicyDef executionPolicyDef = res.getPolicyDefs().getPolicyDef("ExecutionPolicy");
ExecutionPolicy executionPolicy = policyHandler.getPolicy(executionPolicyDef, tx);
executionPolicy.execute(...);
}</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 xsd 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

@ -1,211 +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: Privileges</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="plc.html">PLC</a></li>
<li><a href="tutorial.html">Tutorial</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: Privileges</h1>
<p class="lead page-description">This page discusses Privilege management in Strolch.</p>
</div>
<div class="content">
<!-- content here -->
<p>No framework is complete without user management and privilege validation. The basic form would be Users and
Roles, and then validating that an authenticated user has a given role. In Strolch we go a step further: A
User has roles assigned, and each role has a set of Privileges. The privileges can overlap, a validation is
performed to make sure that the one role doesn't deny and another role allows a specific action.</p>
<p>As explained in the <a href="documentation-runtime.html#privilegeConfig">Privilege Configuration</a> section,
users are defined in the <code>PrivilegeUsers.xml</code> file, and roles are defined in the <code>PrivilegeRoles.xml</code>
file.</p>
<p>Let's assume the following user and role definition:</p>
<pre>
&lt;Users&gt;
&lt;User userId="1" username="jill" password="$PBKDF2WithHmacSHA512,10000,256$61646d696e$cb69962946617da006a2f95776d78b49e5ec7941d2bdb2d25cdb05f957f64344"&gt;
&lt;Firstname&gt;Jill&lt;/Firstname&gt;
&lt;Lastname&gt;Someone&lt;/Lastname&gt;
&lt;State&gt;ENABLED&lt;/State&gt;
&lt;Locale&gt;en-GB&lt;/Locale&gt;
&lt;Roles&gt;
&lt;Role&gt;AppUser&lt;/Role&gt;
&lt;/Roles&gt;
&lt;Properties&gt;
&lt;Property name="realm" value="execution" /&gt;
&lt;/Properties&gt;
&lt;/User&gt;
&lt;/Users&gt;
&lt;Roles&gt;
&lt;Role name="AppUser"&gt;
&lt;Privilege name="li.strolch.service.api.Service" policy="DefaultPrivilege"&gt;
&lt;AllAllowed&gt;true&lt;/AllAllowed&gt;
&lt;/Privilege&gt;
&lt;Privilege name="li.strolch.model.query.StrolchQuery" policy="DefaultPrivilege"&gt;
&lt;AllAllowed&gt;true&lt;/AllAllowed&gt;
&lt;/Privilege&gt;
&lt;Privilege name="li.strolch.search.StrolchSearch" policy="DefaultPrivilege"&gt;
&lt;AllAllowed&gt;true&lt;/AllAllowed&gt;
&lt;/Privilege&gt;
&lt;Role&gt;
&lt;Roles&gt;
</pre>
<p>This configuration contains one user and one role. The user <code>jill</code> has the role
<code>AppUser</code> and the role <code>AppUser</code> has three privileges assigned.</p>
<p>Note how the user's password is configured similar to a unix password definition: Using the dollar sign
<code>&amp;</code> first the hashing algorithm is configured (algorithm, iterations, key length), then the
salt, followed by the password hash.</p>
<p><code>Note:</code> The password can also still be saved using two separate fields: a salt and password field.
This configuration will be immediately changed to the unix form, so won't be described
further here.</p>
<p>Further a user always has a firstname and last name. Optionally a locale can be set, otherwise the system
locale is used. The user's state must be defined as one of <code>NEW</code>, <code>ENABLED</code>, <code>DISABLED</code>,
<code>EXPIRED</code> or <code>SYSTEM</code>. A user can only authenticate/login with the state
<code>ENABLED</code>. A user can have any number of properties, which can then be used at runtime. A user
can also reference any number of roles, the assigned privilege can overlap, a global configuration mode
defines how duplicate privileges are handled.</p>
<p>Roles have a name and any number of <code>Privilege</code> definitions. A Privilege has a name, which in many
cases is the name of Java class/interface on which an action is being invoked. The <code>policy</code> value
defines which policy to use when evaluating the privilege access. The privilege definition is defined in the
<code>PrivilegeConfig.xml</code> and is the name of a class to call for privilege validation.</p>
<p>Further the privilege definitions can have a <code>AllAllowed</code> boolean flag, or any number of <code>Allow</code>
or <code>Deny</code> values. How these values are interpreted is defined in the policy implementation. A
policy takes three input parameters: </p>
<ul>
<li><code>PrivilegeContext</code> &rarr; supplied by privilege and gives access to the
<code>Certificate</code>, thus identifying the user for which privilege access is to be validated.
</li>
<li><code>IPrivilege</code> &rarr; Contains the privilege values: <code>AllAllowed</code>,
<code>Allow</code> and <code>Deny</code></li>
<li><code>Restrictable</code> &rarr; An interface from which the privilege name is retrieved, and the
associated value. The value is an object, and is cast to the relevant input in
the concrete privilege policy.
</li>
</ul>
<p>The following privilege policies are already implemented:</p>
<ul>
<li>DefaultPrivilege &rarr; simple policy where the passed <code>Restrictable</code> is expected to return a
String value, which is compared with allow and deny values.
</li>
<li style="margin-top: 1.0em"><i>Internal:</i> RoleAccessPrivilege &rarr; policy used for the internal
privileges <code>PrivilegeGetRole</code>, <code>PrivilegeAddRole</code>,
<code>PrivilegeModifyRole</code> or <code>PrivilegeModifyRole</code></li>
<li><i>Internal:</i> UserAccessPrivilege &rarr; policy used for the internal privileges <code>PrivilegeGetUser</code>,
<code>PrivilegeAddUser</code>, <code>PrivilegeRemoveUser</code>, <code>PrivilegeModifyUser</code>,
<code>PrivilegeAddRoleToUser</code>, <code>PrivilegeRemoveRoleFromUser</code>, <code>PrivilegeSetUserState</code>,
<code>PrivilegeSetUserLocale</code> or <code>PrivilegeSetUserPassword</code></li>
<li><i>Internal:</i> UserAccessWithSameOrganisationPrivilege &rarr; Same as the
<code>UserAccessPrivilege</code> but expects the authenticated user to have a property <code>organisation</code>
and validates that the user being modified is in the same organisation.
</li>
<li><i>Internal:</i> UsernameFromCertificatePrivilege &rarr; This policy expects a <code>Restrictable</code>
to return the certificate of another authenticated user and is used when modifying an
authenticated user, i.e. killing a session, or modifying its current state, e.g. locale
etc.
</li>
<li><i>Internal:</i> UsernameFromCertificateWithSameOrganisationPrivilege &rarr; Same as <code>UsernameFromCertificatePrivilege</code>
but expects the authenticated user to have a property <code>organisation</code> and
validates that the user being modified is in the same organisation.
</li>
</ul>
<p><b>Note:</b> As a rule, the sequence is <code>AllAllowed</code> &rarr; <code>Allow</code> &rarr;
<code>Deny</code> &rarr; <code>default deny</code></p>
<p></p>
</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 xsd 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

@ -1,202 +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: 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="plc.html">PLC</a></li>
<li><a href="tutorial.html">Tutorial</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 class="lead"><b>The Query API is deprecated and the search API should be used instead.</b>
</p>
<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 xsd 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

@ -1,205 +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: 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="plc.html">PLC</a></li>
<li><a href="tutorial.html">Tutorial</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-tenant 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>
</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, 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: --&gt;
&lt;!--depends&gt;PersistenceHandler&lt;/depends--&gt;
&lt;Properties&gt;
&lt;dataStoreMode&gt;EMPTY|TRANSIENT|CACHED&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&lt;/realms&gt;
&lt;dataStoreMode&gt;TRANSIENT&lt;/dataStoreMode&gt;
&lt;dataStoreFile&gt;DefaultRealm.xml&lt;/dataStoreFile&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.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;db.pool.keepaliveTime.cachedRealm&gt;600000&lt;/db.pool.keepaliveTime.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 xsd 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

@ -1,367 +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: Reports</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="plc.html">PLC</a></li>
<li><a href="tutorial.html">Tutorial</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: Reports</h1>
<p class="lead page-description">This page discusses how to create reports in Strolch</p>
</div>
<div class="content">
<p>Since Strolch has a generic model, it was rather straight forward to create a simple API for writing reports.
In Strolch a report is defined by using its own model, i.e. a Report is a <code>Resource</code> of type
<code>Report</code>.</p>
<p>A report consists of the following parts:</p>
<ul>
<li>policy definition, thus allowing extensions</li>
<li>basic configuration like base object type, order direction, etc.</li>
<li>column definitions</li>
<li>joins</li>
<li>ordering definition</li>
<li>filters</li>
</ul>
<p>An example of a report is as follows:</p>
<pre>
&lt;Resource Id="stockReport" Name="Stock Report" Type="Report"&gt;
&lt;ParameterBag Id="parameters" Name="parameters" Type="Parameters"&gt;
&lt;Parameter Id="objectType" Index="20" Hidden="false" Name="Object Type" Type="String" Interpretation="Resource-Ref" Uom="Player" Value="Player"/&gt;
&lt;Parameter Id="descending" Name="Descending order" Type="Boolean" Value="true"/&gt;
&lt;/ParameterBag&gt;
&lt;ParameterBag Id="ordering" Name="Ordering" Type="Ordering"&gt;
&lt;Parameter Id="name" Name="Name" Type="String" Interpretation="Resource-Ref" Uom="Player" Value="$name"/&gt;
&lt;/ParameterBag&gt;
&lt;ParameterBag Id="noTeamFilter" Name="Filter" Type="Filter"&gt;
&lt;Parameter Id="policy" Name="Filter Policy" Type="String" Interpretation="ReportFilterPolicy" Uom="key:Equals" Value="!"/&gt;
&lt;Parameter Id="fieldRef" Name="Field reference" Type="String" Interpretation="Resource-Ref" Uom="Slot" Value="Bags/relations/team"/&gt;
&lt;/ParameterBag&gt;
&lt;ParameterBag Id="columns" Name="Display Columns" Type="Display"&gt;
&lt;Parameter Id="name" Name="Player" Type="String" Interpretation="Resource-Ref" Uom="Player" Value="$name"/&gt;
&lt;Parameter Id="birthDate" Name="Birth date" Type="String" Interpretation="Resource-Ref" Uom="Player" Value="Bags/parameters/birthDate"/&gt;
&lt;Parameter Id="team" Name="Team" Type="String" Interpretation="Resource-Ref" Uom="Team" Value="$name"/&gt;
&lt;/ParameterBag&gt;
&lt;ParameterBag Id="joins" Name="Joins" Type="Joins"&gt;
&lt;Parameter Id="Team" Index="10" Hidden="false" Name="Team" Type="String" Interpretation="Resource-Ref" Uom="Team" Value="Player"/&gt;
&lt;/ParameterBag&gt;
&lt;Policies&gt;
&lt;Policy Type="ReportPolicy" Value="java:li.strolch.report.policy.GenericReport"/&gt;
&lt;/Policies&gt;
&lt;/Resource&gt;</pre>
<p>This report</p>
<ul>
<li>shows all Resources of type player (parameter <code>objectType</code>) &rarr; marks the object type to
be show in the filter criteria (default), and that its sorting index is at 20.
</li>
<li>orders the report by player's name (parameter bag <code>ordering</code>)</li>
<li>filters out all players with no team assigned (parameter bag <code>noTeamFilter</code>)</li>
<li>defines three columns: Player, Birth date, Team (paramger bag <code>columns</code>)</li>
<li>joins in the resource of type <code>Team</code></li>
<li>Uses the <code>GenericReport</code> class to generate the report</li>
</ul>
<h2>GenericReport</h2>
The default generic report implemented in Strolch has the following features and options:
<h3>Parameters</h3>
<p>The parameters bag can contain the following parameters:</p>
<ul>
<li><code>objectType</code> &rarr; the base type of object to get the input for the report. This means that
the <code>Interpretation</code> is set to one of:
<ul>
<li>Resource-Ref</li>
<li>Order-Ref</li>
<li>Activity-Ref</li>
</ul>
and that the <code>UOM</code> and <code>value</code> of the parameter is set to
the type of element with which to retrieve the elements from the strolch model.
<br /> <b>Note:</b> that the attributes <code>Hidden</code> and <code>Index</code> define the visibility
and sorting index as filter criteria respectively.
</li>
<li><code>descending</code> &rarr; boolean flag to define if sorting is in descending order</li>
<li><code>allowMissingColumns</code> &rarr; flag to define if no exception should be thrown if a column is
missing
</li>
<li><code>dateRangeSel</code> &rarr; defines a lookup parameter to use as a date range selector. This
requires input when executing the report
</li>
</ul>
<h3>Lookups</h3>
<p>Many of the features of the generic report rely on looking up a value on the referenced element. The
following shows the ways that a lookup can be performed:</p>
<ul>
<li><code>$id</code> &rarr; lookup the ID of the element</li>
<li><code>$name</code> &rarr; lookup the name of the element</li>
<li><code>$type</code> &rarr; lookup the type of the element</li>
<li><code>$date</code> &rarr; lookup the date of the element (only possible on <code>Order</code> and <code>Activity</code>
elements)
</li>
<li><code>$state</code> &rarr; lookup the state of the element (only possible on <code>Order</code> and
<code>Activity</code> elements)
</li>
<li><code>Bags/&lt;bag_id&gt;/&lt;param_id&gt;</code> &rarr;</li>
<li><code>$search:&lt;parent_ref_id&gt;:Bags/&lt;bag_id&gt;/&lt;param_id&gt;</code> &rarr; searches for a
parameter with the given
bag and parameter, and
if it does not exist,
looks for the parent
with the given <code>parent_ref_id</code>
on the element. This
allows a recursive
search up a tree of
elements which all have
the same parameter
referencing a parent.
<code>relations</code> bag
</li>
</ul>
<p><b>Note:</b> these definitions are set as the value of a Parameter, and the <code>Interpretation</code> and
<code>UOM</code> of the parameter is used to find the element on which to perform the lookup. I.e. the
following definition:</p>
<pre>&lt;Parameter Id="name" Name="Player" Type="String" Interpretation="Resource-Ref" Uom="Player" Value="$name"/&gt;</pre>
<p>defines that we want to lookup the name of the resource of type Player.</p>
<h3>Ordering</h3>
<p>Ordering, i.e sorting is done by adding the parameter bag with the id <code>ordering</code> and each
parameter defines a column to order by. The sequence of the ordering is defined by the index value assigned
to each parameter.</p>
<h3>Filtering</h3>
<p>Filtering use additional Strolch Policies which implement the operator function. I.e. performing an equals,
etc. The following <code>ReportFilterPolicy</code> are available and should be added in your <code>StrolchPolicies.xml</code>
file:</p>
<pre>
&lt;StrolchPolicies&gt;
...
&lt;PolicyType Type="ReportFilterPolicy" Api="li.strolch.report.policy.ReportFilterPolicy"&gt;
&lt;Policy Key="GreaterThan" Class="li.strolch.report.policy.GreaterThanReportFilter" /&gt;
&lt;Policy Key="LessThan" Class="li.strolch.report.policy.LessThanReportFilter" /&gt;
&lt;Policy Key="Equals" Class="li.strolch.report.policy.EqualsReportFilter" /&gt;
&lt;/PolicyType&gt;
...
&lt;StrolchPolicies&gt;</pre>
<p>From this we can see that we can perform a <code>GreaterThan</code>, <code>LessThan</code> and
<code>Equals</code> filtering. These filters can also be negated by prefixing the filter value with an
exclamation mark (!).</p>
<p>A special case for the filter values are filters on dates. If you are filtering on a date, then you can use
the special operator <code>now()</code>. This filter will use the current date and time and will add/subtract
the ISO8601 period passed as an argument to the operator.</p>
<p>The following shows examples of these filters:</p>
<pre>
&lt;ParameterBag Id="minQtyFilter" Name="Filter" Type="Filter"&gt;
&lt;Parameter Id="policy" Name="Filter Policy" Type="String" Interpretation="ReportFilterPolicy" Uom="key:GreaterThan" Value="10"/&gt;
&lt;Parameter Id="fieldRef" Name="Field reference" Type="String" Interpretation="Resource-Ref" Uom="Product" Value="Bags/parameters/quantity"/&gt;
&lt;/ParameterBag&gt;
&lt;ParameterBag Id="notEmptyFilter" Name="Filter" Type="Filter"&gt;
&lt;Parameter Id="policy" Name="Filter Policy" Type="String" Interpretation="ReportFilterPolicy" Uom="key:Equals" Value="!"/&gt;
&lt;Parameter Id="fieldRef" Name="Field reference" Type="String" Interpretation="Resource-Ref" Uom="Team" Value="Bags/relations/team"/&gt;
&lt;/ParameterBag&gt;
&lt;ParameterBag Id="threeMonthsAgoFilter" Name="Filter" Type="Filter"&gt;
&lt;Parameter Id="policy" Name="Filter Policy" Type="String" Interpretation="ReportFilterPolicy" Uom="key:LessThan" Value="now(-P3M)"/&gt;
&lt;Parameter Id="fieldRef" Name="Field reference" Type="String" Interpretation="Resource-Ref" Uom="FromStock" Value="$date"/&gt;
&lt;/ParameterBag&gt;</pre>
<p><b>Note: </b> One parameter defines which policy gets used and the <code>key:&lt;name&gt;</code> value
references a policy defined in the <code>StrolchPolicies.xml</code> file. Further the lookup is
defined in the <code>fieldRef</code> parameter.</p>
<h3>Joins</h3>
<p>To add columns from data which is not on the element denoted by the base object type, we can join further
elements. This is done by adding the parameter bag <code>joins</code> and then each parameter references an
element to join. The joining is done as follows:</p>
<ul>
<li>The <code>Intepretation</code> and <code>UOM</code> define which object we want to join, i.e. resource
of type foo
</li>
<li>The value of the parameter defines the type of element on which to find the reference</li>
<li>The join ordering is not relevant, as the tree is traversed accordingly</li>
<li>At least one join must reference the base object type</li>
<li>The lookup of the join is done by finding a parameter with any ID, which has the same <code>Interpretation</code>
and <code>UOM</code> as the join definition
</li>
<li>The attributes <code>Hidden</code> and <code>Index</code> define the visibility and sorting index as
filter criteria respectively.
</li>
</ul>
<p>Thus the following:</p>
<pre>
&lt;ParameterBag Id="joins" Name="Joins" Type="Joins"&gt;
&lt;Parameter Id="Team" Index="10" Hidden="false" Name="Team" Type="String" Interpretation="Resource-Ref" Uom="Team" Value="Player"/&gt;
&lt;Parameter Id="Country" Index="5" Hidden="false" Name="Team" Type="String" Interpretation="Resource-Ref" Uom="Country" Value="Team"/&gt;
&lt;/ParameterBag&gt;</pre>
<p>Performs two joins: First we join a resource of type <code>Team</code> by finding the relevant parameter on
the <code>Player</code> resource, and then we lookup a resource of type <code>Country</code> on the
previously joined <code>Team</code> resource.</p>
<h3>Execution of Reports</h3>
<p>To execute a reports, we must instantiate the Report and can then directly generate a JsonObject stream,
which we can then pipe to a browser, file, etc.:</p>
<pre>
Stream&lt;JsonObject&gt; jsonObjectStream = new Report(tx, reportId).doReportAsJson();</pre>
<p>If you prefer a CSV report:</p>
<pre>
try (CSVPrinter csvP = new CSVPrinter(new OutputStreamWriter(out),
CSVFormat.DEFAULT.withHeader(headers).withDelimiter(';'))) {
// do report without AsJson, and then iterating each row and sending to a CSV writer
report.doReport().forEach(row -> {
try {
csvP.printRecord(row.valueStream().collect(Collectors.toList())); // add to CSV
} catch (Exception e) {
logger.error("Could not write CSV row", e);
}
});
}
</pre>
<h3>Filter Criteria</h3>
<p>Predefining filters is a good start, but in some case you only want a portion of the actual filtered data.
For instance if you make a stock report, you might only want one location. This information is dynamic and
thus not stored on the report definition.</p>
<p>To perform these dynamic filterings, one would call the <code>filter()</code> method on the report, passing
the type of element to be filtered, and to which element IDs to reduce the report data to. The following
reduces the report to only return the rows with the <code>product01</code> Product and
<code>location02</code> Location elements:</p>
<pre>
new Report(tx, "stockReport")
.filter("Product", "product01")
.filter("Location", "location02")
.doReportAsJson()</pre>
<p>It is possible to find the possible filter criteria dynamically using the
<code>generateFilterCriteria()</code> method.</p>
<h3>Date Range Filtering</h3>
<p>The last option to filter dynamically is using a date range selector. Define the <code>dateRangeSel</code>
lookup parameter, and then set the date range on the instantiated report:</p>
<pre>
&lt;ParameterBag Id="parameters" Name="parameters" Type="Parameters"&gt;
...
&lt;Parameter Id="dateRangeSel" Name="Date Range Selector" Type="String" Interpretation="Resource-Ref" Uom="Product" Value="Bags/parameters/expirationDate"/&gt;
...
&lt;/ParameterBag&gt;
Date from = new Date(LocalDate.of(2016, 1, 1).toEpochDay() * 86400000);
Date to = new Date(LocalDate.of(2017, 1, 1).toEpochDay() * 86400000);
DateRange dateRange = new DateRange().from(from, true).to(to, false);
List&lt;JsonObject&gt; result = new Report(tx, "stockReport") //
.filter("Product", "product01") //
.dateRange(dateRange) //
.doReportAsJson()
</pre>
<p><b>Note:</b> See the
<a href="https://github.com/4treesCH/strolch/blob/develop/li.strolch.service/src/test/java/li/strolch/report/GenericReportTest.java"
target="_blank">GenericReportTest</a> for examples.</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 xsd 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

@ -1,395 +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: Runtime Configuration</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="plc.html">PLC</a></li>
<li><a href="tutorial.html">Tutorial</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: Runtime</h1>
<p class="lead page-description">This page discusses the Strolch Runtime configuration.</p>
</div>
<div class="content">
<p>A Strolch runtime configuration comprises two parts: a configuration part, and a model part. The
configuration are files located in the <code>..config/</code> folder, and the model are files located in the
<code>../data</code> folder.</p>
<p>In an absolute minimal configuration, the Strolch runtime requires the following folder structure:</p>
<ul>
<li><code>../config/</code>
<dl>
<dt>StrolchConfiguration.xml</dt>
<dd>&rarr; configures the Strolch agent</dd>
<dt>PrivilegeConfig.xml</dt>
<dd>&rarr; configures user management</dd>
<dt>PrivilegeUsers.xml</dt>
<dd>&rarr; contains the users in an XML based user management file</dd>
<dt>PrivilegeRoles.xml</dt>
<dd>&rarr; contains the roles and privileges in an XML based user management</dd>
</dl>
</li>
</ul>
<h2>StrolchConfiguration.xml</h2>
<p>The <i>StrolchConfiguration.xml</i> file configures the Strolch agent. The <i>StrolchConfiguration.xml</i>
defines the following:</p>
<ul>
<li><code>&lt;StrolchConfiguration&gt;</code> root element</li>
<li><code>&lt;env id="xxx"&gt;</code> different environments with the possibility of having a global
environment for configuration valid in multiple environments.
<ul>
<li><code>&lt;Runtime&gt;</code> element which defines the agents name and a few other properties
e.g. <code>locale</code> and <code>verbose</code>:
<ul>
<li><code>&lt;applicationName&gt;</code> the agent's name</li>
<li><code>&lt;Properties&gt;</code></li>
<li><code>&lt;locale&gt;</code> the agent's internal locale for log messages etc.</li>
<li><code>&lt;verbose&gt;</code> the logging level for some internal logging. (Logging is
mostly done using log4j over slf4j)
</li>
</ul>
</li>
</ul>
</li>
<li><code>&lt;Component&gt;</code> elements for each component used in the agent. A component is configured
by defining the following child elements:
<ul>
<li><code>&lt;name&gt;</code> the name of the component, use when defining dependencies between
components. The name is mostly set to the simple name of the interface
of the component
</li>
<li><code>&lt;api&gt;</code> the full class name to the interface of the component. During runtime
this interface will be used to access the component e.g.: <code>ServiceHandler
svcHandler
=
agent.getContainer().getComponent(ServiceHandler.class);</code>
</li>
<li><code>&lt;impl&gt;</code> the full class name of the concrete implementation of the component.
During initialization this class will be instantiated and registered
under the component name and interface. This class must extend the
class <code>li.strolch.agent.api.StrolchComponent</code>
</li>
<li><code>&lt;depends&gt;</code> any number of these elements, where the content is the name of
another component, on which this component depends. Depending
components are initialized and started after the component they
depend on and are stopped and destroyed before
</li>
<li><code>&lt;Properties&gt;</code>
<ul>
<li><code>&lt;...&gt;</code> any number of properties which the component requires. The
element's name will be the key with which the value can be
accessed at runtime.
</li>
</ul>
</li>
</ul>
</li>
</ul>
<p><b>Note:</b> When a property is missing, and the component has a hard coded default value, then when the
component is initialized, the use of the default value and its key is logged. This makes it easy
to see which new properties can be configured. Should the component not define a default value,
then the component will thrown an exception on initialization. In this case it can be a good
moment to read the JavaDoc (or source code) for the component in question to see how it is
configured.</p>
<h2 id="privilegeConfig">Privilege Configuration</h2>
<p>In Strolch authentication and authorization is baked in. To open a transaction, and thus access the Strolch
model, a Certificate object is required, which means the user has been authenticated and possibly
authorized.</p>
<p>The <i>PrivilegeConfig.xml</i> defines the following:</p>
<ul>
<li><code>&lt;Privilege&gt;</code> root element
<ul>
<li><code>&lt;Container&gt;</code> configures the individual Privilege components
<ul>
<li><code>&lt;Parameters&gt;</code> base configuration properties for Privilege</li>
<li><code>&lt;EncryptionHandler&gt;</code> configures the hashing algorithms and other
encryption specific configuration
</li>
<li><code>&lt;PersistenceHandler&gt;</code> configures the persistence of the roles and
users
</li>
<li><code>&lt;UserChallengeHandler&gt;</code> configures a challenge handler so that a user
can reset their password. The default
challenge handler is the <code>li.strolch.privilege.handler.MailUserChallengeHandler</code>
which sends a challenge to the user's defined
e-mail address.
</li>
<li><code>&lt;SsoHandler&gt;</code> the SSO Handler is used to implement a SingleSignOn and
can be used to start a session using a LDAP token, etc.
There is no default implementation as this is project
specific.
</li>
</ul>
</li>
<li><code>&lt;Policies&gt;</code> configures the available privilege policies at runtime, the name
is referenced from the model file
</li>
</ul>
</li>
</ul>
<p>The <code>PrivilegeUsers.xml</code> and <code>PrivilegeRoles.xml</code> define the users and roles and is
used when in <code>PrvilegeConfig.xml</code> the <code>PersistenceHandler</code> is set to <code>ch.eitchnet.privilege.handler.XmlPersistenceHandler</code>:
</p>
<ul>
<li><code>&lt;Users&gt;</code> configures all users
<ul>
<li><code>&lt;User&gt;</code> configures a specific user
<ul>
<li><code>&lt;Firstname&gt;</code> configures a user's first name</li>
<li><code>&lt;Lastname&gt;</code> configure a user's last name</li>
<li><code>&lt;State&gt;</code> configures the user's state, see <code>ch.eitchnet.privilege.model.UserState</code>
</li>
<li><code>&lt;Locale&gt;</code> configure the user's locale</li>
<li><code>&lt;Roles&gt;</code> configures the user's roles
<ul>
<li><code>&lt;Role&gt;</code> adds a role to the user</li>
</ul>
</li>
<li><code>&lt;Properties&gt;</code> configures user specific properties. What properties are
used is not specified and is dependent on the concrete
agent
<ul>
<li><code>&lt;Property&gt;</code> defines a single property</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li><code>&lt;Roles&gt;</code> configures all roles
<ul>
<li><code>&lt;Role&gt;</code> configures a specific role
<ul>
<li><code>&lt;Privilege&gt;</code> configures a specific privilege for this role
<ul>
<li><code>&lt;AllAllowed&gt;</code> if set to true, then defines that all values
associated with this privilege are allowed
</li>
<li><code>&lt;Allow&gt;</code> defines one allowed value for this privilege
</li>
<li><code>&lt;Deny&gt;</code> defines one denied value for this privilege
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<h2>Implementing a StrolchComponent</h2>
<p>Implementing a strolch component requires an interface, which defines the component's API and a concrete
class which implements the interface and extends the class <code>StrolchComponent</code>.</p>
<p>The StrolchComponent class adds the state model to the class, which transitions as follows:<br /> <code>UNDEFINED
=&gt;
SETUP
=&gt;
INITIALIZED
=>
STARTED
&lt;=&gt;
STOPPED
=>
DESTROYED</code>
</p>
<p>Components can switch between <code>STARTED</code> and <code>STOPPED</code>, but once <code>DESTROYED</code>
no further state change is possible. The component's state is changed by changes to the agent's lifecycle.
</p>
<p>A component's state is changed by a call to the appropriate method on the component, override the methods as
necessary. Note that it is good practice that the <code>initialize()</code>-method is used to get all the
configuration properties, and that they should there be evaluated and that the method so return quickly. The
<code>start()</code>-method is called after the agent's initialization and should be where additional
threads are started. Correctly implementing these methods allows to quickly detect a wrongly configured
agent, which might take longer to start for whatever reason.</p>
<p>The following shows a basic implementation of a component on the basis of a post initializer (a component
which performs some actions in its <code>start()</code>-method which should be done after everything else is
started in the agent).</p>
<pre>
public class SimplePostInitializer
extends StrolchComponent
implements PostInitializer {
public SimplePostInitializer(ComponentContainer container,
String componentName) {
super(container, componentName);
}
@Override
public void initialize(ComponentConfiguration configuration) {
// do some initialization, validate configuration values, etc.
// now call super, to update state
super.initialize(configuration);
}
@Override
public void start() {
// start any threads, or perform long running start work
// now call super, to update state
super.start();
}
@Override
public void stop() {
// stop threads and timers, but be ready to start again
// now call super, to update state
super.stop();
}
@Override
public void destroy() {
// destroy this component, release all resources and don't worry about
// being called to start again now call super, to update state
super.destroy();
}
}
</pre>
<p>The new component would then be registered in the <code>StrolchConfiguration.xml</code> as follows:</p>
<pre>
&lt;StrolchConfiguration&gt;
&lt;env id="..."&gt;
...
&lt;Component&gt;
&lt;name&gt;SimplePostInitializer&lt;/name&gt;
&lt;api&gt;li.strolch.agent.api.PostInitializer&lt;/api&gt;
&lt;impl&gt;li.strolch.documentation.SimplePostInitializer&lt;/impl&gt;
&lt;/Component&gt;
...
&lt;/env&gt;
&lt;/StrolchConfiguration&gt;
</pre>
<p>And can be access at runtime using:</p>
<pre>
PostInitializer postInitializer = getContainer().getComponent(PostInitializer.class);
</pre>
<h2>Starting the agent</h2>
<p>When a Strolch runtime is started, then the root path to the runtime configuration must be passed. In Java
this is done by calling:</p>
<pre>
StrolchAgent agent = new StrolchAgent();
agent.setup(environment, rootPath);
agent.initialize();
agent.start();
</pre>
<p>In Servlet 3.0 applications one would implement the <code>javax.servlet.ServletContextListener</code>
interface, add the <code>@WebListener</code> annotation to the class and in the
<code>contextInitialized()</code>-method start Strolch:</p>
<pre>
String realPath = sce.getServletContext().getRealPath("/WEB-INF");
String environment = StrolchEnvironment.getEnvironmentFromEnvProperties(pathF);
this.agent = new StrolchAgent();
this.agent.setup(environment, new File(realPath));
this.agent.initialize();
this.agent.start();
</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 xsd 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

@ -1,183 +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: Searches</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="plc.html">PLC</a></li>
<li><a href="tutorial.html">Tutorial</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: Searches</h1>
<p class="lead page-description">This page discusses Strolch Searches.</p>
</div>
<div class="content">
<p>As is custom for every framework, querying, or searching, the model must be possible. Strolch searches are
implemented using the <code>StrolchSearch</code> class and one of its concrete implementations: <code>ResourceSearch</code>,
<code>OrderSearch</code>, <code>ActivitySearch</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. Thus when searching for objects, the first thing to do is define the type of
object being searched.</p>
<p>The Strolch search API is very expressive and offers multiple ways to perform the same search. The search API
consists of three components: The search classes, the search expressions and the search predicates. The
concept was taken from the <a href="https://camel.apache.org" target="_blank">Apache Camel</a> project.</p>
<p>There are four main search classes:</p>
<ul>
<li><code>RootElementSearch</code> - search for any of <code>Resource</code>, <code>Order</code> or <code>Activity</code>
elements
</li>
<li><code>ResourceSearch</code> - search for <code>Resources</code></li>
<li><code>OrderSearch</code> - search for <code>Orders</code></li>
<li><code>ActivitySearch</code> - search for <code>Activities</code></li>
</ul>
<p>No search is useful without a <code>where</code> clause, which are called search expressions. When writing a
search, there are multiple ways to add such where clauses. Either</p>
<ul>
<li>override the <code>define()</code> method in your sub class and add the where clauses by calling the
<code>where()</code> method, or
</li>
<li>define special methods on the class e.g. <code>byColor()</code> which also calls the
<code>where()</code> method to add a search expression, or
</li>
<li>directly call the <code>where()</code> method after instantiating a search.</li>
</ul>
<p>When extending the class, then the search expressions are available as methods on the super class, otherwise
you can statically import them from
<a href="https://github.com/4treesCH/strolch/blob/develop/li.strolch.agent/src/main/java/li/strolch/search/ExpressionsSupport.java"
target="_blank">ExpressionsSupport</a>.</p>
<p>And of course a where clause needs operators, which are called search predicates. Just as search expressions
are available in sub classes, so are search predicates and can also be statically imported through
<a href="https://github.com/4treesCH/strolch/blob/develop/li.strolch.agent/src/main/java/li/strolch/search/PredicatesSupport.java"
target="_blank">PredicatesSupport</a>.</p>
<p>Examples of search expressions with search predicates follow:</p>
<pre>
ResourceSearch search = new ResourceSearch();
// predicate either as parameter, or chained
search.where(id().isEqualTo("myId"));
search.where(id(isEqualTo("myId")));
// negating
search.where(id(isEqualTo("myId")).not());
search.where(param("bagId", "paramId").isIn(Arrays.asList("red", "blue", "green")));
search.where(paramNull("bagId", "paramId")));
// boolean operations
search.where(id(isEqualTo("myId")) //
.or(name(isEqualTo("myName"))));
</pre>
<p>Note how the predicates can be chained to the search expression, or passed as a parameter to the
expression.</p>
<p>In addition to using predefined search search expressions, one can also just pass a lambda expression which
performs a custom filter:</p>
<pre>
personSearch.where(person -> person.getName().length() == 3);</pre>
<p>See the
<a href="https://github.com/4treesCH/strolch/blob/develop/li.strolch.agent/src/test/java/li/strolch/search/StrolchSearchTest.java"
target="_blank">StrolchSearchTest</a> for many ways in which you can implement tests.</p>
<p>Note that strolch searches requires privileges. Thus when you use a strolch search, add it to the role of the
user in <code>PrivilegeRoles.xml</code>:</p>
<pre>
&lt;Privilege name="li.strolch.search.StrolchSearch" policy="DefaultPrivilege"&gt;
&lt;Allow&gt;internal&lt;/Allow&gt; &lt;!-- internal used for when the search is done in an internal service --&gt;
&lt;Allow&gt;li.strolch.bookshop.search.BookSearch&lt;/Allow&gt;
&lt;/Privilege&gt;</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 xsd 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

@ -1,213 +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: 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="plc.html">PLC</a></li>
<li><a href="tutorial.html">Tutorial</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(tx);
command.setOrder(arg.order);
tx.addCommand(command);
tx.commitOnClose();
}
return ServiceResult.success();
}
public static class AddOrderArg extends ServiceArgument {
public Order order;
}
}
</pre>
<p>AddOrderCommand:</p>
<pre>
public class AddOrderCommand extends Command {
private Order order;
public AddOrderCommand(StrolchTransaction tx) {
super(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 xsd 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

@ -1,191 +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: Transactions</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="plc.html">PLC</a></li>
<li><a href="tutorial.html">Tutorial</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: Transactions</h1>
<p class="lead page-description">This page discusses Strolch Transactions.</p>
</div>
<div class="content">
<p>Strolch Transactions play a central role in a Strolch agent. A transaction is opened for a realm, and grants
access to the model of the agent. Transactions are implemented as a Java <code>try-with-resources</code> by
implementing the <code>AutoCloseable</code> interface. This makes it trivial to understand the scope of a
transaction. </p>
<p>Transactions handle the following:</p>
<ul>
<li>Opening and closing database connections</li>
<li>Releasing locks to strolch elements, if <code>tx.lock(StrolchRootElement)</code> or <code>tx.lock(Locator)</code>
was called
</li>
<li>Performing Commands by executing them in the added order, and validating them first.</li>
<li>Exception handling</li>
<li>Auditing</li>
<li>Updating observers</li>
</ul>
<p>When a transaction is opened, it is by default read-only, i.e. does not perform any commands when it is
closed. Should the TX perform commands, then it is important to call <code>tx.commitOnClose()</code>, but
only at the end of the work, so that exception handling can properly work if something goes wrong.</p>
<p><code>StrolchTransaction</code> offers a myriad of methods:</p>
<ul>
<li>find element by its <code>Locator</code></li>
<li>get methods for elements by type and id, or using a <code>StringParameter</code> or <code>StringListParameter</code>
references
</li>
<li>methods to add, update or remove elements</li>
<li>assert privilege access</li>
<li>get a new element by its template</li>
<li>check if an element exists by type and id</li>
<li>get streams for elements</li>
<li>add commands for execution</li>
</ul>
<p>Transactions are opened by accessing the realm, but there are convenience methods depending on the
use-case:</p>
<ul>
<li>In Services: by calling one of the <code>openTx()</code>-methods</li>
<li>In Commands: Transactions are already open, use method <code>tx()</code> to get instance. <b>Note:</b>
don't open a new TX inside a TX for the same realm!
</li>
<li>REST API: <code>RestfulStrolchComponent.openTx()</code></li>
</ul>
<p>Important is to always open the transaction as a try-with-resource block and to define if the TX should
commit, or not:</p>
<pre>
try (StrolchTransaction tx = openTx(...)) {
// read lock our object
Locator ferrariLoc = Resource.locatorFor("Car", "ferrari");
tx.lock(ferrariLoc);
// find a car by locator
Resource ferrari = tx.findElement(ferrariLoc);
// get a car by ID
Resource opel = tx.getResourceBy("Car", "opel", true);
// modify ball
opel.setName("Opel Corsa");
tx.update(opel);
// get by string reference
StringParameter ownerP = ferrari.getParameter("relations", "owner", true);
Resource owner = tx.getResourceBy(ownerP, true);
// get by string list reference
StringListParameter previousOwnersP = opel.getParameter("relations", "previousOwners", true);
List&lt;Resource&gt; previousOwners = tx.getResourcesBy(previousOwnersP, true);
// check resource exists
if (tx.hasResource("Car", "audi")) {
Resource audi = tx.getResourceBy("Car", "audi", true);
// assert has privilege to remove a car
tx.assertHasPrivilege(Operation.REMOVE, audi);
// remove the car
tx.remove(audi);
}
// iterate all cars
tx.streamResources("Car").forEach(car -> {
logger.info("Car: " + car.getId());
});
// commit if TX was changed
if (tx.needsCommit())
tx.commitOnClose();
}</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 xsd 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

@ -1,149 +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: Versioning</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="plc.html">PLC</a></li>
<li><a href="tutorial.html">Tutorial</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: Versioning</h1>
<p class="lead page-description">This page discusses the Strolch Versioning</p>
</div>
<div class="content">
<p>One of Strolch's features that sets it apart from other frameworks, is that versioning is baked into
Strolch's fabric. The feature is opt-in, as it is not required in all projects, but it only needs enabling,
for all modifications to objects to be versioned, so that rollbacks can be done when needed.</p>
<p>The feature is enabled for each realm. In the <code>StrolchConfiguration.xml</code> file enable it by adding
the <code>enableVersioning</code> propery per realm:</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;Properties&gt;
&lt;realms&gt;defaultRealm, otherRealm&lt;/realms&gt;
&lt;enableVersioning&gt;true&lt;/enableVersioning&gt;
&lt;dataStoreMode&gt;TRANSIENT&lt;/dataStoreMode&gt;
&lt;dataStoreFile&gt;StrolchModel.xml&lt;/dataStoreFile&gt;
&lt;enableVersioning.otherRealm&gt;true&lt;/enableVersioning.otherRealm&gt;
&lt;dataStoreMode.otherRealm&gt;TRANSIENT&lt;/dataStoreMode.otherRealm&gt;
&lt;dataStoreFile.otherRealm&gt;StrolchModel.xml&lt;/dataStoreFile.otherRealm&gt;
&lt;/Properties&gt;
&lt;/Component&gt;
&lt;/env&gt;
...
&lt;/StrolchConfiguration&gt;</pre>
<br />
<p>Once versioning is enabled, versioning is handled automatically. The API for versioning is implemented on the
ElementMaps.</p>
<p>Example: Revert to previous version of a Resource:</p>
<pre>
Resource res = tx.getResourceBy("TestType", "MyTestResource");
ResourceMap resourceMap = tx.getResourceMap();
Resource previousVersion = resourceMap.revertToVersion(tx, res);
// or
Resource previousVersion = resourceMap.revertToVersion(tx, "TestType", "MyTestResource", 1);</pre>
<p>Example: Retrieve all versions of a Resource:</p>
<pre>
List&lt;Resource&gt; versions = resourceMap.getVersionsFor(tx, "TestType", "MyTestResource");</pre>
<br />
<p><b>Note:</b> When reverting to a previous version, it is important to remember, that any references on an
element to other elements will also be restored. As long as the relationship is to the same
element, then this is not an issue, but should the relationship have changed, then it this must
be handled and the user performing a revert be allowed to decided which element to reference in
the reverted version.</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 xsd 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

@ -1,121 +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: Documentation</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="plc.html">PLC</a></li>
<li><a href="tutorial.html">Tutorial</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</h1>
<p class="lead page-description">This is the index page to the documentation of Strolch.</p>
</div>
<div class="content">
<p>Strolch's documentation has only just begun, but as more and more details of the implementation in Strolch
are fixed, more documentation can be created and will be available here.</p>
<p>Currently we have the following topics of discussion:</p>
<ul>
<li><a href="documentation-architecture.html">Strolch Architecture</a></li>
<li><a href="documentation-model.html">Strolch Model</a></li>
<li><a href="documentation-do-and-dont.html">Strolch Do and Dont</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-searches.html">Strolch Searches</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-observers.html">Strolch Observers</a></li>
<li><a href="documentation-versioning.html">Strolch Versioning</a></li>
<li><a href="documentation-reports.html">Strolch Reports</a></li>
<li><a href="documentation-privileges.html">Strolch Privileges</a></li>
<!--
<li><a href="documentation-audits.html">Strolch Audits</a></li>
-->
</ul>
<!-- 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 xsd 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

@ -1,114 +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: Downloads</title>
<!-- Bootstrap core CSS -->
<link href="css/bootstrap.min.css" rel="stylesheet">
<!-- Custom styles for this template -->
<link href="css/custom.css" rel="stylesheet">
<link rel="stylesheet" href="css/downloads.css" type="text/css" />
<!-- 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><a href="documentation.html">Documentation</a></li>
<li><a href="plc.html">PLC</a></li>
<li><a href="tutorial.html">Tutorial</a></li>
<li class="active"><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">Downloads</h1>
<p class="lead page-description">This page describes where you can get Strolch.</p>
</div>
<div class="row">
<div class="col-xs-12">
<p>Strolch is on <a href="https://mvnrepository.com/artifact/li.strolch/li.strolch.agent">Maven central</a>, but if the
latest version is not there, then build it locally. A guide can be found on the
<a href="development.html">development</a> page. </p>
<p>Strolch is also built on <a href="https://ci.4trees.ch/">Jenkins</a>, so you can see if the latest
version passes all tests.</p>
</div>
</div>
<!-- content here -->
</div>
<!-- /.content -->
<div class="row">&nbsp;</div>
<!-- .footer -->
<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>
<!-- /.footer -->
</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 xsd 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

@ -1,229 +0,0 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
<svg xmlns="http://www.w3.org/2000/svg">
<metadata></metadata>
<defs>
<font id="glyphicons_halflingsregular" horiz-adv-x="1200" >
<font-face units-per-em="1200" ascent="960" descent="-240" />
<missing-glyph horiz-adv-x="500" />
<glyph />
<glyph />
<glyph unicode="&#xd;" />
<glyph unicode=" " />
<glyph unicode="*" d="M100 500v200h259l-183 183l141 141l183 -183v259h200v-259l183 183l141 -141l-183 -183h259v-200h-259l183 -183l-141 -141l-183 183v-259h-200v259l-183 -183l-141 141l183 183h-259z" />
<glyph unicode="+" d="M0 400v300h400v400h300v-400h400v-300h-400v-400h-300v400h-400z" />
<glyph unicode="&#xa0;" />
<glyph unicode="&#x2000;" horiz-adv-x="652" />
<glyph unicode="&#x2001;" horiz-adv-x="1304" />
<glyph unicode="&#x2002;" horiz-adv-x="652" />
<glyph unicode="&#x2003;" horiz-adv-x="1304" />
<glyph unicode="&#x2004;" horiz-adv-x="434" />
<glyph unicode="&#x2005;" horiz-adv-x="326" />
<glyph unicode="&#x2006;" horiz-adv-x="217" />
<glyph unicode="&#x2007;" horiz-adv-x="217" />
<glyph unicode="&#x2008;" horiz-adv-x="163" />
<glyph unicode="&#x2009;" horiz-adv-x="260" />
<glyph unicode="&#x200a;" horiz-adv-x="72" />
<glyph unicode="&#x202f;" horiz-adv-x="260" />
<glyph unicode="&#x205f;" horiz-adv-x="326" />
<glyph unicode="&#x20ac;" d="M100 500l100 100h113q0 47 5 100h-218l100 100h135q37 167 112 257q117 141 297 141q242 0 354 -189q60 -103 66 -209h-181q0 55 -25.5 99t-63.5 68t-75 36.5t-67 12.5q-24 0 -52.5 -10t-62.5 -32t-65.5 -67t-50.5 -107h379l-100 -100h-300q-6 -46 -6 -100h406l-100 -100 h-300q9 -74 33 -132t52.5 -91t62 -54.5t59 -29t46.5 -7.5q29 0 66 13t75 37t63.5 67.5t25.5 96.5h174q-31 -172 -128 -278q-107 -117 -274 -117q-205 0 -324 158q-36 46 -69 131.5t-45 205.5h-217z" />
<glyph unicode="&#x2212;" d="M200 400h900v300h-900v-300z" />
<glyph unicode="&#x25fc;" horiz-adv-x="500" d="M0 0z" />
<glyph unicode="&#x2601;" d="M-14 494q0 -80 56.5 -137t135.5 -57h750q120 0 205 86.5t85 207.5t-85 207t-205 86q-46 0 -90 -14q-44 97 -134.5 156.5t-200.5 59.5q-152 0 -260 -107.5t-108 -260.5q0 -25 2 -37q-66 -14 -108.5 -67.5t-42.5 -122.5z" />
<glyph unicode="&#x2709;" d="M0 100l400 400l200 -200l200 200l400 -400h-1200zM0 300v600l300 -300zM0 1100l600 -603l600 603h-1200zM900 600l300 300v-600z" />
<glyph unicode="&#x270f;" d="M-13 -13l333 112l-223 223zM187 403l214 -214l614 614l-214 214zM887 1103l214 -214l99 92q13 13 13 32.5t-13 33.5l-153 153q-15 13 -33 13t-33 -13z" />
<glyph unicode="&#xe001;" d="M0 1200h1200l-500 -550v-550h300v-100h-800v100h300v550z" />
<glyph unicode="&#xe002;" d="M14 84q18 -55 86 -75.5t147 5.5q65 21 109 69t44 90v606l600 155v-521q-64 16 -138 -7q-79 -26 -122.5 -83t-25.5 -111q18 -55 86 -75.5t147 4.5q70 23 111.5 63.5t41.5 95.5v881q0 10 -7 15.5t-17 2.5l-752 -193q-10 -3 -17 -12.5t-7 -19.5v-689q-64 17 -138 -7 q-79 -25 -122.5 -82t-25.5 -112z" />
<glyph unicode="&#xe003;" d="M23 693q0 200 142 342t342 142t342 -142t142 -342q0 -142 -78 -261l300 -300q7 -8 7 -18t-7 -18l-109 -109q-8 -7 -18 -7t-18 7l-300 300q-119 -78 -261 -78q-200 0 -342 142t-142 342zM176 693q0 -136 97 -233t234 -97t233.5 96.5t96.5 233.5t-96.5 233.5t-233.5 96.5 t-234 -97t-97 -233z" />
<glyph unicode="&#xe005;" d="M100 784q0 64 28 123t73 100.5t104.5 64t119 20.5t120 -38.5t104.5 -104.5q48 69 109.5 105t121.5 38t118.5 -20.5t102.5 -64t71 -100.5t27 -123q0 -57 -33.5 -117.5t-94 -124.5t-126.5 -127.5t-150 -152.5t-146 -174q-62 85 -145.5 174t-149.5 152.5t-126.5 127.5 t-94 124.5t-33.5 117.5z" />
<glyph unicode="&#xe006;" d="M-72 800h479l146 400h2l146 -400h472l-382 -278l145 -449l-384 275l-382 -275l146 447zM168 71l2 1z" />
<glyph unicode="&#xe007;" d="M-72 800h479l146 400h2l146 -400h472l-382 -278l145 -449l-384 275l-382 -275l146 447zM168 71l2 1zM237 700l196 -142l-73 -226l192 140l195 -141l-74 229l193 140h-235l-77 211l-78 -211h-239z" />
<glyph unicode="&#xe008;" d="M0 0v143l400 257v100q-37 0 -68.5 74.5t-31.5 125.5v200q0 124 88 212t212 88t212 -88t88 -212v-200q0 -51 -31.5 -125.5t-68.5 -74.5v-100l400 -257v-143h-1200z" />
<glyph unicode="&#xe009;" d="M0 0v1100h1200v-1100h-1200zM100 100h100v100h-100v-100zM100 300h100v100h-100v-100zM100 500h100v100h-100v-100zM100 700h100v100h-100v-100zM100 900h100v100h-100v-100zM300 100h600v400h-600v-400zM300 600h600v400h-600v-400zM1000 100h100v100h-100v-100z M1000 300h100v100h-100v-100zM1000 500h100v100h-100v-100zM1000 700h100v100h-100v-100zM1000 900h100v100h-100v-100z" />
<glyph unicode="&#xe010;" d="M0 50v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5zM0 650v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400 q-21 0 -35.5 14.5t-14.5 35.5zM600 50v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5zM600 650v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400 q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5z" />
<glyph unicode="&#xe011;" d="M0 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM0 450v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200 q-21 0 -35.5 14.5t-14.5 35.5zM0 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5 t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 450v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5 v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM800 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM800 450v200q0 21 14.5 35.5t35.5 14.5h200 q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM800 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5z" />
<glyph unicode="&#xe012;" d="M0 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM0 450q0 -21 14.5 -35.5t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v200q0 21 -14.5 35.5t-35.5 14.5h-200q-21 0 -35.5 -14.5 t-14.5 -35.5v-200zM0 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 50v200q0 21 14.5 35.5t35.5 14.5h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5 t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5zM400 450v200q0 21 14.5 35.5t35.5 14.5h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5zM400 850v200q0 21 14.5 35.5t35.5 14.5h700q21 0 35.5 -14.5t14.5 -35.5 v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5z" />
<glyph unicode="&#xe013;" d="M29 454l419 -420l818 820l-212 212l-607 -607l-206 207z" />
<glyph unicode="&#xe014;" d="M106 318l282 282l-282 282l212 212l282 -282l282 282l212 -212l-282 -282l282 -282l-212 -212l-282 282l-282 -282z" />
<glyph unicode="&#xe015;" d="M23 693q0 200 142 342t342 142t342 -142t142 -342q0 -142 -78 -261l300 -300q7 -8 7 -18t-7 -18l-109 -109q-8 -7 -18 -7t-18 7l-300 300q-119 -78 -261 -78q-200 0 -342 142t-142 342zM176 693q0 -136 97 -233t234 -97t233.5 96.5t96.5 233.5t-96.5 233.5t-233.5 96.5 t-234 -97t-97 -233zM300 600v200h100v100h200v-100h100v-200h-100v-100h-200v100h-100z" />
<glyph unicode="&#xe016;" d="M23 694q0 200 142 342t342 142t342 -142t142 -342q0 -141 -78 -262l300 -299q7 -7 7 -18t-7 -18l-109 -109q-8 -8 -18 -8t-18 8l-300 300q-119 -78 -261 -78q-200 0 -342 142t-142 342zM176 694q0 -136 97 -233t234 -97t233.5 97t96.5 233t-96.5 233t-233.5 97t-234 -97 t-97 -233zM300 601h400v200h-400v-200z" />
<glyph unicode="&#xe017;" d="M23 600q0 183 105 331t272 210v-166q-103 -55 -165 -155t-62 -220q0 -177 125 -302t302 -125t302 125t125 302q0 120 -62 220t-165 155v166q167 -62 272 -210t105 -331q0 -118 -45.5 -224.5t-123 -184t-184 -123t-224.5 -45.5t-224.5 45.5t-184 123t-123 184t-45.5 224.5 zM500 750q0 -21 14.5 -35.5t35.5 -14.5h100q21 0 35.5 14.5t14.5 35.5v400q0 21 -14.5 35.5t-35.5 14.5h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-400z" />
<glyph unicode="&#xe018;" d="M100 1h200v300h-200v-300zM400 1v500h200v-500h-200zM700 1v800h200v-800h-200zM1000 1v1200h200v-1200h-200z" />
<glyph unicode="&#xe019;" d="M26 601q0 -33 6 -74l151 -38l2 -6q14 -49 38 -93l3 -5l-80 -134q45 -59 105 -105l133 81l5 -3q45 -26 94 -39l5 -2l38 -151q40 -5 74 -5q27 0 74 5l38 151l6 2q46 13 93 39l5 3l134 -81q56 44 104 105l-80 134l3 5q24 44 39 93l1 6l152 38q5 40 5 74q0 28 -5 73l-152 38 l-1 6q-16 51 -39 93l-3 5l80 134q-44 58 -104 105l-134 -81l-5 3q-45 25 -93 39l-6 1l-38 152q-40 5 -74 5q-27 0 -74 -5l-38 -152l-5 -1q-50 -14 -94 -39l-5 -3l-133 81q-59 -47 -105 -105l80 -134l-3 -5q-25 -47 -38 -93l-2 -6l-151 -38q-6 -48 -6 -73zM385 601 q0 88 63 151t152 63t152 -63t63 -151q0 -89 -63 -152t-152 -63t-152 63t-63 152z" />
<glyph unicode="&#xe020;" d="M100 1025v50q0 10 7.5 17.5t17.5 7.5h275v100q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5v-100h275q10 0 17.5 -7.5t7.5 -17.5v-50q0 -11 -7 -18t-18 -7h-1050q-11 0 -18 7t-7 18zM200 100v800h900v-800q0 -41 -29.5 -71t-70.5 -30h-700q-41 0 -70.5 30 t-29.5 71zM300 100h100v700h-100v-700zM500 100h100v700h-100v-700zM500 1100h300v100h-300v-100zM700 100h100v700h-100v-700zM900 100h100v700h-100v-700z" />
<glyph unicode="&#xe021;" d="M1 601l656 644l644 -644h-200v-600h-300v400h-300v-400h-300v600h-200z" />
<glyph unicode="&#xe022;" d="M100 25v1150q0 11 7 18t18 7h475v-500h400v-675q0 -11 -7 -18t-18 -7h-850q-11 0 -18 7t-7 18zM700 800v300l300 -300h-300z" />
<glyph unicode="&#xe023;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM500 500v400h100 v-300h200v-100h-300z" />
<glyph unicode="&#xe024;" d="M-100 0l431 1200h209l-21 -300h162l-20 300h208l431 -1200h-538l-41 400h-242l-40 -400h-539zM488 500h224l-27 300h-170z" />
<glyph unicode="&#xe025;" d="M0 0v400h490l-290 300h200v500h300v-500h200l-290 -300h490v-400h-1100zM813 200h175v100h-175v-100z" />
<glyph unicode="&#xe026;" d="M1 600q0 122 47.5 233t127.5 191t191 127.5t233 47.5t233 -47.5t191 -127.5t127.5 -191t47.5 -233t-47.5 -233t-127.5 -191t-191 -127.5t-233 -47.5t-233 47.5t-191 127.5t-127.5 191t-47.5 233zM188 600q0 -170 121 -291t291 -121t291 121t121 291t-121 291t-291 121 t-291 -121t-121 -291zM350 600h150v300h200v-300h150l-250 -300z" />
<glyph unicode="&#xe027;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM350 600l250 300 l250 -300h-150v-300h-200v300h-150z" />
<glyph unicode="&#xe028;" d="M0 25v475l200 700h800l199 -700l1 -475q0 -11 -7 -18t-18 -7h-1150q-11 0 -18 7t-7 18zM200 500h200l50 -200h300l50 200h200l-97 500h-606z" />
<glyph unicode="&#xe029;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -172 121.5 -293t292.5 -121t292.5 121t121.5 293q0 171 -121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM500 397v401 l297 -200z" />
<glyph unicode="&#xe030;" d="M23 600q0 -118 45.5 -224.5t123 -184t184 -123t224.5 -45.5t224.5 45.5t184 123t123 184t45.5 224.5h-150q0 -177 -125 -302t-302 -125t-302 125t-125 302t125 302t302 125q136 0 246 -81l-146 -146h400v400l-145 -145q-157 122 -355 122q-118 0 -224.5 -45.5t-184 -123 t-123 -184t-45.5 -224.5z" />
<glyph unicode="&#xe031;" d="M23 600q0 118 45.5 224.5t123 184t184 123t224.5 45.5q198 0 355 -122l145 145v-400h-400l147 147q-112 80 -247 80q-177 0 -302 -125t-125 -302h-150zM100 0v400h400l-147 -147q112 -80 247 -80q177 0 302 125t125 302h150q0 -118 -45.5 -224.5t-123 -184t-184 -123 t-224.5 -45.5q-198 0 -355 122z" />
<glyph unicode="&#xe032;" d="M100 0h1100v1200h-1100v-1200zM200 100v900h900v-900h-900zM300 200v100h100v-100h-100zM300 400v100h100v-100h-100zM300 600v100h100v-100h-100zM300 800v100h100v-100h-100zM500 200h500v100h-500v-100zM500 400v100h500v-100h-500zM500 600v100h500v-100h-500z M500 800v100h500v-100h-500z" />
<glyph unicode="&#xe033;" d="M0 100v600q0 41 29.5 70.5t70.5 29.5h100v200q0 82 59 141t141 59h300q82 0 141 -59t59 -141v-200h100q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-900q-41 0 -70.5 29.5t-29.5 70.5zM400 800h300v150q0 21 -14.5 35.5t-35.5 14.5h-200 q-21 0 -35.5 -14.5t-14.5 -35.5v-150z" />
<glyph unicode="&#xe034;" d="M100 0v1100h100v-1100h-100zM300 400q60 60 127.5 84t127.5 17.5t122 -23t119 -30t110 -11t103 42t91 120.5v500q-40 -81 -101.5 -115.5t-127.5 -29.5t-138 25t-139.5 40t-125.5 25t-103 -29.5t-65 -115.5v-500z" />
<glyph unicode="&#xe035;" d="M0 275q0 -11 7 -18t18 -7h50q11 0 18 7t7 18v300q0 127 70.5 231.5t184.5 161.5t245 57t245 -57t184.5 -161.5t70.5 -231.5v-300q0 -11 7 -18t18 -7h50q11 0 18 7t7 18v300q0 116 -49.5 227t-131 192.5t-192.5 131t-227 49.5t-227 -49.5t-192.5 -131t-131 -192.5 t-49.5 -227v-300zM200 20v460q0 8 6 14t14 6h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14zM800 20v460q0 8 6 14t14 6h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14z" />
<glyph unicode="&#xe036;" d="M0 400h300l300 -200v800l-300 -200h-300v-400zM688 459l141 141l-141 141l71 71l141 -141l141 141l71 -71l-141 -141l141 -141l-71 -71l-141 141l-141 -141z" />
<glyph unicode="&#xe037;" d="M0 400h300l300 -200v800l-300 -200h-300v-400zM700 857l69 53q111 -135 111 -310q0 -169 -106 -302l-67 54q86 110 86 248q0 146 -93 257z" />
<glyph unicode="&#xe038;" d="M0 401v400h300l300 200v-800l-300 200h-300zM702 858l69 53q111 -135 111 -310q0 -170 -106 -303l-67 55q86 110 86 248q0 145 -93 257zM889 951l7 -8q123 -151 123 -344q0 -189 -119 -339l-7 -8l81 -66l6 8q142 178 142 405q0 230 -144 408l-6 8z" />
<glyph unicode="&#xe039;" d="M0 0h500v500h-200v100h-100v-100h-200v-500zM0 600h100v100h400v100h100v100h-100v300h-500v-600zM100 100v300h300v-300h-300zM100 800v300h300v-300h-300zM200 200v100h100v-100h-100zM200 900h100v100h-100v-100zM500 500v100h300v-300h200v-100h-100v-100h-200v100 h-100v100h100v200h-200zM600 0v100h100v-100h-100zM600 1000h100v-300h200v-300h300v200h-200v100h200v500h-600v-200zM800 800v300h300v-300h-300zM900 0v100h300v-100h-300zM900 900v100h100v-100h-100zM1100 200v100h100v-100h-100z" />
<glyph unicode="&#xe040;" d="M0 200h100v1000h-100v-1000zM100 0v100h300v-100h-300zM200 200v1000h100v-1000h-100zM500 0v91h100v-91h-100zM500 200v1000h200v-1000h-200zM700 0v91h100v-91h-100zM800 200v1000h100v-1000h-100zM900 0v91h200v-91h-200zM1000 200v1000h200v-1000h-200z" />
<glyph unicode="&#xe041;" d="M0 700l1 475q0 10 7.5 17.5t17.5 7.5h474l700 -700l-500 -500zM148 953q0 -42 29 -71q30 -30 71.5 -30t71.5 30q29 29 29 71t-29 71q-30 30 -71.5 30t-71.5 -30q-29 -29 -29 -71z" />
<glyph unicode="&#xe042;" d="M1 700l1 475q0 11 7 18t18 7h474l700 -700l-500 -500zM148 953q0 -42 30 -71q29 -30 71 -30t71 30q30 29 30 71t-30 71q-29 30 -71 30t-71 -30q-30 -29 -30 -71zM701 1200h100l700 -700l-500 -500l-50 50l450 450z" />
<glyph unicode="&#xe043;" d="M100 0v1025l175 175h925v-1000l-100 -100v1000h-750l-100 -100h750v-1000h-900z" />
<glyph unicode="&#xe044;" d="M200 0l450 444l450 -443v1150q0 20 -14.5 35t-35.5 15h-800q-21 0 -35.5 -15t-14.5 -35v-1151z" />
<glyph unicode="&#xe045;" d="M0 100v700h200l100 -200h600l100 200h200v-700h-200v200h-800v-200h-200zM253 829l40 -124h592l62 124l-94 346q-2 11 -10 18t-18 7h-450q-10 0 -18 -7t-10 -18zM281 24l38 152q2 10 11.5 17t19.5 7h500q10 0 19.5 -7t11.5 -17l38 -152q2 -10 -3.5 -17t-15.5 -7h-600 q-10 0 -15.5 7t-3.5 17z" />
<glyph unicode="&#xe046;" d="M0 200q0 -41 29.5 -70.5t70.5 -29.5h1000q41 0 70.5 29.5t29.5 70.5v600q0 41 -29.5 70.5t-70.5 29.5h-150q-4 8 -11.5 21.5t-33 48t-53 61t-69 48t-83.5 21.5h-200q-41 0 -82 -20.5t-70 -50t-52 -59t-34 -50.5l-12 -20h-150q-41 0 -70.5 -29.5t-29.5 -70.5v-600z M356 500q0 100 72 172t172 72t172 -72t72 -172t-72 -172t-172 -72t-172 72t-72 172zM494 500q0 -44 31 -75t75 -31t75 31t31 75t-31 75t-75 31t-75 -31t-31 -75zM900 700v100h100v-100h-100z" />
<glyph unicode="&#xe047;" d="M53 0h365v66q-41 0 -72 11t-49 38t1 71l92 234h391l82 -222q16 -45 -5.5 -88.5t-74.5 -43.5v-66h417v66q-34 1 -74 43q-18 19 -33 42t-21 37l-6 13l-385 998h-93l-399 -1006q-24 -48 -52 -75q-12 -12 -33 -25t-36 -20l-15 -7v-66zM416 521l178 457l46 -140l116 -317h-340 z" />
<glyph unicode="&#xe048;" d="M100 0v89q41 7 70.5 32.5t29.5 65.5v827q0 28 -1 39.5t-5.5 26t-15.5 21t-29 14t-49 14.5v71l471 -1q120 0 213 -88t93 -228q0 -55 -11.5 -101.5t-28 -74t-33.5 -47.5t-28 -28l-12 -7q8 -3 21.5 -9t48 -31.5t60.5 -58t47.5 -91.5t21.5 -129q0 -84 -59 -156.5t-142 -111 t-162 -38.5h-500zM400 200h161q89 0 153 48.5t64 132.5q0 90 -62.5 154.5t-156.5 64.5h-159v-400zM400 700h139q76 0 130 61.5t54 138.5q0 82 -84 130.5t-239 48.5v-379z" />
<glyph unicode="&#xe049;" d="M200 0v57q77 7 134.5 40.5t65.5 80.5l173 849q10 56 -10 74t-91 37q-6 1 -10.5 2.5t-9.5 2.5v57h425l2 -57q-33 -8 -62 -25.5t-46 -37t-29.5 -38t-17.5 -30.5l-5 -12l-128 -825q-10 -52 14 -82t95 -36v-57h-500z" />
<glyph unicode="&#xe050;" d="M-75 200h75v800h-75l125 167l125 -167h-75v-800h75l-125 -167zM300 900v300h150h700h150v-300h-50q0 29 -8 48.5t-18.5 30t-33.5 15t-39.5 5.5t-50.5 1h-200v-850l100 -50v-100h-400v100l100 50v850h-200q-34 0 -50.5 -1t-40 -5.5t-33.5 -15t-18.5 -30t-8.5 -48.5h-49z " />
<glyph unicode="&#xe051;" d="M33 51l167 125v-75h800v75l167 -125l-167 -125v75h-800v-75zM100 901v300h150h700h150v-300h-50q0 29 -8 48.5t-18 30t-33.5 15t-40 5.5t-50.5 1h-200v-650l100 -50v-100h-400v100l100 50v650h-200q-34 0 -50.5 -1t-39.5 -5.5t-33.5 -15t-18.5 -30t-8 -48.5h-50z" />
<glyph unicode="&#xe052;" d="M0 50q0 -20 14.5 -35t35.5 -15h1100q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM0 350q0 -20 14.5 -35t35.5 -15h800q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-800q-21 0 -35.5 -14.5t-14.5 -35.5 v-100zM0 650q0 -20 14.5 -35t35.5 -15h1000q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1000q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM0 950q0 -20 14.5 -35t35.5 -15h600q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-600q-21 0 -35.5 -14.5 t-14.5 -35.5v-100z" />
<glyph unicode="&#xe053;" d="M0 50q0 -20 14.5 -35t35.5 -15h1100q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM0 650q0 -20 14.5 -35t35.5 -15h1100q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5 v-100zM200 350q0 -20 14.5 -35t35.5 -15h700q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-700q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM200 950q0 -20 14.5 -35t35.5 -15h700q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-700q-21 0 -35.5 -14.5 t-14.5 -35.5v-100z" />
<glyph unicode="&#xe054;" d="M0 50v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15t-14.5 35zM100 650v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1000q-21 0 -35.5 15 t-14.5 35zM300 350v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800q-21 0 -35.5 15t-14.5 35zM500 950v100q0 21 14.5 35.5t35.5 14.5h600q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-600 q-21 0 -35.5 15t-14.5 35z" />
<glyph unicode="&#xe055;" d="M0 50v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15t-14.5 35zM0 350v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15 t-14.5 35zM0 650v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15t-14.5 35zM0 950v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100 q-21 0 -35.5 15t-14.5 35z" />
<glyph unicode="&#xe056;" d="M0 50v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15t-14.5 35zM0 350v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15 t-14.5 35zM0 650v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15t-14.5 35zM0 950v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15 t-14.5 35zM300 50v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800q-21 0 -35.5 15t-14.5 35zM300 350v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800 q-21 0 -35.5 15t-14.5 35zM300 650v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800q-21 0 -35.5 15t-14.5 35zM300 950v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15 h-800q-21 0 -35.5 15t-14.5 35z" />
<glyph unicode="&#xe057;" d="M-101 500v100h201v75l166 -125l-166 -125v75h-201zM300 0h100v1100h-100v-1100zM500 50q0 -20 14.5 -35t35.5 -15h600q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-600q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM500 350q0 -20 14.5 -35t35.5 -15h300q20 0 35 15t15 35 v100q0 21 -15 35.5t-35 14.5h-300q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM500 650q0 -20 14.5 -35t35.5 -15h500q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM500 950q0 -20 14.5 -35t35.5 -15h100q20 0 35 15t15 35v100 q0 21 -15 35.5t-35 14.5h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-100z" />
<glyph unicode="&#xe058;" d="M1 50q0 -20 14.5 -35t35.5 -15h600q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-600q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM1 350q0 -20 14.5 -35t35.5 -15h300q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-300q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM1 650 q0 -20 14.5 -35t35.5 -15h500q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM1 950q0 -20 14.5 -35t35.5 -15h100q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM801 0v1100h100v-1100 h-100zM934 550l167 -125v75h200v100h-200v75z" />
<glyph unicode="&#xe059;" d="M0 275v650q0 31 22 53t53 22h750q31 0 53 -22t22 -53v-650q0 -31 -22 -53t-53 -22h-750q-31 0 -53 22t-22 53zM900 600l300 300v-600z" />
<glyph unicode="&#xe060;" d="M0 44v1012q0 18 13 31t31 13h1112q19 0 31.5 -13t12.5 -31v-1012q0 -18 -12.5 -31t-31.5 -13h-1112q-18 0 -31 13t-13 31zM100 263l247 182l298 -131l-74 156l293 318l236 -288v500h-1000v-737zM208 750q0 56 39 95t95 39t95 -39t39 -95t-39 -95t-95 -39t-95 39t-39 95z " />
<glyph unicode="&#xe062;" d="M148 745q0 124 60.5 231.5t165 172t226.5 64.5q123 0 227 -63t164.5 -169.5t60.5 -229.5t-73 -272q-73 -114 -166.5 -237t-150.5 -189l-57 -66q-10 9 -27 26t-66.5 70.5t-96 109t-104 135.5t-100.5 155q-63 139 -63 262zM342 772q0 -107 75.5 -182.5t181.5 -75.5 q107 0 182.5 75.5t75.5 182.5t-75.5 182t-182.5 75t-182 -75.5t-75 -181.5z" />
<glyph unicode="&#xe063;" d="M1 600q0 122 47.5 233t127.5 191t191 127.5t233 47.5t233 -47.5t191 -127.5t127.5 -191t47.5 -233t-47.5 -233t-127.5 -191t-191 -127.5t-233 -47.5t-233 47.5t-191 127.5t-127.5 191t-47.5 233zM173 600q0 -177 125.5 -302t301.5 -125v854q-176 0 -301.5 -125 t-125.5 -302z" />
<glyph unicode="&#xe064;" d="M117 406q0 94 34 186t88.5 172.5t112 159t115 177t87.5 194.5q21 -71 57.5 -142.5t76 -130.5t83 -118.5t82 -117t70 -116t50 -125.5t18.5 -136q0 -89 -39 -165.5t-102 -126.5t-140 -79.5t-156 -33.5q-114 6 -211.5 53t-161.5 139t-64 210zM243 414q14 -82 59.5 -136 t136.5 -80l16 98q-7 6 -18 17t-34 48t-33 77q-15 73 -14 143.5t10 122.5l9 51q-92 -110 -119.5 -185t-12.5 -156z" />
<glyph unicode="&#xe065;" d="M0 400v300q0 165 117.5 282.5t282.5 117.5q366 -6 397 -14l-186 -186h-311q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v125l200 200v-225q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5 t-117.5 282.5zM436 341l161 50l412 412l-114 113l-405 -405zM995 1015l113 -113l113 113l-21 85l-92 28z" />
<glyph unicode="&#xe066;" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h261l2 -80q-133 -32 -218 -120h-145q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5l200 153v-53q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5t-117.5 282.5 zM423 524q30 38 81.5 64t103 35.5t99 14t77.5 3.5l29 -1v-209l360 324l-359 318v-216q-7 0 -19 -1t-48 -8t-69.5 -18.5t-76.5 -37t-76.5 -59t-62 -88t-39.5 -121.5z" />
<glyph unicode="&#xe067;" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h300q61 0 127 -23l-178 -177h-349q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v69l200 200v-169q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5 t-117.5 282.5zM342 632l283 -284l567 567l-137 137l-430 -431l-146 147z" />
<glyph unicode="&#xe068;" d="M0 603l300 296v-198h200v200h-200l300 300l295 -300h-195v-200h200v198l300 -296l-300 -300v198h-200v-200h195l-295 -300l-300 300h200v200h-200v-198z" />
<glyph unicode="&#xe069;" d="M200 50v1000q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-437l500 487v-1100l-500 488v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5z" />
<glyph unicode="&#xe070;" d="M0 50v1000q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-437l500 487v-487l500 487v-1100l-500 488v-488l-500 488v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5z" />
<glyph unicode="&#xe071;" d="M136 550l564 550v-487l500 487v-1100l-500 488v-488z" />
<glyph unicode="&#xe072;" d="M200 0l900 550l-900 550v-1100z" />
<glyph unicode="&#xe073;" d="M200 150q0 -21 14.5 -35.5t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v800q0 21 -14.5 35.5t-35.5 14.5h-200q-21 0 -35.5 -14.5t-14.5 -35.5v-800zM600 150q0 -21 14.5 -35.5t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v800q0 21 -14.5 35.5t-35.5 14.5h-200 q-21 0 -35.5 -14.5t-14.5 -35.5v-800z" />
<glyph unicode="&#xe074;" d="M200 150q0 -20 14.5 -35t35.5 -15h800q21 0 35.5 15t14.5 35v800q0 21 -14.5 35.5t-35.5 14.5h-800q-21 0 -35.5 -14.5t-14.5 -35.5v-800z" />
<glyph unicode="&#xe075;" d="M0 0v1100l500 -487v487l564 -550l-564 -550v488z" />
<glyph unicode="&#xe076;" d="M0 0v1100l500 -487v487l500 -487v437q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-1000q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v438l-500 -488v488z" />
<glyph unicode="&#xe077;" d="M300 0v1100l500 -487v437q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-1000q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v438z" />
<glyph unicode="&#xe078;" d="M100 250v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5zM100 500h1100l-550 564z" />
<glyph unicode="&#xe079;" d="M185 599l592 -592l240 240l-353 353l353 353l-240 240z" />
<glyph unicode="&#xe080;" d="M272 194l353 353l-353 353l241 240l572 -571l21 -22l-1 -1v-1l-592 -591z" />
<glyph unicode="&#xe081;" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM300 500h200v-200h200v200h200v200h-200v200h-200v-200h-200v-200z" />
<glyph unicode="&#xe082;" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM300 500h600v200h-600v-200z" />
<glyph unicode="&#xe083;" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM246 459l213 -213l141 142l141 -142l213 213l-142 141l142 141l-213 212l-141 -141l-141 142l-212 -213l141 -141 z" />
<glyph unicode="&#xe084;" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM270 551l276 -277l411 411l-175 174l-236 -236l-102 102z" />
<glyph unicode="&#xe085;" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM364 700h143q4 0 11.5 -1t11 -1t6.5 3t3 9t1 11t3.5 8.5t3.5 6t5.5 4t6.5 2.5t9 1.5t9 0.5h11.5h12.5 q19 0 30 -10t11 -26q0 -22 -4 -28t-27 -22q-5 -1 -12.5 -3t-27 -13.5t-34 -27t-26.5 -46t-11 -68.5h200q5 3 14 8t31.5 25.5t39.5 45.5t31 69t14 94q0 51 -17.5 89t-42 58t-58.5 32t-58.5 15t-51.5 3q-50 0 -90.5 -12t-75 -38.5t-53.5 -74.5t-19 -114zM500 300h200v100h-200 v-100z" />
<glyph unicode="&#xe086;" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM400 300h400v100h-100v300h-300v-100h100v-200h-100v-100zM500 800h200v100h-200v-100z" />
<glyph unicode="&#xe087;" d="M0 500v200h195q31 125 98.5 199.5t206.5 100.5v200h200v-200q54 -20 113 -60t112.5 -105.5t71.5 -134.5h203v-200h-203q-25 -102 -116.5 -186t-180.5 -117v-197h-200v197q-140 27 -208 102.5t-98 200.5h-194zM290 500q24 -73 79.5 -127.5t130.5 -78.5v206h200v-206 q149 48 201 206h-201v200h200q-25 74 -75.5 127t-124.5 77v-204h-200v203q-75 -23 -130 -77t-79 -126h209v-200h-210z" />
<glyph unicode="&#xe088;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM356 465l135 135 l-135 135l109 109l135 -135l135 135l109 -109l-135 -135l135 -135l-109 -109l-135 135l-135 -135z" />
<glyph unicode="&#xe089;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM322 537l141 141 l87 -87l204 205l142 -142l-346 -345z" />
<glyph unicode="&#xe090;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -115 62 -215l568 567q-100 62 -216 62q-171 0 -292.5 -121.5t-121.5 -292.5zM391 245q97 -59 209 -59q171 0 292.5 121.5t121.5 292.5 q0 112 -59 209z" />
<glyph unicode="&#xe091;" d="M0 547l600 453v-300h600v-300h-600v-301z" />
<glyph unicode="&#xe092;" d="M0 400v300h600v300l600 -453l-600 -448v301h-600z" />
<glyph unicode="&#xe093;" d="M204 600l450 600l444 -600h-298v-600h-300v600h-296z" />
<glyph unicode="&#xe094;" d="M104 600h296v600h300v-600h298l-449 -600z" />
<glyph unicode="&#xe095;" d="M0 200q6 132 41 238.5t103.5 193t184 138t271.5 59.5v271l600 -453l-600 -448v301q-95 -2 -183 -20t-170 -52t-147 -92.5t-100 -135.5z" />
<glyph unicode="&#xe096;" d="M0 0v400l129 -129l294 294l142 -142l-294 -294l129 -129h-400zM635 777l142 -142l294 294l129 -129v400h-400l129 -129z" />
<glyph unicode="&#xe097;" d="M34 176l295 295l-129 129h400v-400l-129 130l-295 -295zM600 600v400l129 -129l295 295l142 -141l-295 -295l129 -130h-400z" />
<glyph unicode="&#xe101;" d="M23 600q0 118 45.5 224.5t123 184t184 123t224.5 45.5t224.5 -45.5t184 -123t123 -184t45.5 -224.5t-45.5 -224.5t-123 -184t-184 -123t-224.5 -45.5t-224.5 45.5t-184 123t-123 184t-45.5 224.5zM456 851l58 -302q4 -20 21.5 -34.5t37.5 -14.5h54q20 0 37.5 14.5 t21.5 34.5l58 302q4 20 -8 34.5t-32 14.5h-207q-21 0 -33 -14.5t-8 -34.5zM500 300h200v100h-200v-100z" />
<glyph unicode="&#xe102;" d="M0 800h100v-200h400v300h200v-300h400v200h100v100h-111q1 1 1 6.5t-1.5 15t-3.5 17.5l-34 172q-11 39 -41.5 63t-69.5 24q-32 0 -61 -17l-239 -144q-22 -13 -40 -35q-19 24 -40 36l-238 144q-33 18 -62 18q-39 0 -69.5 -23t-40.5 -61l-35 -177q-2 -8 -3 -18t-1 -15v-6 h-111v-100zM100 0h400v400h-400v-400zM200 900q-3 0 14 48t36 96l18 47l213 -191h-281zM700 0v400h400v-400h-400zM731 900l202 197q5 -12 12 -32.5t23 -64t25 -72t7 -28.5h-269z" />
<glyph unicode="&#xe103;" d="M0 -22v143l216 193q-9 53 -13 83t-5.5 94t9 113t38.5 114t74 124q47 60 99.5 102.5t103 68t127.5 48t145.5 37.5t184.5 43.5t220 58.5q0 -189 -22 -343t-59 -258t-89 -181.5t-108.5 -120t-122 -68t-125.5 -30t-121.5 -1.5t-107.5 12.5t-87.5 17t-56.5 7.5l-99 -55z M238.5 300.5q19.5 -6.5 86.5 76.5q55 66 367 234q70 38 118.5 69.5t102 79t99 111.5t86.5 148q22 50 24 60t-6 19q-7 5 -17 5t-26.5 -14.5t-33.5 -39.5q-35 -51 -113.5 -108.5t-139.5 -89.5l-61 -32q-369 -197 -458 -401q-48 -111 -28.5 -117.5z" />
<glyph unicode="&#xe104;" d="M111 408q0 -33 5 -63q9 -56 44 -119.5t105 -108.5q31 -21 64 -16t62 23.5t57 49.5t48 61.5t35 60.5q32 66 39 184.5t-13 157.5q79 -80 122 -164t26 -184q-5 -33 -20.5 -69.5t-37.5 -80.5q-10 -19 -14.5 -29t-12 -26t-9 -23.5t-3 -19t2.5 -15.5t11 -9.5t19.5 -5t30.5 2.5 t42 8q57 20 91 34t87.5 44.5t87 64t65.5 88.5t47 122q38 172 -44.5 341.5t-246.5 278.5q22 -44 43 -129q39 -159 -32 -154q-15 2 -33 9q-79 33 -120.5 100t-44 175.5t48.5 257.5q-13 -8 -34 -23.5t-72.5 -66.5t-88.5 -105.5t-60 -138t-8 -166.5q2 -12 8 -41.5t8 -43t6 -39.5 t3.5 -39.5t-1 -33.5t-6 -31.5t-13.5 -24t-21 -20.5t-31 -12q-38 -10 -67 13t-40.5 61.5t-15 81.5t10.5 75q-52 -46 -83.5 -101t-39 -107t-7.5 -85z" />
<glyph unicode="&#xe105;" d="M-61 600l26 40q6 10 20 30t49 63.5t74.5 85.5t97 90t116.5 83.5t132.5 59t145.5 23.5t145.5 -23.5t132.5 -59t116.5 -83.5t97 -90t74.5 -85.5t49 -63.5t20 -30l26 -40l-26 -40q-6 -10 -20 -30t-49 -63.5t-74.5 -85.5t-97 -90t-116.5 -83.5t-132.5 -59t-145.5 -23.5 t-145.5 23.5t-132.5 59t-116.5 83.5t-97 90t-74.5 85.5t-49 63.5t-20 30zM120 600q7 -10 40.5 -58t56 -78.5t68 -77.5t87.5 -75t103 -49.5t125 -21.5t123.5 20t100.5 45.5t85.5 71.5t66.5 75.5t58 81.5t47 66q-1 1 -28.5 37.5t-42 55t-43.5 53t-57.5 63.5t-58.5 54 q49 -74 49 -163q0 -124 -88 -212t-212 -88t-212 88t-88 212q0 85 46 158q-102 -87 -226 -258zM377 656q49 -124 154 -191l105 105q-37 24 -75 72t-57 84l-20 36z" />
<glyph unicode="&#xe106;" d="M-61 600l26 40q6 10 20 30t49 63.5t74.5 85.5t97 90t116.5 83.5t132.5 59t145.5 23.5q61 0 121 -17l37 142h148l-314 -1200h-148l37 143q-82 21 -165 71.5t-140 102t-109.5 112t-72 88.5t-29.5 43zM120 600q210 -282 393 -336l37 141q-107 18 -178.5 101.5t-71.5 193.5 q0 85 46 158q-102 -87 -226 -258zM377 656q49 -124 154 -191l47 47l23 87q-30 28 -59 69t-44 68l-14 26zM780 161l38 145q22 15 44.5 34t46 44t40.5 44t41 50.5t33.5 43.5t33 44t24.5 34q-97 127 -140 175l39 146q67 -54 131.5 -125.5t87.5 -103.5t36 -52l26 -40l-26 -40 q-7 -12 -25.5 -38t-63.5 -79.5t-95.5 -102.5t-124 -100t-146.5 -79z" />
<glyph unicode="&#xe107;" d="M-97.5 34q13.5 -34 50.5 -34h1294q37 0 50.5 35.5t-7.5 67.5l-642 1056q-20 34 -48 36.5t-48 -29.5l-642 -1066q-21 -32 -7.5 -66zM155 200l445 723l445 -723h-345v100h-200v-100h-345zM500 600l100 -300l100 300v100h-200v-100z" />
<glyph unicode="&#xe108;" d="M100 262v41q0 20 11 44.5t26 38.5l363 325v339q0 62 44 106t106 44t106 -44t44 -106v-339l363 -325q15 -14 26 -38.5t11 -44.5v-41q0 -20 -12 -26.5t-29 5.5l-359 249v-263q100 -91 100 -113v-64q0 -20 -13 -28.5t-32 0.5l-94 78h-222l-94 -78q-19 -9 -32 -0.5t-13 28.5 v64q0 22 100 113v263l-359 -249q-17 -12 -29 -5.5t-12 26.5z" />
<glyph unicode="&#xe109;" d="M0 50q0 -20 14.5 -35t35.5 -15h1000q21 0 35.5 15t14.5 35v750h-1100v-750zM0 900h1100v150q0 21 -14.5 35.5t-35.5 14.5h-150v100h-100v-100h-500v100h-100v-100h-150q-21 0 -35.5 -14.5t-14.5 -35.5v-150zM100 100v100h100v-100h-100zM100 300v100h100v-100h-100z M100 500v100h100v-100h-100zM300 100v100h100v-100h-100zM300 300v100h100v-100h-100zM300 500v100h100v-100h-100zM500 100v100h100v-100h-100zM500 300v100h100v-100h-100zM500 500v100h100v-100h-100zM700 100v100h100v-100h-100zM700 300v100h100v-100h-100zM700 500 v100h100v-100h-100zM900 100v100h100v-100h-100zM900 300v100h100v-100h-100zM900 500v100h100v-100h-100z" />
<glyph unicode="&#xe110;" d="M0 200v200h259l600 600h241v198l300 -295l-300 -300v197h-159l-600 -600h-341zM0 800h259l122 -122l141 142l-181 180h-341v-200zM678 381l141 142l122 -123h159v198l300 -295l-300 -300v197h-241z" />
<glyph unicode="&#xe111;" d="M0 400v600q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-596l-304 -300v300h-100q-41 0 -70.5 29.5t-29.5 70.5z" />
<glyph unicode="&#xe112;" d="M100 600v200h300v-250q0 -113 6 -145q17 -92 102 -117q39 -11 92 -11q37 0 66.5 5.5t50 15.5t36 24t24 31.5t14 37.5t7 42t2.5 45t0 47v25v250h300v-200q0 -42 -3 -83t-15 -104t-31.5 -116t-58 -109.5t-89 -96.5t-129 -65.5t-174.5 -25.5t-174.5 25.5t-129 65.5t-89 96.5 t-58 109.5t-31.5 116t-15 104t-3 83zM100 900v300h300v-300h-300zM800 900v300h300v-300h-300z" />
<glyph unicode="&#xe113;" d="M-30 411l227 -227l352 353l353 -353l226 227l-578 579z" />
<glyph unicode="&#xe114;" d="M70 797l580 -579l578 579l-226 227l-353 -353l-352 353z" />
<glyph unicode="&#xe115;" d="M-198 700l299 283l300 -283h-203v-400h385l215 -200h-800v600h-196zM402 1000l215 -200h381v-400h-198l299 -283l299 283h-200v600h-796z" />
<glyph unicode="&#xe116;" d="M18 939q-5 24 10 42q14 19 39 19h896l38 162q5 17 18.5 27.5t30.5 10.5h94q20 0 35 -14.5t15 -35.5t-15 -35.5t-35 -14.5h-54l-201 -961q-2 -4 -6 -10.5t-19 -17.5t-33 -11h-31v-50q0 -20 -14.5 -35t-35.5 -15t-35.5 15t-14.5 35v50h-300v-50q0 -20 -14.5 -35t-35.5 -15 t-35.5 15t-14.5 35v50h-50q-21 0 -35.5 15t-14.5 35q0 21 14.5 35.5t35.5 14.5h535l48 200h-633q-32 0 -54.5 21t-27.5 43z" />
<glyph unicode="&#xe117;" d="M0 0v800h1200v-800h-1200zM0 900v100h200q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5h500v-100h-1200z" />
<glyph unicode="&#xe118;" d="M1 0l300 700h1200l-300 -700h-1200zM1 400v600h200q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5h500v-200h-1000z" />
<glyph unicode="&#xe119;" d="M302 300h198v600h-198l298 300l298 -300h-198v-600h198l-298 -300z" />
<glyph unicode="&#xe120;" d="M0 600l300 298v-198h600v198l300 -298l-300 -297v197h-600v-197z" />
<glyph unicode="&#xe121;" d="M0 100v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM31 400l172 739q5 22 23 41.5t38 19.5h672q19 0 37.5 -22.5t23.5 -45.5l172 -732h-1138zM800 100h100v100h-100v-100z M1000 100h100v100h-100v-100z" />
<glyph unicode="&#xe122;" d="M-101 600v50q0 24 25 49t50 38l25 13v-250l-11 5.5t-24 14t-30 21.5t-24 27.5t-11 31.5zM100 500v250v8v8v7t0.5 7t1.5 5.5t2 5t3 4t4.5 3.5t6 1.5t7.5 0.5h200l675 250v-850l-675 200h-38l47 -276q2 -12 -3 -17.5t-11 -6t-21 -0.5h-8h-83q-20 0 -34.5 14t-18.5 35 q-55 337 -55 351zM1100 200v850q0 21 14.5 35.5t35.5 14.5q20 0 35 -14.5t15 -35.5v-850q0 -20 -15 -35t-35 -15q-21 0 -35.5 15t-14.5 35z" />
<glyph unicode="&#xe123;" d="M74 350q0 21 13.5 35.5t33.5 14.5h18l117 173l63 327q15 77 76 140t144 83l-18 32q-6 19 3 32t29 13h94q20 0 29 -10.5t3 -29.5q-18 -36 -18 -37q83 -19 144 -82.5t76 -140.5l63 -327l118 -173h17q20 0 33.5 -14.5t13.5 -35.5q0 -20 -13 -40t-31 -27q-8 -3 -23 -8.5 t-65 -20t-103 -25t-132.5 -19.5t-158.5 -9q-125 0 -245.5 20.5t-178.5 40.5l-58 20q-18 7 -31 27.5t-13 40.5zM497 110q12 -49 40 -79.5t63 -30.5t63 30.5t39 79.5q-48 -6 -102 -6t-103 6z" />
<glyph unicode="&#xe124;" d="M21 445l233 -45l-78 -224l224 78l45 -233l155 179l155 -179l45 233l224 -78l-78 224l234 45l-180 155l180 156l-234 44l78 225l-224 -78l-45 233l-155 -180l-155 180l-45 -233l-224 78l78 -225l-233 -44l179 -156z" />
<glyph unicode="&#xe125;" d="M0 200h200v600h-200v-600zM300 275q0 -75 100 -75h61q124 -100 139 -100h250q46 0 83 57l238 344q29 31 29 74v100q0 44 -30.5 84.5t-69.5 40.5h-328q28 118 28 125v150q0 44 -30.5 84.5t-69.5 40.5h-50q-27 0 -51 -20t-38 -48l-96 -198l-145 -196q-20 -26 -20 -63v-400z M400 300v375l150 213l100 212h50v-175l-50 -225h450v-125l-250 -375h-214l-136 100h-100z" />
<glyph unicode="&#xe126;" d="M0 400v600h200v-600h-200zM300 525v400q0 75 100 75h61q124 100 139 100h250q46 0 83 -57l238 -344q29 -31 29 -74v-100q0 -44 -30.5 -84.5t-69.5 -40.5h-328q28 -118 28 -125v-150q0 -44 -30.5 -84.5t-69.5 -40.5h-50q-27 0 -51 20t-38 48l-96 198l-145 196 q-20 26 -20 63zM400 525l150 -212l100 -213h50v175l-50 225h450v125l-250 375h-214l-136 -100h-100v-375z" />
<glyph unicode="&#xe127;" d="M8 200v600h200v-600h-200zM308 275v525q0 17 14 35.5t28 28.5l14 9l362 230q14 6 25 6q17 0 29 -12l109 -112q14 -14 14 -34q0 -18 -11 -32l-85 -121h302q85 0 138.5 -38t53.5 -110t-54.5 -111t-138.5 -39h-107l-130 -339q-7 -22 -20.5 -41.5t-28.5 -19.5h-341 q-7 0 -90 81t-83 94zM408 289l100 -89h293l131 339q6 21 19.5 41t28.5 20h203q16 0 25 15t9 36q0 20 -9 34.5t-25 14.5h-457h-6.5h-7.5t-6.5 0.5t-6 1t-5 1.5t-5.5 2.5t-4 4t-4 5.5q-5 12 -5 20q0 14 10 27l147 183l-86 83l-339 -236v-503z" />
<glyph unicode="&#xe128;" d="M-101 651q0 72 54 110t139 38l302 -1l-85 121q-11 16 -11 32q0 21 14 34l109 113q13 12 29 12q11 0 25 -6l365 -230q7 -4 17 -10.5t26.5 -26t16.5 -36.5v-526q0 -13 -86 -93.5t-94 -80.5h-341q-16 0 -29.5 20t-19.5 41l-130 339h-107q-84 0 -139 39t-55 111zM-1 601h222 q15 0 28.5 -20.5t19.5 -40.5l131 -339h293l107 89v502l-343 237l-87 -83l145 -184q10 -11 10 -26q0 -11 -5 -20q-1 -3 -3.5 -5.5l-4 -4t-5 -2.5t-5.5 -1.5t-6.5 -1t-6.5 -0.5h-7.5h-6.5h-476v-100zM1000 201v600h200v-600h-200z" />
<glyph unicode="&#xe129;" d="M97 719l230 -363q4 -6 10.5 -15.5t26 -25t36.5 -15.5h525q13 0 94 83t81 90v342q0 15 -20 28.5t-41 19.5l-339 131v106q0 84 -39 139t-111 55t-110 -53.5t-38 -138.5v-302l-121 84q-15 12 -33.5 11.5t-32.5 -13.5l-112 -110q-22 -22 -6 -53zM172 739l83 86l183 -146 q22 -18 47 -5q3 1 5.5 3.5l4 4t2.5 5t1.5 5.5t1 6.5t0.5 6.5v7.5v6.5v456q0 22 25 31t50 -0.5t25 -30.5v-202q0 -16 20 -29.5t41 -19.5l339 -130v-294l-89 -100h-503zM400 0v200h600v-200h-600z" />
<glyph unicode="&#xe130;" d="M2 585q-16 -31 6 -53l112 -110q13 -13 32 -13.5t34 10.5l121 85q0 -51 -0.5 -153.5t-0.5 -148.5q0 -84 38.5 -138t110.5 -54t111 55t39 139v106l339 131q20 6 40.5 19.5t20.5 28.5v342q0 7 -81 90t-94 83h-525q-17 0 -35.5 -14t-28.5 -28l-10 -15zM77 565l236 339h503 l89 -100v-294l-340 -130q-20 -6 -40 -20t-20 -29v-202q0 -22 -25 -31t-50 0t-25 31v456v14.5t-1.5 11.5t-5 12t-9.5 7q-24 13 -46 -5l-184 -146zM305 1104v200h600v-200h-600z" />
<glyph unicode="&#xe131;" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q162 0 299.5 -80t217.5 -218t80 -300t-80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM298 701l2 -201h300l-2 -194l402 294l-402 298v-197h-300z" />
<glyph unicode="&#xe132;" d="M0 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t231.5 47.5q122 0 232.5 -47.5t190.5 -127.5t127.5 -190.5t47.5 -232.5q0 -162 -80 -299.5t-218 -217.5t-300 -80t-299.5 80t-217.5 217.5t-80 299.5zM200 600l402 -294l-2 194h300l2 201h-300v197z" />
<glyph unicode="&#xe133;" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q162 0 299.5 -80t217.5 -218t80 -300t-80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM300 600h200v-300h200v300h200l-300 400z" />
<glyph unicode="&#xe134;" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q162 0 299.5 -80t217.5 -218t80 -300t-80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM300 600l300 -400l300 400h-200v300h-200v-300h-200z" />
<glyph unicode="&#xe135;" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q121 0 231.5 -47.5t190.5 -127.5t127.5 -190.5t47.5 -232.5q0 -162 -80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM254 780q-8 -33 5.5 -92.5t7.5 -87.5q0 -9 17 -44t16 -60 q12 0 23 -5.5t23 -15t20 -13.5q24 -12 108 -42q22 -8 53 -31.5t59.5 -38.5t57.5 -11q8 -18 -15 -55t-20 -57q42 -71 87 -80q0 -6 -3 -15.5t-3.5 -14.5t4.5 -17q104 -3 221 112q30 29 47 47t34.5 49t20.5 62q-14 9 -37 9.5t-36 7.5q-14 7 -49 15t-52 19q-9 0 -39.5 -0.5 t-46.5 -1.5t-39 -6.5t-39 -16.5q-50 -35 -66 -12q-4 2 -3.5 25.5t0.5 25.5q-6 13 -26.5 17t-24.5 7q2 22 -2 41t-16.5 28t-38.5 -20q-23 -25 -42 4q-19 28 -8 58q6 16 22 22q6 -1 26 -1.5t33.5 -4t19.5 -13.5q12 -19 32 -37.5t34 -27.5l14 -8q0 3 9.5 39.5t5.5 57.5 q-4 23 14.5 44.5t22.5 31.5q5 14 10 35t8.5 31t15.5 22.5t34 21.5q-6 18 10 37q8 0 23.5 -1.5t24.5 -1.5t20.5 4.5t20.5 15.5q-10 23 -30.5 42.5t-38 30t-49 26.5t-43.5 23q11 39 2 44q31 -13 58 -14.5t39 3.5l11 4q7 36 -16.5 53.5t-64.5 28.5t-56 23q-19 -3 -37 0 q-15 -12 -36.5 -21t-34.5 -12t-44 -8t-39 -6q-15 -3 -45.5 0.5t-45.5 -2.5q-21 -7 -52 -26.5t-34 -34.5q-3 -11 6.5 -22.5t8.5 -18.5q-3 -34 -27.5 -90.5t-29.5 -79.5zM518 916q3 12 16 30t16 25q10 -10 18.5 -10t14 6t14.5 14.5t16 12.5q0 -24 17 -66.5t17 -43.5 q-9 2 -31 5t-36 5t-32 8t-30 14zM692 1003h1h-1z" />
<glyph unicode="&#xe136;" d="M0 164.5q0 21.5 15 37.5l600 599q-33 101 6 201.5t135 154.5q164 92 306 -9l-259 -138l145 -232l251 126q13 -175 -151 -267q-123 -70 -253 -23l-596 -596q-15 -16 -36.5 -16t-36.5 16l-111 110q-15 15 -15 36.5z" />
<glyph unicode="&#xe137;" horiz-adv-x="1220" d="M0 196v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM0 596v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000 q-41 0 -70.5 29.5t-29.5 70.5zM0 996v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM600 596h500v100h-500v-100zM800 196h300v100h-300v-100zM900 996h200v100h-200v-100z" />
<glyph unicode="&#xe138;" d="M100 1100v100h1000v-100h-1000zM150 1000h900l-350 -500v-300l-200 -200v500z" />
<glyph unicode="&#xe139;" d="M0 200v200h1200v-200q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM0 500v400q0 41 29.5 70.5t70.5 29.5h300v100q0 41 29.5 70.5t70.5 29.5h200q41 0 70.5 -29.5t29.5 -70.5v-100h300q41 0 70.5 -29.5t29.5 -70.5v-400h-500v100h-200v-100h-500z M500 1000h200v100h-200v-100z" />
<glyph unicode="&#xe140;" d="M0 0v400l129 -129l200 200l142 -142l-200 -200l129 -129h-400zM0 800l129 129l200 -200l142 142l-200 200l129 129h-400v-400zM729 329l142 142l200 -200l129 129v-400h-400l129 129zM729 871l200 200l-129 129h400v-400l-129 129l-200 -200z" />
<glyph unicode="&#xe141;" d="M0 596q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM182 596q0 -172 121.5 -293t292.5 -121t292.5 121t121.5 293q0 171 -121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM291 655 q0 23 15.5 38.5t38.5 15.5t39 -16t16 -38q0 -23 -16 -39t-39 -16q-22 0 -38 16t-16 39zM400 850q0 22 16 38.5t39 16.5q22 0 38 -16t16 -39t-16 -39t-38 -16q-23 0 -39 16.5t-16 38.5zM514 609q0 32 20.5 56.5t51.5 29.5l122 126l1 1q-9 14 -9 28q0 22 16 38.5t39 16.5 q22 0 38 -16t16 -39t-16 -39t-38 -16q-14 0 -29 10l-55 -145q17 -22 17 -51q0 -36 -25.5 -61.5t-61.5 -25.5t-61.5 25.5t-25.5 61.5zM800 655q0 22 16 38t39 16t38.5 -15.5t15.5 -38.5t-16 -39t-38 -16q-23 0 -39 16t-16 39z" />
<glyph unicode="&#xe142;" d="M-40 375q-13 -95 35 -173q35 -57 94 -89t129 -32q63 0 119 28q33 16 65 40.5t52.5 45.5t59.5 64q40 44 57 61l394 394q35 35 47 84t-3 96q-27 87 -117 104q-20 2 -29 2q-46 0 -78.5 -16.5t-67.5 -51.5l-389 -396l-7 -7l69 -67l377 373q20 22 39 38q23 23 50 23 q38 0 53 -36q16 -39 -20 -75l-547 -547q-52 -52 -125 -52q-55 0 -100 33t-54 96q-5 35 2.5 66t31.5 63t42 50t56 54q24 21 44 41l348 348q52 52 82.5 79.5t84 54t107.5 26.5q25 0 48 -4q95 -17 154 -94.5t51 -175.5q-7 -101 -98 -192l-252 -249l-253 -256l7 -7l69 -60 l517 511q67 67 95 157t11 183q-16 87 -67 154t-130 103q-69 33 -152 33q-107 0 -197 -55q-40 -24 -111 -95l-512 -512q-68 -68 -81 -163z" />
<glyph unicode="&#xe143;" d="M80 784q0 131 98.5 229.5t230.5 98.5q143 0 241 -129q103 129 246 129q129 0 226 -98.5t97 -229.5q0 -46 -17.5 -91t-61 -99t-77 -89.5t-104.5 -105.5q-197 -191 -293 -322l-17 -23l-16 23q-43 58 -100 122.5t-92 99.5t-101 100q-71 70 -104.5 105.5t-77 89.5t-61 99 t-17.5 91zM250 784q0 -27 30.5 -70t61.5 -75.5t95 -94.5l22 -22q93 -90 190 -201q82 92 195 203l12 12q64 62 97.5 97t64.5 79t31 72q0 71 -48 119.5t-105 48.5q-74 0 -132 -83l-118 -171l-114 174q-51 80 -123 80q-60 0 -109.5 -49.5t-49.5 -118.5z" />
<glyph unicode="&#xe144;" d="M57 353q0 -95 66 -159l141 -142q68 -66 159 -66q93 0 159 66l283 283q66 66 66 159t-66 159l-141 141q-8 9 -19 17l-105 -105l212 -212l-389 -389l-247 248l95 95l-18 18q-46 45 -75 101l-55 -55q-66 -66 -66 -159zM269 706q0 -93 66 -159l141 -141q7 -7 19 -17l105 105 l-212 212l389 389l247 -247l-95 -96l18 -17q47 -49 77 -100l29 29q35 35 62.5 88t27.5 96q0 93 -66 159l-141 141q-66 66 -159 66q-95 0 -159 -66l-283 -283q-66 -64 -66 -159z" />
<glyph unicode="&#xe145;" d="M200 100v953q0 21 30 46t81 48t129 38t163 15t162 -15t127 -38t79 -48t29 -46v-953q0 -41 -29.5 -70.5t-70.5 -29.5h-600q-41 0 -70.5 29.5t-29.5 70.5zM300 300h600v700h-600v-700zM496 150q0 -43 30.5 -73.5t73.5 -30.5t73.5 30.5t30.5 73.5t-30.5 73.5t-73.5 30.5 t-73.5 -30.5t-30.5 -73.5z" />
<glyph unicode="&#xe146;" d="M0 0l303 380l207 208l-210 212h300l267 279l-35 36q-15 14 -15 35t15 35q14 15 35 15t35 -15l283 -282q15 -15 15 -36t-15 -35q-14 -15 -35 -15t-35 15l-36 35l-279 -267v-300l-212 210l-208 -207z" />
<glyph unicode="&#xe148;" d="M295 433h139q5 -77 48.5 -126.5t117.5 -64.5v335q-6 1 -15.5 4t-11.5 3q-46 14 -79 26.5t-72 36t-62.5 52t-40 72.5t-16.5 99q0 92 44 159.5t109 101t144 40.5v78h100v-79q38 -4 72.5 -13.5t75.5 -31.5t71 -53.5t51.5 -84t24.5 -118.5h-159q-8 72 -35 109.5t-101 50.5 v-307l64 -14q34 -7 64 -16.5t70 -31.5t67.5 -52t47.5 -80.5t20 -112.5q0 -139 -89 -224t-244 -96v-77h-100v78q-152 17 -237 104q-40 40 -52.5 93.5t-15.5 139.5zM466 889q0 -29 8 -51t16.5 -34t29.5 -22.5t31 -13.5t38 -10q7 -2 11 -3v274q-61 -8 -97.5 -37.5t-36.5 -102.5 zM700 237q170 18 170 151q0 64 -44 99.5t-126 60.5v-311z" />
<glyph unicode="&#xe149;" d="M100 600v100h166q-24 49 -44 104q-10 26 -14.5 55.5t-3 72.5t25 90t68.5 87q97 88 263 88q129 0 230 -89t101 -208h-153q0 52 -34 89.5t-74 51.5t-76 14q-37 0 -79 -14.5t-62 -35.5q-41 -44 -41 -101q0 -28 16.5 -69.5t28 -62.5t41.5 -72h241v-100h-197q8 -50 -2.5 -115 t-31.5 -94q-41 -59 -99 -113q35 11 84 18t70 7q33 1 103 -16t103 -17q76 0 136 30l50 -147q-41 -25 -80.5 -36.5t-59 -13t-61.5 -1.5q-23 0 -128 33t-155 29q-39 -4 -82 -17t-66 -25l-24 -11l-55 145l16.5 11t15.5 10t13.5 9.5t14.5 12t14.5 14t17.5 18.5q48 55 54 126.5 t-30 142.5h-221z" />
<glyph unicode="&#xe150;" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM602 900l298 300l298 -300h-198v-900h-200v900h-198z" />
<glyph unicode="&#xe151;" d="M2 300h198v900h200v-900h198l-298 -300zM700 0v200h100v-100h200v-100h-300zM700 400v100h300v-200h-99v-100h-100v100h99v100h-200zM700 700v500h300v-500h-100v100h-100v-100h-100zM801 900h100v200h-100v-200z" />
<glyph unicode="&#xe152;" d="M2 300h198v900h200v-900h198l-298 -300zM700 0v500h300v-500h-100v100h-100v-100h-100zM700 700v200h100v-100h200v-100h-300zM700 1100v100h300v-200h-99v-100h-100v100h99v100h-200zM801 200h100v200h-100v-200z" />
<glyph unicode="&#xe153;" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM800 100v400h300v-500h-100v100h-200zM800 1100v100h200v-500h-100v400h-100zM901 200h100v200h-100v-200z" />
<glyph unicode="&#xe154;" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM800 400v100h200v-500h-100v400h-100zM800 800v400h300v-500h-100v100h-200zM901 900h100v200h-100v-200z" />
<glyph unicode="&#xe155;" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM700 100v200h500v-200h-500zM700 400v200h400v-200h-400zM700 700v200h300v-200h-300zM700 1000v200h200v-200h-200z" />
<glyph unicode="&#xe156;" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM700 100v200h200v-200h-200zM700 400v200h300v-200h-300zM700 700v200h400v-200h-400zM700 1000v200h500v-200h-500z" />
<glyph unicode="&#xe157;" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h300q162 0 281 -118.5t119 -281.5v-300q0 -165 -118.5 -282.5t-281.5 -117.5h-300q-165 0 -282.5 117.5t-117.5 282.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500z" />
<glyph unicode="&#xe158;" d="M0 400v300q0 163 119 281.5t281 118.5h300q165 0 282.5 -117.5t117.5 -282.5v-300q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-163 0 -281.5 117.5t-118.5 282.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM400 300l333 250l-333 250v-500z" />
<glyph unicode="&#xe159;" d="M0 400v300q0 163 117.5 281.5t282.5 118.5h300q163 0 281.5 -119t118.5 -281v-300q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5t-117.5 282.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM300 700l250 -333l250 333h-500z" />
<glyph unicode="&#xe160;" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h300q165 0 282.5 -117.5t117.5 -282.5v-300q0 -162 -118.5 -281t-281.5 -119h-300q-165 0 -282.5 118.5t-117.5 281.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM300 400h500l-250 333z" />
<glyph unicode="&#xe161;" d="M0 400v300h300v200l400 -350l-400 -350v200h-300zM500 0v200h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5h-500v200h400q165 0 282.5 -117.5t117.5 -282.5v-300q0 -165 -117.5 -282.5t-282.5 -117.5h-400z" />
<glyph unicode="&#xe162;" d="M217 519q8 -19 31 -19h302q-155 -438 -160 -458q-5 -21 4 -32l9 -8h9q14 0 26 15q11 13 274.5 321.5t264.5 308.5q14 19 5 36q-8 17 -31 17l-301 -1q1 4 78 219.5t79 227.5q2 15 -5 27l-9 9h-9q-15 0 -25 -16q-4 -6 -98 -111.5t-228.5 -257t-209.5 -237.5q-16 -19 -6 -41 z" />
<glyph unicode="&#xe163;" d="M0 400q0 -165 117.5 -282.5t282.5 -117.5h300q47 0 100 15v185h-500q-41 0 -70.5 29.5t-29.5 70.5v500q0 41 29.5 70.5t70.5 29.5h500v185q-14 4 -114 7.5t-193 5.5l-93 2q-165 0 -282.5 -117.5t-117.5 -282.5v-300zM600 400v300h300v200l400 -350l-400 -350v200h-300z " />
<glyph unicode="&#xe164;" d="M0 400q0 -165 117.5 -282.5t282.5 -117.5h300q163 0 281.5 117.5t118.5 282.5v98l-78 73l-122 -123v-148q0 -41 -29.5 -70.5t-70.5 -29.5h-500q-41 0 -70.5 29.5t-29.5 70.5v500q0 41 29.5 70.5t70.5 29.5h156l118 122l-74 78h-100q-165 0 -282.5 -117.5t-117.5 -282.5 v-300zM496 709l353 342l-149 149h500v-500l-149 149l-342 -353z" />
<glyph unicode="&#xe165;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM406 600 q0 80 57 137t137 57t137 -57t57 -137t-57 -137t-137 -57t-137 57t-57 137z" />
<glyph unicode="&#xe166;" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 800l445 -500l450 500h-295v400h-300v-400h-300zM900 150h100v50h-100v-50z" />
<glyph unicode="&#xe167;" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 700h300v-300h300v300h295l-445 500zM900 150h100v50h-100v-50z" />
<glyph unicode="&#xe168;" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 705l305 -305l596 596l-154 155l-442 -442l-150 151zM900 150h100v50h-100v-50z" />
<glyph unicode="&#xe169;" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 988l97 -98l212 213l-97 97zM200 400l697 1l3 699l-250 -239l-149 149l-212 -212l149 -149zM900 150h100v50h-100v-50z" />
<glyph unicode="&#xe170;" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM200 612l212 -212l98 97l-213 212zM300 1200l239 -250l-149 -149l212 -212l149 148l249 -237l-1 697zM900 150h100v50h-100v-50z" />
<glyph unicode="&#xe171;" d="M23 415l1177 784v-1079l-475 272l-310 -393v416h-392zM494 210l672 938l-672 -712v-226z" />
<glyph unicode="&#xe172;" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-850q0 -21 -15 -35.5t-35 -14.5h-150v400h-700v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 1000h100v200h-100v-200z" />
<glyph unicode="&#xe173;" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-218l-276 -275l-120 120l-126 -127h-378v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM581 306l123 123l120 -120l353 352l123 -123l-475 -476zM600 1000h100v200h-100v-200z" />
<glyph unicode="&#xe174;" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-269l-103 -103l-170 170l-298 -298h-329v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 1000h100v200h-100v-200zM700 133l170 170l-170 170l127 127l170 -170l170 170l127 -128l-170 -169l170 -170 l-127 -127l-170 170l-170 -170z" />
<glyph unicode="&#xe175;" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-300h-400v-200h-500v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 300l300 -300l300 300h-200v300h-200v-300h-200zM600 1000v200h100v-200h-100z" />
<glyph unicode="&#xe176;" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-402l-200 200l-298 -298h-402v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 300h200v-300h200v300h200l-300 300zM600 1000v200h100v-200h-100z" />
<glyph unicode="&#xe177;" d="M0 250q0 -21 14.5 -35.5t35.5 -14.5h1100q21 0 35.5 14.5t14.5 35.5v550h-1200v-550zM0 900h1200v150q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5v-150zM100 300v200h400v-200h-400z" />
<glyph unicode="&#xe178;" d="M0 400l300 298v-198h400v-200h-400v-198zM100 800v200h100v-200h-100zM300 800v200h100v-200h-100zM500 800v200h400v198l300 -298l-300 -298v198h-400zM800 300v200h100v-200h-100zM1000 300h100v200h-100v-200z" />
<glyph unicode="&#xe179;" d="M100 700v400l50 100l50 -100v-300h100v300l50 100l50 -100v-300h100v300l50 100l50 -100v-400l-100 -203v-447q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v447zM800 597q0 -29 10.5 -55.5t25 -43t29 -28.5t25.5 -18l10 -5v-397q0 -21 14.5 -35.5 t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v1106q0 31 -18 40.5t-44 -7.5l-276 -116q-25 -17 -43.5 -51.5t-18.5 -65.5v-359z" />
<glyph unicode="&#xe180;" d="M100 0h400v56q-75 0 -87.5 6t-12.5 44v394h500v-394q0 -38 -12.5 -44t-87.5 -6v-56h400v56q-4 0 -11 0.5t-24 3t-30 7t-24 15t-11 24.5v888q0 22 25 34.5t50 13.5l25 2v56h-400v-56q75 0 87.5 -6t12.5 -44v-394h-500v394q0 38 12.5 44t87.5 6v56h-400v-56q4 0 11 -0.5 t24 -3t30 -7t24 -15t11 -24.5v-888q0 -22 -25 -34.5t-50 -13.5l-25 -2v-56z" />
<glyph unicode="&#xe181;" d="M0 300q0 -41 29.5 -70.5t70.5 -29.5h300q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5h-300q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM100 100h400l200 200h105l295 98v-298h-425l-100 -100h-375zM100 300v200h300v-200h-300zM100 600v200h300v-200h-300z M100 1000h400l200 -200v-98l295 98h105v200h-425l-100 100h-375zM700 402v163l400 133v-163z" />
<glyph unicode="&#xe182;" d="M16.5 974.5q0.5 -21.5 16 -90t46.5 -140t104 -177.5t175 -208q103 -103 207.5 -176t180 -103.5t137 -47t92.5 -16.5l31 1l163 162q17 18 13.5 41t-22.5 37l-192 136q-19 14 -45 12t-42 -19l-118 -118q-142 101 -268 227t-227 268l118 118q17 17 20 41.5t-11 44.5 l-139 194q-14 19 -36.5 22t-40.5 -14l-162 -162q-1 -11 -0.5 -32.5z" />
<glyph unicode="&#xe183;" d="M0 50v212q0 20 10.5 45.5t24.5 39.5l365 303v50q0 4 1 10.5t12 22.5t30 28.5t60 23t97 10.5t97 -10t60 -23.5t30 -27.5t12 -24l1 -10v-50l365 -303q14 -14 24.5 -39.5t10.5 -45.5v-212q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-20 0 -35 14.5t-15 35.5zM0 712 q0 -21 14.5 -33.5t34.5 -8.5l202 33q20 4 34.5 21t14.5 38v146q141 24 300 24t300 -24v-146q0 -21 14.5 -38t34.5 -21l202 -33q20 -4 34.5 8.5t14.5 33.5v200q-6 8 -19 20.5t-63 45t-112 57t-171 45t-235 20.5q-92 0 -175 -10.5t-141.5 -27t-108.5 -36.5t-81.5 -40 t-53.5 -36.5t-31 -27.5l-9 -10v-200z" />
<glyph unicode="&#xe184;" d="M100 0v100h1100v-100h-1100zM175 200h950l-125 150v250l100 100v400h-100v-200h-100v200h-200v-200h-100v200h-200v-200h-100v200h-100v-400l100 -100v-250z" />
<glyph unicode="&#xe185;" d="M100 0h300v400q0 41 -29.5 70.5t-70.5 29.5h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-400zM500 0v1000q0 41 29.5 70.5t70.5 29.5h100q41 0 70.5 -29.5t29.5 -70.5v-1000h-300zM900 0v700q0 41 29.5 70.5t70.5 29.5h100q41 0 70.5 -29.5t29.5 -70.5v-700h-300z" />
<glyph unicode="&#xe186;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v300h-200v100h200v100h-300v-300h200v-100h-200v-100zM600 300h200v100h100v300h-100v100h-200v-500 zM700 400v300h100v-300h-100z" />
<glyph unicode="&#xe187;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h100v200h100v-200h100v500h-100v-200h-100v200h-100v-500zM600 300h200v100h100v300h-100v100h-200v-500 zM700 400v300h100v-300h-100z" />
<glyph unicode="&#xe188;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v100h-200v300h200v100h-300v-500zM600 300h300v100h-200v300h200v100h-300v-500z" />
<glyph unicode="&#xe189;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 550l300 -150v300zM600 400l300 150l-300 150v-300z" />
<glyph unicode="&#xe190;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300v500h700v-500h-700zM300 400h130q41 0 68 42t27 107t-28.5 108t-66.5 43h-130v-300zM575 549 q0 -65 27 -107t68 -42h130v300h-130q-38 0 -66.5 -43t-28.5 -108z" />
<glyph unicode="&#xe191;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v300h-200v100h200v100h-300v-300h200v-100h-200v-100zM601 300h100v100h-100v-100zM700 700h100 v-400h100v500h-200v-100z" />
<glyph unicode="&#xe192;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v400h-200v100h-100v-500zM301 400v200h100v-200h-100zM601 300h100v100h-100v-100zM700 700h100 v-400h100v500h-200v-100z" />
<glyph unicode="&#xe193;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 700v100h300v-300h-99v-100h-100v100h99v200h-200zM201 300v100h100v-100h-100zM601 300v100h100v-100h-100z M700 700v100h200v-500h-100v400h-100z" />
<glyph unicode="&#xe194;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM400 500v200 l100 100h300v-100h-300v-200h300v-100h-300z" />
<glyph unicode="&#xe195;" d="M0 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM182 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM400 400v400h300 l100 -100v-100h-100v100h-200v-100h200v-100h-200v-100h-100zM700 400v100h100v-100h-100z" />
<glyph unicode="&#xe197;" d="M-14 494q0 -80 56.5 -137t135.5 -57h222v300h400v-300h128q120 0 205 86.5t85 207.5t-85 207t-205 86q-46 0 -90 -14q-44 97 -134.5 156.5t-200.5 59.5q-152 0 -260 -107.5t-108 -260.5q0 -25 2 -37q-66 -14 -108.5 -67.5t-42.5 -122.5zM300 200h200v300h200v-300h200 l-300 -300z" />
<glyph unicode="&#xe198;" d="M-14 494q0 -80 56.5 -137t135.5 -57h8l414 414l403 -403q94 26 154.5 104.5t60.5 178.5q0 120 -85 206.5t-205 86.5q-46 0 -90 -14q-44 97 -134.5 156.5t-200.5 59.5q-152 0 -260 -107.5t-108 -260.5q0 -25 2 -37q-66 -14 -108.5 -67.5t-42.5 -122.5zM300 200l300 300 l300 -300h-200v-300h-200v300h-200z" />
<glyph unicode="&#xe199;" d="M100 200h400v-155l-75 -45h350l-75 45v155h400l-270 300h170l-270 300h170l-300 333l-300 -333h170l-270 -300h170z" />
<glyph unicode="&#xe200;" d="M121 700q0 -53 28.5 -97t75.5 -65q-4 -16 -4 -38q0 -74 52.5 -126.5t126.5 -52.5q56 0 100 30v-306l-75 -45h350l-75 45v306q46 -30 100 -30q74 0 126.5 52.5t52.5 126.5q0 24 -9 55q50 32 79.5 83t29.5 112q0 90 -61.5 155.5t-150.5 71.5q-26 89 -99.5 145.5 t-167.5 56.5q-116 0 -197.5 -81.5t-81.5 -197.5q0 -4 1 -11.5t1 -11.5q-14 2 -23 2q-74 0 -126.5 -52.5t-52.5 -126.5z" />
</font>
</defs></svg>

Before

Width:  |  Height:  |  Size: 62 KiB

View File

@ -1 +0,0 @@
google-site-verification: google052dbec2d053a4e1.html

View File

@ -1,265 +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: Overview</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 class="active"><a href="index.html">Overview</a></li>
<li><a href="api.html">API</a></li>
<li><a href="documentation.html">Documentation</a></li>
<li><a href="plc.html">PLC</a></li>
<li><a href="tutorial.html">Tutorial</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">Strolch Overview</h1>
<p class="lead page-description">This page describes the Strolch software agent and the motivation behind its
development.</p>
</div>
<div class="content">
<h2>Overview</h2>
<p>Strolch is an open source component based software agent written in Java and can be compared, in a light
sense, with the Java EE stack: Strolch takes care of persistence, implements Services for use cases, Commands
as re-usable algorithms and has a parameterized data model.</p>
<p>Strolch has an intrinsic understanding for mandates, which are called realms so that a single agent can be
used to implement applications with multiple users/customers for instance in SaaS environments.</p>
<p>The parameterized data model consists of three top level objects, Resources, Orders and Activities. These
objects can have any number of ParameterBags which in turn can have any number of Parameters on them. This
allows for a very dynamic modelling of data structures including modification at run time. Multiple ready to
use Parameter types are already implemented which handle the primitive types in Java including ListParameters
for collections of these primitive types.</p>
<p>One of the main features of the Strolch agent, is that persistence is handled transparently and the user must
not be worried about databases and the likes. Currently there are two implementations for persisting the
Strolch model, a PostgreSQL and an XML file persistence. Currently both persistence layers persist the data
by converting to XML and storing it into the database. The XML file persistence stores each object in its own
file.</p>
<p>The agent itself has a small memory footprint and requires very few components to start. For the agent to be
useful it needs additional functionality which is implemented in StrolchComponents. Each component is
registered via its Java interface on the agent and is bound to the life cycle of the agent. When the agent is
started, these components can be retrieved and used to perform any number of functionalities. This is the
preferred way to extend the Strolch agent. There are a number of components already implemented, e.g. the
ServiceHandler which executes Services in a controlled fashion and can validate authorized access to these
services.</p>
<p>No software product is complete without a system for authentication and authorization. Strolch implements
this by using the Privilege framework which has been written by Robert von Burg. The standard ServiceHandler
detects the existence of the PrivilegeHandler and then validates that the user has authorization to perform
the service. This framework is implemented as its own Strolch component, thus can be retrieved at any time
during execution to perform fine grained and special authorization validation.</p>
<h2>Motivation</h2>
<p>A question often asked is why create Strolch. What are its benefits in contrast to using Java SE with an
OR-Mapper like Hibernate, or using Java EE on JBoss or Glassfish? Especially since many of the features
existing in those stacks needed to be re-created in Strolch.</p>
<p>The first answer to this question is that those systems are often overly complicated and bloated. Java SE
with Hibernate certainly is a viable option when it comes to being light-weightier but Hibernate, even though
it is supposed to, often fails to truly help remove the need to really understand an RDBMS. Often enough
Hibernate will just get in the way of the most important part of development: writing the business code.
Being an OR-Mapper which is supposed to implement all the nitty-gritty details of an RDBMS system, Hibernate,
and JPA for that matter, still often has the developer go back to understanding these details.</p>
<p>Strolch tries a different approach to persistence. Instead of writing pojos/entities, Strolch's model has the
concept that each element's attributes are part of a composition pattern: each attribute is its own object
and thus can be dynamically changed at runtime, but also makes persistence of such an element generic.
Instead of having fixed attributes for a concrete class, these parameters are stored in a map and are
accessed through the parameter's ID.</p>
<p>Assigning an ID to an attribute for accessing of course brings its own downsides, i.e. the parameter might
simply not be there, when being accessed. This is certainly an issue that the developer must handle, when
implementing a project using Strolch, but allows the developer to not need to worry about persistence, as
this is generically handled.</p>
<p>Since the persistence is generically handled, and Strolch stays lightweight on its requirements at runtime,
the developer can quickly get down to what is important for business value: Writing the business logic and
the presentation layer. Here too Strolch tries to help the developer by bringing in concepts which are easy
to follow: Use cases are implemented as Services, and re-usable business logic is put into Commands.</p>
<p>There will be reasons against using Strolch, as there will be against using the Java EE stack, or an
OR-Mapper or even the Java ecosystem for that fact. Important is to note, that the concepts behind Strolch
are nothing new, but have been implemented in at least two previous proprietary products. Since those
products are not accessible to the public, it was decided that a re-implementation might be of use to the
programming community at large.</p>
<p>Currently there is at least one company using Strolch in a commercial project which helps drive Strolch's
development and further motivates its existence.</p>
<p>Strolch is an open source project and licensed under the Apache License 2.0.</p>
<h2>Technologoy</h2>
<p>Strolch is written in Java and is programmed against the JDK 8. Strolch runs on any JRE 8 compliant
environment. Strolch is tested on the Oracle JRE 8.</p>
<h3>Dependencies</h3>
<p>Strolch strives to use as few external dependencies as possible, so that the Strolch runtime is not bloated
unnecessarily. The following list of Strolch dependencies is a summary and was created using mvn
dependency:tree on the strolch_minimal project for release 1.6.47.</p>
<p>Logging</p>
<ul>
<li>org.slf4j:slf4j-api:jar:1.7.25</li>
<li>ch.qos.logback:logback-classic:jar:1.2.3</li>
<li>ch.qos.logback:logback-core:jar:1.2.3</li>
</ul>
<p>Utils</p>
<ul>
<li>javax.mail:javax.mail-api:jar:1.6.0</li>
<li>com.sun.mail:javax.mail:jar:1.6.0</li>
<li>javax.activation:activation:jar:1.1</li>
</ul>
<p>Testing</p>
<ul>
<li>junit:junit:jar:4.12</li>
<li>org.hamcrest:hamcrest-core:jar:1.3</li>
<li>org.hamcrest:hamcrest-library:jar:1.3</li>
<li>org.mockito:mockito-core:jar:2.0.8-beta</li>
<li>org.objenesis:objenesis:jar:2.1</li>
</ul>
<p>Model</p>
<ul>
<li>com.google.code.gson:gson:jar:2.8.2</li>
</ul>
<p>SOQL</p>
<ul>
<li>org.abego.treelayout:org.abego.treelayout.core:jar:1.0.3</li>
<li>org.antlr:antlr-runtime:jar:3.5.2</li>
<li>org.antlr:antlr4-runtime:jar:4.7</li>
<li>org.antlr:antlr4:jar:4.7</li>
<li>org.antlr:ST4:jar:4.0.8</li>
<li>org.glassfish:javax.json:jar:1.0.4</li>
<li>com.ibm.icu:icu4j:jar:58.2</li>
</ul>
<p>PostgreSQL</p>
<ul>
<li>com.zaxxer:HikariCP:jar:2.7.1</li>
<li>org.postgresql:postgresql:jar:42.1.4</li>
</ul>
<p>REST</p>
<ul>
<li>javax.annotation:javax.annotation-api:jar:1.3.1</li>
<li>javax.servlet:javax.servlet-api:jar:3.1.0</li>
<li>javax.ws.rs:javax.ws.rs-api:jar:2.1</li>
</ul>
<p>REST testing</p>
<ul>
<li>javax.validation:validation-api:jar:1.1.0.Final</li>
<li>org.glassfish.grizzly:grizzly-framework:jar:2.3.28</li>
<li>org.glassfish.grizzly:grizzly-http-server:jar:2.3.28</li>
<li>org.glassfish.grizzly:grizzly-http-servlet:jar:2.3.28</li>
<li>org.glassfish.grizzly:grizzly-http:jar:2.3.28</li>
<li>org.glassfish.hk2:hk2-api:jar:2.5.0-b32</li>
<li>org.glassfish.hk2:hk2-locator:jar:2.5.0-b32</li>
<li>org.glassfish.hk2:hk2-utils:jar:2.5.0-b32</li>
<li>org.glassfish.hk2:osgi-resource-locator:jar:1.0.1</li>
<li>org.glassfish.hk2.external:aopalliance-repackaged:jar:2.5.0-b32</li>
<li>org.glassfish.hk2.external:javax.inject:jar:2.5.0-b32</li>
<li>org.glassfish.jersey.bundles.repackaged:jersey-guava:jar:2.25.1</li>
<li>org.glassfish.jersey.containers:jersey-container-grizzly2-http:jar:2.25.1</li>
<li>org.glassfish.jersey.containers:jersey-container-grizzly2-servlet:jar:2.25.1</li>
<li>org.glassfish.jersey.containers:jersey-container-servlet-core:jar:2.25.1</li>
<li>org.glassfish.jersey.containers:jersey-container-servlet:jar:2.25.1</li>
<li>org.glassfish.jersey.core:jersey-client:jar:2.25.1</li>
<li>org.glassfish.jersey.core:jersey-common:jar:2.25.1</li>
<li>org.glassfish.jersey.core:jersey-server:jar:2.25.1</li>
<li>org.glassfish.jersey.media:jersey-media-jaxb:jar:2.25.1</li>
<li>org.glassfish.jersey.test-framework:jersey-test-framework-core:jar:2.25.1</li>
<li>org.javassist:javassist:jar:3.20.0-GA</li>
</ul>
<h4>API</h4>
<p>Check out the <a href="api.html">API page</a> to see how to use Strolch.</p>
</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 xsd 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>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 83 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

View File

@ -1,176 +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: Overview</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 class="active"><a href="index.html">Overview</a></li>
<li><a href="api.html">API</a></li>
<li><a href="documentation.html">Documentation</a></li>
<li><a href="plc.html">PLC</a></li>
<li><a href="tutorial.html">Tutorial</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">Strolch Overview</h1>
<p class="lead page-description">A short introduction to Strolch.</p>
</div>
<div class="content">
<h2>Strolch in short</h2>
<p>Strolch is framework for developing Software. It's main features are:</p>
<ul>
<li>Complete persisted <a href="documentation-model.html">data model</a>:
<ul>
<li>Parameters and values by time</li>
<li>Resources, Orders with arbitrary parameter grouping</li>
<li>Activity/Action hierarchy with arbitrary depth</li>
<li>Policies for delegation</li>
<li>JSON as well as XML transformation</li>
<li>Locator API</li>
</ul>
</li>
<li><a href="documentation-transactions.html">Transactions with pessimistic locking and optional
read-locking</a></li>
<li><a href="documentation-searches.html">Search API</a></li>
<li>Component based</li>
<li><a href="documentation-privileges.html">Deeply integrated privilege handling</a></li>
<li>Fully in-memory</li>
<li>Persisted auditing, versioning, operations log</li>
<li>DAOs for file system or PostgreSQL, easily extended</li>
<li>Execution framework</li>
<li><a href="documentation-services-and-commands.html">Service / Command oriented</a></li>
<li><a href="documentation-reports.html">Reporting API configured by Resource objects</a></li>
<li>REST API for data access</li>
<li>WebComponents UI for
<ul>
<li>Inspector</li>
<li>Users</li>
<li>Roles</li>
<li>Operations Log</li>
<li>Login Screen</li>
<li>Jobs</li>
</ul>
</li>
<li>runs on plain old Java SE</li>
</ul>
<h2>Strolch Intro</h2>
<p>It is a different framework to Spring and other similar type of Java frameworks, as the model is defined as
an abstract model, where you always have the same three types of objects: Resources, Orders and Activities.
The fields are mapped as Parameter objects, of which the important primitives are available.</p>
<p>The nice part about this framework is, that you can be up and ready in a matter of minutes, and start
building your project immediately in that you open your favourite XML editor and start modelling your
data.</p>
<p>Once your data is defined, you write your business logic in the form of Services, Commands and Searches.
There are many predefined services and commands to manipulate the object model, so that you write your own
services when you need to enforce special business rules.</p>
<p>Through the use of Policy objects, you decouple algorithms from your object model, so that at runtime you can
change the behaviour, or easily implement different behaviour depending on your use-case. For instance you
might have a simple billing service which performs a few preparatory steps, and then calls the configured
billing policy to execute the billing depending on the customer, the warehouse, etc.</p>
<p>And of course persistence is as simple as configuring the persistence handler, pointing to your RDBMS and
then setting the mode to CACHED. For you as a developer there is no more thinking in terms of SQL etc., as
this is completely hidden from the developer. There is even a simple file persistence layer if you are
running IoT devices.</p>
<p>The runtime can be just about anything. Usually it is run inside an Apache Tomcat instance as a webapp, as a
WEB UI has been required for all current Strolch projects. You could just as well use a main class. Accessing
the Strolch Agent remotely is usually done through REST.</p>
<p>Strolch is being actively developed, and customers constantly give us reasons to improve and extend the
framework. There is a Polymer Inspector component which makes it easy to see and manipulate the actual data.
The new Search API makes it really easy to query your data.</p>
<p>Yes, Strolch is different, but the concept has come out of the planning and execution segment, and has been
refined over the years until it has become what it is today.</p>
<h2>API</h2>
<p>Check out the <a href="api.html">API page</a> to see how to use Strolch.</p>
<a href="history.html">More to motivation etc.</a>
</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 xsd 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>

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -1,617 +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: PLC</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><a href="documentation.html">Documentation</a></li>
<li class="active"><a href="plc.html">PLC</a></li>
<li><a href="tutorial.html">Tutorial</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">Strolch as a software PLC</h1>
<p class="lead page-description">A soft real time PLC written in Strolch running on Strolch</p>
</div>
<div class="content">
<!-- content here -->
<h2>Overview</h2>
<p>Using Strolch as a PLC has certain advantages and disadvantages. The following is a list of advantages:</p>
<ul>
<li>Same programming model and language for server and PLC</li>
<li>PLC has the same privilege handling as in Strolch</li>
<li>Simulating down to the PLC level is easily possible for easier testing of server logic</li>
</ul>
<p>Of course using the Java language as a PLC has its limitations, we have manage to use it for customers and
are satisfied with the result. What follows is a description in how to set up your own Strolch based PLC.</p>
<p>Checkout the code at <a href="https://github.com/4treesCH/strolch-plc">GitHub</a></p>
<h2>Architecture</h2>
<h3>Overview</h3>
<img class="image" src="images/Strolch-PLC-Architecture-Overview.png" alt="Strolch PLC Architecture Overview">
<p>The Strolch PLC architecture sees the Strolch Agent as the server, managing logical devices, i.e. multiple
sensors and actors together and thus deciding on further steps. With this architecture multiple PLCs can be
combined together in one agent for flow control.</p>
<h3>PLC Architecture</h3>
<img class="image" src="images/Strolch-PLC-Architecture.png" alt="Strolch PLC Architecture">
<p>On the agent side the two main classes are the <code>PlcGwServerHandler</code> and the
<code>PlcGwService</code></p>
<p>The <code>PlcGwServerHandler</code> handles connections from remote PLCs over WebSockets and sends the
requests to these PLCs. A <code>PlcGwService</code> instance will be notified and can then decide on an
action. In an execution model with <code>Activities</code>, the <code>PlcNotificationListener</code>
interface can be implemented, or the <code>PlcExecutionPolicy</code> can be directly extended.</p>
<p>On the PLC side, the <code>PlcGwClientHandler</code> is optional if no agent is required. The <code>PlcHandler</code>
initializes the model and connections. The <code>Plc</code> class is Strolch agnostic and manages the
connections and notifies <code>PlcListener</code> instances on changes coming from the underlying
connections. The <code>PlcService</code> implementations implement business logic, and can also be notified
on updates from connections.</p>
<h2>Example set up</h2>
<p>This example setup describes the movement of containers over conveyors. The conveyors have motors which can
be started and stopped by a GPIO output pin controlled on a Raspberry Pi and each conveyor has a light
barrier to detect the occupancy of a container and the Raspberry Pi detects this on GPIO input pins.</p>
<p>Further at each conveyor location is a barcode reader to read the ID of a container.</p>
<p>The general idea is that the PLC notifies a Strolch agent of changes, and only turns conveyors on, when the
agent gives the command. Thus the agent handles business logic and the PLC controls the I/Os.</p>
<img class="image" src="images/Strolch-Plc-Example.png" alt="Strolch PLC Conveyor Example" />
<h2>New Project</h2>
<ol>
<li>First create a new Strolch Web project using the <a href="development.html">Strolch Maven archetype</a>
</li>
<li>Now add the following Maven dependencies:
<pre>
&lt;properties&gt;
&lt;strolch.version&gt;1.6.0-SNAPSHOT&lt;/strolch.version&gt;
&lt;strolch.plc.version&gt;0.1.0-SNAPSHOT&lt;/strolch.plc.version&gt;
&lt;/properties&gt;
&lt;dependencyManagement&gt;
&lt;dependency&gt;
&lt;groupId&gt;li.strolch&lt;/groupId&gt;
&lt;artifactId&gt;li.strolch.bom&lt;/artifactId&gt;
&lt;type&gt;pom&lt;/type&gt;
&lt;version&gt;${strolch.version}&lt;/version&gt;
&lt;scope&gt;import&lt;/scope&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
&lt;groupId&gt;li.strolch&lt;/groupId&gt;
&lt;artifactId&gt;strolch-plc-bom&lt;/artifactId&gt;
&lt;type&gt;pom&lt;/type&gt;
&lt;version&gt;${strolch.plc.version}&lt;/version&gt;
&lt;scope&gt;import&lt;/scope&gt;
&lt;/dependency&gt;
&lt;/dependencyManagement&gt;
&lt;dependencies&gt;
&lt;!-- PLC --&gt;
&lt;dependency&gt;
&lt;groupId&gt;li.strolch&lt;/groupId&gt;
&lt;artifactId&gt;strolch-plc-core&lt;/artifactId&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
&lt;groupId&gt;li.strolch&lt;/groupId&gt;
&lt;artifactId&gt;strolch-plc-rest&lt;/artifactId&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
&lt;groupId&gt;li.strolch&lt;/groupId&gt;
&lt;artifactId&gt;strolch-plc-gw-client&lt;/artifactId&gt;
&lt;/dependency&gt;
&lt;/dependencies&gt;</pre>
</li>
<li>
<p>Add a bower dependency: <code>"strolch-wc-plc": "strolch-li/strolch-wc-plc#^0.3.4"</code> to <code>src/main/webapp/bower.json</code>
</p>
<p>After adding the dependeny, run <code>gulp</code> in the webapp directory. Gulp should have been
installed through the instructions from the <a href="development.html">development page</a>.</p>
</li>
<li>
<p>Now we need to add the PLC web views to our new project. This is added in the <code>src/main/webapp/app/src/c-app.html</code>
file. Add the following:</p>
<pre>
&lt;!-- HTML Imports --&gt;
&lt;link rel="import" href="../bower_components/strolch-wc-plc/strolch-wc-plc-connections.html"&gt;
&lt;link rel="import" href="../bower_components/strolch-wc-plc/strolch-wc-plc-logical-devices.html"&gt;
&lt;!-- Change default-page to plcLogicalDevices --&gt;
&lt;c-app-routing id="appRouting"
login-page="login"
default-page="plcLogicalDevices"
auth-valid="[[authTokenValid]]"
page="{{page}}"
route-tail="{{routeTail}}"
use-hash-as-path&gt;&lt;/c-app-routing&gt;
&lt;!-- Add the new pages in the iron-pages element: --&gt;
&lt;template is="dom-if" if="[[equal(page, 'plcConnections')]]" restamp&gt;
&lt;strolch-wc-plc-connections id="plcConnections"
base-path="../"
base-rest-path="[[baseRestPath]]"
route="{{subroute}}"&gt;&lt;/strolch-wc-plc-connections&gt;
&lt;/template&gt;
&lt;template is="dom-if" if="[[equal(page, 'plcLogicalDevices')]]" restamp&gt;
&lt;strolch-wc-plc-logical-devices id="plcLogicalDevices"
base-path="../"
base-rest-path="[[baseRestPath]]"
base-ws-path="[[baseWsPath]]"
route="{{subroute}}"&gt;&lt;/strolch-wc-plc-logical-devices&gt;
&lt;/template&gt;
// add a new property to the WebSocket path for observing changes on the PLC
wsObserverPath: {
type: String,
value: function () {
return CustomWeb.baseWsPath + "/plc/observer";
}
}</pre>
</li>
<li>
<p>Don't forget to add the PLC Rest classes to your <code>ResourceConfig</code></p>
<pre>
@ApplicationPath("rest")
public class RestfulApplication extends ResourceConfig {
public RestfulApplication() {
...
// strolch plc services
packages(PlcConnectionsResource.class.getPackage().getName());
...
}
}
</pre>
</li>
<li>
<p>Now we need to configure the PLC's runtime by modifying <code>runtime/StrolchConfiguration.xml</code>
and adding the following:</p>
<pre>
&lt;!--
This component configures the PlcHandler by
loading the PlcConnections, PlcAddresses and PlcTelegrams
--&gt;
&lt;Component&gt;
&lt;name&gt;PlcHandler&lt;/name&gt;
&lt;api&gt;li.strolch.plc.core.PlcHandler&lt;/api&gt;
&lt;impl&gt;li.strolch.plc.core.DefaultPlcHandler&lt;/impl&gt;
&lt;depends&gt;RealmHandler&lt;/depends&gt;
&lt;Properties&gt;
&lt;!-- The component handling the low level connections --&gt;
&lt;plcClass&gt;li.strolch.plc.core.hw.DefaultPlc&lt;/plcClass&gt;
&lt;/Properties&gt;
&lt;/Component&gt;
&lt;!--
This component handles registrations of the PlcServices, i.e. your PLC business logic
--&gt;
&lt;Component&gt;
&lt;name&gt;PlcServiceInitializer&lt;/name&gt;
&lt;api&gt;li.strolch.plc.core.PlcServiceInitializer&lt;/api&gt;
&lt;impl&gt;li.strolch.plc.example.CustomPlcServiceInitializer&lt;/impl&gt;
&lt;depends&gt;PlcHandler&lt;/depends&gt;
&lt;Properties&gt;
&lt;/Properties&gt;
&lt;/Component&gt;
&lt;!--
This component notifies a Strolch agent of changes on the PLC
only if you have a Strolch server with a configured
li.strolch.plc.gw.server.PlcServerWebSocketEndpoint ready to accept connections
--&gt;
&lt;Component&gt;
&lt;name&gt;PlcGwClientHandler&lt;/name&gt;
&lt;api&gt;li.strolch.plc.gw.client.PlcGwClientHandler&lt;/api&gt;
&lt;impl&gt;li.strolch.plc.gw.client.PlcGwClientHandler&lt;/impl&gt;
&lt;depends&gt;PlcHandler&lt;/depends&gt;
&lt;depends&gt;PlcServiceInitializer&lt;/depends&gt;
&lt;Properties&gt;
&lt;plcId&gt;plc-01&lt;/plcId&gt;
&lt;gwUsername&gt;plc-01&lt;/gwUsername&gt;
&lt;gwPassword&gt;plc-01&lt;/gwPassword&gt;
&lt;gwServerUrl&gt;ws://localhost:8080/agent/websocket/strolch/plc&lt;/gwServerUrl&gt;
&lt;/Properties&gt;
&lt;/Component&gt;</pre>
</li>
<li>
<p>Now we add the custom classes we just declared.</p>
<p><b>PlcServiceInitializer</b></p>
<pre>
import java.util.ArrayList;
import java.util.List;
import li.strolch.plc.example.services.*;
import li.strolch.agent.api.ComponentContainer;
import li.strolch.plc.core.PlcHandler;
import li.strolch.plc.core.PlcService;
import li.strolch.plc.core.PlcServiceInitializer;
public class CustomPlcServiceInitializer extends PlcServiceInitializer {
public CustomPlcServiceInitializer(ComponentContainer container, String componentName) {
super(container, componentName);
}
@Override
protected List&lt;PlcService&gt; getPlcServices(PlcHandler plcHandler) {
ArrayList&lt;PlcService&gt; plcServices = new ArrayList&lt;&gt;();
StartupPlcService startupPlcService = new StartupPlcService(plcHandler);
ConveyorPlcService conveyorPlcService = new ConveyorPlcService(plcHandler);
plcServices.add(conveyorPlcService);
plcServices.add(startupPlcService);
return plcServices;
}
}</pre>
<p><b>PlcPostInitializer</b></p>
<pre>
import li.strolch.agent.api.ComponentContainer;
import li.strolch.plc.core.PlcPostInitializer;
public class CustomPostInitializer extends PlcPostInitializer {
public CustomPostInitializer(ComponentContainer container, String componentName) {
super(container, componentName);
}
// override the initialize(), start(), stop() and destroy() methods as needed
}</pre>
</li>
<li>
<p>In the <code>CustomPlcServiceInitializer</code> we added two PlcServices, for which the code is
missing. The following are simple examples:</p>
<p><b>StartupPlcService</b></p>
<pre>
import li.strolch.persistence.api.StrolchTransaction;
import li.strolch.plc.core.PlcHandler;
import li.strolch.plc.core.PlcService;
public class StartupPlcService extends PlcService {
public static final String PLC = "PLC";
public static final String STARTED = "Started";
public static final String STOPPED = "Stopped";
public StartupPlcService(PlcHandler plcHandler) {
super(plcHandler);
}
@Override
public void start(StrolchTransaction tx) {
send(PLC, STARTED);
super.start(tx);
}
@Override
public void stop() {
send(PLC, STOPPED);
super.stop();
}
}</pre>
<p><b>ConveyorPlcService</b></p>
<pre>
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import li.strolch.plc.core.PlcHandler;
import li.strolch.plc.core.PlcService;
import li.strolch.plc.model.PlcAddress;
public class ConveyorPlcService extends PlcService {
public static final int BOX_TRANSFER_DURATION = 30;
private static final String R_CONVEYOR_01 = "Conveyor01";
private static final String A_START_BUTTON = "StartButton";
private static final String T_MOTOR_ON = "MotorOn";
private static final String T_MOTOR_OFF = "MotorOff";
private static final String A_BOX_DETECTED = "BoxDetected";
private boolean motorOn;
private ScheduledFuture&lt;?&gt; motorStopTask;
public ConveyorPlcService(PlcHandler plcHandler) {
super(plcHandler);
}
@Override
public void handleNotification(PlcAddress address, Object value) {
String resource = address.resource;
String action = address.action;
if (!resource.equals("Conveyor01"))
throw new IllegalStateException("Unexpected resource " + resource);
boolean active = (boolean) value;
if (action.equals(A_START_BUTTON)) {
if (active) {
logger.info("Start button pressed. Starting motors...");
send(R_CONVEYOR_01, T_MOTOR_ON);
this.motorOn = true;
scheduleStopTask();
}
} else if (action.equals(A_BOX_DETECTED)) {
if (active && this.motorOn) {
logger.info("Container detected, refreshing stop task...");
scheduleStopTask();
}
} else {
logger.info("Unhandled notification " + address.toKeyAddress());
}
}
private void scheduleStopTask() {
if (this.motorStopTask != null)
this.motorStopTask.cancel(false);
this.motorStopTask = schedule(this::stopMotor, BOX_TRANSFER_DURATION, TimeUnit.SECONDS);
}
private void stopMotor() {
send(R_CONVEYOR_01, T_MOTOR_OFF);
}
@Override
public void register() {
this.plcHandler.register(R_CONVEYOR_01, A_START_BUTTON, this);
this.plcHandler.register(R_CONVEYOR_01, A_BOX_DETECTED, this);
super.register();
}
@Override
public void unregister() {
this.plcHandler.unregister(R_CONVEYOR_01, A_START_BUTTON, this);
this.plcHandler.unregister(R_CONVEYOR_01, A_BOX_DETECTED, this);
super.unregister();
}
}</pre>
</li>
<li>
<p>Now the last part is to add the model, i.e. PlcConnections, PlcAddresses and PlcTelegrams. To have
less configuration files and make it easier to reconfigure at runtime, this data is stored in normal
Strolch <code>Resources</code></p>
<p>In this example we will use simple Raspberry Pi GPIOs. For convenience, and also when sharing I/O
definitions with external partners, it is easier to use a CSV file to define the I/Os and then use
the <code>PlcAddressGenerator</code> to generate and validate the model.</p>
<p>For this purpose in this example, we will use one conveyor with 2 inputs and 1 output. The CSV file
should have the following content:</p>
<pre>
Description,Type,SubType,Device,Pin,Resource,Action1,Action2,Connection,DeviceId
Material Flow,Group,,,,,,,,MaterialFlow
Conveyor 1,Input,Pin,,4,Conveyor,Occupied,,raspiBcmGpioInput
Conveyor 1,Input,Pin,,17,Conveyor,BoxDetected,,raspiBcmGpioInput
Conveyor 1,Output,Pin,,18,Conveyor,MotorOn,MotorOff,raspiBcmGpioOutput</pre>
<p>The CSV headers are as follows:</p>
<ul>
<li>Description &rarr; a simple description for this PlcAddress</li>
<li>Type &rarr;
<ul>
<li>Group &rarr; Must be the first line and generates a PlcLogicalDevice, all succeeding
lines are grouped to this device. Add additional to group further devices
</li>
<li>Input &rarr; defines a boolean input</li>
<li>Output &rarr; defines a boolean output</li>
<li>Virtual &rarr; defines a virtual address which has no corresponding hardware connection.
Used for internal communication.
</li>
<li>DataLogicScanner &rarr; defines an address to read barcodes from a DataLogic Scanner.
The actions must be left empty as the keys Barcode (address), On and Off (telegrams)
will be generated.
</li>
</ul>
</li>
<li>SubType &rarr;
<ul>
<li>For Input and Output types &rarr;
<ul>
<li>DevPin, DevPin0 &rarr; Generates the address as <code>&lt;Connection&gt;.&lt;Device&gt;.&lt;Pin&gt;</code>.
DevPin0 decrements the Device and Pin values by one.
</li>
<li>Pin &rarr; Generates the address as <code>&lt;Connection&gt;.&lt;Pin&gt;</code>.
</li>
</ul>
</li>
<li>For Virtual types &rarr;
<ul>
<li>Boolean</li>
<li>String</li>
</ul>
</li>
</ul>
</li>
<li>Device &rarr; Device number</li>
<li>Pin &rarr; The pin number on the device</li>
<li>Resource &rarr; The resource ID with which to notify the agent</li>
<li>Action1 &rarr; The action ID</li>
<li>Action2 &rarr; The second action ID if required</li>
<li>Connection &rarr; The ID of the PlcConnection with which this I/O is attached</li>
<li>DeviceId &rarr; For type Group: Set the ID of this PlcLogicalDevice being generated</li>
</ul>
<p>When you use this file as input for the <code>PlcAddressGenerator</code>, then it will generate
PlcLogicalDevice, PlcAddress and PlcTelegram elements:</p>
<pre>
&lt;Resource Id="D_MaterialFlow" Name="MaterialFlow" Type="PlcLogicalDevice"&gt;
&lt;ParameterBag Id="parameters" Name="Parameters" Type="Parameters"&gt;
&lt;Parameter Id="description" Name="Description" Type="String" Value="Material Flow"/&gt;
&lt;Parameter Id="group" Name="Group" Type="String" Value="01 Material Flow"/&gt;
&lt;Parameter Id="index" Name="Index" Type="Integer" Value="10"/&gt;
&lt;/ParameterBag&gt;
&lt;ParameterBag Id="relations" Name="Relations" Type="Relations"&gt;
&lt;Parameter Id="addresses" Name="Addresses" Type="StringList" Interpretation="Resource-Ref" Uom="PlcAddress" Value="A_Conveyor-Occupied, A_Conveyor-BoxDetected, A_Conveyor-MotorOn"/&gt;
&lt;Parameter Id="telegrams" Name="Telegrams" Type="StringList" Interpretation="Resource-Ref" Uom="PlcTelegram" Value="T_Conveyor-MotorOn, T_Conveyor-MotorOff"/&gt;
&lt;/ParameterBag&gt;
&lt;/Resource&gt;
&lt;Resource Id="A_Conveyor-Occupied" Name="Conveyor - Occupied" Type="PlcAddress"&gt;
&lt;ParameterBag Id="parameters" Name="Parameters" Type="Parameters"&gt;
&lt;Parameter Id="description" Name="Description" Type="String" Index="5" Value="Conveyor 1"/&gt;
&lt;Parameter Id="address" Name="HW Address" Type="String" Interpretation="PlcConnection" Index="10" Value="raspiBcmGpioInput.4"/&gt;
&lt;Parameter Id="resource" Name="Resource ID for PlcAddress" Type="String" Index="20" Value="Conveyor"/&gt;
&lt;Parameter Id="action" Name="Action ID for PlcAddress" Type="String" Index="30" Value="Occupied"/&gt;
&lt;Parameter Id="index" Name="Index" Type="Integer" Index="40" Value="10"/&gt;
&lt;Parameter Id="value" Name="Value" Type="Boolean" Index="100" Value="false"/&gt;
&lt;/ParameterBag&gt;
&lt;/Resource&gt;
&lt;Resource Id="T_Conveyor-MotorOn" Name="Conveyor - MotorOn" Type="PlcTelegram"&gt;
&lt;ParameterBag Id="parameters" Name="Parameters" Type="Parameters"&gt;
&lt;Parameter Id="description" Name="Description" Type="String" Index="5" Value="Conveyor 1"/&gt;
&lt;Parameter Id="address" Name="HW Address" Type="String" Interpretation="PlcConnection" Index="10" Value="raspiBcmGpioOutput.18"/&gt;
&lt;Parameter Id="resource" Name="Resource ID for PlcAddress" Type="String" Index="20" Value="Conveyor"/&gt;
&lt;Parameter Id="action" Name="Action ID for PlcAddress" Type="String" Index="30" Value="MotorOn"/&gt;
&lt;Parameter Id="index" Name="Index" Type="Integer" Index="40" Value="10"/&gt;
&lt;Parameter Id="value" Name="Value" Type="Boolean" Index="100" Value="true"/&gt;
&lt;/ParameterBag&gt;
&lt;/Resource&gt;</pre>
<p>The PlcLogicalDevice references the PlcAddress and PlcTelegram objects, and is then used in the UI
for grouping.</p>
<p>The PlcAddress is used to store the current value and defines the keys with which the agent will be
notified</p>
<p>The PlcTelegram is used to store default values to send, for specific keys. E.g. The action
<code>On</code> would send true, and <code>Off</code> would send false. This is semantics, and is
defined in each project depending on the hardware.</p>
</li>
<li>
<p>Copy the file <a href="https://github.com/4treesCH/strolch-plc/blob/develop/example/plc-state.xml">plc-state.xml</a>
to your runtime and reference it by use of a <code>&lt;IncludeFile file="plc-state.xml" /&gt;</code>
element. Modify the PlcId to be the same as the one you defined in the
<code>StrolchConfiguration.xml</code>. </p>
</li>
<li>Now that we have a model, the PlcConnections are to be defined. In the previous example we used a
Raspberry Pi's GPIOs. This needs to be defined as a PlcConnection:
<pre>
&lt;Resource Id="raspiBcmGpioOutput" Name="Raspi BCM GPIO Output" Type="PlcConnection"&gt;
&lt;ParameterBag Id="parameters" Name="Parameters" Type="Parameters"&gt;
&lt;Parameter Id="className" Name="Connection Class" Type="String" Value="li.strolch.plc.core.hw.gpio.RaspiBcmGpioOutputConnection"/&gt;
&lt;Parameter Id="state" Name="Connection State" Type="String" Interpretation="Enumeration" Uom="ConnectionState" Value="Disconnected"/&gt;
&lt;Parameter Id="stateMsg" Name="Connection State Msg" Type="String" Interpretation="Enumeration" Uom="ConnectionState"
Value=""/&gt;
&lt;Parameter Id="inverted" Name="Inverted" Type="Boolean" Value="false"/&gt;
&lt;Parameter Id="bcmOutputPins" Name="BCM Output Pins" Type="IntegerList" Value="27"/&gt;
&lt;/ParameterBag&gt;
&lt;/Resource&gt;
&lt;Resource Id="raspiBcmGpioInput" Name="Raspi BCM GPIO Input" Type="PlcConnection"&gt;
&lt;ParameterBag Id="parameters" Name="Parameters" Type="Parameters"&gt;
&lt;Parameter Id="className" Name="Connection Class" Type="String" Value="li.strolch.plc.core.hw.gpio.RaspiBcmGpioInputConnection"/&gt;
&lt;Parameter Id="state" Name="Connection State" Type="String" Interpretation="Enumeration" Uom="ConnectionState" Value="Disconnected"/&gt;
&lt;Parameter Id="stateMsg" Name="Connection State Msg" Type="String" Interpretation="Enumeration" Uom="ConnectionState"
Value=""/&gt;
&lt;Parameter Id="inverted" Name="Inverted" Type="Boolean" Value="true"/&gt;
&lt;Parameter Id="bcmInputPins" Name="BCM Input Pins" Type="IntegerList" Value="4"/&gt;
&lt;/ParameterBag&gt;
&lt;/Resource&gt;</pre>
<p>See
<a href="https://github.com/4treesCH/strolch-plc/blob/develop/example/strolch-plc-example-connections.xml">strolch-plc-example-connections.xml</a>
for further examples. </p>
</li>
</ol>
</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 xsd 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

@ -1,893 +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: Tutorial</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><a href="documentation.html">Documentation</a></li>
<li><a href="plc.html">PLC</a></li>
<li class="active"><a href="tutorial.html">Tutorial</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">Tutorial: Configuration</h1>
<p class="lead page-description">Configure the runtime</p>
</div>
<div class="content">
<a href="tutorial.html" class="pull-left">Previous: Start</a><a href="tutorial-model.html" class="pull-right">Next:
Model</a>
<br><br>
<p>Let's start by creating a new Apache Maven project. We'll need a POM with the proper dependencies. We expect
you to be familiar with Apache Maven, so we'll just show you a working POM file:</p>
<b>pom.xml</b>
<pre class="pre-scrollable">
&lt;?xml version="1.0"?&gt;
&lt;project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"&gt;
&lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;
&lt;groupId&gt;li.strolch&lt;/groupId&gt;
&lt;artifactId&gt;strolch-bookshop&lt;/artifactId&gt;
&lt;version&gt;0.1.0-SNAPSHOT&lt;/version&gt;
&lt;packaging&gt;war&lt;/packaging&gt;
&lt;name&gt;strolch-bookshop&lt;/name&gt;
&lt;description&gt;Bookshop built on Strolch&lt;/description&gt;
&lt;inceptionYear&gt;2017&lt;/inceptionYear&gt;
&lt;properties&gt;
&lt;project.build.sourceEncoding&gt;UTF-8&lt;/project.build.sourceEncoding&gt;
&lt;maven.build.timestamp.format&gt;yyyy-MM-dd HH:mm:ss&lt;/maven.build.timestamp.format&gt;
&lt;buildTimestamp&gt;${maven.build.timestamp}&lt;/buildTimestamp&gt;
&lt;jdk.version&gt;1.8&lt;/jdk.version&gt;
&lt;jersey.version&gt;2.25.1&lt;/jersey.version&gt;
&lt;slf4j.version&gt;1.7.25&lt;/slf4j.version&gt;
&lt;logback.version&gt;1.2.3&lt;/logback.version&gt;
&lt;petitparser.version&gt;2.1.0&lt;/petitparser.version&gt;
&lt;hikaricp.version&gt;2.7.1&lt;/hikaricp.version&gt;
&lt;postgresql.version&gt;42.1.4&lt;/postgresql.version&gt;
&lt;gson.version&gt;2.8.2&lt;/gson.version&gt;
&lt;annotation.version&gt;1.3.1&lt;/annotation.version&gt;
&lt;javaxmail.version&gt;1.6.0&lt;/javaxmail.version&gt;
&lt;serverlet.version&gt;3.1.0&lt;/serverlet.version&gt;
&lt;jaxrs.api.version&gt;2.1&lt;/jaxrs.api.version&gt;
&lt;junit.version&gt;4.12&lt;/junit.version&gt;
&lt;hamcrest.version&gt;1.3&lt;/hamcrest.version&gt;
&lt;mockito.version&gt;2.0.8-beta&lt;/mockito.version&gt;
&lt;maven-compiler-plugin.version&gt;3.7.0&lt;/maven-compiler-plugin.version&gt;
&lt;maven-source-plugin.version&gt;3.0.1&lt;/maven-source-plugin.version&gt;
&lt;maven-jar-plugin.version&gt;3.0.2&lt;/maven-jar-plugin.version&gt;
&lt;maven-war-plugin.version&gt;3.1.0&lt;/maven-war-plugin.version&gt;
&lt;strolch.version&gt;1.6.0-SNAPSHOT&lt;/strolch.version&gt;
&lt;warFinalName&gt;bookshop&lt;/warFinalName&gt;
&lt;m2eclipse.wtp.contextRoot&gt;${warFinalName}&lt;/m2eclipse.wtp.contextRoot&gt;
&lt;/properties&gt;
&lt;dependencies&gt;
&lt;!-- base --&gt;
&lt;dependency&gt;
&lt;groupId&gt;org.slf4j&lt;/groupId&gt;
&lt;artifactId&gt;slf4j-api&lt;/artifactId&gt;
&lt;version&gt;${slf4j.version}&lt;/version&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
&lt;groupId&gt;ch.qos.logback&lt;/groupId&gt;
&lt;artifactId&gt;logback-classic&lt;/artifactId&gt;
&lt;version&gt;${logback.version}&lt;/version&gt;
&lt;scope&gt;runtime&lt;/scope&gt;
&lt;/dependency&gt;
&lt;!-- strolch --&gt;
&lt;dependency&gt;
&lt;groupId&gt;li.strolch&lt;/groupId&gt;
&lt;artifactId&gt;li.strolch.utils&lt;/artifactId&gt;
&lt;version&gt;${strolch.version}&lt;/version&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
&lt;groupId&gt;li.strolch&lt;/groupId&gt;
&lt;artifactId&gt;li.strolch.privilege&lt;/artifactId&gt;
&lt;version&gt;${strolch.version}&lt;/version&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
&lt;groupId&gt;li.strolch&lt;/groupId&gt;
&lt;artifactId&gt;li.strolch.model&lt;/artifactId&gt;
&lt;version&gt;${strolch.version}&lt;/version&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
&lt;groupId&gt;li.strolch&lt;/groupId&gt;
&lt;artifactId&gt;li.strolch.agent&lt;/artifactId&gt;
&lt;version&gt;${strolch.version}&lt;/version&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
&lt;groupId&gt;li.strolch&lt;/groupId&gt;
&lt;artifactId&gt;li.strolch.rest&lt;/artifactId&gt;
&lt;version&gt;${strolch.version}&lt;/version&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
&lt;groupId&gt;li.strolch&lt;/groupId&gt;
&lt;artifactId&gt;li.strolch.service&lt;/artifactId&gt;
&lt;version&gt;${strolch.version}&lt;/version&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
&lt;groupId&gt;li.strolch&lt;/groupId&gt;
&lt;artifactId&gt;li.strolch.testbase&lt;/artifactId&gt;
&lt;version&gt;${strolch.version}&lt;/version&gt;
&lt;scope&gt;test&lt;/scope&gt;
&lt;/dependency&gt;
&lt;!-- utils --&gt;
&lt;dependency&gt;
&lt;groupId&gt;com.google.code.gson&lt;/groupId&gt;
&lt;artifactId&gt;gson&lt;/artifactId&gt;
&lt;version&gt;${gson.version}&lt;/version&gt;
&lt;/dependency&gt;
&lt;!-- web --&gt;
&lt;dependency&gt;
&lt;groupId&gt;javax.servlet&lt;/groupId&gt;
&lt;artifactId&gt;javax.servlet-api&lt;/artifactId&gt;
&lt;version&gt;${serverlet.version}&lt;/version&gt;
&lt;scope&gt;provided&lt;/scope&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
&lt;groupId&gt;javax.ws.rs&lt;/groupId&gt;
&lt;artifactId&gt;javax.ws.rs-api&lt;/artifactId&gt;
&lt;version&gt;${jaxrs.api.version}&lt;/version&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
&lt;groupId&gt;org.glassfish.jersey.core&lt;/groupId&gt;
&lt;artifactId&gt;jersey-common&lt;/artifactId&gt;
&lt;version&gt;${jersey.version}&lt;/version&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
&lt;groupId&gt;org.glassfish.jersey.core&lt;/groupId&gt;
&lt;artifactId&gt;jersey-server&lt;/artifactId&gt;
&lt;version&gt;${jersey.version}&lt;/version&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
&lt;groupId&gt;org.glassfish.jersey.containers&lt;/groupId&gt;
&lt;artifactId&gt;jersey-container-servlet&lt;/artifactId&gt;
&lt;version&gt;${jersey.version}&lt;/version&gt;
&lt;/dependency&gt;
&lt;!-- testing --&gt;
&lt;dependency&gt;
&lt;groupId&gt;junit&lt;/groupId&gt;
&lt;artifactId&gt;junit&lt;/artifactId&gt;
&lt;version&gt;${junit.version}&lt;/version&gt;
&lt;scope&gt;test&lt;/scope&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
&lt;groupId&gt;org.hamcrest&lt;/groupId&gt;
&lt;artifactId&gt;hamcrest-core&lt;/artifactId&gt;
&lt;version&gt;${hamcrest.version}&lt;/version&gt;
&lt;scope&gt;test&lt;/scope&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
&lt;groupId&gt;org.hamcrest&lt;/groupId&gt;
&lt;artifactId&gt;hamcrest-library&lt;/artifactId&gt;
&lt;version&gt;${hamcrest.version}&lt;/version&gt;
&lt;scope&gt;test&lt;/scope&gt;
&lt;/dependency&gt;
&lt;/dependencies&gt;
&lt;build&gt;
&lt;resources&gt;
&lt;!-- filter properties files, and copy the rest --&gt;
&lt;resource&gt;
&lt;directory&gt;src/main/resources&lt;/directory&gt;
&lt;filtering&gt;true&lt;/filtering&gt;
&lt;includes&gt;
&lt;include&gt;**/*.properties&lt;/include&gt;
&lt;/includes&gt;
&lt;/resource&gt;
&lt;resource&gt;
&lt;directory&gt;src/main/resources&lt;/directory&gt;
&lt;filtering&gt;false&lt;/filtering&gt;
&lt;excludes&gt;
&lt;exclude&gt;**/*.properties&lt;/exclude&gt;
&lt;/excludes&gt;
&lt;/resource&gt;
&lt;/resources&gt;
&lt;plugins&gt;
&lt;plugin&gt;
&lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
&lt;artifactId&gt;maven-compiler-plugin&lt;/artifactId&gt;
&lt;version&gt;${maven-compiler-plugin.version}&lt;/version&gt;
&lt;configuration&gt;
&lt;source&gt;${jdk.version}&lt;/source&gt;
&lt;target&gt;${jdk.version}&lt;/target&gt;
&lt;/configuration&gt;
&lt;/plugin&gt;
&lt;plugin&gt;
&lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
&lt;artifactId&gt;maven-war-plugin&lt;/artifactId&gt;
&lt;version&gt;${maven-war-plugin.version}&lt;/version&gt;
&lt;configuration&gt;
&lt;failOnMissingWebXml&gt;false&lt;/failOnMissingWebXml&gt;
&lt;warName&gt;${warFinalName}&lt;/warName&gt;
&lt;/configuration&gt;
&lt;/plugin&gt;
&lt;/plugins&gt;
&lt;/build&gt;
&lt;profiles&gt;
&lt;!-- active when building on eitch's machines --&gt;
&lt;profile&gt;
&lt;id&gt;m2e.eitchpc&lt;/id&gt;
&lt;activation&gt;
&lt;property&gt;
&lt;name&gt;user.name&lt;/name&gt;
&lt;value&gt;eitch&lt;/value&gt;
&lt;/property&gt;
&lt;os&gt;
&lt;family&gt;unix&lt;/family&gt;
&lt;/os&gt;
&lt;/activation&gt;
&lt;properties&gt;
&lt;strolch.env&gt;dev.eitchpc&lt;/strolch.env&gt;
&lt;/properties&gt;
&lt;/profile&gt;
&lt;/profiles&gt;
&lt;/project&gt;
</pre>
<p>Now we need the rest of the directory structure:</p>
<pre class="pre-scrollable">
../strolch-bookshop/
- src/main/java/
- li/strolch/bookshop/
- &lt;!-- java classes --&gt;
- src/main/resources/
- ENV.properties
- appVersion.properties
- logback.xml
- src/main/webapp/WEB-INF/
- StrolchBootstrap.xml
- runtime
- config/
- PrivilegeConfig.xml
- PrivilegeRoles.xml
- PrivilegeUsers.xml
- StrolchConfiguration.xml
- StrolchPolicies.xml
- data/
- StrolchModel.xsd
- defaultModel.xml
- templates.xml
- temp/
</pre>
<p>A few notes to the resource files:</p>
<ul>
<li>The <code>ENV.properties</code> file is filtered by maven and the environment to load is written in it
using the environment variable strolch.env.
</li>
<li>The <code>appVersion.properties</code> file is also filtered by maven and allows to reflect on the
version of this app at runtime.
</li>
<li>The <code>logback.xml</code> file configures logging using SLF4j and Logback.</li>
</ul>
<p>The <code>StrolchBootstrap.xml</code> file is used to configure Strolch's environment and root directory. For
a webapp it can be annoying to store Strolch's configuration inside the webapp, which is why we can define an
absolute path where the configuration is kept. In the following example we keep it in the root of the
sources:</p>
<pre class="pre-scrollable">
&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;StrolchBootstrap&gt;
&lt;env id="dev.eitchpc" default="true"&gt;
&lt;root&gt;/home/eitch/src/git/strolch-bookshop/runtime&lt;/root&gt;
&lt;environment&gt;dev&lt;/environment&gt;
&lt;/env&gt;
&lt;/StrolchBootstrap>
</pre>
<p>Here we define two environments, but the both redefine the environment to dev. This is because we want this
app to start on two different machines with different user home directories. See the profiles in the POM as
to how these environments are activated using a environment property strolch.env.</p>
<p>In this next step we'll create Strolch's configuration at the location we defined in the StrolchBootstrap.xml
file. Strolch's configuration contains of three directories: config, data and temp. config contains static
files which usually aren't changed, data contains model files in XML format and temp is used at runtime for
any temporary files, e.g. storing active sessions.</p>
<p>The configuration as well as the model has been described on Strolch's documentation web page, we'll just
provide you with the files for the bookshop:</p>
<b>PrivilegeConfig.xml</b>
<pre class="pre-scrollable">
&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;Privilege&gt;
&lt;Container&gt;
&lt;Parameters&gt;
&lt;!-- parameters for the container itself --&gt;
&lt;Parameter name="secretKey" value="45f251ce-d51f-4624-990a-8dcd5b181f0e"/&gt;
&lt;Parameter name="secretSalt" value="4770a32d-1512-4891-9a63-362504932500"/&gt;
&lt;Parameter name="persistSessions" value="true"/&gt;
&lt;Parameter name="autoPersistOnUserChangesData" value="false"/&gt;
&lt;Parameter name="privilegeConflictResolution" value="MERGE"/&gt;
&lt;/Parameters&gt;
&lt;EncryptionHandler class="li.strolch.privilege.handler.DefaultEncryptionHandler"&gt;
&lt;Parameters&gt;
&lt;Parameter name="hashAlgorithm" value="PBKDF2WithHmacSHA512"/&gt;
&lt;Parameter name="hashIterations" value="10000"/&gt;
&lt;Parameter name="hashKeyLength" value="256"/&gt;
&lt;/Parameters&gt;
&lt;/EncryptionHandler&gt;
&lt;PersistenceHandler class="li.strolch.privilege.handler.XmlPersistenceHandler"&gt;
&lt;Parameters&gt;
&lt;Parameter name="usersXmlFile" value="PrivilegeUsers.xml"/&gt;
&lt;Parameter name="rolesXmlFile" value="PrivilegeRoles.xml"/&gt;
&lt;/Parameters&gt;
&lt;/PersistenceHandler&gt;
&lt;UserChallengeHandler class="li.strolch.privilege.handler.MailUserChallengeHandler"&gt;
&lt;/UserChallengeHandler&gt;
&lt;/Container&gt;
&lt;Policies&gt;
&lt;Policy name="DefaultPrivilege" class="li.strolch.privilege.policy.DefaultPrivilege"/&gt;
&lt;Policy name="RoleAccessPrivilege" class="li.strolch.privilege.policy.RoleAccessPrivilege"/&gt;
&lt;Policy name="UserAccessPrivilege" class="li.strolch.privilege.policy.UserAccessPrivilege"/&gt;
&lt;Policy name="UserSessionAccessPrivilege" class="li.strolch.privilege.policy.UsernameFromCertificatePrivilege"/&gt;
&lt;/Policies&gt;
&lt;/Privilege&gt;
</pre>
<b>PrivilegeRoles.xml</b>
<pre class="pre-scrollable">
&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;Roles&gt;
&lt;Role name="User"&gt;
&lt;Privilege name="li.strolch.service.api.Service" policy="DefaultPrivilege"&gt;
&lt;/Privilege&gt;
&lt;Privilege name="li.strolch.search.StrolchSearch" policy="DefaultPrivilege"&gt;
&lt;AllAllowed>true&lt;/AllAllowed&gt;
&lt;Allow&gt;li.strolch.bookshop.search.BookSearch&lt;/Allow&gt;
&lt;/Privilege&gt;
&lt;Privilege name="GetResource" policy="ModelPrivilege"&gt;
&lt;AllAllowed&gt;true&lt;/AllAllowed&gt;
&lt;/Privilege&gt;
&lt;Privilege name="GetOrder" policy="ModelPrivilege"&gt;
&lt;AllAllowed&gt;true&lt;/AllAllowed&gt;
&lt;/Privilege&gt;
&lt;Privilege name="GetActivity" policy="ModelPrivilege"&gt;
&lt;AllAllowed&gt;true&lt;/AllAllowed&gt;
&lt;/Privilege&gt;
&lt;Privilege name="AddResource" policy="ModelPrivilege"&gt;
&lt;AllAllowed&gt;true&lt;/AllAllowed&gt;
&lt;/Privilege&gt;
&lt;Privilege name="AddOrder" policy="ModelPrivilege"&gt;
&lt;AllAllowed&gt;true&lt;/AllAllowed&gt;
&lt;/Privilege&gt;
&lt;Privilege name="AddActivity" policy="ModelPrivilege"&gt;
&lt;AllAllowed&gt;true&lt;/AllAllowed&gt;
&lt;/Privilege&gt;
&lt;Privilege name="UpdateResource" policy="ModelPrivilege"&gt;
&lt;AllAllowed&gt;true&lt;/AllAllowed&gt;
&lt;/Privilege&gt;
&lt;Privilege name="UpdateOrder" policy="ModelPrivilege"&gt;
&lt;AllAllowed&gt;true&lt;/AllAllowed&gt;
&lt;/Privilege&gt;
&lt;Privilege name="UpdateActivity" policy="ModelPrivilege"&gt;
&lt;AllAllowed&gt;true&lt;/AllAllowed&gt;
&lt;/Privilege&gt;
&lt;Privilege name="RemoveResource" policy="ModelPrivilege"&gt;
&lt;AllAllowed&gt;true&lt;/AllAllowed&gt;
&lt;/Privilege&gt;
&lt;Privilege name="RemoveOrder" policy="ModelPrivilege"&gt;
&lt;AllAllowed&gt;true&lt;/AllAllowed&gt;
&lt;/Privilege&gt;
&lt;Privilege name="RemoveActivity" policy="ModelPrivilege"&gt;
&lt;AllAllowed&gt;true&lt;/AllAllowed&gt;
&lt;/Privilege&gt;
&lt;/Role&gt;
&lt;Role name="UserPrivileges"&gt;
&lt;Privilege name="PrivilegeSetUserLocale" policy="UserAccessPrivilege" /&gt;
&lt;Privilege name="PrivilegeSetUserPassword" policy="UserAccessPrivilege" /&gt;
&lt;/Role&gt;
&lt;!--
Internal
--&gt;
&lt;Role name="StrolchAdmin"&gt;
&lt;Privilege name="li.strolch.service.api.Service" policy="DefaultPrivilege"&gt;
&lt;AllAllowed&gt;true&lt;/AllAllowed&gt;
&lt;/Privilege&gt;
&lt;Privilege name="li.strolch.search.StrolchSearch" policy="DefaultPrivilege"&gt;
&lt;AllAllowed>true&lt;/AllAllowed&gt;
&lt;/Privilege&gt;
&lt;Privilege name="GetResource" policy="ModelPrivilege"&gt;
&lt;AllAllowed&gt;true&lt;/AllAllowed&gt;
&lt;/Privilege&gt;
&lt;Privilege name="GetOrder" policy="ModelPrivilege"&gt;
&lt;AllAllowed&gt;true&lt;/AllAllowed&gt;
&lt;/Privilege&gt;
&lt;Privilege name="GetActivity" policy="ModelPrivilege"&gt;
&lt;AllAllowed&gt;true&lt;/AllAllowed&gt;
&lt;/Privilege&gt;
&lt;Privilege name="AddResource" policy="ModelPrivilege"&gt;
&lt;AllAllowed&gt;true&lt;/AllAllowed&gt;
&lt;/Privilege&gt;
&lt;Privilege name="AddOrder" policy="ModelPrivilege"&gt;
&lt;AllAllowed&gt;true&lt;/AllAllowed&gt;
&lt;/Privilege&gt;
&lt;Privilege name="AddActivity" policy="ModelPrivilege"&gt;
&lt;AllAllowed&gt;true&lt;/AllAllowed&gt;
&lt;/Privilege&gt;
&lt;Privilege name="UpdateResource" policy="ModelPrivilege"&gt;
&lt;AllAllowed&gt;true&lt;/AllAllowed&gt;
&lt;/Privilege&gt;
&lt;Privilege name="UpdateOrder" policy="ModelPrivilege"&gt;
&lt;AllAllowed&gt;true&lt;/AllAllowed&gt;
&lt;/Privilege&gt;
&lt;Privilege name="UpdateActivity" policy="ModelPrivilege"&gt;
&lt;AllAllowed&gt;true&lt;/AllAllowed&gt;
&lt;/Privilege&gt;
&lt;Privilege name="RemoveResource" policy="ModelPrivilege"&gt;
&lt;AllAllowed&gt;true&lt;/AllAllowed&gt;
&lt;/Privilege&gt;
&lt;Privilege name="RemoveOrder" policy="ModelPrivilege"&gt;
&lt;AllAllowed&gt;true&lt;/AllAllowed&gt;
&lt;/Privilege&gt;
&lt;Privilege name="RemoveActivity" policy="ModelPrivilege"&gt;
&lt;AllAllowed&gt;true&lt;/AllAllowed&gt;
&lt;/Privilege&gt;
&lt;Privilege name="PrivilegeAddUser" policy="UserAccessPrivilege"&gt;
&lt;AllAllowed&gt;true&lt;/AllAllowed&gt;
&lt;/Privilege&gt;
&lt;Privilege name="PrivilegeSetUserPassword" policy="UserAccessPrivilege"&gt;
&lt;AllAllowed&gt;true&lt;/AllAllowed&gt;
&lt;/Privilege&gt;
&lt;/Role&gt;
&lt;Role name="agent"&gt;
&lt;Privilege name="li.strolch.privilege.handler.SystemAction" policy="DefaultPrivilege"&gt;
&lt;Allow&gt;li.strolch.runtime.privilege.StrolchSystemAction&lt;/Allow&gt;
&lt;Allow&gt;li.strolch.runtime.privilege.StrolchSystemActionWithResult&lt;/Allow&gt;
&lt;Allow&gt;li.strolch.persistence.postgresql.PostgreSqlSchemaInitializer&lt;/Allow&gt;
&lt;/Privilege&gt;
&lt;Privilege name="li.strolch.service.api.Service" policy="DefaultPrivilege"&gt;
&lt;AllAllowed&gt;true&lt;/AllAllowed&gt;
&lt;/Privilege&gt;
&lt;Privilege name="li.strolch.model.query.StrolchQuery" policy="DefaultPrivilege"&gt;
&lt;AllAllowed&gt;true&lt;/AllAllowed&gt;
&lt;/Privilege&gt;
&lt;Privilege name="li.strolch.search.StrolchSearch" policy="DefaultPrivilege"&gt;
&lt;AllAllowed>true&lt;/AllAllowed&gt;
&lt;/Privilege&gt;
&lt;Privilege name="GetResource" policy="ModelPrivilege"&gt;
&lt;AllAllowed&gt;true&lt;/AllAllowed&gt;
&lt;/Privilege&gt;
&lt;Privilege name="GetOrder" policy="ModelPrivilege"&gt;
&lt;AllAllowed&gt;true&lt;/AllAllowed&gt;
&lt;/Privilege&gt;
&lt;Privilege name="GetActivity" policy="ModelPrivilege"&gt;
&lt;AllAllowed&gt;true&lt;/AllAllowed&gt;
&lt;/Privilege&gt;
&lt;Privilege name="AddResource" policy="ModelPrivilege"&gt;
&lt;AllAllowed&gt;true&lt;/AllAllowed&gt;
&lt;/Privilege&gt;
&lt;Privilege name="AddOrder" policy="ModelPrivilege"&gt;
&lt;AllAllowed&gt;true&lt;/AllAllowed&gt;
&lt;/Privilege&gt;
&lt;Privilege name="AddActivity" policy="ModelPrivilege"&gt;
&lt;AllAllowed&gt;true&lt;/AllAllowed&gt;
&lt;/Privilege&gt;
&lt;Privilege name="UpdateResource" policy="ModelPrivilege"&gt;
&lt;AllAllowed&gt;true&lt;/AllAllowed&gt;
&lt;/Privilege&gt;
&lt;Privilege name="UpdateOrder" policy="ModelPrivilege"&gt;
&lt;AllAllowed&gt;true&lt;/AllAllowed&gt;
&lt;/Privilege&gt;
&lt;Privilege name="UpdateActivity" policy="ModelPrivilege"&gt;
&lt;AllAllowed&gt;true&lt;/AllAllowed&gt;
&lt;/Privilege&gt;
&lt;Privilege name="RemoveResource" policy="ModelPrivilege"&gt;
&lt;AllAllowed&gt;true&lt;/AllAllowed&gt;
&lt;/Privilege&gt;
&lt;Privilege name="RemoveOrder" policy="ModelPrivilege"&gt;
&lt;AllAllowed&gt;true&lt;/AllAllowed&gt;
&lt;/Privilege&gt;
&lt;Privilege name="RemoveActivity" policy="ModelPrivilege"&gt;
&lt;AllAllowed&gt;true&lt;/AllAllowed&gt;
&lt;/Privilege&gt;
&lt;Privilege name="PrivilegeAction" policy="DefaultPrivilege"&gt;
&lt;Allow&gt;Persist&lt;/Allow&gt;
&lt;Allow&gt;PersistSessions&lt;/Allow&gt;
&lt;Allow&gt;GetCertificates&lt;/Allow&gt;
&lt;/Privilege&gt;
&lt;Privilege name="PrivilegeAddUser" policy="UserAccessPrivilege"&gt;
&lt;AllAllowed&gt;true&lt;/AllAllowed&gt;
&lt;/Privilege&gt;
&lt;Privilege name="PrivilegeModifyUser" policy="UserAccessPrivilege"&gt;
&lt;AllAllowed&gt;true&lt;/AllAllowed&gt;
&lt;/Privilege&gt;
&lt;Privilege name="PrivilegeGetUser" policy="UserAccessPrivilege"&gt;
&lt;AllAllowed&gt;true&lt;/AllAllowed&gt;
&lt;/Privilege&gt;
&lt;/Role&gt;
&lt;/Roles&gt;
</pre>
<b>PrivilegeUsers.xml</b>
<pre class="pre-scrollable">
&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;Users&gt;
&lt;User userId="U10" username="jill" password="8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918"&gt;
&lt;Firstname&gt;Jill&lt;/Firstname&gt;
&lt;Lastname&gt;Someone&lt;/Lastname&gt;
&lt;State&gt;ENABLED&lt;/State&gt;
&lt;Locale&gt;en-GB&lt;/Locale&gt;
&lt;Roles&gt;
&lt;Role&gt;User&lt;/Role&gt;
&lt;Role&gt;UserPrivileges&lt;/Role&gt;
&lt;/Roles&gt;
&lt;Properties&gt;
&lt;Property name="email" value="eitch+jill@eitchnet.ch" /&gt;
&lt;/Properties&gt;
&lt;/User&gt;
&lt;User userId="U01" username="admin" password="8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918"&gt;
&lt;Firstname&gt;Jill&lt;/Firstname&gt;
&lt;Lastname&gt;Someone&lt;/Lastname&gt;
&lt;State&gt;ENABLED&lt;/State&gt;
&lt;Locale&gt;en-GB&lt;/Locale&gt;
&lt;Roles&gt;
&lt;Role&gt;StrolchAdmin&lt;/Role&gt;
&lt;Role&gt;UserPrivileges&lt;/Role&gt;
&lt;/Roles&gt;
&lt;Properties&gt;
&lt;Property name="email" value="eitch+admin@eitchnet.ch" /&gt;
&lt;/Properties&gt;
&lt;/User&gt;
&lt;!--
Internal
--&gt;
&lt;User userId="S01" username="agent"&gt;
&lt;State&gt;SYSTEM&lt;/State&gt;
&lt;Roles&gt;
&lt;Role&gt;agent&lt;/Role&gt;
&lt;/Roles&gt;
&lt;/User&gt;
&lt;/Users&gt;
</pre>
<b>StrolchConfiguration.xml</b>
<pre class="pre-scrollable">
&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;StrolchConfiguration&gt;
&lt;env id="global"&gt;
&lt;Runtime&gt;
&lt;applicationName&gt;Bookshop&lt;/applicationName&gt;
&lt;Properties&gt;
&lt;locale&gt;en&lt;/locale&gt;
&lt;verbose&gt;true&lt;/verbose&gt;
&lt;/Properties&gt;
&lt;/Runtime&gt;
&lt;Component&gt;
&lt;name&gt;PrivilegeHandler&lt;/name&gt;
&lt;api&gt;li.strolch.runtime.privilege.PrivilegeHandler&lt;/api&gt;
&lt;impl&gt;li.strolch.runtime.privilege.DefaultStrolchPrivilegeHandler&lt;/impl&gt;
&lt;Properties&gt;
&lt;privilegeConfigFile&gt;PrivilegeConfig.xml&lt;/privilegeConfigFile&gt;
&lt;/Properties&gt;
&lt;/Component&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;Properties&gt;
&lt;realms&gt;defaultRealm&lt;/realms&gt;
&lt;dataStoreMode&gt;TRANSIENT&lt;/dataStoreMode&gt;
&lt;dataStoreFile&gt;defaultModel.xml&lt;/dataStoreFile&gt;
&lt;enableObserverUpdates&gt;true&lt;/enableObserverUpdates&gt;
&lt;/Properties&gt;
&lt;/Component&gt;
&lt;Component&gt;
&lt;name&gt;ServiceHandler&lt;/name&gt;
&lt;api&gt;li.strolch.service.api.ServiceHandler&lt;/api&gt;
&lt;impl&gt;li.strolch.service.api.DefaultServiceHandler&lt;/impl&gt;
&lt;depends&gt;RealmHandler&lt;/depends&gt;
&lt;depends&gt;PrivilegeHandler&lt;/depends&gt;
&lt;Properties&gt;
&lt;verbose&gt;true&lt;/verbose&gt;
&lt;/Properties&gt;
&lt;/Component&gt;
&lt;Component&gt;
&lt;name&gt;PolicyHandler&lt;/name&gt;
&lt;api&gt;li.strolch.policy.PolicyHandler&lt;/api&gt;
&lt;impl&gt;li.strolch.policy.DefaultPolicyHandler&lt;/impl&gt;
&lt;Properties&gt;
&lt;readPolicyFile&gt;true&lt;/readPolicyFile&gt;
&lt;/Properties&gt;
&lt;/Component&gt;
&lt;Component&gt;
&lt;name&gt;ExecutionHandler&lt;/name&gt;
&lt;api&gt;li.strolch.execution.ExecutionHandler&lt;/api&gt;
&lt;impl&gt;li.strolch.execution.EventBasedExecutionHandler&lt;/impl&gt;
&lt;depends&gt;RealmHandler&lt;/depends&gt;
&lt;depends&gt;PrivilegeHandler&lt;/depends&gt;
&lt;/Component&gt;
&lt;Component&gt;
&lt;name&gt;RestfulHandler&lt;/name&gt;
&lt;api&gt;li.strolch.rest.RestfulStrolchComponent&lt;/api&gt;
&lt;impl&gt;li.strolch.rest.RestfulStrolchComponent&lt;/impl&gt;
&lt;depends&gt;SessionHandler&lt;/depends&gt;
&lt;Properties&gt;
&lt;secureCookie&gt;false&lt;/secureCookie&gt;
&lt;restLogging&gt;false&lt;/restLogging&gt;
&lt;restLoggingEntity&gt;false&lt;/restLoggingEntity&gt;
&lt;restTracing&gt;ALL&lt;/restTracing&gt;
&lt;/Properties&gt;
&lt;/Component&gt;
&lt;Component&gt;
&lt;name&gt;SessionHandler&lt;/name&gt;
&lt;api&gt;li.strolch.rest.StrolchSessionHandler&lt;/api&gt;
&lt;impl&gt;li.strolch.rest.DefaultStrolchSessionHandler&lt;/impl&gt;
&lt;depends&gt;PrivilegeHandler&lt;/depends&gt;
&lt;Properties&gt;
&lt;session.ttl.minutes&gt;30&lt;/session.ttl.minutes&gt;
&lt;session.reload&gt;true&lt;/session.reload&gt;
&lt;/Properties&gt;
&lt;/Component&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;fromAddr&gt;relayer@eitchnet.ch&lt;/fromAddr&gt;
&lt;fromName&gt;Susi&lt;/fromName&gt;
&lt;overrideRecipients&gt;IPSC Test &lt;eitch@eitchnet.ch&gt;&lt;/overrideRecipients&gt;
&lt;recipientWhitelist&gt;eitch@eitchnet.ch&lt;/recipientWhitelist&gt;
&lt;username&gt;test&lt;/username&gt;
&lt;password&gt;test&lt;/password&gt;
&lt;auth&gt;true&lt;/auth&gt;
&lt;startTls&gt;true&lt;/startTls&gt;
&lt;host&gt;smtp.gmail.com&lt;/host&gt;
&lt;port&gt;587&lt;/port&gt;
&lt;/Properties&gt;
&lt;/Component&gt;
&lt;/env&gt;
&lt;env id="dev"&gt;
&lt;!-- overrides go here --&gt;
&lt;/env&gt;
&lt;/StrolchConfiguration&gt;
</pre>
<b>StrolchPolicies.xml</b>
<pre class="pre-scrollable">
&lt;StrolchPolicies&gt;
&lt;PolicyType Type="ExecutionPolicy" Api="li.strolch.execution.policy.ExecutionPolicy"&gt;
&lt;Policy Key="DurationExecution" Class="li.strolch.execution.policy.DurationExecution" /&gt;
&lt;Policy Key="ReservationExection" Class="li.strolch.execution.policy.ReservationExection" /&gt;
&lt;/PolicyType&gt;
&lt;PolicyType Type="ConfirmationPolicy" Api="li.strolch.execution.policy.ConfirmationPolicy"&gt;
&lt;Policy Key="DefaultConfirmation" Class="li.strolch.execution.policy.ConfirmationPolicy" /&gt;
&lt;/PolicyType&gt;
&lt;PolicyType Type="ActivityArchivalPolicy" Api="li.strolch.execution.policy.ActivityArchivalPolicy"&gt;
&lt;Policy Key="DefaultActivityArchival" Class="li.strolch.execution.policy.ActivityArchivalPolicy" /&gt;
&lt;/PolicyType&gt;
&lt;/StrolchPolicies&gt;
</pre>
<p>A few notes on the configuration:</p>
<ul>
<li>Note how there are three users. Jill is a user with currently no privileges as it's role definition is
empty. Admin can do everything, and the agent user is a system user which can also do everything.
</li>
<li>There is one realm defined in the <code>RealmHandler</code> component which references the <code>defaultModel.xml</code>
file in the data directory. This file then includes the currently still empty <code>templates.xml</code>
file.
</li>
<li>We have defined a global environment, but are using the dev environment. The dev environment includes
the definitions in the global environment.
</li>
<li>In <code>PrivilegeConfig.xml</code> we have enabled persistence of sessions, so you will be needing the
unlimited JCE libraries for your JVM and when you restart the server, you don't need to log back in, if
your session is still alive.
</li>
<li>In <code>PrivilegeRoles.xml</code> there seems to be a lot of boilerplate. One thing about a highly
configurable system is that sometimes the configuration is bigger. In this case we have opted to have
the configuration shown and not use default values which you don't see, so that privilege acces is
clearly seen.
</li>
</ul>
<p>Your project is now ready to be imported into your favourite IDE. We have used both IntelliJ and Eclipse so
this is up to you.</p>
Now that we have a configuration, it is time to have Strolch started when the WAR is deployed and started. In
your IDE create a new class as follows:</p>
<b>StartupListener.java</b>
<pre class="pre-scrollable">
package li.strolch.bookshop.web;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
import java.io.InputStream;
import li.strolch.agent.api.StrolchAgent;
import li.strolch.agent.api.StrolchBootstrapper;
import li.strolch.utils.helper.StringHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@WebListener
public class StartupListener implements ServletContextListener {
private static final Logger logger = LoggerFactory.getLogger(StartupListener.class);
private static final String APP_NAME = "Bookshop";
private StrolchAgent agent;
@Override
public void contextInitialized(ServletContextEvent sce) {
logger.info("Starting " + APP_NAME + "...");
long start = System.currentTimeMillis();
try {
String boostrapFileName = "/WEB-INF/" + StrolchBootstrapper.FILE_BOOTSTRAP;
InputStream bootstrapFile = sce.getServletContext().getResourceAsStream(boostrapFileName);
StrolchBootstrapper bootstrapper = new StrolchBootstrapper(StartupListener.class);
this.agent = bootstrapper.setupByBoostrapFile(StartupListener.class, bootstrapFile);
this.agent.initialize();
this.agent.start();
} catch (Throwable e) {
logger.error("Failed to start " + APP_NAME + " due to: " + e.getMessage(), e);
throw e;
}
long took = System.currentTimeMillis() - start;
logger.info("Started " + APP_NAME + " in " + (StringHelper.formatMillisecondsDuration(took)));
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
if (this.agent != null) {
logger.info("Destroying " + APP_NAME + "...");
try {
this.agent.stop();
this.agent.destroy();
} catch (Throwable e) {
logger.error("Failed to stop " + APP_NAME + " due to: " + e.getMessage(), e);
throw e;
}
}
logger.info("Destroyed " + APP_NAME);
}
}
</pre>
<p>Now configure your IDE to start the web project, and then once it has started, you should see the following
in the logs:</p>
<pre class="pre-scrollable">
Bookshop:dev All 8 Strolch Components started. Took 44ms. Strolch is now ready to be used. Have fun =))
</pre>
<p>This log tells us the name of the app as defined in the StrolchConfiguration.xml file as well as which
environment was loaded. Further we can see that 8 components were configured and started.</p>
<p>This concludes the initial setup of a new Strolch project. We can now go ahead and start building the
business logic.</p>
<!-- content here -->
<a href="tutorial.html" class="pull-left">Previous: Start</a><a href="tutorial-model.html" class="pull-right">Next:
Model</a>
</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 xsd 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

@ -1,623 +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: Tutorial CRUD Book</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><a href="documentation.html">Documentation</a></li>
<li><a href="plc.html">PLC</a></li>
<li class="active"><a href="tutorial.html">Tutorial</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">Tutorial: CRUD Book</h1>
<p class="lead page-description">Writing the CRUD services for books.</p>
</div>
<div class="content">
<a href="tutorial-model.html" class="pull-left">Previous: Model</a> <br><br>
<h3>Preparation</h3>
<p>Since Books are central to the bookshop, we'll first create the <a target="_blank"
href="https://en.wikipedia.org/wiki/Create,_read,_update_and_delete">CRUD</a>
REST API for them. The API will be as follows:</p>
<pre>
GET ../rest/books?query=,offset=,limit=
GET ../rest/books/{id}
POST ../rest/books
PUT ../rest/books/{id}
DELETE ../rest/books/{id}
</pre>
<p>Thus corresponding with querying, getting, creating, updating and removing of books. So let's go ahead and
add these REST APIs to our project.</p>
<p>Our project is using JAX-RS 2.0 as the API and Jersey 2.x as the implementation, thus first we need to
configure JAX-RS. Thus create the following class:</p>
<pre class="pre-scrollable">
@ApplicationPath("rest")
public class RestfulApplication extends ResourceConfig {
public RestfulApplication() {
// add strolch resources
register(AuthenticationService.class);
register(ModelQuery.class);
register(Inspector.class);
// add project resources by package name
packages(BooksResource.class.getPackage().getName());
// filters
register(AuthenticationRequestFilter.class, Priorities.AUTHENTICATION);
register(AccessControlResponseFilter.class);
register(AuthenticationResponseFilter.class);
register(HttpCacheResponseFilter.class);
// log exceptions and return them as plain text to the caller
register(StrolchRestfulExceptionMapper.class);
// the JSON generated is in UTF-8
register(CharsetResponseFilter.class);
RestfulStrolchComponent restfulComponent = RestfulStrolchComponent.getInstance();
if (restfulComponent.isRestLogging()) {
register(new LoggingFeature(java.util.logging.Logger.getLogger(LoggingFeature.DEFAULT_LOGGER_NAME),
Level.SEVERE, LoggingFeature.Verbosity.PAYLOAD_ANY, Integer.MAX_VALUE));
property(ServerProperties.TRACING, "ALL");
property(ServerProperties.TRACING_THRESHOLD, "TRACE");
}
}
}
</pre>
<p>As we add new resources they will be automatically since we register the entire package.</p>
<p>Now add the books resource class:</p>
<pre>
@Path("books")
public class BooksResource {
}
</pre>
<h3>Search</h3>
<p>The first service we'll add is to query, or search for the existing books. The API defines three parameters,
with which the result can be controlled. The method can be defined as follows:</p>
<pre>
@GET
@Produces(MediaType.APPLICATION_JSON)
public Response query(@Context HttpServletRequest request, @QueryParam("query") String queryS,
@QueryParam("offset") String offsetS, @QueryParam("limit") String limitS) {
// TODO
}
</pre>
<p>To fill this method we need a few things. First let's define a constants class where we keep String constants
which we used in the model file:</p>
<pre>
public class BookShopConstants {
public static final String TYPE_BOOK = "Book";
}
</pre>
<p>As this tutorial progresses, more and more constants will be added here. This class helps with two issues:
Through the constants we can easily reason over where certain fields, and types are used and of course String
literals in code are a rather bad thing.</p>
<p>In Strolch there are multiple way to access objects. The old way was using Queries, the new search API is
much more fluent and easier to read and write. The search API, as well as the deprecated query API allows us
to implement privilege validation and thus one should create corresponding classes for each type of search.
Book entities are Resources, thus we will be creating a <code>ResourceSearch</code>. The search is for
Resources of type Book thus the resulting search looks as follows:</p>
<pre>
public class BooksSearch&lt;U&gt; extends ResourceSearch&lt;U&gt; {
public BookSearch() {
types(TYPE_BOOK);
}
public BookSearch stringQuery(String value) {
if (isEmpty(value))
return this;
// split by spaces
value = value.trim();
String[] values = value.split(" ");
// add where clauses for id, name and description
where(id().containsIgnoreCase(values) //
.or(name().containsIgnoreCase(values)) //
.or(param(BAG_PARAMETERS, PARAM_DESCRIPTION).containsIgnoreCase(values)));
return this;
}
}
</pre>
<p>Note how we added a special method <code>stringQuery(String)</code> - this method defines where a search
string entered by the user will be used to match a book. In this case for <code>ID</code>, <code>name</code>
and the <code>description</code> parameter.</p>
<p>So that our users can call this query, we must give them this as a privilege. This is done by adding the full
class name to the <code>PrivilegeRoles.xml</code> file as follows:</p>
<pre>
...
&lt;Role name="User"&gt;
&lt;Privilege name="li.strolch.search.StrolchSearch" policy="DefaultPrivilege"&gt;
&lt;Allow&gt;internal&lt;/Allow&gt;
&lt;Allow&gt;li.strolch.bookshop.search.BookSearch&lt;/Allow&gt;
&lt;/Privilege&gt;
&lt;/Role&gt;
...
</pre>
<p><b>Note:</b> The <code>internal</code> allow value is a special privilege which is used internally when a
service or something performs internal queries. This means that a service can perform a query
for object to which the user might not have access, but without which the service could not be
completed. We will use this in a later stage. </p>
<p>Now we have all parts we need to implement the query method. The method will include opening a transaction,
instantiating the search, executing the search, and returning the result:</p>
<pre class="pre-scrollable">
@Path("books")
public class BooksResource {
@GET
@Produces(MediaType.APPLICATION_JSON)
public Response query(@Context HttpServletRequest request, @QueryParam("query") String queryS,
@QueryParam("offset") String offsetS, @QueryParam("limit") String limitS) {
// this is an authenticated method call, thus we can get the certificate from the request:
Certificate cert = (Certificate) request.getAttribute(StrolchRestfulConstants.STROLCH_CERTIFICATE);
int offset = StringHelper.isNotEmpty(offsetS) ? Integer.valueOf(offsetS) : 0;
int limit = StringHelper.isNotEmpty(limitS) ? Integer.valueOf(limitS) : 0;
// open the TX with the certificate, using this class as context
Paging&lt;Resource&gt; paging;
try (StrolchTransaction tx = RestfulStrolchComponent.getInstance().openTx(cert, getClass())) {
// perform a book search
paging = new BookSearch() //
.stringQuery(queryS) //
.search(tx) //
.orderByName(false) //
.toPaging(offset, limit);
}
ResourceVisitor&lt;JsonObject&gt; visitor = new StrolchRootElementToJsonVisitor().flat().asResourceVisitor();
return ResponseUtil.toResponse(paging, e -&gt; e.accept(visitor));
}
}
</pre>
<p><b>Note:</b> We automatically transform the Resource objects to JSON using the <code>StrolchElementToJsonVisitor</code>.
By calling the method <code>.flat()</code> we have a more compact JSON format. Paging is handled
by a util class.</p>
<p>The helper class <code>ResponseUtil</code> takes care of creating the JsonObject and the proper page. As a
rule we use the format where we return two fields: <code>msg</code> is a dash if all is ok, otherwise an
error message will be present. Data is always in the <code>data</code> field. This is just a personal taste,
and can be changed to one's own taste.</p>
<h3>Get</h3>
We have all we need now to implement the GET method:
<pre class="pre-scrollable">
@GET
@Path("{id}")
@Produces(MediaType.APPLICATION_JSON)
public Response get(@Context HttpServletRequest request, @PathParam("id") String id) {
// this is an authenticated method call, thus we can get the certificate from the request:
Certificate cert = (Certificate) request.getAttribute(StrolchRestfulConstants.STROLCH_CERTIFICATE);
// open the TX with the certificate, using this class as context
try (StrolchTransaction tx = RestfulStrolchComponent.getInstance().openTx(cert, getClass())) {
// get the book
Resource book = tx.getResourceBy(BookShopConstants.TYPE_BOOK, id);
if (book == null)
return ResponseUtil.toResponse(Status.NOT_FOUND, "Book " + id + " does not exist!");
// transform to JSON
JsonObject bookJ = book.accept(new StrolchRootElementToJsonVisitor().flat());
// return
return ResponseUtil.toResponse(StrolchRestfulConstants.DATA, bookJ);
}
}
</pre>
<p>Note how we simply retrieve the book as a Resource from the TX. This is a good moment to familiarize yourself
with the API of the <code>StrolchTransaction</code>. There are methods to retrieve elements, and also perform
queries. We will use more of these methods later.</p>
<p>Further it can be noted that a simple retrieval isn't validated against the user's privileges, the user is
authenticated, which is enough for the moment.</p>
<h3>Create</h3>
To create a new book we need to implement a <code>Service</code>. This service will be called <code>CreateBookService</code>.
A Service always has a <code>ServiceArgument</code> and a <code>ServiceResult</code>. Our service will use the
<code>JsonServiceArgument</code> and the <code>JsonServiceResult</code>. The implementation of the POST method
is as follows:
<pre class="pre-scrollable">
@POST
@Produces(MediaType.APPLICATION_JSON)
public Response create(@Context HttpServletRequest request, String data) {
// this is an authenticated method call, thus we can get the certificate from the request:
Certificate cert = (Certificate) request.getAttribute(StrolchRestfulConstants.STROLCH_CERTIFICATE);
// parse data to JSON
JsonObject jsonData = JsonParser.parseString(data).getAsJsonObject();
// instantiate the service with the argument
CreateBookService svc = new CreateBookService();
JsonServiceArgument arg = svc.getArgumentInstance();
arg.jsonElement = jsonData;
// perform the service
ServiceHandler serviceHandler = RestfulStrolchComponent.getInstance().getServiceHandler();
JsonServiceResult result = serviceHandler.doService(cert, svc, arg);
// return depending on the result state
if (result.isOk())
return ResponseUtil.toResponse(StrolchRestfulConstants.DATA, result.getResult());
return ResponseUtil.toResponse(result);
}
</pre>
<p><b>Note:</b> We return the created object again as JSON in its own data field.</p>
The service is implemented as follows:
<pre class="pre-scrollable">
public class CreateBookService extends AbstractService&lt;JsonServiceArgument, JsonServiceResult&gt; {
@Override
protected JsonServiceResult getResultInstance() {
return new JsonServiceResult();
}
@Override
public JsonServiceArgument getArgumentInstance() {
return new JsonServiceArgument();
}
@Override
protected JsonServiceResult internalDoService(JsonServiceArgument arg) throws Exception {
// open a new transaction, using the realm from the argument, or the certificate
Resource book;
try (StrolchTransaction tx = openArgOrUserTx(arg)) {
// get a new book "instance" from the template
book = tx.getResourceTemplate(BookShopConstants.TYPE_BOOK);
// map all values from the JSON object into the new book element
book.accept(new FromFlatJsonVisitor(arg.jsonElement.getAsJsonObject()).ignoreBag(BAG_RELATIONS));
// save changes
tx.add(book);
// notify the TX that it should commit on close
tx.commitOnClose();
}
// map the return value to JSON
JsonObject result = book.accept(new StrolchElementToJsonVisitor().flat());
// and return the result
return new JsonServiceResult(result);
}
}
</pre>
<p><b>Note:</b> For the authenticated user to be able to perform this service, we must add it to their
privileges:</p>
<pre>
...
&lt;Role name="User"&gt;
...
&lt;Privilege name="li.strolch.service.api.Service" policy="DefaultPrivilege"&gt;
&lt;Allow&gt;li.strolch.bookshop.service.CreateBookService&lt;/Allow&gt;
&lt;/Privilege&gt;
...
&lt;/Role&gt;
...
</pre>
<h3>Update</h3>
<p>Updating of a book is basically the same as the creation, we just use PUT, verify that the book exists and
give the user the privilege.</p>
<p><b>PUT Method:</b></p>
<pre class="pre-scrollable">
@PUT
@Path("{id}")
@Produces(MediaType.APPLICATION_JSON)
public Response update(@Context HttpServletRequest request, @PathParam("id") String id, String data) {
// this is an authenticated method call, thus we can get the certificate from the request:
Certificate cert = (Certificate) request.getAttribute(StrolchRestfulConstants.STROLCH_CERTIFICATE);
// parse data to JSON
JsonObject jsonData = JsonParser.parseString(data).getAsJsonObject();
// instantiate the service with the argument
UpdateBookService svc = new UpdateBookService();
JsonServiceArgument arg = svc.getArgumentInstance();
arg.objectId = id;
arg.jsonElement = jsonData;
// perform the service
ServiceHandler serviceHandler = RestfulStrolchComponent.getInstance().getServiceHandler();
JsonServiceResult result = serviceHandler.doService(cert, svc, arg);
// return depending on the result state
if (result.isOk())
return ResponseUtil.toResponse(StrolchRestfulConstants.DATA, result.getResult());
return ResponseUtil.toResponse(result);
}
</pre>
<p><b>Update Service:</b></p>
<pre class="pre-scrollable">
public class UpdateBookService extends AbstractService&lt;JsonServiceArgument, JsonServiceResult&gt; {
@Override
protected JsonServiceResult getResultInstance() {
return new JsonServiceResult();
}
@Override
public JsonServiceArgument getArgumentInstance() {
return new JsonServiceArgument();
}
@Override
protected JsonServiceResult internalDoService(JsonServiceArgument arg) throws Exception {
// verify same book
DBC.PRE.assertEquals("ObjectId and given Id must be same!", arg.objectId,
arg.jsonElement.getAsJsonObject().get(Json.ID).getAsString());
// open a new transaction, using the realm from the argument, or the certificate
Resource book;
try (StrolchTransaction tx = openArgOrUserTx(arg)) {
// get the existing book
book = tx.getResourceBy(BookShopConstants.TYPE_BOOK, arg.objectId, true);
// map all values from the JSON object into the new book element
book.accept(new FromFlatJsonVisitor(arg.jsonElement.getAsJsonObject()).ignoreBag(BAG_RELATIONS));
// save changes
tx.update(book);
// notify the TX that it should commit on close
tx.commitOnClose();
}
// map the return value to JSON
JsonObject result = book.accept(new StrolchElementToJsonVisitor().flat());
// and return the result
return new JsonServiceResult(result);
}
}
</pre>
<p><b>Privilege:</b></p>
<pre>
...
&lt;Role name="User"&gt;
...
&lt;Privilege name="li.strolch.service.api.Service" policy="DefaultPrivilege"&gt;
...
&lt;Allow&gt;li.strolch.bookshop.service.UpdateBookService&lt;/Allow&gt;
...
&lt;/Privilege&gt;
...
&lt;/Role&gt;
...
</pre>
<h3>Remove</h3>
<p>To remove a book, we need a DELETE method, a remove service and the associated privilege.</p>
<p><b>DELETE Method:</b></p>
<pre class="pre-scrollable">
@DELETE
@Path("{id}")
@Produces(MediaType.APPLICATION_JSON)
public Response update(@Context HttpServletRequest request, @PathParam("id") String id) {
// this is an authenticated method call, thus we can get the certificate from the request:
Certificate cert = (Certificate) request.getAttribute(StrolchRestfulConstants.STROLCH_CERTIFICATE);
// instantiate the service with the argument
RemoveBookService svc = new RemoveBookService();
StringServiceArgument arg = svc.getArgumentInstance();
arg.value = id;
// perform the service
ServiceHandler serviceHandler = RestfulStrolchComponent.getInstance().getServiceHandler();
ServiceResult result = serviceHandler.doService(cert, svc, arg);
// return depending on the result state
return ResponseUtil.toResponse(result);
}
</pre>
<p><b>Remove Service:</b></p>
<pre class="pre-scrollable">
public class RemoveBookService extends AbstractService&lt;StringServiceArgument, ServiceResult&gt; {
@Override
protected ServiceResult getResultInstance() {
return new ServiceResult();
}
@Override
public StringServiceArgument getArgumentInstance() {
return new StringServiceArgument();
}
@Override
protected ServiceResult internalDoService(StringServiceArgument arg) throws Exception {
// open a new transaction, using the realm from the argument, or the certificate
try (StrolchTransaction tx = openArgOrUserTx(arg)) {
// get the existing book
Resource book = tx.getResourceBy(BookShopConstants.TYPE_BOOK, arg.value, true);
// save changes
tx.remove(book);
// notify the TX that it should commit on close
tx.commitOnClose();
}
// and return the result
return ServiceResult.success();
}
}
</pre>
<p><b>Privilege:</b></p>
<pre>
...
&lt;Role name="User"&gt;
...
&lt;Privilege name="li.strolch.service.api.Service" policy="DefaultPrivilege"&gt;
...
&lt;Allow&gt;li.strolch.bookshop.service.RemoveBookService&lt;/Allow&gt;
...
&lt;/Privilege&gt;
...
&lt;/Role&gt;
...
</pre>
<h3>Notes:</h3>
<p>One should now see a pattern emerge:</p>
<ul>
<li>The REST API delegates to the Services, or Searches, with the exception of the retrieval of a single
object by id.
</li>
<li>Services should do initial validation of the input. Not much validation was done here, but more could be
done.
</li>
<li>Commands are reusable objects to perform recurring work.</li>
<li>Searches and Services are privileged actions for which a user must have the privilege to perform the
action.
</li>
</ul>
<p>The book services are quite simple, but as more requirements arise, it should be easy to implement them in
the service layer. Thus should a service be required to be performed by an integration layer, then they can
simply call the services, since the input is defined and validation is done there (i.e. NOT in the REST
API).</p>
<p>This concludes the CRUD of books.</p>
<a href="tutorial-model.html" class="pull-left">Previous: Model</a>
<!-- content here -->
<a href="tutorial-model.html"></a>
</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 xsd 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

@ -1,276 +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: Tutorial Model</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><a href="documentation.html">Documentation</a></li>
<li><a href="plc.html">PLC</a></li>
<li class="active"><a href="tutorial.html">Tutorial</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">Tutorial: Model</h1>
<p class="lead page-description">Defining the model for the bookshop</p>
</div>
<div class="content">
<a href="tutorial-configuration.html" class="pull-left">Previous:
Configuration</a><a href="tutorial-crud-book.html"
class="pull-right">Next: CRUD
Books</a>
<br><br>
<p>Looking back at our functionality, we can list the following entities that need to be modelled (We'll go into
detail further down):</p>
<ul>
<li>Book &rightarrow; books can be orderd</li>
<li>UserCart &rightarrow; we want to store the cart of the user</li>
<li>Account &rightarrow; we need to know where to send the orders</li>
<li>PurchaseOrder &rightarrow; we need to know what was ordered and keep track of its state</li>
<li>FromStock &rightarrow; we want to use activities to implement the process of an order</li>
</ul>
<p>In Strolch we model entities by defining the element as a template. Thus in the <code>templates.xml</code>
file we can add the templates with the following content:</p>
<b>Book</b>
<pre class="pre-scrollable">
&lt;Resource Id="Book" Name="Book Template" Type="Template"&gt;
&lt;ParameterBag Id="parameters" Name="Parameters" Type="Parameters"&gt;
&lt;Parameter Id="description" Name="Description" Type="String" Value="" /&gt;
&lt;Parameter Id="quantity" Name="Quantity in Stock" Type="Integer" Value="0" /&gt;
&lt;/ParameterBag&gt;
&lt;/Resource&gt;
</pre>
<b>Account</b>
<pre class="pre-scrollable">
&lt;Resource Id="Account" Name="Account Template" Type="Template"&gt;
&lt;ParameterBag Id="parameters" Name="Parameters" Type="Parameters"&gt;
&lt;Parameter Id="user" Name="User" Type="String" Value="" /&gt;
&lt;Parameter Id="firstName" Name="First Name" Type="String" Value="" /&gt;
&lt;Parameter Id="lastName" Name="Last Name" Type="String" Value="" /&gt;
&lt;Parameter Id="email" Name="E-Mail" Type="String" Value="" /&gt;
&lt;/ParameterBag&gt;
&lt;ParameterBag Name="Address" Id="address" Type="Address"&gt;
&lt;Parameter Id="phone" Name="Telephone Number" Type="String" Value="" /&gt;
&lt;Parameter Id="street" Name="Street" Type="String" Value="" /&gt;
&lt;Parameter Id="city" Name="City" Type="String" Value="" /&gt;
&lt;Parameter Id="zip" Name="Postal Code" Type="String" Value="" /&gt;
&lt;Parameter Id="country" Name="Country" Type="String" Value="" /&gt;
&lt;/ParameterBag&gt;
&lt;/Resource&gt;
</pre>
<b>UserCart</b>
<pre class="pre-scrollable">
&lt;Resource Id="UserCart" Name="UserCart Template" Type="Template"&gt;
&lt;ParameterBag Id="books" Name="Books" Type="Book"&gt;
&lt;!-- Parameter Id="bookId" Name="Book reference" Type="Float" Value="0" / --&gt;
&lt;/ParameterBag&gt;
&lt;ParameterBag Id="relations" Name="Relations" Type="Parameters"&gt;
&lt;Parameter Id="account" Name="Account" Type="String" Interpretation="Resource-Ref" Uom="Account" Value="" /&gt;
&lt;/ParameterBag&gt;
&lt;/Resource&gt;
</pre>
<b>PurchaseOrder</b>
<pre class="pre-scrollable">
&lt;Order Id="PurchaseOrder" Name="PurchaseOrder Template" Type="Template" State="Created"&gt;
&lt;ParameterBag Id="books" Name="Books" Type="Book"&gt;
&lt;!-- Parameter Id="bookId" Name="Book reference" Type="Float" Value="0" / --&gt;
&lt;/ParameterBag&gt;
&lt;ParameterBag Id="relations" Name="Relations" Type="Parameters"&gt;
&lt;Parameter Id="account" Name="Account" Type="String" Interpretation="Resource-Ref" Uom="Account" Value="" /&gt;
&lt;/ParameterBag&gt;
&lt;/Order&gt;
</pre>
<b>FromStock</b>
<pre class="pre-scrollable">
&lt;Activity Id="FromStock" Name="From Stock Template" Type="FromStock" TimeOrdering="Series"&gt;
&lt;ParameterBag Name="objectives" Id="Objectives" Type="Objectives"&gt;
&lt;Parameter Name="Duration" Id="duration" Value="PT1MS" Type="Duration" /&gt;
&lt;/ParameterBag&gt;
&lt;Action Id="validate" Name="Validation of order" Type="Use" ResourceType="Validation" ResourceId="validation" /&gt;
&lt;!-- for each book we do a consume, i.e. reduce the stock quantity --&gt;
&lt;Action Id="Consume" Name="Consume Template for book" Type="Template"&gt;
&lt;ParameterBag Id="parameters" Name="Parameters" Type="Parameters"&gt;
&lt;Parameter Id="quantity" Name="Quantity" Type="Float" Value="0" /&gt;
&lt;/ParameterBag&gt;
&lt;/Action&gt;
&lt;Action Id="package" Name="Packaging of PurchaseOrder" Type="Use" ResourceType="Packaging" ResourceId="packaging" /&gt;
&lt;Action Id="send" Name="Sending of package" Type="Use" ResourceType="Sending" ResourceId="sending" /&gt;
&lt;/Activity&gt;
</pre>
<p>Let's explain a few things:</p>
<ul>
<li>The <code>Book</code> entity is a <code>Resource</code> object and only contains the description and the
current quantity in stock.
</li>
<li>The <code>Account</code> entity is a Resource and contains the address and further details of the user,
and with the <code>user</code> parameter the username is defined, thus referencing the real user.
</li>
<li>The <code>UserCart</code> entity is a Resource and has a reference to the account Resource. Note how the
reference is done using a StringParameter, where Interpretation, UOM and the value is set in a specific
manner.
</li>
<li>The <code>UserCart</code> entity is a Resource and references books using a special
<code>ParameterBag</code> with the type set to <code>Book</code>, the actual type of the book entity.
Each Parameter is of type <code>Float</code> and the ID of the parameter is the ID of the book, and the
value is the quantity that the user would like to purchase. There will only be one cart per
user/account.
</li>
<li>The <code>PurchaseOrder</code> entity is an <code>Order</code> object, and is basically a copy of the
UserCart entity. This is the confirmed purchase order for the contents of a cart, and can then be used
for reports on how much of which book was sold.
</li>
<li>The <code>FromStock</code> entity is an <code>Activity</code> object and defines the process we will go
through when delivering a purchase to a user. Note how the activity has a ParameterBag
<code>objectives</code> with a <code>duration</code> parameter. This defines globally for this activity
how long each <code>Action</code> should execute. This can be overridden in each Action and can help to
plan how much effort goes into the delivering of each PurchaseOrder.
</li>
<li>Further note how the activity has three special actions (<code>validate</code>, <code>package</code> and
<code>send</code>) on which a <code>ResourceType</code> and <code>ResourceId</code> are defined. Actions
are always performed on a Resource, as the referenced Resource defines the behaviour of the action
through defined <code>Policy</code> objects.
</li>
<li>For each book which will be purchased, an Action will be created of type <code>Consume</code>. In the
template this is defined by a template Action with the id <code>Consume</code> and will later be changed
accordingly.
</li>
</ul>
<p>Since we are referencing resources from actions in the activity, we need to add these as well, but not as
templates. They can be added to the <code>defaultModel.xml</code> file:</p>
<pre>
&lt;Resource Id="validation" Name="Validation Resource" Type="Validation"&gt;
&lt;Policies&gt;
&lt;Policy Type="ExecutionPolicy" Value="key:ValidationExecution" /&gt;
&lt;Policy Type="ConfirmationPolicy" Value="key:DefaultConfirmation" /&gt;
&lt;/Policies&gt;
&lt;/Resource&gt;
&lt;Resource Id="packaging" Name="Packaging Resource" Type="Packaging"&gt;
&lt;Policies&gt;
&lt;Policy Type="ExecutionPolicy" Value="key:PackagingExecution" /&gt;
&lt;Policy Type="ConfirmationPolicy" Value="key:DefaultConfirmation" /&gt;
&lt;/Policies&gt;
&lt;/Resource&gt;
&lt;Resource Id="sending" Name="Sending Resource" Type="Sending"&gt;
&lt;Policies&gt;
&lt;Policy Type="ExecutionPolicy" Value="key:SendingExecution" /&gt;
&lt;Policy Type="ConfirmationPolicy" Value="key:DefaultConfirmation" /&gt;
&lt;/Policies&gt;
&lt;/Resource&gt;
</pre>
<p>What should now be noted by these three new Resources is that they have Policy definitions:</p>
<ul>
<li><code>ExecutionPolicy</code> &rightarrow; defines how an action on this resource is executed by
referencing an ExecutionPolicy implementation.
</li>
<li><code>ConfirmationPolicy</code> &rightarrow; defines behaviour to be performed on every state change of
an action being performed on this resource by referencing an
ConfirmationPolicy implementation.
</li>
</ul>
<p>Currently these resources reference policies which don't exist. We will resolve this issue later, when we
implement the execution of the activity.</p>
<p>This concludes the model definition. In the next step we'll start creating services and commands for our
model.</p>
<a href="tutorial-configuration.html" class="pull-left">Previous:
Configuration</a><a href="tutorial-crud-book.html"
class="pull-right">Next: CRUD
Books</a>
<!-- content here -->
<a href="tutorial-model.html"></a>
</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 xsd 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

@ -1,122 +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: Tutorial</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><a href="documentation.html">Documentation</a></li>
<li><a href="plc.html">PLC</a></li>
<li class="active"><a href="tutorial.html">Tutorial</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">Tutorial</h1>
<p class="lead page-description">Let's build a bookshop!</p>
</div>
<div class="content">
<p>In this tutorial we will build a book store using Strolch. This book store will be without a UI, but we will
do everything using REST APIs, which should make it easy to add a UI later using whatever framework suits one
most.</p>
<p>The book store will have the following features:</p>
<ul>
<li>The store owner can add, update and remove books</li>
<li>The store owner can edit the stock quantity</li>
<li>Users can view a list of books</li>
<li>Users can add books to a virtual cart</li>
<li>Users can create and verify an account using an e-mail address</li>
<li>Users can submit an order for the books in their cart</li>
<li>The store owner can see the orders by state (pending, preparing, sent)</li>
<li>The store owner can update the state of an order (preparing, sent)</li>
<li>Notify the user when the order is sent</li>
</ul>
<p>Navigation:</p>
<ul>
<li><a href="tutorial-configuration.html">Configuration</a></li>
<li><a href="tutorial-model.html">Model</a></li>
</ul>
<p>The code to the book can be downloaded from <a href="https://github.com/4treesCH/strolch-bookshop">GitHub</a>
and will be updated as this tutorial is updated.</p>
<a href="tutorial-configuration.html" class="pull-right">Next: Configuration</a>
</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 xsd 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

@ -1,201 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="https://strolch.li/xsd/StrolchModel-1.6.xsd"
xmlns="https://strolch.li/xsd/StrolchModel-1.6.xsd"
elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:annotation>
<xs:documentation>This is Version 1.6.x of the StrolchModel XSD.</xs:documentation>
</xs:annotation>
<xs:element name="StrolchModel" type="StrolchModelType"/>
<xs:complexType name="StrolchModelType">
<xs:sequence maxOccurs="unbounded" minOccurs="0">
<xs:choice>
<xs:element type="IncludeFileType" name="IncludeFile" maxOccurs="unbounded" minOccurs="0"/>
<xs:element type="OrderType" name="Order" maxOccurs="unbounded" minOccurs="0"/>
<xs:element type="ResourceType" name="Resource" maxOccurs="unbounded" minOccurs="0"/>
<xs:element type="ActivityType" name="Activity" maxOccurs="unbounded" minOccurs="0"/>
</xs:choice>
</xs:sequence>
</xs:complexType>
<xs:complexType name="IncludeFileType">
<xs:attribute type="xs:string" name="file"/>
</xs:complexType>
<xs:complexType name="VersionType">
<xs:attribute type="xs:int" name="Version" use="required"/>
<xs:attribute type="xs:string" name="CreatedBy" use="required"/>
<xs:attribute type="xs:string" name="UpdatedBy" use="required"/>
<xs:attribute type="xs:dateTime" name="Created" use="required"/>
<xs:attribute type="xs:dateTime" name="Updated" use="required"/>
<xs:attribute type="xs:string" name="Deleted" use="required"/>
</xs:complexType>
<xs:complexType name="OrderType">
<xs:sequence>
<xs:element type="VersionType" name="Version" maxOccurs="1" minOccurs="0"/>
<xs:element type="ParameterBagType" name="ParameterBag" maxOccurs="unbounded" minOccurs="0"/>
<xs:element type="PoliciesType" name="Policies" maxOccurs="1" minOccurs="0"/>
</xs:sequence>
<xs:attribute type="xs:string" name="Id" use="required"/>
<xs:attribute type="xs:string" name="Name" use="required"/>
<xs:attribute type="xs:string" name="Type" use="required"/>
<xs:attribute type="xs:dateTime" name="Date" use="optional"/>
<xs:attribute type="StateType" name="State" use="optional"/>
</xs:complexType>
<xs:complexType name="ResourceType">
<xs:sequence>
<xs:element type="VersionType" name="Version" maxOccurs="1" minOccurs="0"/>
<xs:element type="ParameterBagType" name="ParameterBag" maxOccurs="unbounded" minOccurs="0"/>
<xs:element type="TimedStateType" name="TimedState" maxOccurs="unbounded" minOccurs="0"/>
<xs:element type="PoliciesType" name="Policies" maxOccurs="1" minOccurs="0"/>
</xs:sequence>
<xs:attribute type="xs:string" name="Id" use="required"/>
<xs:attribute type="xs:string" name="Name" use="required"/>
<xs:attribute type="xs:string" name="Type" use="required"/>
</xs:complexType>
<xs:complexType name="ActivityType">
<xs:sequence>
<xs:element type="VersionType" name="Version" maxOccurs="1" minOccurs="0"/>
<xs:element type="ParameterBagType" name="ParameterBag" maxOccurs="unbounded" minOccurs="0"/>
<xs:sequence maxOccurs="unbounded" minOccurs="0">
<xs:choice>
<xs:element type="ActionType" name="Action" maxOccurs="unbounded" minOccurs="0"/>
<xs:element type="ActivityType" name="Activity" maxOccurs="unbounded" minOccurs="0"/>
</xs:choice>
</xs:sequence>
<xs:element type="PoliciesType" name="Policies" maxOccurs="1" minOccurs="0"/>
</xs:sequence>
<xs:attribute type="xs:string" name="Id" use="required"/>
<xs:attribute type="xs:string" name="Name" use="required"/>
<xs:attribute type="xs:string" name="Type" use="required"/>
<xs:attribute type="TimeOrderingType" name="TimeOrdering" use="required"/>
</xs:complexType>
<xs:complexType name="ActionType">
<xs:sequence>
<xs:element type="ParameterBagType" name="ParameterBag" maxOccurs="unbounded" minOccurs="0"/>
<xs:element type="PoliciesType" name="Policies" maxOccurs="1" minOccurs="0"/>
<xs:element type="ValueChangeType" name="ValueChange" maxOccurs="unbounded" minOccurs="0"/>
</xs:sequence>
<xs:attribute type="xs:string" name="Id" use="required"/>
<xs:attribute type="xs:string" name="Name" use="required"/>
<xs:attribute type="xs:string" name="ResourceId" use="optional"/>
<xs:attribute type="xs:string" name="ResourceType" use="optional"/>
<xs:attribute type="StateType" name="State" use="optional"/>
<xs:attribute type="xs:string" name="Type" use="required"/>
</xs:complexType>
<xs:complexType name="ParameterBagType">
<xs:sequence>
<xs:element type="ParameterType" name="Parameter" maxOccurs="unbounded" minOccurs="0"/>
</xs:sequence>
<xs:attribute type="xs:string" name="Id" use="required"/>
<xs:attribute type="xs:string" name="Name" use="required"/>
<xs:attribute type="xs:string" name="Type" use="required"/>
</xs:complexType>
<xs:complexType name="ParameterType">
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute type="xs:string" name="Id" use="required"/>
<xs:attribute type="xs:string" name="Name" use="required"/>
<xs:attribute type="ParameterValueType" name="Type" use="required"/>
<xs:attribute type="xs:string" name="Value" use="optional"/>
<xs:attribute type="xs:string" name="Interpretation" use="optional"/>
<xs:attribute type="xs:string" name="Uom" use="optional"/>
<xs:attribute type="xs:boolean" name="Hidden" use="optional"/>
<xs:attribute type="xs:int" name="Index" use="optional"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:complexType name="PoliciesType">
<xs:sequence>
<xs:element type="PolicyType" name="Policy" maxOccurs="unbounded" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="PolicyType">
<xs:attribute type="xs:string" name="Type" use="required"/>
<xs:attribute type="xs:string" name="Value" use="required"/>
</xs:complexType>
<xs:complexType name="TimedStateType">
<xs:sequence>
<xs:element type="ValueType" name="Value" maxOccurs="unbounded" minOccurs="0"/>
</xs:sequence>
<xs:attribute type="xs:string" name="Id" use="required"/>
<xs:attribute type="xs:string" name="Name" use="required"/>
<xs:attribute type="TimedStateTypeType" name="Type" use="required"/>
<xs:attribute type="xs:string" name="Interpretation" use="optional"/>
<xs:attribute type="xs:string" name="Uom" use="optional"/>
<xs:attribute type="xs:boolean" name="Hidden" use="optional"/>
<xs:attribute type="xs:int" name="Index" use="optional"/>
</xs:complexType>
<xs:complexType name="ValueType">
<xs:attribute type="xs:dateTime" name="Time" use="required"/>
<xs:attribute type="xs:string" name="Value" use="required"/>
</xs:complexType>
<xs:complexType name="ValueChangeType">
<xs:attribute type="xs:string" name="StateId" use="optional"/>
<xs:attribute type="xs:dateTime" name="Time" use="required"/>
<xs:attribute type="xs:string" name="Value" use="required"/>
<xs:attribute type="TimedStateTypeType" name="Type" use="required"/>
</xs:complexType>
<xs:simpleType name="StateType">
<xs:restriction base="xs:string">
<xs:enumeration value="Created"/>
<xs:enumeration value="Planning"/>
<xs:enumeration value="Planned"/>
<xs:enumeration value="Execution"/>
<xs:enumeration value="Stopped"/>
<xs:enumeration value="Warning"/>
<xs:enumeration value="Error"/>
<xs:enumeration value="Executed"/>
<xs:enumeration value="Closed"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="TimeOrderingType">
<xs:restriction base="xs:string">
<xs:enumeration value="Series"/>
<xs:enumeration value="Parallel"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="ParameterValueType">
<xs:restriction base="xs:string">
<xs:enumeration value="Boolean"/>
<xs:enumeration value="String"/>
<xs:enumeration value="Text"/>
<xs:enumeration value="Integer"/>
<xs:enumeration value="Long"/>
<xs:enumeration value="Float"/>
<xs:enumeration value="Date"/>
<xs:enumeration value="Duration"/>
<xs:enumeration value="StringList"/>
<xs:enumeration value="IntegerList"/>
<xs:enumeration value="FloatList"/>
<xs:enumeration value="LongList"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="TimedStateTypeType">
<xs:restriction base="xs:string">
<xs:enumeration value="Boolean"/>
<xs:enumeration value="Integer"/>
<xs:enumeration value="Float"/>
<xs:enumeration value="Long"/>
<xs:enumeration value="FloatList"/>
<xs:enumeration value="StringSet"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>