[[cil2]]
= Component Implementation - Lesson 2 - Configuration
:author: Andrzej Wójcik <andrzej.wojcik@tigase.net>
:author: Artur Hefczyc <artur.hefczyc@tigase.net>
:version: v2.2, March 2017: Reformatted for v8.0.0.

:toc:
:numbered:
:website: http://tigase.net/

It might be hard to tell what the first important thing you should do with your new component implementation. Different developers may have a different view on this. It seems to me however that it is always a good idea to give to your component a way to configure it and provide some runtime settings.

This guide describes how to add configuration handling to your component.

To demonstrate how to implement component configuration let's say we want to configure which types of packets will be logged by the component. There are three possible packet types: *message*, *presence* and *iq* and we want to be able to configure logging of any combination of the three. Furthermore we also want to be able to configure the text which is prepended to the logged message and to optionally switch secure login. (Secure logging replaces all packet CData with text: _CData size: NN_ to protect user privacy.)

Let's create the following private variables in our component *TestModule*:

[source,java]
-----
private String[] packetTypes = {"message", "presence", "iq"};
private String prependText = "My packet: ";
private boolean secureLogging = false;
-----

To make them configurable we have to annote them with `@ConfigField` annotation. It requires `desc` field (describing configuration option) and has following optional properties:
* `alias` - alternative name of the variable
* `allowAliasFromParent` - specifies whether value from alias from parent bean should be allowed
* `type` - specifies general type of the field, which impacts possible obfuscation of the value in the logs/"config-dump" file; possible values: `Plain` (no changes), `Password` (complete value will be obfuscated) and `JdbcUrl` (only password part will be obfuscated from the URL)

[source,java]
-----
@ConfigField(desc = "Logged packet types", alias = "packet-types")
private String[] packetTypes = {"message", "presence", "iq"};
@ConfigField(desc = "Prefix", alias = "log-prepend")
private String prependText = "My packet: ";
@ConfigField(desc = "Secure logging", alias = "secure-logging")
private boolean secureLogging = false;
-----

And this is it. Tigase Kernel will take care of this fields and will update them when configuration will change.

The syntax in `config.tdsl` file is very simple and is described in details in the _Admin Guide_. To set the configuration for your component in `config.tdsl` file you have to append following lines to the file inside test component configuration block:

[source,dsl]
-----
test-module {
  log-prepend = 'My packet: '
  packet-types = [ 'message', 'presence', 'iq' ]
  secure-logging = true
}
-----

The square brackets are used to mark that we set a list consisting of a few elements, have a look at the _Admin Guide_ documentation for more details.

And this is the complete code of the new component module with a modified `process(...)` method taking advantage of configuration settings:

[source,java]
-----
@Bean(name = "test-module", parent = TestComponent.class, active = true)
public static class TestModule extends AbstractModule {

  private static final Logger log = Logger.getLogger(TestModule.class.getCanonicalName());

  private Criteria CRITERIA = ElementCriteria.name("message");

  @ConfigField(desc = "Logged packet types", alias = "packet-types")
  private String[] packetTypes = {"message", "presence", "iq"};
  @ConfigField(desc = "Prefix", alias = "log-prepend")
  private String prependText = "My packet: ";
  @ConfigField(desc = "Secure logging", alias = "secure-logging")
  private boolean secureLogging = false;

  @Override
  public Criteria getModuleCriteria() {
    return CRITERIA;
  }

  public void setPacketTypes(String[] packetTypes) {
    this.packetTypes = packetTypes;
    Criteria crit = new Or();
    for (String packetType : packetTypes) {
      crit.add(ElementCriteria.name(packetType));
    }
    CRITERIA = crit;
  }

  @Override
  public void process(Packet packet) throws ComponentException, TigaseStringprepException {
    log.finest(prependText + packet.toString(secureLogging));
  }
}
-----

Of course we can do much more useful packet processing in the `process(...)` method. This is just an example code.

TIP: Here we used a setter *setPacketType(String[] packetTypes)* which is a setter for field *packetTypes*. Tigase Kernel will use it instead of assigning value directly to a field which gives up opportunity to convert value to different type and update other field - in our case we updated *CRITERIA* field which will result in change of packet types which for which method *void process(...)* will be called.
