[Major] Added maven archetypes to create new projects

This commit is contained in:
Robert von Burg 2019-09-10 13:22:49 +02:00
parent 14712c4556
commit 15a9c924e7
86 changed files with 4497 additions and 634 deletions

View File

@ -15,14 +15,65 @@ Strolch consists of the following modules:
- li.strolch.service
- li.strolch.testbase
With the following test applications:
- li.strolch.tutorialapp
- li.strolch.tutorialwebapp
- li.strolch.planningwebapp
- strolch_minimal
- strolch_minimal_rest
And of course the website itself:
- li.strolch.website
Getting Started
----------------
Either use a version on Maven Central: https://mvnrepository.com/artifact/li.strolch/li.strolch.agent
Or install locally first:
git clone https://github.com/4treesCH/strolch.git
cd strolch
mvn clean install -DskipTests
Then you can create your own project. Please read the README files in the generated projects.
Java App:
mvn archetype:generate \
-DarchetypeGroupId=li.strolch \
-DarchetypeArtifactId=li.strolch.mvn.archetype.main \
-DarchetypeVersion=1.6.0-SNAPSHOT \
-DgroupId=<my.groupid> \
-DartifactId=<my-artifactId> \
-Dversion=<my.version> \
-DappName="<my app name>"
mvn archetype:generate \
-DarchetypeGroupId=li.strolch \
-DarchetypeArtifactId=li.strolch.mvn.archetype.main \
-DarchetypeVersion=1.6.0-SNAPSHOT \
-DgroupId=com.example \
-DartifactId=strolch-test-app \
-Dversion=0.1.0-SNAPSHOT \
-DappName="My Test App"
WebApp:
mvn archetype:generate \
-DarchetypeGroupId=li.strolch \
-DarchetypeArtifactId=li.strolch.mvn.archetype.webapp \
-DarchetypeVersion=1.6.0-SNAPSHOT \
-DgroupId=<my.groupid> \
-DartifactId=<my-artifactId> \
-Dversion=<my.version> \
-DappName="<my app name>"
mvn archetype:generate \
-DarchetypeGroupId=li.strolch \
-DarchetypeArtifactId=li.strolch.mvn.archetype.webapp \
-DarchetypeVersion=1.6.0-SNAPSHOT \
-DgroupId=com.example \
-DartifactId=strolch-test-webapp \
-Dversion=0.1.0-SNAPSHOT \
-DappName="My Test Web App"
More Information
-----------------
Find more to Strolch at our website: http://strolch.li

View File

@ -0,0 +1 @@
target/

View File

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<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">
<parent>
<artifactId>li.strolch</artifactId>
<groupId>li.strolch</groupId>
<version>1.6.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>li.strolch.mvn.archetype.main</artifactId>
<packaging>maven-archetype</packaging>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>false</filtering>
</resource>
</resources>
<extensions>
<extension>
<groupId>org.apache.maven.archetype</groupId>
<artifactId>archetype-packaging</artifactId>
<version>3.1.2</version>
</extension>
</extensions>
</build>
</project>

View File

@ -0,0 +1,37 @@
<archetype-descriptor
xsi:schemaLocation="http://maven.apache.org/plugins/maven-archetype-plugin/archetype-descriptor/1.0.0
http://maven.apache.org/xsd/archetype-descriptor-1.0.0.xsd"
xmlns="http://maven.apache.org/plugins/maven-archetype-plugin/archetype-descriptor/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
name="li.strolch.mvn.archetype.main">
<requiredProperties>
<requiredProperty key="appName">
<defaultValue>Strolch App</defaultValue>
</requiredProperty>
</requiredProperties>
<fileSets>
<fileSet filtered="true" packaged="true" encoding="UTF-8">
<directory>src/main/java</directory>
</fileSet>
<fileSet filtered="true" encoding="UTF-8">
<directory>src/main/resources</directory>
</fileSet>
<fileSet filtered="true" packaged="true" encoding="UTF-8">
<directory>src/test/java</directory>
</fileSet>
<fileSet filtered="true" encoding="UTF-8">
<directory>src/test/resources</directory>
</fileSet>
<fileSet filtered="true" encoding="UTF-8">
<directory>runtime</directory>
</fileSet>
<fileSet filtered="true" encoding="UTF-8">
<directory></directory>
<includes>
<include>README.md</include>
</includes>
</fileSet>
</fileSets>
</archetype-descriptor>

View File

@ -0,0 +1,37 @@
Strolch Project: ${appName} / ${artifactId}
======================================
This is a Strolch project which is started by a main()-method. It has an example
test class to show how to start an agent for tests.
The project's runtime directory is in the root folder and contains the
configuration and data files needed to start via the main()-method.
The test has it's own runtime directory, with its own configuration, but the
model file in the data directory points to the main runtime directory and uses
that model file, so that one does not need to duplicate resource files.
Preparation
------------------
Please change the SCM connection in the pom.xml:
<scm>
<!-- TODO: Change this to your SCM URL -->
<connection>scm:git:https://github.com/4treesCH/strolch.git</connection>
<developerConnection>scm:git:https://github.com/4treesCH/strolch.git</developerConnection>
<url>https://github.com/4treesCH/strolch</url>
</scm>
Running tests
-------------------------
mvn clean test
Running App
--------------------------
mvn clean compile
mvn exec:java

View File

@ -0,0 +1,229 @@
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>${groupId}</groupId>
<artifactId>${artifactId}</artifactId>
<name>${appName}</name>
<version>${version}</version>
<packaging>jar</packaging>
<scm>
<!-- TODO: Change this to your SCM URL -->
<connection>scm:git:https://github.com/4treesCH/strolch.git</connection>
<developerConnection>scm:git:https://github.com/4treesCH/strolch.git</developerConnection>
<url>https://github.com/4treesCH/strolch</url>
</scm>
<properties>
<appFinalName>${artifactId}</appFinalName>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.build.timestamp.format>yyyy-MM-dd HH:mm:ss</maven.build.timestamp.format>
<buildTimestamp>${maven.build.timestamp}</buildTimestamp>
<jdk.version>1.8</jdk.version>
<!-- compile time dependencies -->
<slf4j.version>1.7.26</slf4j.version>
<logback.version>1.2.3</logback.version>
<gson.version>2.8.5</gson.version>
<strolch.version>1.6.0-SNAPSHOT</strolch.version>
<!-- test time dependencies -->
<junit.version>4.12</junit.version>
<hamcrest.version>2.1</hamcrest.version>
<!-- maven plug-in dependencies -->
<buildnumber-maven-plugin.version>1.4</buildnumber-maven-plugin.version>
<maven-compiler-plugin.version>3.8.1</maven-compiler-plugin.version>
<maven-jar-plugin.version>3.1.2</maven-jar-plugin.version>
<maven-exec-plugin.version>1.6.0</maven-exec-plugin.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>li.strolch</groupId>
<artifactId>li.strolch.bom</artifactId>
<type>pom</type>
<version>${strolch.version}</version>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>${gson.version}</version>
</dependency>
<!-- test -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-core</artifactId>
<version>${hamcrest.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-library</artifactId>
<version>${hamcrest.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- base -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
<!-- strolch -->
<dependency>
<groupId>li.strolch</groupId>
<artifactId>li.strolch.model</artifactId>
</dependency>
<dependency>
<groupId>li.strolch</groupId>
<artifactId>li.strolch.agent</artifactId>
</dependency>
<dependency>
<groupId>li.strolch</groupId>
<artifactId>li.strolch.service</artifactId>
</dependency>
<dependency>
<groupId>li.strolch</groupId>
<artifactId>li.strolch.testbase</artifactId>
<scope>test</scope>
</dependency>
<!-- testing -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-library</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>${appFinalName}</finalName>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>**/*.properties</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
<filtering>false</filtering>
<excludes>
<exclude>**/*.properties</exclude>
</excludes>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>buildnumber-maven-plugin</artifactId>
<version>${buildnumber-maven-plugin.version}</version>
<executions>
<execution>
<phase>validate</phase>
<goals>
<goal>create</goal>
</goals>
</execution>
</executions>
<configuration>
<doCheck>false</doCheck>
<doUpdate>false</doUpdate>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<source>${jdk.version}</source>
<target>${jdk.version}</target>
<showDeprecation>true</showDeprecation>
<showWarnings>true</showWarnings>
<compilerArgument>-Xlint:all</compilerArgument>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>${maven-exec-plugin.version}</version>
<configuration>
<mainClass>${package}.Main</mainClass>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
<!-- for dev: always enable strolch environment "dev" -->
<profile>
<id>dev.local</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<strolch.env>dev</strolch.env>
</properties>
</profile>
</profiles>
</project>

View File

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<Privilege>
<Container>
<Parameters>
<!-- parameters for the container itself -->
<Parameter name="secretKey" value="CHANGE-ME-1"/>
<Parameter name="secretSalt" value="CHANGE-ME-2"/>
<Parameter name="persistSessions" value="true"/>
<Parameter name="autoPersistOnUserChangesData" value="false"/>
<Parameter name="privilegeConflictResolution" value="MERGE"/>
</Parameters>
<EncryptionHandler class="li.strolch.privilege.handler.DefaultEncryptionHandler">
<Parameters>
<!-- WARNING: If you change iterations or keyLength, then all passwords are invalid -->
<!-- default algorithm is: PBKDF2WithHmacSHA512 -->
<Parameter name="hashAlgorithm" value="PBKDF2WithHmacSHA512" />
<!-- default iterations: 200000 -->
<Parameter name="hashIterations" value="10000" />
<!-- default key length: 256 -->
<Parameter name="hashKeyLength" value="256" />
</Parameters>
</EncryptionHandler>
<PersistenceHandler class="li.strolch.privilege.handler.XmlPersistenceHandler">
<Parameters>
<Parameter name="usersXmlFile" value="PrivilegeUsers.xml" />
<Parameter name="rolesXmlFile" value="PrivilegeRoles.xml" />
</Parameters>
</PersistenceHandler>
<UserChallengeHandler class="li.strolch.privilege.handler.ConsoleUserChallengeHandler">
</UserChallengeHandler>
</Container>
<Policies>
<Policy name="DefaultPrivilege" class="li.strolch.privilege.policy.DefaultPrivilege"/>
<Policy name="ModelPrivilege" class="li.strolch.runtime.privilege.ModelPrivilege" />
<Policy name="RoleAccessPrivilege" class="li.strolch.privilege.policy.RoleAccessPrivilege"/>
<Policy name="UserAccessPrivilege" class="li.strolch.privilege.policy.UserAccessPrivilege"/>
<Policy name="UserSessionAccessPrivilege" class="li.strolch.privilege.policy.UsernameFromCertificatePrivilege"/>
</Policies>
</Privilege>

View File

@ -0,0 +1,189 @@
<?xml version="1.0" encoding="UTF-8"?>
<Roles>
<Role name="agent">
<Privilege name="li.strolch.privilege.handler.SystemAction" policy="DefaultPrivilege">
<Allow>li.strolch.runtime.privilege.StrolchSystemAction</Allow>
<Allow>li.strolch.runtime.privilege.StrolchSystemActionWithResult</Allow>
</Privilege>
<Privilege name="PrivilegeAction" policy="DefaultPrivilege">
<Allow>PersistSessions</Allow>
<Allow>GetCertificates</Allow>
</Privilege>
<Privilege name="GetResource" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="GetOrder" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="GetActivity" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="AddResource" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="AddOrder" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="AddActivity" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="UpdateResource" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="UpdateOrder" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="UpdateActivity" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="RemoveResource" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="RemoveOrder" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="RemoveActivity" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
</Role>
<Role name="AppUser">
<Privilege name="li.strolch.service.api.Service" policy="DefaultPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="li.strolch.model.query.StrolchQuery" policy="DefaultPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="li.strolch.search.StrolchSearch" policy="DefaultPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="li.strolch.report.ReportSearch" policy="DefaultPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="GetResource" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="GetOrder" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="GetActivity" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="AddResource" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="AddOrder" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="AddActivity" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="UpdateResource" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="UpdateOrder" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="UpdateActivity" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="RemoveResource" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="RemoveOrder" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="RemoveActivity" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
</Role>
<Role name="StrolchAdmin">
<Privilege name="PrivilegeAddUser" policy="UserAccessPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="PrivilegeSetUserPassword" policy="UserAccessPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="li.strolch.handler.operationslog.OperationsLog" policy="DefaultPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="li.strolch.search.StrolchSearch" policy="DefaultPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="li.strolch.report.ReportSearch" policy="DefaultPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="li.strolch.model.query.StrolchQuery" policy="DefaultPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="li.strolch.job.StrolchJob" policy="DefaultPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="li.strolch.job.StrolchJobsHandler" policy="DefaultPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="li.strolch.service.api.Service" policy="DefaultPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
</Role>
<Role name="PrivilegeAdmin">
<Privilege name="PrivilegeAddUser" policy="UserAccessPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="PrivilegeRemoveUser" policy="UserAccessPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="InvalidateSession" policy="UserSessionAccessPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="PrivilegeSetUserPassword" policy="UserAccessPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="PrivilegeSetUserLocale" policy="UserAccessPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="PrivilegeAction" policy="DefaultPrivilege">
<Allow>Reload</Allow>
<Allow>GetPolicies</Allow>
<Allow>Persist</Allow>
<Allow>GetCertificates</Allow>
<Allow>PersistSessions</Allow>
</Privilege>
<Privilege name="PrivilegeGetUser" policy="UserAccessPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="PrivilegeSetUserState" policy="UserAccessPrivilege">
<Deny>SYSTEM</Deny>
<Allow>DISABLED</Allow>
<Allow>ENABLED</Allow>
</Privilege>
<Privilege name="PrivilegeAddRoleToUser" policy="UserAccessPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="PrivilegeGetRole" policy="RoleAccessPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="GetSession" policy="UserSessionAccessPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="PrivilegeModifyUser" policy="UserAccessPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="PrivilegeRemoveRole" policy="RoleAccessPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="PrivilegeRemoveRoleFromUser" policy="UserAccessPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="PrivilegeModifyRole" policy="RoleAccessPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="PrivilegeAddRole" policy="RoleAccessPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
</Role>
</Roles>

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<Users>
<User userId="0" username="agent">
<State>SYSTEM</State>
<Roles>
<Role>agent</Role>
</Roles>
</User>
<!-- Password: admin -->
<User userId="1" username="admin" password="cb69962946617da006a2f95776d78b49e5ec7941d2bdb2d25cdb05f957f64344" salt="61646d696e">
<Firstname>Application</Firstname>
<Lastname>Administrator</Lastname>
<State>ENABLED</State>
<Locale>en-GB</Locale>
<Roles>
<Role>AppUser</Role>
</Roles>
<Properties>
<Property name="organization" value="strolch.li"/>
<Property name="organizationalUnit" value="Development"/>
</Properties>
</User>
</Users>

View File

@ -0,0 +1,100 @@
<?xml version="1.0" encoding="UTF-8"?>
<StrolchConfiguration>
<env id="dev">
<Runtime>
<applicationName>${appName}</applicationName>
<Properties>
<locale>en</locale>
<verbose>true</verbose>
</Properties>
</Runtime>
<Component>
<name>PrivilegeHandler</name>
<api>li.strolch.runtime.privilege.PrivilegeHandler</api>
<impl>li.strolch.runtime.privilege.DefaultStrolchPrivilegeHandler</impl>
<Properties>
<privilegeConfigFile>PrivilegeConfig.xml</privilegeConfigFile>
</Properties>
</Component>
<Component>
<name>RealmHandler</name>
<api>li.strolch.agent.api.RealmHandler</api>
<impl>li.strolch.agent.impl.DefaultRealmHandler</impl>
<depends>PrivilegeHandler</depends>
<Properties>
<realms>defaultRealm</realms>
<dataStoreMode>TRANSIENT</dataStoreMode>
<dataStoreFile>Model.xml</dataStoreFile>
<enableObserverUpdates>true</enableObserverUpdates>
</Properties>
</Component>
<Component>
<name>EnumHandler</name>
<api>li.strolch.runtime.query.enums.EnumHandler</api>
<impl>li.strolch.runtime.query.enums.DefaultEnumHandler</impl>
<depends>RealmHandler</depends>
</Component>
<Component>
<name>ServiceHandler</name>
<api>li.strolch.service.api.ServiceHandler</api>
<impl>li.strolch.service.api.DefaultServiceHandler</impl>
<depends>RealmHandler</depends>
<depends>PrivilegeHandler</depends>
<Properties>
<verbose>true</verbose>
</Properties>
</Component>
<Component>
<name>PolicyHandler</name>
<api>li.strolch.policy.PolicyHandler</api>
<impl>li.strolch.policy.DefaultPolicyHandler</impl>
<Properties>
<readPolicyFile>true</readPolicyFile>
</Properties>
</Component>
<Component>
<name>MigrationsHandler</name>
<api>li.strolch.migrations.MigrationsHandler</api>
<impl>li.strolch.migrations.MigrationsHandler</impl>
<depends>RealmHandler</depends>
</Component>
<Component>
<name>OperationsLog</name>
<api>li.strolch.handler.operationslog.OperationsLog</api>
<impl>li.strolch.handler.operationslog.OperationsLog</impl>
<depends>RealmHandler</depends>
</Component>
<Component>
<name>StrolchJobsHandler</name>
<api>li.strolch.job.StrolchJobsHandler</api>
<impl>li.strolch.job.StrolchJobsHandler</impl>
<depends>RealmHandler</depends>
</Component>
<Component>
<name>PostInitializer</name>
<api>li.strolch.agent.api.PostInitializer</api>
<impl>${package}.PostInitializer</impl>
<depends>ServiceHandler</depends>
<Properties>
</Properties>
</Component>
<Component>
<name>ExecutionHandler</name>
<api>li.strolch.execution.ExecutionHandler</api>
<impl>li.strolch.execution.EventBasedExecutionHandler</impl>
<depends>PostInitializer</depends>
<Properties>
<restartExecution>true</restartExecution>
</Properties>
</Component>
</env>
</StrolchConfiguration>

View File

@ -0,0 +1,3 @@
<StrolchPolicies>
</StrolchPolicies>

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<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.xsd">
<Resource Id="yellowBall" Name="Yellow Ball" Type="Ball">
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
<Parameter Id="color" Name="Color" Type="String" Value="yellow"/>
</ParameterBag>
</Resource>
</StrolchModel>

View File

@ -0,0 +1,196 @@
<?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: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="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="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="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>

View File

@ -0,0 +1,52 @@
package ${package};
import li.strolch.agent.api.StrolchAgent;
import li.strolch.agent.api.StrolchBootstrapper;
import li.strolch.runtime.configuration.StrolchEnvironment;
import li.strolch.utils.helper.StringHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Main {
private static final Logger logger = LoggerFactory.getLogger(Main.class);
private static final String APP_NAME = "${appName}";
private static StrolchAgent agent;
public static void main(String[] args) throws Throwable {
logger.info("Starting " + APP_NAME + "...");
long start = System.currentTimeMillis();
try {
// find environment from ENV.properties
String env = StrolchEnvironment.getEnvironmentFromResourceEnv(Main.class);
// and now start by system properties user.dir
StrolchBootstrapper bootstrapper = new StrolchBootstrapper(Main.class);
Main.agent = bootstrapper.setupByUserDir(env, "runtime");
Main.agent.initialize();
Main.agent.start();
} catch (Throwable e) {
logger.error("Failed to start " + APP_NAME + " due to: " + e.getMessage(), e);
throw e;
}
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
try {
Thread.sleep(200);
System.out.println("Shutting down ...");
Main.agent.stop();
Main.agent.destroy();
} catch (InterruptedException e) {
logger.error("Failed to stop " + APP_NAME + " due to " + e.getMessage(), e);
}
}
});
long took = System.currentTimeMillis() - start;
logger.info("Started " + APP_NAME + " in " + (StringHelper.formatMillisecondsDuration(took)));
}
}

