Initial support for declarative configuration

Programmatic and declarative configuration

The common and only way to configure wildfly-swarm nodes was to use the Java API. With the inclusion of SWARM-14, external, declarative configuration of wildfly-swarm nodes becomes possible.

Typically you would rely on the config-api to configure any of the subsystems the container leverages:

Java API (i.e. Main.java)
return new DatasourcesFraction()
    .jdbcDriver("h2", (d) -> {
        d.driverDatasourceClassName("org.h2.Driver");
        d.xaDatasourceClass("org.h2.jdbcx.JdbcDataSource");
        d.driverModuleName("com.h2database.h2");
    })
    .dataSource("ExampleDS", (ds) -> {
        ds.driverName("h2");
        ds.connectionUrl("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE");
        ds.userName("sa");
        ds.password("sa");
    });

With the additional support for declarative configuration, you can push the subsystem configurations into an external XML file. If you have previous experience with Wildfly itself, then this should be familiar to you:

XML Configuration (i.e. standalone.xml)
<subsystem xmlns="urn:jboss:domain:datasources:4.0">
     <datasources>
        <datasource jndi-name="java:jboss/datasources/ExampleDS" pool-name="ExampleDS" enabled="true" use-java-context="true">
            <connection-url>jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE</connection-url>
            <driver>h2</driver>
                <security>
                    <user-name>sa</user-name>
                    <password>sa</password>
                </security>
            </datasource>
            <drivers>
            <driver name="h2" module="com.h2database.h2">
                <datasource-class>org.h2.Driver</datasource-class>
                    <xa-datasource-class>org.h2.jdbcx.JdbcDataSource</xa-datasource-class>
                 </driver>
            </drivers>
    </datasources>
</subsystem>

The notable change to container API is an extended constructor that allows you to reference an XML configuration file:

    // reference a configuration file
    URL xmlConfig = cl.getResource("standalone.xml");

    // launch the container pointing it to the XML file
    Container container = new Container(false, xmlConfig);

    // add the fractions needed
    container.fraction(new DatasourcesFraction());

    // Start the container
    container.start();

Relation of fractions and wildfly extensions

If you migrate from wildfly to swarm you would typically already have a standalone.xml file. Maybe you already configured and tested your services using a regular wildfly installation or because you are in the process of decomposing a larger application into a set of services based on swarm.

The top of 'standalone.xml' file contains a series of <extension module="…​"/> elements. In wildfly these are used to determine the capabilities provided by the runtime. I.e. whether messaging or datasources are supported and the corresponding services and API’s are available.

In swarm we take a slightly different approach. The runtime capabilities are represented by fractions, shipped as maven artifacts. The inclusion of the dependencies in your build file determines what functionality will be available to your application. Many of these fractions provide 'extensions' to the wildfly runtime, but the details to integrate these are hidden behind the wildfly-swarm maven plugin.

The current implementation to support declarative configuration retains this pattern. You have to declare maven dependencies on fractions to express what runtime capabilities your application requires and the swarm plugin does the assembly and put’s everything where it needs to be.

When we parse external XML configurations, we basically ignore the <extensions/> section of the file and all subsystem declarations for which we don’t find any matching fractions. This lenient approach allows you to focus on those parts of the XML configuration that matters and should simplify migration from wildfly to wildfly-swarm.

Caveats and gotchas

As described before, the parser simply logs warning messages for subsystems that are declared in the XML, but don’t have a corresponding fraction dependency. It’s advised to remove the part’s you don’t need.

The relation between fractions and subsystems is not well documented at the moment, which would be a precursor to successfully trim the XML.

Some subsystem don’t have corresponding fractions or the fractions have not yet been modified to support declarative configuration, but we work on improving both cases. These fractions currently support declarative configuration:

  • Datasources

  • EE

  • IO

  • JAXRS

  • JCA

  • Logging

  • Naming

  • Remoting

  • Security

  • Transactions

  • Undertow

A much bigger challenge is that the XML configuration doesn’t provide defaults that have been verified within the swarm context. When leveraging the Java API to configure the fractions, you implicitly rely on default configuration values that the swarm team has build into each fraction. However when you migrate from wildfly and carry over the standalone.xml that’s not the case. As a result some things may work differently or not at all.

When you run into problems, get in touch with us on IRC.

The road ahead

First of all we will extend support for declarative configurations to other fractions. With regard to this we will also work to improve the documentation, in particular focusing on the changes needed to successfully migrate from wildfly using an existing standalone.xml.

In addition to this, we’ll investigate ways to leverage the <extension/> and <subsystem/> elements that might be given in and XML file, to determine what fractions need to be packaged with your application. But this is an area with a lot of uncertainty, in particular around the question whether the XML is an appropriate vehicle to express the dependencies between fractions, modules, subsystems ,etc.