[New] Added new maven-archetype for PLC projects

This commit is contained in:
Robert von Burg 2022-08-17 14:50:56 +02:00
parent 3fc67af657
commit 2179bc1051
Signed by: eitch
GPG Key ID: 75DB9C85C74331F7
101 changed files with 8206 additions and 0 deletions

View File

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

View File

@ -0,0 +1,41 @@
<?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>
<groupId>li.strolch</groupId>
<artifactId>li.strolch-maven-archetypes</artifactId>
<version>0.1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>li.strolch.mvn.archetype.plc</artifactId>
<packaging>maven-archetype</packaging>
<distributionManagement>
<site>
<id>localhost</id>
<url>file://${project.basedir}/../target/${project.artifactId}</url>
</site>
</distributionManagement>
<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>${archetype-packaging.version}</version>
</extension>
</extensions>
</build>
</project>

View File

@ -0,0 +1,109 @@
<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>
<modules>
<module id="${rootArtifactId}-shared" dir="__rootArtifactId__-shared" name="${rootArtifactId}-shared">
<fileSets>
<fileSet filtered="true" packaged="true" encoding="UTF-8">
<directory>src/main/java</directory>
</fileSet>
</fileSets>
</module>
<module id="${rootArtifactId}-web" dir="__rootArtifactId__-web" name="${rootArtifactId}-web">
<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="false" encoding="UTF-8">
<directory>src/main/webapp/</directory>
<excludes>
<exclude>bower.json</exclude>
<exclude>package.json</exclude>
<exclude>locales.json</exclude>
<exclude>app/index.html</exclude>
<exclude>app/src/behaviors/c-app-behavior.html</exclude>
<exclude>app/src/main/c-drawer.html</exclude>
</excludes>
</fileSet>
<fileSet filtered="true" encoding="UTF-8">
<directory>src/main/webapp/</directory>
<includes>
<include>bower.json</include>
<include>package.json</include>
<include>locales.json</include>
<include>app/index.html</include>
<include>app/src/behaviors/c-app-behavior.html</include>
<include>app/src/main/c-drawer.html</include>
</includes>
</fileSet>
<fileSet filtered="true" encoding="UTF-8">
<directory>runtime</directory>
</fileSet>
</fileSets>
</module>
<module id="${rootArtifactId}-plc-web" dir="__rootArtifactId__-plc-web" name="${rootArtifactId}-plc-web">
<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="false" encoding="UTF-8">
<directory>src/main/webapp/</directory>
<excludes>
<exclude>bower.json</exclude>
<exclude>package.json</exclude>
<exclude>locales.json</exclude>
<exclude>app/index.html</exclude>
<exclude>app/src/behaviors/c-app-behavior.html</exclude>
<exclude>app/src/main/c-drawer.html</exclude>
</excludes>
</fileSet>
<fileSet filtered="true" encoding="UTF-8">
<directory>src/main/webapp/</directory>
<includes>
<include>bower.json</include>
<include>package.json</include>
<include>locales.json</include>
<include>app/index.html</include>
<include>app/src/behaviors/c-app-behavior.html</include>
<include>app/src/main/c-drawer.html</include>
</includes>
</fileSet>
<fileSet filtered="true" encoding="UTF-8">
<directory>runtime</directory>
</fileSet>
</fileSets>
</module>
</modules>
<fileSets>
<fileSet filtered="true" encoding="UTF-8">
<directory></directory>
<includes>
<include>README.md</include>
</includes>
<excludes>
<exclude>${rootArtifactId}-shared</exclude>
<exclude>${rootArtifactId}-web</exclude>
<exclude>${rootArtifactId}-plc-web</exclude>
</excludes>
</fileSet>
</fileSets>
</archetype-descriptor>

View File

@ -0,0 +1,4 @@
Strolch Project: ${appName} / ${artifactId}
======================================
This is an example app for Strolch PLC. It is a multi-module project.

View File

