【问题标题】:IQ Custom provider not recognizedIQ 自定义提供程序无法识别
【发布时间】:2014-05-18 17:16:05
【问题描述】:

我正在使用 aSmackOpenfire

经过大量研究,我发现 Openfire 不支持消息归档并安装了插件 OpenArchive

现在存档工作正常,所有消息都可以正常存储。

现在在客户端,我尝试发送 IQ 节 来检索存档的聊天记录

首先我添加了一个如下所示的 IQ Provider:

pm.addIQProvider("list", "urn:xmpp:archive", new ListIQProvider());

然后我用了:

final IQ iq = new IQ()
{

    @Override public String getChildElementXML()
    {

        return "<list  xmlns='urn:xmpp:archive' with='test@customOpenfire.com'><set xmlns='http://jabber.org/protocol/rsm'><max xmlns='http://jabber.org/protocol/rsm'>30</max></set> </list>";

    }
};

iq.setType(IQ.Type.GET);
iq.setPacketID("987654321");

xmppConnection.sendPacket(iq);

效果很好,我收到了回复。

<iq id="987654321" to="admin@customOpenfire.com/Smack" type="result">
<list xmlns="urn:xmpp:archive">
    <chat with="test@customOpenfire.com" start="2014-04-06T12:11:28.674Z"/>
    <chat with="test@customOpenfire.com" start="2014-04-03T16:55:59.523Z"/>
    <chat with="test@customOpenfire.com" start="2014-04-05T16:33:03.377Z"/>
    <chat with="test@customOpenfire.com" start="2014-04-02T14:32:10.499Z"/>
    <chat with="test@customOpenfire.com" start="2014-04-06T12:47:52.961Z"/>
    <chat with="test@customOpenfire.com" start="2014-04-03T14:46:24.877Z"/>
    <chat with="test@customOpenfire.com" start="2014-04-06T12:37:14.608Z"/>
    <chat with="test@customOpenfire.com" start="2014-04-03T15:48:46.642Z"/>
    <chat with="test@customOpenfire.com" start="2014-04-02T13:46:07.750Z"/>
    <chat with="test@customOpenfire.com" start="2014-04-04T18:25:57.968Z"/>
    <chat with="test@customOpenfire.com" start="2014-04-03T19:08:45.238Z"/>
    <chat with="test@customOpenfire.com" start="2014-04-04T18:47:19.067Z"/>
    <chat with="test@customOpenfire.com" start="2014-04-04T19:34:27.819Z"/>
    <chat with="test@customOpenfire.com" start="2014-04-02T15:09:13.140Z"/>
    <chat with="test@customOpenfire.com" start="2014-04-03T18:30:36.804Z"/>
    <chat with="test@customOpenfire.com" start="2014-04-05T14:09:34.973Z"/>
    <chat with="test@customOpenfire.com" start="2014-04-04T22:47:54.363Z"/>
    <chat with="test@customOpenfire.com" start="2014-04-02T15:32:44.540Z"/>
    <chat with="test@customOpenfire.com" start="2014-04-03T17:18:37.940Z"/>
    <chat with="test@customOpenfire.com" start="2014-04-03T13:37:15.630Z"/>
    <chat with="test@customOpenfire.com" start="2014-04-04T17:10:39.116Z"/>

    <set xmlns="http://jabber.org/protocol/rsm">
        <first index="0">66</first>
        <last>139</last>
        <count>21</count>
    </set>
</list>
</iq>

然后我想检索实际的消息,所以我发送了这个 IQ 节

final IQ iq = new IQ()
{

    @Override public String getChildElementXML()
    {

        return "<retrieve  xmlns='urn:xmpp:archive' with='test@customOpenfire.com'><set xmlns='http://jabber.org/protocol/rsm'><max xmlns='http://jabber.org/protocol/rsm'>30</max></set> </retrieve>";

    }
};

iq.setType(IQ.Type.GET);
iq.setPacketID("987654321");

xmppConnection.sendPacket(iq);

当然,在我创建自定义提供程序并将其添加如下之后:

pm.addIQProvider("retrieve", "urn:xmpp:archive", new ChatIQProvider());

我应该收到类似的东西:

<iq xmlns="jabber:client" type="result" id="hgfg" to="admin@customOpenfire.com/7dd0f2fc">
<chat xmlns="urn:xmpp:archive" with="test@customOpenfire.com" start="2014-04-02T13:46:07.750Z">
    <from secs="0" jid="test@customOpenfire.com">
        <body>hello</body>
    </from>
    <to secs="2">
        <body>hey</body>
    </to>
    <from secs="5" jid="test@customOpenfire.com">
        <body>test</body>
    </from>
    <set xmlns="http://jabber.org/protocol/rsm">
        <first index="0">0</first>
        <last>2</last>
        <count>3</count>
    </set>
