1. Introduction

This document describes best practices for developing a customized on-premise application based on edoras one. It is mainly intended for software developers, although some topics address system installation and configuration and may therefore also be of interest to system administrators.

Various topics are presented, grouped by general theme, with each topic describing a specific development task. The topics are generally independent of each other and can be read on their own without having to read the entire document. A working knowledge of the concepts underlying edoras one is required, and some topics will also require knowledge of edoras gear or some additional external technologies.

2. Obtaining the example project

Many of the examples described in this document are demonstrated in an example on-premise project. To obtain a copy of this project please contact edorasware support.

3. Overview of the example project

The example project demonstrates the following aspects of developing an on-premise application with edoras one:

  • the basic configuration needed to start edoras one based on the core dependencies. The files involved here are generally identified with bootstrap, either in the file path or filename.

  • additional customizations for a specific project (in our examples we use the fictitious domain com.acme). The files involved here are generally identified with acme, either in the file path or filename.

4. Creating a clean skeleton project

The example project is pre-packaged with example services, listeners etc. already in the project. If you need a bare project for your own development you can strip out all of this additional example code:

  • obtain the example project

  • go to the project root folder

  • execute the following Gradle command on the command line:

Create the skeleton project on Mac/Linux
  ./gradlew createSkeletonProject
Create the skeleton project on Windows
  gradlew.bat createSkeletonProject

The project will then be a clean skeleton project.

5. Setting up a development environment

Developing on-premise applications with edoras one is fairly straightforward if you are familiar with standard Java development workflows:

  • create a new project using a build tool (e.g. Maven or Gradle)

  • include the edoras one artifacts in your project as normal dependencies

  • provide the basic configuration needed to start edoras one

  • extend edoras one by adding your own configurations and / or classes as required

This section describes setting up your development environment and including edoras one into your project. The following sections describe the edoras one extension points and how they can be used to customize edoras one and integrate it into your IT infrastructure.

5.1. Configuring the build system

5.1.1. Basic project build information

The example project provides build configurations for both the Maven and Gradle build systems. You can use whichever build system you prefer. For the Maven build Maven 3.0.0 or greater is required. The Gradle build is based on the Gradle wrapper and downloads the appropriate version automatically.

You can download the build tools here:

Basic Maven configuration

The project information and compiler version (Java 7 is required) should be set in the Maven pom.xml:

Project information in pom.xml
  <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>com.edorasware.one</groupId>
          <artifactId>edoras-one-bootstrap</artifactId>
          <version>1.0.0</version>
          <packaging>war</packaging>
Compiler configuration in pom.xml
  <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-compiler-plugin</artifactId>
      <version>3.1</version>
      <configuration>
          <source>1.7</source>
          <target>1.7</target>
      </configuration>
  </plugin>

You should also configure the resource encoding to avoid warnings during the build:

Resource configuration in pom.xml
  <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-resources-plugin</artifactId>
      <version>2.6</version>
      <configuration>
          <encoding>UTF-8</encoding>
      </configuration>
  </plugin>
Basic Gradle configuration

First you need to apply the war plugin and define the project information:

Project information in build.gradle
  apply plugin: 'war'
  
  allprojects {
    group = 'com.edorasware.one'
    version = '1.0.0'
  }

5.1.2. Artifact repository configuration

To build the project you will need access to a Maven repository containing the edoras one artifacts so that the edoras one dependencies can be resolved. The artifacts can either be uploaded to a repository manually, or if you have access to the edorasware public repository then the connection details may be configured into your local repository and artifacts will be downloaded from edorasware automatically when they are needed.

After adding the edoras one artifacts to your repository you will also need to provide a suitable repository configuration and access credentials.

Maven repository configuration

The Maven repository configuration will typically be located in the pom.xml file. The following snippet shows the configuration for the edoras repository. The configuration for your local repository will look similar.

Repository configuration in pom.xml for Maven builds
  <repositories>
      <repository>
          <id>repo.edorasware.com</id>
          <url>https://repo.edorasware.com/edoras-repo</url>
      </repository>
  </repositories>
  
  <pluginRepositories>
      <pluginRepository>
          <id>repo.edorasware.com</id>
          <url>https://repo.edorasware.com/edoras-repo</url>
      </pluginRepository>
  </pluginRepositories>

Add the repository credentials to the servers section in your local Maven configuration file. By default you can find the Maven configuration file at <USER_HOME>/.m2/settings.xml.

Add this block to the settings file
  <servers>
      <server>
          <id>repo.edorasware.com</id>
          <username>customer-username</username>
          <password>customer-password</password>
      </server>
  </servers>

Additional details of how to configure a Maven repository can be found on the Maven project page.

Gradle repository configuration

The Gradle repository configuration will typically be located in the build.gradle file. The following snippet shows the configuration for the edoras repository. The configuration for your local repository will look similar.

Repository configuration in build.gradle for Gradle builds
  repositories {
    maven {
      credentials {
        username DOWNLOAD_REPO_USERNAME
        password DOWNLOAD_REPO_PASSWORD
      }
      url "https://repo.edorasware.com/edoras-repo"
    }
    mavenCentral()
  }

Add the credentials that you received from edorasware to your local gradle.properties file. By default you can find the Gradle configuration file at <USER_HOME>/.gradle/gradle.properties.

Add this block to the gradle.properties file
  DOWNLOAD_REPO_USERNAME=customer-username
  DOWNLOAD_REPO_PASSWORD=customer-password

5.1.3. edoras one dependency configuration

The edoras one artifacts can now be added to the project as a dependency.

Maven dependency configuration

By adding a property to the <properties> tag of the Maven pom.xml file the edoras one version can be set in a single place:

edoras one version property in the Maven pom.xml
  <properties>
      <com.edorasware.one.version>@projectVersion@</com.edorasware.one.version>
  </properties>

This property can then be used in the dependency configuration to import the required dependencies:

edoras one dependencies in the Maven pom.xml
  <!-- Compile dependencies -->
  <dependency>
      <groupId>com.edorasware.one</groupId>
      <artifactId>edoras-one-client</artifactId>
      <version>${com.edorasware.one.version}</version>
  </dependency>
  
  <dependency>
      <groupId>com.edorasware.one</groupId>
      <artifactId>edoras-one-server-rest</artifactId>
      <version>${com.edorasware.one.version}</version>
      <exclusions>
          <!-- TODO fix for https://issues.apache.org/jira/browse/BATIK-1038 -->
          <exclusion>
              <groupId>org.apache.xmlgraphics</groupId>
              <artifactId>batik-extensions</artifactId>
          </exclusion>
      </exclusions>
  </dependency>
  
  <dependency>
      <groupId>com.edorasware.one</groupId>
      <artifactId>edoras-one-server-test</artifactId>
      <version>${com.edorasware.one.version}</version>
      <scope>test</scope>
  </dependency>
  
  <dependency>
      <groupId>com.edorasware.one</groupId>
      <artifactId>edoras-one-server-core</artifactId>
      <classifier>test</classifier>
      <version>${com.edorasware.one.version}</version>
      <scope>test</scope>
  </dependency>
  
  <dependency>
      <groupId>com.edorasware.license</groupId>
      <artifactId>edoras-license-one</artifactId>
      <classifier>development</classifier>
      <version>1.0.4</version>
  </dependency>
Gradle dependency configuration

By adding a property to the <properties> tag of the Gradle build.gradle file the edoras one version can be set in a single place:

edoras one version property in the Gradle build.gradle
  def edorasOneVersion = '@projectVersion@'

This property can then be used in the dependency configuration to import the required dependencies:

edoras one dependencies in the Gradle build.gradle
  compile "com.edorasware.one:edoras-one-client:$edorasOneVersion"
  compile("com.edorasware.one:edoras-one-server-rest:$edorasOneVersion") {
    //TODO fix for https://issues.apache.org/jira/browse/BATIK-1038
    exclude group: 'org.apache.xmlgraphics', module: 'batik-extensions'
  }
  
  testCompile "com.edorasware.one:edoras-one-server-test:$edorasOneVersion"
  testCompile "com.edorasware.one:edoras-one-server-core:$edorasOneVersion:test"
  testRuntime "com.edorasware.license:edoras-license-one:1.0.4:development"

5.1.4. Database dependency configuration

In addition to the edoras one dependencies, at least one database dependency is also required. For convenience the build configurations from the example project already contain dependencies for some commonly-used databases:

Database dependencies in pom.xml for Maven builds
  <dependency>
      <groupId>com.h2database</groupId>
      <artifactId>h2</artifactId>
      <version>1.3.168</version>
  </dependency>
Database dependencies in build.gradle for Gradle builds
  compile "com.h2database:h2:1.3.168"

5.1.5. Logging dependency configuration

edoras one uses the Simple Logging Facade for Java (SLF4J) for logging. SLF4J is a framework that allows the end user to plug in the desired logging framework at deployment time. You can learn more about slf4j on the {slf4j-page}.

Maven dependency configuration

By adding a property to the <properties> tag of the Maven pom.xml file the slf4j version can be set in a single place:

Logging version property in the Maven pom.xml
  <org.slf4j.version>1.7.7</org.slf4j.version>

This property can then be used in the dependency configuration to import the required dependencies. The following dependencies instruct SLF4J to send all logging output from components used in edoras one to slf4j:

Basic logging dependencies in pom.xml for Maven builds
  <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>jul-to-slf4j</artifactId>
      <version>${org.slf4j.version}</version>
  </dependency>
  
  <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>jcl-over-slf4j</artifactId>
      <version>${org.slf4j.version}</version>
  </dependency>
  
  <dependency>
      <artifactId>commons-logging</artifactId>
      <groupId>commons-logging</groupId>
      <version>1.1.3</version>
      <scope>provided</scope>  <!-- globally replace commons-logging with jcl-over-slf4j -->
  </dependency>

A suitable adapter can then be configured to send the slf4j output to a particular logging system. In the bootstrap project we use log4j, so we include the slf4j-to-log4j adapter:

Logging adapter in pom.xml for Maven builds
  <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-log4j12</artifactId>
      <version>${org.slf4j.version}</version>
  </dependency>
Gradle dependency configuration

By adding a property to the <properties> tag of the Gradle build.gradle file the slf4j version can be set in a single place:

Logging version property in the Gradle build.gradle
  def slf4jVersion = '1.7.12'

This property can then be used in the dependency configuration to import the required dependencies. The following dependencies instruct SLF4J to send all logging output from components used in edoras one to slf4j:

Basic logging dependencies in the Gradle build.gradle
  runtime "org.slf4j:jul-to-slf4j:$slf4jVersion"
  runtime "org.slf4j:jcl-over-slf4j:$slf4jVersion"
  
  // globally replace commons-logging with jcl-over-slf4j
  providedRuntime "commons-logging:commons-logging:1.1.3"

A suitable adapter can then be configured to send the slf4j output to a particular logging system. In the bootstrap project we use log4j, so we include the slf4j-to-log4j adapter:

Logging adapter in the Gradle build.gradle
  runtime "org.slf4j:slf4j-log4j12:$slf4jVersion"

5.2. Configuring edoras one

edoras one is configured using Spring. For details of the Spring project, please refer to the Spring project page.

The starting point for the Spring configuration is defined in the web.xml file that is deployed with the application. This will typically contain the location of the root Spring configuration file and the default profiles that will be used:

webapp/WEB-INF/web.xml
  <!-- Spring context configuration -->
  <context-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath*:/com/edorasware/acme/config/acme-context.xml</param-value>
  </context-param>
  
  <context-param>
      <param-name>spring.profiles.default</param-name>
      <param-value>database-h2,integration-development,security-basic</param-value>
  </context-param>

The majority of the necessary Spring configuration is provided by the edoras one artifacts and can be reused by an on-premise project, but a small amount of configuration is required for each specific installation.

To configure the on-premise project you will need to provide a Spring application context configuration, for example:

com/edorasware/bootstrap/config/one-application-context.xml
  <?xml version="1.0" encoding="UTF-8"?>
  <beans xmlns="http://www.springframework.org/schema/beans"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns:context="http://www.springframework.org/schema/context"
         xsi:schemaLocation="http://www.springframework.org/schema/beans
                             http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
                             http://www.springframework.org/schema/context
                             http://www.springframework.org/schema/context/spring-context.xsd">
  
      <context:property-placeholder
              location="classpath:/com/edorasware/bootstrap/config/one.properties,file:/${user.home}/.edoras-one/one.properties"
              system-properties-mode="OVERRIDE"
              ignore-resource-not-found="true"/>
  
      <!-- configure JUL-SLF4J rerouting as Activiti logs to Java Util Logging API -->
      <bean id="julReroute"
            class="com.edorasware.commons.core.util.logging.JulToSlf4jBridgeHandlerInstaller"
            init-method="init"/>
  
      <!-- import the edoras one, edoras vis and edoras cmmn context -->
      <import resource="classpath*:/config/one-core-application-context.xml"/>
      <import resource="classpath:/com/edorasware/vis/config/vis-application-context.xml"/>
  
      <!-- import the database configuration -->
      <import resource="classpath:/com/edorasware/bootstrap/config/database-config.xml"/>
  
      <!-- import the security configuration -->
      <import resource="classpath:/com/edorasware/bootstrap/config/security/*-config.xml"/>
  
      <!-- import the integration configuration -->
      <import resource="classpath:/com/edorasware/bootstrap/config/integration-config.xml"/>
  
      <!-- import the content configuration -->
      <import resource="classpath:/com/edorasware/bootstrap/config/content-config.xml"/>
  
  </beans>

