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 describe system installation and configuration and may also be of interest to system administrators.

2. Obtaining up the example project

The examples described here are demonstrated in an example on-premise project which can be obtained from edorasware. To obtain a copy of this project please contact edorasware support.

2.1. Skeleton project

The example project mentioned above has example services, listeners etc. already in the project. But for users which need a bare project without any example code we have the skeleton project. To get this you just need to obtain the example project, browse to the project root folder and then 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

After that, all the examples etc. are stripped away from the project.

3. Basic project setup

The example project has a Maven and a Gradle build configuration such that you can choose which one you like. For the Maven build Maven 3.0.0 or greater is required. The Gradle build is based on the Gradle wrapper and downloads the proper version by its own.

You can download the build tools here:

3.1. 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>

3.2. 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'
  }

3.3. Artifacts repository configuration

You will need to make the edoras one artifacts available in a Maven repository so that the dependencies for an on-premise project can be resolved. The artifacts can typically be uploaded to the repository manually, or if you have access to the edorasware public repository then the details may be configured into your local repository and artifacts can 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 Maven repository configuration. This will typically be located in the pom.xml file (for Maven builds) or in the build.gradle file (for Gradle builds) of your project. 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>
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"
    }
  }

In addition you have to configure the credentials to access the Maven repository in your home directory (as it will contain passwords that should not be checked in to a source control system).

3.3.1. For Maven

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.

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.

3.3.2. For Gradle

Add the credentials that you received from edorasware to the 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

3.4. edoras one dependency

The edoras one artifacts can now be added to the Maven/Gradle project as a dependency, for example using the following configuration:

edoras one dependencies in pom.xml for Maven builds
  -->
  <!-- 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.3</version>
  </dependency>

Do not forget to add a property called <com.edorasware.one.version>1.5.0.S80</com.edorasware.one.version> into the <properties> tag of the pom.xml.

edoras one dependencies in build.gradle for Gradle builds
  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.3:development"

Do not forget to define a variable called def edorasOneVersion = '1.5.0.S80' inside the build.gradle.

3.5. Database dependencies

In addition to the edoras one dependencies, at least one database dependency is also required. For convenience the pom.xml/build.gradle from the project already contains dependency for the most important databases:

Database dependencies in pom.xml for Maven builds
  -->
  <dependency>
      <groupId>postgresql</groupId>
      <artifactId>postgresql</artifactId>
      <version>9.2-1002.jdbc4</version>
  </dependency>
  
  <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.30</version>
  </dependency>
  
  <dependency>
      <groupId>com.h2database</groupId>
      <artifactId>h2</artifactId>
      <version>1.3.168</version>
  </dependency>
  
  <dependency>
      <groupId>org.springframework.data</groupId>
      <artifactId>spring-data-mongodb</artifactId>
      <version>1.5.0.RELEASE</version>
  </dependency>
Database dependencies in build.gradle for Gradle builds
  compile "postgresql:postgresql:9.2-1002.jdbc4"
  compile "mysql:mysql-connector-java:5.1.30"
  compile "com.h2database:h2:1.3.168"
  compile "org.springframework.data:spring-data-mongodb:1.5.0.RELEASE"

3.6. Logging dependencies

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. The following dependencies instruct SLF4J to collect all logging output and finally use the log4j logging framework to do the logging. Go to http://www.slf4j.org/ to learn more about SLF4J.

Logging dependencies in pom.xml for Maven builds
  -->
  <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-log4j12</artifactId>
      <version>${org.slf4j.version}</version>
  </dependency>
  
  <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>

Do not forget to add a property called <org.slf4j.version>1.7.7</org.slf4j.version> into the <properties> tag of the pom.xml.

Logging dependencies in build.gradle for Gradle builds
  compile "org.slf4j:slf4j-log4j12:$slf4jVersion"
  compile "org.slf4j:jul-to-slf4j:$slf4jVersion"
  compile "org.slf4j:jcl-over-slf4j:$slf4jVersion"
  
  // globally replace commons-logging with jcl-over-slf4j
  providedCompile "commons-logging:commons-logging:1.1.3"