View File

@ -0,0 +1,84 @@
package ${package};
import java.util.concurrent.TimeUnit;
import li.strolch.agent.api.ComponentContainer;
import li.strolch.agent.api.StrolchAgent;
import li.strolch.agent.impl.SimplePostInitializer;
import li.strolch.execution.ArchiveExecutedActivitiesJob;
import li.strolch.execution.ExecutionHandler;
import li.strolch.handler.mail.MailHandler;
import li.strolch.job.JobMode;
import li.strolch.job.StrolchJobsHandler;
import li.strolch.policy.ReloadPoliciesJob;
import li.strolch.policy.ReloadPrivilegeHandlerJob;
import li.strolch.runtime.configuration.RuntimeConfiguration;
import li.strolch.utils.helper.ExceptionHelper;
public class PostInitializer extends SimplePostInitializer {
public PostInitializer(ComponentContainer container, String componentName) {
super(container, componentName);
}
@Override
public void start() throws Exception {
if (!getContainer().hasComponent(StrolchJobsHandler.class))
return;
StrolchJobsHandler jobsHandler = getComponent(StrolchJobsHandler.class);
// Manually triggered jobs to run once on startup
// jobsHandler.register(XXX.class).runNow();
// special jobs which are triggered by an admin, and not run at startup
jobsHandler.register(ReloadPoliciesJob.class);
jobsHandler.register(ReloadPrivilegeHandlerJob.class);
// recurring jobs
// jobsHandler.registerAndScheduleJob(XXX.class);
if (getContainer().hasComponent(ExecutionHandler.class)) {
StrolchAgent agent = getContainer().getAgent();
ArchiveExecutedActivitiesJob archiveExecutedActivitiesJob = new ArchiveExecutedActivitiesJob(agent,
JobMode.Recurring, 5, TimeUnit.MINUTES, 6, TimeUnit.HOURS);
jobsHandler.register(archiveExecutedActivitiesJob).runNow();
}
notifyStart();
super.start();
}
private void notifyStart() {
if (!(getConfiguration().getBoolean("notifyStart", Boolean.FALSE) && getContainer()
.hasComponent(MailHandler.class)))
return;
String recipients = getConfiguration().getString("notifyStartRecipients", "");
if (recipients.isEmpty()) {
logger.error("config param notifyStartRecipients is empty, can not notify of boot!");
return;
}
StrolchAgent agent = getContainer().getAgent();
RuntimeConfiguration runtimeConfiguration = agent.getStrolchConfiguration().getRuntimeConfiguration();
String subject = runtimeConfiguration.getApplicationName() + ":" + runtimeConfiguration.getEnvironment()
+ " Startup Complete!";
String body = "Dear User\n\n" //
+ "The " + getConfiguration().getRuntimeConfiguration().getApplicationName()
+ " Server has just completed startup with version " //
+ agent.getVersion().getAppVersion().getArtifactVersion() //
+ "\n\n" //
+ "\tYour Server.";
try {
getContainer().getComponent(MailHandler.class).sendMail(subject, body, recipients);
} catch (Exception e) {
logger.error("Notifying of server startup failed: " + ExceptionHelper.getRootCause(e), e);
}
}
}

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!-- encoders are assigned the type
ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
<encoder>
<pattern>%d [%thread] %-5level %class{36}:%line %method - %msg%n</pattern>
</encoder>
</appender>
<root level="info">
<appender-ref ref="STDOUT" />
</root>
</configuration>

View File

@ -0,0 +1,49 @@
package ${package};
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertEquals;
import li.strolch.model.Resource;
import li.strolch.persistence.api.StrolchTransaction;
import li.strolch.privilege.model.Certificate;
import li.strolch.testbase.runtime.RuntimeMock;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
public class SimpleTest {
private static final String SRC_PATH = "src/test/resources/runtime-SimpleTest";
private static final String TARGET_PATH = "target/" + SimpleTest.class;
private static RuntimeMock runtimeMock;
private static Certificate certificate;
@BeforeClass
public static void beforeClass() {
runtimeMock = new RuntimeMock().mockRuntime(TARGET_PATH, SRC_PATH);
runtimeMock.startContainer();
certificate = runtimeMock.loginTest();
}
@AfterClass
public static void afterClass() {
if (certificate != null)
runtimeMock.logout(certificate);
if (runtimeMock != null)
runtimeMock.destroyRuntime();
}
@Test
public void shouldLoadIntoRealm() {
try (StrolchTransaction tx = runtimeMock.openUserTx(certificate, true)) {
Resource ball = tx.getResourceBy("Ball", "yellowBall", true);
assertTrue(ball.hasParameter("parameters", "color"));
assertEquals("yellow", ball.getParameter("parameters", "color", true).getValue());
}
}
}

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!-- encoders are assigned the type
ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
<encoder>
<pattern>%d [%thread] %-5level %class{36}:%line %method - %msg%n</pattern>
</encoder>
</appender>
<root level="info">
<appender-ref ref="STDOUT" />
</root>
</configuration>

View File

@ -5,9 +5,9 @@
<Parameters>
<!-- parameters for the container itself -->
<Parameter name="secretKey" value="58d27145-5d1a-48ea-9e1c-f5a522f6a19f"/>
<Parameter name="secretSalt" value="25bd8911-0008-464f-82b8-4c5200db8dd7"/>
<Parameter name="autoPersistOnPasswordChange" value="true" />
<Parameter name="secretKey" value="test-secret"/>
<Parameter name="secretSalt" value="test-secret"/>
<Parameter name="autoPersistOnUserChangesData" value="true" />
</Parameters>
<EncryptionHandler class="li.strolch.privilege.handler.DefaultEncryptionHandler">
@ -37,6 +37,9 @@
<Policies>
<Policy name="DefaultPrivilege" class="li.strolch.privilege.policy.DefaultPrivilege" />
<Policy name="ModelPrivilege" class="li.strolch.runtime.privilege.ModelPrivilege" />
<Policy name="RoleAccessPrivilege" class="li.strolch.privilege.policy.RoleAccessPrivilege" />
<Policy name="UserAccessPrivilege" class="li.strolch.privilege.policy.UserAccessPrivilege" />
<Policy name="UserSessionAccessPrivilege" class="li.strolch.privilege.policy.UsernameFromCertificatePrivilege"/>
</Policies>
</Privilege>

View File

@ -4,10 +4,16 @@
<Privilege name="li.strolch.privilege.handler.SystemAction" policy="DefaultPrivilege">
<Allow>li.strolch.runtime.privilege.StrolchSystemAction</Allow>
<Allow>li.strolch.runtime.privilege.StrolchSystemActionWithResult</Allow>
<Allow>li.strolch.persistence.postgresql.PostgreSqlSchemaInitializer</Allow>
</Privilege>
<Privilege name="PrivilegeAction" policy="DefaultPrivilege">
<Allow>PersistSessions</Allow>
<Allow>GetCertificates</Allow>
<Privilege name="li.strolch.service.api.Service" policy="DefaultPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="li.strolch.model.query.StrolchQuery" policy="DefaultPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="li.strolch.search.StrolchSearch" policy="DefaultPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="GetResource" policy="ModelPrivilege">

View File

@ -1,12 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<Users>
<User userId="0" username="agent">
<User userId="1" username="agent">
<State>SYSTEM</State>
<Roles>
<Role>agent</Role>
</Roles>
</User>
<User userId="1" username="admin" password="cb69962946617da006a2f95776d78b49e5ec7941d2bdb2d25cdb05f957f64344" salt="61646d696e">
<!-- Password: admin -->
<User userId="3" username="test" password="fdd9d2def3475e1d5cc87107b87e14fd6adbca664c2874fc379a1e53931c0428" salt="74657374">
<Firstname>Application</Firstname>
<Lastname>Administrator</Lastname>
<State>ENABLED</State>
@ -15,8 +16,7 @@
<Role>AppUser</Role>
</Roles>
<Properties>
<Property name="organization" value="eitchnet.ch" />
<Property name="organizationalUnit" value="Development" />
<Property name="realm" value="defaultRealm" />
</Properties>
</User>
</Users>

View File

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8"?>
<StrolchConfiguration>
<env id="dev">
<Runtime>
<applicationName>${appName}</applicationName>
<Properties>
<locale>en</locale>
<verbose>true</verbose>
</Properties>
</Runtime>
<Component>
<name>PrivilegeHandler</name>
<api>li.strolch.runtime.privilege.PrivilegeHandler</api>
<impl>li.strolch.runtime.privilege.DefaultStrolchPrivilegeHandler</impl>
<Properties>
<privilegeConfigFile>PrivilegeConfig.xml</privilegeConfigFile>
</Properties>
</Component>
<Component>
<name>RealmHandler</name>
<api>li.strolch.agent.api.RealmHandler</api>
<impl>li.strolch.agent.impl.DefaultRealmHandler</impl>
<depends>PrivilegeHandler</depends>
<Properties>
<realms>defaultRealm</realms>
<dataStoreMode>TRANSIENT</dataStoreMode>
<dataStoreFile>Model.xml</dataStoreFile>
<enableObserverUpdates>true</enableObserverUpdates>
</Properties>
</Component>
<Component>
<name>ServiceHandler</name>
<api>li.strolch.service.api.ServiceHandler</api>
<impl>li.strolch.service.api.DefaultServiceHandler</impl>
<depends>RealmHandler</depends>
<depends>PrivilegeHandler</depends>
<Properties>
<verbose>true</verbose>
</Properties>
</Component>
<Component>
<name>PostInitializer</name>
<api>li.strolch.agent.api.PostInitializer</api>
<impl>${package}.PostInitializer</impl>
<depends>ServiceHandler</depends>
<Properties>
</Properties>
</Component>
</env>
</StrolchConfiguration>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<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.xsd">
<!-- include root model here -->
<IncludeFile file="../../../runtime/data/Model.xml"/>
<!-- add test specific model data here -->
</StrolchModel>

View File

@ -0,0 +1 @@
target/

View File

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<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">
<parent>
<artifactId>li.strolch</artifactId>
<groupId>li.strolch</groupId>
<version>1.6.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>li.strolch.mvn.archetype.webapp</artifactId>
<packaging>maven-archetype</packaging>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>false</filtering>
</resource>
</resources>
<extensions>
<extension>
<groupId>org.apache.maven.archetype</groupId>
<artifactId>archetype-packaging</artifactId>
<version>3.1.2</version>
</extension>
</extensions>
</build>
</project>

View File

