Configuring WSO2 Micro-integrator with single TOML configuration model

dhanushka madushan
Think Integration
Published in
9 min readOct 31, 2019

Product configuration is an important part of using any software application. It is a bad experience to end-user when a product has too many different configurations to configure. It’s become worst when there are multiple files that need to be configured and those files are in different formats. In the WSO2 product pack, there are many configuration files with different formats(XML and properties). Single TOML based configuration gives you a way to define all of these configurations in a single TOML file.

TOML file format has been selected as the configuration file format since its highly readable. TOML file format is easy to read due to its obvious semantics. It looks the same as the property file. But it can be used to define more complex data structures.

How it works internally?

Internally product read configurations same as previous. When the server starting up it checks whether deployment.toml file exists inside the `PRODUCT_HOME/conf/` directory. If it does exist, it parses deployement.toml configurations. Parse configuration then goes through a set of phases and these configurations might be changed in these phases. Finally, these configurations generate actual configuration files according to the set of template files that are defined in `PRODUCT_HOME/repository/resources/conf/templates/` folder. There newly generated file will be replaced with the original file.

When the server starting up it reads configuration the same as the previous way. The only difference is that when the server starting up it replaces existing configurations with the configurations provided by the deployment.toml file.

Each time the server getting started, it checks whether deployment.toml file changed or not. If it changed, deployment.toml configurations will be applied upon existing configuration. You can avoid applying configuration by either deleting deployment.toml file or using `-DavoidConfigUpdate` option on server startup.

TOML configuration format

TOML configuration format has been selected due to high readability. TOML format does support to define from a simple string to complex arrays. TOML format looks the same as the property file format. It does have sections. Each section has a section header and section content. Section headers defined by using a single bracket(“[]”). For example, you can define a server hostname as follows.

[server]
hostname = "localhost"

The left-hand side is the key and the right-hand side is the value as a string. TOML format supports the following value formats.

  • String
hostname = "localhost"
  • Integer
max_worker_pool_size=500
  • Float
flt2 = 3.1415
  • Boolean
listener_enable = true
  • Date time
odt1 = 1979-05-27T07:32:00Z
  • Arrays
target_hosts = ["example.com", ".*.sample.com"]
  • Table
[server]
hostname = "localhost"
http_content_negotiation = true
[transport.passthru.http.listener]
port=8280

For the simplicity to understand how it structured, JSON converted TOML configuration looks like below. Here, each dot-separated keys are considered as separate objects.

{
"server": {
"hostname": "localhost",
"http_content_negotiation": true
},
"transport": {
"passthru": {
"http": {
"listener": {
"port": 8280
}
}
}
}
}
  • Array of Table
[[custom_message_formatters.blocking]]
content_type = "application/json/badgerfish"
class = "org.apache.axis2.json.JSONBadgerfishMessageFormatter"
[[custom_message_formatters.blocking]]
content_type = "text/xml"
class = "org.apache.axis2.transport.http.SOAPMessageFormatter"

If the above sample converted into the JSON format, it would be looks like below.

"custom_message_formatters": {
"blocking": [
{
"content_type": "application/json/badgerfish",
"class": "org.apache.axis2.json.JSONBadgerfishMessageFormatter"
},{
"content_type": "text/xml",
"class": "org.apache.axis2.transport.http.SOAPMessageFormatter"
}
]
}

If you open up deployment.toml file from fresh WSO2 Micro-integrator pack in inside `PRODUCT_HOME/conf/` folder, It looks like follows.

[server]
hostname = "localhost"
[user_store]
type = "read_only_ldap"
[keystore.tls]
file_name = "wso2carbon.jks"
password = "wso2carbon"
alias = "wso2carbon"
key_password = "wso2carbon"
[truststore]
file_name = "client-truststore.jks"
password = "wso2carbon"
alias = "symmetric.key.value"
algorithm = "AES"

These configurations are must configured properties(For production usage you need to change the default configs. You should use default configs only for local dev environment). For example, you should generate a new Keystore and set Keystore details under `[keystore.tls]` section.

Using escape characters with a string

TOML file format gives two way’s to define strings. You can use a single quote and double quotes to define a string. If you used double quotes, it allows using escape characters inside the string. For example, if you need to define a newline character is inside a string, then you can use `\n` in inside the double-quotes. Here follow the whole list of escape characters supported by the TOML file.

  • \b — backspace (U+0008)
  • \t — tab (U+0009)
  • \n — linefeed (U+000A)
  • \f — form feed (U+000C)
  • \r — carriage return (U+000D)
  • \” — quote (U+0022)
  • \\ — backslash (U+005C)
  • \uXXXX — Unicode (U+XXXX)
  • \UXXXXXXXX — Unicode (U+XXXXXXXX)