In this configuration, the properties are read in using application defaults (provided by the on-premise WAR file) and can be overridden by system properties.

The files one-core-application-context.xml and vis-application-context.xml are provided by edoras one and contain the default edoras one Spring configuration.

The remaining imports are provided by the example on-premise project and contain the configuration for the database connection, security context, basic integration services and the content provider. These configurations are described separately.

The application context can naturally contain any additional Spring configuration needed by the on-premise implementation. The one-application-context.xml can also be included in a project-specific configuration file to improve readability and maintainability (see com/edorasware/acme/config/acme-context.xml in the example project).

5.2.1. Database configuration

In the example project, the database is configured in the com/edorasware/bootstrap/config/database-config.xml file, which is loaded from the classpath:

com/edorasware/bootstrap/config/database-config.xml
  <?xml version="1.0" encoding="UTF-8"?>
  <beans xmlns="http://www.springframework.org/schema/beans"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://www.springframework.org/schema/beans
                             http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">
  
      <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
          <property name="dataSource" ref="dataSource"/>
      </bean>
  
      <beans profile="database-h2">
          <bean id="h2HikariConfig" class="com.zaxxer.hikari.HikariConfig">
              <property name="poolName" value="edorasOnePool"/>
              <property name="connectionTestQuery" value="SELECT 1"/>
              <property name="driverClassName" value="org.h2.Driver"/>
              <property name="jdbcUrl" value="${h2Url}"/>
              <property name="username" value="sa"/>
              <property name="password" value=""/>
              <property name="connectionTimeout" value="30000"/>
              <property name="idleTimeout" value="30000"/>
              <property name="maxLifetime" value="1800000"/>
              <property name="maximumPoolSize" value="4"/>
          </bean>
  
          <bean id="dataSource" class="org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy">
              <property name="targetDataSource">
                  <bean class="com.zaxxer.hikari.HikariDataSource" destroy-method="close">
                      <constructor-arg name="configuration" ref="h2HikariConfig"/>
                  </bean>
              </property>
          </bean>
      </beans>
  
      <beans profile="database-jndi">
          <bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
              <property name="jndiName" value="${databaseJndiName}"/>
          </bean>
      </beans>
  
  </beans>

The active database is selected using a Spring profile which should be set when the application is started.

If you want to externalize the database properties then they can be added to the com/edorasware/bootstrap/config/one.properties properties file.

5.2.2. Security configuration

The application security is configured by files in the folder com/edorasware/bootstrap/config/security. Standard configurations are provided for basic authentication (security-basic-config.xml):

com/edorasware/bootstrap/config/security/security-basic-config.xml
  <?xml version="1.0" encoding="UTF-8"?>
  <beans xmlns="http://www.springframework.org/schema/beans"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns:security="http://www.springframework.org/schema/security"
         xsi:schemaLocation="http://www.springframework.org/schema/beans
                             http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
                             http://www.springframework.org/schema/security
                             http://www.springframework.org/schema/security/spring-security-3.2.xsd">
  
      <import resource="security-config-base.xml"/>
  
      <security:http pattern="/login.html" security="none"/>
      <security:http pattern="/login-error.html" security="none"/>
  
      <security:http pattern="/rest/documents/*/content">
          <security:intercept-url pattern="/**" access="ROLE_USER"/>
          <security:custom-filter ref="browserRedirectionFilter" position="FIRST"/>
          <security:session-management session-fixation-protection="none"/>
          <security:custom-filter ref="sessionManagementFilter" position="SESSION_MANAGEMENT_FILTER"/>
          <security:http-basic/>
          <security:logout/>
      </security:http>
  
      <security:http>
          <security:intercept-url pattern="/**" access="ROLE_USER"/>
          <security:custom-filter position="SWITCH_USER_FILTER" ref="switchUserProcessingFilter"/>
          <security:intercept-url pattern="/j_spring_security_switch_user" access="ROLE_USER"/>
          <security:custom-filter ref="browserRedirectionFilter" position="FIRST"/>
          <security:session-management session-fixation-protection="none"/>
          <security:custom-filter ref="sessionManagementFilter" position="SESSION_MANAGEMENT_FILTER"/>
          <security:http-basic/>
          <security:logout/>
          <security:form-login login-page="${application.endpoint}/login.html"
                               default-target-url="${application.endpoint}/"
                               always-use-default-target="true"
                               authentication-failure-url="${application.endpoint}/login-error.html"/>
      </security:http>
  
      <bean id="sessionManagementFilter"
            class="org.springframework.security.web.session.SessionManagementFilter">
          <constructor-arg name="securityContextRepository"
                           ref="httpSessionSecurityContextRepository"/>
          <property name="invalidSessionStrategy">
              <bean class="com.edorasware.cloud.security.CloudInvalidSessionStrategy">
                  <constructor-arg name="invalidSessionUrl" value="${application.endpoint}/login.html"/>
              </bean>
          </property>
      </bean>
  
      <bean id="httpSessionSecurityContextRepository" class="org.springframework.security.web.context.HttpSessionSecurityContextRepository"/>
  
      <bean id="browserRedirectionFilter" class="com.edorasware.cloud.filter.BrowserRedirectionFilter">
          <property name="loginPageUrlPattern" value="${application.endpoint}/login.html(.*)"/>
          <property name="landingPageUrlPattern" value="${application.endpoint}(.*)"/>
      </bean>
  
      <!-- default authentication manager which uses the default one user details service to get
      the user work objects. The passwords are also encoded with the default password encoder -->
      <security:authentication-manager>
          <security:authentication-provider user-service-ref="userDetailsService">
              <security:password-encoder ref="passwordEncoder"/>
          </security:authentication-provider>
      </security:authentication-manager>
  
  </beans>

In the example root configuration file (com/edorasware/bootstrap/config/one-application-context.xml), the security configuration is imported with the help of the security.type system property which defaults to basic. If you want to create your own security configuration you need to set the security.type property (e.g. to extended) and then create a corresponding security configuration file inside the com/edorasware/bootstrap/config/security folder (e.g. security-extended-config.xml).

5.2.3. Integration configuration

The integration of edoras one with external systems is configured in the file com/edorasware/bootstrap/config/integration-context.xml:

com/edorasware/bootstrap/config/integration-config.xml
  <?xml version="1.0" encoding="UTF-8"?>
  <beans xmlns="http://www.springframework.org/schema/beans"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://www.springframework.org/schema/beans
                             http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">
  
      <beans profile="integration-development">
          <bean id="mailSender" class="com.edorasware.cloud.core.mail.LoggingMailSender"/>
      </beans>
  
      <beans profile="integration-production">
          <bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
              <property name="host" value="${mail.smtp.host}"/>
              <property name="port" value="${mail.smtp.port}"/>
              <property name="username" value="${mail.smtp.username}"/>
              <property name="password" value="${mail.smtp.password}"/>
              <property name="defaultEncoding" value="${mail.smtp.encoding}"/>
              <property name="javaMailProperties">
                  <props>
                      <prop key="mail.debug">${mail.smtp.debug}</prop>
                      <prop key="mail.transport.protocol">${mail.smtp.transport.protocol}</prop>
                      <prop key="mail.smtp.auth">${mail.smtp.auth}</prop>
                      <prop key="mail.smtp.socketFactory.port">${mail.smtp.port}</prop>
                      <prop key="mail.smtp.socketFactory.class">javax.net.ssl.SSLSocketFactory</prop>
                      <prop key="mail.smtp.socketFactory.fallback">false</prop>
                      <prop key="mail.smtp.quitwait">false</prop>
                  </props>
              </property>
          </bean>
      </beans>
  
  </beans>

This example uses two Spring profiles to define the mail sender bean which is used to send emails.

Details of specific integration options and how they can be configured are provided in the relevant sections of this document.

5.2.4. Content configuration

The storage of file content in edoras one is configured in the file com/edorasware/bootstrap/config/content-config.xml:

com/edorasware/acme/config/content-config.xml
  <?xml version="1.0" encoding="UTF-8"?>
  <beans xmlns="http://www.springframework.org/schema/beans"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns:mongo="http://www.springframework.org/schema/data/mongo"
         xsi:schemaLocation="http://www.springframework.org/schema/beans
                             http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
                             http://www.springframework.org/schema/data/mongo
                             http://www.springframework.org/schema/data/mongo/spring-mongo.xsd">
  
      <!-- configure the content provider -->
      <bean id="contentProvider"
            class="com.edorasware.cloud.core.content.internal.FileBasedContentProvider">
          <constructor-arg value="${fileBasedContentProvider.contentDir}"/>
          <constructor-arg value="${contentProvider.tempDir}"/>
          <constructor-arg value="2"/>
      </bean>
  
      <beans profile="cloud">
          <mongo:db-factory
                  id="mongoDbFactory"
                  host="${mongo.host}"
                  port="${mongo.port}"
                  dbname="${mongo.dbname}"
                  username="${mongo.username}"
                  password="${mongo.password}"/>
          <mongo:mapping-converter id="mongoConverter"/>
  
          <bean class="org.springframework.data.mongodb.gridfs.GridFsTemplate">
              <constructor-arg ref="mongoDbFactory"/>
              <constructor-arg ref="mongoConverter"/>
          </bean>
  
          <bean id="contentProvider" class="com.edorasware.acme.patch.MongoDbContentProvider"/>
      </beans>
  
  </beans>

This example stores content using a file-based content provider by default, or can be overridden using a Spring profile to use MongoDB-based content storage.

5.3. Tenant initialization

To use edoras one, you also need to create a tenant. An edoras one installation may support multiple tenants using a single database, where each tenant is completely isolated from the others (i.e. it has it’s own set of users, work objects, Apps etc.).

On startup, edoras one looks for tenant JSON configuration files in the locations configured by the tenant.data.location property. If a configuration file is found for a tenant not already present in the database then that tenant will be initialised according to the tenant configuration file:

Tenant initialization in acme.json
  {
      "name": "acme",
  
      "accounts": [
          {
              "name": "acme",
              "domain": "acme.com",
              "groups": [ "Manager" ],
              "users": [
                  {
                      "firstName": "John",
                      "lastName": "Smith",
                      "login": "john",
                      "email": "john.smith@acme.com",
                      "memberGroups": [ "Manager" ],
                      "language": "en"
                  }
              ]
          }
      ]
  }

Once a tenant is initialised it will not be updated, even if the tenant configuration file is changed at a later date.

For a full description of the tenant JSON format, please refer to the edoras one administration guide.

5.4. Logging configuration

In the bootstrap project, we are using log4j as the logging framework. The default logging configuration for log4j is provided by the log4j.properties file in the root package.

Default logging configuration in log4j.properties
  # Comment this line and uncomment the following to allow log writing to a local file
  log4j.rootLogger=INFO, A
  # log4j.rootLogger=INFO, A, local.file
  
  log4j.appender.A=org.apache.log4j.ConsoleAppender
  
  log4j.appender.A.layout=org.apache.log4j.PatternLayout
  log4j.appender.A.layout.ConversionPattern=%d{ISO8601} %-5p %-85.85c - %m%n
  
  ## Spring framework
  #log4j.logger.org.springframework=WARN
  #log4j.logger.org.springframework.integration=DEBUG
  
  ## Spring web
  #log4j.logger.org.springframework.web=DEBUG
  
  ## Project
  #log4j.logger.com.edorasware.customer.acme=DEBUG
  
  log4j.appender.local.file=org.apache.log4j.FileAppender
  log4j.appender.local.file.append=false
  log4j.appender.local.file.file=/tmp/edoras.log
  log4j.appender.local.file.threshold=INFO
  log4j.appender.local.file.layout=org.apache.log4j.PatternLayout
  log4j.appender.local.file.layout.ConversionPattern=%-5p %c: %m%n

If an alternative logging configuration is needed in a given environment, this can be specified without rebuilding the WAR file by setting the appropriate system property when the application server is started, for example by adding -Dlog4j.configuration=file:C:/tmp/log4j.properties to the application server command line.

5.5. Property settings

The default property settings are defined in the one.properties file located in the com/edorasware/bootstrap/config folder.

Installation-specific property values can be set using system properties, for example by adding them to the application server command line.

For a full description of the standard edoras one properties, please refer to the edoras one administration guide.

5.6. edoras vis configuration

The edoras vis configuration is optional as the defaults should be sufficient for most project. If you still need to change the palette or adapt the edoras vis editor then please read on.

5.6.1. Palette configuration

Palette configuration should be added into the project’s Spring configuration as shown below.

  <bean id="paletteConfiguration" class="com.edorasware.bpm.modeler.config.PaletteConfiguration">
      <property name="paths">
          <list>
              <value>classpath:com/edorasware/vis/palette</value>
          </list>
      </property>
      <property name="baseProcessPalette" value="classpath:com/edorasware/vis/palette/base.process.palette.xml"/>
      <property name="baseFormPalette" value="classpath:com/edorasware/vis/palette/base.form.palette.xml"/>
      <property name="baseCasePalette" value="classpath:com/edorasware/vis/palette/base.case.palette.xml"/>
      <property name="defaultProcessPaletteName" value="default.process.palette.xml"/>
      <property name="defaultFormPaletteName" value="default.form.palette.xml"/>
      <property name="defaultCasePaletteName" value="default.case.palette.xml"/>
  </bean>
Table 1. Supported palette configuration bean properties
Name Description

paths

List of palette folder paths

baseProcessPalette

Fully qualified base process palette file name

baseFormPalette

Fully qualified base form palette file name

baseCasePalette

Fully qualified base case palette file name

defaultProcessPaletteName