@ -0,0 +1,270 @@
<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>${groupId}</groupId>
<artifactId>${rootArtifactId}</artifactId>
<version>${version}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>${rootArtifactId}-plc-web</artifactId>
<name>${rootArtifactId}-plc-web</name>
<packaging>war</packaging>
<properties>
<appFinalName>plc</appFinalName>
<warFinalName>plc</warFinalName>
</properties>
<dependencies>
<!-- base -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<scope>compile</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>
<dependency>
<groupId>li.strolch</groupId>
<artifactId>li.strolch.persistence.xml</artifactId>
</dependency>
<!-- PLC -->
<dependency>
<groupId>li.strolch</groupId>
<artifactId>strolch-plc-core</artifactId>
</dependency>
<dependency>
<groupId>li.strolch</groupId>
<artifactId>strolch-plc-rest</artifactId>
</dependency>
<dependency>
<groupId>li.strolch</groupId>
<artifactId>strolch-plc-gw-client</artifactId>
</dependency>
<dependency>
<groupId>li.strolch</groupId>
<artifactId>strolch-plc-util</artifactId>
</dependency>
<!-- my-app -->
<dependency>
<groupId>${groupId}</groupId>
<artifactId>${rootArtifactId}-shared</artifactId>
</dependency>
<!-- web -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
<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>
<!-- test -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</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.apache.maven.plugins</groupId>
<artifactId>maven-clean-plugin</artifactId>
<version>${maven-clean-plugin.version}</version>
<configuration>
<filesets>
<fileset>
<directory>src/main/webapp/app/bower_components</directory>
<includes>
<include>**</include>
</includes>
<followSymlinks>false</followSymlinks>
</fileset>
</filesets>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>${exec-maven-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,48 @@
<?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"/>
<Parameter name="allowSessionRefresh" 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,196 @@
<?xml version="1.0" encoding="UTF-8"?>
<Roles>
<!--
Internal
-->
<Role name="ModelAccessor">
<Privilege name="GetOrder" 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="UpdateActivity" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="GetActivity" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="RemoveActivity" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="GetResource" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="RemoveResource" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="AddResource" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="UpdateOrder" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="RemoveOrder" 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="RequirePasswordChange" 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="UserPrivileges">
<Privilege name="li.strolch.service.api.Service" policy="DefaultPrivilege">
<Allow>li.strolch.service.privilege.users.PrivilegeSetUserPasswordService</Allow>
<Allow>li.strolch.service.privilege.users.PrivilegeSetUserLocaleService</Allow>
</Privilege>
<Privilege name="PrivilegeSetUserPassword" policy="UserAccessPrivilege"/>
<Privilege name="PrivilegeSetUserLocale" policy="UserAccessPrivilege"/>
</Role>
<Role name="PrivilegeAdmin">
<Privilege name="li.strolch.service.api.Service" policy="DefaultPrivilege">
<Allow>li.strolch.service.privilege.users.PrivilegeUpdateUserService</Allow>
<Allow>li.strolch.service.privilege.users.PrivilegeUpdateUserRolesService</Allow>
<Allow>li.strolch.service.privilege.users.PrivilegeSetUserPasswordService</Allow>
<Allow>li.strolch.service.privilege.users.PrivilegeSetUserLocaleService</Allow>
<Allow>li.strolch.service.privilege.users.PrivilegeRemoveUserService</Allow>
<Allow>li.strolch.service.privilege.users.PrivilegeRemoveRoleFromUserService</Allow>
<Allow>li.strolch.service.privilege.users.PrivilegeAddUserService</Allow>
<Allow>li.strolch.service.privilege.users.PrivilegeAddRoleToUserService</Allow>
<Allow>li.strolch.service.privilege.roles.PrivilegeUpdateRoleService</Allow>
<Allow>li.strolch.service.privilege.roles.PrivilegeRemoveRoleService</Allow>
<Allow>li.strolch.service.privilege.roles.PrivilegeRemovePrivilegeFromRoleService</Allow>
<Allow>li.strolch.service.privilege.roles.PrivilegeAddRoleService</Allow>
<Allow>li.strolch.service.privilege.roles.PrivilegeAddOrReplacePrivilegeOnRoleService</Allow>
</Privilege>
<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="RequirePasswordChange" 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>
<Role name="agent">
<Privilege name="PrivilegeAddUser" policy="UserAccessPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="PrivilegeRemoveUser" policy="UserAccessPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="li.strolch.search.StrolchSearch" policy="DefaultPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<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>Persist</Allow>
<Allow>GetCertificates</Allow>
<Allow>PersistSessions</Allow>
</Privilege>
<Privilege name="PrivilegeGetUser" policy="UserAccessPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="li.strolch.model.query.StrolchQuery" policy="DefaultPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="li.strolch.service.api.Service" policy="DefaultPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="PrivilegeModifyUser" policy="UserAccessPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
</Role>
</Roles>

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<Users>
<!-- password: admin -->
<User password="$PBKDF2WithHmacSHA512,10000,256$83c5d3697a69497ed4d999cde98a6a2c586114435cab5a80327734b3a032766b$c9185893044f5421f28c2a6def129e072186c7d73b78ec4ec60c1044c97546fe" userId="U10" username="admin">
<Firstname>Admin</Firstname>
<Lastname>Admin</Lastname>
<State>ENABLED</State>
<Locale>en-GB</Locale>
<Roles>
<Role>ModelAccessor</Role>
<Role>PrivilegeAdmin</Role>
<Role>StrolchAdmin</Role>
<Role>UserPrivileges</Role>
</Roles>
</User>
<User userId="S01" username="agent">
<State>SYSTEM</State>
<Locale>en</Locale>
<Roles>
<Role>ModelAccessor</Role>
<Role>PrivilegeAdmin</Role>
<Role>agent</Role>
</Roles>
</User>
</Users>

View File

@ -0,0 +1,157 @@
<?xml version="1.0" encoding="UTF-8"?>
<StrolchConfiguration>
<env id="global">
<Runtime>
<applicationName>${appName} PLC</applicationName>
<Properties>
<locale>en</locale>
<verbose>true</verbose>
<timezone>Europe/Zurich</timezone>
</Properties>
</Runtime>
<Component>
<name>PrivilegeHandler</name>
<api>li.strolch.runtime.privilege.PrivilegeHandler</api>
<impl>li.strolch.runtime.privilege.DefaultStrolchPrivilegeHandler</impl>
</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>defaultModel.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>
</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>
<Properties>
<maxMessages>200</maxMessages>
</Properties>
</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.maxKeepAlive.minutes>10080</session.maxKeepAlive.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>PlcHandler</name>
<api>li.strolch.plc.core.PlcHandler</api>
<impl>li.strolch.plc.core.DefaultPlcHandler</impl>
<depends>RealmHandler</depends>
<Properties>
<plcClass>li.strolch.plc.core.hw.DefaultPlc</plcClass>
<plcId>plc-01</plcId>
</Properties>
</Component>
<Component>
<name>PostInitializer</name>
<api>li.strolch.agent.api.PostInitializer</api>
<impl>li.strolch.plc.core.PlcPostInitializer</impl>
<depends>StrolchJobsHandler</depends>
<depends>PlcServiceInitializer</depends>
</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>
<Component>
<name>PlcServiceInitializer</name>
<api>li.strolch.plc.core.PlcServiceInitializer</api>
<impl>${package}.plc.web.components.CustomPlcServiceInitializer</impl>
<depends>PlcHandler</depends>
</Component>
<Component>
<name>PlcGwClientHandler</name>
<api>li.strolch.plc.gw.client.PlcGwClientHandler</api>
<impl>li.strolch.plc.gw.client.PlcGwClientHandler</impl>
<depends>PlcHandler</depends>
<depends>PlcServiceInitializer</depends>
<Properties>
<gwUsername>plc-01</gwUsername>
<gwPassword>plc-01</gwPassword>
<gwServerUrl>ws://localhost:8080/${rootArtifactId}-web/websocket/strolch/plc</gwServerUrl>
</Properties>
</Component>
</env>
<env id="dev">
<!-- taken from global env -->
</env>
<env id="test">
<!-- taken from global env -->
</env>
</StrolchConfiguration>

View File

@ -0,0 +1,8 @@
# README for Address mappings
Use the following Google Sheet to easily define the address mappings:
https://docs.google.com/spreadsheets/d/10fgTfR3FZCVbQ5bbh0xB1u8rLIaw2KEyO45VMv7y5ho/edit?usp=sharing
Download the sheet `strolch-plc-example`
And then run `li.strolch.plc.core.util.PlcAddressGeneratorTest` to generate the Plc address mappings.

View File

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

View File

@ -0,0 +1,22 @@
<?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-1.6.xsd">
<IncludeFile file="plc-templates.xml"/>
<IncludeFile file="plc-state.xml"/>
<IncludeFile file="strolch-plc-example.xml"/>
<IncludeFile file="strolch-plc-example-connections.xml"/>
<!--
PLC to store connection state to server
-->
<Resource Id="plc-01" Name="PLC-01" Type="Plc">
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
<Parameter Id="connectionState" Name="Connection State" Type="String" Interpretation="Enumeration" Uom="ConnectionState" Value="Disconnected"/>
<Parameter Id="connectionStateMsg" Name="Connection State Msg" Type="String" Interpretation="Enumeration" Uom="ConnectionState"
Value=""/>
</ParameterBag>
</Resource>
</StrolchModel>

View File

@ -0,0 +1,68 @@
<?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-1.6.xsd">
<Resource Id="configuration" Name="Configuration" Type="Configuration">
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
<Parameter Id="verbose" Name="Verbose Override" Type="Boolean" Value="true"/>
</ParameterBag>
</Resource>
<!--
PLC State
-->
<Resource Id="plc" Name="PLC" Type="PlcLogicalDevice">
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
<Parameter Id="group" Name="Group" Type="String" Value="99 Startup"/>
<Parameter Id="index" Name="Index" Type="Integer" Value="999999"/>
</ParameterBag>
<ParameterBag Id="relations" Name="Relations" Type="Relations">
<Parameter Id="addresses" Name="Addresses" Type="StringList" Interpretation="Resource-Ref" Uom="PlcAddress"
Value="addrPlcStarted, addrPlcConnected"/>
<Parameter Id="telegrams" Name="Telegrams" Type="StringList" Interpretation="Resource-Ref" Uom="PlcTelegram"
Value="telPlcStarted, telPlcStopped"/>
</ParameterBag>
</Resource>
<Resource Id="addrPlcConnected" Name="PLC - Connected" Type="PlcAddress">
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
<Parameter Id="address" Name="HW Address" Type="String" Interpretation="PlcConnection" Value="VirtualString.plcServerConnected"/>
<Parameter Id="resource" Name="Resource ID for PlcAddress" Type="String" Value="PLC"/>
<Parameter Id="action" Name="Action ID for PlcAddress" Type="String" Value="ServerConnected"/>
<Parameter Id="valueType" Name="Value Type" Type="String" Interpretation="Interpretation" Uom="PlcValueType" Value="String"/>
<Parameter Id="value" Name="Value" Type="String" Value="false"/>
<Parameter Id="index" Name="Index" Type="Integer" Value="5"/>
</ParameterBag>
</Resource>
<Resource Id="addrPlcStarted" Name="PLC - Started" Type="PlcAddress">
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
<Parameter Id="address" Name="HW Address" Type="String" Interpretation="PlcConnection" Value="raspiBcmGpioOutput.4"/>
<Parameter Id="resource" Name="Resource ID for PlcAddress" Type="String" Value="PLC"/>
<Parameter Id="action" Name="Action ID for PlcAddress" Type="String" Value="Started"/>
<Parameter Id="value" Name="Value" Type="Boolean" Value="false"/>
<Parameter Id="inverted" Name="Inverted" Type="Boolean" Value="false"/>
<Parameter Id="index" Name="Index" Type="Integer" Value="10"/>
<Parameter Id="remote" Name="remote" Type="Boolean" Value="true"/>
</ParameterBag>
</Resource>
<Resource Id="telPlcStarted" Name="PLC - Started" Type="PlcTelegram">
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
<Parameter Id="address" Name="HW Address" Type="String" Interpretation="PlcConnection" Value="raspiBcmGpioOutput.4"/>
<Parameter Id="resource" Name="Resource ID for PlcAddress" Type="String" Value="PLC"/>
<Parameter Id="action" Name="Action ID for PlcAddress" Type="String" Value="Started"/>
<Parameter Id="value" Name="Value" Type="Boolean" Value="true"/>
<Parameter Id="index" Name="Index" Type="Integer" Value="10"/>
<Parameter Id="remote" Name="remote" Type="Boolean" Value="true"/>
</ParameterBag>
</Resource>
<Resource Id="telPlcStopped" Name="PLC - Stopped" Type="PlcTelegram">
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
<Parameter Id="address" Name="HW Address" Type="String" Interpretation="PlcConnection" Value="raspiBcmGpioOutput.4"/>
<Parameter Id="resource" Name="Resource ID for PlcAddress" Type="String" Value="PLC"/>
<Parameter Id="action" Name="Action ID for PlcAddress" Type="String" Value="Stopped"/>
<Parameter Id="value" Name="Value" Type="Boolean" Value="false"/>
<Parameter Id="index" Name="Index" Type="Integer" Value="20"/>
<Parameter Id="remote" Name="remote" Type="Boolean" Value="true"/>
</ParameterBag>
</Resource>
</StrolchModel>

View File

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8" ?>
<StrolchModel xmlns="https://strolch.li/xsd/StrolchModel-1.6.xsd">
<Resource Id="PlcLogicalDevice" Name="PlcLogicalDevice Template" Type="Template">
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
<Parameter Id="description" Name="Description" Index="5" Type="String" Value=""/>
<Parameter Id="group" Name="Group" Index="20" Type="String" Value="default"/>
<Parameter Id="index" Name="Index" Index="30" Type="Integer" Value="0"/>
</ParameterBag>
<ParameterBag Id="relations" Name="Relations" Type="Relations">
<Parameter Id="addresses" Name="Addresses" Index="10" Type="StringList" Interpretation="Resource-Ref" Uom="PlcAddress" Value=""/>
<Parameter Id="telegrams" Name="Telegrams" Index="20" Type="StringList" Interpretation="Resource-Ref" Uom="PlcTelegram" Value=""/>
</ParameterBag>
</Resource>
<Resource Id="PlcAddress" Name="PlcAddress Template" Type="Template">
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
<Parameter Id="description" Name="Description" Index="5" Type="String" Value=""/>
<Parameter Id="address" Name="HW Address" Index="10" Type="String" Interpretation="PlcConnection" Value=""/>
<Parameter Id="resource" Name="Resource ID for PlcAddress" Index="20" Type="String" Value=""/>
<Parameter Id="action" Name="Action ID for PlcAddress" Index="30" Type="String" Value=""/>
<Parameter Id="inverted" Name="Inverted" Index="40" Type="Boolean" Value="false"/>
<Parameter Id="index" Name="Index" Index="40" Type="Integer" Value="50"/>
</ParameterBag>
</Resource>
<Resource Id="PlcTelegram" Name="PlcTelegram Template" Type="Template">
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
<Parameter Id="description" Name="Description" Index="5" Type="String" Value=""/>
<Parameter Id="address" Name="HW Address" Index="10" Type="String" Interpretation="PlcConnection" Value=""/>
<Parameter Id="resource" Name="Resource ID for PlcAddress" Index="20" Type="String" Value=""/>
<Parameter Id="action" Name="Action ID for PlcAddress" Index="30" Type="String" Value=""/>
<Parameter Id="index" Name="Index" Index="40" Type="Integer" Value="10"/>
</ParameterBag>
</Resource>
</StrolchModel>

View File

@ -0,0 +1,131 @@
<?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-1.6.xsd">
<!--
Barcode reader connection, currently place holder with RandomString
-->
<Resource Id="dataLogicScanner" Name="DataLogic Scanner Connection" Type="PlcConnection">
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
<Parameter Id="className" Name="Connection Class" Type="String" Value="li.strolch.plc.core.hw.connections.DataLogicScannerConnection"/>
<Parameter Id="address" Name="Scanner IP Address" Type="String" Value="192.168.1.249:51236"/>
<Parameter Id="readTimeout" Name="Read Timeout (s)" Type="Integer" Value="60"/>
<Parameter Id="state" Name="Connection State" Type="String" Interpretation="Enumeration" Uom="ConnectionState" Value="Disconnected"/>
<Parameter Id="stateMsg" Name="Connection State Msg" Type="String" Interpretation="Enumeration" Uom="ConnectionState"
Value=""/>
</ParameterBag>
</Resource>
<!--
Raspberry GPIO BCM Address connection
-->
<Resource Id="raspiBcmGpioOutput" Name="Raspi BCM GPIO Output" Type="PlcConnection">
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
<Parameter Id="className" Name="Connection Class" Type="String" Value="li.strolch.plc.core.hw.gpio.RaspiBcmGpioOutputConnection"/>
<Parameter Id="state" Name="Connection State" Type="String" Interpretation="Enumeration" Uom="ConnectionState" Value="Disconnected"/>
<Parameter Id="stateMsg" Name="Connection State Msg" Type="String" Interpretation="Enumeration" Uom="ConnectionState"
Value=""/>
<Parameter Id="inverted" Name="Inverted" Type="Boolean" Value="true"/>
<Parameter Id="bcmOutputPins" Name="BCM Output Pins" Type="IntegerList" Value="4"/>
<Parameter Id="simulated" Name="Simulated" Type="Boolean" Value="true"/>
</ParameterBag>
</Resource>
<Resource Id="raspiBcmGpioInput" Name="Raspi BCM GPIO Input" Type="PlcConnection">
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
<Parameter Id="className" Name="Connection Class" Type="String" Value="li.strolch.plc.core.hw.gpio.RaspiBcmGpioInputConnection"/>
<Parameter Id="state" Name="Connection State" Type="String" Interpretation="Enumeration" Uom="ConnectionState" Value="Disconnected"/>
<Parameter Id="stateMsg" Name="Connection State Msg" Type="String" Interpretation="Enumeration" Uom="ConnectionState"
Value=""/>
<Parameter Id="inverted" Name="Inverted" Type="Boolean" Value="true"/>
<Parameter Id="bcmInputPins" Name="BCM Input Pins" Type="IntegerList" Value="17"/>
<Parameter Id="simulated" Name="Simulated" Type="Boolean" Value="true"/>
</ParameterBag>
</Resource>
<!--
I2C input connections
-->
<Resource Id="i2cInput.dev01" Name="PCF8574 Input 0x38" Type="PlcConnection">
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
<Parameter Id="className" Name="Connection Class" Type="String" Value="li.strolch.plc.core.hw.i2c.PCF8574InputConnection"/>
<Parameter Id="state" Name="Connection State" Type="String" Interpretation="Enumeration" Uom="ConnectionState" Value="Disconnected"/>
<Parameter Id="stateMsg" Name="Connection State Msg" Type="String" Interpretation="Enumeration" Uom="ConnectionState"
Value=""/>
<Parameter Id="i2cBus" Name="I2C Bus" Type="Integer" Value="1"/>
<Parameter Id="addresses" Name="Addresses" Type="IntegerList" Value="0x38"/>
<Parameter Id="verbose" Name="Verbose" Type="Boolean" Value="false"/>
<Parameter Id="inverted" Name="Inverted" Type="Boolean" Value="false"/>
<Parameter Id="interruptPinPullResistance" Name="Raspi Interrupt PinPullResistance" Type="String" Value="PULL_UP"/>
<Parameter Id="interruptChangeState" Name="Raspi Interrupt Change State" Type="String" Value="LOW"/>
<Parameter Id="interruptBcmPinAddress" Name="Raspi BCM Interrupt Pin" Type="Integer" Value="9"/>
<Parameter Id="enableInterruptFix" Name="Enable Interrupt Fix" Type="Boolean" Value="true"/>
<Parameter Id="simulated" Name="Simulated" Type="Boolean" Value="true"/>
</ParameterBag>
</Resource>
<Resource Id="i2cInput.dev02" Name="PCF8574 Input 0x39" Type="PlcConnection">
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
<Parameter Id="className" Name="Connection Class" Type="String" Value="li.strolch.plc.core.hw.i2c.PCF8574InputConnection"/>
<Parameter Id="state" Name="Connection State" Type="String" Interpretation="Enumeration" Uom="ConnectionState" Value="Disconnected"/>
<Parameter Id="stateMsg" Name="Connection State Msg" Type="String" Interpretation="Enumeration" Uom="ConnectionState"
Value=""/>
<Parameter Id="i2cBus" Name="I2C Bus" Type="Integer" Value="1"/>
<Parameter Id="addresses" Name="Addresses" Type="IntegerList" Value="0x39"/>
<Parameter Id="verbose" Name="Verbose" Type="Boolean" Value="false"/>
<Parameter Id="inverted" Name="Inverted" Type="Boolean" Value="false"/>
<Parameter Id="interruptPinPullResistance" Name="Raspi Interrupt PinPullResistance" Type="String" Value="PULL_UP"/>
<Parameter Id="interruptChangeState" Name="Raspi Interrupt Change State" Type="String" Value="LOW"/>
<Parameter Id="interruptBcmPinAddress" Name="Raspi BCM Interrupt Pin" Type="Integer" Value="10"/>
<Parameter Id="enableInterruptFix" Name="Enable Interrupt Fix" Type="Boolean" Value="true"/>
<Parameter Id="simulated" Name="Simulated" Type="Boolean" Value="true"/>
</ParameterBag>
</Resource>
<Resource Id="i2cInput.dev03" Name="PCF8574 Input 0x3a" Type="PlcConnection">
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
<Parameter Id="className" Name="Connection Class" Type="String" Value="li.strolch.plc.core.hw.i2c.PCF8574InputConnection"/>
<Parameter Id="state" Name="Connection State" Type="String" Interpretation="Enumeration" Uom="ConnectionState" Value="Disconnected"/>
<Parameter Id="stateMsg" Name="Connection State Msg" Type="String" Interpretation="Enumeration" Uom="ConnectionState"
Value=""/>
<Parameter Id="i2cBus" Name="I2C Bus" Type="Integer" Value="1"/>
<Parameter Id="addresses" Name="Addresses" Type="IntegerList" Value="0x3a"/>
<Parameter Id="verbose" Name="Verbose" Type="Boolean" Value="false"/>
<!-- we don't invert dev03 -->
<Parameter Id="inverted" Name="Inverted" Type="Boolean" Value="false"/>
<Parameter Id="interruptPinPullResistance" Name="Raspi Interrupt PinPullResistance" Type="String" Value="PULL_UP"/>
<Parameter Id="interruptChangeState" Name="Raspi Interrupt Change State" Type="String" Value="LOW"/>
<Parameter Id="interruptBcmPinAddress" Name="Raspi BCM Interrupt Pin" Type="Integer" Value="24"/>
<Parameter Id="enableInterruptFix" Name="Enable Interrupt Fix" Type="Boolean" Value="true"/>
<Parameter Id="simulated" Name="Simulated" Type="Boolean" Value="true"/>
</ParameterBag>
</Resource>
<!--
I2C output connections
-->
<Resource Id="i2cOutput.dev01" Name="PCF8574 Output 0x20" Type="PlcConnection">
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
<Parameter Id="className" Name="Connection Class" Type="String" Value="li.strolch.plc.core.hw.i2c.PCF8574OutputConnection"/>
<Parameter Id="state" Name="Connection State" Type="String" Interpretation="Enumeration" Uom="ConnectionState" Value="Disconnected"/>
<Parameter Id="stateMsg" Name="Connection State Msg" Type="String" Interpretation="Enumeration" Uom="ConnectionState"
Value=""/>
<Parameter Id="i2cBus" Name="I2C Bus" Type="Integer" Value="1"/>
<Parameter Id="addresses" Name="Addresses" Type="IntegerList" Value="0x20"/>
<Parameter Id="verbose" Name="Verbose" Type="Boolean" Value="false"/>
<Parameter Id="inverted" Name="Inverted" Type="Boolean" Value="false"/>
<Parameter Id="simulated" Name="Simulated" Type="Boolean" Value="true"/>
</ParameterBag>
</Resource>
<Resource Id="i2cOutput.dev02" Name="PCF8574 Output 0x21" Type="PlcConnection">
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
<Parameter Id="className" Name="Connection Class" Type="String" Value="li.strolch.plc.core.hw.i2c.PCF8574OutputConnection"/>
<Parameter Id="state" Name="Connection State" Type="String" Interpretation="Enumeration" Uom="ConnectionState" Value="Disconnected"/>
<Parameter Id="stateMsg" Name="Connection State Msg" Type="String" Interpretation="Enumeration" Uom="ConnectionState"
Value=""/>
<Parameter Id="i2cBus" Name="I2C Bus" Type="Integer" Value="1"/>
<Parameter Id="addresses" Name="Addresses" Type="IntegerList" Value="0x21"/>
<Parameter Id="verbose" Name="Verbose" Type="Boolean" Value="false"/>
<Parameter Id="inverted" Name="Inverted" Type="Boolean" Value="false"/>
<Parameter Id="simulated" Name="Simulated" Type="Boolean" Value="true"/>
</ParameterBag>
</Resource>
</StrolchModel>

View File

@ -0,0 +1,59 @@
Description,Type,SubType,Device,Pin,Resource,Action1,Action2,Connection,DeviceId,Inverted,Value,Remote
Mode,Group,,,,,,,,Mode,,,
Automatic Mode,Virtual,Boolean,,,AutomaticMode,On,Off,VirtualBoolean.AutomaticMode,,,,TRUE
Stop All Actors,Virtual,Boolean,,,StopAllActors,Now,,VirtualBoolean.StopAllActors,,,,TRUE
Sector 1,Group,,,,,,,,Conveyor01,,,
Motor Conveyor B1.1,Output,DevPin0,1,1,Sector01,Motor1On,Motor1Off,i2cOutput.dev01,,,,
Signal Motor Fault Conveyor B1.1 ,Input,DevPin0,1,1,Sector01,Motor1Fault,,i2cInput.dev01,,,,
Motor Conveyor B1.2,Output,DevPin0,1,2,Sector01,Motor2On,Motor2Off,i2cOutput.dev01,,,,
Signal Motor Fault Conveyor B1.2,Input,DevPin0,1,2,Sector01,Motor2Fault,,i2cInput.dev01,,,,
Start Button Conveyor 1,Input,DevPin0,1,8,Sector01,StartButton,,i2cInput.dev01,,TRUE,,
Light Barrier Conveyor 1,Input,DevPin0,2,1,Sector01,BoxDetected,,i2cInput.dev02,,,,
Emergency Stop Sector 1,Input,DevPin0,3,2,Sector01,EmergencyStop,,i2cInput.dev03,,,,TRUE
Sector 2,,,,,,,,,Conveyor03,,,
Motor Conveyor B2.1,Output,DevPin0,1,3,Sector02,Motor1On,Motor1Off,i2cOutput.dev01,,,,
Signal Motor Fault Conveyor B2.1 ,Input,DevPin0,1,3,Sector02,Motor1Fault,,i2cInput.dev01,,,,
Motor Conveyor B2.2,Output,DevPin0,1,4,Sector02,Motor2On,Motor2Off,i2cOutput.dev01,,,,
Signal Motor Fault Conveyor B2.2,Input,DevPin0,1,4,Sector02,Motor2Fault,,i2cInput.dev01,,,,
Light Barrier Conveyor 2,Input,DevPin0,2,2,Sector02,BoxDetectedStart,,i2cInput.dev02,,,,
Light Barrier Conveyor End 2,Input,DevPin0,2,3,Sector02,BoxDetectedEnd,,i2cInput.dev02,,,,
Sector 3 Fill Station,Group,,,,,,,,BoxFillStation,,,
Request Next Container,Virtual,Boolean,-,,FillStation,NextContainer,NextContainerDone,VirtualBoolean.NextContainer,,,,TRUE
Release Current Container,Virtual,Boolean,-,,FillStation,ReleaseContainer,ReleaseContainerDone,VirtualBoolean.ReleaseContainer,,,,TRUE
Current Container,Virtual,String,-,,FillStation,CurrentContainer,,VirtualString.CurrentContainer,,,,TRUE
Motor Conveyor B3,Output,DevPin0,1,5,FillStation,MotorOn,MotorOff,i2cOutput.dev01,,,,
Signal Motor Fault Conveyor B3,Input,DevPin0,1,5,FillStation,MotorFault,,i2cInput.dev01,,,,
Entry Stopper Open Valve,Output,DevPin0,2,1,FillStation,EntryOpen,EntryClose,i2cOutput.dev02,,,,
Entry Stopper Opened,Input,DevPin0,3,4,FillStation,EntryClosed,,i2cInput.dev03,,TRUE,,TRUE
Entry Stopper Closed,Input,DevPin0,3,5,FillStation,EntryOpened,,i2cInput.dev03,,TRUE,,TRUE
Light Barrier Fill Station Occupied,Input,DevPin0,2,4,FillStation,Occupied,,i2cInput.dev02,,,,TRUE
Fill Station Barcode Reader,DataLogicScanner,,-,,DataLogicScanner,,,dataLogicScanner,,,,
Exit Stopper Open Valve,Output,DevPin0,2,2,FillStation,ExitOpen,ExitClose,i2cOutput.dev02,,,,
Exit Stopper Opened,Input,DevPin0,3,6,FillStation,ExitClosed,,i2cInput.dev03,,TRUE,,TRUE
Exit Stopper Closed,Input,DevPin0,3,7,FillStation,ExitOpened,,i2cInput.dev03,,TRUE,,TRUE
Emergency Stop Sector 3,Input,DevPin0,3,3,FillStation,EmergencyStop,,i2cInput.dev03,,,,TRUE
Signallampe,Group,,,,,,,,Alarm,,,
Signal Horn,Output,DevPin0,2,3,Alarm,Horn,,i2cOutput.dev02,,,,
Signal Warning,Output,DevPin0,2,4,Alarm,Warning,,i2cOutput.dev02,,,,
Signal Operation,Output,DevPin0,2,5,Alarm,Operational,,i2cOutput.dev02,,,,
Sector 4,Group,,,,,,,,Conveyor05,,,
Motor Conveyor B4.1,Output,DevPin0,1,6,Sector04,Motor1On,Motor1Off,i2cOutput.dev01,,,,
Signal Motor Fault Conveyor B4.1 ,Input,DevPin0,1,6,Sector04,Motor1Fault,,i2cInput.dev01,,,,
Motor Conveyor B4.2,Output,DevPin0,1,7,Sector04,Motor2On,Motor2Off,i2cOutput.dev01,,,,
Signal Motor Fault Conveyor B4.2,Input,DevPin0,1,7,Sector04,Motor2Fault,,i2cInput.dev01,,,,
Light Barrier Conveyor 4,Input,DevPin0,2,5,Sector04,BoxDetected,,i2cInput.dev02,,,,
Control Cabinet,Group,,,,,,,,Cabinet,,,
Power Supply Control 5V,Input,DevPin0,2,6,Cabinet,Power5V,,i2cInput.dev02,,TRUE,,
Power Supply Drives 24V,Input,DevPin0,2,7,Cabinet,Power24VMotors,,i2cInput.dev02,,TRUE,,
Power Supply Sensor / Actors 24V,Input,DevPin0,2,8,Cabinet,Power24VSensors,,i2cInput.dev02,,TRUE,,
Security Relay Operational,Input,DevPin0,3,1,SecurityRelay,Operational,,i2cInput.dev03,,TRUE,,TRUE
Security Relay Acknowledge,Output,DevPin0,1,8,SecurityRelay,Reset,,i2cOutput.dev01,,,,
Configuration,Group,,,,,,,,Configuration,,,
Transfer time Sector 1.1,Virtual,Integer,-,,Sector01,TransferDuration1,,VirtualInteger.Sector01TransferDuration1,,,30,
Transfer time Sector 1.2,Virtual,Integer,-,,Sector01,TransferDuration2,,VirtualInteger.Sector01TransferDuration2,,,30,
Transfer time Sector 2.1,Virtual,Integer,-,,Sector02,TransferDuration1,,VirtualInteger.Sector02TransferDuration1,,,30,
Transfer time Sector 2.2,Virtual,Integer,-,,Sector02,TransferDuration2,,VirtualInteger.Sector02TransferDuration2,,,30,
Transfer time Fill Station,Virtual,Integer,-,,FillStation,TransferDuration,,VirtualInteger.FillStationTransferDuration,,,10,
Barcode scan duration,Virtual,Integer,-,,DataLogicScanner,ScanDuration,,VirtualInteger.DataLogicScannerScanDuration,,,4,
Transfer time Sector 4.1,Virtual,Integer,-,,Sector04,TransferDuration1,,VirtualInteger.Sector04TransferDuration1,,,30,
Transfer time Sector 4.2,Virtual,Integer,-,,Sector04,TransferDuration2,,VirtualInteger.Sector04TransferDuration2,,,30,
1 Description Type SubType Device Pin Resource Action1 Action2 Connection DeviceId Inverted Value Remote
2 Mode Group Mode
3 Automatic Mode Virtual Boolean AutomaticMode On Off VirtualBoolean.AutomaticMode TRUE
4 Stop All Actors Virtual Boolean StopAllActors Now VirtualBoolean.StopAllActors TRUE
5 Sector 1 Group Conveyor01
6 Motor Conveyor B1.1 Output DevPin0 1 1 Sector01 Motor1On Motor1Off i2cOutput.dev01
7 Signal Motor Fault Conveyor B1.1 Input DevPin0 1 1 Sector01 Motor1Fault i2cInput.dev01
8 Motor Conveyor B1.2 Output DevPin0 1 2 Sector01 Motor2On Motor2Off i2cOutput.dev01
9 Signal Motor Fault Conveyor B1.2 Input DevPin0 1 2 Sector01 Motor2Fault i2cInput.dev01
10 Start Button Conveyor 1 Input DevPin0 1 8 Sector01 StartButton i2cInput.dev01 TRUE
11 Light Barrier Conveyor 1 Input DevPin0 2 1 Sector01 BoxDetected i2cInput.dev02
12 Emergency Stop Sector 1 Input DevPin0 3 2 Sector01 EmergencyStop i2cInput.dev03 TRUE
13 Sector 2 Conveyor03
14 Motor Conveyor B2.1 Output DevPin0 1 3 Sector02 Motor1On Motor1Off i2cOutput.dev01
15 Signal Motor Fault Conveyor B2.1 Input DevPin0 1 3 Sector02 Motor1Fault i2cInput.dev01
16 Motor Conveyor B2.2 Output DevPin0 1 4 Sector02 Motor2On Motor2Off i2cOutput.dev01
17 Signal Motor Fault Conveyor B2.2 Input DevPin0 1 4 Sector02 Motor2Fault i2cInput.dev01
18 Light Barrier Conveyor 2 Input DevPin0 2 2 Sector02 BoxDetectedStart i2cInput.dev02
19 Light Barrier Conveyor End 2 Input DevPin0 2 3 Sector02 BoxDetectedEnd i2cInput.dev02
20 Sector 3 Fill Station Group BoxFillStation
21 Request Next Container Virtual Boolean - FillStation NextContainer NextContainerDone VirtualBoolean.NextContainer TRUE
22 Release Current Container Virtual Boolean - FillStation ReleaseContainer ReleaseContainerDone VirtualBoolean.ReleaseContainer TRUE
23 Current Container Virtual String - FillStation CurrentContainer VirtualString.CurrentContainer TRUE
24 Motor Conveyor B3 Output DevPin0 1 5 FillStation MotorOn MotorOff i2cOutput.dev01
25 Signal Motor Fault Conveyor B3 Input DevPin0 1 5 FillStation MotorFault i2cInput.dev01
26 Entry Stopper Open Valve Output DevPin0 2 1 FillStation EntryOpen EntryClose i2cOutput.dev02
27 Entry Stopper Opened Input DevPin0 3 4 FillStation EntryClosed i2cInput.dev03 TRUE TRUE
28 Entry Stopper Closed Input DevPin0 3 5 FillStation EntryOpened i2cInput.dev03 TRUE TRUE
29 Light Barrier Fill Station Occupied Input DevPin0 2 4 FillStation Occupied i2cInput.dev02 TRUE
30 Fill Station Barcode Reader DataLogicScanner - DataLogicScanner dataLogicScanner
31 Exit Stopper Open Valve Output DevPin0 2 2 FillStation ExitOpen ExitClose i2cOutput.dev02
32 Exit Stopper Opened Input DevPin0 3 6 FillStation ExitClosed i2cInput.dev03 TRUE TRUE
33 Exit Stopper Closed Input DevPin0 3 7 FillStation ExitOpened i2cInput.dev03 TRUE TRUE
34 Emergency Stop Sector 3 Input DevPin0 3 3 FillStation EmergencyStop i2cInput.dev03 TRUE
35 Signallampe Group Alarm
36 Signal Horn Output DevPin0 2 3 Alarm Horn i2cOutput.dev02
37 Signal Warning Output DevPin0 2 4 Alarm Warning i2cOutput.dev02
38 Signal Operation Output DevPin0 2 5 Alarm Operational i2cOutput.dev02
39 Sector 4 Group Conveyor05
40 Motor Conveyor B4.1 Output DevPin0 1 6 Sector04 Motor1On Motor1Off i2cOutput.dev01
41 Signal Motor Fault Conveyor B4.1 Input DevPin0 1 6 Sector04 Motor1Fault i2cInput.dev01
42 Motor Conveyor B4.2 Output DevPin0 1 7 Sector04 Motor2On Motor2Off i2cOutput.dev01
43 Signal Motor Fault Conveyor B4.2 Input DevPin0 1 7 Sector04 Motor2Fault i2cInput.dev01
44 Light Barrier Conveyor 4 Input DevPin0 2 5 Sector04 BoxDetected i2cInput.dev02
45 Control Cabinet Group Cabinet
46 Power Supply Control 5V Input DevPin0 2 6 Cabinet Power5V i2cInput.dev02 TRUE
47 Power Supply Drives 24V Input DevPin0 2 7 Cabinet Power24VMotors i2cInput.dev02 TRUE
48 Power Supply Sensor / Actors 24V Input DevPin0 2 8 Cabinet Power24VSensors i2cInput.dev02 TRUE
49 Security Relay Operational Input DevPin0 3 1 SecurityRelay Operational i2cInput.dev03 TRUE TRUE
50 Security Relay Acknowledge Output DevPin0 1 8 SecurityRelay Reset i2cOutput.dev01
51 Configuration Group Configuration
52 Transfer time Sector 1.1 Virtual Integer - Sector01 TransferDuration1 VirtualInteger.Sector01TransferDuration1 30
53 Transfer time Sector 1.2 Virtual Integer - Sector01 TransferDuration2 VirtualInteger.Sector01TransferDuration2 30
54 Transfer time Sector 2.1 Virtual Integer - Sector02 TransferDuration1 VirtualInteger.Sector02TransferDuration1 30
55 Transfer time Sector 2.2 Virtual Integer - Sector02 TransferDuration2 VirtualInteger.Sector02TransferDuration2 30
56 Transfer time Fill Station Virtual Integer - FillStation TransferDuration VirtualInteger.FillStationTransferDuration 10
57 Barcode scan duration Virtual Integer - DataLogicScanner ScanDuration VirtualInteger.DataLogicScannerScanDuration 4
58 Transfer time Sector 4.1 Virtual Integer - Sector04 TransferDuration1 VirtualInteger.Sector04TransferDuration1 30
59 Transfer time Sector 4.2 Virtual Integer - Sector04 TransferDuration2 VirtualInteger.Sector04TransferDuration2 30

View File

@ -0,0 +1,26 @@
package ${package}.plc.web.components;
import java.util.ArrayList;
import java.util.List;
import ${package}.plc.web.services.StartupPlcService;
import li.strolch.agent.api.ComponentContainer;
import li.strolch.plc.core.PlcHandler;
import li.strolch.plc.core.PlcService;
import li.strolch.plc.core.PlcServiceInitializer;
public class CustomPlcServiceInitializer extends PlcServiceInitializer {
public CustomPlcServiceInitializer(ComponentContainer container, String componentName) {
super(container, componentName);
}
@Override
protected List<PlcService> getPlcServices(PlcHandler plcHandler) {
ArrayList<PlcService> plcServices = new ArrayList<>();
plcServices.add(new StartupPlcService(plcHandler));
return plcServices;
}
}

View File

@ -0,0 +1,87 @@
package ${package}.plc.web.components;
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 {
registerJobs();
notifyStart();
super.start();
}
private void registerJobs() 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();
}
}
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,26 @@
package ${package}.plc.web.services;
import static ${package}.plc.shared.SharedPlcConstants.*;
import li.strolch.persistence.api.StrolchTransaction;
import li.strolch.plc.core.PlcHandler;
import li.strolch.plc.core.PlcService;
public class StartupPlcService extends PlcService {
public StartupPlcService(PlcHandler plcHandler) {
super(plcHandler);
}
@Override
public void start(StrolchTransaction tx) {
send(PLC, STARTED);
super.start(tx);
}
@Override
public void stop() {
send(PLC, STOPPED);
super.stop();
}
}