</chat>

但在我的数据包侦听器中,结果不会被解析,并且会像我删除 ListIQProvider() 后的 list 节 一样被处理。

这是我的自定义类:

ChatIQ:

public class ChatIQ extends IQ {


private String xmlns;
private String with;
private String start;

private List<From> froms;
private Set set;

public ChatIQ()
{
    this.froms = new ArrayList<ChatIQ.From>();
}

public String getXmlns()
{
    return xmlns;
}

public void setXmlns(String xmlns)
{
    this.xmlns = xmlns;
}

public String getWith()
{
    return with;
}

public void setWith(String with)
{
    this.with = with;
}

public String getStart()
{
    return start;
}

public void setStart(String start)
{
    this.start = start;
}



public void addFrom(From from)
 {
    froms.add(from);
 }

 public List<From> getFroms()
 {
    return froms;
 }

public Set getSet()
 {
    return set;
 }

 public void setSet(Set set)
 {
    this.set = set;
 }

 @Override
 public String getChildElementXML()
 {
     StringBuilder builder = new StringBuilder("<chat xmlns=\"urn:xmpp:archive\"");
        builder.append("with=\"").append(with).append("\"");
        builder.append(" start=\"");
        builder.append(start);
        builder.append("\">");
        for(From from : froms)
        {
            builder.append(from.toXml());
        }
        builder.append(set.toXml());
        builder.append("</chat>");
        return builder.toString();
 }

 public static class From 
 {
     private String secs;
     private String jid;

     private Body body;

     public String getSecs()
    {
        return secs;
    }


    public void setSecs(String secs)
    {
        this.secs = secs;
    }


    public String getJid()
    {
        return jid;
    }


    public void setJid(String jid)
    {
        this.jid = jid;
    }


    public Body getBody()
    {
        return body;
    }


    public void setBody(Body body)
    {
        this.body = body;
    }


    public String toXml()
    {
        StringBuilder builder = new StringBuilder("<from ");
        builder.append("secs=\"").append(secs).append("\" ");
        builder.append("jid=\"").append(jid).append("\" >");
        builder.append(body.toXml());
        builder.append("</from>");
        return builder.toString();
    }
 }

 public static class Body 
 {
     private String message;

    public Body(String message)
    {
        this.message = message;
    }

    public String getMessage()
    {
        return message;
    }

    public void setMessage(String message)
    {
        this.message = message;
    }

    public Object toXml()
    {
        StringBuilder builder = new StringBuilder("<body>");
        builder.append(message);
        builder.append("</body>");
        return builder.toString();
    }
 }

 public static class Set {
    private int last;
    private int count;
    private int indexAtt;
    private int first;

    public Set()
    {
    }

    public int getLast()
    {
        return last;
    }

    public void setLast(int last)
    {
        this.last = last;
    }

    public int getCount()
    {
        return count;
    }

    public void setCount(int count)
    {
        this.count = count;
    }

    public int getIndexAtt()
    {
        return indexAtt;
    }

    public void setIndexAtt(int indexAtt)
    {
        this.indexAtt = indexAtt;
    }

    public int getFirst()
    {
        return first;
    }

    public void setFirst(int first)
    {
        this.first = first;
    }

    public String toXml()
    {
        StringBuilder builder = new StringBuilder("<set xmlns=\"http://jabber.org/protocol/rsm\">");
        builder.append("<first index=\"").append(indexAtt).append("\">").append(first).append("</first>");
        builder.append("<last>").append(last).append("</last>");
        builder.append("<count>").append(count).append("</count>");
        builder.append("</set>");
        return builder.toString();
    }
 }

}

ChatIQProvider:

public class ChatIQProvider implements IQProvider {

 public ChatIQProvider()
 {
 }