Fully qualified default process palette file name

defaultFormPaletteName

Fully qualified default form palette file name

defaultCasePaletteName

Fully qualified default case palette file name

5.6.2. Editor configuration

Editor configuration should be added into the project’s Spring configuration as shown below.

  <bean id="editorConfiguration" class="com.edorasware.bpm.modeler.config.EditorConfiguration">
      <property name="disableSaveDialog" value="true"/>
      <property name="showSystemFormPalette" value="false"/>
      <property name="showSystemProcessPalette" value="false"/>
      <property name="showSystemCasePalette" value="false"/>
      <property name="saveNotificationUrl" value="../rest/modeler"/>
  </bean>
Table 2. Supported editor configuration bean properties
Name Description

disableSaveDialog

Flag to enable or disable showing the save dialog for each save operation

showSystemFormPalette

Flag to show/hide system form palette in the form designer

showSystemProcessPalette

Flag to show/hide system process palette in the process designer

showSystemCasePalette

Flag to show/hide system case palette in the case designer

saveNotificationUrl

URL to which the save notification will be posted

5.7. License file

To start edoras one you will need a valid edoras one license file. The license location is configured in the one.properties file located in the com/edorasware/bootstrap/config folder.

com/edorasware/bootstrap/config/one.properties
  edorasware.license = file:${user.home}/.edorasware/edorasware.license

5.8. Build and deploy the on-premise WAR file

The project WAR file can now be build using the Maven package target or the Gradle war task. The generated war can then be deployed in a suitable application server.

5.9. Developing with Eclipse

This section guides you through the basic setup needed to develop edoras one on-premise projects using the Eclipse IDE. It assumes that you have a copy of the edoras one bootstrap project and have access to the edorasware repository.

If you plan to use the project for real development then you should place the project under some form of source control (e.g. Git or Subversion) before importing it into the IDE and making your own modifications. This will not be covered here.

5.9.1. Add the edoras repository credentials to your Maven configuration

All artifacts required to build and run your edoras one are available in the edoras repository. This repository is usually configured in the POM of your edoras one bootstrap project. The only missing information is the repository access credentials. Add the credentials that you received from edorasware to the servers section in your local Maven configuration file. By default you can find the Maven configuration file at <USER_HOME>/.m2/settings.xml.

    ...
    <servers>
        ...
        <server>
            <id>repo.edorasware.com</id>
            <username>customer-username</username>
            <password>customer-password</password>
        </server>
        ...
    </servers>
    ...

5.9.2. Install Eclipse

Download an appropriate package for your system from the Eclipse project page and install it in a suitable location.

5.9.3. Start Eclipse

Start the installed Eclipse and select or create a workspace:

createWorkspace

5.9.4. Configure the Java runtime

edoras one runs inside an application server and requires larger memory settings than the ones that are available by default in a Java VM. In the following steps we change the memory settings to a suitable value.

Select the WindowPreferences menu item to open the Preferences dialog. Choose the Installed JREs preferences in the Java section. Select the default JRE (that is the one highlighted in bold) and press the Edit…​ button to show the Edit JRE dialog. Add the option -XX:MaxPermSize=128M to the Default VM arguments text field. This increases the maximum permanent generation size to a value that is sufficient for edoras one.

javaMaxPermSize

5.9.5. Import the bootstrap project into your workspace

Select the FileImport…​ menu item to open the project import dialog. Then select Existing Maven Projects:

importMavenProject

Then select the folder where you have extracted the bootstrap project:

importProject

5.9.6. Configure an application server

edoras one is deployed to standard Servlet 3.0 web application servers. The following shows how to integrate the Tomcat 7.0 web application server into Eclipse. Please refer to the Tomcat installation guide to learn how to install Tomcat in your local environment.

Integration of other application servers is done in a similar way.

When you have installed Tomcat to a local directory, select the FileNewOther…​ menu item to open the Select a Wizard dialog. Choose the Server option in the Server section and press the Next button.

serverSelectWizard

In the Define a New Server page of the wizard, choose the Tomcat 7.0 Server type and press the Next button.

serverSelectServerType

In the Tomcat Server page of the wizard, press the Browse…​ button and choose the home directory of your installed Tomcat web application server.

Press the Finish button to create the application server inside Eclipse.

serverDefineTomcatServer

Select the WindowShow ViewServers menu item. This brings you to the Servers view.

serverServersView

Double click the Tomcat 7.0 Server option to open the editor for that server. Change the timeouts in the Timeouts section: change Start to 450 seconds and Stop to 150 seconds. This is required as it takes the application server some time to start up and stop edoras one and the default settings are too small.

serverSetTimeouts

Switch to the Modules tab by clicking the Modules label at the bottom of the editor. In the Modules tab press the Add Web Module…​ button to open the Add Web Module dialog. Choose your project module and press the OK button to deploy your project into the application server.

serverAddWebModule

When you have added the web module, you can change the deployment path by editing the table entry (setting the path when creating the web module does not currently work). Change your deployment path to '/acme' and select the FileSave All menu item to save your changes.

5.9.7. Start the application server

Select the application server in the Servers view and press the Start the server toolbar button.

serverStart

Congratulations, you now have started your edoras one application!

Direct your browser to http://localhost:8080/acme and enjoy!

5.10. Developing with IntelliJ IDEA

This section guides you through the basic setup needed to develop edoras one on-premise projects using the IntelliJ IDEA IDE. It assumes that you have a copy of the edoras one bootstrap project and have access to the edorasware repository.

If you plan to use the project for real development then you should place the project under some form of source control (e.g. Git or Subversion) before importing it into the IDE and making your own modifications. This will not be covered here.

5.10.1. Add the edoras repository credentials to your Maven configuration

All artifacts required to build and run your edoras one are available in the edoras repository. This repository is usually configured in the POM of your edoras one bootstrap project. The only missing information is the repository access credentials. Add the credentials that you received from edorasware to the servers section in your local Maven configuration file. By default you can find the Maven configuration file at <USER_HOME>/.m2/settings.xml.

    ...
    <servers>
        ...
        <server>
            <id>repo.edorasware.com</id>
            <username>customer-username</username>
            <password>customer-password</password>
        </server>
        ...
    </servers>
    ...

5.10.2. Install IntelliJ IDEA

Download an appropriate package for your system from the IntelliJ IDEA project page and install it in a suitable location.

5.10.3. Start IntelliJ IDEA

Start the installed IntelliJ IDEA.

5.10.4. Import the bootstrap project into your workspace

Either select Import project from the IDEA start screen, or use the FileOpen…​ menu item from an existing project.

Select the Maven pom.xml (or Gradle build.gradle) from the folder where you extracted the bootstrap project:

importProject

You may see some information dialogs that alternative build files have been detected. These dialogs may be safely ignored.

5.10.5. Check the project language level

Open the project settings dialog with FileProject Structure…​ and check that the Project language level is set to 7:

languageLevel

5.10.6. Configure an application server

edoras one is deployed to standard Servlet 3.0 web application servers. The following shows how to integrate the Tomcat 7.0 web application server into IDEA. Please refer to the Tomcat installation guide to learn how to install Tomcat in your local environment.

Integration of other application servers is done in a similar way.

When you have installed Tomcat to a local directory, select the RunEdit Configurations…​ menu item to open the run configuration dialog:

runConfiguration

Select the + icon to add a new run configuration, and then select Tomcat ServerLocal.

Give the run configuration a suitable name (e.g. bootstrap), and configure the installed Tomcat application server using the Configure…​ button.

bootstrapRunConfiguration

Add the bootstrap deployment artifact by selecting the Deployment tab and adding the deployment artifact edoras-one-bootstrap:war exploded:

deployArtifact

When it has been added, you can change the Application context setting to /acme by selecting the artifact in the deployment list.

5.10.7. Start the application server

Select the bootstrap run configuration from the selection widget in the IDEA toolbar, and then press the green arrow to the right to start the server.

runServer

Congratulations, you now have started your edoras one application!

Direct your browser to http://localhost:8080/acme (if it has not been opened automatically) and enjoy!

6. Customizing edoras one

This section describes the extension points for common on-premise use cases. If no suitable extension point is documented for a feature that you require then contact edorasware support to find a solution.

6.1. Overriding edoras one bean definitions

The default edoras one Spring bean configurations can be overridden if a new Spring bean is defined with the same ID after the base configuration has been imported (if two bean definitions have the same ID then the last definition wins).

6.2. Action event listeners

Custom work object action event listeners can be added to the edoras one configuration by creating the action listener implementation and then registering it as a bean with a bean ID that matches the following pattern:

customer{First|Last}{Task|Case|Process|WorkObject}ActionListener

customerFirst listeners will be invoked before all other listeners, customerLast listeners will be invoked after all other listeners.

Note
If more than one listener is required, then the listeners can be combined using a composite action listener (Composite{Task|Case|Process|WorkObject}ActionListener) and the composite listener registered using the above naming convention.

As an example, a listener to log the creation of new task objects can be defined:

LoggingTaskActionListener.java
  package com.edorasware.acme.listeners;
  
  import com.edorasware.gear.core.task.support.TaskActionEvent;
  import com.edorasware.gear.core.task.support.TaskActionListener;
  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;
  
  public class LoggingTaskActionListener implements TaskActionListener {
      private static final Logger LOG = LoggerFactory.getLogger(LoggingTaskActionListener.class);
  
      @Override
      public void actionWillBePerformed(TaskActionEvent event) {
          if (event.isCreationEvent()) {
              LOG.info("About to create task {}", event.getNewTask().getId());
          }
      }
  
      @Override
      public void actionPerformed(TaskActionEvent event) {
          if (event.isCreationEvent()) {
              LOG.info("Created task {}", event.getNewTask().getId());
          }
      }
  }

and then the bean can be defined with a suitable ID to register it with the task service:

acme-context.xml
  <bean id="customerLastTaskActionListener"
        class="com.edorasware.acme.listeners.LoggingTaskActionListener"/>

For details on action listener implementation, please refer to the edoras gear documentation.

6.3. Automatic App updates

When a new tenant is initialized an App called the System App is automatically installed. This App contains the models required for correct operation of the edoras one software, and is typically loaded from the edoras one artifacts as it is strongly tied to a specific edoras one release.

NOTE

It is strongly recommended that the System App be updated automatically to make sure that the latest version is active after the edoras one dependency has been updated to a newer version (which may also include a new System App).

Section [_app_development_workflow] describes how to configure workflows to support transfer of Apps between systems with automatic updates, and the section [_incoming_adapter_lifecycle] describes how the pre-defined system app adapter can be configured to perform automatic updates of the System App. :acme-root-dir: ../../../edoras-one-bootstrap/ :acme-src-dir: ../../../edoras-one-bootstrap/src/main/

6.4. Expressions and service beans

The powerful expression resolver used in the edoras one server supports access to arbitrary Spring bean property values and methods. This capability can be used in on-premise projects to integrate custom Java code with process models via expressions: service beans can be written in Java and registered with the expression resolver, and the appropriate methods can then be invoked from a process model at the appropriate time. There are many potential ways to use this capability, but some typical use cases might be:

  • data initialization

  • data conversion

  • encapsulation of complex business logic

  • integration with external systems

6.4.1. Defining service beans

Service beans are simply plain Java objects registered as a Spring bean with a particular ID.

As an example, if we want to create a service to generate new task names, we can create the Java class:

TaskNameService.java
  package com.edorasware.acme.expression;
  
  import org.activiti.engine.delegate.DelegateExecution;
  
  import java.util.UUID;
  import java.util.concurrent.atomic.AtomicInteger;
  
  /**
   * An example service bean that allows UUID strings to be created from a process model.
   */
  public class TaskNameService {
  
      private static AtomicInteger taskCount = new AtomicInteger();
  
      /**
       * Returns a new task name based on the given base name.
       *
       * @param baseName the base name
       * @return the task name
       */
      public String nextTaskName(String baseName) {
          return baseName + "-" + taskCount.incrementAndGet();
      }
  }

and use this to create a corresponding Spring bean with a suitable ID, either explicitly:

acme-context.xml
  <bean id="taskNameService"
        class="com.edorasware.acme.expression.TaskNameService"/>

or by adding an appropriate Spring annotation (e.g. @Service) to the class definition and enabling the Spring component scan for the relevant package:

acme-context.xml
  <!-- Scan the project-specific classes to locate REST controllers etc. -->
  <context:component-scan base-package="com.edorasware.acme"/>

To allow open access to all available Spring beans from a process definition would be a big security problem, so edoras one only allows the expression resolver to access a limited set of beans. These beans are defined by the expression.bean.whitelist property. To allow access to the bean that we have defined we therefore have also to override the default value of this property to include the new bean ID:

`com/edorasware/bootstrap/config/one.properties
  # Allows beans to be resolved in the expression resolver.
  # CAUTION: this means that methods may be executed on the bean from
  # user-provided expressions, so watch out for security loopholes!
  expression.bean.whitelist = convert2PdfActivityExecutor,documentActivityExecutor,\
    mailActivityService,processVariables,restVariableService,date,caseActivityExecutor,\
    commentService,identityManager,modelManager,taskNameService,acmeService

6.4.2. Accessing service beans

Once the bean has been defined and made accessible, it can be used by expressions within process definitions. As an example we can use the taskNameService bean to generate task names for user tasks:

serviceBean

6.4.3. Passing values using method parameters

The simplest way to pass values to a service bean method is to simply use the expression to provide the relevant values to the method call. We used this approach in the previous example when we passed in the name of the parent case:

Method invocation with method parameters
  #{taskNameService.nextTaskName(case.name)}

This approach has a number of advantages:

  • the input values are modeled, and it is therefore relatively easy for the modeler to understand what is happening

  • the same method may be used in different contexts where the source values come from different places

  • changes to variable names can be made without affecting running processes (old processes will continue to use the old variable name)

It works well for simple utility function when only a few parameters are required, but as the number of parameters increases, the method invocations become complex and therefore awkward to write and maintain.

6.4.4. Passing values using the execution context

For more complex use cases, an alternative is to provide the current Activiti execution context as a parameter to the service task method and allow the method itself to extract the information it needs and make any changes that may be required. When doing this, it is useful to extend the AbstractActivityService class, as this provides a number of useful utility methods for working with execution context, such as locating the current work object. The following example service uses the execution context to add a message to a variable in the root work object:

AcmeService.java
  /**
   * An example service bean that uses an execution context.
   */
  @Service
  public class AcmeService extends AbstractActivityService {
  
      // type-safe variable definition for the service message
      private static final VariableName<String, String> SERVICE_MSG =
              VariableName.create("serviceMsg", String.class);
  
      @Autowired
      private GenericWorkObjectService workObjectService;
  
      /**
       * Adds a service invocation message to the root work object.
       *
       * @param execution the execution context
       */
      public void invoke(DelegateExecution execution) {
          WorkObject<?, ?, ?> workObjectInScope = getWorkObjectInScope(execution);
          AnyWorkObject rootObject = getRootObject(workObjectInScope);
  
          WorkObjectUpdate.Builder<?, ?, ?, ?, ?> updateBuilder =
                  this.workObjectService.createUpdateBuilder(rootObject.getGlobalId());
  
          String message = "AcmeService was invoked at " + getTimestamp()
                  + " with tag " + getTag(execution);
  
          updateBuilder.putVariable(SERVICE_MSG, message);
  
          this.workObjectService.apply(updateBuilder.build(), "ACME service invocation");
      }
  
      /**
       * Returns the value of the tag property in the task definition.
       *
       * @param execution the execution context
       * @return the value of the tag property
       */
      private String getTag(DelegateExecution execution) {
          Map<String, String> properties = getCurrentTaskStringProperties(execution);
          String value = properties.get("edoras:tag");
          return hasText(value) ? value : "UNDEFINED";
      }
  
      /**
       * Returns a string with the current timestamp.
       *
       * @return the current timestamp
       */
      private String getTimestamp() {
          DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm");
          return dateFormat.format(new Date());
      }
  }

The execution context is passed into the method call by using the execution keyword within the expression:

Method invocation with execution context
  #{acmeService.invoke(execution)}

This approach delegates full control to the service implementation, allowing it to navigate the work object hierarchy to read or modify whatever it needs to. Obviously, this is very powerful, but it also means that the values used by the method are not visible to the modeler, making it hard to see what is really going on. It is therefore important to try to make the behaviour as intuitive as possible and to provide good documentation for the available services to the modelers.

As the data used by the implementation is coded in Java rather then being part of the model, it is also more complicated to change the way that values are stored in the work object hierarchy. Any change to the values used by the service will take effect immediately for all processes that use that service in the future, including processes that are already running.

6.4.5. Managing database transactions in service beans

Service bean method invocations are typically executed from within a process. The process engine already manages the transactions used during process execution, and so no additional transaction handling needs to be provided by service bean implementations.

6.4.6. Security

As service beans have access to the full functionality of Java and edoras one, it is also important that security is considered when creating a new service bean implementation. Users should not be able to use a service bean to gain access to confidential information to which they would not otherwise have access, to corrupt or delete information, or to interfere with the normal functioning of edoras one.

6.4.7. Creating custom service tasks in the process palette

We have already seen how service beans can be invoked using expressions. When specific service beans are used on a regular basis, it may be convenient to extend the process palette in the process modeler to include customized service tasks for common use cases.

Details of how to customize the process palette can be found in the section Customizing palettes.

As an example, we start by creating a patch to the default edoras one process palette (thereby reusing all of the existing palette configuration):

acme.process.palette.xml
  <palette id="acme-process-palette"
           resource-bundle="translation"
           apply-patch-to-palette="edoras-one-process-palette"
           xmlns="http://www.edorasware.com/schema/vis/process-palette"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.edorasware.com/schema/vis/process-palette
                               http://www.edorasware.com/schema/vis/edoras-vis-process-palette-2.0.43.xsd">
  
      <!-- palette configuration... -->
  </palette>

To make our custom tasks easy to find, we will create a separate group to contain them:

acme.process.palette.xml
  <group id="acme-tasks">
      <component id="acmeservicetask" extends="ServiceTask"
                 attribute-groups="acmeServiceTaskAttributes"/>
  </group>

In the process modeler, this group is now added to the existing ones:

acme group

We can then define the attributes that should appear when the service task is edited. For our example, we will provide a default name and background color, set the expression to invoke the service (not visible in the modeler), define a new tag attribute, and suppress some of the additional service task attributes that are not needed:

acme.process.palette.xml
  <attribute-groups>
      <attribute-group id="acmeServiceTaskAttributes">
  
          <!-- Provide suitable default values for base attributes -->
          <attribute category="common" id="name" type="SimpleText"
                     value="ACME service task"
                     readonly="false" optional="true"
                     ref-to-view="text_name"/>
          <attribute id="bgcolor" category="common" type="Color"
                     value="#ccffcc" index="190"
                     readonly="false" optional="false"
                     ref-to-view="fill_el" fill="true" stroke="false"/>
  
          <!-- use a fixed expression to invoke the service -->
          <attribute id="expression" category="edoras" type="SimpleText"
                     value="#{acmeService.invoke(execution)}"
                     readonly="true" optional="false" visible="false"/>
  
          <!-- add a custom attribute that we can access in the service -->
          <attribute id="tag" category="edoras" type="SimpleText"
                     value="default" export="true"
                     readonly="false" optional="false"/>
  
          <!-- suppress attributes that aren't needed -->
          <attribute id="delegateExpression" category="edoras" type="SimpleText"
                     value=""
                     readonly="false" optional="true" visible="false"/>
          <attribute id="resultVariable" category="edoras" type="SimpleText"
                     value=""
                     readonly="false" optional="true" visible="false"/>
          <attribute id="class" category="edoras" type="SimpleText"
                     value=""
                     readonly="false" optional="true" visible="false"/>
  
      </attribute-group>
  </attribute-groups>

Note that the tag attribute is marked as 'exported', meaning that it will be added to the final task definition as a property, where it can be accessed by the service bean. The resulting definition property key has the edoras: prefix to avoid possible collisions with other properties used in the process engine.

The display strings used in the modeler are supplied by the corresponding resource bundle, allowing them to be translated:

translation.properties
  acme-tasks.title = ACME tasks
  acmeservicetask.title = ACME service task
  acmeServiceTaskAttributes.tag.title = Tag
  acmeServiceTaskAttributes.tag.description = Tag

When we add the custom task to a process in the modeler, we can see that the default attribute values are applied, and that some of the normal service task attributes are no longer available:

acme attributes

6.5. REST services

REST controller classes in edoras one are defined as plain Java classes annotated with the standard Spring Web annotations:

ReferenceDataController.java
  /**
   * Controller that provides basic application reference data.
   */
  @Controller
  @RequestMapping(value = "/referencedata")
  public final class ReferenceDataController {
      // ...
  }

The individual REST endpoints are defined within a REST controller using annotations on the endpoint implementation methods. For example, the following method defines a REST endpoint for the GET HTTP request method, with the URL /referencedata/domains (the concatenation of the class and method request mappings). It also supports the optional typedText request parameter and returns a list of domains which will be encoded in JSON format:

ReferenceDataController.java
  /**
   * Look up domains that match the given typed text.
   *
   * @param typedText the text typed (usually from an auto-complete field)
   * @return a list of matching domains with an OK response code
   */
  @RequestMapping(value = "domains", method = RequestMethod.GET)
  @ResponseBody
  public ResponseEntity<List<Domain>> getDomains(
          @RequestParam(required = false) String typedText)
  {
      LOG.debug("Requesting domains for '{}'", typedText);
  
      List<Domain> domains = this.referenceDataManager.getDomains(typedText);
  
      return new ResponseEntity<>(domains, RestUtils.JSON_HTTP_HEADERS, HttpStatus.OK);
  }

To activate the REST service controller, you can either declare it explicitly as a bean in the Spring configuration, or use a Spring component scan to automatically locate annotated beans in a given package:

acme-context.xml
  <!-- Scan the project-specific classes to locate REST controllers etc. -->
  <context:component-scan base-package="com.edorasware.acme"/>

In both cases, the REST endpoints defined by the REST controller will be published under the path '/rest' relative to the edoras one base URL. So if the main edoras one application is accessible under the URL http://localhost:8080/acme, the domains endpoint shown above will be accessible under http://localhost:8080/acme/rest/referencedata/domains.

6.5.1. Managing database transactions in REST services

edoras one uses Spring Transaction Management to manage transactions.

If your REST controller methods access a database then you should add the appropriate Spring transaction annotations so that Spring can correctly manage the transactions. You can either add the annotations to the REST controller methods directly, or to classes invoked by the REST controller. Wherever the annotations are added, it is important that the scope of the annotated methods is sufficient, so that multiple database operations will be grouped correctly within a single transaction.

As an example, the REST controller for the reference data service delegates calls to a ReferenceDataManager implementation:

DatabaseReferenceDataManager.java
  /**
   * Manages reference data using persistent database storage.
   */
  public class DatabaseReferenceDataManager implements ReferenceDataManager {
  
      @Override
      @Transactional(readOnly = true)
      public List<Domain> getDomains(String typedText) {
          // ...
      }
  
      // ...

Note that only the database-driven implementation needs to be annotated in this way. The alternative StaticReferenceDataManager implementation used for testing is driven by static data and therefore does not need any transaction annotations.

6.5.2. Supporting edoras form REST-based widgets

The REST APIs needed to support specific form widgets in edoras one are described in detail in the edoras one Modeler Guide.

The Dynamic Link Button widget requires a REST endpoint with a specific response (see the edoras one Modeler Guide for details). To simplify the implementation of REST endpoints to support this widget, a Java class is provided that directly supports this response (NavigationResponse):

NavigationController.java
  import com.edorasware.bootstrap.rest.util.NavigationResponse;
  import com.edorasware.one.permission.view.ViewName;
      // ...
  
      /**
       * Create a navigation response for the next (oldest) task.
       *
       * @return the navigation response or NOT_FOUND if no task is available
       */
      @RequestMapping(value = "nextTask", method = RequestMethod.GET)
      @ResponseBody
      public ResponseEntity<NavigationResponse> getNextTask() {
          LOG.debug("Requesting next task navigation");
  
          TaskQuery query = TaskQuery.builder()
                  .predicate(Task.STATE.isActive())
                  .sorting(Task.CREATION_TIME.orderDesc())
                  .limit(1)
                  .build();
  
          Task task = this.taskService.findTask(query);
          if (task == null) {
              return new ResponseEntity<>(HttpStatus.NOT_FOUND);
          }
  
          NavigationResponse response = NavigationResponse.get(task, ViewName.BROWSE);
          return new ResponseEntity<>(response, RestUtils.JSON_HTTP_HEADERS, HttpStatus.OK);
      }

6.6. Other project-specific Spring beans

Any project-specific Spring beans can also be configured directly in the application context (or in a file that is included by the application context). For example we can configure a ReferenceDataManager instance:

acme-context.xml
  <bean class="com.edorasware.acme.services.referencedata.internal.StaticReferenceDataManager">
      <constructor-arg>
          <bean class="com.edorasware.cloud.core.config.DerivedStringListFactoryBean">
              <property name="sourceString" value="Switzerland,Swaziland,Spain"/>
          </bean>
      </constructor-arg>
  </bean>

This can be injected automatically where it is needed, for example into a reference data REST controller.

7. Customizing palettes

edoras vis allows the palette used to design processes, forms and cases to be customized. One or more customized palettes of form, process or case widgets can be created by extending the generic widgets supported by edoras vis. Once created, each custom palette can be associated with one or more models of the appropriate type. When a custom palette has been associated with a model all the widgets from the palette will be available in the appropriate editor view.

A custom form palette has to be configured in an XML file that has the .form.palette.xml file extension. It should conform to the edoras-vis-form-palette XML schema definition.

A custom process palette has to be configured in an XML file that has the .process.palette.xml file extension. It should conform to the edoras-vis-process-palette XML schema definition.

A custom case palette has to be configured in an XML file that has the .case.palette.xml file extension. It should conform to the edoras-vis-case-palette XML schema definition.

7.1. Configuring palette locations

edoras vis can be configured with multiple locations containing the palette definitions for a workspace. To configure additional palette locations the paletteConfiguration bean will need to be overwritten with an updated paths property:

modeler-config.xml
  <!-- configure the modeler palettes -->
  <bean id="paletteConfiguration" class="com.edorasware.bpm.modeler.config.PaletteConfiguration">
      <property name="paths">
          <list>
              <value>classpath:com/edorasware/vis/palette</value>
              <value>classpath:com/edorasware/acme/palette</value>
          </list>
      </property>
  
      <property name="baseProcessPalette"
                value="classpath:com/edorasware/vis/palette/base.process.palette.xml"/>
      <property name="baseFormPalette"
                value="classpath:com/edorasware/vis/palette/base.form.palette.xml"/>
      <property name="baseCasePalette"
                value="classpath:com/edorasware/vis/palette/base.case.palette.xml"/>
      <property name="defaultProcessPaletteName"
                value="default.process.palette.xml"/>
      <property name="defaultFormPaletteName"
                value="default.form.palette.xml"/>
      <property name="defaultCasePaletteName"
                value="default.case.palette.xml"/>
  </bean>

Palette locations may be specified either with classpaths as shown here, or with absolute filesystem paths. Classpath locations simplify deployment but mean that palette changes will need to be deployed by rebuilding the deployment artifact. Filesystem locations may be system-specific but would allow palettes to be updated without rebuilding the deployment artifact. The latter may be especially useful in a development environment where palettes are being modified regularly.

All of the custom palette XMLs located directly under the configured folder will be available and can be associated with an edoras vis model. One model can only be associated with one custom palette configuration.

If a custom palette XML is deleted or if any of its custom widgets are deleted, the widgets in models associated with that custom palette will automatically fallback to their respective generic widget parent(s) when the models are subsequently opened for editing.

7.2. Configuring a custom palette

The root element of a custom palette XML file supports the following attributes:

Table 3. Attributes and elements supported by the palette element
Name Mandatory Description

id

true

Id of the palette.

title

false

The title of custom palette that is displayed in edoras vis editor view.

parent-palette

false

The parent palette from which a custom palette is extended.

edoras vis supports following parent process palettes:

  • edoras-gear (default value)

  • bpmn2.0

edoras vis supports following parent form palette:

  • edoras-forms (default value)

hide-parent-palette-elements

false

The boolean value to hide stencils of the parent palette. Defaults to true.

apply-patch-to-palette

false

The name of a palette to be patched. The contents of the named palette will be modified / extended instead of a new palette being created.

resource-bundle

false

Resource Bundle File containing language specific translations. All resource bundle files should be placed under an i18n directory in the same directory as the palette XML file. Refer to Defining resource keys for language specific attributes in custom palette for more details.

See Sample custom palette for an example.

7.2.1. Defining widget groups in a custom palette

edoras vis supports grouping of widgets within custom palettes.

Table 4. Attributes supported by the group element
Name Mandatory Description

id

true

Unique Id of the group

title

false

Title of the group

description

false

Description of the group

index

false

Index of the group, Sorted in ascending order

Sample group element is shown below.

<group id="Events" title="Events" description="Events description" index="5" >
    <component id="events_start" extends="StartNoneEvent"
               attribute-groups="commonAttributes, formControlAttributes"/>
    <component id="events_end" extends="EndNoneEvent" description="End Event">
        <attribute id="custom_event_attribute" title="Custom Event Attribute" value="custom"/>
    </component>
</group>

7.2.2. Defining widgets in a custom palette

edoras vis supports creating of custom widgets in a custom palette by extending/referencing available generic widgets.

To add a widget to the custom palette, a widget element has to be added to the group element.

The widget element in turn may contain one or more attribute elements which define the widget specific properties.

Table 5. Attributes supported by the widget element
Name Mandatory Description

id

true

Unique Id of the widget

title

false

Title of the widget

description

false

Description of the widget

visible

false

Configure visibility of the widget in editor.

extends

false

Id of the widget that is extended

ref

false

Id of the widget that is referenced

roles

false

Comma separated list of roles supported by the widget, Which are inturn used by rules. See Defining rules in a custom palette for more details.

attribute-groups

false

Comma separated list of attribute group id that need to be added to the widget. See Defining attribute groups in a custom palette for more details.

presentation-id

false

Presentation reference required to render the widget SVG/Image on the editor canvas. See [defining-custom-component-presentation-in-a-custom-palette] for more details.

default-lane-id

false

Applicable only for Pool type.Configure default lane Id for a pool.

shortcut-menu-index

false

Applicable only for Process palette. Configure index for short cut menus from process widgets.

index

false

Index of the widget, sorted in ascending order

behaviour-type

false

Applicable only for Form palette. Describes the behaviour of the referred widget.

1. Widget extending StartNoneEvent with attribute-groups:
<component id="events_start" extends="StartNoneEvent" attribute-groups="commonAttributes, formControlAttributes" ></component>

2. Widget extending Task with custom widget-presentation and short cut menu index:
<component id="formtask" extends="Task" presentation-id="presentation.task" shortcut-menu-index="1" ></component>

3. Widget referencing EndNoneEvent with a custom attribute and index:
<component id="events_end" description="End Event" ref="EndNoneEvent" index="5">
    <attribute id="custom_event_attribute" title="Custom Event Attribute" value="custom"/>
</component>

4. Widget behaving like a password widget:
<component id="base-password" extends="component" presentation-id="password.presentation" behaviour-type="Password" />

7.2.3. Defining custom categories in a custom palette

edoras vis supports defining of custom categories for attributes. These categories can be used to display the attributes of a widget under different headings in the property window of the editor view.

Table 6. Attributes supported by the category element
Name Mandatory Description

id

true

Unique Id of the category

title

false

Title of the category

index

false

Index of the category. It decides the position of category in property window

visible

false

Boolean value to hide the attributes category in property window

Sample custom-categories element is shown below.

<custom-categories>
    <category id="custom_category_1" index = "101" title="custom category 1(en)" />
    <category id="custom_category_2" title="custom category 2(en)"/>
    <category id="custom_category_3" title="custom category 3(en)" visible="false"/>
</custom-categories>

Sample application of custom categories to attributes is shown below.

<attribute id="namekey"  value=""   type="SimpleText" category= "custom_category_1" />
<attribute id="name" title="Name" description="Name" value="" type="SimpleText" category="custom_category_2"/>
<attribute id="behavior" type="ComboBox" category= "custom_category_1"  index="3" title="behavior">
    <items>
        <item id="none" title="none" value="none" />
        <item id="all" title="all" value="all" />
        <item id="one" title="one" value="one" />
        <item id="complex" title="complex" value="complex" />
    </items>
</attribute>

7.2.4. Defining attributes in a custom palette

edoras vis supports defining custom attributes in the custom palette configuration.

To add an attribute with in custom palette, an attribute element has to be used. This element can only exist with in any of the following parent elements:

  • attribute-group

  • custom-attributes-group

  • model-attributes

  • component

Table 7. Attributes supported by the attribute element
Name Mandatory Description

id

true

Unique identifier of the attribute

title

false

Title of the attribute

description

false

Description of the attribute

value

false

Value of the attribute

type

false

Type of the attribute. Check Attribute types supported in a custom palette for more details.

category

false

Name of the category under which the attribute should be displayed in the property window of editor view.

export

false

Boolean value to specify whether an attribute should be exported to the xml and json(only for forms).

index

false

Integer value to define position of the attribute in the property window of the editor view.

ref-to-view

false

Id of the SVG element to which attribute value is mapped. Know more ref-to-view

readonly

false

Boolean value to make the attribute readonly.

optional

false

Boolean value to make the attribute mandatory.

visible

false

Boolean value to make the attribute visible in the property window.

filter

false

Applicable only for TreeView type. A comma separated list of file extensions. Know more filter

multilanguage

false

Boolean value to specify whether the attribute supports multilanguage. Know more multilanguage

fill

false

Applicable only for Color type. Know more fill

url

false

Applicable only for RestComboBox type.

stroke

false

Applicable only for Color type.

multiselect

false

Applicable only for RestComboBox type.

constant

false

Boolean value to make attribute value as constant.

length

false

Integer value to support maximum length for value.

popular

false

Boolean value to make attribute to has higher priority while displaying.

field-map

false

Applicable only for RestComboBox type. To map item display-name and value returned in the REST end point’s response.

item-icon-visible

false

Applicable only for RestComboBox type. To make each item’s icon visible.

select-all

false

Applicable only for RestComboBox type. To pre-select all the items returned by the REST end.

custompalette

false

Applicable only for TreeView type. To provide name of the palette for default selection in tree view editor’s drop-down list.

model-id

false

Applicable only for TreeView type.

runtime

false

Applicable for all type attributes. To make run time attribute visible. Know more runtime and runtime-value

runtime-value

false

Provide default value to run time attribute. Know more runtime and runtime-value

readonly-editor

false

Applicable only for RestComplex and Complex type. To provide non editable editor.

placeholder

false

Applicable only for TreeView type.

output-mapping

false

Applicable only for complex editor type.

edoras vis support multiple languages.

Table 8. Language specific attributes supported by the attribute element
Name Mandatory Description

title

false

If title is Resource bundle key, Then title will be picked form resource bundle file.

description

false

If description is Resource bundle key, Then description will be picked form resource bundle file

value

false

If value is Resource bundle key, Then value will be picked form resource bundle file

7.2.5. Defining resource keys for language specific attributes in custom palette

edoras vis supports defining language specific for custom attributes/widgets in the custom palette configuration.

edoras vis follows below format while generating translation keys.

Table 9. Tranlation keys for supported elements
Element Translation Key Format

Component

Component supports title and description as language specific property

<component-id>.title
<component-id>.description

Group

Group supports title and description as language specific property

<group-id>.title
<group-id>.description

Attribute

Attribute support only title, description and value as language specific property

If attribute element is within the widget element then the format of key is

<component-id>.<attribute-id>.title
<component-id>.<attribute-id>.description
<component-id>.<attribute-id>.value

If attribute element is within the attribute-goup element then the format of key is

<attribute-group-id>.<attribute-id>.title
<attribute-group-id>.<attribute-id>.description
<attribute-group-id>.<attribute-id>.value

If attribute element is within the custom-attributes-goup element then the format of key is

<custom-attributes-group-id>.<attribute-id>.title
<custom-attributes-group-id>.<attribute-id>.description
<custom-attributes-group-id>.<attribute-id>.value

If attribute element is within the model-attributes element then the format of key is

<model-attributes-id>.<attribute-id>.title
<model-attributes-id>.<attribute-id>.description
<model-attributes-id>.<attribute-id>.value

Category

Category support only title as language specific property

<category-id>.title

7.2.6. Defining validation rules for attributes in a custom palette

edoras vis supports defining validation rules for custom attributes in the custom palette configuration.

edoras vis supports following validation rules.

Table 10. Validation rules
Rule Description Example

Range

This rule can be applied to integer attributes to specify minimum and maximum allowed values.

<attribute id="cCardCvv" type="Integer"  title="Credit Card CVV" description="Credit Card CVV" optional="false">
    <validation-rules>
        <range min="100" max="999" />
    </validation-rules>
</attribute>

Length

This rule can be applied to specify the minimum and maximum length of value.

<attribute id="cCard" type="SimpleText"  title="Credit Card Number" description="Credit Card Number" optional="false">
    <validation-rules>
        <length min="0" max="16" />
    </validation-rules>
</attribute>

Expression

This rule can be applied to validate value against JavaScript expression.

<attribute id="cCard" type="SimpleText"  title="Credit Card Number" description="Credit Card Number" optional="false">
    <validation-rules>
        <expression pattern="^4[0-9]{12}(?:[0-9]{3})?$" />
    </validation-rules>
</attribute>

7.2.7. Attribute types supported in a custom palette

edoras vis supports following attribute types.

Table 11. Attribute types
Type Field Type Example

SimpleText

Text Field

<attribute id="name" title="Name" description="Name" value="" type="SimpleText"/>

TextArea

Text Area

<attribute id="summary" title="Summary" description="Summary" value="" type="TextArea" />

Integer

Number Field

<attribute id="age" title="Age" description="Age" value="15" type="Integer" category="common" />

Float

Number Field

<attribute id="price" title="Price" description="Price" value="1.11" type="Float" category="common" />

Boolean

Check Box

<attribute id="isValid" title="Is Valid" description="Is Valid" value="true" type="Boolean"/>

ComboBox

ComboBox

<attribute id="selectnumber" title="Select Number" description="Select Number" value="2" type="ComboBox">
    <items>
        <item id="1" title="One" value="1" />
        <item id="2" title="Two" value="2" />
        <item id="3" title="Three" value="3" />
    </items>
</attribute>

Check Special attribute items for more details.

RestComboBox

ComboBox

<attribute id="company" title="Company" description="Company" url="http://www.company.com" type="RestComboBox"/>

TextEditor

Text Editor

<attribute id="notesShort" title="NotesShort" type="TextEditor" value="" description="Short notes."/>

RichText

Rich Text Editor

<attribute id="documentation" title="Documentation" description="Documentation" value="" type="RichText"/>

TreeView

Tree view dialog

<attribute id="form_entry" title="FormRef" type="TreeView" value="" description="Form referenced by Form Task." filter="xfm" optional="false" readonly="true" />

For supported key event Click here [key-events-for-treeview-dialog]

Date

Date field

<attribute id="duedate" title="Due Date" description="Due Date" value="" type="Date"/>

ComplexDate

Date Editor

<attribute id="min-date" type="ComplexDate" value="" readonly="false" path="extraSettings.minDate" export="true" category="edoras" index="105"/>

Color

Color field

<attribute id="bgcolor" title="BackgroundColor" type="Color" value="#ffffcc" description="" ref-to-view="fill_el" fill="true" stroke="false" optional="false"/>

Complex

Complex dialog

<attribute id="in" title="In" type="Complex" description="Execution element for data input." value="">
    <complex-items>
        <complex-item id="source" name="Source" type="SimpleText" value="" width="150" />
        <complex-item id="target" name="Target" type="SimpleText" value="" width="150" />
    </complex-items>
</attribute>

For supported key event Click here [key-events-for-complex-dialog]

ComplexKeyValue

Complex dialog

<attribute id="in" title="In" type="ComplexKeyValue" description="Property for Complex Key Value editor." value="">
    <complex-items>
        <complex-item id="key" name="Key" type="SimpleText" value="" width="150" />
        <complex-item id="value" name="Value" type="SimpleText" value="" width="150" />
    </complex-items>
</attribute>

For supported key event Click here [key-events-for-complex-dialog]

ComplexForm

Form dialog

<attribute id="email" title="Email Properties" type="ComplexForm" description="Email properties" value="">
    <complex-items>
        <complex-item id="from" name="From" type="SimpleText" value="" width="250" vtype="expressionOrEmail" optional="false" />
        <complex-item id="to" name="To" type="SimpleText" value="" width="250" vtype="expressionOrEmailList" optional="false" />
        <complex-item id="cc" name="Cc" type="SimpleText" value="" width="250" vtype="expressionOrEmailList" />
        <complex-item id="bcc" name="Bcc" type="SimpleText" value="" width="250" vtype="expressionOrEmailList" />
        <complex-item id="subject" name="Subject" type="SimpleText" value="" width="250" />
        <complex-item id="html" name="Html" type="RichText" value="" width="250" />
    </complex-items>
</attribute>

Check Special Attribute complex-items for more details.

Link

Link field

<attribute id="link" title="SimpleLink" type="Link" value="http://www.google.com" />

ComplexTrigger

Complex dialog

<attribute id="ComplexTrigger" type="ComplexTrigger" title="Complex Trigger" value="" optional="true" readonly="false" category="edoras" />

RestComplex

ComboBox

<attribute id="RestComplex" readonly-editor="false" type="RestComplex" title="RestComplex" value="" url="../rest/one-groups" readonly="false" optional="true" category="edoras">
        <complex-items>
            <complex-item id="id" type="SimpleText" value="" name="ID" optional="false" />
            <complex-item id="title" type="SimpleText" value="" name="Title" optional="true" />
            <complex-item id="value" type="SimpleText" value="" name="Value" />
        </complex-items>
</attribute>

7.2.8. Defining custom widget presentation in a custom palette

edoras vis supports defining the SVG and Image for a widget.

Table 12. Attributes supported by the widget-presentations element
Name Mandatory Description

base-palette-icon-path

true

Base folder path where all related images are present.

base-editor-view-path

true

Base folder path where all related SVG file are present.

Table 13. Attributes supported by the widget-presentation element
Name Mandatory Description

id

true

Id of the widget presentation.

palette-icon-path

false

Path of image file used in presentation.

editor-view-path

false

Path of SVG file used in presentation.

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<component-presentations base-palette-icon-path="icons" base-editor-view-path="view">
    <component-presentation id="presentation.number" palette-icon-path="number.png" editor-view-path="number.svg"/>
    <component-presentation id="presentation.password" palette-icon-path="password.png" editor-view-path="password.svg"/>
</component-presentations>

For detailed explanation on oryx related elements and attributes in SVG view check here SVG view features

7.2.9. Defining rules in a custom palette

edoras vis supports defining the rules for a widget behaviour.

Table 14. Rules supported by an edoras vis custom palette widgets
Name Mandatory Description

containment-rules

This rule can be applied to widgets to specify containment rules based on roles.

<containment-rules>
    <containment-rule role="base_container" contains="standard_container,core_form_controls"/>
    <containment-rule role="standard_container" contains="core_form_controls"/>
</containment-rules>

morphing-rules

This rule can be applied to widgets to specify morphing rules (Changing from one type to another) based on roles.

<morphing-rules>
    <morphing-rule role="controls_morph" base-morphs="Input"/>
</morphing-rules>

connection-rules

This rule can be applied to widgets to specify connection rules between widgets based on roles (Used Only in Process Custom Palettes).

<connection-rules>
    <connection-rule role="SequenceFlow">
        <connects from="sequence_start" to="sequence_end"/>
    </connection-rule>
    <connection-rule role="MessageFlow">
        <connects from="messageflow_start" to="messageflow_end"/>
    </connection-rule>
</connection-rules>
  1. SequenceFlow widgets can be used to connect between widgets having roles "sequence_start" and "sequence_end"

  2. MessageFlow widgets can be used to connect between widgets having roles "messageflow_start" and "messageflow_end"

cardinality-rules

This rule can be applied to widgets to specify number of incoming and outgoing connector rules based on roles (Used Only in Process Custom Palettes).

<cardinality-rules>
     <cardinality-rule role="Startevents_all">
        <incoming role="SequenceFlow" maximum="0"/>
    </cardinality-rule>
    <cardinality-rule role="Endevents_all">
        <outgoing role="SequenceFlow" maximum="0"/>
    </cardinality-rule>
</cardinality-rules>
  1. Widgets having "Startevents_all" as role cannot have incoming sequence flows.

  2. Widgets having "Endevents_all" as role cannot have outgoing sequence flows.

7.2.10. Defining attribute groups in a custom palette

edoras vis supports defining custom attribute groups, which can be used to assign a set of attributes to multiple widgets. .Attributes supported by an attribute-group element

Name

Mandatory

Description

name

true

Unique name of the attribute group

An attribute-groups element can contain one or more attribute-group elements. Similarly an attribute-group element can contain one or more attribute elements, as shown in the sample below.

<attribute-groups>
    <attribute-group id="commonAttributes">
        <attribute id="id" title="Id" value=""/>
        <attribute id="nameKey" title="NameKey" description="NameKey" type="SimpleText" value="" />
    </attribute-group>
    <attribute-group id="formControlAttributes">
        <attribute id="label" runtime="false" multilanguage="false" category="common"/>
        <attribute id="description" title="Description" type="SimpleText" visible="false"/>
    </attribute-group>
</attribute-groups>

7.2.11. Defining custom attributes in custom palette

edoras vis supports defining custom attributes.

Table 15. Attributes supported by the custom-attributes-group element
Name Mandatory Description

id

true

Id of the custom-attributes-group.

ref

false

Id of the widget to which the custom attributes are applied to. If this attribute is skipped then the attributes are applied to all the widgets.

A custom-attributes element can contain one or more custom-attributes-group elements. Similarly, a custom-attributes-group element can contain one or more attribute elements, as shown in the sample below.

<custom-attributes>
    <custom-attributes-group id="customAttributeGroup1">
        <attribute id="id" title="Id" value=""/>
        <attribute id="nameKey" title="NameKey" description="NameKey" type="SimpleText" value="" />
    </custom-attributes-group>
    <custom-attributes-group id="customAttributeGroup2" ref="Task">
        <attribute id="label" runtime="false" multilanguage="false" category="common"/>
        <attribute id="description" title="Description" type="SimpleText" visible="false"/>
    </custom-attributes-group>
</custom-attributes>

7.2.12. Defining model attributes in a custom palette

edoras vis supports defining model attributes in a custom palette.

To add model attributes a model-attributes element has to be added.

A model-attributes element can contain one or more attribute elements. All attributes which are defined within the model-attributes element will be added to the model. See the sample below.

<model-attributes id="modelAttributes" >
    <attribute id="expressionid" title="Label Expresion" value=""/>
    <attribute id="guid" title="GUID" description="GUID of the model" type="SimpleText" value="" />
</model-attributes>

7.3. Special attributes of attribute element in palette

7.3.1. ref-to-view

ref-to-view specifies an id of SVG element in the graphical representation of a widget. If this attribute is set, the property will manipulate the graphical representation at run-time, for example, changing the color or rendering text. Depending on the property’s type you can reference different types of SVG elements as show below.

  • ref-to-view="text_name" (for text)

  • ref-to-view="fill_el" (for color)

<attribute id="name"   value="" category="common"  type="SimpleText" ref-to-view="text_name"/>

7.3.2. filter

The filter attribute is applicable only for TreeView type and is used to filter the nodes displayed in the tree view.

edoras vis supports following filters :

  • mod is used for Processes

  • xfm is used for Forms

<attribute id="form_entry" title="FormRef" type="TreeView" value="" description="Form referenced by Form Task." filter="xfm" optional="false" readonly="true" />

7.3.3. fill

fill is an optional attribute applicable only for Color type. If fill attribute is set to true the background color of a shape can be set.

fill

7.3.4. multilanguage

multilanguage is an optional attribute used to show or hide the language specific attributes for a given attribute in the property window.

multilanguage

7.3.5. runtime and runtime-value

runtime is an optional attribute used to show or hide runtime-value of an attribute in the property window of the editor.

<attribute id ="description" runtime-value="" runtime="true" multilanguage="true"> </attribute>
runtime

7.3.6. wrapLines

wrapLines is an optional attribute used to customize attributes of type String.

If wrapLines is set to false, the text field shown will be of single line.

If wrapLines is set to true, the text field shown will be of multi line.

7.3.7. items

items can be used as a child element of the attribute element of type ComboBox. This is used to define the list of values for the combobox.

<attribute id="behavior" type="ComboBox" category= "edoras"  index="3" title="behavior">
    <items>
        <item id="none" title="none" value="none" />
        <item id="all" title="all" value="all" />
        <item id="one" title="one" value="one" />
        <item id="complex" title="complex" value="complex" />
    </items>
</attribute>

7.3.8. complex-items

complex-items can be used as child element of attribute element if the attribute is of one of the following types:

  • Complex

  • ComplexForm

complex-items element can contain one or more complex-item elements.

Table 16. Attributes supported by the complex-item element
Name Mandatory Description

id

true

Id of the complex-item

name

false

Title of the complex-item

value

false

Value of the complex-item

type

false

Type of the complex-item, It can only support following types:

  • SimpleText

  • TextArea

  • ComboBox

  • RestComboBox

  • Boolean

  • Integer

  • Float

  • Date

  • ComplexDate

  • Color

  • Link

  • TextEditor

  • RichText

  • TreeView

value

false

Used for validating values, Following are the supported vtype values:

  • singleEmail

  • emailList

  • expressionOrEmail

  • expressionOrEmailList

width

false

Width of the complex-item

optional

false

Used to make the complex-item optional or otherwise

<attribute id="email" title="Email Properties" type="ComplexForm" description="Email properties" value="">
    <complex-items>
        <complex-item id="from" name="From" type="SimpleText" value="" width="250" vtype="expressionOrEmail" optional="false" />
        <complex-item id="to" name="To" type="SimpleText" value="" width="250" vtype="expressionOrEmailList" optional="false" />
        <complex-item id="cc" name="Cc" type="SimpleText" value="" width="250" vtype="expressionOrEmailList" />
        <complex-item id="bcc" name="Bcc" type="SimpleText" value="" width="250" vtype="expressionOrEmailList" />
        <complex-item id="subject" name="Subject" type="SimpleText" value="" width="250" />
        <complex-item id="html" name="Html" type="RichText" value="" width="250" />
    </complex-items>
</attribute>

7.3.9. dependency

dependency can be used as a child element of the attribute element. This is used to make attribute visible/hide based on another attribute value.

<attribute id="thumbnail-max-height" type="SimpleText" title="Thumbnail Maximum Height" value="" >
    <dependency ref="preview" value="thumbnail" />
</attribute>

7.4. SVG view features

7.4.1. oryx:magnet

With oryx:magnet you can define special points on a node where you can dock other nodes or edges to connect them.

You can connect a docker to any point on a node, but magnets help the user creating nicer looking models. If you do not define a magnet for a node, it will a have default magnet in the center. Magnets are specified with 'magnet' elements, for example:

<oryx:magnets>
    <oryx:magnet oryx:cx="1" oryx:cy="20" oryx:anchors="left" />
    <oryx:magnet oryx:cx="1" oryx:cy="40" oryx:anchors="left" />
    <oryx:magnet oryx:cx="1" oryx:cy="60" oryx:anchors="left" />

    <oryx:magnet oryx:cx="25" oryx:cy="79" oryx:anchors="bottom" />
    <oryx:magnet oryx:cx="50" oryx:cy="79" oryx:anchors="bottom" />
    <oryx:magnet oryx:cx="75" oryx:cy="79" oryx:anchors="bottom" />

    <oryx:magnet oryx:cx="99" oryx:cy="20" oryx:anchors="right" />
    <oryx:magnet oryx:cx="99" oryx:cy="40" oryx:anchors="right" />
    <oryx:magnet oryx:cx="99" oryx:cy="60" oryx:anchors="right" />

    <oryx:magnet oryx:cx="25" oryx:cy="1" oryx:anchors="top" />
    <oryx:magnet oryx:cx="50" oryx:cy="1" oryx:anchors="top" />
    <oryx:magnet oryx:cx="75" oryx:cy="1" oryx:anchors="top" />

    <oryx:magnet oryx:cx="50" oryx:cy="40" oryx:default="yes" />
  </oryx:magnets>

The oryx:magnets element is a direct child of the svg element.

magnet

The magnets are shown as small light red circles light_magnet

7.4.2. oryx:docker

dockers are the other part of the dockers-magnets concept. A docker is a control object to connect an edge to a node or in this case to connect two nodes. A node can have at most one docker that can be defined by using a docker element:

<oryx:docker oryx:cx="16" oryx:cy="16" />
docker

A docker is shown as a small green circle green_docker

A docker element needs only position information. Docking nodes on nodes can be used as a shortcut for connecting two nodes with an edge. In this figure, the rectangular shape is the source and the circular shape is the target.

7.4.3. Text

Text is rendered with SVG text elements.

<text
       font-size="12"
       id="text_name"
       x="50"
       y="40"
       oryx:align="middle center"
       oryx:fittoelem="text_frame"
       stroke="black">
</text>
text

Oryx extends these element with attributes for the alignment and the rotation of the text. The alignment uses the specified coordinates (attributes x and y) as the reference point. A value of middle center means that the horizontal center and vertical middle point of the text will be positioned on the reference point.

Note
If you want to set the text element’s value using a property, you have to set the id of the text element by using ref-to-view attribute in custom palette.
<attribute id="name"   value="" category="common"  type="RichText" ref-to-view="text_name"/>

7.4.4. oryx:minimumSize

  • Value: float float

  • Initial: 1 1

  • Optional: yes

  • Applies to: SVG elements

minimumSize defines the minimum size the node can be resized to, if the node is resizable. The first value defines the minimum width, the second the minimum height.

<g pointer-events="fill" oryx:minimumSize="200 80" >

7.4.5. oryx:maximumSize

  • Value: float float

  • Initial: -

  • Optional: yes

  • Applies to: SVG elements

maximumSize defines the maximum size the node can be resized to, if the node is resizable. The first value defines the maximum width, the second the maximum height.

<g pointer-events="fill" oryx:minimumSize="80 60" oryx:maximumSize="200 160" >

7.5. Removing widgets from the main palette using fragment/patch palettes

edoras vis supports defining model attributes in a custom palette.

This feature can be used in cases where some of the default widgets provided in the default palettes should not been shown (since similar custom widgets have been added). To remove certain widgets, add the widget IDs as a comma separated list to the stencil-ids attribute of the <remove-stencils> element in the patch/fragment palette as shown in the below sample:

    <remove-stencils
            stencil-ids="cloud-attachment,cloud-upload"/>

Note this only works for elements contained in the main palette to which the patch palette is applied to.

7.6. Sample custom palette

A sample custom palette is given below:

<?xml version="1.0" encoding="UTF-8"?>
<palette id="custom-process-palette"
     xmlns="http://www.edorasware.com/schema/vis/process-palette"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://www.edorasware.com/schema/vis/process-palette
                         http://www.edorasware.com/schema/vis/edoras-vis-process-palette-2.0.43.xsd"
     resource-bundle="translation">

    <attribute-groups>
        <attribute-group id="baseAttributes">
            <attribute id="id" value="" title="" />
            <attribute id="name" value="" title="Name"
                       multilanguage="false" category="common" ref-to-view="text_name"/>
            <attribute id="documentation" value="" title="Documentation"
                       multilanguage="false" category="common"/>
        </attribute-group>

        <attribute-group id="usertask">
            <attribute id="notesShort" title="" value="" />
            <attribute id="notesShortKey" title="" value="" />
            <attribute id="candidateusers" title="CandidateUsers" value=""
                       category="edoras" type="RestComboBox" url="/rest/modeler-users"/>
            <attribute id="candidategroups" title="CandidateGroups" value=""
                       category="edoras" type="RestComboBox" url="/rest/modeler-groups"/>
            <attribute id="support" title="Support Link" type="Link"
                       value="http://www.edorasware.com/support" />
        </attribute-group>
    </attribute-groups>

    <model-attributes id="modelAttributes">
        <attribute id="guid" value="" title="" />
        <attribute id="labelExpression" value="" title="" />
        <attribute id="version" value="" title="" />
        <attribute id="author" value="" title="" />
        <attribute id="language" value="" title="" visible="false"/>
        <attribute id="namespaces" value="" title="" visible="false"/>
    </model-attributes>

    <group title="Custom Tasks" id="custom-shapes">
        <component id="CustomFormTask" extends="FormTask"
                   attribute-groups="baseAttributes,usertask"/>
        <component id="CustomManualTask" extends="ManualTask"
                   attribute-groups="baseAttributes,usertask"/>
        <component id="CustomEndNoneEvent" extends="EndNoneEvent"
                   attribute-groups="baseAttributes"/>
        <component id="CustomSequenceFlow" extends="SequenceFlow"
                   attribute-groups="baseAttributes"/>
        <component id="CustomTextAnnotation" extends="TextAnnotation"
                   attribute-groups="baseAttributes"/>
        <component id="CustomAssociationUndirected" extends="Association_Undirected"
                   attribute-groups="baseAttributes"/>
        <component id="CustomExclusiveDatabasedGateway" extends="Exclusive_Databased_Gateway"
                   attribute-groups="baseAttributes"/>
        <component id="CustomParallelGateway" extends="ParallelGateway"
                   attribute-groups="baseAttributes"/>
    </group>

    <group title="Activities" id="activities">
        <component ref="Task" id="RefTask"/>
        <component ref="Subprocess" id="RefSubprocess"/>
        <component id="RefFormTask" extends="FormTask">
            <attribute id="formInit" value="" title="Init Form Ref"
                   type="TreeView" filter="xfm" category="common" export="true"/>
            <attribute id="guid-ref" value="" title="Init Form Ref (ID)"
                   type="SimpleText" category="common" export="true" visible="false"/>
        </component>
        <component ref="CollapsedSubprocess" id="RefCollapsedSubprocess"/>
        <component ref="ExpandedSubProcess" id="RefExpandedSubProcess"/>
        <component ref="CallActivity" id="RefCallActivity"/>
    </group>

    <group title="Gateways" id="gateways">
        <component ref="Exclusive_Databased_Gateway" id="RefExclusive_Databased_Gateway"/>
        <component ref="ParallelGateway" id="RefParallelGateway"/>
    </group>

    <group title="Events" id="events">
        <component ref="StartNoneEvent" id="StartNoneEvent"/>
        <component ref="EndNoneEvent" id="EndNoneEvent"/>
    </group>

    <group title="Connectors" id="connectors">
        <component ref="SequenceFlow" id="RefSequenceFlow"/>
        <component ref="Association_Undirected" id="RefAssociation_Undirected"/>
        <component ref="Association_Unidirectional" id="RefAssociation_Unidirectional"/>
        <component ref="MessageFlow" id="RefMessageFlow"/>
        <component ref="Association_Bidirectional" id="RefAssociation_Bidirectional"/>
    </group>

</palette>

8. Defining App development workflows

8.1. App development overview

edoras one supports configurable app development workflows, allowing automatic or semi-automatic exchange of Apps between different edoras one installations and tenants.

To transfer an App out of an edoras one tenant, the App content is written to the local filesystem using an outgoing channel adapter. The adapter can then send a message to a Spring Integration channel to trigger additional processing (e.g. to copy the App to another system).

Spring Integration can also be used to receive incoming Apps and send them to the Incoming App Service. This documentation will describe the interface between edoras one and Spring Integration. For details of how to configure Spring Integration to implement a given App distribution workflow please refer to the Spring Integration project page.

Here is a high level overview of the App workflow processing:

AppWorkflow

8.2. Outgoing adapter configuration

An outgoing adapter can be declared as a Spring bean which implements the interface:

com.edorasware.cloud.core.transfer.OutgoingAppChannelAdapter

edoras one provides the following standard channel adapter implementations:

com.edorasware.cloud.core.transfer.internal.LocalDirectoryOutgoingAppChannelAdapter

writes the App to the local filesystem as a file tree within a root directory.

com.edorasware.cloud.core.transfer.internal.LocalZipFileOutgoingAppChannelAdapter

writes the App to the local filesystem as a ZIP file.

In all channel adapter implementations the App will be written using an ID that is constant across all systems where the App is installed.

The outgoing channel adapter should be declared as a bean in the installation-specific Spring configuration. In addition to the required bean constructor parameters, the following bean properties are supported:

Table 17. Supported outgoing channel bean properties
Property Description

baseDirectory

the App storage base directory

name

a descriptive channel name

outputChannel

a Spring Integration channel to receive outgoing App notification messages

useTenantSubdirectories

store each App in a subdirectory according to the originating tenant

To send Apps to selected output channels automatically whenever an App is deployed, define a list with id deployedAppChannelAdapters that includes references to the required output channel adapters. When an App is deployed it will be sent to all of the defined adapters without additional user intervention.

As an example, a typical outgoing channel adapter configuration for deployed Apps could look like the following:

  <util:list id="deployedAppChannelAdapters"
             value-type="com.edorasware.cloud.core.transfer.OutgoingAppChannelAdapter">
      <ref bean="outgoingAppChannelAdapter"/>
  </util:list>
  
  <bean id="outgoingAppChannelAdapter"
        class="com.edorasware.cloud.core.transfer.internal.LocalZipFileOutgoingAppChannelAdapter">
      <constructor-arg name="name" value="Local Directory"/>
      <constructor-arg name="baseDirectory" value="${transfer.outgoing.location}"/>
      <property name="useTenantSubdirectories" value="true"/>
      <property name="outputChannel" ref="loggingChannel"/>
  </bean>
  
  <int:channel id="loggingChannel"/>
  
  <int:logging-channel-adapter channel="loggingChannel" log-full-message="true"/>

This configuration will save each deployed App as a Zip file in the given directory, and then send a message to the logging channel (where the full message content will be logged).

8.3. Outgoing adapter message format

By setting the outputChannel property outgoing channel adapter implementations can send a message to a Spring Integration channel whenever an App is saved. These messages can be used to trigger the additional processing needed for App distribution, and have the following format:

  • the message payload is a org.springframework.core.io.Resource describing the App location

  • the message has additional headers with information that may be useful in subsequent processing

Table 18. Outgoing Spring Integration message headers
Header Type Description

appName

String

the current App name (this may change over time)

appSourceId

String

the App source ID (constant across all systems)

comment

String

a comment supplied when the App distribution was triggered

sourceTenantName

String

the name of the originating tenant

8.4. Incoming adapter configuration

The incoming Spring Integration configuration can import an App by sending a message to the pre-defined App channel:

resourceAppChannel accepts messages with org.springframework.core.io.Resource payloads describing the App location. This channel supports:

  • remote App Zip resources

  • local App Zip files

  • local App file trees

Per default an incoming adapter configuration (like in the example below) is already set and you just need to set the apps.preinstalled.location system property to the correct path where the apps are located. If you want to override this adapter then follow this example:

An incoming channel adapter configuration to automatically load pre-installed apps from a given input directory could look like the following:

  <!-- Update pre-installed Apps in all tenants when the App is modified -->
  <int:resource-inbound-channel-adapter id="incomingAppChannelAdapter"
                                        channel="resourceArrayAppChannel"
                                        auto-startup="false"
      pattern="${apps.preinstalled.location}">
  
      <!-- classpath items won't change so reduce polling to a minimum -->
      <int:poller fixed-delay="86400" time-unit="SECONDS" />
  </int:resource-inbound-channel-adapter>
  
  <int:channel id="resourceArrayAppChannel" datatype="org.springframework.core.io.Resource[]"/>
  
  <int:splitter input-channel="resourceArrayAppChannel" output-channel="resourceAppChannel"/>

This configuration polls the given directory, filters the results to leave modified App Zip files and passes these on to the fileAppChannel. The messages with a `File payload are then converted to a corresponding `Resource* messages and passed onto the pre-defined resource channel to trigger the import processing.

8.5. Incoming App service message format

The incoming App service accepts messages from a Spring Integration channel as follows:

  • the message payload is a org.springframework.core.io.Resource describing the App location

  • the message has additional headers with information to control the App import process

Table 19. Incoming Spring Integration message headers
Header Type Default Description

isSystemApp

Boolean

false

Set to true if the incoming app is the system app

isEditableApp

Boolean

true

Set to true if the app should be editable after import

removeAfterImport

Boolean

false

Set to true if the incoming app should be removed after import

forceAppImport

Boolean

false

Set to true if the incoming app should always be installed (no version checking will be performed)

tenantNames

String

<empty>

A comma-separated list of tenant names for the tenants where the app should be installed. If no tenant is specified then the app will be installed on all tenants.

8.6. Incoming adapter lifecycle

Unfortunately, although the standard Spring Integration channel adapters will be started automatically as part of the Spring lifecycle, the lifecycle phase cannot be modified and is not compatible with the edoras one lifecycle phases. This means that by default some channel adapters may be started before edoras one is ready to receive Apps.

As a workaround for this problem, the channel adapter auto-startup property can be set to false, and the bean reference added to the managedChannels list of the incomingChannelManager bean:

  <bean id="incomingChannelManager"
        class="com.edorasware.cloud.core.transfer.IncomingAppChannelAdapterLifecycleBean">
      <property name="managedChannels">
          <list>`
              <ref bean="systemAppAdapter"/>
              <ref bean="incomingAppChannelAdapter"/>
          </list>
      </property>
  </bean>