View File

@ -0,0 +1,50 @@
package ${package}.plc.web.web;
import static ${package}.plc.web.web.StartupListener.APP_NAME;
import javax.ws.rs.ApplicationPath;
import java.util.logging.Level;
import li.strolch.plc.rest.PlcConnectionsResource;
import li.strolch.rest.RestfulStrolchComponent;
import li.strolch.rest.StrolchRestfulClasses;
import org.glassfish.jersey.logging.LoggingFeature;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.ServerProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ApplicationPath("rest")
public class RestfulApplication extends ResourceConfig {
private static final Logger logger = LoggerFactory.getLogger(RestfulApplication.class);
public RestfulApplication() {
setApplicationName(APP_NAME);
// strolch services
for (Class<?> clazz : StrolchRestfulClasses.getRestfulClasses()) {
register(clazz);
}
packages(PlcConnectionsResource.class.getPackage().getName());
// filters
for (Class<?> clazz : StrolchRestfulClasses.getProviderClasses()) {
register(clazz);
}
RestfulStrolchComponent restfulComponent = RestfulStrolchComponent.getInstance();
if (restfulComponent.isRestLogging()) {
register(new LoggingFeature(java.util.logging.Logger.getLogger(LoggingFeature.DEFAULT_LOGGER_NAME),
Level.SEVERE, LoggingFeature.Verbosity.PAYLOAD_ANY, Integer.MAX_VALUE));
property(ServerProperties.TRACING, "ALL");
property(ServerProperties.TRACING_THRESHOLD, "TRACE");
}
logger.info(
"Initialized REST application " + getApplicationName() + " with " + getClasses().size() + " classes, "
+ getInstances().size() + " instances, " + getResources().size() + " resources and "
+ getProperties().size() + " properties");
}
}

View File

@ -0,0 +1,108 @@
package ${package}.plc.web.web;
import static li.strolch.utils.helper.ExceptionHelper.hasCause;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
import java.io.File;
import java.io.InputStream;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.util.ContextInitializer;
import li.strolch.agent.api.StrolchAgent;
import li.strolch.agent.api.StrolchBootstrapper;
import li.strolch.exception.StrolchException;
import li.strolch.rest.RestfulStrolchComponent;
import li.strolch.utils.helper.FileHelper;
import li.strolch.utils.helper.StringHelper;
import li.strolch.xmlpers.api.XmlPersistenceException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.impl.StaticLoggerBinder;
@WebListener
public class StartupListener implements ServletContextListener {
private static final Logger logger = LoggerFactory.getLogger(StartupListener.class);
public static final String APP_NAME = "MyApp";
private StrolchAgent agent;
@Override
public void contextInitialized(ServletContextEvent sce) {
logger.info("Starting " + APP_NAME + "...");
long start = System.currentTimeMillis();
try {
startStrolch(sce);
} catch (Throwable e) {
logger.error("Failed to start " + APP_NAME + " due to: " + e.getMessage(), e);
throw e;
}
long took = System.currentTimeMillis() - start;
logger.info("Started " + APP_NAME + " in " + (StringHelper.formatMillisecondsDuration(took)));
}
private void startStrolch(ServletContextEvent sce) {
String bootstrapFileName = "/" + StrolchBootstrapper.FILE_BOOTSTRAP;
InputStream bootstrapFile = getClass().getResourceAsStream(bootstrapFileName);
StrolchBootstrapper bootstrapper = new StrolchBootstrapper(StartupListener.class);
this.agent = bootstrapper.setupByBootstrapFile(StartupListener.class, bootstrapFile);
try {
this.agent.initialize();
this.agent.start();
RestfulStrolchComponent.getInstance().setWebPath(sce.getServletContext().getRealPath("/"));
} catch (StrolchException e) {
if (!hasCause(e, XmlPersistenceException.class))
throw e;
logger.error(
"Failed to start Strolch due to a XmlPersistenceException. Deleting local dbStore and restarting the agent...");
this.agent.stop();
this.agent.destroy();
File dataPath = this.agent.getStrolchConfiguration().getRuntimeConfiguration().getDataPath();
File dbStorePath = new File(dataPath, "dbStore");
if (dbStorePath.exists()) {
if (!FileHelper.deleteFile(dbStorePath, true))
throw new IllegalStateException(
"Strolch failed to load due to a persistence exception, could not delete dbStore, so failing hard!");
// now try again to start
bootstrapper = new StrolchBootstrapper(StartupListener.class);
bootstrapFile = getClass().getResourceAsStream(bootstrapFileName);
this.agent = bootstrapper.setupByBootstrapFile(StartupListener.class, bootstrapFile);
this.agent.initialize();
this.agent.start();
}
}
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
try {
new ContextInitializer((LoggerContext) StaticLoggerBinder.getSingleton().getLoggerFactory()).autoConfig();
} catch (Exception e) {
System.err.println("Failed to reconfigure logging...");
e.printStackTrace(System.err);
}
if (this.agent != null) {
logger.info("Destroying " + APP_NAME + "...");
try {
this.agent.stop();
this.agent.destroy();
} catch (Throwable e) {
logger.error("Failed to stop " + APP_NAME + " due to: " + e.getMessage(), e);
throw e;
}
}
logger.info("Destroyed " + APP_NAME);
}
}

View File

@ -0,0 +1,32 @@
<?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>
<env id="test" default="true">
<root>/absolute/path/to/runtime</root>
<environment>test</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,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.baseWsPath);
})();

View File

@ -0,0 +1,42 @@
<!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/main/c-main.html">
<style>
@font-face {
font-family: 'Ubuntu-local';
src: url(font/Ubuntu-Regular.ttf);
}
body {
margin: 0;
padding: 0;
font-family: 'Ubuntu-local', sans-serif;
font-size: 14px;
background-color: #fafafa;
}
</style>
</head>
<body unresolved>
<c-main></c-main>
</body>
</html>

View File

@ -0,0 +1,199 @@
<link rel="import" href="../../bower_components/polymer/polymer.html">
<link rel="import" href="./c-component-behavior.html">
<script>
CustomAppBehaviorImpl = {
properties: {
notifications: {
type: Array,
value: []
},
},
onClearSearchTerm: function () {
this.$$("#debouncedInput").onClearTapped();
},
_updatePageTitle: function (pageName) {
if (pageName === "${appName}" || pageName === "${appName}")
document.title = pageName;
else
document.title = "${appName}: " + (this.localize == null ? pageName : this.localize(pageName));
},
onLogOut: function () {
this.$$("#pages").logout();
sessionStorage.clear();
Strolch.clearStorageData();
this.deleteCookie("strolch.authorization");
window.location.reload();
},
reloadPage: function (pageName) {
this._updatePageTitle(pageName);
this.debounce('page-reload-' + pageName, function () {
var page = this.$$('#' + pageName);
if (page && page.reload) {
console.log('Reloading ' + pageName);
page.reload();
}
switch (pageName) {
case 'login' :
case 'inspector' :
case 'control' :
case 'operations-log' :
case 'jobs' :
case 'sessions' :
case 'users' :
case 'roles' :
case 'i18n-editor' :
case 'reports' :
this.set('toolbarConfig', {
pageTitle: pageName,
backButton: true,
hasSearchTerm: false
});
break;
default:
if (page != null && page.toolbarConfig != null) {
this.set('toolbarConfig', page.toolbarConfig);
}
}
}, 100);
},
onShowToast: function (e) {
if (this.$.toast.opened) {
this.$.toast.close();
this.async(function () {
this.toastText = e.detail.text;
this.$.toast.open();
}, 100);
} else {
this.toastText = e.detail.text;
this.$.toast.open();
}
},
onShowDialog: function (e) {
var dlgTitle;
if (e.detail.title != null)
dlgTitle = e.detail.title;
else
dlgTitle = e.detail.isError ? 'errorOccurred' : 'info';
var dlgText;
if (e.detail.text)
dlgText = e.detail.text;
else if (e.detail.message)
dlgText = e.detail.message;
else
dlgText = JSON.stringify(e.detail);
this._showDialog(dlgTitle, dlgText);
},
onShowNotification: function (e) {
console.log("Showing notification " + e.detail.id);
this.push("notifications", e.detail);
},
onClearNotification: function (e) {
console.log("Clearing notification " + e.detail.id);
for (var i = 0; i < this.notifications.length; i++) {
if (this.notifications[i].id === e.detail.id) {
this.splice("notifications", i, 1);
break;
}
}
},
onServerNotAvailable: function (event) {
clearInterval(this.checkForNewVersionInterval);
this.showInfo({
translate: true,
okLbl: 'reconnect',
title: 'serverNotAvailable',
line1: 'serverNotAvailableMsg',
cancelable: false,
callback: function (confirmed) {
if (confirmed)
this.reconnect();
}.bind(this)
});
},
onSessionInvalid: function (e) {
console.log(this.routeTail);
if (this.routeTail.prefix !== '/login') {
this.showInfo({
translate: true,
title: 'sessionInvalid',
line1: 'sessionInvalidConfirmNavToLogin',
cancelable: false,
callback: function (confirmed) {
if (!confirmed) return;
this.deleteCookie('strolch.authorization');
this.set("authTokenValid", false);
}.bind(this)
});
}
},
onPrivilegeDenied: function (e) {
if (this.authTokenValid) {
if (e.detail && e.detail.detail && e.detail.detail.request //
&& e.detail.detail.request.response //
&& e.detail.detail.request.response.i18n) {
this.showInfo({
title: 'privilegeDenied',
i18n: e.detail.detail.request.response.i18n,
translate: true
});
} else if (e.detail && e.detail.detail && e.detail.detail.request //
&& e.detail.detail.request.response //
&& e.detail.detail.request.response.exceptionMsg) {
this.showInfo({
title: 'privilegeDenied',
line1: e.detail.detail.request.response.exceptionMsg,
line2: this.requestEventToUrl(e),
translate: true
});
} else {
this.showInfo({
title: 'privilegeDenied',
line1: 'privilegeDeniedText',
line2: this.requestEventToUrl(e),
translate: true
});
}
} else {
console.warn("Privilege denied to URL " + this.requestEventToUrl(e));
this.requestErrorToMsg(e);
}
},
_showDialog: function (dlgTitle, dlgText, dlgReason) {
if (this.localize) {
var data = {
title: this.localize(dlgTitle),
line1: this.localize(dlgText)
};
if (dlgReason)
data.line1 += ": " + dlgReason;
this.$.infoDlg.open(data);
} else {
this.debounce('show-dlg', function () {
var data = {
title: this.localize(dlgTitle),
line1: this.localize(dlgText)
};
if (dlgReason)
data.line1 += ": " + dlgReason;
this.$.infoDlg.open(data);
}.bind(this), 250);
}
},
};
CustomAppBehavior = [CustomComponentBehavior, CustomAppBehaviorImpl];
</script>

View File

@ -0,0 +1,30 @@
<link rel="import" href="../../bower_components/polymer/polymer.html">
<link rel="import" href="../../bower_components/strolch-wc-util-behavior/strolch-wc-component-behavior.html">
<link rel="import" href="../../bower_components/strolch-wc-localize-behavior/strolch-wc-localize-behavior.html">
<script>
CustomComponentBehaviorImpl = {
properties: {
baseRestPath: {
type: String,
value: function () {
return CustomWeb.baseRestPath;
}
},
baseWsPath: {
type: String,
value: function () {
return CustomWeb.baseWsPath;
}
},
localesPath: {
type: String,
value: '../../../locales.json'
}
}
};
CustomComponentBehavior = [StrolchComponentBehavior, StrolchLocalizeBehavior, CustomComponentBehaviorImpl];
</script>

View File