The single quote is the preferred format that does not allow to use escape characters in it. Therefore you can use it to define simple plain text without worrying about escape characters.

In case you need to use a backslash in double-quotes, always remember to use double backslashes.

! Important things to Remember!

Do not define the same section headers twice

Following configuration is invalid since `[transport.rabbitmq]` defined in two places. `sender_enable` parameter also should defined along with `listener_enable` property in `[transport.rabbitmq]` section. Always remember there cannot be two section headers with the same name and section header is unique.

[server]
hostname = "localhost"
http_content_negotiation = true
[transport.rabbitmq]
listener_enable = true
[[transport.rabbitmq.listener]]
name = "AMQPConnectionFactory"
parameter.hostname = "localhost"
parameter.port = 5672
[transport.rabbitmq]
sender_enable = true

Careful about section ordering

When you define a section somewhere on toml file If you need to add another subsection for that section, be careful to define it below the main section. Here below invalid use case of section ordering.

[mediation.inbound]
core_threads = 20
max_threads = 100
[mediation]
synapse.core_threads = 20
synapse.max_threads = 100

This configuration is wrong since `[mediation]` section defined below the `[mediation.inbound]` subsection. The corrected configuration should be as follows.

[mediation]
synapse.core_threads = 20
synapse.max_threads = 100
[mediation.inbound]
core_threads = 20
max_threads = 100

Using custom parameters

In some scenarios, you may need to define properties other than the defined list of parameters. In this case, you can use custom parameters to include custom values. Please refer “Defining synapse properties” section for custom parameter example.

Not all configurations support custom parameters. In this blog, I have describe almost all(Unless if I haven’t missed) the custom parameters that are supported for EI 7(MI 1.1.0).

If custom parameters contain dot-separated keys, then you need to surround it with single quotes.

Defining synapse properties

WSO2 MI does provide support to define the following parameters with deployment TOML file to configure synapse related properties.

[mediation]
synapse.core_threads = 20
synapse.max_threads = 100
synapse.threads_queue_length = 10
synapse.global_timeout_interval = "120000"
synapse.enable_xpath_dom_failover=true
synapse.temp_data_chunk_size=3072
synapse.command_debugger_port=9005
synapse.event_debugger_port=9006
synapse.script_mediator_pool_size=15
synapse.enable_xml_nil=false
synapse.disable_auto_primitive_regex = "^-?(0|[1-9][0-9]*)(\\.[0-9]+)?([eE][+-]?[0-9]+)?$"
synapse.disable_custom_replace_regex = "@@@"
synapse.enable_namespace_declaration = false
synapse.build_valid_nc_name = false
synapse.enable_auto_primitive = false
synapse.json_out_auto_array = false
synapse.preserve_namespace_on_xml_to_json=false
flow.statistics.enable=false
flow.statistics.capture_all=false
statistics.enable_clean=true
statistics.clean_interval = 1000
stat.tracer.collect_payloads=false
stat.tracer.collect_mediation_properties=false
inbound.core_threads = 20
inbound.max_threads = 100
internal_http_api_enable = true
internal_http_api_port = 9191
internal_https_api_port = 9154

If you need to define anything other than the above config, you can configure those by using custom parameters as follows.

[synapse_properties]
'key1' = "parameter value1"
'key2' = "parameter value2"

always remember to use a single quotation surrounded by the key, if the key has separated with dots. Btw, as a best practice, it is better to use a single quote even though keys do not contain dots.

Passthru properties also follow the same rules in new TOML configurations. Here below the list of passthru parameters that support the new TOML format.

[transport.http]
socket_timeout = 180000
core_worker_pool_size = 400
max_worker_pool_size = 400
worker_pool_queue_length = -1
io_buffer_size = 16384
max_http_connection_per_host_port = 32767
preserve_http_user_agent = false
preserve_http_server_name = true
preserve_http_headers = ["Content-Type"]
disable_connection_keepalive = false
enable_message_size_validation = false
max_message_size_bytes = 81920
max_open_connections = -1
force_xml_validation = false
force_json_validation = false
reverse_proxy_mode = false

Here below how to add two custom passthru properties.

[passthru_properties]
'key1' = "parameter value1"
'key2' = "parameter value2"

Adding system parameters

There are two ways to pass system parameters into the WSO2 server. Either you can specify the parameter in server startup, or by using TOML file. For example, if you need to pass `org.wso2.CipherTransformation = true` as a system parameter, you can either start server with `-Dorg.wso2.CipherTransformation=true` or define parameter inside TOML file as follows.

