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:
./gradlew createSkeletonProject
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
:
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>
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:
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:
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.
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
.
<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.
build.gradle
for Gradle builds repositories {
maven {
credentials {
username DOWNLOAD_REPO_USERNAME
password DOWNLOAD_REPO_PASSWORD
}
url "https://repo.edorasware.com/edoras-repo"
}
}
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
.
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:
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:
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:
build.gradle
def edorasOneVersion = '@projectVersion@'
This property can then be used in the dependency configuration to import the required dependencies:
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:
pom.xml
for Maven builds <dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.3.168</version>
</dependency>
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:
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:
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:
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:
build.gradle
def slf4jVersion = '1.7.7'
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:
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:
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</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/security-${security.type:basic}-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="dataSource" class="org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy">
<property name="targetDataSource">
<bean class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="org.h2.Driver"/>
<property name="url" value="jdbc:h2:file:~/.edoras-one/db/acme;IGNORECASE=TRUE;AUTO_SERVER=TRUE"/>
<property name="username" value="sa"/>
<property name="password" value=""/>
<property name="validationQuery" value="select 1"/>
<property name="maxActive" value="4"/>
<property name="maxWait" value="30000"/>
</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-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>
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:
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.
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>
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>
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:
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 Window
⇒ Preferences
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.
5.9.5. Import the bootstrap project into your workspace
Select the File
⇒ Import…
menu item to open the project import dialog. Then select Existing Maven Projects
:
Then select the folder where you have extracted the bootstrap project:
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 File
⇒ New
⇒ Other…
menu
item to open the Select a Wizard
dialog. Choose the Server
option in the Server
section and press the Next
button.
In the Define a New Server
page of the wizard, choose the Tomcat 7.0 Server
type and press the Next
button.
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.
Select the Window
⇒ Show View
⇒ Servers
menu item.
This brings you to the Servers
view.
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.
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.
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 File
⇒ Save 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.
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 File
⇒ Open…
menu item from an existing project.
Select the Maven pom.xml
(or Gradle build.gradle
) from the folder where you extracted the bootstrap project:
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 File
⇒ Project Structure…
and check that the Project language level
is set to 7
:
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 Run
⇒ Edit Configurations…
menu
item to open the run configuration dialog:
Select the +
icon to add a new run configuration, and then select Tomcat Server
⇒ Local
.
Give the run configuration a suitable name (e.g. bootstrap
), and configure the installed Tomcat application
server using the Configure…
button.
Add the bootstrap deployment artifact by selecting the Deployment
tab and adding the
deployment artifact edoras-one-bootstrap:war exploded
:
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.
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:
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:
<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.
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
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:
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:
<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:
# 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,modelManager
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:
6.4.1. 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.5. REST services
REST controller classes in edoras one are defined as plain Java classes annotated with the standard Spring Web annotations:
/**
* 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:
/**
* 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:
<!-- 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 '/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:
/**
* 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.
6.5.3. Supporting the edoras form Dynamic Link Button widget
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
):
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:
<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. Defining App development workflows
7.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:
7.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:
Property | Description |
---|---|
|
the App storage base directory |
|
a descriptive channel name |
|
a Spring Integration channel to receive outgoing App notification messages |
|
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).
7.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
Header | Type | Description |
---|---|---|
|
|
the current App name (this may change over time) |
|
|
the App source ID (constant across all systems) |
|
|
a comment supplied when the App distribution was triggered |
|
|
the name of the originating tenant |
7.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.
7.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
Header | Type | Default | Description |
---|---|---|---|
|
Boolean |
false |
Set to true if the incoming app is the system app |
|
Boolean |
true |
Set to true if the app should be editable after import |
|
Boolean |
false |
Set to true if the incoming app should be removed after import |
|
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. |
7.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.
|
7.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 correspondingspringframework.core.io.Resource
payload, preserving all message headers.
8. Deployment
8.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.
8.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:
<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 thesettings.xml
file is stored in~/.m2/settings.xml
. See http://maven.apache.org/settings.html#Servers to learn more about the Mavensettings.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 namedcontentdb
that stores the document content.
Putting all this together, the Cloud Foundry plugin section looks as follows:
<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.
<!-- 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).
<servers>
<server>
<id>run.pivotal.io</id>
<username>user</username>
<password>pass</password>
</server>
</servers>
8.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.
8.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 |
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:
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.
8.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/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.
8.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>
8.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. |
8.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:
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.
8.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.
8.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
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
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"
8.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
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
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"