@ -0,0 +1,199 @@
<link rel="import" href="../../bower_components/polymer/polymer.html">
<link rel="import" href="../../bower_components/iron-icons/iron-icons.html">
<link rel="import" href="../../bower_components/iron-ajax/iron-ajax.html">
<link rel="import" href="../../bower_components/app-layout/app-toolbar/app-toolbar.html">
<link rel="import" href="../../bower_components/paper-material/paper-material.html">
<link rel="import" href="../../bower_components/paper-dropdown-menu/paper-dropdown-menu.html">
<link rel="import" href="../../bower_components/paper-listbox/paper-listbox.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-icon-button/paper-icon-button.html">
<link rel="import" href="../../bower_components/strolch-wc-inspector/strolch-wc-inspector-menu.html">
<link rel="import" href="../behaviors/c-component-behavior.html">
<link rel="import" href="../styles/c-app-style.html">
<dom-module id="c-drawer">
<template>
<style is="custom-style" include="c-app-style">
:root {
}
app-drawer {
z-index: 10;
}
app-toolbar {
background-color: var(--app-primary-color);
color: var(--app-regular-highlight-fg-color);
}
paper-menu {
--paper-menu-selected-item: {
background-color: var(--app-light-highlight-bg-color);
};
--paper-menu-focused-item: {
background-color: var(--app-regular-highlight-bg-color);
};
}
paper-menu paper-item {
cursor: pointer;
}
paper-menu paper-item:hover {
background-color: var(--app-regular-highlight-bg-color);
}
.info-div {
display: block !important;
font-size: small;
color: darkgray;
}
.strolch {
color: #7f7f7f;
font-family: monospace;
font-weight: 600;
font-size: 30px;
text-shadow: 2px 2px 3px #7f7f7f;
margin: auto;
}
</style>
<app-drawer id="appDrawer">
<app-toolbar>
<paper-icon-button icon="menu" on-tap="closeDrawer"></paper-icon-button>
<div main-title>[[localize('appTitle')]]</div>
</app-toolbar>
<paper-menu id="menu" selected="{{page}}" attr-for-selected="id" on-tap="onMenuTap">
<paper-item id="plcConnections" class="menu-item">[[localize('plcConnections')]]</paper-item>
<paper-item id="plcLogicalDevices" class="menu-item">[[localize('plcLogicalDevices')]]</paper-item>
</paper-menu>
<template is="dom-if" if="[[hasRole('StrolchAdmin')]]">
<strolch-wc-inspector-menu selected-page="[[page]]"
on-menu-tap="onInspectorMenuTap"></strolch-wc-inspector-menu>
</template>
<paper-menu on-tap="onLogoutTapped">
<paper-item id="logout" class="menu-item">[[localize('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-item data="fr">Français</paper-item>
</paper-listbox>
</paper-dropdown-menu>
</paper-material>
<paper-material id="container" class="container" elevation="0">
<p class="strolch">${appName} PLC</p>
</paper-material>
</app-drawer>
<!-- Ajax requests -->
<iron-ajax id="ajaxPutLocale" content-type="application/json" handle-as="json" method="PUT"></iron-ajax>
</template>
<script>
Polymer({
is: 'c-drawer',
behaviors: [
CustomComponentBehavior
],
properties: {
authTokenValid: {
type: Boolean
},
userConfig: {
type: Object,
observer: "userConfigChanged"
},
userLocale: {
type: String,
observer: "userLocaleChanged"
},
version: {
type: Object
}
},
observers: [],
listeners: {},
toggleDrawer: function () {
this.$$("#appDrawer").toggle();
},
closeDrawer: function () {
this.$$("#appDrawer").close();
},
onInspectorMenuTap: function (e) {
this.changePage(e.detail.target.id, false);
},
onMenuTap: function (e) {
this.changePage(e.detail.sourceEvent.target.id, false);
},
onLogoutTapped: function (e) {
this.fire('cx-logout');
},
userConfigChanged: function (newValue, oldValue) {
if (newValue != null) {
var userLocale = Strolch.getUserLocale();
if (userLocale !== newValue.locale) {
console.log("Updating server side locale for user " + newValue.username + " to " + userLocale);
newValue.locale = userLocale;
Strolch.setUserConfig(newValue);
this.$.ajaxPutLocale.url = this.baseRestPath + "/strolch/sessions/" + newValue.sessionId + "/locale/" + userLocale;
this.$.ajaxPutLocale.generateRequest();
}
this.userLocale = newValue.locale;
}
},
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();
}
},
/* Lifecycle */
});
</script>
</dom-module>

View File

@ -0,0 +1,268 @@
<link rel="import" href="../../bower_components/polymer/polymer.html">
<link rel="import" href="../../bower_components/iron-icons/iron-icons.html">
<link rel="import" href="../../bower_components/app-layout/app-drawer-layout/app-drawer-layout.html">
<link rel="import" href="../../bower_components/app-layout/app-drawer/app-drawer.html">
<link rel="import" href="../../bower_components/app-layout/app-toolbar/app-toolbar.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/strolch-wc-debounced-input/strolch-wc-debounced-input.html">
<link rel="import" href="../../bower_components/strolch-wc-notification/strolch-wc-notification.html">
<link rel="import" href="../../bower_components/strolch-wc-information-dialog/strolch-wc-information-dialog.html">
<link rel="import" href="../behaviors/c-app-behavior.html">
<link rel="import" href="../styles/c-app-style.html">
<link rel="import" href="../utils/c-app-routing.html">
<link rel="import" href="./c-drawer.html">
<link rel="import" href="./c-pages.html">
<dom-module id="c-main">
<template>
<style is="custom-style" include="c-app-style">
:root {
display: block;
}
app-toolbar {
background-color: var(--app-primary-color);
color: var(--app-regular-highlight-fg-color);
}
strolch-wc-debounced-input {
--focus-color: white;
--input-color: white;
--regular-color: white;
}
</style>
<!-- Routing -->
<c-app-routing id="appRouting"
login-page="login"
auth-valid="[[authTokenValid]]"
page="{{page}}"
route-tail="{{routeTail}}"
use-hash-as-path></c-app-routing>
<app-drawer-layout fullbleed force-narrow>
<template is="dom-if" if="[[authTokenValid]]">
<c-drawer id="drawer" page="[[page]]" auth-token-valid="[[authTokenValid]]" user-config="[[userConfig]]" version="[[version]]"
on-strolch-app-version-outdated="onAppVersionOutdated"></c-drawer>
<app-toolbar>
<paper-icon-button icon="menu" on-tap="toggleDrawer"></paper-icon-button>
<div main-title>[[localize(page)]]</div>
<template is="dom-if" if="[[toolbarConfig.hasSearchTerm]]">
<strolch-wc-debounced-input id="debouncedInput"
debounced-input="{{searchTerm}}"></strolch-wc-debounced-input>
</template>
</app-toolbar>
</template>
<template is="dom-repeat" items="[[notifications]]" as="notification">
<strolch-wc-notification message="[[notification.message]]"
action1="[[notification.action1]]"
action2="[[notification.action2]]"
action3="[[notification.action3]]"
callback1="[[notification.callback1]]"
callback2="[[notification.callback2]]"
callback3="[[notification.callback3]]"
bind="[[notification.bind]]"
fa-icon="[[notification.faIcon]]"></strolch-wc-notification>
</template>
<c-pages id="pages" page="[[page]]" toolbar-config="{{toolbarConfig}}" route="{{routeTail}}" search-term="[[searchTerm]]"
user-location="{{userLocation}}"></c-pages>
<paper-toast id="toast" text="[[toastText]]"></paper-toast>
<paper-toast id="newVersionAvailableToast" duration="0">
<paper-button class="refresh" on-tap="refreshBrowser">[[localize('refresh')]]</paper-button>
</paper-toast>
</app-drawer-layout>
<strolch-wc-information-dialog id="infoDlg"
locales-path="../../../locales.json"></strolch-wc-information-dialog>
<!-- Ajax requests -->
<iron-ajax id="ajaxGetAppVersion"
url="[[baseRestPath]]/strolch/version"
content-type="application/json"
handle-as="json"
method="GET"
on-response="onGetAppVersionResponse"
on-error="onGetAppVersionError"></iron-ajax>
</template>
<script>
Polymer({
is: 'c-main',
behaviors: [
CustomAppBehavior
],
properties: {
toolbarConfig: {
type: Object
},
searchTerm: {
type: String
},
page: {
type: String
},
authToken: {
type: String
},
authTokenValid: {
type: Boolean,
value: false
},
userConfig: {
type: Object
},
route: {
type: Object
},
toastText: {
type: String,
value: 'not-yet-set'
},
version: {
type: Object
}
},
observers: [],
listeners: {
"strolch-session-valid": "onSessionValidated",
"strolch-reload": "reload",
"strolch-show-toast": "onShowToast",
"strolch-server-not-available": "onServerNotAvailable",
"strolch-session-invalid": "onSessionInvalid",
"strolch-privilege-denied": "onPrivilegeDenied",
"strolch-change-page": "onPageChange",
"strolch-show-dialog": "onShowDialog",
"strolch-show-info": "onShowInfo",
"strolch-ajax-request-error": "onRequestError",
"strolch-show-notification": "onShowNotification",
"strolch-clear-notification": "onClearNotification",
"strolch-clear-search-term": "onClearSearchTerm",
"cx-logout": "onLogOut",
},
reload: function () {
this.reloadPage(this.page);
},
toggleDrawer: function () {
this.$$("#drawer").toggleDrawer();
},
closeDrawer: function () {
this.$$("#drawer").closeDrawer();
},
onPageChange: function (e) {
this.closeDrawer();
if (e && e.detail && e.detail.page) {
var pageName = e.detail.page;
// set the next page
document.title = this.localize == null ? pageName : this.localize(pageName);
this.$.appRouting.pushNextPage(pageName, e.detail.keepQueryParams);
} else {
console.log("received page change without new value");
}
},
onShowInfo: function (e) {
this.$.infoDlg.open(e.detail);
},
onSessionValidated: function () {
console.log("Session validated.");
this.set("authToken", Strolch.getAuthToken());
this.set("authTokenValid", true);
this.set("userConfig", Strolch.getUserConfig());
this.$.ajaxGetAppVersion.generateRequest();
},
onGetAppVersionResponse: function (event) {
this.version = event.detail.response;
Strolch.setAppVersion(this.version);
var artifactVersion = this.version.appVersion.artifactVersion;
var scmRevision = this.version.appVersion.scmRevision;
console.log("App Version is " + artifactVersion);
var currentVersion = sessionStorage.appScmRevision;
if (currentVersion == null //
|| currentVersion === 'undefined' //
|| scmRevision == null
|| scmRevision === 'undefined') {
sessionStorage.appScmRevision = scmRevision;
console.log("App SCM Revision is now known as " + scmRevision);
} else if (scmRevision !== currentVersion) {
console.log("App SCM Revision has changed from " + currentVersion + " to " + scmRevision + ". Need to refresh browser...");
this.fire("strolch-app-version-outdated", {newVersion: scmRevision});
this.$.newVersionAvailableToast.text = this.localize('newVersionAvailableRefreshRequired') + ": " + artifactVersion;
this.$.newVersionAvailableToast.open();
}
},
onGetAppVersionError: 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);
}
},
refreshBrowser: function () {
sessionStorage.appScmRevision = this.version.appVersion.scmRevision;
document.location.reload();
},
checkForNewVersion: function () {
this.$.ajaxGetAppVersion.generateRequest();
},
reconnect: function () {
this.onGetAppVersionResponse = function (event) {
var version = event.detail.response;
this.scmRevision = version.appVersion.scmRevision;
sessionStorage.appScmRevision = this.scmRevision;
document.location.reload();
};
this.$.ajaxGetAppVersion.generateRequest();
},
/* Lifecycle */
attached: function () {
setTimeout(function () {
this.checkForNewVersion();
}.bind(this), 5000);
this.checkForNewVersionInterval = setInterval(function () {
this.checkForNewVersion();
}.bind(this), 300000);
window.addEventListener("beforeunload", function (e) {
console.log("App SCM Revision " + sessionStorage.appScmRevision + " is cleared due to unload of UI");
delete sessionStorage.appScmRevision;
return null;
});
},
});
</script>
</dom-module>

View File

@ -0,0 +1,192 @@
<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/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-operations-log.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-inspector/strolch-wc-i18n-editor.html">
<link rel="import" href="../../bower_components/strolch-wc-reports/strolch-wc-reports.html">
<link rel="import" href="../../bower_components/strolch-wc-plc/strolch-wc-plc-connections.html">
<link rel="import" href="../../bower_components/strolch-wc-plc/strolch-wc-plc-logical-devices.html">
<link rel="import" href="../behaviors/c-app-behavior.html">
<link rel="import" href="../styles/c-app-style.html">
<link rel="import" href="../views/c-view404.html">
<dom-module id="c-pages">
<template>
<style is="custom-style" include="c-app-style">
:root {
display: block;
}
</style>
<iron-pages selected="[[selectedPage]]" attr-for-selected="id" fallback-selection="view404">
<strolch-wc-auth id="login"
app-title="[[localize('appTitle')]]"
toolbar-config="{{toolbarConfig}}"
base-path="../"
show-version
show-keep-alive theme="[[theme]]"></strolch-wc-auth>
<template is="dom-if" if="[[equal(page, 'plcConnections')]]" restamp>
<strolch-wc-plc-connections id="plcConnections"
base-path="../"
base-rest-path="[[baseRestPath]]"
route="{{subroute}}"></strolch-wc-plc-connections>
</template>
<template is="dom-if" if="[[equal(page, 'plcLogicalDevices')]]" restamp>
<strolch-wc-plc-logical-devices id="plcLogicalDevices"
base-path="../"
base-rest-path="[[baseRestPath]]"
base-ws-path="[[baseWsPath]]"
route="{{subroute}}"></strolch-wc-plc-logical-devices>
</template>
<template is="dom-if" if="[[equal(page, 'inspector')]]" restamp>
<strolch-wc-inspector id="inspector"
toolbar-config="{{toolbarConfig}}"
base-path="../"
route="{{route}}"></strolch-wc-inspector>
</template>
<template is="dom-if" if="[[equal(page, 'operations-log')]]" restamp>
<strolch-wc-operations-log id="operations-log"
toolbar-config="{{toolbarConfig}}"
base-path="../"
route="{{route}}"></strolch-wc-operations-log>
</template>
<template is="dom-if" if="[[equal(page, 'jobs')]]" restamp>
<strolch-wc-jobs id="jobs"
toolbar-config="{{toolbarConfig}}"
base-path="../"
route="{{route}}"></strolch-wc-jobs>
</template>
<template is="dom-if" if="[[equal(page, 'reports')]]" restamp>
<strolch-wc-reports id="reports"
toolbar-config="{{toolbarConfig}}"
base-path="../"
base-rest-path="[[baseRestPath]]"
locales-path="../../../locales.json"
route="{{route}}"
facet-limit="[[reportFacetLimit]]"
propagate-show-dialog></strolch-wc-reports>
</template>
<template is="dom-if" if="[[equal(page, 'users')]]" restamp>
<strolch-wc-users id="users"
toolbar-config="{{toolbarConfig}}"
base-path="../"
route="{{route}}"></strolch-wc-users>
</template>
<template is="dom-if" if="[[equal(page, 'roles')]]" restamp>
<strolch-wc-roles id="roles"
toolbar-config="{{toolbarConfig}}"
base-path="../"
route="{{route}}"></strolch-wc-roles>
</template>
<template is="dom-if" if="[[equal(page, 'sessions')]]" restamp>
<strolch-wc-sessions id="sessions"
toolbar-config="{{toolbarConfig}}"
base-path="../"
route="{{route}}"></strolch-wc-sessions>
</template>
<template is="dom-if" if="[[equal(page, 'control')]]" restamp>
<strolch-wc-control id="control"
class="padded-view"
base-path="../"
base-ws-path="[[baseWsPath]]"
toolbar-config="{{toolbarConfig}}"
search-term="{{searchTerm}}"
user-location="{{userLocation}}"
route="{{routeTail}}"
propagate-show-dialog></strolch-wc-control>
</template>
<c-view404 id="view404"></c-view404>
</iron-pages>
</template>
<script>
Polymer({
is: 'c-pages',
behaviors: [
CustomAppBehavior
],
properties: {
toolbarConfig: {
type: Object,
notify: true
},
searchTerm: {
type: String
},
page: {
type: String,
observer: 'observePage'
},
selectedPage: {
type: String,
observer: 'observeSelectedPage'
},
route: {
type: Object
},
reportFacetLimit: {
type: Number,
value: function () {
return 25;
}
}
},
observers: [],
listeners: {},
observePage: function (newValue, oldValue) {
if (newValue) {
this.async(function () {
this.selectedPage = newValue;
}, 10);
}
},
observeSelectedPage: function (newValue, oldValue) {
if (newValue) {
console.log("Page changed to " + newValue + ", reloading...");
this.reloadPage(newValue);
}
},
logout: function () {
this.$$('#login').logout();
}
});
</script>
</dom-module>

View File

@ -0,0 +1,14 @@
<link rel="import" href="../../bower_components/polymer/polymer.html">
<link rel="import" href="../../bower_components/strolch-wc-styles/strolch-wc-app-style.html">
<dom-module id="c-app-style">
<template>
<style is="c-app-style" include="strolch-wc-app-style">
:root {
}
</style>
</template>
</dom-module>

View File

@ -0,0 +1,148 @@
<!-- Components -->
<link rel="import" href="../../bower_components/polymer/polymer.html">
<link rel="import" href="../../bower_components/app-route/app-location.html">
<link rel="import" href="../../bower_components/app-route/app-route.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"
},
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)"
],
computeDefaultPage: function (userConfig) {
if (userConfig == null)
return "plcLogicalDevices";
Strolch.setUserConfig(userConfig);
if (Strolch.hasRole("StrolchAdmin")) {
return "plcLogicalDevices";
} else {
return "plcLogicalDevices";
}
},
observeRouteData: function (routeData) {
// redirect to login or default if there is no page
if (!routeData.page) {
var firstPage = this.authValid ? this.computeDefaultPage(Strolch.getUserConfig()) : 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) {
// 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.computeDefaultPage(Strolch.getUserConfig()));
}
}
// 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) {
console.log("Not authenticated, navigating from page " + pathBase + " to " + this.loginPage);
// 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,46 @@
<link rel="import" href="../../bower_components/polymer/polymer.html">
<link rel="import" href="../styles/c-app-style.html">
<dom-module id="c-view404">
<template>
<style is="custom-style" include="c-app-style">
:host {
display: block;
min-height: 100%;
padding: 10px 20px;
}
</style>
Oops you hit a 404.
</template>
<script>
Polymer({
is: 'c-view404',
behaviors: [
CustomComponentBehavior, StrolchLocalizeBehavior
],
properties: {
toolbarConfig: {
type: Object,
notify: true,
readOnly: true,
value: {
hasSearchTerm: false
}
},
dataObj: {
type: Object
},
messages: {
type: Array
}
}
});
</script>
</dom-module>

View File

@ -0,0 +1,43 @@
{
"name": "${rootArtifactId}-plc-web",
"authors": [
"Robert von Burg <eitch@eitchnet.ch>"
],
"private": true,
"dependencies": {
"strolchjs": "strolch-li/strolchjs#^0.5.3",
"strolch-wc-styles": "strolch-li/strolch-wc-styles#^0.4.8",
"strolch-wc-auth": "strolch-li/strolch-wc-auth#^0.9.9",
"strolch-wc-badge": "strolch-li/strolch-wc-badge#^0.1.4",
"strolch-wc-notification": "strolch-li/strolch-wc-notification#^0.1.1",
"strolch-wc-inspector": "strolch-li/strolch-wc-inspector#^0.23.6",
"strolch-wc-util-behavior": "strolch-li/strolch-wc-util-behavior#^0.3.7",
"strolch-wc-localize-behavior": "strolch-li/strolch-wc-localize-behavior#^1.1.15",
"strolch-wc-debounced-input": "strolch-li/strolch-wc-debounced-input#^0.1.6",
"strolch-wc-dialog-button": "strolch-li/strolch-wc-dialog-button#^0.1.7",
"strolch-wc-information-dialog": "strolch-li/strolch-wc-information-dialog#^0.1.14",
"strolch-wc-parameter-input": "strolch-li/strolch-wc-parameter-input#^0.1.5",
"strolch-wc-reports": "strolch-li/strolch-wc-reports#^0.5.3",
"strolch-wc-paging": "strolch-li/strolch-wc-paging#^0.1.7",
"strolch-wc-ws-observer": "strolch-li/strolch-wc-ws-observer#^0.2.11",
"strolch-wc-tree": "strolch-li/strolch-wc-tree#^0.2.6",
"strolch-wc-plc": "strolch-li/strolch-wc-plc#^0.3.19",
"polymer": "Polymer/polymer#^1.12.0",
"iron-pages": "PolymerElements/iron-pages#^1.0.9",
"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.6",
"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-toggle-button": "PolymerElements/paper-toggle-button#^1.3.0",
"paper-toast": "PolymerElements/paper-toast#^1.3.1"
},
"devDependencies": {
}
}

View File