[system.parameter]
'org.wso2.CipherTransformation' = RSA/ECB/OAEPwithSHA1andMGF1Padding

You can add new parameters under `[system.parameter]` section as you wish. Here, also remember to surround key with single quotes, since key contains dots.

Configuring message builders and formatters

The latest TOML configuration model does enable the following message builders and formatters by default. Unless you need to change the default classes for builders as formatters it will work by default with following default class names.

[message_formatters]
form_urlencoded = "org.apache.synapse.commons.formatters.XFormURLEncodedFormatter"
multipart_form_data = "org.apache.axis2.transport.http.MultipartFormDataFormatter"
application_xml = "org.apache.axis2.transport.http.ApplicationXMLFormatter"
text_xml = "org.apache.axis2.transport.http.SOAPMessageFormatter"
soap_xml = "org.apache.axis2.transport.http.SOAPMessageFormatter"
text_plain = "org.apache.axis2.format.PlainTextFormatter"
application_json = "org.wso2.micro.integrator.core.json.JsonStreamFormatter"
json_badgerfish = "org.apache.axis2.json.JSONBadgerfishMessageFormatter"
text_javascript = "org.apache.axis2.json.JSONMessageFormatter"
octet_stream = "org.wso2.carbon.relay.ExpandingMessageFormatter"
application_binary = "org.apache.axis2.format.BinaryFormatter"
[message_builders]
application_xml = "org.apache.axis2.builder.ApplicationXMLBuilder"
form_urlencoded = "org.apache.synapse.commons.builders.XFormURLEncodedBuilder"
multipart_form_data = "org.apache.axis2.builder.MultipartFormDataBuilder"
text_plain = "org.apache.axis2.format.PlainTextBuilder"
application_json = "org.wso2.micro.integrator.core.json.JsonStreamBuilder"
json_badgerfish = "org.apache.axis2.json.JSONBadgerfishOMBuilder"
text_javascript = "org.apache.axis2.json.JSONBuilder"
octet_stream = "org.wso2.carbon.relay.BinaryRelayBuilder"
application_binary = "org.apache.axis2.format.BinaryBuilder"

In case if you need to use your own builder or formatter, you can define it on deployment toml file.

If you need to define a message builder or formatter other than the above list, then you can add it as follows.

[[custom_message_formatters]]
content_type = "application/json/badgerfish"
class = "org.apache.axis2.json.JSONBadgerfishMessageFormatter"
[[custom_message_builders]]
content_type = "application/json/badgerfish"
class = "org.apache.axis2.json.JSONBadgerfishOMBuilder"

Configuring transport

All transport configurations define under the `[transport]` section. All the transport follows the following key naming convention.

[transport.<tranport-type>]
<listener-or-sender>.<property>=value

For example, http sample transport configurations will be as follows. Here the transport type is `http` `sender`.

[transport.http]
sender.enable = true
sender.warn_on_http_500 = "*"
sender.proxy_host = "$ref{server.hostname}"
sender.proxy_port = 3128

Here another example of VFS listener.

[transport.vfs]
listener.enable = true
listener.keystore.file_name = "$ref{keystore.tls.file_name}"
listener.keystore.type = "$ref{keystore.tls.type}"
listener.keystore.password = "$ref{keystore.tls.password}"
listener.keystore.key_password = "$ref{keystore.tls.key_password}"
listener.keystore.alias = "$ref{keystore.tls.alias}"

Transport listeners and senders can be individually enabled and disable by using `enable` property. These configuration conventions apply for following transports.

  • HTTP (Both http/https transport configure under `[transport.http]` section)
  • VFS
  • FIX
  • WS
  • WSSTCP
  • UDP
  • MSMQ
  • MQTT

Custom parameters can be passed into this transport by the following convention.

[transport.<tranport-type>]
parameter.'<custom-parameter>'=value

Always remember to surround custom parameters with a single quote to avoid TOML parsing issues(If the custom parameter has dots inside).

Since JMS and RabbitMQ transport can have multiple transport definitions, it follows the following convention to define JMS configs.

[[transport.<transport-type>.<listener-or-sender>]]
parameter.<property>=value

Example JMS configuration with JMS queue and topic as follows.

[[transport.jms.listener]]
name = "myTopicConnectionFactory"
parameter.initial_naming_factory = "com.sun.jndi.fscontext.RefFSContextFactory"
parameter.provider_url = "file:/C:/JNDI-Directory"
parameter.connection_factory_name = "MQ_JMS_MANAGER"
parameter.connection_factory_type = "topic"
parameter.destination = "ivtT"
[[transport.jms.listener]]
name = "default"
parameter.initial_naming_factory = "com.sun.jndi.fscontext.RefFSContextFactory"
parameter.provider_url = "file:/C:/JNDI-Directory"
parameter.connection_factory_name = "MQ_JMS_MANAGER"
parameter.connection_factory_type = "queue"
parameter.destination = "bogusq"