Do not forget to define a variable called def slf4jVersion = '1.7.7' inside the build.gradle.

3.7. edoras one configuration

edoras one is configured using Spring.

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

To configure the on-premise project you will need to create the basic Spring configuration, for example in the default application context configuration file:

com/edorasware/one/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/one/config/one.properties" system-properties-mode="OVERRIDE"/>
  
      <!-- configure JUL-SLF4J rerouting since Activiti logs directly 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/one/config/database-config.xml"/>
  
      <!-- import the security configuration -->
      <import resource="classpath:/com/edorasware/one/config/security/security-${security.type:basic}-config.xml"/>
  
      <!-- import the integration configuration -->
      <import resource="classpath:/com/edorasware/one/config/integration-config.xml"/>
  
      <!-- import the content configuration -->
      <import resource="classpath:/com/edorasware/one/config/content-config.xml"/>
  
  </beans>

As you can see, the properties are read in using application defaults (provided by the on-premise WAR file) and possibly 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.

Each installation should also provide configurations for the database connection, security context, basic integration services and the content provider. These configurations are described separately in the following sections.

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).

3.7.1. Database configuration

In the example project, the database is configured in the com/edorasware/one/config/database-config.xml file loaded from the classpath. The different databases are configured with Spring profiles and if you want to externalize the database properties, then you can add them to the com/edorasware/one/config/one.properties properties file.

3.7.2. Security configuration

The application security is configured within the configuration folder com/edorasware/one/config/security. The standard configurations are provided for basic authentication (security-context-basic.xml):

com/edorasware/one/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-abstract-config.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="/login.html"
                               default-target-url="/"
                               always-use-default-target="false"
                               authentication-failure-url="/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="/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>

As you can see in the com/edorasware/one/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 create a file named security-extended-config.xml inside the com/edorasware/one/config/security folder and set the security.type to extended.

3.7.3. Integration configuration

The integration of edoras one with external systems is configured by the file integration-context.xml. Currently there are two profiles configured which define the mail sender bean which is used to send emails. Other integration configurations are described below.

3.8. Content configuration

The current content configuration com/edorasware/one/config/content-config.xml of edoras one defines the default content provider which stores the files on the file system.

3.8.1. Tenant initialization

To use edoras one, you need to create a tenant. 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.

3.8.2. Logging configuration

The default logging configuration is done by the log4j.properties file in the root package. An external logging configuration can be configured by setting the appropriate system property, for example by adding -Dlog4j.configuration=file:C:/tmp/log4j.properties to the application server command line.

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/jboss.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

3.8.3. Property settings

The default property settings are defined in the one.properties file located in the com/edorasware/one/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.

3.9. 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.

3.9.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

3.9.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

3.10. 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/one/config folder.

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

3.11. 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.

4. 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.

4.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).

4.2. 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.

4.3. 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.

4.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

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 provide UUID strings, we can create the Java class:

UuidService.java
  package com.edorasware.acme.expression;
  
  import java.util.UUID;
  
  /**
   * An example service bean that allows UUID strings to be created from a process model.
   */
  public class UuidService {
  
      /**
       * Returns a new UUID string.
       */
      public String getUuid() {
          return UUID.randomUUID().toString();
      }
  }

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

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

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/one/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,uuidService

Once the bean has been defined and made accessible, it can be used within process definitions. As an example we can write a UUID into a task name:

serviceBean

4.5. REST services

REST controller classes can be defined using the standard Spring annotations:

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

The individual REST endpoints are also defined using Spring annotations on the endpoint implementation methods. In this example the REST endpoint supports the typedText request parameter and returns a list of domains which will be encoded in JSON format, allowing it to be used with an auto-complete form widget:

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:

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

4.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 the REST controller defined above simply delegates the domain lookup to an 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>

5. App development workflow

5.1. 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

5.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 3. 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).

5.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 4. 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

5.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.

5.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 5. 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

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.

5.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.

5.7. 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.

Appendix A: IDE setup

This appendix gives step by step instructions to setup your integrated development environment.

A.1. Eclipse setup

The following instructions guide you through the set up of an edoras one project inside Eclipse.

