aSmack - Пакет към XML с помощта на Packet Listener извежда nullable елементи

Използвам aSmack в моето приложение за Android, за да комуникирам с моя XMPP сървър, и включих отстраняването на грешки за Smack, за да мога да видя всички XML идващи/излизащи. Проблемът ми тук е, че използвам PacketListener, за да получа отговора на сървъра за пакета, който изпратих, но когато извикам метода toXML() на пакета, получих странен изход.
Класове и повече подробности по-долу.

Моят сървър има внедряване на XEP-0136 и тъй като aSmack все още няма кода за него, правя IQ пакета и го изпращам и това работи според очакванията, както можете да видите по-долу моя XML пакет, както е проектиран в XEP-0136, извлича списък с колекции ( http://xmpp.org/extensions/xep-0136.html#manage-list )

Xml пакет, изпратен до сървъра

06-13 14:11:21.769: D/SMACK(3018): 02:11:21 PM SENT (1079273464): 
<iq id="[email protected]/Smack/Conversations" type="get">
  <list with="[email protected]" xmlns="urn:xmpp:archive">
    <set xmlns="http://jabber.org/protocol/rsm">
      <max>30</max>
    </set>
  </list>
</iq>

За да създам този XML, получих файловете на XML схемата, както са проектирани в XEP-0136, и с помощта на SimpleXML lib картографирах всички елементи и това е кодът, който използвам, за да създам и изпратя пакета:

XMPPService.java

private static final int MAX_LIST = 30;

public void getConversations(String email, BaseActivity activity)
{
    if (isAuthenticated())
    {
        String packetId = connection.getUser() + "/Conversations";
        Set set = new Set();
        set.setMax(MAX_LIST);

        List list = new List();
        list.setWith(email);
        list.setSet(set);

        final IQ iq = new IQ();
        iq.setList(list);
        iq.setType(IQType.get);
        iq.setId(packetId);

        PacketIDFilter filter = new PacketIDFilter(packetId);
        connection.addPacketListener(new ChatListListener(activity), filter);
        sendPacket(iq);
    }
}

public void sendPacket(IQ iq)
{
    if (isAuthenticated())
    {
        connection.sendPacket(new IQPacket(iq));
    }
}

IQPacket.java

public class IQPacket extends Packet {

 private IQ iq;

 public IQPacket(IQ iq)
 {
    this.iq = iq;
 }

 public IQPacket(Packet packet, IQ iq)
 {
    super(packet);
    this.iq = iq;
 }

 @Override
 public String toXML()
 {
    StringWriter writer = new StringWriter();
    Serializer serializer = new Persister();
    try
    {
        serializer.write(iq, writer);
        return writer.getBuffer().toString();
    } catch (Exception e)
    {
        Log.e("COMPANY", "Error serializing xml", e);
    }
    return null;
 }

}

Както казах, тази част работи, проблемът ми е за слушателя, когато извикам метода toXML() за получения пакет, не мога да получа важната информация за чатовете, но изходът за отстраняване на грешки на Smack ми отпечатва всички информация, която очаквам, както можете да видите по-долу:

Smack Debug за получен XML

06-13 14:11:21.989: D/SMACK(3018): 02:11:21 PM RCV  (1079273464): 
<iq type="result" id="[email protected]/Smack/Conversations" to="[email protected]/Smack">
  <list xmlns="urn:xmpp:archive">
    <chat with="[email protected]" start="2013-06-10T13:19:25.000Z"/>
    <chat with="[email protected]" start="2013-06-10T13:36:50.876Z"/>
    <set xmlns="http://jabber.org/protocol/rsm">
      <first index="0">2</first>
      <last>3</last>
      <count>9</count>
    </set>
  </list>
</iq>

Също така този XML е очакваният отговор, тъй като имам всички тези елементи, картографирани като JavaBeans, но това е, което получавам, когато получа пакета на моя ChatListener и извикам метода toXML():

06-13 14:11:22.009: I/System.out(3018): 
<iq id="[email protected]/Smack/Conversations" to="[email protected]/Smack" type="result">nullnullnullnullnullnull2nullnull3nullnull9nullnull</iq>

ChatListListener.java

public class ChatListListener implements PacketListener {

 private BaseActivity activity;

 public ChatListListener(BaseActivity activity)
 {
    this.activity = activity;
 }

 @Override
 public void processPacket(Packet packet)
 {
    activity.notifyPacketReceived();
    System.out.println(packet.toXML());
 }
}

Пакетът е от org.jivesoftware.smack.packet.Packet, така че това е пакетът по подразбиране от aSmack lib.

Въпросът ми е какво правя различно от дебъгера Smack? Погледнах кода му и за това, което видях, той също извиква метода toXML() от пакета и добавя ReceiveListener. Идеята ми тук е, след като извикам toXML(), мога да използвам SimpleXML, за да го трансформирам в моя IQ.java, който картографирах и да започна да използвам неговата информация.

РЕДАКТИРАНЕ

Добавяне на повече информация. След като потърсих кода на Smack и как той обработва получения пакет, разбрах, че може би трябва да използвам IQProvider. Така че регистрирах своя IQProvider

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

И след това поставих точка на прекъсване на метода parseIQ(XmlPullParser arg0) на моя IQProvider и пакетът всъщност се изпраща на моя доставчик, но все пак има всички тези нулеви елементи. Изгубен съм в момента, защото имам нужда от това, за да продължа да работя, ще продължа да проучвам изходния код на Smack.


person Davi Alves    schedule 13.06.2013    source източник


Отговори (2)


След много проучвания и търсене на източници на Smack, открих решението. Стъпките са, добавете IQProvider, добавете PacketListener за вашия пакет, изпратете пакета. Изчакайте пакета на вашия IQProvider, анализирайте го и получете отговора си на вашия Listener.

И така addIQProvider и addPacketListener бяха прави, работата е там, че трябва да направя пълния анализ на XML на моя ListIQProvider, звучи просто, но ми отне известно време разберете това.

public class ListIQProvider implements IQProvider {

 public ListIQProvider()
 {
 }

 @Override
 public IQ parseIQ(XmlPullParser parser) throws Exception
 {
    Logger.d(String.format("Received iq packet, namespace[%s], name[%s]", parser.getNamespace(), parser.getName()));
    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"));
 }
}

След това всичко, което трябваше да направя на моя ChatListListener, беше да прехвърлям Packet към моя клас ListIQ. Това е. Работата тук е, че пакетът, получен от моя ChatListListener, е същият пакет, който се връща от метода parseIQ на моя ListIQProvider. Така че в този въпрос/отговор имаме почти всичко необходимо за XEP-0136 или поне започнете да го използвате. Тъй като не намерих добър и лесен източник в мрежата, който да ми помогне, споделям своя тук. По-долу е класът 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();
    }
 }

}
person Davi Alves    schedule 17.06.2013
comment
можете ли да отговорите на stackoverflow.com/ questions/22566411/ Аз също съм изправен пред същия проблем - person No_Rulz; 22.03.2014
comment
Благодаря за пълния източник, точно това ми трябваше. Това ли е причината хората да предпочитат JSON сега или това е просто ужасен дизайн? - person sbaar; 30.08.2014
comment
Няма проблем. Всъщност XEP имат добър дизайн, просто е трудно да го реализирате сами. Не мисля, че JSON би отговарял на изискванията на XMPP, има по-голям смисъл да се използва XML, предполагам, а освен това протоколът е по-стар от JSON. - person Davi Alves; 01.09.2014