@ -0,0 +1,93 @@
const gulp = require('gulp');
const $ = require('gulp-load-plugins')();
const merge = require('merge-stream');
const del = require('del');
// temporary until gulp 4.0 is released
const runSequence = require('run-sequence');
const vulcanize = require('gulp-vulcanize');
const minify = require('gulp-minify');
const crisper = require('gulp-crisper');
const shell = require('gulp-shell');
const rename = require("gulp-rename");
const replace = require('gulp-replace');
// 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 font = gulp.src([
'app/font/*'
])
.pipe(gulp.dest('www/font/'));
var imgs = gulp.src([
'app/img/*.svg', 'app/img/*.ico', 'app/img/*.png', 'app/img/*.gif'
])
.pipe(gulp.dest('www/img/'));
var locales = gulp.src([
'app/bower_components/**/locales.json'
])
.pipe(gulp.dest('www/bower_components/'));
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, font, imgs, locales, 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(replace('<link rel="stylesheet" type="text/css" href="https://fonts.googleapis.com/css?family=Roboto+Mono:400,700|Roboto:400,300,300italic,400italic,500,500italic,700,700italic" crossorigin="anonymous">', ''))
.pipe(replace("font-family: 'Roboto', 'Noto', sans-serif;", "font-family: 'Ubuntu-local', sans-serif;"))
.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,155 @@
{
"en": {
"plcConnections": "PLC Connections",
"plcLogicalDevices": "PLC Logical Devices",
"agent.service.failed.access.denied": "User {user} may not perform service {service}",
"agent.query.failed.access.denied": "User {user} may not perform query {query}",
"agent.search.failed.access.denied": "User {user} may not perform search {search}",
"logout": "Logout",
"info": "Information",
"keepAlive": "Stay logged in",
"appTitle": "${appName} PLC",
"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",
"privilegeDenied": "Action denied",
"privilegeDeniedText": "The action has been denied",
"sessionInvalid": "Session Invalid",
"sessionInvalidConfirmNavToLogin": "The session has expired or is invalid. Please logon again.",
"sessionInvalidLoggingBackIn": "The session is invalid or has expired, automatic logon has commenced...",
"enabled": "Active",
"severity": "Severity",
"true": "Yes",
"false": "No",
"Info": "Information",
"Exception": "Exception",
"clearInactiveMessages": "Remove inactive messages",
"clearInactiveMessagesConfirm": "Should all inactive messages be removed?",
"errorOccurred": "An error occurred",
"systemAction.failed": "SystemAction {action} failed: {reason}",
"Created": "Created",
"Planning": "Planning",
"Planned": "Planned",
"Execution": "Execution",
"Warning": "Warning",
"Error": "Error",
"Executed": "Executed",
"Closed": "Closed",
"date": "Date",
"deleted": "Deleted",
"id": "ID",
"status": "Status",
"enable": "Enable",
"disable": "Disable",
"mode": "Mode",
"user": "User",
"i18n-editor": "Internationalization editor",
"login": "Login"
},
"de": {
"appTitle": "${appName} Steuerung",
"plcConnections": "SPS Verbindungen",
"plcLogicalDevices": "SPS Logische Geräte",
"logout": "Ausloggen",
"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",
"privilegeDenied": "Aktion verweigert",
"privilegeDeniedText": "Die Aktion wurde verweigert.",
"sessionInvalid": "Sitzung ungültig",
"sessionInvalidConfirmNavToLogin": "Die Sitzung ist abgelaufen oder ungültig. Bitte neu anmelden.",
"sessionInvalidLoggingBackIn": "Die Sitzung ist ungültig oder abgelaufen, automatische Anmeldung wird ausgeführt...",
"errorOccurred": "Ein Fehler ist aufgetreten",
"login": "Login",
"i18n-editor": "Internationalisierungs Editor",
"user": "Benutzer",
"mode": "Modus",
"enable": "Aktivieren",
"disable": "Deaktivieren",
"status": "Status",
"id": "ID",
"deleted": "Gelöscht",
"date": "Datum",
"Created": "Erstellt",
"Planning": "In Planung",
"Planned": "Geplant",
"Execution": "In Ausführung",
"Warning": "Warnung",
"Error": "Fehler",
"Executed": "Ausgeführt",
"Closed": "Geschlossen",
"keepAlive": "Eingeloggt bleiben",
"systemAction.failed": "Systembefehl {action} fehlgeschlagen: {reason}",
"enabled": "Aktiv",
"severity": "Schweregrad",
"true": "Ja",
"false": "Nein",
"Info": "Information",
"Exception": "Ausnahme",
"clearInactiveMessages": "Inaktive Meldungen entfernen",
"clearInactiveMessagesConfirm": "Sollen alle inaktive Meldungen entfernt werden?",
"executionDate": "Ausführungsdatum",
"orderDate": "Auftragsdatum",
"info": "Information",
"agent.service.failed.access.denied": "Benutzer {user} darf Service {service} nicht ausführen",
"agent.query.failed.access.denied": "Benutzer {user} darf Abfrage {query} nicht ausführen",
"agent.search.failed.access.denied": "Benutzer {user} darf Suche {search} nicht ausführen"
},
"fr": {
"appTitle": "${appName} Controle",
"language": "Langue",
"reports": "Rapports",
"operations-log": "Logs",
"jobs": "Jobs",
"sessions": "Sessions",
"users": "Utilisateurs",
"roles": "Rôles",
"control": "Controle",
"inspector": "Inspecteur",
"newVersionAvailableRefreshRequired": "Une nouvelle version est disponible!",
"refresh": "Actualiser",
"close": "Fermer",
"cancel": "Annuler",
"ok": "Ok",
"reconnect": "Reconnecter",
"serverNotAvailable": "Server indisponible",
"serverNotAvailableMsg": "La connexion au serveur est indisponible",
"privilegeDenied": "Action refusée",
"privilegeDeniedText": "L'action a été refusée.",
"sessionInvalid": "Session invalide",
"sessionInvalidConfirmNavToLogin": "La session a expirée, veuillez vous reconnecter.",
"sessionInvalidLoggingBackIn": "La session a expirée, reconnexion automatiqque...",
"errorOccurred": "Une erreur s'est produite",
"agent.service.failed.access.denied": "Utilisateur {user} ne peut exécuter le service {service}",
"agent.query.failed.access.denied": "Utilisateur {user} ne peut exécuter la demande {query}",
"agent.search.failed.access.denied": "Utilisateur {user} ne peut exécuter la recherche {search}"
}
}

View File

@ -0,0 +1,37 @@
{
"name": "${rootArtifactId}-plc-web",
"description": "${appName}",
"version": "${version}",
"private": true,
"repository": {
"type": "git",
"url": "https://github.com/strolch-li/strolch.git"
},
"author": "Robert von Burg <eitch@eitchnet.ch>",
"license": "Proprietary",
"keywords": [],
"bugs": {
"url": "https://github.com/strolch-li/strolch/issues"
},
"homepage": "https://www.strolch.li",
"devDependencies": {
"bower": "^1.8.8",
"del": "^2.2.2",
"gulp": "^3.9.1",
"gulp-crisper": "^1.1.0",
"gulp-imagemin": "^7.1.0",
"gulp-load-plugins": "^1.4.0",
"gulp-minify": "0.0.15",
"gulp-rename": "^1.2.2",
"gulp-shell": "^0.8.0",
"gulp-size": "^2.1.0",
"gulp-vulcanize": "^6.1.0",
"gulp-replace": "^1.1.3",
"merge-stream": "^1.0.0",
"run-sequence": "^1.2.2",
"vulcanize": "^1.15.3"
},
"scripts": {
"postinstall": "bower install"
}
}

View File

@ -0,0 +1,100 @@
<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>${groupId}</groupId>
<artifactId>${rootArtifactId}</artifactId>
<version>${version}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>${rootArtifactId}-shared</artifactId>
<name>${rootArtifactId}-shared</name>
<packaging>jar</packaging>
<properties>
<!-- properties -->
</properties>
<dependencies>
<!-- base -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</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>strolch-plc-model</artifactId>
</dependency>
<!-- utils -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
<!-- test -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<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>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,78 @@
package ${package}.plc.shared;
public class SharedPlcConstants {
public static final String PARAM_AUTOMATIC_MODE = "automaticMode";
public static final String PARAM_PLC_STARTED = "plcStarted";
public static final String PARAM_PLC_CONNECTED = "plcConnected";
public static final String R_ALARM = "Alarm";
public static final String R_AUTOMATIC_MODE = "AutomaticMode";
public static final String R_CABINET = "Cabinet";
public static final String R_DATA_LOGIC_SCANNER = "DataLogicScanner";
public static final String R_FILL_STATION = "FillStation";
public static final String R_SECTOR_01 = "Sector01";
public static final String R_SECTOR_02 = "Sector02";
public static final String R_SECTOR_04 = "Sector04";
public static final String R_SECURITY_RELAY = "SecurityRelay";
public static final String R_STOP_ALL_ACTORS = "StopAllActors";
public static final String R_BUTTON_1 = "Button1";
public static final String R_BUTTON_2 = "Button2";
public static final String R_BUTTON_3 = "Button3";
public static final String R_LED_1 = "Led1";
public static final String R_LED_2 = "Led2";
public static final String A_PRESSED = "Pressed";
public static final String A_RELEASED = "Released";
public static final String A_BOX_DETECTED = "BoxDetected";
public static final String A_BOX_DETECTED_END = "BoxDetectedEnd";
public static final String A_BOX_DETECTED_START = "BoxDetectedStart";
public static final String A_CURRENT_CONTAINER = "CurrentContainer";
public static final String A_EMERGENCY_STOP = "EmergencyStop";
public static final String A_ENTRY_CLOSE = "EntryClose";
public static final String A_ENTRY_CLOSED = "EntryClosed";
public static final String A_ENTRY_OPEN = "EntryOpen";
public static final String A_ENTRY_OPENED = "EntryOpened";
public static final String A_EXIT_CLOSE = "ExitClose";
public static final String A_EXIT_CLOSED = "ExitClosed";
public static final String A_EXIT_OPEN = "ExitOpen";
public static final String A_EXIT_OPENED = "ExitOpened";
public static final String A_HORN = "Horn";
public static final String A_MOTOR_1_FAULT = "Motor1Fault";
public static final String A_MOTOR_1_OFF = "Motor1Off";
public static final String A_MOTOR_1_ON = "Motor1On";
public static final String A_MOTOR_2_FAULT = "Motor2Fault";
public static final String A_MOTOR_2_OFF = "Motor2Off";
public static final String A_MOTOR_2_ON = "Motor2On";
public static final String A_MOTOR_FAULT = "MotorFault";
public static final String A_MOTOR_OFF = "MotorOff";
public static final String A_MOTOR_ON = "MotorOn";
public static final String A_NEXT_CONTAINER = "NextContainer";
public static final String A_NEXT_CONTAINER_DONE = "NextContainerDone";
public static final String A_NOW = "Now";
public static final String A_OCCUPIED = "Occupied";
public static final String A_OFF = "Off";
public static final String A_ON = "On";
public static final String A_OPERATIONAL = "Operational";
public static final String A_POWER_5V = "Power5V";
public static final String A_POWER_24V_MOTORS = "Power24VMotors";
public static final String A_POWER_24V_SENSORS = "Power24VSensors";
public static final String A_RELEASE_CONTAINER = "ReleaseContainer";
public static final String A_RELEASE_CONTAINER_DONE = "ReleaseContainerDone";
public static final String A_RESET = "Reset";
public static final String A_SCAN_DURATION = "ScanDuration";
public static final String A_START_BUTTON = "StartButton";
public static final String A_TRANSFER_DURATION = "TransferDuration";
public static final String A_TRANSFER_DURATION_1 = "TransferDuration1";
public static final String A_TRANSFER_DURATION_2 = "TransferDuration2";
public static final String A_WARNING = "Warning";
public static final String PLC = "PLC";
public static final String STARTED = "Started";
public static final String STOPPED = "Stopped";
public static final String ROLE_SHOP_FLOOR = "ShopFloor";
}

View File

@ -0,0 +1,249 @@
<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>${groupId}</groupId>
<artifactId>${rootArtifactId}</artifactId>
<version>${version}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>${rootArtifactId}-web</artifactId>
<name>${rootArtifactId}-web</name>
<packaging>war</packaging>
<properties>
<appFinalName>${rootArtifactId}-web</appFinalName>
<warFinalName>${rootArtifactId}-web</warFinalName>
</properties>
<dependencies>
<!-- base -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<scope>compile</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>
<!-- Strolch PLC -->
<dependency>
<groupId>li.strolch</groupId>
<artifactId>strolch-plc-gw-server</artifactId>
</dependency>
<!-- my-app -->
<dependency>
<groupId>${groupId}</groupId>
<artifactId>${rootArtifactId}-shared</artifactId>
</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>
<!-- testing -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</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.apache.maven.plugins</groupId>
<artifactId>maven-clean-plugin</artifactId>
<version>${maven-clean-plugin.version}</version>
<configuration>
<filesets>
<fileset>
<directory>src/main/webapp/app/bower_components</directory>
<includes>
<include>**</include>
</includes>
<followSymlinks>false</followSymlinks>
</fileset>
</filesets>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>${exec-maven-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,48 @@
<?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"/>
<Parameter name="allowSessionRefresh" 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,216 @@
<?xml version="1.0" encoding="UTF-8"?>
<Roles>
<Role name="ShopFloor">
<Privilege name="li.strolch.service.api.Service" 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="${package}.server.web.service.ShopFloorActionService" policy="DefaultPrivilege">
<Allow>EnableAutomaticMode</Allow>
<Allow>DisableAutomaticMode</Allow>
<Allow>StopAll</Allow>
</Privilege>
</Role>
<!--
Internal
-->
<Role name="PLC">
</Role>
<Role name="ModelAccessor">
<Privilege name="GetOrder" 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="UpdateActivity" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="GetActivity" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="RemoveActivity" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="GetResource" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="RemoveResource" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="AddResource" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="UpdateOrder" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="RemoveOrder" policy="ModelPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
</Role>
<Role name="StrolchAdmin">
<Privilege name="I18n" policy="DefaultPrivilege">
<Allow>Get</Allow>
<Allow>Update</Allow>
</Privilege>
<Privilege name="PrivilegeAddUser" policy="UserAccessPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="PrivilegeSetUserPassword" policy="UserAccessPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="RequirePasswordChange" 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.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="UserPrivileges">
<Privilege name="li.strolch.service.api.Service" policy="DefaultPrivilege">
<Allow>li.strolch.service.privilege.users.PrivilegeSetUserPasswordService</Allow>
<Allow>li.strolch.service.privilege.users.PrivilegeSetUserLocaleService</Allow>
</Privilege>
<Privilege name="PrivilegeSetUserPassword" policy="UserAccessPrivilege"/>
<Privilege name="PrivilegeSetUserLocale" policy="UserAccessPrivilege"/>
</Role>
<Role name="PrivilegeAdmin">
<Privilege name="li.strolch.service.api.Service" policy="DefaultPrivilege">
<Allow>li.strolch.service.privilege.users.PrivilegeUpdateUserService</Allow>
<Allow>li.strolch.service.privilege.users.PrivilegeUpdateUserRolesService</Allow>
<Allow>li.strolch.service.privilege.users.PrivilegeSetUserPasswordService</Allow>
<Allow>li.strolch.service.privilege.users.PrivilegeSetUserLocaleService</Allow>
<Allow>li.strolch.service.privilege.users.PrivilegeRemoveUserService</Allow>
<Allow>li.strolch.service.privilege.users.PrivilegeRemoveRoleFromUserService</Allow>
<Allow>li.strolch.service.privilege.users.PrivilegeAddUserService</Allow>
<Allow>li.strolch.service.privilege.users.PrivilegeAddRoleToUserService</Allow>
<Allow>li.strolch.service.privilege.roles.PrivilegeUpdateRoleService</Allow>
<Allow>li.strolch.service.privilege.roles.PrivilegeRemoveRoleService</Allow>
<Allow>li.strolch.service.privilege.roles.PrivilegeRemovePrivilegeFromRoleService</Allow>
<Allow>li.strolch.service.privilege.roles.PrivilegeAddRoleService</Allow>
<Allow>li.strolch.service.privilege.roles.PrivilegeAddOrReplacePrivilegeOnRoleService</Allow>
</Privilege>
<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="RequirePasswordChange" 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>
<Role name="agent">
<Privilege name="PrivilegeAddUser" policy="UserAccessPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="PrivilegeRemoveUser" policy="UserAccessPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="li.strolch.search.StrolchSearch" policy="DefaultPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<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>Persist</Allow>
<Allow>GetCertificates</Allow>
<Allow>PersistSessions</Allow>
</Privilege>
<Privilege name="PrivilegeGetUser" policy="UserAccessPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="li.strolch.service.api.Service" policy="DefaultPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="PrivilegeModifyUser" policy="UserAccessPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
</Role>
</Roles>

View File

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<Users>
<!-- Password: plc-01 -->
<User userId="100" username="plc-01" password="$PBKDF2WithHmacSHA512,10000,256$66356438613636353335646634343039366630316238383430663766343431383265666438306666613533336530363437383163623664373534353034343564$88cae5330f44cde7bb7bc43a51ab7e814366482673c13448e3391c40ca004894">
<Firstname>PLC</Firstname>
<Lastname>01</Lastname>
<State>ENABLED</State>
<Locale>en</Locale>
<Roles>
<Role>PLC</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>StrolchAdmin</Role>
<Role>ShopFloor</Role>
<Role>ModelAccessor</Role>
<Role>PrivilegeAdmin</Role>
</Roles>
<Properties>
<Property name="organization" value="strolch.li"/>
<Property name="organizationalUnit" value="Development"/>
</Properties>
</User>
<User userId="0" username="agent">
<State>SYSTEM</State>
<Roles>
<Role>ModelAccessor</Role>
<Role>PrivilegeAdmin</Role>
<Role>agent</Role>
</Roles>
</User>
</Users>

View File

@ -0,0 +1,132 @@
<?xml version="1.0" encoding="UTF-8"?>
<StrolchConfiguration>
<env id="global">
<Runtime>
<applicationName>${appName}</applicationName>
<Properties>
<locale>en</locale>
<verbose>true</verbose>
<timezone>Europe/Zurich</timezone>
</Properties>
</Runtime>
<Component>
<name>PrivilegeHandler</name>
<api>li.strolch.runtime.privilege.PrivilegeHandler</api>
<impl>li.strolch.runtime.privilege.DefaultStrolchPrivilegeHandler</impl>
</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>
</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.maxKeepAlive.minutes>10080</session.maxKeepAlive.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}.server.web.components.PostInitializer</impl>
<depends>RestfulHandler</depends>
</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>
<Component>
<name>PlcGwServerHandler</name>
<api>li.strolch.plc.gw.server.PlcGwServerHandler</api>
<impl>li.strolch.plc.gw.server.PlcGwServerHandler</impl>
<depends>ServiceHandler</depends>
<Properties>
<systemUser>plc-server</systemUser>
</Properties>
</Component>
</env>
<env id="dev">
<!-- taken from global env -->
</env>
<env id="test">
<!-- taken from global env -->
</env>
</StrolchConfiguration>

View File

@ -0,0 +1,21 @@
<?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="configuration" Name="Configuration" Type="Configuration">
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
<Parameter Id="plcId" Name="PLC ID" Type="String" Value="plc-01"/>
<Parameter Id="plcStarted" Name="plcStarted" Type="Boolean" Value="false"/>
<Parameter Id="automaticMode" Name="automaticMode" Type="Boolean" Value="true"/>
</ParameterBag>
</Resource>
<Resource Id="plc-01" Name="PLC-01" Type="Plc">
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
<Parameter Id="connectionState" Name="Connection State" Type="String" Value="Disconnected" Interpretation="Enumeration" Uom="ConnectionState"/>
<Parameter Id="connectionStateMsg" Name="Connection State Msg" Type="String" Value=""/>
<Parameter Id="localIp" Name="Local IP" Type="StringList" Value=""/>
</ParameterBag>
</Resource>
</StrolchModel>

View File

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

View File

@ -0,0 +1,124 @@
package ${package}.server.web.components;
import static li.strolch.plc.model.PlcConstants.PARAM_PLC_ID;
import java.util.concurrent.TimeUnit;
import ${package}.server.web.service.plc.ModePlcSrvService;
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.persistence.api.StrolchTransaction;
import li.strolch.plc.gw.server.PlcGwServerHandler;
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 {
private ModePlcSrvService modePlcService;
public PostInitializer(ComponentContainer container, String componentName) {
super(container, componentName);
}
@Override
public void start() throws Exception {
registerJobs();
registerPlcServices();
notifyStart();
super.start();
}
@Override
public void stop() throws Exception {
unregisterPlcServices();
super.stop();
}
private void registerPlcServices() throws Exception {
PlcGwServerHandler plcHandler = getComponent(PlcGwServerHandler.class);
String plcId = runAsAgentWithResult(ctx -> {
try (StrolchTransaction tx = openTx(ctx.getCertificate(), true)) {
return tx.getConfiguration().getString(PARAM_PLC_ID);
}
});
if (plcId.isEmpty()) {
logger.error("No PLC ID defined on configuration! Can not start PLC Services!");
return;
}
this.modePlcService = new ModePlcSrvService(plcId, plcHandler);
this.modePlcService.register();
}
private void unregisterPlcServices() {
if (this.modePlcService != null)
this.modePlcService.unregister();
}
private void registerJobs() 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();
}
}
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,34 @@
package ${package}.server.web.json;
import static ${package}.plc.shared.SharedPlcConstants.*;
import static li.strolch.plc.model.PlcConstants.PARAM_PLC_ID;
import com.google.gson.JsonObject;
import li.strolch.model.Resource;
import li.strolch.model.json.StrolchRootElementToJsonVisitor;
import li.strolch.persistence.api.StrolchTransaction;
import li.strolch.plc.gw.server.PlcGwServerHandler;
public class JsonVisitors {
public static StrolchRootElementToJsonVisitor toJson() {
return new StrolchRootElementToJsonVisitor().withoutPolicies();
}
public static StrolchRootElementToJsonVisitor flatToJson() {
return toJson().withoutVersion().flat();
}
public static JsonObject shopFloorToJson(StrolchTransaction tx) {
Resource configuration = tx.getConfiguration();
PlcGwServerHandler plcHandler = tx.getContainer().getComponent(PlcGwServerHandler.class);
JsonObject data = new JsonObject();
data.addProperty(PARAM_AUTOMATIC_MODE, configuration.getBoolean(PARAM_AUTOMATIC_MODE));
data.addProperty(PARAM_PLC_STARTED, configuration.getBoolean(PARAM_PLC_STARTED));
data.addProperty(PARAM_PLC_CONNECTED, plcHandler.isPlcConnected(tx.getConfiguration().getString(PARAM_PLC_ID)));
return data;
}
}

View File

