提供者体系结构 : Packet扩充和自定义IQ

    • IQProvider —解析IQ请求为Java对象。
    • PacketExtension — 解析附于packe中的XML子文档为PacketExtension实像。

    默认情况下, Smack仅知道怎样处理含有子packetIQ packet,这些子packet存在像如下所示的命名空间中:

    • jabberauth
    • jabber:iq:roster
    • jabberregister

    有很多IQ类型和扩展XMPP标准的一部分,当然,可以添加不限数量的自定义扩展。为了支持这一点,一个可扩展的用户提供通过Smack和解析机制构建供应商。

    无论何时发现包扩展包,解析将被传递到正确的供应商。每个提供者必须实现PacketExtensionProvider接口。每个扩展提供者负责解析原始XML流,通过XML Pull解析器,contruct对象。

    您还可以创建一个内部提供者(provider.IntrospectionProvider.PacketExtensionIntrospectionProvider)。这里,使用bean内省来自动设置的属性类使用数据包中的值扩展元素。

    当没有扩展提供者注册一个元素名称和命名空间的组合,Smack将存储所有的顶级元素sub-packet DefaultPacketExtension对象,然后将它附加到数据包。

    • 调用addXXProvider方法——你可以直接调用适当的添加方法
    • 添加一个加载器——你可以添加一个ProviderLoader将注入的方式加载多个提供者(两种类型)经理。这是打加载所使用的机制从特定的文件格式(通过ProviderFileLoader)。实现者可以提供负载的手段提供他们希望从任何来源,或简单地重用ProviderFileLoader从他们自己的供应商文件来加载。
      1. ProviderManager.addLoader(new ProviderFileLoader(FileUtils.getStreamForUrl("classpath:com/myco/provider/myco_custom.providers", null)));
    • VM参数——你可以通过VM参数smack.provider.file文件添加一个提供者。这将加载文件在指定的URL在启动时初始化。这还假设缺省配置,因为它要求VmArgInitializer是启动配置的一部分。
      1. -Dsmack.provider.file=classpath:com/myco/provider/myco_custom.providers
      2. or
      3. -Dsmack.provider.file=file:///c:/myco/provider/myco_custom.providers

    IQ提供者类必须实现IQProvider接口。每个IQProvider负责解析原始XML流创建一个IQ实例。

    您还可以创建一个内省提供者(provider.IntrospectionProvider.IQIntrospectionProvider)。使用bean内省来自动设置属性的IQ实例使用IQ包中发现XML值。例如,一个XMPP时间包类似于以下:

    1. // Time Stanza
    2. <iq type='result' to='joe@example.com' from='mary@example.com' id='time_1'>
    3. <query xmlns='jabber:iq:time'>
    4. <utc>20020910T17:58:35</utc>
    5. <tz>MDT</tz>
    6. <display>Tue Sep 10 12:58:35 2002</display>
    7. </query>
    8. </iq>

    自检服务将自动尝试从XML字符串值转换为一个boolean, int, long, float, double,或者Class,根据预设的IQ实例的类型。

    让我们假设你想写一个新的provider,不支持的IQ在Smack中。
    自定义的IQ

    1. <iq type='set' from='juliet@capulet.example/balcony' to='romeo@montage.example'>
    2. <myiq xmlns='example:iq:foo' token='secret'>
    3. <user age='42'>John Doe</user>
    4. <location>New York</location>
    5. </myiq>
    6. </iq>

    自定义的IQ Provider

    1. public class MyIQProvider extends IQProvider<MyIQ> {
    2. @Override
    3. public MyIQ parse(XmlPullParser parser, int initialDepth) throws XmlPullParserException, IOException {
    4. // Define the data we are trying to collect with sane defaults
    5. int age = -1;
    6. String user = null;
    7. String location = null;
    8. // Start parsing loop
    9. outerloop: while(true) {
    10. switch(eventType) {
    11. case XmlPullParser.START_TAG:
    12. switch (elementName) {
    13. case "user":
    14. age = ParserUtils.getIntegerAttribute(parser, "age");
    15. user = parser.nextText();
    16. break;
    17. case "location"
    18. location = parser.nextText();
    19. break;
    20. }
    21. break;
    22. case XmlPullParser.END_TAG:
    23. // Abort condition: if the are on a end tag (closing element) of the same depth
    24. if (parser.getDepth() == initialDepth) {
    25. break outerloop;
    26. }
    27. break;
    28. }
    29. }
    30. // Construct the IQ instance at the end of parsing, when all data has been collected
    31. return new MyIQ(user, age, location);
    32. }
    33. }

    DiscoItemsProvider

    1. <iq type='result' from='shakespeare.lit' to='romeo@montague.net/orchard' id='items1'>
    2. <query xmlns='http://jabber.org/protocol/disco#items'>
    3. <item jid='people.shakespeare.lit' name='Directory of Characters'/>
    4. <item jid='plays.shakespeare.lit' name='Play-Specific Chatrooms'/>
    5. <item jid='mim.shakespeare.lit' name='Gateway to Marlowe IM'/>
    6. <item jid='words.shakespeare.lit' name='Shakespearean Lexicon'/>
    7. <item jid='globe.shakespeare.lit' name='Calendar of Performances'/>
    8. <item jid='headlines.shakespeare.lit' name='Latest Shakespearean News'/>
    9. <item jid='catalog.shakespeare.lit' name='Buy Shakespeare Stuff!'/>
    10. <item jid='en2fr.shakespeare.lit' name='French Translation Service'/>
    11. </query>
    12. </iq>

    Disco Items IQProvider

    Stanza extension providers负责解析包扩展,自定义名称空间中的子元素的IQmessagepresence packets(数据包)。

    Pubsub Subscription Stanza

    1. <iq type='result' from='pubsub.shakespeare.lit' to='francisco@denmark.lit/barracks' id='sub1'>
    2. <pubsub xmlns='http://jabber.org/protocol/pubsub'>
    3. <subscription node='princely_musings' jid='francisco@denmark.lit' subscription='unconfigured'>
    4. <subscribe-options>
    5. <required/>
    6. </pubsub>
    7. </iq>

    Subscription PacketExtensionProvider Implementation

    1. public class SubscriptionProvider implements PacketExtensionProvider {
    2. public PacketExtension parseExtension(XmlPullParser parser) throws Exception {
    3. String jid = parser.getAttributeValue(null, "jid");
    4. String nodeId = parser.getAttributeValue(null, "node");
    5. String subId = parser.getAttributeValue(null, "subid");
    6. String state = parser.getAttributeValue(null, "subscription");
    7. boolean isRequired = false;
    8. int tag = parser.next();
    9. if ((tag == XmlPullParser.START_TAG) && parser.getName().equals("subscribe-options")) {
    10. tag = parser.next();
    11. if ((tag == XmlPullParser.START_TAG) && parser.getName().equals("required"))
    12. isRequired = true;
    13. while (parser.next() != XmlPullParser.END_TAG && parser.getName() != "subscribe-options");
    14. }
    15. while (parser.getEventType() != XmlPullParser.END_TAG) parser.next();
    16. return new Subscription(jid, nodeId, subId, (state == null ? null : Subscription.State.valueOf(state), isRequired);
    17. }
    18. }

    这是Provider文件的格式可以由ProviderFileLoader解析。

    1. <?xml version="1.0"?>
    2. <smackProviders>
    3. <iqProvider>
    4. <elementName>query</elementName>
    5. <namespace>jabber:iq:time</namespace>
    6. <className>org.jivesoftware.smack.packet.Time</className>
    7. </iqProvider>
    8. <iqProvider>
    9. <elementName>query</elementName>
    10. <namespace>http://jabber.org/protocol/disco#items</namespace>
    11. <className>org.jivesoftware.smackx.provider.DiscoverItemsProvider</className>
    12. </iqProvider>
    13. <extensionProvider>
    14. <elementName>subscription</elementName>
    15. <namespace>http://jabber.org/protocol/pubsub</namespace>
    16. <className>org.jivesoftware.smackx.pubsub.provider.SubscriptionProvider</className>
    17. </smackProviders>