Note
The systemAppAdapter reference is a default adapter provided by edoras one to update the system App to the latest version whenever the server is restarted. This should always be included when overwriting the incomingChannelManager bean definition.

8.7. App version checking

When an App is imported into edoras one, a version check will normally be performed. This makes sure that the currently installed version is a direct ancestor of the version that is being imported. If this is not the case then the App being imported is based on a different version of the App than the one that is installed. This means that changes currently installed on the system may be lost.

This version check may be disabled using the incoming message headers, but this should only be done when the scenarios where this may be necessary have been established and the possible consequences of silently ignoring version conflicts have been considered.

8.8. Spring Integration extensions

The following implementations are provided by edoras one and can be used in Spring Integration configurations to support some common integration use cases:

com.edorasware.cloud.core.transfer.integration.ModifiedFilesFilter

a FileListFilter implementation that tracks the incoming files and accepts files that are either new or have been modified. This is useful for polling an incoming App directory where the Apps aren’t removed after import.

com.edorasware.cloud.core.transfer.integration.FileToResourceTransformer

transforms messages with a java.io.File payload into a message with a corresponding springframework.core.io.Resource payload, preserving all message headers.

9. Deployment

9.1. Deploying to Cloud Foundry

This appendix gives step by step instructions on how to deploy your application to a Cloud Foundry server. Cloud Foundry is an open Platform as a Service (PaaS) infrastructure.

