Server

Variables and Configuration Pattern

Updated: May 27, 2021

This page provides information about all options available in the current Nuxeo framework.

Glossary

Let's review first the main concepts:

  • Environment variables: variables set in the OS that cannot be changed at runtime
  • System properties: variables set on the Java command line using the -Dpropertyname=value syntax, that can be added at runtime using System#setProperties or System.getProperties#load method, retrieved through the various System#getProperty methods.
  • Nuxeo configuration properties: variables set in the nuxeo.conf file.
  • Nuxeo template properties: variables set via Nuxeo configuration templates properties files loaded via Java properties utilities.

Variables Retrieval

Variables are retrieved and set at different phases of the Nuxeo application startup, the rest of the document will focus on:

  • Application startup: in this phase, ConfigurationGenerator logics will retrieve and aggregate some variables from all variables and properties described in the glossary. These variables will be taken into account for the Nuxeo Runtime startup.
  • Nuxeo Runtime startup: in this phase, the Nuxeo Runtime Framework will resolve XML configuration files for Nuxeo Runtime components: these files can reference variables that will be expanded, and can then be retrieved from Java code.

Application Startup

Pre-processing Initialization

Java class ConfigurationGenerator holds pre-processing logics that will impact the Runtime Properties Initialization. As a general rule, in case of duplicate keys for properties loaded during the different steps, the last loaded value will override the previous one:

  1. The map is initialized with properties held by file at NUXEO_HOME/templates/nuxeo.defaults.
  2. If an environment variable NUXEO_ENVIRONMENT is set, for instance to value prod, the map is then filled with properties held by file at NUXEO_HOME/templates/nuxeo.prod.
  3. The map is then filled with System properties via System#getProperties.
  4. The map is then filled with nuxeo.conf variable properties.
  5. Then templates are resolved thanks to the property nuxeo.templates (*). This resolution supports “included templates” resolution thanks to the nuxeo.template.includes property resolution. Templates are ordered so that they follow the declaration order, and so that included templates are taken into account before the template including them.
  6. If an environment variable NUXEO_PROFILES is set, the value is added to the list of templates previously resolved. Multiple profiles can be defined, separated by a comma.
  7. For each template, following the order of the list of template names previously resolved, the map is then filled by properties held by file at TEMPLATE_DIRECTORY/nuxeo.defaults, and if an environment variable NUXEO_ENVIRONMENT is set, for instance to value prod, the map is then filled with properties held by file at TEMPLATE_DIRECTORY/nuxeo.prod. Note that TEMPLATE_DIRECTORY can either stand for the template name (in which case the sub-directory with this name will be resolved inside the NUXEO_HOME/templates/ directory), or an absolute directory path.

These steps are covered by environment variables expansion explained below.

Pre-processing Environment Variables Expansion

During preprocessing, properties pushed to the main map can be expanded when they are declared with the pattern ${env:VARIABLE_NAME} or ${env:VARIABLE_NAME:defaultValue}, for nuxeo.conf templates and for properties held by templates.

Values are replaced according to environment variables: for the given property name, the value returned by System#getEnv will be used, and will default to the defaultValue if specified, or to an empty string.

Although all resolutions can follow this pattern, this is specifically useful to declare additional Nuxeo configuration templates:

nuxeo.templates=default,common,testinclude,${env:TEST_ENV:testenv}

Template properties resolution was introduced to cover a deployment use case, so that a docker image can be run in a specific target environment, with a pre-constructed map of values that can/should be controlled by the environment, in the docker run command line:

docker run -e NUXEO_ENVIRONMENT=prod -e NUXEO_PROFILES=the-deploy-template-name image

Pre-processing Environment

The complete resulting map is written in the file at NUXEO_HOME/nxserver/config/configuration.properties at server startup, so that it can be processed at Nuxeo Runtime startup.

If the configuration is saved (behaviour controlled by specific property nuxeo.force.generation), new properties and properties which resolve to a new value will be written to the nuxeo.conf file (properties which value was expanded are not taken into account).

The method ConfigurationGenerator#getEnv returns a java object holding the same map, except it is first initialized with the content of the NUXEO_HOME/templates/common/config/distribution.properties file. This environment is retrieved by nuxeo-launcher and by nuxeo-connect-standalone, and is useful for Nuxeo Packages management logics.

DeploymentPreprocessor Templates Variables Expansion

Java class DeploymentPreprocessor logics are also covered by variable expansion using the following patterns:

${propertyName}

Or:

${propertyName:=defaultValue}

The map used for expansion is a bit different and includes the following:

  1. A default environment is created, using a map filled with System properties, and some selected additional properties are added to this map.
  2. Then the map is filled with properties defined in the NUXEO_HOME/nxserver/system.properties files.
  3. Then the properties computed during pre-processing are added.

These steps are covered by environment variables expansion explained below.

Variable expansion happens when running copy/append commands (and alike) declared in the deployment-fragment.xml file: content is processed to replace variables using the resulting properties map. The replacement is recursive in case the property references another property.

This is useful to control configuration added to the web.xml, or other preprocessor template files defined in NUXEO_HOME/nxserver/META-INF like faces-config.xml. Here’s an example from JSF:

<context-param>
  <param-name>javax.faces.FACELETS_REFRESH_PERIOD</param-name>
  <param-value>${javax.faces.FACELETS_REFRESH_PERIOD:=-1}</param-value>