 @Override
 public IQ parseIQ(XmlPullParser parser) throws Exception
 {
    Log.d("CHAT IQ PROVIDER", String.format("Received iq packet, namespace[%s], name[%s]", parser.getNamespace(), parser.getName()));
    ChatIQ iq = new ChatIQ();
    ChatIQ.Set set = new Set();
    boolean done = false;

    From from = new From();
    String secs = "", jid = "";
    while (!done)
    {
        int eventType = parser.next();
        if (eventType == XmlPullParser.START_TAG)
        {
            if (parser.getName().equals("from"))
            {
                secs = parser.getAttributeValue("", "secs");
                jid = parser.getAttributeValue("", "jid");

                from = new From();

                iq.addFrom(from);
            }
            else if(parser.getName().equals("body") && from.getBody()==null)
            {
                ChatIQ.Body body = new Body(parser.nextText());
                from.setBody(body);
            }
            else if (parser.getName().equals("first"))
            {
                int index = parseInt(parser.getAttributeValue("", "index"));
                set.setIndexAtt(index);
                int first = parseInt(parser.nextText());
                set.setFirst(first);
            }
            else if (parser.getName().equals("last"))
            {
                int last = parseInt(parser.nextText());
                set.setLast(last);
            }
            else if (parser.getName().equals("count"))
            {
                int count = parseInt(parser.nextText());
                set.setCount(count);
            }
        }
        else if (eventType == XmlPullParser.END_TAG)
        {
            if (parser.getName().equals("chat"))
            {
                iq.setSet(set);
                done = true;
            }
        }
    }

    return iq;
 }

 private int parseInt(String integer)
 {
    return Integer.parseInt((integer != null ? integer : "0"));
 }
}

我的问题如下:

  • 为什么我的自定义 IQProvider 无法识别?
  • 我能否在不通过 IQproviders 的情况下获取接收到的 XML 并对其进行解析?
  • 有没有更简单的方法可以从服务器检索归档消息?知道消息存在并且我确实在客户端收到它们,我只是找不到获取内容并解析它的方法。

谢谢。