@ -0,0 +1,66 @@
package ${package}.server.web.rest;
import static ${package}.plc.shared.SharedPlcConstants.ROLE_SHOP_FLOOR;
import static ${package}.server.web.json.JsonVisitors.shopFloorToJson;
import static li.strolch.model.Tags.Json.DATA;
import static li.strolch.plc.model.PlcConstants.PARAM_PLC_ID;
import static li.strolch.rest.StrolchRestfulConstants.STROLCH_CERTIFICATE;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.*;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import ${package}.server.web.service.ShopFloorActionService;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import li.strolch.persistence.api.StrolchTransaction;
import li.strolch.privilege.model.Certificate;
import li.strolch.rest.RestfulStrolchComponent;
import li.strolch.rest.helper.ResponseUtil;
import li.strolch.service.JsonServiceArgument;
import li.strolch.service.api.ServiceHandler;
@Path("shopFloor")
public class ShopFloorResource {
private static String getContext() {
StackTraceElement element = new Throwable().getStackTrace()[2];
return element.getClassName() + "." + element.getMethodName();
}
private StrolchTransaction openTx(Certificate certificate) {
return RestfulStrolchComponent.getInstance().openTx(certificate, getContext());
}
@GET
@Produces(MediaType.APPLICATION_JSON)
public Response getState(@Context HttpServletRequest request) {
Certificate cert = (Certificate) request.getAttribute(STROLCH_CERTIFICATE);
try (StrolchTransaction tx = openTx(cert)) {
tx.assertHasRole(ROLE_SHOP_FLOOR);
return ResponseUtil.toResponse(DATA, shopFloorToJson(tx));
}
}
@PUT
@Path("action")
@Consumes(MediaType.APPLICATION_JSON)
public Response doAction(@Context HttpServletRequest request, String data) {
Certificate cert = (Certificate) request.getAttribute(STROLCH_CERTIFICATE);
JsonObject jsonObject = JsonParser.parseString(data).getAsJsonObject();
try (StrolchTransaction tx = openTx(cert)) {
jsonObject.addProperty(PARAM_PLC_ID, tx.getConfiguration().getString(PARAM_PLC_ID));
}
ShopFloorActionService svc = new ShopFloorActionService();
JsonServiceArgument arg = svc.getArgumentInstance();
arg.jsonElement = jsonObject;
ServiceHandler svcHandler = RestfulStrolchComponent.getInstance().getServiceHandler();
return ResponseUtil.toResponse(svcHandler.doService(cert, svc, arg));
}
}

View File

@ -0,0 +1,111 @@
package ${package}.server.web.service;
import static ${package}.plc.shared.SharedPlcConstants.*;
import static li.strolch.plc.model.PlcConstants.PARAM_PLC_ID;
import java.util.Optional;
import com.google.gson.JsonObject;
import li.strolch.model.Resource;
import li.strolch.persistence.api.StrolchTransaction;
import li.strolch.plc.gw.server.PlcGwServerHandler;
import li.strolch.plc.gw.server.PlcGwSrvI18n;
import li.strolch.plc.gw.server.service.SendPlcTelegramCommand;
import li.strolch.plc.model.PlcAddressResponse;
import li.strolch.plc.model.PlcConstants;
import li.strolch.privilege.model.SimpleRestrictable;
import li.strolch.service.JsonServiceArgument;
import li.strolch.service.api.AbstractService;
import li.strolch.service.api.ServiceResult;
import li.strolch.utils.dbc.DBC;
public class ShopFloorActionService extends AbstractService<JsonServiceArgument, ServiceResult> {
@Override
protected ServiceResult getResultInstance() {
return new ServiceResult();
}
@Override
public JsonServiceArgument getArgumentInstance() {
return new JsonServiceArgument();
}
@Override
protected ServiceResult internalDoService(JsonServiceArgument arg) {
JsonObject data = arg.jsonElement.getAsJsonObject();
String action = data.get(PlcConstants.PARAM_ACTION).getAsString();
DBC.PRE.assertNotEmpty("action must be set!", action);
Optional<ServiceResult> result;
try (StrolchTransaction tx = openArgOrUserTx(arg, false)) {
// validate that the user can do this action
tx.validateAction(new SimpleRestrictable(getPrivilegeValue(), action));
switch (action) {
case "EnableAutomaticMode" -> result = setAutomaticMode(tx, A_ON);
case "DisableAutomaticMode" -> result = setAutomaticMode(tx, A_OFF);
case "StopAll" -> result = stopAll(tx);
default -> {
tx.rollbackOnClose();
throw new IllegalArgumentException("Unexpected action " + action);
}
}
if (result.isPresent()) {
tx.rollbackOnClose();
} else if (tx.needsCommit()) {
tx.commitOnClose();
}
}
return result.orElseGet(ServiceResult::success);
}
private String getPlcId(StrolchTransaction tx) {
return tx.getConfiguration().getString(PARAM_PLC_ID);
}
protected Optional<ServiceResult> stopAll(StrolchTransaction tx) {
return assertPlcConnected(tx).or(() -> sendPlcTelegram(tx, R_STOP_ALL_ACTORS, A_NOW));
}
protected Optional<ServiceResult> setAutomaticMode(StrolchTransaction tx, String action) {
return assertPlcConnected(tx) //
.or(() -> sendPlcTelegram(tx, R_AUTOMATIC_MODE, action)) //
.or(() -> {
Resource configuration = tx.getConfiguration();
configuration.setBoolean(PARAM_AUTOMATIC_MODE, action.equals(A_ON));
tx.update(configuration);
return Optional.empty();
});
}
protected Optional<ServiceResult> assertPlcConnected(StrolchTransaction tx) {
PlcGwServerHandler plcHandler = getComponent(PlcGwServerHandler.class);
if (!plcHandler.isPlcConnected(getPlcId(tx)))
return Optional.of(ServiceResult.error("PLC " + getPlcId(tx) + " is not connected!")
.i18n(PlcGwSrvI18n.bundle, "execution.plc.notConnected", "plc", getPlcId(tx)));
return Optional.empty();
}
public static Optional<ServiceResult> sendPlcTelegram(StrolchTransaction tx, String resource, String action) {
SendPlcTelegramCommand cmd = new SendPlcTelegramCommand(tx);
cmd.setPlcId(tx.getConfiguration().getString(PARAM_PLC_ID));
cmd.setResource(resource);
cmd.setAction(action);
cmd.validate();
cmd.doCommand();
PlcAddressResponse response = cmd.getResponse();
if (response.isFailed())
return Optional.of(ServiceResult.error(response.getState() + ": " + response.getStateMsg()));
return Optional.empty();
}
}

View File

@ -0,0 +1,53 @@
package ${package}.server.web.service.plc;
import static ${package}.plc.shared.SharedPlcConstants.*;
import static li.strolch.utils.helper.ExceptionHelper.getCallerMethod;
import li.strolch.model.Resource;
import li.strolch.persistence.api.StrolchTransaction;
import li.strolch.plc.gw.server.PlcGwServerHandler;
import li.strolch.plc.gw.server.PlcGwService;
import li.strolch.plc.model.PlcAddressKey;
public class ModePlcSrvService extends PlcGwService {
public ModePlcSrvService(String plcId, PlcGwServerHandler plcHandler) {
super(plcId, plcHandler);
}
@Override
public void handleNotification(PlcAddressKey addressKey, Object value) {
run(ctx -> {
try (StrolchTransaction tx = openTx(ctx, getCallerMethod(), false)) {
Resource configuration = tx.getConfiguration();
switch (addressKey.action) {
case A_ON -> configuration.setBoolean(PARAM_AUTOMATIC_MODE, (boolean) value);
case STARTED -> configuration.setBoolean(PARAM_PLC_STARTED, true);
case STOPPED -> configuration.setBoolean(PARAM_PLC_STARTED, false);
}
logger.info(addressKey + " = " + value);
tx.update(configuration);
tx.commitOnClose();
}
});
}
@Override
public void register() {
register(R_AUTOMATIC_MODE, A_ON);
register(PLC, STARTED);
register(PLC, STOPPED);
super.register();
}
@Override
public void unregister() {
unregister(R_AUTOMATIC_MODE, A_ON);
unregister(PLC, STARTED);
unregister(PLC, STOPPED);
super.unregister();
}
}

View File

@ -0,0 +1,52 @@
package ${package}.server.web.web;
import static ${package}.server.web.web.StartupListener.APP_NAME;
import javax.ws.rs.ApplicationPath;
import java.util.logging.Level;
import ${package}.server.web.rest.ShopFloorResource;
import li.strolch.rest.RestfulStrolchComponent;
import li.strolch.rest.StrolchRestfulClasses;
import org.glassfish.jersey.logging.LoggingFeature;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.ServerProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ApplicationPath("rest")
public class RestfulApplication extends ResourceConfig {
private static final Logger logger = LoggerFactory.getLogger(RestfulApplication.class);
public RestfulApplication() {
setApplicationName(APP_NAME);
// register app rest services
register(ShopFloorResource.class);
// strolch services
for (Class<?> clazz : StrolchRestfulClasses.getRestfulClasses()) {
register(clazz);
}
// filters
for (Class<?> clazz : StrolchRestfulClasses.getProviderClasses()) {
register(clazz);
}
RestfulStrolchComponent restfulComponent = RestfulStrolchComponent.getInstance();
if (restfulComponent.isRestLogging()) {
register(new LoggingFeature(java.util.logging.Logger.getLogger(LoggingFeature.DEFAULT_LOGGER_NAME),
Level.SEVERE, LoggingFeature.Verbosity.PAYLOAD_ANY, Integer.MAX_VALUE));
property(ServerProperties.TRACING, "ALL");
property(ServerProperties.TRACING_THRESHOLD, "TRACE");
}
logger.info(
"Initialized REST application " + getApplicationName() + " with " + getClasses().size() + " classes, "
+ getInstances().size() + " instances, " + getResources().size() + " resources and "
+ getProperties().size() + " properties");
}
}

View File

@ -0,0 +1,67 @@
package ${package}.server.web.web;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
import java.io.InputStream;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.util.ContextInitializer;
import li.strolch.agent.api.StrolchAgent;
import li.strolch.agent.api.StrolchBootstrapper;
import li.strolch.utils.helper.StringHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.impl.StaticLoggerBinder;
@WebListener
public class StartupListener implements ServletContextListener {
private static final Logger logger = LoggerFactory.getLogger(StartupListener.class);
public static final String APP_NAME = "MyApp";
private StrolchAgent agent;
@Override
public void contextInitialized(ServletContextEvent sce) {
logger.info("Starting " + APP_NAME + "...");
long start = System.currentTimeMillis();
try {
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();
this.agent.start();
} catch (Throwable e) {
logger.error("Failed to start " + APP_NAME + " due to: " + e.getMessage(), e);
throw e;
}
long took = System.currentTimeMillis() - start;
logger.info("Started " + APP_NAME + " in " + (StringHelper.formatMillisecondsDuration(took)));
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
try {
new ContextInitializer((LoggerContext) StaticLoggerBinder.getSingleton().getLoggerFactory()).autoConfig();
} catch (Exception e) {
System.err.println("Failed to reconfigure logging...");
e.printStackTrace(System.err);
}
if (this.agent != null) {
logger.info("Destroying " + APP_NAME + "...");
try {
this.agent.stop();
this.agent.destroy();
} catch (Throwable e) {
logger.error("Failed to stop " + APP_NAME + " due to: " + e.getMessage(), e);
throw e;
}
}
logger.info("Destroyed " + APP_NAME);
}
}

View File

@ -0,0 +1,32 @@
<?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>
<env id="test" default="true">
<root>/absolute/path/to/runtime</root>
<environment>test</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,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.baseWsPath);
})();

View File

@ -0,0 +1,42 @@
<!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/main/c-main.html">
<style>
@font-face {
font-family: 'Ubuntu-local';
src: url(font/Ubuntu-Regular.ttf);
}
body {
margin: 0;
padding: 0;
font-family: 'Ubuntu-local', sans-serif;
font-size: 14px;
background-color: #fafafa;
}
</style>
</head>
<body unresolved>
<c-main></c-main>
</body>
</html>

View File

@ -0,0 +1,199 @@
<link rel="import" href="../../bower_components/polymer/polymer.html">
<link rel="import" href="./c-component-behavior.html">
<script>
CustomAppBehaviorImpl = {
properties: {
notifications: {
type: Array,
value: []
},
},
onClearSearchTerm: function () {
this.$$("#debouncedInput").onClearTapped();
},
_updatePageTitle: function (pageName) {
if (pageName === "${appName}" || pageName === "${appName}")
document.title = pageName;
else
document.title = "${appName}: " + (this.localize == null ? pageName : this.localize(pageName));
},
onLogOut: function () {
this.$$("#pages").logout();
sessionStorage.clear();
Strolch.clearStorageData();
this.deleteCookie("strolch.authorization");
window.location.reload();
},
reloadPage: function (pageName) {
this._updatePageTitle(pageName);
this.debounce('page-reload-' + pageName, function () {
var page = this.$$('#' + pageName);
if (page && page.reload) {
console.log('Reloading ' + pageName);
page.reload();
}
switch (pageName) {
case 'login' :
case 'inspector' :
case 'control' :
case 'operations-log' :
case 'jobs' :
case 'sessions' :
case 'users' :
case 'roles' :
case 'i18n-editor' :
case 'reports' :
this.set('toolbarConfig', {
pageTitle: pageName,
backButton: true,
hasSearchTerm: false
});
break;
default:
if (page != null && page.toolbarConfig != null) {
this.set('toolbarConfig', page.toolbarConfig);
}
}
}, 100);
},
onShowToast: function (e) {
if (this.$.toast.opened) {
this.$.toast.close();
this.async(function () {
this.toastText = e.detail.text;
this.$.toast.open();
}, 100);
} else {
this.toastText = e.detail.text;
this.$.toast.open();
}
},
onShowDialog: function (e) {
var dlgTitle;
if (e.detail.title != null)
dlgTitle = e.detail.title;
else
dlgTitle = e.detail.isError ? 'errorOccurred' : 'info';
var dlgText;
if (e.detail.text)
dlgText = e.detail.text;
else if (e.detail.message)
dlgText = e.detail.message;
else
dlgText = JSON.stringify(e.detail);
this._showDialog(dlgTitle, dlgText);
},
onShowNotification: function (e) {
console.log("Showing notification " + e.detail.id);
this.push("notifications", e.detail);
},
onClearNotification: function (e) {
console.log("Clearing notification " + e.detail.id);
for (var i = 0; i < this.notifications.length; i++) {
if (this.notifications[i].id === e.detail.id) {
this.splice("notifications", i, 1);
break;
}
}
},
onServerNotAvailable: function (event) {
clearInterval(this.checkForNewVersionInterval);
this.showInfo({
translate: true,
okLbl: 'reconnect',
title: 'serverNotAvailable',
line1: 'serverNotAvailableMsg',
cancelable: false,
callback: function (confirmed) {
if (confirmed)
this.reconnect();
}.bind(this)
});
},
onSessionInvalid: function (e) {
console.log(this.routeTail);
if (this.routeTail.prefix !== '/login') {
this.showInfo({
translate: true,
title: 'sessionInvalid',
line1: 'sessionInvalidConfirmNavToLogin',
cancelable: false,
callback: function (confirmed) {
if (!confirmed) return;
this.deleteCookie('strolch.authorization');
this.set("authTokenValid", false);
}.bind(this)
});
}
},
onPrivilegeDenied: function (e) {
if (this.authTokenValid) {
if (e.detail && e.detail.detail && e.detail.detail.request //
&& e.detail.detail.request.response //
&& e.detail.detail.request.response.i18n) {
this.showInfo({
title: 'privilegeDenied',
i18n: e.detail.detail.request.response.i18n,
translate: true
});
} else if (e.detail && e.detail.detail && e.detail.detail.request //
&& e.detail.detail.request.response //
&& e.detail.detail.request.response.exceptionMsg) {
this.showInfo({
title: 'privilegeDenied',
line1: e.detail.detail.request.response.exceptionMsg,
line2: this.requestEventToUrl(e),
translate: true
});
} else {
this.showInfo({
title: 'privilegeDenied',
line1: 'privilegeDeniedText',
line2: this.requestEventToUrl(e),
translate: true
});
}
} else {
console.warn("Privilege denied to URL " + this.requestEventToUrl(e));
this.requestErrorToMsg(e);
}
},
_showDialog: function (dlgTitle, dlgText, dlgReason) {
if (this.localize) {
var data = {
title: this.localize(dlgTitle),
line1: this.localize(dlgText)
};
if (dlgReason)
data.line1 += ": " + dlgReason;
this.$.infoDlg.open(data);
} else {
this.debounce('show-dlg', function () {
var data = {
title: this.localize(dlgTitle),
line1: this.localize(dlgText)
};
if (dlgReason)
data.line1 += ": " + dlgReason;
this.$.infoDlg.open(data);
}.bind(this), 250);
}
},
};
CustomAppBehavior = [CustomComponentBehavior, CustomAppBehaviorImpl];
</script>

View File

@ -0,0 +1,30 @@
<link rel="import" href="../../bower_components/polymer/polymer.html">
<link rel="import" href="../../bower_components/strolch-wc-util-behavior/strolch-wc-component-behavior.html">
<link rel="import" href="../../bower_components/strolch-wc-localize-behavior/strolch-wc-localize-behavior.html">
<script>
CustomComponentBehaviorImpl = {
properties: {
baseRestPath: {
type: String,
value: function () {
return CustomWeb.baseRestPath;
}
},
baseWsPath: {
type: String,
value: function () {
return CustomWeb.baseWsPath;
}
},
localesPath: {
type: String,
value: '../../../locales.json'
}
}
};
CustomComponentBehavior = [StrolchComponentBehavior, StrolchLocalizeBehavior, CustomComponentBehaviorImpl];
</script>

View File