Здравейте, аз също имах същия проблем и мога да кажа, че този код работи, просто бих променил начина, по който създавате заявката за списъка към сървъра. (поне на моя сървър)

final IQ iq = new IQ()
    {

        @Override public String getChildElementXML()
        {

            return "<list xmlns='urn:xmpp:archive'/>";

        }
    };

    iq.setType(IQ.Type.GET);

    PacketTypeFilter filter = new PacketTypeFilter(Packet.class);


    connection.addPacketListener(new PacketListener()
    {
        @Override public void processPacket(Packet packet)
        {
            Log.i(TAG, packet.toXML());
        }
    }, filter);

    connection.sendPacket(iq);

както казахте преди, изглежда доста лесно, но документацията не е много ясна за това как да се изгради IQ обект. Надявам се да помогне.

person pleonasmik    schedule 12.02.2014
comment
Но пак няма да можете да анализирате отговора. Вие просто правите възможно изпращането на заявка за извличане на чатове. - person Davi Alves; 13.02.2014
comment
Разбира се, че не, за да обработите отговора, трябва да регистрирате доставчик, както направихте. Току-що се опитах да направя публикацията ви малко по-добра, но все пак вашият код е важната част, затова разработих класовете, които се простират от IQProvider за анализиране на чат (и съобщение) по доста различен начин. Все пак ти дадох +1, защото публикацията ти ми помогна много. - person pleonasmik; 14.02.2014
comment
Хей, опитах, но получавам грешка 503 услугата не е налична. ‹iq id=hsWL2-4 [email protected] [email protected] type=error›‹error code=503 type=CANCEL› ‹service-unavailable xmlns=urn: ietf:params:xml:ns:xmpp-stanzas/›‹/error›‹/iq› - person Hardik; 06.03.2014
comment
@Hardik, изглежда, че сървърът не работи или архивът на съобщенията не е достъпен? - person pleonasmik; 22.04.2014