<properties>
<version.swarm>2017.7.0</version.swarm>
<version.swarm.fraction-plugin>57</version.swarm.fraction-plugin>
</properties>
Fraction Authoring
Introduction
The composable pieces of WildFly Swarm are called fractions. Each fraction starts with a single Maven-addressable artifact which may transitively bring in others.
The pom.xml
It is useful to set at least a pair of properties, specifying the version of the WildFly Swarm SPI and fraction-plugin being used:
You can include all of the primary bits of WildFly Swarm using the
bom-all
artifact in a <dependencyManagement>
import. Additionally,
you’ll need two more dependencies added in order to write CDI components
to configure the server.
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.wildfly.swarm</groupId>
<artifactId>bom-all</artifactId>
<version>${version.swarm}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.enterprise</groupId>
<artifactId>cdi-api</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
Additionally, the wildfly-swarm-fraction-plugin
should be configured
within the parent pom.xml
so that it fires for every sub-module:
<build>
<plugins>
<plugin>
<groupId>org.wildfly.swarm</groupId>
<artifactId>wildfly-swarm-fraction-plugin</artifactId>
<version>${version.swarm.fraction-plugin}</version>
<executions>
<execution>
<phase>process-classes</phase>
<goals>
<goal>process</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
What’s in a Fraction
A "fraction" can include all or none of the following components. Ultimately a fraction contributes configuration or capabilities to a runtime system.
Package Layout
For a given fraction, a unique package root is required. In the usual
case of the core code, it matches the pattern of org.wildfly.swarm.CAPABILITY
,
such as org.wildfly.swarm.undertow
or org.wildfly.swarm.naming
.
Within the root the following additional sub-packages may be found:
-
deployment
-
detect
-
internal
-
runtime
The org.wildfly.swarm.CAPABILITY.detect
package holds classes that are
used for determining if the fraction applies to a given deployment.
The org.wildfly.swarm.CAPABILITY.runtime
and org.wildfly.swarm.CAPABILITY.internal
package holds classes that are considered "back-end" components, loaded via our
internal CDI implementation in order to configure and setup the server.
The org.wildfly.swarm.CAPABILITY.deployment
package holds other classes
that should not be considered either part of the front-end API of the fraction
exposed to users, nor a part of the back-end components to configure the
server. Instead, the .deployment
package is a sidecar to hold additional
classes that may be added to deployment archives.
The module.conf
Alongside your pom.xm
you need at least an empty module.conf
file to signal
the plugin that your build is actually a fraction.
This file is used to enumerate the JBoss-Modules dependencies your fraction
may have, and helps produce the resulting module.xml
files for your fraction.
In this file, one per line, you may list the module dependencies you may have. If your fraction relies on runtime linking to other fractions, they should typically be listed in this file.
org.jboss.logging
org.wildfly.swarm.undertow
Maven Artifact Dependencies
You cannot specify maven artifact style dependencies in the module.conf file. If you have such dependencies, you need to create a JBoss-Modules module.xml descriptor in your fraction’s src/main/resources/modules directory. For example, the org.wildfly.swarm:fluentd fraction includes the following src/main/resources/modules/org/fluentd/main/module.xml to declare dependencies on:
-
org.fluentd:fluent-logger:${fluentd.version}
-
org.msgpack:msgpack:0.6.8
-
com.googlecode.json-simple:json-simple:1.1.1
-
org.javassist:javassist:3.18.1-GA
-
org.slf4j:slf4j-api:1.7.7.jbossorg-1
-
org.jboss.logmanager:jboss-logmanager-ext:${version.jboss-logmanager-ext}
<?xml version="1.0" ?>
<module xmlns="urn:jboss:module:1.3" name="org.fluentd">
<resources>
<artifact name="org.fluentd:fluent-logger:${fluentd.version}"/>
<artifact name="org.msgpack:msgpack:0.6.8"/>
<artifact name="com.googlecode.json-simple:json-simple:1.1.1"/>
<artifact name="org.javassist:javassist:3.18.1-GA"/>
<artifact name="org.slf4j:slf4j-api:1.7.7.jbossorg-1"/>
<artifact name="org.jboss.logmanager:jboss-logmanager-ext:${version.jboss-logmanager-ext}"/>
</resources>
<dependencies>
<module name="org.jboss.logmanager"/>
<module name="javax.json.api"/>
<module name="javax.xml.stream.api"/>
</dependencies>
</module>
For more information on the syntax of the JBoss-Modules module.xml descriptor, see https://jboss-modules.github.io/jboss-modules/manual/.
Generated modules
The wildfly-swarm-fraction-plugin generates a number of module.xml descriptors depending on what features it has found in the faction. You may override any one of these descriptors by providing the corresponding module.xml in your src/main/resources/modules directory.
-
api: this is a module definition that depends on all modules specified in module.conf + swarm container and cdi modules, the fraction artifact, excluding the <fraction-root-package>/{runtime,deployment} packages if they exist. It is used to configure fractions, container, etc, when running in Uber jar mode when JBoss-Modules is fully active
-
deployment: is a module definition that depends on all modules specified in module.conf, the fraction:main module, excluding the <fraction-root-package>/{runtime,META-INF} paths, the fraction artifact excluding the <fraction-root-package>/{runtime,internal,META-INF} packages. This module is automatically added as a module dependency to any deployments. It’s a convenient way to had code into the user deployment for handling integrations with the container.
-
main: This is a module definition similar to API, but active when running from IDE or wildfly-swarm:run
-
runtime: this is a module definition that depends on the fraction artifact with the root excluded, the main module, swarm and cdi modules, and all modules in module.conf. This module is used to load the fraction and any of its runtime code. These modules are what JBoss Modules loads for use by the WF self contained server to make extensions, subsystems, etc available for the deployment.
The *Fraction.java
If the fraction includes configuration capabilities, or otherwise alters
the runtime system through deployments or adjustments to the server, it
may include an implementation of org.wildfly.swarm.spi.api.Fraction
.
Any opaque POJO configuration details that are required may be added in the implementation, and will be made available to the back-end runtime portion during server boot-up to control configuration.
In the event that no particular configuration values are required, no
Fraction
implementation is required. If provided, it should reside in the
absolute root of the fraction java package, such as org.wildfly.swarm.undertow.UndertowFraction
.
package com.mycorp.cheese;
import java.util.Set;
import java.util.HashSet;
import org.wildfly.swarm.spi.api.Fraction;
public class CheeseFraction implements Fraction {
// arbitrary configuration parameters are allowed
public void cheese(String type) {
this.cheeses.add( type );
}
public void cheeses(Set<String> types) {
this.cheeses.addAll( types );
}
public Set<String> cheeses() {
return this.cheeses;
}
private Set<String> cheeses = new HashSet<>();
}
Runtime CDI Components
Within the runtime
sub-package of the fraction, a variety of CDI-enabled
components may be used. Within these classes, you can use typical CDI mechanisms
such as @Inject
, @Produces
, and Instance<>
in order to accomplish whatever
is required for your fraction. Typically these components would, at the minimum,
inject their own fraction. They should each be marked as @Singleton
.
@Singleton
public class MyComponents implements Whatever {
@Inject
private MyFraction myFraction;
}
DeploymentProcessor
If your fraction needs an opportunity to alter or otherwise prepare all deployed
archives, you may implement the org.wildfly.swarm.spi.api.DeploymentProcessor
interface.
@DeploymentScoped
public class MyArchivePreparer implements DeploymentProcessor {
private final Archive archive;
@Inject
private MyFraction myFraction;
@Inject
public MyArchivePreparer(Archive archive) {
this.archive = archive;
}
@Override
public void process() throws Exception {
WARArchive war = archive.as(WARArchive.class);
...
}
}
Useful Annotations
There are a few additional annotations that you may include on your fraction class:
-
@WildFlyExtension(module = "org.keycloak.keycloak-adapter-subsystem"), if the fraction is installed, then the named WildFly Extension will also be installed. This is equivalent to the <extension> element in the WildFly standalone.xml.
-
@WildFlySubsystem("keycloak"), if the fraction is installed, then the named WildFly Subsystem will also be included. This is equivalent to the <subsystem> element in the WildFly standalone.xml.
-
@DeploymentModule(name = "org.keycloak.keycloak-core") adds the indicated module dependency to the deployment archives that are appropriate to a fraction.
Injecting IndexView
If your fraction needs an opportunity to process the Jandex metadata of all deployed
archives, you can inject org.jboss.jandex.IndexView
into your DeploymentProcessor
instance, e.g.
@DeploymentScoped
public class ServiceClientProcessor implements DeploymentProcessor {
private final Archive<?> archive;
private final IndexView index;
@Inject
public ServiceClientProcessor(Archive archive, IndexView index) {
this.archive = archive;
this.index = index;
}
}
Customizer
Most of the heavy-lifting of configuration may occur within implementations of
org.wildfly.swarm.spi.api.Customizer
.
If your fraction is always present with other fractions, cross-fraction manipulation may be achieved.
Two different executions of Customizers
occur. All customizers annotated with
@Pre
are fired, followed by all annotated with @Post
.
@Post
@Singleton
public class MyCustomizer implements Customizer {
@Inject
private MyFraction myFraction;
@Inject
private UndertowFraction undertowFraction;
public void customize() {
if ( undertowHasSSL() ) {
doSomethingSpecialWithMyFraction()
}
}
}
Archive
producers
In some cases, a fraction implicitly produces a deployment archive by its simple
presence in the dependency graph. For example, including org.wildfly.swarm:jolokia
ensures that the Jolokia web-app is deployed. This is accomplished by having a CDI
component that @Produces
a ShrinkWrap Archive
. No particular interface is required
to be implemented.
@Singleton
public MyArchiveProducers {
@Inject
private MyFraction myFraction;
@Produces
Archive myManagementConsole() {
WARArchive archive = ... // produces the Archive any way you like
archive.setContextRoot( myFraction.getContextRoot() );
return archive;
}
}
The @ConfigurationValue
annotation
Any of your components can also @Inject
configuration values that
are sourced from either project-defaults.yml
based upon the currently
active stage, or system properties if no project stage is available.
@Inject @ConfigurationValue('my.db.url')
private String dbUrl;
@Inject @ConfigurationValue('my.age')
private int age;
Transitive dependencies
If your fraction depends upon the presence of a Servlet container being
configured, you should add a dependency on the necessary fractions into
your pom.xml
<dependencies>
<dependency>
<groupId>org.wildfly.swarm</groupId>
<artifactId>undertow</artifactId>
</dependency>
</dependencies>
By doing this, a user must only include your fraction, and the Undertow fraction will be dragged along implicitly into their application.