@ -0,0 +1,40 @@
<archetype-descriptor
xsi:schemaLocation="http://maven.apache.org/plugins/maven-archetype-plugin/archetype-descriptor/1.0.0
http://maven.apache.org/xsd/archetype-descriptor-1.0.0.xsd"
xmlns="http://maven.apache.org/plugins/maven-archetype-plugin/archetype-descriptor/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
name="li.strolch.mvn.archetype.webapp">
<requiredProperties>
<requiredProperty key="appName">
<defaultValue>Strolch App</defaultValue>
</requiredProperty>
</requiredProperties>
<fileSets>
<fileSet filtered="true" packaged="true" encoding="UTF-8">
<directory>src/main/java</directory>
</fileSet>
<fileSet filtered="true" encoding="UTF-8">
<directory>src/main/resources</directory>
</fileSet>
<fileSet filtered="true" packaged="true" encoding="UTF-8">
<directory>src/test/java</directory>
</fileSet>
<fileSet filtered="true" encoding="UTF-8">
<directory>src/test/resources</directory>
</fileSet>
<fileSet filtered="true" encoding="UTF-8">
<directory>src/main/webapp</directory>
</fileSet>
<fileSet filtered="true" encoding="UTF-8">
<directory>runtime</directory>
</fileSet>
<fileSet filtered="true" encoding="UTF-8">
<directory></directory>
<includes>
<include>README.md</include>
</includes>
</fileSet>
</fileSets>
</archetype-descriptor>

View File

@ -0,0 +1,61 @@
Strolch Project: ${appName} / ${artifactId}
======================================
This is a Strolch project which is started by a servlet container as this
project builds WARs.
The project's runtime directory is in the root folder and contains the
configuration and data files needed to start via the `StartupListener`.
The test has it's own runtime directory, with its own configuration, but the
model file in the data directory points to the main runtime directory and uses
that model file, so that one does not need to duplicate resource files.
Preparation
------------------
Please change the SCM connection in the pom.xml:
<scm>
<!-- TODO: Change this to your SCM URL -->
<connection>scm:git:https://github.com/4treesCH/strolch.git</connection>
<developerConnection>scm:git:https://github.com/4treesCH/strolch.git</developerConnection>
<url>https://github.com/4treesCH/strolch</url>
</scm>
Before you are able to start the app, you need to update the path in the
`StrolchBootstrap.xml` file in web `src/main/webapp/WEB-INF`. There add a new
environment with the following format:
<env id="dev.${username}" default="true">
<root>${path.to.runtime.directory}</root>
<environment>dev</environment>
</env>
Now install web dependencies:
cd src/main/webapp
npm install
gulp
Running tests
-------------------------
mvn clean test
Building WAR
--------------------------
Without compressing the web files:
mvn clean package
With compressing the web files for local runtime:
mvn clean package -Prelease -Pdev.local
And if you want to prepare for deployment, which uses a different environment:
mvn clean package -Prelease -Dstrolch.env=<env from StrolchBootstrap.xml>

View File