9.1.1. Maven support

Cloud Foundry provides a Maven plugin that allows you to deploy applications with Maven goals. This appendix only gives basic instructions, please refer to http://docs.cloudfoundry.org/buildpacks/java/build-tool-int.html to learn more about Maven support for Cloud Foundry.

Install Maven plugin

To install the Cloud Foundry Maven plugin, add the corresponding section to your pom.xml file:

Cloud Foundry plugin installation in pom.xml
  <plugin>
      <groupId>org.cloudfoundry</groupId>
      <artifactId>cf-maven-plugin</artifactId>
      <version>1.0.3</version>
  </plugin>

Cloud Foundry does not have a persistent file system (the file system is cleared before an application restart), therefore it is not possible to persistently store work item and document content data in the file system. In this environment the application uses Cloud Foundry services to persistently store data.

Usually the application loads edorasware license from the file system (e.g. from the user’s home directory). Again, this approach is not possible with Cloud Foundry as there is no persistent file system, so we supply the edorasware license as an environment variable.

Configure Maven plugin

The configuration section of the plugin defines the default values used for the Cloud Foundry goals. It is possible to overwrite the default values with system variables.

server

Used to look up the Cloud Foundry credentials in the Maven settings.xml file. By default the settings.xml file is stored in ~/.m2/settings.xml. See http://maven.apache.org/settings.html#Servers to learn more about the Maven settings.xml file.

