Tigase组件第二节 – 配置(TODO:配置API和init.properties需要链接到中文文档)
本文翻译自 - http://www.tigase.org/content/component-implementation-lesson-2-configuration
可能很难为开发组件第一步做什么下定论。不同的开发者有不同的看法,对我而言,为组建添加一种能够在运行时修改配置文件,并允许组建动态得对配置改变做出正确处理的机制是首要任务。
下面的文字讲述当配置项变化时,组件该如何处理。专门有一篇文档会提供配置API的细节描述,所以这里不会深入去探讨,在必要时仅展示部分代码。
我们把组件打印哪一种package到日志文件作为可配置项,通过这个例子展示组件如何对配置修改做出正确的处理。一共有三种类型的消息:“message”,“presence”和“iq”。要求是:哪种或哪些消息需要打印到日志文件是可配置的;可以为日志内容添加前缀,且前缀是可配置的;且打印输出功能可以配置为“正常模式”或“隐私保护模式”。(隐私保护模式状态下的日志内容会替换CData标签的内容为“CData size: NN”。)
首先为组件添加一些私有变量:
1
2
3
|
privateString[] packetTypes = {"message","presence","iq"};
privateString prependText ="My packet: ";
privatebooleansecureLogging =false;
|
配置项的格式是键值对,我们首先为“刚才提到的几个配置要求”设置“配置项的键”:
1
2
3
|
privatestaticfinalString PACKET_TYPES_KEY ="packet-types";
privatestaticfinalString PREPEND_TEXT_KEY ="log-prepend";
privatestaticfinalString SECURE_LOGGING_KEY ="secure-logging";
|
维护组件的配置信息有两种方法:getDefault(…)获取缺省配置信息,setProperties(…)设置配置项:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
@Override
publicMap getDefaults(Map params) {
Map defs =super.getDefaults(params);
defs.put(PACKET_TYPES_KEY, packetTypes);
defs.put(PREPEND_TEXT_KEY, prependText);
defs.put(SECURE_LOGGING_KEY, secureLogging);
returndefs;
}
@Override
publicvoidsetProperties(Map 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);
}
|
你不必实现getDefaults(…)方法,也不必提供缺省的配置信息;但是如果你做了,它会对你带来帮助。
首先,从开发者的角度,你不必在setProperties(…)方法当中检查配置项的值是否为null(null总是缺省值,用户也可能因为没有在配置文件当中设定配置项而产生null的结果),因为配置管理框架会对比用户的输入项和缺省配置项,并最终挑选出可用的配置项。这会让你的setProperties(…)方法变得简洁。
其次,这样做也会让管理员轻松一些。就像在下面的截图里面展示的那样,配置项有缺省参数,并且可以通过配置ad-hoc命令来进行调整。所以管理员可以使用ta的XMPP客户端在运行时维护你的组件配置信息。
而且所有的配置项的缺省值都被保存在tigase.xml配置文件当中(储天行注:Tigase从5.x版本之后已经取消了tigase.xml配置文件)。你可以查看并修改这些项,然后看看服务器运行是否如你预期的那样。
无论你是否实现了getDefaults(…)方法,你都可以手动在tigase.xml或init.properties文件里面添加配置项。
init.properties文件的配置语法也很简单,语法的细节请参阅TODO:这里是一个链接。就像上面图片所展示的那样,配置项的键名组成为:“组件名称” + “/” + “属性键名”。可以在init.properties文件当中添加下面的内容来对配置项进行设置:
1
2
3
|
test/log-prepend="My packet: "
test/packet-types[s]=message,presence,iq
test/secure-logging[B]=true
|
方括号里面是属性的类型,请参考TODO:这里是一个链接来获取更多的细节。
下面是组建增加了对配置修改相关操作的processPacket(…)方法的完整代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
|
importjava.util.Map;
importjava.util.logging.Logger;
importtigase.server.AbstractMessageReceiver;
importtigase.server.Packet;
publicclassTestComponentextendsAbstractMessageReceiver {
privatestaticfinalLogger log =
Logger.getLogger(TestComponent.class.getName());
privatestaticfinalString PACKET_TYPES_KEY ="packet-types";
privatestaticfinalString PREPEND_TEXT_KEY ="log-prepend";
privatestaticfinalString SECURE_LOGGING_KEY ="secure-logging";
privateString[] packetTypes = {"message","presence","iq"};
privateString prependText ="My packet: ";
privatebooleansecureLogging =false;
@Override
publicvoidprocessPacket(Packet packet) {
for(String pType : packetTypes) {
if(pType == packet.getElemName()) {
log.finest(prependText + packet.toString(secureLogging));
}
}
}
@Override
publicMap<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);
returndefs;
}
@Override
publicvoidsetProperties(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(inti =0; i < packetTypes.length; i++) {
packetTypes[i] = packetTypes[i].intern();
}
prependText = (String)props.get(PREPEND_TEXT_KEY);
secureLogging = (Boolean)props.get(SECURE_LOGGING_KEY);
}
}
|
当然我们还可以在方法里面添加更多“有用”的代码,这只是一个样例代码。请注意在processPacket(…)方法中比较packet的元素名和类型是允许的。出于对内存的消耗和系统性能的影响,所有字符串的比较都通过String.intern(…)方法实现。