Configuration overlays using stage properties

In some cases it may be desirable to extract some of the configuration properties and switch them depending on the target environment. Project stages are a way to move environment specific configuration properties into an external file.

project-stages.yml

A stage configuration is represented in an external YAML file:

logger:
    level: DEBUG
swarm:
  port:
    offset: 10
---
project:
    stage: development
logger:
    level: DEBUG
swarm:
  port:
    offset: 50
---
project:
    stage: production
logger:
    level: INFO
swarm:
  port:
    offset: 100

Project Stage Definitions

In this example some of configuration values are kept externally. The file contains multiple yaml documents (separated by ---) and the project: stage: <name> definition indicates which key can be used to enable a stage. To use these stage properties you’d need to explicitly reference this file during Container bootstrap:

Container Bootstrap

ClassLoader cl = Main.class.getClassLoader();
URL stageConfig = cl.getResource("project-stages.yml");

Swarm swarm = new Swarm(false)
       .withStageConfig(stageConfig);
[...]
Note
Auto detection picks up project-stages.yml from src/main/resources

Command-line switches / System Properties

Two notable command-line switches are available to easily re-configure Swarm in different environments:

System Property Example Purpose

swarm.project.stage

-Dswarm.project.stage=<stage name>

Enables a specific stage (fallback to System environment variable SWARM_PROJECT_STAGE or default if neither exists)

swarm.project.stage.file

-Dswarm.project.stage.file=<URL>

Allows to reference a different project-stages.yml file

Referencing Stage Configuration Values

The stage configuration properties are internally resolved to simple properties:

YAML Internal

swarm: port: offset:

swarm.port.offset

logger: level:

logger.level

Internally there are three ways to get hold of stage configuration values.

  1. Reference them as expressions (standalone.xml)

  2. Retrieve them through StageConfig

  3. Inject them in CDI contexts

Using Expressions

The fist case is useful when you work with standalone.xml and still need to extract environment specific properties. In this cases you can make use of regular WildFly expressions in XML:

<subsystem xmlns="urn:jboss:domain:logging:3.0">
  <console-handler name="CONSOLE">
      <level name="${logger.level:INFO}"/>
      <formatter>
          <named-formatter name="COLOR-PATTERN"/>
      </formatter>
  </console-handler>
  <root-logger>
      <level name="${logger.level:INFO}"/>
      <handlers>
          <handler name="CONSOLE"/>
      </handlers>
  </root-logger>
  [...]
</subsystem>

Here the stage configuration logger.level is referenced using the expression syntax ${logger.level:INFO} (INFO is the fallback value).

Using StageConfig

StageConfig is the java type representing the former YAML file. It allows you to access named properties following the standard java properties name syntax (i.e. logger.level)

It is available in two places:

  1. Injectable into Customizers, ArchivePreparers, etc

  2. From Swarm

The first case is intended to be used by Fraction authors if they need to hook into the stage configuration for the default configuration of a fraction itself.

The later case is intended for users to combine stage and fraction configuration in a custom Main():

Swarm swarm = new Swarm(false)
              .withStageConfig(stageConfig);

swarm.fraction(
  new DatasourcesFraction()
    .jdbcDriver("h2", (d) -> {
        d.driverClassName("org.h2.Driver");
        d.xaDatasourceClass("org.h2.jdbcx.JdbcDataSource");
        d.driverModuleName("com.h2database.h2");
    })
    .dataSource("ExampleDS", (ds) -> {

        ds.driverName("h2");

        ds.connectionUrl(
                // referencing stage configuration values
                swarm
                        .stageConfig()
                        .resolve("database.connection.url")
                        .getValue()
        );
        ds.userName("sa");
        ds.password("sa");
    })
);

In this example the datasource#connectionUrl() is resolved from a stage configuration value. The stage configuration is exposed through the container.