Component implementation - Lesson 2 - Configuration
It might be hard to tell what is the first important thing to 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. There is detailed configuration API description available so again I am not getting deep into all details just the necessary code.
To demonstrate how to maintain the component configuration let's say we want to make configurable types of packets which are being 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 them. Furthermore we also want to be able to configure the text which is prepended to the logged message and optionally switch the secure logging on. (Secure logging replaces all packet CData with text: 'CData size: NN' to protect user privacy.)
Let's create following private variables in our component:
private String[] packetTypes = {"message", "presence", "iq"};
private String prependText = "My packet: ";
private boolean secureLogging = false;As the component configuration is maintained in a form of (key, value) Map we have to invent keys for each of our configuration entry:
private static final String PACKET_TYPES_KEY = "packet-types"; private static final String PREPEND_TEXT_KEY = "log-prepend"; private static final String SECURE_LOGGING_KEY = "secure-logging";
There are two methods used to maintain the component configuration: getDefaults(...) where the component provides some configuration defaults and setProperties(...) which sets working configuration for the component:
@Override
public Map<String, Object> getDefaults(Map<String, Object> params) {
Map<String, Object> defs = super.getDefaults(params);
defs.put(PACKET_TYPES_KEY, packetTypes);
defs.put(PREPEND_TEXT_KEY, prependText);
defs.put(SECURE_LOGGING_KEY, secureLogging);
return defs;
}
@Override
public void setProperties(Map<String, Object> props) {
super.setProperties(props);
packetTypes = (String[])props.get(PACKET_TYPES_KEY);
prependText = (String)props.get(PREPEND_TEXT_KEY);
secureLogging = (Boolean)props.get(SECURE_LOGGING_KEY);
} You do not have to implement getDefaults(...) method and provide default settings for your configuration but doing so gives you a few benefits.
The first, from the developer point of view, you don't have to check in the setProperties(...) whether the value is null as it always be either the default or user provided. It also will always be of a correct type as the configuration framework takes care of the types comparing between the user provided settings and default values. So this just makes your setProperties(...) code much simpler and clearer.
Secondly this also makes the administrator live easier. As you can see on the screenshot, configuration parameters provided with default values, can be changed via configuration ad-hoc commands. So the administrator can maintain your component at run-time from his XMPP client.
Also all configuration parameters for which defaults are provided are saved to tigase.xml configuration file. You can review them, change and actually see whether your component behaves as you expect.
Regardless you implemented the getDefaults(...) method or not you can always manually add parameters to the tigase.xml file or provide them via init.properties file.
The syntax in init.properties file is actually very simple and is described in details in the documentation for this file. As it shows on the screenshot the configuration parameter name consists of: 'component name' + / + 'property key'. To set configuration for your component in init.properties file you have to append following lines to the file:
test/log-prepend="My packet: " test/packet-types[s]=message,presence,iq test/secure-logging[B]=true
In square brackets you provide the property type, have a look at the documentation for more details.
And this is the complete code of the new component with modified processPacket(...) method taking advantage of configuration settings:
import java.util.Map;
import java.util.logging.Logger;
import tigase.server.AbstractMessageReceiver;
import tigase.server.Packet;
public class TestComponent extends AbstractMessageReceiver {
private static final Logger log =
Logger.getLogger(TestComponent.class.getName());
private static final String PACKET_TYPES_KEY = "packet-types";
private static final String PREPEND_TEXT_KEY = "log-prepend";
private static final String SECURE_LOGGING_KEY = "secure-logging";
private String[] packetTypes = {"message", "presence", "iq"};
private String prependText = "My packet: ";
private boolean secureLogging = false;
@Override
public void processPacket(Packet packet) {
for (String pType : packetTypes) {
if (pType == packet.getElemName()) {
log.finest(prependText + packet.toString(secureLogging));
}
}
}
@Override
public Map<String, Object> getDefaults(Map<String, Object> params) {
Map<String, Object> defs = super.getDefaults(params);
defs.put(PACKET_TYPES_KEY, packetTypes);
defs.put(PREPEND_TEXT_KEY, prependText);
defs.put(SECURE_LOGGING_KEY, secureLogging);
return defs;
}
@Override
public void setProperties(Map<String, Object> props) {
super.setProperties(props);
packetTypes = (String[])props.get(PACKET_TYPES_KEY);
// Make sure we can compare element names by reference
// instead of String content
for (int i = 0; i < packetTypes.length; i++) {
packetTypes[i] = packetTypes[i].intern();
}
prependText = (String)props.get(PREPEND_TEXT_KEY);
secureLogging = (Boolean)props.get(SECURE_LOGGING_KEY);
}
}Of course we can do much more useful packet processing in processPacket(...) method. This is just a code example. Please note comparing packet element name with our packet type by reference is intentional and allowed in this context. All Element names are processed with String.intern() function to preserve memory and improve performance of string comparation.
- Add new comment
- 1309 reads






Recent comments
2 hours 6 min ago
4 hours 11 min ago
4 hours 13 min ago
4 hours 34 min ago
7 hours 48 min ago
7 hours 53 min ago
23 hours 21 min ago
1 day 4 hours ago
1 day 4 hours ago
1 day 5 hours ago