target

Defines the URL of your Cloud Foundry infrastructure API.

org

Defines your organization inside the Cloud Foundry infrastructure.

space

Defines the space to be used inside your organization.

env

Defines the environment variables needed by edoras one. The only environment variable we define here is the edorasware license.

services

Defines the Cloud Foundry services needed by edoras one: a relational database named datadb that stores the work items and a mongo DB named contentdb that stores the document content.

Putting all this together, the Cloud Foundry plugin section looks as follows:

Cloud Foundry plugin configuration in pom.xml
  <plugin>
      <groupId>org.cloudfoundry</groupId>
      <artifactId>cf-maven-plugin</artifactId>
      <version>1.0.3</version>
      <configuration>
          <server>${cloudfoundry.server}</server>
          <target>${cloudfoundry.target}</target>
          <org>${cloudfoundry.org}</org>
          <space>${cloudfoundry.space}</space>
          <memory>1024</memory>
          <env>
              <EDORASWARE_LICENSE>${edorasware.license}</EDORASWARE_LICENSE>
          </env>
          <services>
              <service>
                  <name>datadb</name>
                  <label>${cloudfoundry.service.datadb.label}</label>
                  <plan>${cloudfoundry.service.datadb.plan}</plan>
              </service>
              <service>
                  <name>contentdb</name>
                  <label>${cloudfoundry.service.contentdb.label}</label>
                  <plan>${cloudfoundry.service.contentdb.plan}</plan>
              </service>
          </services>
      </configuration>
  </plugin>