@ -0,0 +1,202 @@
<link rel="import" href="../../bower_components/polymer/polymer.html">
<link rel="import" href="../../bower_components/iron-icons/iron-icons.html">
<link rel="import" href="../../bower_components/iron-ajax/iron-ajax.html">
<link rel="import" href="../../bower_components/app-layout/app-toolbar/app-toolbar.html">
<link rel="import" href="../../bower_components/paper-material/paper-material.html">
<link rel="import" href="../../bower_components/paper-dropdown-menu/paper-dropdown-menu.html">
<link rel="import" href="../../bower_components/paper-listbox/paper-listbox.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-icon-button/paper-icon-button.html">
<link rel="import" href="../../bower_components/strolch-wc-inspector/strolch-wc-inspector-menu.html">
<link rel="import" href="../behaviors/c-component-behavior.html">
<link rel="import" href="../styles/c-app-style.html">
<dom-module id="c-drawer">
<template>
<style is="custom-style" include="c-app-style">
:root {
}
app-drawer {
z-index: 10;
}
app-toolbar {
background-color: var(--app-primary-color);
color: var(--app-regular-highlight-fg-color);
}
paper-menu {
--paper-menu-selected-item: {
background-color: var(--app-light-highlight-bg-color);
};
--paper-menu-focused-item: {
background-color: var(--app-regular-highlight-bg-color);
};
}
paper-menu paper-item {
cursor: pointer;
}
paper-menu paper-item:hover {
background-color: var(--app-regular-highlight-bg-color);
}
.info-div {
display: block !important;
font-size: small;
color: darkgray;
}
.strolch {
color: #7f7f7f;
font-family: monospace;
font-weight: 600;
font-size: 30px;
text-shadow: 2px 2px 3px #7f7f7f;
margin: auto;
}
</style>
<app-drawer id="appDrawer">
<app-toolbar>
<paper-icon-button icon="menu" on-tap="closeDrawer"></paper-icon-button>
<div main-title>[[localize('appTitle')]]</div>
</app-toolbar>
<paper-menu id="menu" selected="{{page}}" attr-for-selected="id" on-tap="onMenuTap">
<paper-item id="shop-floor" class="menu-item">[[localize('shop-floor')]]</paper-item>
<template is="dom-if" if="[[hasPrivilege('li.strolch.report.ReportSearch')]]">
<paper-item id="reports" class="menu-item">[[localize('reports')]]</paper-item>
</template>
</paper-menu>
<template is="dom-if" if="[[hasRole('StrolchAdmin')]]">
<strolch-wc-inspector-menu selected-page="[[page]]"
on-menu-tap="onInspectorMenuTap"></strolch-wc-inspector-menu>
</template>
<paper-menu on-tap="onLogoutTapped">
<paper-item id="logout" class="menu-item">[[localize('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-item data="fr">Français</paper-item>
</paper-listbox>
</paper-dropdown-menu>
</paper-material>
<paper-material id="container" class="container" elevation="0">
<p class="strolch">${appName}</p>
</paper-material>
</app-drawer>
<!-- Ajax requests -->
<iron-ajax id="ajaxPutLocale" content-type="application/json" handle-as="json" method="PUT"></iron-ajax>
</template>
<script>
Polymer({
is: 'c-drawer',
behaviors: [
CustomComponentBehavior
],
properties: {
authTokenValid: {
type: Boolean
},
userConfig: {
type: Object,
observer: "userConfigChanged"
},
userLocale: {
type: String,
observer: "userLocaleChanged"
},
version: {
type: Object
}
},
observers: [],
listeners: {},
toggleDrawer: function () {
this.$$("#appDrawer").toggle();
},
closeDrawer: function () {
this.$$("#appDrawer").close();
},
onInspectorMenuTap: function (e) {
this.changePage(e.detail.target.id, false);
},
onMenuTap: function (e) {
this.changePage(e.detail.sourceEvent.target.id, false);
},
onLogoutTapped: function (e) {
this.fire('cx-logout');
},
userConfigChanged: function (newValue, oldValue) {
if (newValue != null) {
var userLocale = Strolch.getUserLocale();
if (userLocale !== newValue.locale) {
console.log("Updating server side locale for user " + newValue.username + " to " + userLocale);
newValue.locale = userLocale;
Strolch.setUserConfig(newValue);
this.$.ajaxPutLocale.url = this.baseRestPath + "/strolch/sessions/" + newValue.sessionId + "/locale/" + userLocale;
this.$.ajaxPutLocale.generateRequest();
}
this.userLocale = newValue.locale;
}
},
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();
}
},
/* Lifecycle */
});
</script>
</dom-module>

View File

@ -0,0 +1,268 @@
<link rel="import" href="../../bower_components/polymer/polymer.html">
<link rel="import" href="../../bower_components/iron-icons/iron-icons.html">
<link rel="import" href="../../bower_components/app-layout/app-drawer-layout/app-drawer-layout.html">
<link rel="import" href="../../bower_components/app-layout/app-drawer/app-drawer.html">
<link rel="import" href="../../bower_components/app-layout/app-toolbar/app-toolbar.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/strolch-wc-debounced-input/strolch-wc-debounced-input.html">
<link rel="import" href="../../bower_components/strolch-wc-notification/strolch-wc-notification.html">
<link rel="import" href="../../bower_components/strolch-wc-information-dialog/strolch-wc-information-dialog.html">
<link rel="import" href="../behaviors/c-app-behavior.html">
<link rel="import" href="../styles/c-app-style.html">
<link rel="import" href="../utils/c-app-routing.html">
<link rel="import" href="./c-drawer.html">
<link rel="import" href="./c-pages.html">
<dom-module id="c-main">
<template>
<style is="custom-style" include="c-app-style">
:root {
display: block;
}
app-toolbar {
background-color: var(--app-primary-color);
color: var(--app-regular-highlight-fg-color);
}
strolch-wc-debounced-input {
--focus-color: white;
--input-color: white;
--regular-color: white;
}
</style>
<!-- Routing -->
<c-app-routing id="appRouting"
login-page="login"
auth-valid="[[authTokenValid]]"
page="{{page}}"
route-tail="{{routeTail}}"
use-hash-as-path></c-app-routing>
<app-drawer-layout fullbleed force-narrow>
<template is="dom-if" if="[[authTokenValid]]">
<c-drawer id="drawer" page="[[page]]" auth-token-valid="[[authTokenValid]]" user-config="[[userConfig]]" version="[[version]]"
on-strolch-app-version-outdated="onAppVersionOutdated"></c-drawer>
<app-toolbar>
<paper-icon-button icon="menu" on-tap="toggleDrawer"></paper-icon-button>
<div main-title>[[localize(page)]]</div>
<template is="dom-if" if="[[toolbarConfig.hasSearchTerm]]">
<strolch-wc-debounced-input id="debouncedInput"
debounced-input="{{searchTerm}}"></strolch-wc-debounced-input>
</template>
</app-toolbar>
</template>
<template is="dom-repeat" items="[[notifications]]" as="notification">
<strolch-wc-notification message="[[notification.message]]"
action1="[[notification.action1]]"
action2="[[notification.action2]]"
action3="[[notification.action3]]"
callback1="[[notification.callback1]]"
callback2="[[notification.callback2]]"
callback3="[[notification.callback3]]"
bind="[[notification.bind]]"
fa-icon="[[notification.faIcon]]"></strolch-wc-notification>
</template>
<c-pages id="pages" page="[[page]]" toolbar-config="{{toolbarConfig}}" route="{{routeTail}}" search-term="[[searchTerm]]"
user-location="{{userLocation}}"></c-pages>
<paper-toast id="toast" text="[[toastText]]"></paper-toast>
<paper-toast id="newVersionAvailableToast" duration="0">
<paper-button class="refresh" on-tap="refreshBrowser">[[localize('refresh')]]</paper-button>
</paper-toast>
</app-drawer-layout>
<strolch-wc-information-dialog id="infoDlg"
locales-path="../../../locales.json"></strolch-wc-information-dialog>
<!-- Ajax requests -->
<iron-ajax id="ajaxGetAppVersion"
url="[[baseRestPath]]/strolch/version"
content-type="application/json"
handle-as="json"
method="GET"
on-response="onGetAppVersionResponse"
on-error="onGetAppVersionError"></iron-ajax>
</template>
<script>
Polymer({
is: 'c-main',
behaviors: [
CustomAppBehavior
],
properties: {
toolbarConfig: {
type: Object
},
searchTerm: {
type: String
},
page: {
type: String
},
authToken: {
type: String
},
authTokenValid: {
type: Boolean,
value: false
},
userConfig: {
type: Object
},
route: {
type: Object
},
toastText: {
type: String,
value: 'not-yet-set'
},
version: {
type: Object
}
},
observers: [],
listeners: {
"strolch-session-valid": "onSessionValidated",
"strolch-reload": "reload",
"strolch-show-toast": "onShowToast",
"strolch-server-not-available": "onServerNotAvailable",
"strolch-session-invalid": "onSessionInvalid",
"strolch-privilege-denied": "onPrivilegeDenied",
"strolch-change-page": "onPageChange",
"strolch-show-dialog": "onShowDialog",
"strolch-show-info": "onShowInfo",
"strolch-ajax-request-error": "onRequestError",
"strolch-show-notification": "onShowNotification",
"strolch-clear-notification": "onClearNotification",
"strolch-clear-search-term": "onClearSearchTerm",
"cx-logout": "onLogOut",
},
reload: function () {
this.reloadPage(this.page);
},
toggleDrawer: function () {
this.$$("#drawer").toggleDrawer();
},
closeDrawer: function () {
this.$$("#drawer").closeDrawer();
},
onPageChange: function (e) {
this.closeDrawer();
if (e && e.detail && e.detail.page) {
var pageName = e.detail.page;
// set the next page
document.title = this.localize == null ? pageName : this.localize(pageName);
this.$.appRouting.pushNextPage(pageName, e.detail.keepQueryParams);
} else {
console.log("received page change without new value");
}
},
onShowInfo: function (e) {
this.$.infoDlg.open(e.detail);
},
onSessionValidated: function () {
console.log("Session validated.");
this.set("authToken", Strolch.getAuthToken());
this.set("authTokenValid", true);
this.set("userConfig", Strolch.getUserConfig());
this.$.ajaxGetAppVersion.generateRequest();
},
onGetAppVersionResponse: function (event) {
this.version = event.detail.response;
Strolch.setAppVersion(this.version);
var artifactVersion = this.version.appVersion.artifactVersion;
var scmRevision = this.version.appVersion.scmRevision;
console.log("App Version is " + artifactVersion);
var currentVersion = sessionStorage.appScmRevision;
if (currentVersion == null //
|| currentVersion === 'undefined' //
|| scmRevision == null
|| scmRevision === 'undefined') {
sessionStorage.appScmRevision = scmRevision;
console.log("App SCM Revision is now known as " + scmRevision);
} else if (scmRevision !== currentVersion) {
console.log("App SCM Revision has changed from " + currentVersion + " to " + scmRevision + ". Need to refresh browser...");
this.fire("strolch-app-version-outdated", {newVersion: scmRevision});
this.$.newVersionAvailableToast.text = this.localize('newVersionAvailableRefreshRequired') + ": " + artifactVersion;
this.$.newVersionAvailableToast.open();
}
},
onGetAppVersionError: 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);
}
},
refreshBrowser: function () {
sessionStorage.appScmRevision = this.version.appVersion.scmRevision;
document.location.reload();
},
checkForNewVersion: function () {
this.$.ajaxGetAppVersion.generateRequest();
},
reconnect: function () {
this.onGetAppVersionResponse = function (event) {
var version = event.detail.response;
this.scmRevision = version.appVersion.scmRevision;
sessionStorage.appScmRevision = this.scmRevision;
document.location.reload();
};
this.$.ajaxGetAppVersion.generateRequest();
},
/* Lifecycle */
attached: function () {
setTimeout(function () {
this.checkForNewVersion();
}.bind(this), 5000);
this.checkForNewVersionInterval = setInterval(function () {
this.checkForNewVersion();
}.bind(this), 300000);
window.addEventListener("beforeunload", function (e) {
console.log("App SCM Revision " + sessionStorage.appScmRevision + " is cleared due to unload of UI");
delete sessionStorage.appScmRevision;
return null;
});
},
});
</script>
</dom-module>

View File

@ -0,0 +1,179 @@
<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/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-operations-log.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-inspector/strolch-wc-i18n-editor.html">
<link rel="import" href="../../bower_components/strolch-wc-reports/strolch-wc-reports.html">
<link rel="import" href="../behaviors/c-app-behavior.html">
<link rel="import" href="../styles/c-app-style.html">
<link rel="import" href="../views/c-shop-floor.html">
<link rel="import" href="../views/c-view404.html">
<dom-module id="c-pages">
<template>
<style is="custom-style" include="c-app-style">
:root {
display: block;
}
</style>
<iron-pages selected="[[selectedPage]]" attr-for-selected="id" fallback-selection="view404">
<strolch-wc-auth id="login"
app-title="[[localize('appTitle')]]"
toolbar-config="{{toolbarConfig}}"
base-path="../"
show-version
show-keep-alive></strolch-wc-auth>
<c-shop-floor id="shop-floor"
toolbar-config="{{toolbarConfig}}"
search-term="[[searchTerm]]"
base-path="../"></c-shop-floor>
<template is="dom-if" if="[[equal(page, 'inspector')]]" restamp>
<strolch-wc-inspector id="inspector"
toolbar-config="{{toolbarConfig}}"
base-path="../"
route="{{route}}"></strolch-wc-inspector>
</template>
<template is="dom-if" if="[[equal(page, 'operations-log')]]" restamp>
<strolch-wc-operations-log id="operations-log"
toolbar-config="{{toolbarConfig}}"
base-path="../"
route="{{route}}"></strolch-wc-operations-log>
</template>
<template is="dom-if" if="[[equal(page, 'jobs')]]" restamp>
<strolch-wc-jobs id="jobs"
toolbar-config="{{toolbarConfig}}"
base-path="../"
route="{{route}}"></strolch-wc-jobs>
</template>
<template is="dom-if" if="[[equal(page, 'reports')]]" restamp>
<strolch-wc-reports id="reports"
toolbar-config="{{toolbarConfig}}"
base-path="../"
base-rest-path="[[baseRestPath]]"
locales-path="../../../locales.json"
route="{{route}}"
facet-limit="[[reportFacetLimit]]"
propagate-show-dialog></strolch-wc-reports>
</template>
<template is="dom-if" if="[[equal(page, 'users')]]" restamp>
<strolch-wc-users id="users"
toolbar-config="{{toolbarConfig}}"
base-path="../"
route="{{route}}"></strolch-wc-users>
</template>
<template is="dom-if" if="[[equal(page, 'roles')]]" restamp>
<strolch-wc-roles id="roles"
toolbar-config="{{toolbarConfig}}"
base-path="../"
route="{{route}}"></strolch-wc-roles>
</template>
<template is="dom-if" if="[[equal(page, 'sessions')]]" restamp>
<strolch-wc-sessions id="sessions"
toolbar-config="{{toolbarConfig}}"
base-path="../"
route="{{route}}"></strolch-wc-sessions>
</template>
<template is="dom-if" if="[[equal(page, 'control')]]" restamp>
<strolch-wc-control id="control"
class="padded-view"
base-path="../"
base-ws-path="[[baseWsPath]]"
toolbar-config="{{toolbarConfig}}"
search-term="{{searchTerm}}"
user-location="{{userLocation}}"
route="{{routeTail}}"
propagate-show-dialog></strolch-wc-control>
</template>
<c-view404 id="view404"></c-view404>
</iron-pages>
</template>
<script>
Polymer({
is: 'c-pages',
behaviors: [
CustomAppBehavior
],
properties: {
toolbarConfig: {
type: Object,
notify: true
},
searchTerm: {
type: String
},
page: {
type: String,
observer: 'observePage'
},
selectedPage: {
type: String,
observer: 'observeSelectedPage'
},
route: {
type: Object
},
reportFacetLimit: {
type: Number,
value: function () {
return 25;
}
}
},
observers: [],
listeners: {},
observePage: function (newValue, oldValue) {
if (newValue) {
this.async(function () {
this.selectedPage = newValue;
}, 10);
}
},
observeSelectedPage: function (newValue, oldValue) {
if (newValue) {
console.log("Page changed to " + newValue + ", reloading...");
this.reloadPage(newValue);
}
},
logout: function () {
this.$$('#login').logout();
}
});
</script>
</dom-module>

View File

@ -0,0 +1,14 @@
<link rel="import" href="../../bower_components/polymer/polymer.html">
<link rel="import" href="../../bower_components/strolch-wc-styles/strolch-wc-app-style.html">
<dom-module id="c-app-style">
<template>
<style is="c-app-style" include="strolch-wc-app-style">
:root {
}
</style>
</template>
</dom-module>

View File

@ -0,0 +1,148 @@
<!-- Components -->
<link rel="import" href="../../bower_components/polymer/polymer.html">
<link rel="import" href="../../bower_components/app-route/app-location.html">
<link rel="import" href="../../bower_components/app-route/app-route.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"
},
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)"
],
computeDefaultPage: function (userConfig) {
if (userConfig == null)
return "shop-floor";
Strolch.setUserConfig(userConfig);
if (Strolch.hasRole("StrolchAdmin")) {
return "shop-floor";
} else {
return "shop-floor";
}
},
observeRouteData: function (routeData) {
// redirect to login or default if there is no page
if (!routeData.page) {
var firstPage = this.authValid ? this.computeDefaultPage(Strolch.getUserConfig()) : 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) {
// 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.computeDefaultPage(Strolch.getUserConfig()));
}
}
// 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) {
console.log("Not authenticated, navigating from page " + pathBase + " to " + this.loginPage);
// 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,190 @@
<link rel="import" href="../../bower_components/polymer/polymer.html">
<link rel="import" href="../../bower_components/iron-ajax/iron-ajax.html">
<link rel="import" href="../../bower_components/paper-card/paper-card.html">
<link rel="import" href="../../bower_components/paper-dialog/paper-dialog.html">
<link rel="import" href="../../bower_components/strolch-wc-paging/strolch-wc-paging.html">
<link rel="import" href="../styles/c-app-style.html">
<link rel="import" href="../behaviors/c-component-behavior.html">
<dom-module id="c-shop-floor">
<template>
<style is="custom-style" include="c-app-style">
:host {
display: block;
min-height: 100%;
padding-left: 20px;
padding-bottom: 20px;
}
h2 {
margin-left: 10px;
}
paper-card {
margin: 0 0 10px 10px;
padding: 0;
width: inherit;
min-width: 350px;
}
.actions {
padding: 10px;
}
.icons {
margin: 16px;
}
.icons div {
display: inline-block;
padding-right: 16px;
}
.icons iron-icon {
color: #0b8043
}
paper-dialog {
min-width: 500px;
}
.row {
display: flex;
justify-content: flex-start;
}
</style>
<div class="actions no-padding actions-right">
<paper-icon-button icon="icons:refresh" on-tap="reload"></paper-icon-button>
</div>
<h2>[[localize('plc')]]</h2>
<div class="row">
<paper-card heading="[[localize('plc')]]">
<div class="icons">
<div>
<iron-icon icon$="[[getCheckedIcon(shopFloor.plcConnected)]]"></iron-icon>
<span>[[localize('plcConnected')]]</span>
</div>
</div>
<div class="icons">
<div>
<iron-icon icon$="[[getCheckedIcon(shopFloor.plcStarted)]]"></iron-icon>
<span>[[localize('plcStarted')]]</span>
</div>
</div>
<div class="icons">
<div>
<iron-icon icon$="[[getCheckedIcon(shopFloor.automaticMode)]]"></iron-icon>
<span>[[localize('automaticMode')]]</span>
</div>
</div>
<div class="actions">
<paper-button on-tap="enableAutomaticMode" raised>[[localize('enable')]]</paper-button>
<paper-button on-tap="disableAutomaticMode" raised>[[localize('disable')]]</paper-button>
<paper-button on-tap="stopAll" raised>[[localize('stopAll')]]</paper-button>
</div>
</paper-card>
</div>
<iron-ajax id="ajaxGetState"
url="[[baseRestPath]]/shopFloor"
method="GET"
content-type="application/json"
on-response="onGetState"
on-error="onRequestError"></iron-ajax>
<iron-ajax id="ajax"
url="[[baseRestPath]]/shopFloor"
content-type="application/json"
on-response="ajaxComplete"
on-error="onRequestError"></iron-ajax>
</template>
<script>
Polymer({
is: 'c-shop-floor',
behaviors: [
CustomComponentBehavior
],
properties: {
toolbarConfig: {
type: Object,
notify: true,
readOnly: true,
value: {
hasSearchTerm: true
}
},
shopFloor: {
type: Object
}
},
getCheckedIcon: function (state) {
return state != null && state === true ? "icons:radio-button-checked" : "icons:radio-button-unchecked";
},
ajaxComplete: function () {
this.reload();
},
reload: function () {
this.$.ajaxGetState.generateRequest();
},
attached: function () {
this.poll();
},
poll: function () {
this.debounce("reload", function () {
this.reload();
this.poll();
}, 5000);
},
onGetState: function (e) {
this.shopFloor = e.detail.response.data;
},
enableAutomaticMode: function () {
this.sendTelegram("EnableAutomaticMode", "enableAutomaticMode", "enableAutomaticModeConfirm");
},
disableAutomaticMode: function () {
this.sendTelegram("DisableAutomaticMode", "disableAutomaticMode", "disableAutomaticModeConfirm");
},
stopAll: function () {
this.sendTelegram("StopAll", "stopAll", "stopAllConfirm");
},
sendTelegram: function (action, confirmTitle, confirmMsg) {
var body;
if (typeof action === "object") {
body = action;
} else {
body = {action: action};
}
this.showInfo({
title: this.localize(confirmTitle),
line1: this.localize(confirmMsg),
callback: function (confirmed) {
if (!confirmed) return;
this.$.ajax.url = this.baseRestPath + "/shopFloor/action";
this.$.ajax.method = "PUT";
this.$.ajax.body = body;
this.$.ajax.generateRequest();
}.bind(this)
});
}
});
</script>
</dom-module>

View File

@ -0,0 +1,46 @@
<link rel="import" href="../../bower_components/polymer/polymer.html">
<link rel="import" href="../styles/c-app-style.html">
<dom-module id="c-view404">
<template>
<style is="custom-style" include="c-app-style">
:host {
display: block;
min-height: 100%;
padding: 10px 20px;
}
</style>
Oops you hit a 404.
</template>
<script>
Polymer({
is: 'c-view404',
behaviors: [
CustomComponentBehavior, StrolchLocalizeBehavior
],
properties: {
toolbarConfig: {
type: Object,
notify: true,
readOnly: true,
value: {
hasSearchTerm: false
}
},
dataObj: {
type: Object
},
messages: {
type: Array
}
}
});
</script>
</dom-module>

