Pre-processors allow us to perform actions on the Interlok configuration before it is unmarshalled and the Interlok instance starts up. The original configuration will not be modified by this process and the following general rules will apply:
- Multiple pre-processors may be configured, which will be executed in the order they are configured.
- Each pre-processor configured will have access to the referenced configuration file and may change that content.
- The first pre-processor will have access to the configuration verbatim from the configuration file.
- Each subsequent pre-processor will be handed over the configuration from the previous pre-processor.
- Standard ENTITY references are handled in a pre-processor dependent way; we recommend that you don’t use ENTITY if you are using pre-processors.
Configuration of Pre-Processors
Although each pre-processor may require their own separate configuration file(s); pre-processors are activated if bootstrap.properties
contains a preProcessors
key. All configuration pre-processors are optional, and may require additional libraries to be copied into your installation.
Each pre-processor can be configured colon separated as the value to this property. e.g
preProcessors=variableSubstitution:schema
Available Pre-Processors
PreProcessor Name | Description |
---|---|
variableSubstitution | Perform variable substitution based on a previously defined property file (requires optional/varsub ) |
systemProperties | Perform variable substition based on system properties (since 3.0.1 and requires optional/varsub ) |
environmentVariables | Perform variable substition based on environment Variables (since 3.0.1 and requires optional/varsub ) |
schema | Validate (optional generation) of adapter configuration against a specified schema file (requires optional/schema ) |
xinclude | Include other XML documents into configuration using <xi:include> tags (requires optional/xinclude ) |
xslt | Execute a transform on the configuration file before unmarshalling (requires optional/xinclude ) |
Variable Substitution
This pre-processor allows you to configure place-holders in your Interlok configuration, which will be swapped out with values configured in a separate property file. The idea is that multiple environments that require almost identical configuration can more easily be set-up by simply duplicating the main Interlok configuration files across all environments.
Typically broker URL’s, usernames, passwords and destination values would be a fair use for variable substitution.
Additional Configuration
The following properties can be specified in the bootstrap.properties to control the behaviour of the variable substitution;
Property | Default | Mandatory | Description |
---|---|---|---|
variable-substitution.varprefix | ${ | No | The value here will be prefixed to the variable name to search for in the configuration to be switched out. |
variable-substitution.varpostfix | } | No | The value here will be appended to the variable name to search for in the configuration to be switched out. |
variable-substitution.properties.url | Yes | The URL to the property file containing the list of substitutions; in the form of variableName=Value. Multiple files are supported by adding a unique suffix for each filename which are then sorted before processing. | |
variable-substitution.url.useHostname | false | No | since 3.7.1 if set to true, then each URL defined by variable-substitution.properties.url will be formatted passing in the hostname as the 1st parameter. |
variable-substitution.impl | simple | No | The substitution engine that will perform the variable substitution. Since 3.1.0 simple, simpleWithLogging, strict, strictWithLogging are available. |
If you have in your bootstrap.properties :
preProcessors=variableSubstitution
variable-substitution.properties.url.1=file://localhost//path/to/my/shared-variables
variable-substitution.properties.url.3=file://localhost//path/to/my/variables-%1$s
variable-substitution.properties.url.2=file://localhost//path/to/my/local-variables
variable-substitution.url.useHostname=true
Assuming that your hostname is localhost.localdomain then the following files will be read /path/to/my/shared-variables
, /path/to/my/local-variables
, /path/to/my/variables-localhost.localdomain
(in that order due to sort order) to resolve any variables. The last defined property takes precedence. After reading in the variables, let’s assume that it contains :
broker.url=tcp://localhost:2506
broker.backup.url=tcp://my.host:2507
Then all instances of “${broker.url}” and “${broker.backup.url}” will be replaced within your Interlok configuration before Interlok starts up. In addition to a pre-processor there is also a xstream-varsub-marshaller that can be used where you might normally configure a xstream-marshaller.
Since 3.0.1 variable definitions may refer to other variable definitions, system properties, and environment variables. They will be resolved in that order so a variable definition will always take precedence over a system property and so on. This means that on a Windows machine, the following properties file would be perfectly acceptable
adapter.unique.id=Interlok
adapter.fs.base.url=file://localhost/c:/adaptris/interlok/fs/${adapter.unique.id}/${user.name}
adapter.consume.fs.url=${adapter.fs.base.url}/${COMPUTERNAME}/in
${adapter.unique.id}
will be resolved from the previous definintion.${user.name}
will be resolved from the standard java system property${COMPUTERNAME}
will be resolved from the environment.
Since 3.1.0 additional implementations have been made available which will have slightly different behaviour based on whether variable substitution has occurred for all variable definitions found in configuration. simple and simpleWithLogging will log a warning after performing substitutions if there are any remaining variables that have not been substituted
TRACE [main] [VariableSubstitution] Replacing ${adapter.unique.id} with interlok-xxe
WARN [main] [VariableSubstitution] ${adapter.transform.url} is undefined for variable substitution
strict and strictWithLogging will throw an exception after performing substitutions if there are any remaining variables that have not been substituted and may terminate the adapter process.
TRACE [main] [VariableSubstitution] Replacing ${adapter.unique.id} with interlok-xxe
Exception in thread "main" com.adaptris.core.CoreException: ${adapter.transform.url} is undefined for variable substitution
at com.adaptris.core.varsub.D.o00000(SimpleStringSubstitution.java:59)
at com.adaptris.core.varsub.D.doSubstitution(SimpleStringSubstitution.java:49)
System Properties
Similar to variable substitution this pre-processor allows you to configure place-holders in your Interlok configuration, these will be swapped out for the corresponding system property values. The idea is that multiple environments that require almost identical configuration can more easily be set-up by simply duplicating the main Interlok configuration files across all environments and modifying the system properties when starting up the Interlok instance. It is generally expected that you would use the variable substition pre-processor and define variables which refer to the system properties required; this pre-processor included for completeness and behaviour follows that of variable substitution processor.
Additional Configuration
The following properties can be specified in the bootstrap.properties to control the behaviour of the system properties pre-processor
Property | Default | Mandatory | Description |
---|---|---|---|
system-properties.varprefix | ${ | No | The value here will be prefixed to the variable name to search for in the configuration to be switched out. |
system-properties.varpostfix | } | No | The value here will be appended to the variable name to search for in the configuration to be switched out. |
system-properties.impl | simple | No | The substitution engine that will perform the variable substitution. Since 3.1.0 simple, simpleWithLogging, strict, strictWithLogging are available. |
If you have in your bootstrap.properties:
preProcessors=systemProperties
Then any system properties present within configuration (such as ${user.dir}
or ${user.name}
) will be replaced within your Interlok configuration unmarshalling happens. Note that on Windows ${user.dir}
will contain backslashes; which means that it will be unsuitable as a URL reference.
Environment Variables
Similar to variable substitution this pre-processor allows you to configure place-holders in your Interlok configuration, these will be swapped out for the corresponding environment variables. The idea is that multiple environments that require almost identical configuration can more easily be set-up by simply duplicating the main Interlok configuration files across all environments and modifying the environment when starting up the Interlok instance. It is generally expected that you would use the variable substition pre-processor and define variables which refer to the environment variables required; this pre-processor included for completeness and behaviour follows that of variable substitution processor.
Additional Configuration
The following properties can be specified in the bootstrap.properties to control the behaviour of the environment variables pre-processor
Property | Default | Mandatory | Description |
---|---|---|---|
environment-variables.varprefix | ${ | No | The value here will be prefixed to the variable name to search for in the configuration to be switched out. |
environment-variables.varpostfix | } | No | The value here will be appended to the variable name to search for in the configuration to be switched out. |
environment-variables.impl | simple | No | The substitution engine that will perform the variable substitution. Since 3.1.0 simple, simpleWithLogging, strict, strictWithLogging are available. |
If you have in your bootstrap.properties:
preProcessors=environmentVariables
Then any environment variables present within configuration (such as ${COMPUTERNAME}
on Windows or ${HOSTNAME}
on Linux) will be replaced within your Interlok configuration before unmarshalling happens.
Schema validation
This pre-processor allows you to validate your configuration with an Interlok RelaxNG schema. Optionally the schema file itself may also be generated before validation. If your configuration file is validated successfully the log file will contain the location of the schema file used and the success of the validation. Should the configuration file not be validated, then Interlok will not start-up and the log file will detail the validation errors.
Further Configuration
The following properties can be specified in the bootstrap.properties to control the behaviour of the schema validation;
Property | Default | Mandatory | Versions | Description |
---|---|---|---|---|
schema.file.url | Yes | all | The url to the Interlok RelaxNG schema file. Note, the schema file itself does not have to exist, if you specify the regeneration (below). | |
schema.regenerate | false | No | all | Set to ‘true’ if you want to re-create the RelaxNG schema before we validate your configuration. |
schema.classpath.screen.patterns | .*adp-core.*\\.jar |
No | Up to 3.6.6 only | A comma separated list of regular expressions used to match all the jars that should be searched for valid components. |
schema.package.patterns | com.adaptris,-com.adaptris.core.stubs |
No | since 3.7.0 | A comma separated list of packages that should be searched for valid components. You can blacklist a package by using a - at the front of the package (the default blacklists the com.adaptris.core.stubs package which is just for unit-testing custom components) |
Example
preProcessors=schema
schema.file.url=file://localhost//path/to/my/schema.rng
If the schema already exists, your configuration will be validated against that schema when you start Interlok; otherwise an exception may be thrown.
preProcessors=schema
schema.file.url=file://localhost//path/to/my/schema.rng
schema.regenerate=true
Regardless of whether the schema file exists or not a new file will be generated and then your configuration will be validated against it.
preProcessors=schema
schema.file.url=file://localhost//path/to/my/schema.rng
schema.regenerate=true
schema.package.patterns=io.github.adaptris,com.mycompany
Regardless of whether the schema file exists or not a new file will be generated and then your configuration will be validated against it. Also, as well as checking the default com.adaptris
packages it will also check the io.github.adaptris
and com.mycompany
package (including sub packages)
XInclude
The XInclude pre-processor allows you to inject xml documents into your Interlok configuration before Interlok starts up. There is also a xstream-xinclude-marshaller that can be used where you might normally configure a xstream-marshaller.
Example
If you have in your bootstrap.properties;
preProcessors=xinclude
And you have an Interlok Configuration file like this;
<?xml version="1.0"?>
<adapter xmlns:xi="http://www.w3.org/2001/XInclude">
<unique-id>xinclude_adapter</unique-id>
<channel-list>
<xi:include href="file://localhost/opt/adaptris/interlok/config/channel.xml"/>
</channel-list>
</adapter>
- We have used an absolute path for the href rather than a relative one; the xinclude library is somewhat ambiguous how relative paths are processed.
And you have an xml document named channel.xml that looks like this;
<channel>
<auto-start>true</auto-start>
<unique-id>SEND</unique-id>
<workflow-list>
<standard-workflow>
<unique-id>SendMessage</unique-id>
<consumer class="polling-trigger">
<destination class="configured-consume-destination">
<configured-thread-name>SendMessage</configured-thread-name>
</destination>
<template>hello world</template>
<poller class="quartz-cron-poller">
<cron-expression>*/7 * * * * ?</cron-expression>
</poller>
</consumer>
<service-collection class="service-list"/>
</standard-workflow>
</workflow-list>
</channel>
During initialization of Interlok, the XInclude pre-processor will pick up the directive <xi:include href="....
from the Interlok configuration and inject the channel.xml content directly into your Interlok configuration to look like this;
<?xml version="1.0"?>
<adapter xmlns:xi="http://www.w3.org/2001/XInclude">
<unique-id>xinclude_adapter</unique-id>
<channel-list>
<channel>
<auto-start>true</auto-start>
<unique-id>SEND</unique-id>
<workflow-list>
<standard-workflow>
<unique-id>SendMessage</unique-id>
<consumer class="polling-trigger">
<destination class="configured-consume-destination">
<configured-thread-name>SendMessage</configured-thread-name>
</destination>
<template>hello world</template>
<poller class="quartz-cron-poller">
<cron-expression>*/7 * * * * ?</cron-expression>
</poller>
</consumer>
<service-collection class="service-list"/>
</standard-workflow>
</workflow-list>
</channel>
</channel-list>
</adapter>
XSLT
For whatever reason, you may want to execute a transform on the configuration XML before proceeding to the unmarshalling stage (a common use-case is to duplicate workflows before unmarshalling). You can do this with the xslt preprocessor.
Additional Configuration
The following properties can be specified in the bootstrap.properties to control the behaviour of the xslt pre-processor.
Property | Default | Mandatory | Description |
---|---|---|---|
xslt.preprocessor.url | Yes | The XSLT to execute, passing in the current adapter configuration. | |
xslt.preprocessor.params.XXXX | No | Values here will be passed in as a stylesheet parameter called XXXX ; you will have <xsl:param name="XXXX"/> in your stylesheet etc. |
|
xslt.preprocessor.environment.params | false | No | Whether or not system properties and environment variables are passed as stylesheet parameters; be aware that any xslt.preprocessor.params.* values will take precedence. |
xslt.preprocessor.transformerImpl | No | Specify the XML TransformFactory to use, if not specified defaults to TransformerFactory.newInstance() which uses the JVM default |
Example
You already have a stylesheet written, stored in the config directory as duplicate.xslt…
preProcessors=xslt
xslt.preprocessor.url=file://localhost/./config/duplicate.xslt
xslt.preprocessor.params.duplicates=5
Will execute your XSLT; passing in 5
as the transform parameter duplicates.
Writing your own pre-processor
If you need to extend the pre-processor behaviour with your own functionality (e.g. you might want to verify the checksum of the file) then you will need to implement ConfigurationPreProcessor and the implementation should have a constructor taking in a BootstrapProperties object.
Pre-processors are generally configured by their short names (though it is possible to use the fully qualified classname). To generate a short name you need to include a file in the META-INF/com/adaptris/core/preprocessor
directory of the jar file. The name of the file should be the short name (e.g. variableSubstitution
). The property file contains a single property class which refers to the fully qualified name of your pre-processor. For the variable substitution pre-processor we have a file META-INF/com/adaptris/core/preprocessor/variableSubstitution
which contains
class=com.adaptris.core.varsub.VariableSubstitutionPreProcessor