To ease the handling of the Cloud Foundry plugin configuration in the pom.xml file you can use Maven properties. The property values are then stored in two places: properties that are not security critical are defined inside a properties element at the top of the pom.xml file, security critical properties are defined in the Maven settings.xml file.

Properties in pom.xml
  <!-- Cloud Foundry properties -->
  <cloudfoundry.server>run.pivotal.io</cloudfoundry.server>
  <cloudfoundry.target>http://api.run.pivotal.io</cloudfoundry.target>
  <cloudfoundry.org>edorasware</cloudfoundry.org>
  <cloudfoundry.space>development</cloudfoundry.space>
  
  <cloudfoundry.service.datadb.label>elephantsql</cloudfoundry.service.datadb.label>
  <cloudfoundry.service.datadb.plan>turtle</cloudfoundry.service.datadb.plan>
  
  <cloudfoundry.service.contentdb.label>mongolab</cloudfoundry.service.contentdb.label>
  <cloudfoundry.service.contentdb.plan>sandbox</cloudfoundry.service.contentdb.plan>

Make sure that the server id in the Maven settings.xml file matches the server configuration value of Cloud Foundry plugin (run.pivotal.io in our case).

Settings in Maven settings.xml
  <servers>
      <server>
          <id>run.pivotal.io</id>
          <username>user</username>
          <password>pass</password>
      </server>
  </servers>

9.1.2. Use Maven plugin

To access your Cloud Foundry infrastructure, the Cloud Foundry Maven plugin offers different Maven goals. The most important is the one to deploy your application:

mvn cf:push

Congratulations! You have deployed your first edoras one application to a Cloud Foundry infrastructure.

9.1.3. Command line support

The recommended way to work with Cloud Foundry is to use the Maven integration (see above) or the Gradle integration. However for special cases it is possible to use the Cloud Foundry command line tool. One such special case is when your Cloud Foundry infrastructure does not support recent versions of the Maven / Gradle integration plugins.

Note

It is not possible to define environment variables that contain line feeds with the Cloud Foundry command line tool. Therefore you cannot use an environment variable to supply the edorasware license to the Cloud Foundry infrastructure.

In this case you have to place the edorasware license file inside your application and access it from there, e.g. in the WEB-INF folder.

First make sure to install the correct version of the Cloud Foundry command line tool that matches your Cloud Foundry infrastructure. Then open a command line and invoke the Cloud Foundry commands as required. The following batch file lists the commands needed to deploy an edoras one application:

Batch file
  REM stop application
  cf stop edoras-one-bootstrap
  
  REM deploy application without start
  cf push edoras-one-bootstrap ^
     -d beta.swisscloud.io ^
     -m 1G ^
     -p target\edoras-one-bootstrap.war ^
     -t 150 ^
     --no-start
  
  REM create and bind relational database service
  cf create-service mariadb 512mb datadb
  cf bind-service edoras-one-bootstrap datadb
  
  REM create and bind document database service
  cf create-service mongodb default contentdb
  cf bind-service edoras-one-bootstrap contentdb
  
  REM start application
  cf start edoras-one-bootstrap

See http://docs.cloudfoundry.org/devguide/#cf to learn more about the Cloud Foundry command line tool.

9.2. How to integrate edoras one in your own html

It’s possible to use edoras one in your own html inside a div.

First of all, you should know some limitations:

  • edoras one app must be the unique angularJS app in your html.

  • The div which contains edoras one requires a defined height, that is, not auto, with percentage or pixels.

  • The minimum size supported in edoras one is 1024x768. That means that the div which contains edoras one must fit this measure.

The following html code must be inserted in your page:

<div ng-app="oneModule" class="edoras-one" >
    <link type="text/css" media="all" href="./one/less/main-1.5.0.S70.less" rel="stylesheet/less"/>
    <script type="text/javascript" src="./forms/app/fms.files-1.5.0.S70.js"></script>
    <script type="text/javascript" src="./one/app/one.files-1.5.0.S70.js"></script>
    <script type="text/javascript" src="./forms/css/resources.css"></script>
    <script type="text/javascript" src="./one/css/resources.css"></script>
    <link rel="stylesheet" href="./forms/libs/upload/css/bootstrap.min.css" />
    <link rel="stylesheet" href="./forms/libs/upload/css/external/bootstrap-image-gallery.min.css" />
    <link rel="stylesheet" href="./forms/libs/upload/css/jquery.fileupload-ui.css" />
    <script type="text/javascript" src="./forms/libs/less/less-1.7.5.min.js"></script>
    <div e-application-loader>
        <div id="mainDiv">
            <div e-menu></div>
            <div e-header></div>
            <div class="viewContainer">
                <div class="ng-view"></div>
                <div e-actions-pane></div>
            </div>
            <div e-version ></div>
        </div>
        <div e-notification-bar></div>
        <div e-select-dashboard-pane ></div>
        <div e-global-message></div>
    </div>
</div>

You must have the production files in the correct directory structure with "./one" and "./forms" directories and the backend endpoints.

If you want and you are able to do, you can define these css and scripts tags in your head element instead of the body, in order to be loaded synchronously before the page is rendered.

9.2.1. Customizing edoras one elements

You can avoid showing some elements like the menu, the header or the actions pane by simply deleting it from the html above. These elements are:

<div e-menu></div>
<div e-header></div>
<div e-actions-pane></div>

9.2.2. Placing our html in a different place than the resources

In the html we can set a variable APP_CONTEXT to specify where the resources are.

For example if we have our resources in http://domain.com/resources but our html is in http://domain.com/web, we can set the APP_CONTEXT to "../resources/":

<script>window.APP_CONTEXT = '../resources/';</script>

This script tag must be placed before the fms.files.js script tag:

<script>window.APP_CONTEXT = '../resources/';</script>
<script type="text/javascript" src="./forms/app/fms.files-1.5.0.S70.js"></script>

We can set the APP_CONTEXT with relative or absolute values:

<script>window.APP_CONTEXT = '../resources/';</script>
<script>window.APP_CONTEXT = '/resources/';</script>
<script>window.APP_CONTEXT = 'http://domain.com/resources';</script>
Note
If you want to set a context of an external domain you can experience problems with CORS browser security. Contact your administrator in that case.

9.3. Application logging

The bootstrap project should log correctly using application-specified logging without changes.

For JBoss application servers, an additional deployment configuration file is included in the bootstrap project to prevent logging-related classes from the application container being added to the application classpath and interfering with the application-specific logging:

JBoss deployment configuration WEB-INF/jboss-deployment-structure.xml
  <?xml version="1.0" encoding="UTF-8"?>
  <jboss-deployment-structure>
      <deployment>
      <exclusions>
            <module name="org.apache.log4j"/>
            <module name="org.slf4j"/>
            <module name="org.jboss.logging"/>
            <module name="commons-logging"/>
            <module name="org.apache.commons.logging"/>
            <module name="org.jboss.logging.jul-to-slf4j-stub"/>
      </exclusions>
      </deployment>
  </jboss-deployment-structure>

Application logging is configured as described in the section Logging configuration.

9.4. Container logging

The logging configuration shown in the bootstrap project uses log4j and a local logging configuration within the deployed WAR file. The resulting logs will typically be written to an application-specific log file, separate from any log files that may be used by the container in which the application is deployed.

An alternative logging approach is to delegate the logging to the container, allowing the logs from both the container and the application to be written to a single log file and controlled using a single logging configuration. The following sections describe the required configuration for this setup using some common application containers.

9.4.1. Tomcat container logging

The Tomcat application server uses a custom logging implementation for server logging that is not supported by an slf4j adapter. For this reason we cannot simply delegate the logging to the container in the default configuration. To use container logging, the server must be reconfigured to use log4j as described on the following web page:

When the server has been reconfigured in this way, you just need to remove the log4j library from the bootstrap project by excluding it explicitly when the slf4j-to-log4j adapter is included. The slf4j-to-log4j adapter will then find the log4j implementation from the Tomcat lib directory and use it for all edoras one logging. You will also need to remove the bootstrap project log4j.properties file, and transfer any required edoras one logging configuration to the container log4j.properties file.

If you have unit tests within the bootstrap project then you will also need to add a testing runtime dependency for the log4j library, as the unit tests will not have access to the log4j library in the Tomcat container.

Maven dependency configuration
Tomcat container logging configuration in the Maven pom.xml
  <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-log4j12</artifactId>
      <version>${org.slf4j.version}</version>
      <scope>runtime</scope>
      <exclusions>
          <exclusion>
              <groupId>log4j</groupId>
              <artifactId>log4j</artifactId>
          </exclusion>
      </exclusions>
  </dependency>
  
  <dependency>
      <groupId>log4j</groupId>
      <artifactId>log4j</artifactId>
      <version>1.2.17</version>
      <scope>test</scope>
  </dependency>
Gradle dependency configuration
Tomcat container logging configuration in the Gradle build.gradle
  // Route the logs to log4j ...
  runtime("org.slf4j:slf4j-log4j12:$slf4jVersion") {
    // ... where log4j itself is supplied by the Tomcat container
    exclude group: 'log4j', module: 'log4j'
  }
  
  // we still need a local log4j library for testing
  testRuntime "log4j:log4j:1.2.17"

9.4.2. JBoss container logging

The JBoss application server supports all of the logging frameworks used in edoras one, so to use JBoss container logging it is only necessary to do the following:

  • remove the logging dependencies

  • remove the julReroute bean definition from the application’s Spring configuration

  • remove the logging configuration file log4j.properties (or move it to the test source tree if it is still needed for unit testing)

  • remove the file WEB-INF/jboss-deployment-structure.xml

If the project contains unit tests, however, the logging dependencies will need to be retained and moved to the test scope as shown below.

Maven dependency configuration
JBoss container logging configuration in the Maven pom.xml
  <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>jul-to-slf4j</artifactId>
      <version>${org.slf4j.version}</version>
      <scope>test</scope>
  </dependency>
  <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>jcl-over-slf4j</artifactId>
      <version>${org.slf4j.version}</version>
      <scope>test</scope>
  </dependency>
  <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-log4j12</artifactId>
      <version>${org.slf4j.version}</version>
      <scope>test</scope>
  </dependency>
Gradle dependency configuration
JBoss container logging configuration in the Gradle build.gradle
  // Retain test dependencies for unit testing ...
  testRuntime "org.slf4j:jul-to-slf4j:$slf4jVersion"
  testRuntime "org.slf4j:jcl-over-slf4j:$slf4jVersion"
  testRuntime "org.slf4j:slf4j-log4j12:$slf4jVersion"