【问题讨论】:

    标签: android xmpp chat archive provider


    【解决方案1】:

    我解决了这个问题,但我忘了在这里为可能有同样问题的其他人发布答案。 无论如何,修复非常简单。而不是:

    pm.addIQProvider("retrieve", "urn:xmpp:archive", new ChatIQProvider());
    

    我应该使用:

    pm.addIQProvider("chat", "urn:xmpp:archive", new ChatIQProvider());
    

    我必须注册 IQ 响应而不是请求的子标签的名称,因此“聊天”而不是“检索”。

    希望这会有所帮助,因为我找不到任何关于在 android smack api 中使用自定义 IQ 的示例。

    由于评论太长,我在这里添加。

    给你:

    ListIQProvider:

    public class ListIQProvider implements IQProvider {
    
     public ListIQProvider()
     {
     }
    
     @Override
     public IQ parseIQ(XmlPullParser parser) throws Exception
     {
        ListIQ iq = new ListIQ();
        ListIQ.Set set = new Set();
        boolean done = false;
    
        String with = "", start = "";
        while (!done)
        {
            int eventType = parser.next();
            if (eventType == XmlPullParser.START_TAG)
            {
                if (parser.getName().equals("chat"))
                {
                    with = parser.getAttributeValue("", "with");
                    start = parser.getAttributeValue("", "start");
                    iq.addChat(new Chat(with, start));
                }
                else if (parser.getName().equals("first"))
                {
                    int index = parseInt(parser.getAttributeValue("", "index"));
                    set.setIndexAtt(index);
                    int first = parseInt(parser.nextText());
                    set.setFirst(first);
                }
                else if (parser.getName().equals("last"))
                {
                    int last = parseInt(parser.nextText());
                    set.setLast(last);
                }
                else if (parser.getName().equals("count"))
                {
                    int count = parseInt(parser.nextText());
                    set.setCount(count);
                }
            }
            else if (eventType == XmlPullParser.END_TAG)
            {
                if (parser.getName().equals("list"))
                {
                    iq.setSet(set);
                    done = true;
                }
            }
        }
    
        return iq;
     }
    
     private int parseInt(String integer)
     {
        return Integer.parseInt((integer != null ? integer : "0"));
     }
    

    }

    ListIQ:

    public class ListIQ extends IQ {
    
     private List<Chat> chats;
    
     private Set set;
    
     public ListIQ()
     {
        this.chats = new ArrayList<ListIQ.Chat>();
     }
    
     public Set getSet()
     {
        return set;
     }
    
     public void setSet(Set set)
     {
        this.set = set;
     }
    
     public void addChat(Chat chat)
     {
        chats.add(chat);
     }
    
     public List<Chat> getChats()
     {
        return chats;
     }
    
     @Override
     public String getChildElementXML()
     {
        StringBuilder builder = new StringBuilder("<list xmlns=\"urn:xmpp:archive\">");
        for (Chat chat : chats)
        {
            builder.append(chat.toXml());
        }
        builder.append(set.toXml());
        builder.append("</list>");
        return builder.toString();
     }
    
     public static class Chat {
        private String with;
        private String start;
    
        public Chat()
        {
        }
    
        public Chat(String with, String start)
        {
            this.with = with;
            this.start = start;
        }
    
        public String getWith()
        {
            return with;
        }
    
        public void setWith(String with)
        {
            this.with = with;
        }
    
        public String getStart()
        {
            return start;
        }
    
        public void setStart(String start)
        {
            this.start = start;
        }
    
        public String toXml()
        {
            StringBuilder builder = new StringBuilder("<chat with=\"");
            builder.append(with).append("\"");
            builder.append(" start=\"");
            builder.append(start);
            builder.append("\"/>");
            return builder.toString();
        }
    
     }
    
     public static class Set {
        private int last;
        private int count;
        private int indexAtt;
        private int first;
    
        public Set()
        {
        }
    
        public int getLast()
        {
            return last;
        }
    
        public void setLast(int last)
        {
            this.last = last;
        }
    
        public int getCount()
        {
            return count;
        }
    
        public void setCount(int count)
        {
            this.count = count;
        }
    
        public int getIndexAtt()
        {
            return indexAtt;
        }
    
        public void setIndexAtt(int indexAtt)
        {
            this.indexAtt = indexAtt;
        }
    
        public int getFirst()
        {
            return first;
        }
    
        public void setFirst(int first)
        {
            this.first = first;
        }
    
        public String toXml()
        {
            StringBuilder builder = new StringBuilder("<set xmlns=\"http://jabber.org/protocol/rsm\">");
            builder.append("<first index=\"").append(indexAtt).append("\">").append(first).append("</first>");
            builder.append("<last>").append(last).append("</last>");
            builder.append("<count>").append(count).append("</count>");
            builder.append("</set>");
            return builder.toString();
        }
     }
    
    }
    

    我只是使用这个类,在 Xmpp 连接连接后立即调用ServiceProviders.Register_Providers(ProviderManager.getInstance());

    服务提供者:

    public class ServiceProviders
    {
        public static void Register_Providers(ProviderManager pm)
        {
            Log.e("PROVIDER", "START");
            // Private Data Storage
            pm.addIQProvider("query", "jabber:iq:private", new PrivateDataManager.PrivateDataIQProvider());
    
            // Time
            try
            {
                pm.addIQProvider("query", "jabber:iq:time", Class.forName("org.jivesoftware.smackx.packet.Time"));
            }
            catch (ClassNotFoundException e)
            {
                Log.w("TestClient", "Can't load class for org.jivesoftware.smackx.packet.Time");
            }
    
            // Roster Exchange
            pm.addExtensionProvider("x", "jabber:x:roster", new RosterExchangeProvider());
    
            // Message Events
            pm.addExtensionProvider("x", "jabber:x:event", new MessageEventProvider());
    
            // Chat State
            pm.addExtensionProvider("active", "http://jabber.org/protocol/chatstates", new ChatStateExtension.Provider());
    
            pm.addExtensionProvider("composing", "http://jabber.org/protocol/chatstates", new ChatStateExtension.Provider());
    
            pm.addExtensionProvider("paused", "http://jabber.org/protocol/chatstates", new ChatStateExtension.Provider());
    
            pm.addExtensionProvider("inactive", "http://jabber.org/protocol/chatstates", new ChatStateExtension.Provider());
    
            pm.addExtensionProvider("gone", "http://jabber.org/protocol/chatstates", new ChatStateExtension.Provider());
    
            // XHTML
            pm.addExtensionProvider("html", "http://jabber.org/protocol/xhtml-im", new XHTMLExtensionProvider());
    
            // Group Chat Invitations
            pm.addExtensionProvider("x", "jabber:x:conference", new GroupChatInvitation.Provider());
    
            // Service Discovery # Items
            pm.addIQProvider("query", "http://jabber.org/protocol/disco#items", new DiscoverItemsProvider());
    
            // Service Discovery # Info
            pm.addIQProvider("query", "http://jabber.org/protocol/disco#info", new DiscoverInfoProvider());
    
            // Data Forms
            pm.addExtensionProvider("x", "jabber:x:data", new DataFormProvider());
    
            // MUC User
            pm.addExtensionProvider("x", "http://jabber.org/protocol/muc#user", new MUCUserProvider());
    
            // MUC Admin
            pm.addIQProvider("query", "http://jabber.org/protocol/muc#admin", new MUCAdminProvider());
    
            // MUC Owner
            pm.addIQProvider("query", "http://jabber.org/protocol/muc#owner", new MUCOwnerProvider());
    
            // Delayed Delivery
            pm.addExtensionProvider("x", "jabber:x:delay", new DelayInformationProvider());
    
            // Version
            try
            {
                pm.addIQProvider("query", "jabber:iq:version", Class.forName("org.jivesoftware.smackx.packet.Version"));
            }
            catch (ClassNotFoundException e)
            {
                // Not sure what's happening here.
            }
    
            // VCard
            pm.addIQProvider("vCard", "vcard-temp", new VCardProvider());
    
            // Offline Message Requests
            pm.addIQProvider("offline", "http://jabber.org/protocol/offline", new OfflineMessageRequest.Provider());
    
            // Offline Message Indicator
            pm.addExtensionProvider("offline", "http://jabber.org/protocol/offline", new OfflineMessageInfo.Provider());
    
            // Last Activity
            pm.addIQProvider("query", "jabber:iq:last", new LastActivity.Provider());
    
            // User Search
            pm.addIQProvider("query", "jabber:iq:search", new UserSearch.Provider());
    
            // SharedGroupsInfo
            pm.addIQProvider("sharedgroup", "http://www.jivesoftware.org/protocol/sharedgroup", new SharedGroupsInfo.Provider());
    
            // JEP-33: Extended Stanza Addressing
            pm.addExtensionProvider("addresses", "http://jabber.org/protocol/address", new MultipleAddressesProvider());
    
            // FileTransfer
            pm.addIQProvider("si", "http://jabber.org/protocol/si", new StreamInitiationProvider());
    
            pm.addIQProvider("query", "http://jabber.org/protocol/bytestreams", new BytestreamsProvider());
    
            // Privacy
            pm.addIQProvider("query", "jabber:iq:privacy", new PrivacyProvider());
    
            pm.addIQProvider("command", "http://jabber.org/protocol/commands", new AdHocCommandDataProvider());
            pm.addExtensionProvider("malformed-action", "http://jabber.org/protocol/commands", new AdHocCommandDataProvider.MalformedActionError());
            pm.addExtensionProvider("bad-locale", "http://jabber.org/protocol/commands", new AdHocCommandDataProvider.BadLocaleError());
            pm.addExtensionProvider("bad-payload", "http://jabber.org/protocol/commands", new AdHocCommandDataProvider.BadPayloadError());
            pm.addExtensionProvider("bad-sessionid", "http://jabber.org/protocol/commands", new AdHocCommandDataProvider.BadSessionIDError());
            pm.addExtensionProvider("session-expired", "http://jabber.org/protocol/commands", new AdHocCommandDataProvider.SessionExpiredError());
    
            pm.addIQProvider("query", "http://jabber.org/protocol/disco#info", new DiscoverInfoProvider());
    
            pm.addExtensionProvider("x", "jabber:x:data", new DataFormProvider());
    
            // archive
            pm.addIQProvider("list", "urn:xmpp:archive", new ListIQProvider());
    
            pm.addIQProvider("chat", "urn:xmpp:archive", new ChatIQProvider());
    
        }
    }
    

    @HirenPatel

    首先您需要将归档插件添加到Openfire。 然后在客户端中的Xmpp连接之后,您必须注册您的供应商,包括帮助检索聊天消息的供应商:

    pm.addIQProvider("list", "urn:xmpp:archive", new ListIQProvider());
    pm.addIQProvider("chat", "urn:xmpp:archive", new ChatIQProvider());
    

    然后你需要像下面这样发送一个 IQ 节:

    final IQ iq = new IQ()
    {
    
        @Override public String getChildElementXML()
        {
    
            return "<retrieve  xmlns='urn:xmpp:archive' with='test@customOpenfire.com'><set xmlns='http://jabber.org/protocol/rsm'><max xmlns='http://jabber.org/protocol/rsm'>30</max></set> </retrieve>";
    
        }
    };
    
    iq.setType(IQ.Type.GET);
    iq.setPacketID("987654321");
    
    xmppConnection.sendPacket(iq);
    

    【讨论】:

    • 嗨,你从哪里得到 pm.addIQProvider("list", "urn:xmpp:archive", new ListIQProvider()); 的结果。你有 ListIQProvider 的代码吗?
    • 嗨安娜。评论太长,所以我将其添加到上面的答案中。
    • 谢谢,但我不明白你把这行放在哪里: pm.addIQProvider("chat", "urn:xmpp:archive", new ChatIQProvider());
    • 不,它们不一样。 ChatIQ 包含一个带有正文的聊天,该正文是消息的实际内容。而 ListIQ 包含一个没有正文的聊天列表。哪个智商节?如果您指的是我发送来恢复存档的节,则列表和检索都在开头的问题中。
    • @Miro,我该如何整合它?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-10-28
    • 2021-09-23
    • 2023-04-11
    • 2023-03-07
    • 2016-07-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多