During this procedure we will install the following software in a Windows 64-bit environment:

  • Eclipse package (Spring Tool Suite is recommended as edoras one uses the Spring framework internally)

  • SVN Team provider (Subversive)

  • Maven connector (Subversive)

If you have a different operating system or if you prefer a different Eclipse package or team provider then please adapt the instructions accordingly.

Please follow the instructions even if you have already installed an Eclipse package on your computer. Maybe your installation is missing some of the Eclipse plugins that we will use later in this tutorial. Reading the instructions will make this clear and then it is easy to add the missing Eclipse plugins to your installation.

A.1.1. Install Eclipse

Navigate your browser to http://spring.io/tools/sts/all and download an appropriate package. I usually download the native installer and not the archive.

springToolSuiteDownload

Start the downloaded installer and install Eclipse in a location of your choice. I usually install it in C:\Spring Tool Suite.

springToolSuiteInstallation

Start the installed Eclipse and create the default workspace in a location of your choice. In this tutorial I create the default workspace in my user home directory.

sprintToolSuiteCreateWorkspace

Select the HelpInstall New Software…​ menu item to open the Install dialog. In the Work with dropdown, choose the Eclipse update site that matches your Eclipse version (Kepler in this tutorial). Select Subversive SVN team provider in the Collaboration section of the Eclipse update site.

svnTeamProviderInstallation

Restart Eclipse when it asks you to do so.

Select the WindowPreferences menu item to open the preferences dialog. Choose the SVN preferences in the Team section. A dialog pops up if the Subversive SVN connector is not yet installed in your Eclipse installation. In that case select the latest SVN Kit connector and press the Finish button.

svnTeamProviderConnectorInstallation

Restart Eclipse when it asks you to do so.

Select the WindowPreferences menu item to open the Preferences dialog. Choose the Discovery preferences in the Maven section and press press the Open Catalog button. Click the m2e Marketplace link, select the m2e-subversive SVN handler and press the Finish button.

m2eSubversiveHandlerInstallation

Restart Eclipse when it asks you to do so.

Congratulations, you have finished the installation of Eclipse including all required plugins!

A.1.2. Configure 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

A.1.3. Add the edoras repository 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 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>
    ...

A.1.4. Import your edoras one project

There are two ways to import your edoras one project: from the file system or from the version control system.

First we look how to import a edoras one project from the file system. Ask support@edorasware.com for a edoras one project template packaged in a ZIP archive and extract the ZIP archive into your workspace. Select the FileImport…​ menu item to open the Import dialog. Select the Existing Maven Projects option in the Maven section and press the Next button. Press the Browse…​ button and choose your workspace as Root Directory. After Eclipse has analyzed the root directory it presents the edoras one project template in the Projects list. Press the Finish button to add that project to your workspace.

importMavenProjectFromFileSystem

The other option is to import a edoras one project from the version control system. Select the FileImport…​ menu item to open the Import dialog. Select the Check out Maven Projects from SCM option in the Maven section and press the Next button. Select the svn option and enter https://vcs.edorasware.com/svn/customers/example/trunk in the SCM URL field. Press the Finish button to add that project to your workspace.

importMavenProjectFromVersionControlSystem

A.1.5. Integrate 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 http://tomcat.apache.org/tomcat-7.0-doc/appdev/installation.html to learn how to install Tomcat in your local environment.

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

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 To`mcat 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 tomcat home directory of your installed tomcat web application server. Press the Finish button to create the application server inside Eclipse.

serverDefineTomcatServer

Select the WindowShow ViewOther…​ menu item to open the Show View dialog. Choose the Server option in the Server section and press the OK button. 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

Select the FileSave All menu item to save your changes.

Congratulations, you now have integrated the project embedded application server into Eclipse!

A.1.6. 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!

A.2. Intellij IDEA setup

TBD

Appendix B: 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.

B.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.

B.1.1. 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.

B.1.2. 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
  -->
  <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>

B.1.3. 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.

B.2. 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.

Appendix C: 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/libs/less/es5-shim.min.js"></script>
    <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.

C.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>

C.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.