None of these array type transports are defined as default. Therefore, If you need to only enable transport with no parameters, you can use transport enable disable features according to the following convention.

[transport.<transport-type>]
<listener-or-sender>_enable = true

For example, if you need to only enable JMS sender, add this configuration into the deployment.toml file.

[transport.jms]
sender_enable = true

You can configure RabbitMQ transport in the same way. Example RabbitMQ sender as follows.

[[transport.rabbitmq.sender]]name = "AMQPConnectionFactory"
parameter.hostname = "localhost"
parameter.port = 5672
parameter.username = "guest"
parameter.password = "guest"

Custom parameters for these types of transport arrays would follow the following convention.

[[transport.rabbitmq.sender]]
parameter.'<custom-parameter>' = value

Configuring blocking transport

Blocking transport definition for TOML file follows the same rules as non-blocking transport. It follows the following convention to define single transport.

[transport.blocking.<tranport-type>]
<listener-or-sender>.<property>=value

Follows an example configuration for blocking http transport.

[transport.blocking.http]
listener.enable = true
listener.port = 8200
listener.hostname = "localhost"

JMS can be configured according to the following convention.

[[transport.blocking.<transport-type>.<listener-or-sender>]]
parameter.<property>=value

Here an example of blocking JMS transport sender.

[transport.blocking.jms]
sender_enable = true
[[transport.blocking.jms.sender]]
name = "myTopicSender"
parameter.initial_naming_factory = "org.apache.activemq.artemis.jndi.ActiveMQInitialContextFactory"
parameter.provider_url = "tcp://localhost:61616"
parameter.connection_factory_name = "TopicConnectionFactory"
parameter.connection_factory_type = "topic"

Configuring secure vault

If you are already familiar with EI 6xx series, configuring secure vault is not that easy task to do. In the latest single TOML config model, configuring secure vault is super simple. You can do secure vault configuration inside the TOML file itself rather than changing multiple different files.

All secrets define inside the `[secrets]` section. Inside this section, you can define secrets as key-value pairs. Follow an example of how to define a secret inside the TOML file.

[secrets]
carbon_password = "[wso2carbon]"
admin_password = "[admin]"

Here, there are two passwords defined with the relevant value. Always remember to insert plain values surround brackets. To encrypt plain text values, you need to run cipher tools with `./ciphertool.sh -Dconfigure` command. Once you run this command, it will generate encrypted values as follows in deployment.toml file.

carbon_password  = "aCjz6PyiZ0k0G9uxzhKNQaHW7QvfR+9O4Na9SedX0KLimtZBPsmYjtL7dbrZWCJm0O77AZyLOPFcR+g+ZDey4iO0dkF9DIQlm7BCL5i9fUcSLQk/4pc9rMrlOnoJ+dkp5XjwtXqs528D/qdfo1ywXkJXS3vt2Mb5+ZirAvkhnI2uMzwbEDjIFJxUQdrE4cPUnnq/9XDBLFb4CwznYdxC6OMF9IgCn/V9ezNjTu8icA50fRNx7jipCMy/RVkq9CUwRJEmKI9DgDurX3LDs3X3jpgeX17OmisFzbx26GzllL0MBf+0AVc7C60YpXEezGSOfdaa2Oti1VvGwrSkLRYapw=="
admin_password = "YLGU7Kim9nLL9HPNjorixpuhHbc5rQ8+o8vH3gA/xdJunCNY4cD0F8O5a4owP+IZrGldGRzzMz9nXTOljTDDYJMvwj0g2M1hNAr0q9vUuLR2x1hnI+8wRv96rVKr9MJQQyWn76Ru1JTeoHQngcnPTGsfVh3EmCfHQCia8crhV3W55ZWpf4kCjsmNZoKNSnzeeBypFFErT3LBxMja+Su5XTHAkS3jp0IYxAZSYoDqUs2rYEV9El0uRKQdCUB6AyDUE8OTLglnH2I0a3uE/b9HiKK48Yujdit10xxe+qaCDdI4TPObT3U4xOkBAWPUBtXcBj3Bvm7HnMeqzi8EAORTnA=="

You can use these encrypted entities when you need to define a secret value. For example, If you need to set a super admin username password, it would be as follows.

[super_admin]
username = "admin"
password = "$secret{admin_password}"

Further Reading

--

--