</context-param>

Nuxeo Runtime Startup

The properties map available to the runtime framework after startup differs from the one handled during pre-processing: let’s start by explaining how this property map is defined, and what kind of variable expansion is supported.

Then let’s summarize the various options to define and retrieve properties for the Nuxeo Runtime XML Components configurations (that have been documented here).

Runtime Properties Initialization

RuntimeService implementations holds API that will be used by Framework#getProperty and Framework#expandVars methods.

As a general rule, in case of duplicate keys for properties loaded during the different steps, the last loaded value will override the previous one:

  1. The map is initialized with System properties (although those should also be included in the configuration.properties file, they might differ from them as the Java process is not the same, see NuxeoLaucher#start logics)
  2. The map is then filled with properties loaded from all files in the NUXEO_HOME/nxserver/config directory ending with .config, .ini or .properties, sorted alphabetically, ignoring case. These files include the configuration.properties file that was written during pre-processing.

At this stage, properties are not expanded yet: variables expansion mechanism is explained below.

As a reference, here is the ordered list of configuration files (except from the configuration.properties file, these are setup by common-base and common templates):

  • configuration.properties
  • distribution.properties
  • jms.properties
  • nuxeo-tomcat.properties
  • nuxeo-webapp-core.properties
  • nuxeo.properties
  • quartz.properties
  • webengine.properties

Runtime Properties Variables Expansion

During Runtime startup, properties pushed to the main map can be expanded when they are declared with the pattern ${propertyName} or ${propertyName:=defaultValue}.

This expansion happens on-the-fly when calling the getter methods Framework#getProperty or Framework#expandVars.

Expansion happens within the map of properties described above, and can be recursive: it is possible to define a property and reference it in another property, for instance:

elasticsearch.indexName=nuxeo
audit.elasticsearch.indexName=${elasticsearch.indexName}-audit
seqgen.elasticsearch.indexName=${elasticsearch.indexName}-uidgen

Runtime Components Variables Expansion

All Nuxeo runtime registration files are parsed so that their variables are expanded, before the content is processed by the Runtime framework: this allows XML configurations to hold variables in any place of the XML content with the same pattern:

${propertyName}

Or:

${propertyName:=defaultValue}

If the Nuxeo Runtime properties hold the variable name, it will be resolved, otherwise the defaultValue will be used, or an empty string if not defined.

XML content is parsed as a single string: variables can be placed anywhere in the content.

Component Properties

Java components accept "simple" properties configuration, the drawback is that these properties cannot be overridden via XML contributions:

<?xml version="1.0"?>
<component name="org.mycompany.myproject.MyService">

  <implementation class="org.mycompany.myproject.MyComponent" />
  <property name="myProp" value="myValue" />

</component>

Of course the value can also hold a mapping to resolve the value from a Nuxeo Runtime property:

<?xml version="1.0"?>
<component name="org.mycompany.myproject.MyService">

  <implementation class="org.mycompany.myproject.MyComponent" />
  <property name="myProp" value="${propertyName:=defaultValue}" />

</component>

This property can then be resolved from the component code when activating the component:

public class MyComponent extends DefaultComponent {

    @Override
    public void activate(ComponentContext context) {
        String myPropValue = (String) context.getPropertyValue("myProp");
    }

}

ConfigurationService Properties

The ConfigurationService runtime component was designed to declare simple configurations, so that they can be documented and overridden via XML contributions:

<?xml version="1.0"?>
<component name="org.mycompany.myproject.MyService">

  <implementation class="org.mycompany.myproject.MyComponent" />

  <extension target="org.nuxeo.runtime.ConfigurationService" point="configuration">
    <documentation>
      This configuration property can be documented here. HTML tags are accepted.
    </documentation>
    <property name="org.mycompany.myproject.myprop">myDefaultValue</property>
  </extension>

</component>

From the component code, that property can be retrieved from the Runtime framework, after starting the component, for instance (to make sure ConfigurationService is available):

import org.nuxeo.runtime.services.config.ConfigurationService;

public class MyComponent extends DefaultComponent {

    protected static final String MY_PROP_NAME = "org.mycompany.myproject.myprop";

    @Override
    public void start(ComponentContext context) {
        super.start(context);
        String myPropValue = Framework.getService(ConfigurationService.class).getString(MY_PROP_NAME);
    }

}

ConfigurationService Properties Mixed With Properties

Using the ConfigurationService and a Runtime property can be combined, by referencing a variable expression in the ConfigurationService contribution:

<extension target="org.nuxeo.runtime.ConfigurationService" point="configuration">
  <property name="org.mycompany.myproject.myprop">
    ${propertyName:=myDefaultValue}
  </property>
</extension>

These properties can be retrieved from the JAVA API in the same way as in the previous case, through the ConfigurationService API.

Note that if a ConfigurationService contribution uses the same property name than a Runtime property, a warning will be issued at startup, to avoid confusions and ease up migrations, as a number of properties were moved out of nuxeo.conf files to be declared to the ConfigurationService when it was introduced. Variable expansion still applies, if it can help with migrations: if the code looks for this value on the ConfigurationService and a static value is used for it instead of an expression, the property with the same name declared in the nuxeo.conf file, for instance, will not be taken into account.

We'd love to hear your thoughts!

All fields required