View File

@ -0,0 +1,41 @@
{
"name": "${rootArtifactId}-web",
"authors": [
"Robert von Burg <eitch@eitchnet.ch>"
],
"private": true,
"dependencies": {
"strolchjs": "strolch-li/strolchjs#^0.5.3",
"strolch-wc-styles": "strolch-li/strolch-wc-styles#^0.4.8",
"strolch-wc-auth": "strolch-li/strolch-wc-auth#^0.9.9",
"strolch-wc-badge": "strolch-li/strolch-wc-badge#^0.1.4",
"strolch-wc-notification": "strolch-li/strolch-wc-notification#^0.1.1",
"strolch-wc-inspector": "strolch-li/strolch-wc-inspector#^0.23.6",
"strolch-wc-util-behavior": "strolch-li/strolch-wc-util-behavior#^0.3.7",
"strolch-wc-localize-behavior": "strolch-li/strolch-wc-localize-behavior#^1.1.15",
"strolch-wc-debounced-input": "strolch-li/strolch-wc-debounced-input#^0.1.6",
"strolch-wc-dialog-button": "strolch-li/strolch-wc-dialog-button#^0.1.7",
"strolch-wc-information-dialog": "strolch-li/strolch-wc-information-dialog#^0.1.14",
"strolch-wc-parameter-input": "strolch-li/strolch-wc-parameter-input#^0.1.5",
"strolch-wc-reports": "strolch-li/strolch-wc-reports#^0.5.3",
"strolch-wc-paging": "strolch-li/strolch-wc-paging#^0.1.7",
"strolch-wc-ws-observer": "strolch-li/strolch-wc-ws-observer#^0.2.11",
"strolch-wc-tree": "strolch-li/strolch-wc-tree#^0.2.6",
"polymer": "Polymer/polymer#^1.12.0",
"iron-pages": "PolymerElements/iron-pages#^1.0.9",
"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.6",
"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-toggle-button": "PolymerElements/paper-toggle-button#^1.3.0",
"paper-toast": "PolymerElements/paper-toast#^1.3.1"
},
"devDependencies": {
}
}

View File

@ -0,0 +1,93 @@
const gulp = require('gulp');
const $ = require('gulp-load-plugins')();
const merge = require('merge-stream');
const del = require('del');
// temporary until gulp 4.0 is released
const runSequence = require('run-sequence');
const vulcanize = require('gulp-vulcanize');
const minify = require('gulp-minify');
const crisper = require('gulp-crisper');
const shell = require('gulp-shell');
const rename = require("gulp-rename");
const replace = require('gulp-replace');
// 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 font = gulp.src([
'app/font/*'
])
.pipe(gulp.dest('www/font/'));
var imgs = gulp.src([
'app/img/*.svg', 'app/img/*.ico', 'app/img/*.png', 'app/img/*.gif'
])
.pipe(gulp.dest('www/img/'));
var locales = gulp.src([
'app/bower_components/**/locales.json'
])
.pipe(gulp.dest('www/bower_components/'));
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, font, imgs, locales, 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(replace('<link rel="stylesheet" type="text/css" href="https://fonts.googleapis.com/css?family=Roboto+Mono:400,700|Roboto:400,300,300italic,400italic,500,500italic,700,700italic" crossorigin="anonymous">', ''))
.pipe(replace("font-family: 'Roboto', 'Noto', sans-serif;", "font-family: 'Ubuntu-local', sans-serif;"))
.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,183 @@
{
"en": {
"agent.service.failed.access.denied": "User {user} may not perform service {service}",
"agent.query.failed.access.denied": "User {user} may not perform query {query}",
"agent.search.failed.access.denied": "User {user} may not perform search {search}",
"logout": "Logout",
"info": "Information",
"keepAlive": "Stay logged in",
"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",
"privilegeDenied": "Action denied",
"privilegeDeniedText": "The action has been denied",
"sessionInvalid": "Session Invalid",
"sessionInvalidConfirmNavToLogin": "The session has expired or is invalid. Please logon again.",
"sessionInvalidLoggingBackIn": "The session is invalid or has expired, automatic logon has commenced...",
"enabled": "Active",
"severity": "Severity",
"true": "Yes",
"false": "No",
"Info": "Information",
"Exception": "Exception",
"clearInactiveMessages": "Remove inactive messages",
"clearInactiveMessagesConfirm": "Should all inactive messages be removed?",
"errorOccurred": "An error occurred",
"systemAction.failed": "SystemAction {action} failed: {reason}",
"Created": "Created",
"Planning": "Planning",
"Planned": "Planned",
"Execution": "Execution",
"Warning": "Warning",
"Error": "Error",
"Executed": "Executed",
"Closed": "Closed",
"date": "Date",
"deleted": "Deleted",
"id": "ID",
"status": "Status",
"enable": "Enable",
"disable": "Disable",
"mode": "Mode",
"user": "User",
"i18n-editor": "Internationalization editor",
"login": "Login",
"plc": "Control",
"automaticMode": "Automatic Mode",
"plcConnected": "PLC Connected",
"plcStarted": "PLC Started",
"stopAll": "Stop All",
"stopAllConfirm": "Should all Motors be stopped?",
"enableAutomaticMode": "Enable Automatic Mode",
"enableAutomaticModeConfirm": "Should the automatic mode be enabled?",
"disableAutomaticMode": "Disable Automatic Mode",
"disableAutomaticModeConfirm": "Should the automatic mode be disabled?",
"shop-floor": "Shop-Floor"
},
"de": {
"shop-floor": "Fördertechnik",
"stopAll": "Alles Stoppen",
"stopAllConfirm": "Sollen alle Motoren gestoppt werden?",
"automaticMode": "Automatik Modus",
"disableAutomaticMode": "Automatik Modus Deaktivieren",
"disableAutomaticModeConfirm": "Soll der Automatik Modus deaktiviert werden?",
"enableAutomaticMode": "Automatik Modus Aktivieren",
"enableAutomaticModeConfirm": "Soll der Automatik Modus aktiviert werden?",
"plc": "Steuerung",
"plcConnected": "Steuerung Verbunden",
"plcStarted": "Steuerung gestartet",
"appTitle": "${appName}",
"logout": "Ausloggen",
"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",
"privilegeDenied": "Aktion verweigert",
"privilegeDeniedText": "Die Aktion wurde verweigert.",
"sessionInvalid": "Sitzung ungültig",
"sessionInvalidConfirmNavToLogin": "Die Sitzung ist abgelaufen oder ungültig. Bitte neu anmelden.",
"sessionInvalidLoggingBackIn": "Die Sitzung ist ungültig oder abgelaufen, automatische Anmeldung wird ausgeführt...",
"errorOccurred": "Ein Fehler ist aufgetreten",
"login": "Login",
"i18n-editor": "Internationalisierungs Editor",
"user": "Benutzer",
"mode": "Modus",
"enable": "Aktivieren",
"disable": "Deaktivieren",
"status": "Status",
"id": "ID",
"deleted": "Gelöscht",
"date": "Datum",
"Created": "Erstellt",
"Planning": "In Planung",
"Planned": "Geplant",
"Execution": "In Ausführung",
"Warning": "Warnung",
"Error": "Fehler",
"Executed": "Ausgeführt",
"Closed": "Geschlossen",
"keepAlive": "Eingeloggt bleiben",
"systemAction.failed": "Systembefehl {action} fehlgeschlagen: {reason}",
"enabled": "Aktiv",
"severity": "Schweregrad",
"true": "Ja",
"false": "Nein",
"Info": "Information",
"Exception": "Ausnahme",
"clearInactiveMessages": "Inaktive Meldungen entfernen",
"clearInactiveMessagesConfirm": "Sollen alle inaktive Meldungen entfernt werden?",
"executionDate": "Ausführungsdatum",
"orderDate": "Auftragsdatum",
"info": "Information",
"agent.service.failed.access.denied": "Benutzer {user} darf Service {service} nicht ausführen",
"agent.query.failed.access.denied": "Benutzer {user} darf Abfrage {query} nicht ausführen",
"agent.search.failed.access.denied": "Benutzer {user} darf Suche {search} nicht ausführen"
},
"fr": {
"shop-floor": "Système de convoyage",
"stopAll": "Arrêter tout",
"stopAllConfirm": "Les moteurs, doivent-ils être arrêtés ?",
"automaticMode": "Mode automatique",
"plcConnected": "Contrôle connecté",
"plc": "Système de contrôle",
"disableAutomaticMode": "Désactiver le mode automatique",
"disableAutomaticModeConfirm": "Voulez-vous désactiver le mode automatique?",
"enableAutomaticMode": "Activer le mode automatique",
"enableAutomaticModeConfirm": "Voulez-vous activer le mode automatique ?",
"appTitle": "${appName}",
"language": "Langue",
"reports": "Rapports",
"operations-log": "Logs",
"jobs": "Jobs",
"sessions": "Sessions",
"users": "Utilisateurs",
"roles": "Rôles",
"control": "Controle",
"inspector": "Inspecteur",
"newVersionAvailableRefreshRequired": "Une nouvelle version est disponible!",
"refresh": "Actualiser",
"close": "Fermer",
"cancel": "Annuler",
"ok": "Ok",
"reconnect": "Reconnecter",
"serverNotAvailable": "Server indisponible",
"serverNotAvailableMsg": "La connexion au serveur est indisponible",
"privilegeDenied": "Action refusée",
"privilegeDeniedText": "L'action a été refusée.",
"sessionInvalid": "Session invalide",
"sessionInvalidConfirmNavToLogin": "La session a expirée, veuillez vous reconnecter.",
"sessionInvalidLoggingBackIn": "La session a expirée, reconnexion automatiqque...",
"errorOccurred": "Une erreur s'est produite",
"agent.service.failed.access.denied": "Utilisateur {user} ne peut exécuter le service {service}",
"agent.query.failed.access.denied": "Utilisateur {user} ne peut exécuter la demande {query}",
"agent.search.failed.access.denied": "Utilisateur {user} ne peut exécuter la recherche {search}"
}
}

View File

@ -0,0 +1,37 @@
{
"name": "${rootArtifactId}-web",
"description": "${appName}",
"version": "${version}",
"private": true,
"repository": {
"type": "git",
"url": "https://github.com/strolch-li/strolch.git"
},
"author": "Robert von Burg <eitch@eitchnet.ch>",
"license": "Proprietary",
"keywords": [],
"bugs": {
"url": "https://github.com/strolch-li/strolch/issues"
},
"homepage": "https://www.strolch.li",
"devDependencies": {
"bower": "^1.8.8",
"del": "^2.2.2",
"gulp": "^3.9.1",
"gulp-crisper": "^1.1.0",
"gulp-imagemin": "^7.1.0",
"gulp-load-plugins": "^1.4.0",
"gulp-minify": "0.0.15",
"gulp-rename": "^1.2.2",
"gulp-shell": "^0.8.0",
"gulp-size": "^2.1.0",
"gulp-vulcanize": "^6.1.0",
"gulp-replace": "^1.1.3",
"merge-stream": "^1.0.0",
"run-sequence": "^1.2.2",
"vulcanize": "^1.15.3"
},
"scripts": {
"postinstall": "bower install"
}
}

View File

@ -0,0 +1,474 @@
<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>${groupId}</groupId>
<artifactId>${artifactId}</artifactId>
<packaging>pom</packaging>
<name>${artifactId}</name>
<version>${version}</version>
<description>Module build to build all projects for ${artifactId}</description>
<scm>
<!-- TODO: Change this to your SCM URL -->
<connection>scm:git:https://github.com/strolch-li/strolch.git</connection>
<developerConnection>scm:git:https://github.com/strolch-li/strolch.git</developerConnection>
<url>https://github.com/strolch-li/strolch</url>
</scm>
<properties>
<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>17</jdk.version>
<maven.compiler.source>${jdk.version}</maven.compiler.source>
<maven.compiler.target>${jdk.version}</maven.compiler.target>
<!-- compile time dependencies -->
<slf4j.version>1.7.30</slf4j.version>
<logback.version>1.2.9</logback.version>
<jersey.version>2.34</jersey.version>
<gson.version>2.8.9</gson.version>
<hikaricp.version>5.0.0</hikaricp.version>
<postgresql.version>42.4.1</postgresql.version>
<antlr.version>4.9.3</antlr.version>
<annotation.version>1.3.2</annotation.version>
<activation.version>1.1.1</activation.version>
<javaxmail.version>1.6.2</javaxmail.version>
<serverlet.version>4.0.1</serverlet.version>
<jaxrs.api.version>2.1.1</jaxrs.api.version>
<jaxrs.ri.version>2.35</jaxrs.ri.version>
<jaxb.api.version>2.3.1</jaxb.api.version>
<jaxb.core.version>2.3.0.1</jaxb.core.version>
<jaxb.impl.version>2.3.3</jaxb.impl.version>
<jaxws.version>2.3.3</jaxws.version>
<jakarta.jws-api.version>2.1.0</jakarta.jws-api.version>
<jaxp.version>1.4.2</jaxp.version>
<tyrus.version>1.17</tyrus.version>
<grizzly.version>2.4.4</grizzly.version>
<websocket.version>1.1</websocket.version>
<sax.version>2.0.1</sax.version>
<csv.version>1.9.0</csv.version>
<cron.version>1.6.2</cron.version>
<camel.version>3.14.0</camel.version>
<pi4j.version>1.4</pi4j.version>
<strolch.version>1.8.0-SNAPSHOT</strolch.version>
<strolch-plc.version>1.2.0-SNAPSHOT</strolch-plc.version>
<!-- test time dependencies -->
<junit.version>4.13.2</junit.version>
<hamcrest.version>2.2</hamcrest.version>
<!-- maven plug-in dependencies -->
<maven-scm-plugin.version>1.12.2</maven-scm-plugin.version>
<buildnumber-maven-plugin.version>3.0.0</buildnumber-maven-plugin.version>
<versions-maven-plugin.version>2.8.1</versions-maven-plugin.version>
<maven-compiler-plugin.version>3.8.1</maven-compiler-plugin.version>
<maven-source-plugin.version>3.2.1</maven-source-plugin.version>
<maven-site-plugin.version>3.10.0</maven-site-plugin.version>
<maven-eclipse-plugin.version>2.10</maven-eclipse-plugin.version>
<maven-jar-plugin.version>3.2.0</maven-jar-plugin.version>
<maven-war-plugin.version>3.3.2</maven-war-plugin.version>
<tomcat7-maven-plugin.version>2.2</tomcat7-maven-plugin.version>
<maven-javadoc-plugin.version>3.3.1</maven-javadoc-plugin.version>
<maven-deploy-plugin.version>3.0.0-M2</maven-deploy-plugin.version>
<maven-resources-plugin.version>3.2.0</maven-resources-plugin.version>
<maven-dependency-plugin.version>3.2.0</maven-dependency-plugin.version>
<maven-assembly-plugin.version>3.3.0</maven-assembly-plugin.version>
<maven-project-info-reports-plugin.version>3.1.2</maven-project-info-reports-plugin.version>
<maven-gpg-plugin.version>3.0.1</maven-gpg-plugin.version>
<nexus-staging-maven-plugin.version>1.6.12</nexus-staging-maven-plugin.version>
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
<exec-maven-plugin.version>3.0.0</exec-maven-plugin.version>
<archetype-packaging.version>3.2.0</archetype-packaging.version>
<maven-clean-plugin.version>3.2.0</maven-clean-plugin.version>
</properties>
<modules>
<module>${rootArtifactId}-shared</module>
<module>${rootArtifactId}-plc-web</module>
<module>${rootArtifactId}-web</module>
</modules>
<dependencyManagement>
<dependencies>
<!-- Base -->
<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>
<!-- my-plc-app -->
<dependency>
<groupId>${groupId}</groupId>
<artifactId>${rootArtifactId}-shared</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>${groupId}</groupId>
<artifactId>${rootArtifactId}-plc-web</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>${groupId}</groupId>
<artifactId>${rootArtifactId}-web</artifactId>
<version>${project.version}</version>
</dependency>
<!-- Strolch -->
<dependency>
<groupId>li.strolch</groupId>
<artifactId>li.strolch.bom</artifactId>
<type>pom</type>
<version>${strolch.version}</version>
<scope>import</scope>
</dependency>
<!-- PLC -->
<dependency>
<groupId>li.strolch</groupId>
<artifactId>strolch-plc-model</artifactId>
<version>${strolch-plc.version}</version>
</dependency>
<dependency>
<groupId>li.strolch</groupId>
<artifactId>strolch-plc-core</artifactId>
<version>${strolch-plc.version}</version>
</dependency>
<dependency>
<groupId>li.strolch</groupId>
<artifactId>strolch-plc-rest</artifactId>
<version>${strolch-plc.version}</version>
</dependency>
<dependency>
<groupId>li.strolch</groupId>
<artifactId>strolch-plc-gw-server</artifactId>
<version>${strolch-plc.version}</version>
</dependency>
<dependency>
<groupId>li.strolch</groupId>
<artifactId>strolch-plc-gw-client</artifactId>
<version>${strolch-plc.version}</version>
</dependency>
<dependency>
<groupId>li.strolch</groupId>
<artifactId>strolch-plc-util</artifactId>
<version>${strolch-plc.version}</version>
</dependency>
<!-- web -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>${gson.version}</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-core</artifactId>
<version>${jaxb.core.version}</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>${jaxb.impl.version}</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>${jaxb.api.version}</version>
</dependency>
<dependency>
<groupId>javax.xml</groupId>
<artifactId>jaxp-api</artifactId>
<version>${jaxp.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>${serverlet.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>jakarta.xml.ws</groupId>
<artifactId>jakarta.xml.ws-api</artifactId>
<version>${jaxws.version}</version>
</dependency>
<dependency>
<groupId>jakarta.jws</groupId>
<artifactId>jakarta.jws-api</artifactId>
<version>${jakarta.jws-api.version}</version>
</dependency>
<dependency>
<groupId>com.sun.xml.ws</groupId>
<artifactId>jaxws-rt</artifactId>
<version>${jaxws.version}</version>
<scope>runtime</scope>
<exclusions>
<exclusion>
<groupId>com.fasterxml.woodstox</groupId>
<artifactId>woodstox-core</artifactId>
</exclusion>
<exclusion>
<groupId>org.codehaus.woodstox</groupId>
<artifactId>stax2-api</artifactId>
</exclusion>
</exclusions>
</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>
<!-- 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>
<build>
<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>
<pluginManagement>
<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>
<showDeprecation>true</showDeprecation>
<showWarnings>true</showWarnings>
<compilerArgument>-Xlint:all</compilerArgument>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven-surefire-plugin.version}</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>${maven-source-plugin.version}</version>
<executions>
<execution>
<id>attach-sources-no-fork</id>
<phase>generate-sources</phase>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-site-plugin</artifactId>
<version>${maven-site-plugin.version}</version>
<configuration>
<outputEncoding>UTF-8</outputEncoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-eclipse-plugin</artifactId>
<version>${maven-eclipse-plugin.version}</version>
<configuration>
<downloadJavadocs>true</downloadJavadocs>
<downloadSources>true</downloadSources>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>${maven-jar-plugin.version}</version>
<configuration>
<archive>
<manifest>
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
<addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>${maven-javadoc-plugin.version}</version>
<executions>
<execution>
<id>attach-javadocs</id>
<phase>deploy</phase>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<!-- explicitly define maven-deploy-plugin after other to force exec
order -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<version>${maven-deploy-plugin.version}</version>
<executions>
<execution>
<id>deploy</id>
<phase>deploy</phase>
<goals>
<goal>deploy</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>${maven-dependency-plugin.version}</version>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/lib</outputDirectory>
<overWriteReleases>false</overWriteReleases>
<overWriteSnapshots>false</overWriteSnapshots>
<overWriteIfNewer>true</overWriteIfNewer>
<excludeTransitive>false</excludeTransitive>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>${maven-assembly-plugin.version}</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
<profiles>
<profile>
<id>release</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>

Some files were not shown because too many files have changed in this diff Show More