@ -0,0 +1,375 @@
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>${groupId}</groupId>
<artifactId>${artifactId}</artifactId>
<name>${appName}</name>
<version>${version}</version>
<packaging>war</packaging>
<scm>
<!-- TODO: Change this to your SCM URL -->
<connection>scm:git:https://github.com/4treesCH/strolch.git</connection>
<developerConnection>scm:git:https://github.com/4treesCH/strolch.git</developerConnection>
<url>https://github.com/4treesCH/strolch</url>
</scm>
<properties>
<appFinalName>${artifactId}</appFinalName>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.build.timestamp.format>yyyy-MM-dd HH:mm:ss</maven.build.timestamp.format>
<buildTimestamp>${maven.build.timestamp}</buildTimestamp>
<jdk.version>1.8</jdk.version>
<!-- compile time dependencies -->
<slf4j.version>1.7.26</slf4j.version>
<logback.version>1.2.3</logback.version>
<gson.version>2.8.5</gson.version>
<jersey.version>2.29</jersey.version>
<annotation.version>1.3.2</annotation.version>
<serverlet.version>4.0.1</serverlet.version>
<jaxrs.api.version>2.1.1</jaxrs.api.version>
<jaxrs.ri.version>2.29</jaxrs.ri.version>
<websocket.version>1.1</websocket.version>
<jaxb.api.version>2.4.0-b180830.0359</jaxb.api.version>
<tyrus.version>1.13</tyrus.version>
<strolch.version>1.6.0-SNAPSHOT</strolch.version>
<!-- test time dependencies -->
<junit.version>4.12</junit.version>
<hamcrest.version>2.1</hamcrest.version>
<!-- maven plug-in dependencies -->
<buildnumber-maven-plugin.version>1.4</buildnumber-maven-plugin.version>
<maven-compiler-plugin.version>3.8.1</maven-compiler-plugin.version>
<maven-jar-plugin.version>3.1.2</maven-jar-plugin.version>
<maven-exec-plugin.version>1.6.0</maven-exec-plugin.version>
<maven-war-plugin.version>3.2.3</maven-war-plugin.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>li.strolch</groupId>
<artifactId>li.strolch.bom</artifactId>
<type>pom</type>
<version>${strolch.version}</version>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>${gson.version}</version>
</dependency>
<!-- Restful API -->
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>${jaxb.api.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>${serverlet.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
<version>${jaxrs.api.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.bundles</groupId>
<artifactId>jaxrs-ri</artifactId>
<version>${jaxrs.ri.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey</groupId>
<artifactId>jersey-bom</artifactId>
<version>${jersey.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.glassfish.tyrus</groupId>
<artifactId>tyrus-client</artifactId>
<version>${tyrus.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.tyrus</groupId>
<artifactId>tyrus-container-grizzly-client</artifactId>
<version>${tyrus.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.tyrus</groupId>
<artifactId>tyrus-container-grizzly-server</artifactId>
<version>${tyrus.version}</version>
</dependency>
<!-- websocket -->
<dependency>
<groupId>javax.websocket</groupId>
<artifactId>javax.websocket-api</artifactId>
<version>${websocket.version}</version>
<scope>provided</scope>
</dependency>
<!-- test -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-core</artifactId>
<version>${hamcrest.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-library</artifactId>
<version>${hamcrest.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- base -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
<!-- strolch -->
<dependency>
<groupId>li.strolch</groupId>
<artifactId>li.strolch.model</artifactId>
</dependency>
<dependency>
<groupId>li.strolch</groupId>
<artifactId>li.strolch.agent</artifactId>
</dependency>
<dependency>
<groupId>li.strolch</groupId>
<artifactId>li.strolch.rest</artifactId>
</dependency>
<dependency>
<groupId>li.strolch</groupId>
<artifactId>li.strolch.service</artifactId>
</dependency>
<dependency>
<groupId>li.strolch</groupId>
<artifactId>li.strolch.testbase</artifactId>
<scope>test</scope>
</dependency>
<!-- web -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
</dependency>
<dependency>
<groupId>javax.websocket</groupId>
<artifactId>javax.websocket-api</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.bundles</groupId>
<artifactId>jaxrs-ri</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.tyrus</groupId>
<artifactId>tyrus-client</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.tyrus</groupId>
<artifactId>tyrus-container-grizzly-client</artifactId>
</dependency>
<!-- testing -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-library</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>${appFinalName}</finalName>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>**/*.properties</include>
<include>StrolchBootstrap.xml</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
<filtering>false</filtering>
<excludes>
<exclude>**/*.properties</exclude>
<exclude>StrolchBootstrap.xml</exclude>
</excludes>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>buildnumber-maven-plugin</artifactId>
<version>${buildnumber-maven-plugin.version}</version>
<executions>
<execution>
<phase>validate</phase>
<goals>
<goal>create</goal>
</goals>
</execution>
</executions>
<configuration>
<doCheck>false</doCheck>
<doUpdate>false</doUpdate>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<source>${jdk.version}</source>
<target>${jdk.version}</target>
<showDeprecation>true</showDeprecation>
<showWarnings>true</showWarnings>
<compilerArgument>-Xlint:all</compilerArgument>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>${maven-war-plugin.version}</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
<warName>${warFinalName}</warName>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
<!-- for dev: always enable strolch environment "dev" -->
<profile>
<id>dev.local</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<strolch.env>dev.local</strolch.env>
</properties>
</profile>
<profile>
<id>release</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>${maven-exec-plugin.version}</version>
<executions>
<execution>
<id>exec-npm-install</id>
<phase>generate-sources</phase>
<configuration>
<executable>npm</executable>
<arguments>
<argument>install</argument>
</arguments>
<workingDirectory>${basedir}/src/main/webapp</workingDirectory>
</configuration>
<goals>
<goal>exec</goal>
</goals>
</execution>
<execution>
<id>exec-gulp</id>
<phase>generate-sources</phase>
<configuration>
<executable>gulp</executable>
<workingDirectory>${basedir}/src/main/webapp</workingDirectory>
</configuration>
<goals>
<goal>exec</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
<warName>${warFinalName}</warName>
<packagingExcludes>app/**/*,node_modules/**/*</packagingExcludes>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>

View File

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<Privilege>
<Container>
<Parameters>
<!-- parameters for the container itself -->
<Parameter name="secretKey" value="CHANGE-ME-1"/>
<Parameter name="secretSalt" value="CHANGE-ME-2"/>
<Parameter name="persistSessions" value="true"/>
<Parameter name="autoPersistOnUserChangesData" value="false"/>
<Parameter name="privilegeConflictResolution" value="MERGE"/>
</Parameters>
<EncryptionHandler class="li.strolch.privilege.handler.DefaultEncryptionHandler">
<Parameters>
<!-- WARNING: If you change iterations or keyLength, then all passwords are invalid -->
<!-- default algorithm is: PBKDF2WithHmacSHA512 -->
<Parameter name="hashAlgorithm" value="PBKDF2WithHmacSHA512" />
<!-- default iterations: 200000 -->
<Parameter name="hashIterations" value="10000" />
<!-- default key length: 256 -->
<Parameter name="hashKeyLength" value="256" />
</Parameters>
</EncryptionHandler>
<PersistenceHandler class="li.strolch.privilege.handler.XmlPersistenceHandler">
<Parameters>
<Parameter name="usersXmlFile" value="PrivilegeUsers.xml" />
<Parameter name="rolesXmlFile" value="PrivilegeRoles.xml" />
</Parameters>
</PersistenceHandler>
<UserChallengeHandler class="li.strolch.privilege.handler.ConsoleUserChallengeHandler">
</UserChallengeHandler>
</Container>
<Policies>
<Policy name="DefaultPrivilege" class="li.strolch.privilege.policy.DefaultPrivilege"/>
<Policy name="ModelPrivilege" class="li.strolch.runtime.privilege.ModelPrivilege" />
<Policy name="RoleAccessPrivilege" class="li.strolch.privilege.policy.RoleAccessPrivilege"/>
<Policy name="UserAccessPrivilege" class="li.strolch.privilege.policy.UserAccessPrivilege"/>
<Policy name="UserSessionAccessPrivilege" class="li.strolch.privilege.policy.UsernameFromCertificatePrivilege"/>
</Policies>
</Privilege>

View File

@ -0,0 +1,189 @@
<?xml version="1.0" encoding="UTF-8"?>
<Roles>
<Role name="agent">
<Privilege name="li.strolch.privilege.handler.SystemAction" policy="DefaultPrivilege">
<Allow>li.strolch.runtime.privilege.StrolchSystemAction</Allow>
<Allow>li.strolch.runtime.privilege.StrolchSystemActionWithResult</Allow>
</Privilege>
<Privilege name="PrivilegeAction" policy="DefaultPrivilege">
<Allow>PersistSessions</Allow>
<Allow>GetCertificates</Allow>
</Privilege>
<Privilege name="GetResource" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="GetOrder" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="GetActivity" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="AddResource" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="AddOrder" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="AddActivity" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="UpdateResource" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="UpdateOrder" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="UpdateActivity" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="RemoveResource" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="RemoveOrder" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="RemoveActivity" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
</Role>
<Role name="AppUser">
<Privilege name="li.strolch.service.api.Service" policy="DefaultPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="li.strolch.model.query.StrolchQuery" policy="DefaultPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="li.strolch.search.StrolchSearch" policy="DefaultPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="li.strolch.report.ReportSearch" policy="DefaultPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="GetResource" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="GetOrder" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="GetActivity" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="AddResource" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="AddOrder" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="AddActivity" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="UpdateResource" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="UpdateOrder" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="UpdateActivity" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="RemoveResource" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="RemoveOrder" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="RemoveActivity" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
</Role>
<Role name="StrolchAdmin">
<Privilege name="PrivilegeAddUser" policy="UserAccessPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="PrivilegeSetUserPassword" policy="UserAccessPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="li.strolch.handler.operationslog.OperationsLog" policy="DefaultPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="li.strolch.search.StrolchSearch" policy="DefaultPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="li.strolch.report.ReportSearch" policy="DefaultPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="li.strolch.model.query.StrolchQuery" policy="DefaultPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="li.strolch.job.StrolchJob" policy="DefaultPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="li.strolch.job.StrolchJobsHandler" policy="DefaultPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="li.strolch.service.api.Service" policy="DefaultPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
</Role>
<Role name="PrivilegeAdmin">
<Privilege name="PrivilegeAddUser" policy="UserAccessPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="PrivilegeRemoveUser" policy="UserAccessPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="InvalidateSession" policy="UserSessionAccessPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="PrivilegeSetUserPassword" policy="UserAccessPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="PrivilegeSetUserLocale" policy="UserAccessPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="PrivilegeAction" policy="DefaultPrivilege">
<Allow>Reload</Allow>
<Allow>GetPolicies</Allow>
<Allow>Persist</Allow>
<Allow>GetCertificates</Allow>
<Allow>PersistSessions</Allow>
</Privilege>
<Privilege name="PrivilegeGetUser" policy="UserAccessPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="PrivilegeSetUserState" policy="UserAccessPrivilege">
<Deny>SYSTEM</Deny>
<Allow>DISABLED</Allow>
<Allow>ENABLED</Allow>
</Privilege>
<Privilege name="PrivilegeAddRoleToUser" policy="UserAccessPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="PrivilegeGetRole" policy="RoleAccessPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="GetSession" policy="UserSessionAccessPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="PrivilegeModifyUser" policy="UserAccessPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="PrivilegeRemoveRole" policy="RoleAccessPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="PrivilegeRemoveRoleFromUser" policy="UserAccessPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="PrivilegeModifyRole" policy="RoleAccessPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="PrivilegeAddRole" policy="RoleAccessPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
</Role>
</Roles>

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<Users>
<User userId="0" username="agent">
<State>SYSTEM</State>
<Roles>
<Role>agent</Role>
</Roles>
</User>
<!-- Password: admin -->
<User userId="1" username="admin" password="cb69962946617da006a2f95776d78b49e5ec7941d2bdb2d25cdb05f957f64344" salt="61646d696e">
<Firstname>Application</Firstname>
<Lastname>Administrator</Lastname>
<State>ENABLED</State>
<Locale>en-GB</Locale>
<Roles>
<Role>AppUser</Role>
<Role>StrolchAdmin</Role>
<Role>PrivilegeAdmin</Role>
</Roles>
<Properties>
<Property name="organization" value="strolch.li"/>
<Property name="organizationalUnit" value="Development"/>
</Properties>
</User>
</Users>

View File

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="UTF-8"?>
<StrolchConfiguration>
<env id="dev">
<Runtime>
<applicationName>${appName}</applicationName>
<Properties>
<locale>en</locale>
<verbose>true</verbose>
</Properties>
</Runtime>
<Component>
<name>PrivilegeHandler</name>
<api>li.strolch.runtime.privilege.PrivilegeHandler</api>
<impl>li.strolch.runtime.privilege.DefaultStrolchPrivilegeHandler</impl>
<Properties>
<privilegeConfigFile>PrivilegeConfig.xml</privilegeConfigFile>
</Properties>
</Component>
<Component>
<name>RealmHandler</name>
<api>li.strolch.agent.api.RealmHandler</api>
<impl>li.strolch.agent.impl.DefaultRealmHandler</impl>
<depends>PrivilegeHandler</depends>
<Properties>
<realms>defaultRealm</realms>
<dataStoreMode>TRANSIENT</dataStoreMode>
<dataStoreFile>Model.xml</dataStoreFile>
<enableObserverUpdates>true</enableObserverUpdates>
</Properties>
</Component>
<Component>
<name>EnumHandler</name>
<api>li.strolch.runtime.query.enums.EnumHandler</api>
<impl>li.strolch.runtime.query.enums.DefaultEnumHandler</impl>
<depends>RealmHandler</depends>
</Component>
<Component>
<name>ServiceHandler</name>
<api>li.strolch.service.api.ServiceHandler</api>
<impl>li.strolch.service.api.DefaultServiceHandler</impl>
<depends>RealmHandler</depends>
<depends>PrivilegeHandler</depends>
<Properties>
<verbose>true</verbose>
</Properties>
</Component>
<Component>
<name>PolicyHandler</name>
<api>li.strolch.policy.PolicyHandler</api>
<impl>li.strolch.policy.DefaultPolicyHandler</impl>
<Properties>
<readPolicyFile>true</readPolicyFile>
</Properties>
</Component>
<Component>
<name>MigrationsHandler</name>
<api>li.strolch.migrations.MigrationsHandler</api>
<impl>li.strolch.migrations.MigrationsHandler</impl>
<depends>RealmHandler</depends>
</Component>
<Component>
<name>OperationsLog</name>
<api>li.strolch.handler.operationslog.OperationsLog</api>
<impl>li.strolch.handler.operationslog.OperationsLog</impl>
<depends>RealmHandler</depends>
</Component>
<Component>
<name>StrolchJobsHandler</name>
<api>li.strolch.job.StrolchJobsHandler</api>
<impl>li.strolch.job.StrolchJobsHandler</impl>
<depends>RealmHandler</depends>
</Component>
<Component>
<name>SessionHandler</name>
<api>li.strolch.rest.StrolchSessionHandler</api>
<impl>li.strolch.rest.DefaultStrolchSessionHandler</impl>
<depends>PrivilegeHandler</depends>
<Properties>
<session.ttl.minutes>30</session.ttl.minutes>
<session.reload>true</session.reload>
</Properties>
</Component>
<Component>
<name>RestfulHandler</name>
<api>li.strolch.rest.RestfulStrolchComponent</api>
<impl>li.strolch.rest.RestfulStrolchComponent</impl>
<depends>SessionHandler</depends>
<Properties>
<secureCookie>false</secureCookie>
</Properties>
</Component>
<Component>
<name>PostInitializer</name>
<api>li.strolch.agent.api.PostInitializer</api>
<impl>${package}.PostInitializer</impl>
<depends>RestfulHandler</depends>
<Properties>
</Properties>
</Component>
<Component>
<name>ExecutionHandler</name>
<api>li.strolch.execution.ExecutionHandler</api>
<impl>li.strolch.execution.EventBasedExecutionHandler</impl>
<depends>PostInitializer</depends>
<Properties>
<restartExecution>true</restartExecution>
</Properties>
</Component>
</env>
</StrolchConfiguration>

View File

@ -0,0 +1,3 @@
<StrolchPolicies>
</StrolchPolicies>

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<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.xsd">
<Resource Id="yellowBall" Name="Yellow Ball" Type="Ball">
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
<Parameter Id="color" Name="Color" Type="String" Value="yellow"/>
</ParameterBag>
</Resource>
</StrolchModel>

View File

@ -0,0 +1,196 @@
<?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: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="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="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="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>

View File

@ -0,0 +1,84 @@
package ${package};
import java.util.concurrent.TimeUnit;
import li.strolch.agent.api.ComponentContainer;
import li.strolch.agent.api.StrolchAgent;
import li.strolch.agent.impl.SimplePostInitializer;
import li.strolch.execution.ArchiveExecutedActivitiesJob;
import li.strolch.execution.ExecutionHandler;
import li.strolch.handler.mail.MailHandler;
import li.strolch.job.JobMode;
import li.strolch.job.StrolchJobsHandler;
import li.strolch.policy.ReloadPoliciesJob;
import li.strolch.policy.ReloadPrivilegeHandlerJob;
import li.strolch.runtime.configuration.RuntimeConfiguration;
import li.strolch.utils.helper.ExceptionHelper;
public class PostInitializer extends SimplePostInitializer {
public PostInitializer(ComponentContainer container, String componentName) {
super(container, componentName);
}
@Override
public void start() throws Exception {
if (!getContainer().hasComponent(StrolchJobsHandler.class))
return;
StrolchJobsHandler jobsHandler = getComponent(StrolchJobsHandler.class);
// Manually triggered jobs to run once on startup
// jobsHandler.register(XXX.class).runNow();
// special jobs which are triggered by an admin, and not run at startup
jobsHandler.register(ReloadPoliciesJob.class);
jobsHandler.register(ReloadPrivilegeHandlerJob.class);
// recurring jobs
// jobsHandler.registerAndScheduleJob(XXX.class);
if (getContainer().hasComponent(ExecutionHandler.class)) {
StrolchAgent agent = getContainer().getAgent();
ArchiveExecutedActivitiesJob archiveExecutedActivitiesJob = new ArchiveExecutedActivitiesJob(agent,
JobMode.Recurring, 5, TimeUnit.MINUTES, 6, TimeUnit.HOURS);
jobsHandler.register(archiveExecutedActivitiesJob).runNow();
}
notifyStart();
super.start();
}
private void notifyStart() {
if (!(getConfiguration().getBoolean("notifyStart", Boolean.FALSE) && getContainer()
.hasComponent(MailHandler.class)))
return;
String recipients = getConfiguration().getString("notifyStartRecipients", "");
if (recipients.isEmpty()) {
logger.error("config param notifyStartRecipients is empty, can not notify of boot!");
return;
}
StrolchAgent agent = getContainer().getAgent();
RuntimeConfiguration runtimeConfiguration = agent.getStrolchConfiguration().getRuntimeConfiguration();
String subject = runtimeConfiguration.getApplicationName() + ":" + runtimeConfiguration.getEnvironment()
+ " Startup Complete!";
String body = "Dear User\n\n" //
+ "The " + getConfiguration().getRuntimeConfiguration().getApplicationName()
+ " Server has just completed startup with version " //
+ agent.getVersion().getAppVersion().getArtifactVersion() //
+ "\n\n" //
+ "\tYour Server.";
try {
getContainer().getComponent(MailHandler.class).sendMail(subject, body, recipients);
} catch (Exception e) {
logger.error("Notifying of server startup failed: " + ExceptionHelper.getRootCause(e), e);
}
}
}

View File

@ -0,0 +1,57 @@
package ${package};
import javax.ws.rs.ApplicationPath;
import java.util.logging.Level;
import li.strolch.rest.RestfulStrolchComponent;
import li.strolch.rest.StrolchRestfulExceptionMapper;
import li.strolch.rest.endpoint.*;
import li.strolch.rest.filters.*;
import org.glassfish.jersey.logging.LoggingFeature;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.ServerProperties;
@ApplicationPath("rest")
public class RestfulApplication extends ResourceConfig {
public RestfulApplication() {
// ${appName} services
//packages(GatewayResource.class.getPackage().getName());
// strolch services
register(AuthenticationService.class);
register(StrolchJobsResource.class);
register(ReportResource.class);
register(ControlResource.class);
register(EnumQuery.class);
register(Inspector.class);
register(UserSessionsService.class);
register(PrivilegeUsersService.class);
register(PrivilegeRolesService.class);
register(PrivilegePoliciesService.class);
register(OperationsLogResource.class);
register(VersionQuery.class);
// filters
register(AuthenticationRequestFilter.class);
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, null));
property(ServerProperties.TRACING, "ALL");
property(ServerProperties.TRACING_THRESHOLD, "TRACE");
}
}
}

View File

@ -1,4 +1,4 @@
package li.strolch.minimal.rest.main;
package ${package};
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
@ -15,7 +15,7 @@ import org.slf4j.LoggerFactory;
public class StartupListener implements ServletContextListener {
private static final Logger logger = LoggerFactory.getLogger(StartupListener.class);
private static final String APP_NAME = "Strolch Minimal Rest";
private static final String APP_NAME = "${appName}";
private StrolchAgent agent;
@ -25,8 +25,8 @@ public class StartupListener implements ServletContextListener {
logger.info("Starting " + APP_NAME + "...");
long start = System.currentTimeMillis();
try {
String boostrapFileName = "/WEB-INF/" + StrolchBootstrapper.FILE_BOOTSTRAP;
InputStream bootstrapFile = sce.getServletContext().getResourceAsStream(boostrapFileName);
String bootstrapFileName = "/" + StrolchBootstrapper.FILE_BOOTSTRAP;
InputStream bootstrapFile = getClass().getResourceAsStream(bootstrapFileName);
StrolchBootstrapper bootstrapper = new StrolchBootstrapper(StartupListener.class);
this.agent = bootstrapper.setupByBootstrapFile(StartupListener.class, bootstrapFile);
this.agent.initialize();

View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<StrolchBootstrap>
<!-- use attribute default="true" to allow optional values -->
<env id="dev" default="true">
<!-- optional, to load different environment -->
<environment>dev</environment>
<!-- always optional root tag, default: system property user.dir -->
<root>runtime</root>
<!-- optional config tag, if default="true": config/ -->
<!-- <config>config</config> -->
<!-- optional data tag, if default="true": data/ -->
<!-- <data>data</data> -->
<!-- optional temp tag, if default="true": temp/ -->
<!-- <temp>temp</temp> -->
</env>
<env id="dev.local" default="true">
<root>${project.basedir}/runtime</root>
<environment>dev</environment>
</env>
</StrolchBootstrap>

View File

@ -0,0 +1,6 @@
groupId=${project.groupId}
artifactId=${project.artifactId}
artifactVersion=${project.version}
scmRevision=${buildNumber}
scmBranch=${scmBranch}
buildTimestamp=${buildTimestamp}

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!-- encoders are assigned the type
ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
<encoder>
<pattern>%d [%thread] %-5level %class{36}:%line %method - %msg%n</pattern>
</encoder>
</appender>
<root level="info">
<appender-ref ref="STDOUT" />
</root>
</configuration>

View File

@ -0,0 +1,3 @@
{
"directory": "app/bower_components"
}

View File

@ -0,0 +1,4 @@
package-lock.json
node_modules/
app/bower_components/
www/

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.1" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd">
<!-- For WebSockets with large frames -->
<context-param>
<param-name>org.apache.tomcat.websocket.textBufferSize</param-name>
<param-value>1048576</param-value>
</context-param>
<context-param>
<param-name>org.apache.tomcat.websocket.binaryBufferSize</param-name>
<param-value>1048576</param-value>
</context-param>
</web-app>

View File

@ -0,0 +1,12 @@
CustomWeb = {
//
};
(function () {
var basePath = window.location.pathname.substr(0, window.location.pathname.indexOf('/index.html'));
basePath = basePath.substr(0, basePath.lastIndexOf('/'));
CustomWeb.baseRestPath = basePath + '/rest';
console.log('Base REST Path is ' + CustomWeb.baseRestPath);
CustomWeb.baseWsPath = basePath + '/websocket';
console.log('Base WebSocket Path is ' + CustomWeb.baseRestPath);
})();

View File

@ -0,0 +1,36 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>${appName}</title>
<meta name="description" content="${appName}">
<!-- Required meta tags always come first -->
<meta charset="utf-8">
<link rel="shortcut icon" type="image/png" href="../favicon.ico"/>
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<script src="./bower_components/webcomponentsjs/webcomponents-lite.js"></script>
<script src="./bower_components/strolchjs/Strolch.js"></script>
<script src="./CustomWeb.js"></script>
<link rel="import" href="./src/c-app.html">
<style>
body {
margin: 0;
padding: 0;
font-family: 'Roboto', 'Noto', sans-serif;
background-color: #eeeeee;
}
</style>
</head>
<body unresolved>
<c-app></c-app>
</body>
</html>

View File

@ -0,0 +1,149 @@
<!-- Components -->
<link rel="import" href="../bower_components/polymer/polymer.html">
<link rel="import" href="../bower_components/paper-menu/paper-menu.html">
<link rel="import" href="../bower_components/paper-item/paper-item.html">
<link rel="import" href="../bower_components/paper-styles/color.html">
<link rel="import" href="../bower_components/strolch-wc-inspector/strolch-wc-inspector-menu.html">
<link rel="import" href="./c-compute-behavior.html">
<dom-module id="c-app-menu">
<template>
<style is="custom-style">
paper-menu {
--paper-menu-selected-item: {
background-color: var(--paper-indigo-50);
};
}
paper-menu paper-item {
cursor: pointer;
}
paper-menu paper-item:hover {
background-color: var(--paper-indigo-100);
}
paper-menu paper-item:focus:before,
paper-menu paper-item:focus:after {
background: unset;
}
paper-item {
display: flex;
flex-direction: row;
align-content: center;
justify-content: flex-start;
height: 1px;
}
.menu-item {
min-width: 160px;
}
.info-div {
display: block !important;
font-size: small;
color: darkgray;
}
.container {
padding-bottom: 20px;
padding-left: 15px;
padding-right: 15px;
@apply --layout-horizontal;
@apply --layout-start-justified;
}
.strolch {
color: #7f7f7f;
font-family: monospace;
font-weight: 600;
font-size: 30px;
text-shadow: 2px 2px 3px #7f7f7f;
margin: auto;
}
</style>
<paper-menu id="menu" selected="{{page}}" attr-for-selected="id" on-tap="onMenuTap" hidden="[[sessionInvalid]]">
<paper-item id="reports" class="menu-item">Reports</paper-item>
</paper-menu>
<strolch-wc-inspector-menu selected-page="[[page]]"
on-menu-tap="onInspectorMenuTap"></strolch-wc-inspector-menu>
<paper-menu on-tap="onMenuTap">
<paper-item id="logout" class="menu-item">Logout</paper-item>
</paper-menu>
<paper-material id="container" class="container info-div" elevation="0">
<p>[[userConfig.firstname]] [[userConfig.lastname]] / [[userConfig.username]]</p>
<p title="[[version.appVersion.scmRevision]]">[[version.appVersion.artifactVersion]]</p>
</paper-material>
<paper-material id="container" class="container" elevation="0">
<paper-dropdown-menu label="[[localize('language')]]">
<paper-listbox class="dropdown-content" selected="{{userLocale}}" attr-for-selected="data">
<paper-item data="de">Deutsch</paper-item>
<paper-item data="en">English</paper-item>
</paper-listbox>
</paper-dropdown-menu>
</paper-material>
<paper-material id="container" class="container" elevation="0">
<p class="strolch">Strolch</p>
</paper-material>
</template>
<script>
Polymer({
is: "c-app-menu",
properties: {
userConfig: {
type: Object
},
version: {
type: Object
},
userLocale: {
type: String,
notify: true
}
},
observers: [
"observePageChange(page)"
],
observePageChange: function (page) {
if (this.selectedPage != page) {
this.$.menu.select(page);
}
},
behaviors: [
CustomComputeBehavior, StrolchLocalizeBehavior
],
onInspectorMenuTap: function (event) {
this.selectedPage = event.detail.target.id;
this.fire('menu-tap', {target: event.detail.target});
},
onMenuTap: function (event) {
this.selectedPage = event.detail.sourceEvent.target.id;
this.fire('menu-tap', {target: event.detail.sourceEvent.target});
}
});
</script>
</dom-module>

View File

@ -0,0 +1,135 @@
<!-- Components -->
<link rel="import" href="../bower_components/polymer/polymer.html">
<link rel="import" href="../bower_components/app-route/app-route.html">
<link rel="import" href="../bower_components/app-route/app-location.html">
<dom-module id="c-app-routing">
<template>
<!-- Routing -->
<app-location use-hash-as-path="[[useHashAsPath]]" route="{{route}}"></app-location>
<app-route route="{{route}}" data="{{routeData}}" tail="{{routeTail}}" pattern="/:page"></app-route>
</template>
<script>
Polymer({
<!-- Settings -->
is: "c-app-routing",
<!-- Properties -->
properties: {
useHashAsPath: {
type: Boolean
},
authValid: {
type: Boolean
},
loginPage: {
type: String,
value: "login"
},
defaultPage: {
type: String,
value: "default"
},
exposedPages: {
type: Array,
value: []
},
returnPath: {
type: String
},
page: {
type: String,
notify: true
},
path: {
type: String
},
routeData: {
type: Object,
notify: true
},
routeTail: {
type: Object,
notify: true
}
},
<!-- Observers -->
observers: [
"observeRouteData(routeData)",
"observeRoutePath(route.path)",
"redirectApp(path, authValid)"
],
observeRouteData: function (routeData) {
// redirect to login or default if there is no page
if (!routeData.page) {
var firstPage = this.authValid ? this.defaultPage : this.loginPage;
this.replaceCurrentPage(firstPage);
}
else {
// this debounces multiple page changes by the app route component
this.set("page", routeData.page);
}
},
observeRoutePath: function (routePath) {
// this debounces multiple path changes by the app route component
this.set("path", routePath);
},
redirectApp: function (path, authValid) {
// find the base of the path
var pathBase = path.split("/")[1];
// prevent navigation to login if the auth is still valid
if (pathBase == this.loginPage && authValid == true) {
// instead return to a path that was tried to access before login or the default page
if (this.returnPath) this.replaceCurrentPath(this.returnPath);
else this.replaceCurrentPage(this.defaultPage);
}
// prevent navigation to any page but exposed pages if the auth is invalid
var accessesExposedPage = (pathBase == this.loginPage || this.exposedPages.indexOf(pathBase) != -1);
if (!accessesExposedPage && authValid == false) {
// instead save this path to return after login and go to login
this.set("returnPath", path);
this.replaceCurrentPage(this.loginPage);
}
},
<!-- Functions -->
replaceCurrentPage: function (currentPage) {
this.replaceCurrentPath("/" + currentPage);
},
replaceCurrentPath: function (currentPath) {
var _currentPath = (this.useHashAsPath ? "#" : "") + currentPath;
history.replaceState({}, _currentPath, _currentPath);
this.updateRoutePath(currentPath);
},
pushNextPage: function (nextPage, keepQueryParams) {
this.pushNextPath("/" + nextPage, keepQueryParams);
},
pushNextPath: function (nextPath, keepQueryParams) {
if (keepQueryParams) {
var queryParams = Strolch.getQueryParamsAsString();
if (Strolch.isNotEmptyString(queryParams)) {
if (nextPath.endsWith('/'))
nextPath = nextPath + '?' + queryParams;
else
nextPath = nextPath + '/?' + queryParams;
}
}
var _nextPath = (this.useHashAsPath ? "#" : "") + nextPath;
history.pushState({}, _nextPath, _nextPath);
this.updateRoutePath(nextPath);
},
updateRoutePath: function (path) {
if (this.route.path != path) {
this.set("route.path", path);
this.notifyPath("route.path");
}
}
});
</script>
</dom-module>

View File

@ -0,0 +1,592 @@
<link rel="import" href="../bower_components/polymer/polymer.html">
<link rel="import" href="../bower_components/iron-pages/iron-pages.html">
<link rel="import" href="../bower_components/iron-selector/iron-selector.html">
<link rel="import" href="../bower_components/iron-icons/iron-icons.html">
<link rel="import" href="../bower_components/app-route/app-location.html">
<link rel="import" href="../bower_components/app-route/app-route.html">
<link rel="import" href="../bower_components/app-layout/app-toolbar/app-toolbar.html">
<link rel="import" href="../bower_components/app-layout/app-toolbar/app-toolbar.html">
<link rel="import" href="../bower_components/app-layout/app-drawer/app-drawer.html">
<link rel="import" href="../bower_components/app-layout/app-drawer-layout/app-drawer-layout.html">
<link rel="import" href="../bower_components/paper-icon-button/paper-icon-button.html">
<link rel="import" href="../bower_components/paper-toast/paper-toast.html">
<link rel="import" href="../bower_components/paper-styles/color.html">
<link rel="import" href="../bower_components/paper-styles/default-theme.html">
<link rel="import" href="../bower_components/paper-styles/shadow.html">
<link rel="import" href="../bower_components/paper-styles/typography.html">
<link rel="import" href="../bower_components/strolch-wc-localize-behavior/strolch-wc-localize-behavior.html">
<link rel="import" href="../bower_components/strolch-wc-styles/strolch-wc-styles.html">
<link rel="import" href="../bower_components/strolch-wc-auth/strolch-wc-auth.html">
<link rel="import" href="../bower_components/strolch-wc-inspector/strolch-wc-inspector.html">
<link rel="import" href="../bower_components/strolch-wc-inspector/strolch-wc-users.html">
<link rel="import" href="../bower_components/strolch-wc-inspector/strolch-wc-roles.html">
<link rel="import" href="../bower_components/strolch-wc-inspector/strolch-wc-sessions.html">
<link rel="import" href="../bower_components/strolch-wc-inspector/strolch-wc-jobs.html">
<link rel="import" href="../bower_components/strolch-wc-inspector/strolch-wc-operations-log.html">
<link rel="import" href="../bower_components/strolch-wc-inspector/strolch-wc-inspector-menu.html">
<link rel="import" href="../bower_components/strolch-wc-inspector/strolch-wc-control.html">
<link rel="import" href="../bower_components/strolch-wc-reports/strolch-wc-reports.html">
<link rel="import" href="./c-compute-behavior.html">
<link rel="import" href="./c-app-routing.html">
<link rel="import" href="./c-app-menu.html">
<link rel="import" href="./c-view404.html">
<dom-module id="c-app">
<template>
<style is="custom-styles" include="strolch-wc-styles">
:host {
--app-primary-color: var(--paper-blue-900);
--app-secondary-color: black;
display: block;
margin: 0;
padding: 0;
font-size: 14px;
}
app-header {
color: #fff;
background-color: var(--app-primary-color);
}
app-header paper-icon-button {
--paper-icon-button-ink-color: white;
}
app-toolbar {
background-color: var(--paper-blue-900);
color: #fff;
}
strolch-wc-reports {
--app-pages-content-padding: 0 0;
}
.padded-view {
padding-left: 10px;
padding-right: 10px;
}
paper-toast {
max-width: 500px !important;
}
</style>
<!-- Routing -->
<c-app-routing id="appRouting"
login-page="login"
default-page="maintenance"
auth-valid="[[authTokenValid]]"
page="{{page}}"
route-tail="{{routeTail}}"
use-hash-as-path></c-app-routing>
<!-- Content -->
<app-drawer-layout fullbleed force-narrow>
<!-- Drawer content -->
<app-drawer id="drawer" opened="false">
<app-toolbar>Menu</app-toolbar>
<div style="height: 100%; overflow: auto;">
<c-app-menu page="[[page]]"
version="[[appVersion]]"
user-config="[[userConfig]]"
user-locale="{{userLocale}}"
on-menu-tap="onMenuTap"></c-app-menu>
</div>
</app-drawer>
<!-- Main content -->
<app-header-layout has-scrolling-region>
<div class="g-row">
<div class="g-12">
<app-header condenses reveals effects="waterfall">
<app-toolbar hidden="[[!authTokenValid]]">
<paper-icon-button icon="menu" drawer-toggle></paper-icon-button>
<div main-title>[[localize(page)]]</div>
</app-toolbar>
</app-header>
</div>
</div>
<div class="g-row">
<div class="g-12">
<iron-pages selected="[[page]]" attr-for-selected="id">
<strolch-wc-auth id="login"
app-title="[[localize('appTitle')]]"
base-path="../"
show-version
on-strolch-session-valid="sessionValidated"></strolch-wc-auth>
<template is="dom-if" if="[[equal(page, 'inspector')]]" restamp>
<strolch-wc-inspector id="inspector"
base-path="../"
route="{{subroute}}"></strolch-wc-inspector>
</template>
<template is="dom-if" if="[[equal(page, 'operations-log')]]" restamp>
<strolch-wc-operations-log id="operations-log"
base-path="../"
route="{{subroute}}"></strolch-wc-operations-log>
</template>
<template is="dom-if" if="[[equal(page, 'jobs')]]" restamp>
<strolch-wc-jobs id="jobs" base-path="../" route="{{subroute}}"></strolch-wc-jobs>
</template>
<template is="dom-if" if="[[equal(page, 'reports')]]" restamp>
<strolch-wc-reports id="reports"
base-path="../"
base-rest-path="[[baseRestPath]]"
locales-path="../../../locales.json"
route="{{subroute}}"
facet-limit="[[reportFacetLimit]]"
propagate-show-dialog></strolch-wc-reports>
</template>
<template is="dom-if" if="[[equal(page, 'users')]]" restamp>
<strolch-wc-users id="users" base-path="../" route="{{subroute}}"></strolch-wc-users>
</template>
<template is="dom-if" if="[[equal(page, 'roles')]]" restamp>
<strolch-wc-roles id="roles" base-path="../" route="{{subroute}}"></strolch-wc-roles>
</template>
<template is="dom-if" if="[[equal(page, 'sessions')]]" restamp>
<strolch-wc-sessions id="sessions"
base-path="../"
route="{{subroute}}"></strolch-wc-sessions>
</template>
<template is="dom-if" if="[[equal(page, 'control')]]" restamp>
<strolch-wc-control id="control"
class="padded-view"
base-path="../"
toolbar-config="{{toolbarConfig}}"
search-term="{{searchTerm}}"
user-location="{{userLocation}}"
route="{{routeTail}}"
propagate-show-dialog></strolch-wc-control>
</template>
<template is="dom-if" if="[[equal(page, 'view404')]]" restamp>
<c-view404 id="view404"></c-view404>
</template>
</iron-pages>
</div>
</div>
<paper-toast id="toast"
text="[[toastText]]"
duration="1750"
on-iron-overlay-closed="_onToastClosed"></paper-toast>
<paper-toast id="newVersionAvailableToast"
text="[[localize('newVersionAvailableRefreshRequired')]]"
duration="0">
<paper-button class="refresh" on-tap="refreshBrowser">[[localize('refresh')]]</paper-button>
</paper-toast>
</app-header-layout>
</app-drawer-layout>
<paper-dialog id="dlg" modal>
<h2>[[dlgTitle]]</h2>
<p id="dlgText"></p>
<div class="buttons">
<paper-button dialog-confirm autofocus>{{localize('close')}}</paper-button>
</div>
</paper-dialog>
<paper-dialog id="confirmationDlg" modal>
<h2>[[dlgTitle]]</h2>
<p id="confirmationDlgText"></p>
<div class="buttons">
<paper-button dialog-dismiss>{{localize('cancel')}}</paper-button>
<paper-button dialog-confirm autofocus>{{localize('ok')}}</paper-button>
</div>
</paper-dialog>
<paper-dialog id="serverNotConnectedDlg" modal>
<h2>[[localize('serverNotAvailable')]]</h2>
<p>[[localize('serverNotAvailableMsg')]]</p>
<div class="buttons">
<paper-button autofocus on-tap="reconnect">{{localize('reconnect')}}</paper-button>
</div>
</paper-dialog>
<iron-ajax id="ajaxGetVersion"
url="[[baseRestPath]]/strolch/version"
content-type="application/json"
handle-as="json"
method="GET"
on-response="onGetVersionResponse"
on-error="onGetVersionError"
auto></iron-ajax>
<iron-ajax id="ajaxPutLocale" content-type="application/json" handle-as="json" method="PUT"></iron-ajax>
</template>
<script>
Polymer({
is: 'c-app',
behaviors: [
CustomComputeBehavior, StrolchLocalizeBehavior
],
properties: {
page: {
type: String,
observer: 'observePage'
},
authToken: {
type: String
},
authTokenValid: {
type: Boolean,
value: false
},
userConfig: {
type: Object,
value: function () {
return Strolch.getUserConfig();
}
},
userLocale: {
type: String,
observer: "userLocaleChanged",
value: function () {
return Strolch.getUserLocale();
}
},
appVersion: {
type: Object
},
route: {
type: Object
},
dlgTitle: {
type: String
},
dlgText: {
type: String
},
queuedToasts: {
type: Array,
value: []
},
toastText: {
type: String,
value: 'default-toast-text'
},
reportFacetLimit: {
type: Number,
value: function () {
return 25;
}
}
},
observers: [],
listeners: {
"cx-show-toast": "onShowToast",
"cx-server-not-available": "onServerNotAvailable",
"cx-session-invalid": "onSessionInvalid",
"cx-privilege-denied": "onPrivilegeDenied",
"cx-page-change": "onPageChange",
"cx-show-dialog": "onShowDialog",
"strolch-show-dialog": "onShowStrolchDialog",
"cx-show-confirmation": "onShowConfirmation",
"cx-show-notification": "onShowNotification",
"cx-clear-notification": "onClearNotification",
"cx-log-out": "onLogOut",
},
observePage: function (newValue, oldValue) {
if (newValue) {
this._reloadPage(newValue);
}
},
onPageChange: function (event) {
if (event && event.detail && event.detail.page) {
var pageName = event.detail.page;
// set the next page
this.$.appRouting.pushNextPage(pageName, event.detail.keepQueryParams);
} else {
console.log("received page change without new value");
}
},
onMenuTap: function (event) {
var action = event.detail.target.id;
this.closeDrawer();
// depending on the action either navigate or log out
switch (action) {
case "logout":
this.fire("cx-log-out");
break;
default:
this.changePage(action);
}
},
toggleDrawer: function () {
this.$$("#drawer").toggle();
},
closeDrawer: function () {
this.$$("#drawer").close();
},
onShowToast: function (e) {
if (this.$.toast.opened) {
// purge if we have too many
if (this.queuedToasts.length > 5)
this.queuedToasts = [];
this.queuedToasts.push(e.detail.text);
} else {
this.toastText = e.detail.text;
this.$.toast.open();
}
},
_onToastClosed: function (e) {
if (this.queuedToasts.length > 0) {
this.toastText = this.queuedToasts.splice(0, 1)[0];
this.$.toast.open();
}
},
onShowStrolchDialog: function (event) {
var dlgTitle;
if (event.detail.title != null)
dlgTitle = event.detail.title;
else
dlgTitle = event.detail.isError ? 'errorOccurred' : 'info';
var dlgText = event.detail.text;
this._showDialog(dlgTitle, dlgText);
},
onShowDialog: function (event) {
var dlgTitle;
if (event.detail.title != null)
dlgTitle = event.detail.title;
else
dlgTitle = event.detail.isError ? 'errorOccurred' : 'info';
var dlgText = event.detail.message;
this._showDialog(dlgTitle, dlgText);
},
onShowConfirmation: function (event) {
var dlgTitle = event.detail.title;
var dlgText = event.detail.text;
var dlgCallback = event.detail.callback;
this._showConfirmation(dlgTitle, dlgText, dlgCallback);
},
onShowNotification: function (event) {
this.$.toolBar.showNotification(event.detail);
},
onClearNotification: function (event) {
this.$.toolBar.clearNotification(event.detail);
},
onLogOut: function (event) {
this.$.login.logout();
this.set("authTokenValid", false);
},
onServerNotAvailable: function (event) {
clearInterval(this.checkForNewVersionInterval);
this.$.dlg.close();
this.$.confirmationDlg.close();
this.$.serverNotConnectedDlg.open();
},
onSessionInvalid: function (event) {
var that = this;
console.log(this.routeTail);
if (this.routeTail.prefix != '/login') {
this._showConfirmation('sessionInvalid', 'sessionInvalidConfirmNavToLogin', function () {
that.deleteCookie('strolch.authorization');
that.set("authTokenValid", false);
});
}
},
onPrivilegeDenied: function (event) {
if (this.authTokenValid) {
this._showDialog('privilegeDenied', 'privilegeDeniedText', this.requestEventToUrl(event));
} else {
console.warn("Privilege denied to URL " + this.requestEventToUrl(event), this.requestErrorToMsg(event));
}
},
userLocaleChanged: function (newValue, oldValue) {
if (newValue && oldValue) {
console.log('User locale changed to ' + newValue);
this.$.ajaxPutLocale.generateRequest();
Strolch.setUserLocale(newValue);
window.location.reload();
} else if (this.userConfig == null && Strolch.getUserConfig() != null && Strolch.getUserConfig().locale != newValue) {
this.userConfig = Strolch.getUserConfig();
this.userConfig.locale = newValue;
Strolch.setUserConfig(this.userConfig);
this.$.ajaxPutLocale.generateRequest();
}
},
sessionValidated: function () {
console.log("Session validated.");
var userLocale = Strolch.getUserLocale();
var userConfig = Strolch.getUserConfig();
if (userLocale !== userConfig.locale) {
console.log("Updating server side locale for user " + userConfig.username + " to " + userLocale);
userConfig.locale = userLocale;
Strolch.setUserConfig(userConfig);
this.$.ajaxPutLocale.url = this.baseRestPath + "/strolch/sessions/" + userConfig.sessionId + "/locale/" + userLocale;
this.$.ajaxPutLocale.generateRequest();
}
this.set("authToken", Strolch.getAuthToken());
this.set("authTokenValid", true);
this.set("userConfig", userConfig);
},
logout: function () {
sessionStorage.clear();
Polymer.dom(this.root).querySelectorAll('#auth')[0].logout();
Strolch.clearStorageData();
this.deleteCookie("strolch.authorization");
},
_showDialog: function (dlgTitle, dlgText, dlgReason) {
if (this.localize) {
this.dlgTitle = this.localize(dlgTitle);
dlgText = this.localize(dlgText);
if (dlgReason)
dlgText += ": " + dlgReason;
console.log("Message: " + this.dlgTitle + ': ' + dlgText);
this.$.dlgText.innerHTML = this.localize(dlgText);
this.$.dlg.open();
} else {
this.debounce('show-dlg', function () {
this.dlgTitle = this.localize(dlgTitle);
dlgText = this.localize(dlgText);
if (dlgReason)
dlgText += ": " + dlgReason;
console.log("Message: " + this.dlgTitle + ': ' + dlgText);
this.$.dlgText.innerHTML = this.localize(dlgText);
this.$.dlg.open();
}, 250);
}
},
_showConfirmation: function (dlgTitle, dlgText, dlgCallback) {
if (this.localize) {
this.dlgTitle = this.localize(dlgTitle);
dlgText = this.localize(dlgText);
console.log("Message: " + this.dlgTitle + ': ' + dlgText);
this.$.confirmationDlgText.innerHTML = this.localize(dlgText);
var dlg = this.$.confirmationDlg;
var onClose = function (event) {
dlgCallback(event.detail.confirmed);
dlg.removeEventListener("iron-overlay-closed", onClose);
};
dlg.addEventListener("iron-overlay-closed", onClose);
dlg.open();
} else {
this.debounce('show-dlg', function () {
this.dlgTitle = this.localize(dlgTitle);
dlgText = this.localize(dlgText);
console.log("Message: " + this.dlgTitle + ': ' + dlgText);
this.$.confirmationDlgText.innerHTML = this.localize(dlgText);
var dlg = this.$.confirmationDlg;
var onClose = function (event) {
dlgCallback(event.detail.confirmed);
dlg.removeEventListener("iron-overlay-closed", onClose);
};
dlg.addEventListener("iron-overlay-closed", onClose);
dlg.open();
}, 250);
}
},
refreshBrowser: function () {
localStorage['appScmRevision'] = this.scmRevision;
document.location.reload();
},
checkForNewVersion: function () {
this.$.ajaxGetVersion.generateRequest();
},
reconnect: function () {
this.$.serverNotConnectedDlg.close();
this.onGetVersionResponse = function (event) {
var version = event.detail.response;
this.scmRevision = version.appVersion.scmRevision;
localStorage['appScmRevision'] = this.scmRevision;
document.location.reload();
};
this.$.ajaxGetVersion.generateRequest();
},
onGetVersionResponse: function (event) {
var version = event.detail.response;
Strolch.setAppVersion(version);
this.scmRevision = version.appVersion.scmRevision;
if (localStorage['appScmRevision'] == null) {
localStorage['appScmRevision'] = this.scmRevision;
} else if (this.scmRevision != localStorage['appScmRevision']) {
console.log("App SCM Revision has changed from " + localStorage['appScmRevision'] + " to " + this.scmRevision + ". Need to refresh browser...");
this.$.newVersionAvailableToast.open();
}
this.appVersion = version;
},
onGetVersionError: function (event) {
console.log(event);
var readyState = event.detail.request.xhr.readyState;
var status = event.detail.request.xhr.status;
if (readyState === 4 && status === 404) {
console.log("Ignoring 404 for get version, as server is probably still starting...");
} else {
this.onRequestError(event);
}
},
/* Lifecycle */
attached: function () {
var that = this;
setTimeout(function () {
that.checkForNewVersion();
}, 3000);
this.checkForNewVersionInterval = setInterval(function () {
that.checkForNewVersion();
}, 10000);
},
_reloadPage: function (pageName) {
this.debounce('page-reload', function () {
var page = this.$$('#' + pageName);
if (page && page.reload) {
console.log('Reloading ' + pageName);
page.reload();
}
}, 100);
},
});
</script>
</dom-module>

View File

@ -0,0 +1,463 @@
<script>
CustomComputeBehavior = {
properties: {
baseRestPath: {
type: String,
value: function () {
return CustomWeb.baseRestPath;
}
},
localesPath: {
type: String,
value: '../../locales.json'
}
},
/*
* Strolch functions
*/
hasQueryPrivilege: function (privilegeValue) {
return Strolch.hasRole('StrolchAdmin') || Strolch.hasQueryPrivilege(privilegeValue);
},
hasSearchPrivilege: function (privilegeValue) {
return Strolch.hasRole('StrolchAdmin') || Strolch.hasSearchPrivilege(privilegeValue);
},
hasServicePrivilege: function (privilegeValue) {
return Strolch.hasRole('StrolchAdmin') || Strolch.hasServicePrivilege(privilegeValue);
},
hasPrivilege: function (privilege, value) {
return Strolch.hasRole('StrolchAdmin') || Strolch.hasPrivilege(privilege, value);
},
hasRole: function (name) {
return Strolch.hasRole('StrolchAdmin') || Strolch.hasRole(name);
},
hasComponent: function (name) {
return Strolch.hasComponent(name);
},
/*
* Compute functions
*/
hasMsg: function (value) {
return Strolch.isNotEmptyString(value) && value != "-";
},
isEqual: function (v1, v2) {
return v1 === v2;
},
stringToArray: function (string) {
if (string == null || string.length == 0)
return [];
var a = [];
var b = string.split(',');
for (var i = 0; i < b.length; i++) {
a.push(b[i].trim());
}
return a;
},
stringArrayLength: function (string) {
if (string == null || string.length == 0)
return 0;
return string.split(',').length;
},
isDefined: function (arg0) {
return arg0 != undefined;
},
isNull: function (arg0) {
return arg0 == undefined || arg0 == null;
},
isNotNull: function (arg0) {
return arg0 != undefined && arg0 != null;
},
isNaN: function (arg0) {
return this.stringEmpty(arg0) || isNaN(arg0);
},
equal: function (arg0, arg1) {
return arg0 == arg1;
},
notEqual: function (arg0, arg1) {
return arg0 != arg1;
},
defined: function (arg0) {
return !!arg0;
},
greater: function (arg0, arg1) {
return arg0 > arg1;
},
greaterEqual: function (arg0, arg1) {
return arg0 >= arg1;
},
lesser: function (arg0, arg1) {
return arg0 < arg1;
},
lesserEqual: function (arg0, arg1) {
return arg0 <= arg1;
},
and: function (arg0, arg1) {
return !!(arg0 && arg1);
},
or: function (arg0, arg1) {
return !!(arg0 || arg1);
},
arrayLength: function (array) {
return (array && array.length) ? array.length : 0;
},
arrayFilled: function (array) {
return !!(array && array.length && array.length > 0);
},
arraySizeLessThan: function (array, size) {
return array != null && array.length < size;
},
arraySizeGreaterThanOrEq: function (array, size) {
return array != null && array.length >= size;
},
arrayEquals: function (array1, array2) {
if (array1 == null && array2 == null)
return true;
if (array1 == null && array2 != null)
return false;
if (array2 == null && array1 != null)
return false;
return (array1.length == array2.length) && array1.every(function (element, index) {
return element === array2[index];
});
},
add: function (arg0, arg1) {
return Number(arg0) + Number(arg1);
},
sub: function (arg0, arg1) {
return Number(arg0) - Number(arg1);
},
round: function (value) {
return Math.round(value * 1000) / 1000;
},
stringEmpty: function () {
for (var i in arguments) {
var arg = arguments[i];
if (!arg || arg.length == 0) return true;
}
return false;
},
isEmptyString: function (val) {
return typeof val == 'undefined' || val == null || val === '';
},
isNotEmptyString: function (val) {
return !this.isEmptyString(val);
},
isChrome: function () {
var isChromium = window.chrome, //
winNav = window.navigator, //
vendorName = winNav.vendor, //
isOpera = winNav.userAgent.indexOf("OPR") > -1, //
isIEedge = winNav.userAgent.indexOf("Edge") > -1, //
isIOSChrome = winNav.userAgent.match("CriOS");
if (isIOSChrome) {
return true;
} else if (isChromium !== null && //
typeof isChromium !== "undefined" && //
vendorName === "Google Inc." && //
isOpera === false && //
isIEedge === false) {
return true;
} else {
return false;
}
},
isFirefox: function () {
return navigator.userAgent.toLowerCase().indexOf('firefox') > -1;
},
isIE: function () {
var isIE = /*@cc_on!@*/false || !!document.documentMode;
return isIE;
},
isEdge: function () {
return !Susi.Compute.isIE() && !!window.StyleMedia;
},
/*
* Date Time functions
*/
formatDateTime: function (string) {
return Strolch.toLocalDateTime(string);
},
// gets the clock time as displayed in the UI
getTimeString: function (datetime) {
var hour = datetime.getHours().toString();
var min = datetime.getMinutes().toString();
hour = hour.length < 2 ? "0" + hour : hour;
min = min.length < 2 ? "0" + min : min;
return hour + ":" + min;
},
// gets the calendar date as displayed in the UI
getDateString: function (datetime, addCentury) {
if (typeof (datetime) == 'string') {
datetime = new Date(datetime);
}
var day = (datetime.getDate()).toString();
var month = (datetime.getMonth() + 1).toString();
var year = (datetime.getFullYear()).toString();
day = day.length < 2 ? "0" + day : day;
month = month.length < 2 ? "0" + month : month;
year = addCentury ? year : year.slice(-2);
return day + "." + month + "." + year;
},
// gets the date of a date string from getDateString()
getDate: function (datetimeString) {
var splitString = datetimeString.split(".");
if (splitString.length != 3) return null;
var year = Number(splitString[2]);
var month = Number(splitString[1]) - 1;
var day = Number(splitString[0]);
return new Date(year, month, day);
},
// gets the clock time of the current time
getCurrentTimeString: function () {
return Susi.Datetime.getTimeString(new Date());
},
toDateTime: function (val) {
function pad10(i) {
if (i < 10) return '0' + i;
return i;
}
function pad100(i) {
if (i < 10) return '00' + i;
if (i < 100) return '0' + i;
return i;
}
if (Strolch.isEmptyString(val) || val == '-') return '-';
var date = new Date(val);
var y = date.getFullYear();
var m = pad10(date.getMonth() + 1);
var d = pad10(date.getDate());
var h = pad10(date.getHours());
var mi = pad10(date.getMinutes());
var s = pad10(date.getSeconds());
var mil = pad100(date.getMilliseconds());
return y + m + d + h + mi + s;
},
// gets the calendar date of the current time
getCurrentDateString: function () {
return Susi.Datetime.getDateString(new Date());
},
clearTime: function (date) {
date.setHours(0);
date.setMinutes(0);
date.setSeconds(0);
date.setMilliseconds(0);
return date;
},
dateToJson: function (date) {
date.setTime(date.getTime() - date.getTimezoneOffset() * 60 * 1000);
return date.toJSON();
},
// returns true if a datetime has past
isPast: function (datetime) {
return Date.now() > datetime.getTime();
},
// returns true if a datetime is future
isFuture: function (datetime) {
return Date.now() < datetime.getTime();
},
// turns hours into milliseconds
hToMs: function (hour) {
return hour * 3600000;
},
// turns milliseconds into hours
msToH: function (milliseconds) {
return milliseconds / 3600000;
},
getCookie: function (cname) {
var name = cname + "=";
var decodedCookie = decodeURIComponent(document.cookie);
var ca = decodedCookie.split(';');
for (var i = 0; i < ca.length; i++) {
var c = ca[i];
while (c.charAt(0) == ' ') {
c = c.substring(1);
}
if (c.indexOf(name) == 0) {
return c.substring(name.length, c.length);
}
}
return null;
},
setCookie: function (cname, cvalue, validDays) {
var d = new Date();
d.setTime(d.getTime() + (validDays * 24 * 60 * 60 * 1000));
var expires = "expires=" + d.toUTCString();
document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/";
},
deleteCookie: function (cname) {
document.cookie = cname + '=; Path=/; expires=Thu, 01 Jan 1970 00:00:01 GMT;';
},
// fires an event that will change the page of the app
changePage: function (page, keepQueryParams) {
if (typeof keepQueryParams !== 'boolean')
keepQueryParams = false;
this.fire("cx-page-change", {
page: page,
keepQueryParams: keepQueryParams
});
},
// convenience function to get the error message from responses
onRequestError: function (event) {
var readyState = event.detail.request.xhr.readyState;
var response = event.detail.request.xhr.response;
var status = event.detail.request.xhr.status;
var isError = status && status >= 500;
if (readyState === 4 && status === 0) {
this.fire("cx-server-not-available", event);
} else if (status == 401) {
this.fire("cx-session-invalid", event);
} else if (status == 403) {
this.fire("cx-privilege-denied", event);
} else {
this.requestErrorToMsg(event);
}
},
requestEventToUrl: function (event) {
return event.detail.detail.request.url;
},
requestErrorToMsg: function (event) {
var response;
if (event.detail.request)
response = event.detail.request.xhr.response;
else
response = event.detail.detail.error.message;
var msg = "";
var isError = false;
if (response && response.state) {
isError = response.state === "EXCEPTION";
}
if (response && response.i18n) {
var args = [response.i18n.key];
Object.keys(response.i18n.values).forEach(function (key) {
args.push(key);
args.push(response.i18n.values[key]);
});
msg = this.localize.apply(this, args);
} else {
if (response && response.msg) {
msg = response.msg;
} else if (typeof (response) == 'string') {
if (response.trim().charAt(0) == '{') {
var json = JSON.parse(response);
if (json && json.i18n) {
var args = [json.i18n.key];
Object.keys(json.i18n.values).forEach(function (key) {
args.push(key);
args.push(json.i18n.values[key]);
});
msg = this.localize.apply(this, args);
} else if (json.msg) {
msg = json.msg;
} else {
msg = response;
}
} else {
msg = response;
}
} else if (event.detail && event.detail.error && event.detail.error.message && event.detail.request && event.detail.request.url) {
msg = event.detail.error.message + ": " + event.detail.request.url;
} else if (event.detail && event.detail.error && event.detail.error.message) {
msg = event.detail.error.message;
} else {
console.error("Missing error message on request error", event);
msg = "Request Failed and no message available!";
}
}
this.showDialog(msg, isError);
},
// fires an event that will show a dialog
showDialog: function (message, isError) {
this.fire("cx-show-dialog", {
message: message,
isError: isError
});
},
// fires an event that will show a dialog
showDialogTitle: function (title, message) {
this.fire("cx-show-dialog", {
title: title,
message: message
});
},
// fires an event that will show a confirmation dialog
showConfirmation: function (title, text, callback) {
this.fire("cx-show-confirmation", {
title: title,
text: text,
callback: callback
});
},
// fires an event that will show a notification below the toolbar
showNotification: function (id, message, faIcon, action1, callback1, action2, callback2, action3, callback3) {
this.fire("cx-show-notification", {
id: id,
message: message,
faIcon: faIcon,
action1: action1,
callback1: callback1,
action2: action2,
callback2: callback2,
action3: action3,
callback3: callback3
});
},
clearNotification: function (id) {
this.fire("cx-clear-notification", {
id: id
});
},
showError: function (title, text) {
this.showDialogTitle(title, text, true);
},
showToast: function (text) {
this.fire('cx-show-toast', {text: text});
}
};
</script>

View File

@ -0,0 +1,23 @@
<link rel="import" href="../bower_components/polymer/polymer.html">
<dom-module id="c-view404">
<template>
<style>
:host {
display: block;
min-height: 100%;
padding: 10px 20px;
}
</style>
Oops you hit a 404.
</template>
<script>
Polymer({
is: 'c-view404'
});
</script>
</dom-module>

View File

@ -0,0 +1,32 @@
{
"name": "ipsc-gateway",
"authors": [
"Robert von Burg <eitch@eitchnet.ch>"
],
"private": true,
"dependencies": {
"strolchjs": "4treesCH/strolchjs#^0.2.7",
"strolch-wc-styles": "4treesCH/strolch-wc-styles#^0.2.0",
"strolch-wc-auth": "4treesCH/strolch-wc-auth#^0.7.7",
"strolch-wc-inspector": "4treesCH/strolch-wc-inspector#^0.18.0",
"strolch-wc-localize-behavior": "4treesCH/strolch-wc-localize-behavior#^1.1.4",
"strolch-wc-reports": "4treesCH/strolch-wc-reports#^0.2.3",
"strolch-wc-paging": "4treesCH/strolch-wc-paging#^0.1.1",
"strolch-wc-ws-observer": "4treesCH/strolch-wc-ws-observer#^0.1.5",
"polymer": "Polymer/polymer#^1.11.3",
"iron-pages": "PolymerElements/iron-pages#^1.0.8",
"font-awesome": "fortawesome-font-awesome#^4.7.0",
"app-route": "PolymerElements/app-route#^1.0.1",
"app-layout": "PolymerElements/app-layout#^1.0.1",
"paper-dropdown-menu": "PolymerElements/paper-dropdown-menu#^1.5.1",
"paper-menu": "PolymerElements/paper-menu#^1.3.0",
"paper-icon-button": "PolymerElements/paper-icon-button#^1.1.4",
"paper-header-panel": "PolymerElements/paper-header-panel#^1.1.7",
"paper-input": "PolymerElements/paper-input#^1.1.24",
"paper-radio-group": "PolymerElements/paper-radio-group#^1.2.2",
"paper-toast": "PolymerElements/paper-toast#^1.3.1"
},
"devDependencies": {
}
}

View File

@ -0,0 +1,85 @@
var gulp = require('gulp');
var $ = require('gulp-load-plugins')();
var merge = require('merge-stream');
var del = require('del');
// temporary until gulp 4.0 is released
var runSequence = require('run-sequence');
var vulcanize = require('gulp-vulcanize');
var minify = require('gulp-minify');
var crisper = require('gulp-crisper');
var shell = require('gulp-shell');
var rename = require("gulp-rename");
// Copy All Files At The Root Level
gulp.task('copy', function () {
var svg = gulp.src([
'app/**/*.svg', '!app/bower_components/**/hero.svg', '!app/bower_components/mocha/**/*', '!app/bower_components/**/{demo,test,site}/**/*'
])
.pipe(gulp.dest('www/'));
var imgs = gulp.src([
'app/img/*.svg', 'app/img/*.ico', 'app/img/*.png', 'app/img/*.gif'
])
.pipe(gulp.dest('www/img/'));
var json = gulp.src([
'app/bower_components/strolch-wc-auth/locales.json'
])
.pipe(gulp.dest('www/bower_components/strolch-wc-auth/'));
var app_files = gulp.src([
'app/bower.json', 'app/manifest.json', 'app/locales.json', '**/moment.min.js'
])
.pipe(gulp.dest('www/'));
var js = gulp.src([
'src/**/*'
])
.pipe(gulp.dest('js'));
return merge(svg, imgs, json, app_files, js)
.pipe($.size({title: 'Copy app files to dist dir:'}));
});
gulp.task('vulcanize', function () {
return gulp.src('app/index.html')
.pipe(vulcanize({
stripComments: true,
inlineScripts: true,
inlineCss: true
}))
.pipe(crisper())
.pipe(gulp.dest('www/'));
});
gulp.task('compress', function () {
return gulp.src('www/index.js')
.pipe(minify({}))
.pipe(gulp.dest('www/'))
});
// Clean Output Directory
gulp.task('clean-www', del.bind(null, ['www/']));
// Remove unneeded files
gulp.task('del-files', del.bind(null, ['www/index-min.js']));
gulp.task('move-indexjs-js', function () {
return gulp.src('./www/index-min.js') //
.pipe(rename('index.js'))
.pipe(gulp.dest('./www/'));
});
// bower install
gulp.task('bower', shell.task('bower install'));
// Build Production Files, the Default Task
gulp.task('prepare', ['bower'], function (cb) {
runSequence('clean-www', cb);
});
gulp.task('default', ['prepare'], function (cb) {
runSequence('copy', 'vulcanize', 'compress', 'del-files', cb);
});

View File

@ -0,0 +1,7 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="refresh" content="0;url=./www/index.html" />
</head>
</html>

View File

@ -0,0 +1,42 @@
{
"de": {
"appTitle": "${appName}",
"language": "Sprache",
"reports": "Berichte",
"operations-log": "Betriebsnachrichten",
"jobs": "Jobs",
"sessions": "Sitzungen",
"users": "Benutzer",
"roles": "Rollen",
"control": "Control",
"inspector": "Inspector",
"newVersionAvailableRefreshRequired": "Eine neue Version steht zur Verfügung",
"refresh": "Aktualisieren",
"close": "Schliessen",
"cancel": "Abbrechen",
"ok": "Ok",
"reconnect": "Wiederhestellen",
"serverNotAvailable": "Server nicht erreichbar",
"serverNotAvailableMsg": "Die Verbindung zum Server ist zur Zeit unterbrochen"
},
"en": {
"appTitle": "${appName}",
"language": "Language",
"reports": "Reports",
"operations-log": "Operation Logs",
"jobs": "Jobs",
"sessions": "Sessions",
"users": "Users",
"roles": "Roles",
"control": "Control",
"inspector": "Inspector",
"newVersionAvailableRefreshRequired": "A new version is available",
"refresh": "Refresh",
"close": "Close",
"cancel": "Cancel",
"ok": "Ok",
"reconnect": "Reconnect",
"serverNotAvailable": "Server not available",
"serverNotAvailableMsg": "The connection to the server is currently not available"
}
}

View File

@ -0,0 +1,33 @@
{
"name": "ipsc-gateway-web",
"description": "IPSC Gateway Web",
"version": "0.1.0",
"private": true,
"repository": {
"type": "git",
"url": "git@bitbucket.org:4trees/ipsc.git"
},
"author": "Robert von Burg <robert.vonburg@4trees.ch>",
"license": "Proprietary",
"keywords": [],
"bugs": {
"url": "https://bitbucket.org/4trees/ipsc/issues"
},
"homepage": "www.ipsc.ch",
"devDependencies": {
"bower": "^1.8.0",
"del": "^2.2.2",
"gulp": "^3.9.1",
"gulp-crisper": "^1.1.0",
"gulp-imagemin": "^3.1.1",
"gulp-load-plugins": "^1.4.0",
"gulp-minify": "0.0.15",
"gulp-rename": "^1.2.2",
"gulp-shell": "^0.5.2",
"gulp-size": "^2.1.0",
"gulp-vulcanize": "^6.1.0",
"merge-stream": "^1.0.0",
"run-sequence": "^1.2.2",
"vulcanize": "^1.15.3"
}
}

View File

@ -0,0 +1,49 @@
package ${package};
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertEquals;
import li.strolch.model.Resource;
import li.strolch.persistence.api.StrolchTransaction;
import li.strolch.privilege.model.Certificate;
import li.strolch.testbase.runtime.RuntimeMock;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
public class SimpleTest {
private static final String SRC_PATH = "src/test/resources/runtime-SimpleTest";
private static final String TARGET_PATH = "target/" + SimpleTest.class;
private static RuntimeMock runtimeMock;
private static Certificate certificate;
@BeforeClass
public static void beforeClass() {
runtimeMock = new RuntimeMock().mockRuntime(TARGET_PATH, SRC_PATH);
runtimeMock.startContainer();
certificate = runtimeMock.loginTest();
}
@AfterClass
public static void afterClass() {
if (certificate != null)
runtimeMock.logout(certificate);
if (runtimeMock != null)
runtimeMock.destroyRuntime();
}
@Test
public void shouldLoadIntoRealm() {
try (StrolchTransaction tx = runtimeMock.openUserTx(certificate, true)) {
Resource ball = tx.getResourceBy("Ball", "yellowBall", true);
assertTrue(ball.hasParameter("parameters", "color"));
assertEquals("yellow", ball.getParameter("parameters", "color", true).getValue());
}
}
}

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!-- encoders are assigned the type
ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
<encoder>
<pattern>%d [%thread] %-5level %class{36}:%line %method - %msg%n</pattern>
</encoder>
</appender>
<root level="info">
<appender-ref ref="STDOUT" />
</root>
</configuration>

View File

@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8"?>
<Privilege>
<Container>
<Parameters>
<!-- parameters for the container itself -->
<Parameter name="secretKey" value="test-secret"/>
<Parameter name="secretSalt" value="test-secret"/>
<Parameter name="autoPersistOnUserChangesData" value="true" />
</Parameters>
<EncryptionHandler class="li.strolch.privilege.handler.DefaultEncryptionHandler">
<Parameters>
<!-- WARNING: If you change iterations or keyLength, then all passwords are invalid -->
<!-- default algorithm is: PBKDF2WithHmacSHA512 -->
<Parameter name="hashAlgorithm" value="PBKDF2WithHmacSHA512" />
<!-- default iterations: 200000 -->
<Parameter name="hashIterations" value="10000" />
<!-- default key length: 256 -->
<Parameter name="hashKeyLength" value="256" />
</Parameters>
</EncryptionHandler>
<PersistenceHandler class="li.strolch.privilege.handler.XmlPersistenceHandler">
<Parameters>
<Parameter name="usersXmlFile" value="PrivilegeUsers.xml" />
<Parameter name="rolesXmlFile" value="PrivilegeRoles.xml" />
</Parameters>
</PersistenceHandler>
<UserChallengeHandler class="li.strolch.privilege.handler.ConsoleUserChallengeHandler">
</UserChallengeHandler>
</Container>
<Policies>
<Policy name="DefaultPrivilege" class="li.strolch.privilege.policy.DefaultPrivilege" />
<Policy name="ModelPrivilege" class="li.strolch.runtime.privilege.ModelPrivilege" />
<Policy name="RoleAccessPrivilege" class="li.strolch.privilege.policy.RoleAccessPrivilege" />
<Policy name="UserAccessPrivilege" class="li.strolch.privilege.policy.UserAccessPrivilege" />
<Policy name="UserSessionAccessPrivilege" class="li.strolch.privilege.policy.UsernameFromCertificatePrivilege"/>
</Policies>
</Privilege>

View File

@ -0,0 +1,105 @@
<?xml version="1.0" encoding="UTF-8"?>
<Roles>
<Role name="agent">
<Privilege name="li.strolch.privilege.handler.SystemAction" policy="DefaultPrivilege">
<Allow>li.strolch.runtime.privilege.StrolchSystemAction</Allow>
<Allow>li.strolch.runtime.privilege.StrolchSystemActionWithResult</Allow>
<Allow>li.strolch.persistence.postgresql.PostgreSqlSchemaInitializer</Allow>
</Privilege>
<Privilege name="li.strolch.service.api.Service" policy="DefaultPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="li.strolch.model.query.StrolchQuery" policy="DefaultPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="li.strolch.search.StrolchSearch" policy="DefaultPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="GetResource" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="GetOrder" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="GetActivity" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="AddResource" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="AddOrder" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="AddActivity" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="UpdateResource" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="UpdateOrder" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="UpdateActivity" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="RemoveResource" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="RemoveOrder" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="RemoveActivity" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
</Role>
<Role name="AppUser">
<Privilege name="li.strolch.service.api.Service" policy="DefaultPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="li.strolch.model.query.StrolchQuery" policy="DefaultPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="li.strolch.search.StrolchSearch" policy="DefaultPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="GetResource" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="GetOrder" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="GetActivity" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="AddResource" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="AddOrder" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="AddActivity" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="UpdateResource" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="UpdateOrder" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="UpdateActivity" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="RemoveResource" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="RemoveOrder" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="RemoveActivity" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
</Role>
</Roles>

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<Users>
<User userId="1" username="agent">
<State>SYSTEM</State>
<Roles>
<Role>agent</Role>
</Roles>
</User>
<!-- Password: admin -->
<User userId="3" username="test" password="fdd9d2def3475e1d5cc87107b87e14fd6adbca664c2874fc379a1e53931c0428" salt="74657374">
<Firstname>Application</Firstname>
<Lastname>Administrator</Lastname>
<State>ENABLED</State>
<Locale>en-GB</Locale>
<Roles>
<Role>AppUser</Role>
</Roles>
<Properties>
<Property name="realm" value="defaultRealm" />
</Properties>
</User>
</Users>

View File

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8"?>
<StrolchConfiguration>
<env id="dev">
<Runtime>
<applicationName>${appName}</applicationName>
<Properties>
<locale>en</locale>
<verbose>true</verbose>
</Properties>
</Runtime>
<Component>
<name>PrivilegeHandler</name>
<api>li.strolch.runtime.privilege.PrivilegeHandler</api>
<impl>li.strolch.runtime.privilege.DefaultStrolchPrivilegeHandler</impl>
<Properties>
<privilegeConfigFile>PrivilegeConfig.xml</privilegeConfigFile>
</Properties>
</Component>
<Component>
<name>RealmHandler</name>
<api>li.strolch.agent.api.RealmHandler</api>
<impl>li.strolch.agent.impl.DefaultRealmHandler</impl>
<depends>PrivilegeHandler</depends>
<Properties>
<realms>defaultRealm</realms>
<dataStoreMode>TRANSIENT</dataStoreMode>
<dataStoreFile>Model.xml</dataStoreFile>
<enableObserverUpdates>true</enableObserverUpdates>
</Properties>
</Component>
<Component>
<name>ServiceHandler</name>
<api>li.strolch.service.api.ServiceHandler</api>
<impl>li.strolch.service.api.DefaultServiceHandler</impl>
<depends>RealmHandler</depends>
<depends>PrivilegeHandler</depends>
<Properties>
<verbose>true</verbose>
</Properties>
</Component>
<Component>
<name>PostInitializer</name>
<api>li.strolch.agent.api.PostInitializer</api>
<impl>${package}.PostInitializer</impl>
<depends>ServiceHandler</depends>
<Properties>
</Properties>
</Component>
</env>
</StrolchConfiguration>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<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.xsd">
<!-- include root model here -->
<IncludeFile file="../../../runtime/data/Model.xml"/>
<!-- add test specific model data here -->
</StrolchModel>

10
pom.xml
View File

@ -144,12 +144,12 @@
<module>li.strolch.websocket</module>
<module>li.strolch.performancetest</module>
<module>strolch_minimal_rest</module>
<module>li.strolch.website</module>
<!-- keep a module as last which is deployable to central -->
<module>li.strolch.bom</module>
<module>li.strolch.mvn.archetype.main</module>
<module>li.strolch.mvn.archetype.webapp</module>
</modules>
@ -338,12 +338,6 @@
</dependencyManagement>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<pluginManagement>
<plugins>

View File

@ -1,32 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" output="target/classes" path="src/main/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
<attributes>
<attribute name="maven.pomderived" value="true"/>
<attribute name="org.eclipse.jst.component.dependency" value="/WEB-INF/lib"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="target/classes"/>
</classpath>

View File

@ -1 +0,0 @@
/target/

View File

@ -1,21 +0,0 @@
Strolch Minimal Rest
======================
A minimal Strolch project for Restful Applications which builds using Maven and the end result starts a
servlet based web application which runs in e.g. Apache Tomcat 8.0
Build
-------------------
On the console run:
$ mvn clean package -Dstrolch.env=dev
This creates a WAR in target/strolch_minimal.war
Run
---------------------
Copy the WAR to your webapps/ folder in Tomcat and start Tomcat.
If everything goes find, then you should find a line as follows:
ComponentContainerImpl start - strolch_minimal_rest:dev All 4 Strolch Components started. Strolch is now ready to be used. Have fun =))
Eclipse
--------------------
One should only need to add the web application to a server configuration.

View File

@ -1 +0,0 @@
Robert von Burg <eitch@eitchnet.ch>

View File

@ -1,270 +0,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/maven-v4_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>strolch_minimal_rest</artifactId>
<packaging>war</packaging>
<inceptionYear>2014</inceptionYear>
<name>strolch_minimal_rest</name>
<url>http://www.strolch.li</url>
<issueManagement>
<system>Github Issues</system>
<url>https://github.com/4treesCH/strolch/issues</url>
</issueManagement>
<scm>
<connection>scm:git:https://github.com/4treesCH/strolch.git</connection>
<developerConnection>scm:git:https://github.com/4treesCH/strolch.git</developerConnection>
<url>https://github.com/4treesCH/strolch</url>
</scm>
<licenses>
<license>
<name>Apache License 2.0</name>
<url>http://www.apache.org/licenses/LICENSE-2.0</url>
</license>
</licenses>
<organization>
<name>Strolch</name>
<url>http://www.strolch.li</url>
</organization>
<developers>
<developer>
<id>eitch</id>
<name>Robert von Burg</name>
<email>eitch@eitchnet.ch</email>
<url>http://www.eitchnet.ch</url>
<roles>
<role>architect</role>
<role>developer</role>
</roles>
<timezone>+1</timezone>
</developer>
</developers>
<properties>
<m2eclipse.wtp.contextRoot>strolch_minimal</m2eclipse.wtp.contextRoot>
<warFinalName>strolch_minimal</warFinalName>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.build.timestamp.format>yyyy-MM-dd HH:mm:ss</maven.build.timestamp.format>
<buildTimestamp>${maven.build.timestamp}</buildTimestamp>
<java-version>1.8</java-version>
<strolch.version>${project.version}</strolch.version>
<tomcat7Url>http://tomcat.eitchnet.ch:8080/manager/text</tomcat7Url>
<tomcat7ServerId>tomcat7.eitchnet.ch</tomcat7ServerId>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>li.strolch</groupId>
<artifactId>li.strolch.bom</artifactId>
<type>pom</type>
<version>${project.version}</version>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jersey</groupId>
<artifactId>jersey-bom</artifactId>
<version>${jersey.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- base -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<scope>runtime</scope>
</dependency>
<!-- eitchnet -->
<dependency>
<groupId>li.strolch</groupId>
<artifactId>li.strolch.utils</artifactId>
</dependency>
<dependency>
<groupId>li.strolch</groupId>
<artifactId>li.strolch.privilege</artifactId>
</dependency>
<!-- strolch -->
<dependency>
<groupId>li.strolch</groupId>
<artifactId>li.strolch.model</artifactId>
</dependency>
<dependency>
<groupId>li.strolch</groupId>
<artifactId>li.strolch.agent</artifactId>
</dependency>
<dependency>
<groupId>li.strolch</groupId>
<artifactId>li.strolch.service</artifactId>
</dependency>
<dependency>
<groupId>li.strolch</groupId>
<artifactId>li.strolch.rest</artifactId>
</dependency>
<!-- Servlet 3.0 API -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<scope>provided</scope>
</dependency>
<!-- Web -->
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-grizzly2-http</artifactId>
<scope>test</scope>
</dependency>
<!-- uncomment this to get JSON support: <dependency> <groupId>org.glassfish.jersey.media</groupId> <artifactId>jersey-media-moxy</artifactId> </dependency> -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
<!-- testing -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-library</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>${warFinalName}</finalName>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>**/*.properties</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
<filtering>false</filtering>
<excludes>
<exclude>**/*.properties</exclude>
</excludes>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${java-version}</source>
<target>${java-version}</target>
<showDeprecation>true</showDeprecation>
<showWarnings>true</showWarnings>
<compilerArgument>-Xlint:all</compilerArgument>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-eclipse-plugin</artifactId>
<configuration>
<downloadJavadocs>true</downloadJavadocs>
<downloadSources>true</downloadSources>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
<warName>${warFinalName}-${project.version}</warName>
<webResources>
<resource>
<directory>src/main/non-packaged-resources</directory>
<targetPath>WEB-INF</targetPath>
<filtering>true</filtering>
<includes>
<include>**/ENV.properties</include>
</includes>
</resource>
</webResources>
</configuration>
</plugin>
<plugin>
<!-- Publish to Tomcat: mvn tomcat7:redeploy -->
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<configuration>
<url>${tomcat7Url}</url>
<server>${tomcat7ServerId}</server>
<path>/${warFinalName}</path>
</configuration>
</plugin>
<plugin>
<groupId>org.sonatype.plugins</groupId>
<artifactId>nexus-staging-maven-plugin</artifactId>
<configuration>
<skipNexusStagingDeployMojo>true</skipNexusStagingDeployMojo>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>m2e</id>
<!-- This profile is only activated when building in Eclipse with m2e -->
<activation>
<property>
<name>m2e.version</name>
</property>
</activation>
<properties>
<strolch.env>dev</strolch.env>
</properties>
</profile>
</profiles>
</project>

View File

@ -1,41 +0,0 @@
/*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package li.strolch.minimal.rest.postinitializer;
import li.strolch.agent.api.ComponentContainer;
import li.strolch.agent.impl.SimplePostInitializer;
/**
* @author Robert von Burg <eitch@eitchnet.ch>
*/
public class PostInitializer extends SimplePostInitializer {
/**
* @param container
* @param componentName
*/
public PostInitializer(ComponentContainer container, String componentName) {
super(container, componentName);
}
@Override
public void start() throws Exception {
logger.info("Started PostInitializer."); //$NON-NLS-1$
super.start();
}
}

View File

@ -1,33 +0,0 @@
package li.strolch.minimal.rest.resources;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import li.strolch.minimal.rest.util.Result;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.Gson;
@Path("greetings")
public class GreetingsResource {
private static final Logger logger = LoggerFactory.getLogger(GreetingsResource.class);
@GET
@Produces(MediaType.APPLICATION_JSON)
public Response helloWorld(@QueryParam("name") String name) {
logger.info("Received request for: " + name);
Result result = new Result("Hello " + name);
String entity = new Gson().toJson(result);
return Response.ok(entity, MediaType.APPLICATION_JSON).build();
}
}

View File

@ -1,48 +0,0 @@
/*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package li.strolch.minimal.rest.resources;
import java.util.logging.Level;
import javax.ws.rs.ApplicationPath;
import org.glassfish.jersey.logging.LoggingFeature;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.ServerProperties;
/**
* @author Robert von Burg <eitch@eitchnet.ch>
*/
@ApplicationPath(value = "rest")
public class RestfulApplication extends ResourceConfig {
public RestfulApplication() {
packages(GreetingsResource.class.getPackage().getName());
//register(CharsetResponseFilter.class);
//register(HttpCacheResponseFilter.class);
//register(RestfulExceptionMapper.class);
LoggingFeature loggingFeature = new LoggingFeature(
java.util.logging.Logger.getLogger(LoggingFeature.DEFAULT_LOGGER_NAME), Level.SEVERE,
LoggingFeature.Verbosity.PAYLOAD_ANY, null);
register(loggingFeature);
property(ServerProperties.TRACING, "ALL");
property(ServerProperties.TRACING_THRESHOLD, "TRACE");
}
}

View File

@ -1,26 +0,0 @@
package li.strolch.minimal.rest.util;
import java.text.MessageFormat;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.Gson;
@Provider
public class RestfulExceptionMapper implements ExceptionMapper<Exception> {
private static final Logger logger = LoggerFactory.getLogger(RestfulExceptionMapper.class);
@Override
public Response toResponse(Exception ex) {
logger.error(MessageFormat.format("Handling exception {0}", ex.getClass()), ex); //$NON-NLS-1$
return Response.serverError().entity(new Gson().toJson(new Result(ex))).type(MediaType.APPLICATION_JSON)
.build();
}
}

View File

@ -1,57 +0,0 @@
/*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package li.strolch.minimal.rest.util;
import li.strolch.utils.helper.StringHelper;
/**
* @author Robert von Burg <eitch@eitchnet.ch>
*/
public class Result {
private String msg;
private String exceptionMsg;
public Result(String msg) {
this.msg = msg;
}
public Result(Exception e) {
this.msg = StringHelper.isEmpty(e.getMessage()) ? e.getClass().getName() : e.getMessage();
this.exceptionMsg = StringHelper.formatExceptionMessage(e);
}
public Result() {
this.msg = StringHelper.DASH;
}
public String getMsg() {
return this.msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public String getExceptionMsg() {
return exceptionMsg;
}
public void setExceptionMsg(String exceptionMsg) {
this.exceptionMsg = exceptionMsg;
}
}

View File

@ -1,16 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!-- encoders are assigned the type
ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
<encoder>
<pattern>%d [%thread] %-5level %class{36}:%line %method - %msg%n</pattern>
</encoder>
</appender>
<root level="info">
<appender-ref ref="STDOUT"/>
</root>
</configuration>

View File

@ -1 +0,0 @@
/META-INF/

View File

@ -1,47 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<StrolchConfiguration>
<env id="dev">
<Runtime>
<applicationName>strolch_minimal_rest</applicationName>
<Properties>
<locale>en</locale>
<verbose>true</verbose>
</Properties>
</Runtime>
<Component>
<name>PrivilegeHandler</name>
<api>li.strolch.runtime.privilege.PrivilegeHandler</api>
<impl>li.strolch.runtime.privilege.DefaultStrolchPrivilegeHandler</impl>
<Properties>
<privilegeConfigFile>PrivilegeConfig.xml</privilegeConfigFile>
</Properties>
</Component>
<Component>
<name>RealmHandler</name>
<api>li.strolch.agent.api.RealmHandler</api>
<impl>li.strolch.agent.impl.DefaultRealmHandler</impl>
<depends>PrivilegeHandler</depends>
<Properties>
<dataStoreMode>EMPTY</dataStoreMode>
</Properties>
</Component>
<Component>
<name>ServiceHandler</name>
<api>li.strolch.service.api.ServiceHandler</api>
<impl>li.strolch.service.api.DefaultServiceHandler</impl>
<depends>RealmHandler</depends>
<depends>PrivilegeHandler</depends>
<Properties>
<verbose>true</verbose>
</Properties>
</Component>
<Component>
<name>PostInitializer</name>
<api>li.strolch.agent.api.PostInitializer</api>
<impl>li.strolch.minimal.rest.postinitializer.PostInitializer</impl>
<depends>ServiceHandler</depends>
<Properties>
</Properties>
</Component>
</env>
</StrolchConfiguration>

View File

@ -1,11 +0,0 @@
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<!--meta http-equiv="refresh" content="0; url=pages/index.html" /-->
<title>Strolch Minimal</title>
</head>
<body>
<p>Hello World</p>
</body>
</html>