Make PubSubManager.getNode(String) more robust

I've got reports from users that in some cases there can be multiple
identities. Not just one, and in this case, the node type may not be the
first identity. We now iterate over all identities until we either found
one of type "leaf" or "collection".

For example one user reports an ejabberd with PEP case, where the first
identity is of type "pep", the second of type "leaf" and a third one
with category "account" and type "registered".

Also extend DiscoverInfo API with hasIdentity(String, String) and
getIdentities(String, String).
This commit is contained in:
Florian Schmaus 2014-10-16 17:43:44 +02:00
parent 8d7b329432
commit 17bb738e9e
2 changed files with 52 additions and 5 deletions

View File

@ -19,6 +19,7 @@ package org.jivesoftware.smackx.disco.packet;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.util.XmlStringBuilder;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
@ -129,6 +130,39 @@ public class DiscoverInfo extends IQ implements Cloneable {
return Collections.unmodifiableList(identities);
}
/**
* Returns true if this DiscoverInfo contains at least one Identity of the given category and type.
*
* @param category the category to look for.
* @param type the type to look for.
* @return true if this DiscoverInfo contains a Identity of the given category and type.
*/
public boolean hasIdentity(String category, String type) {
for (Identity identity : identities) {
if (identity.getCategory().equals(category) && identity.getType().equals(type)) {
return true;
}
}
return false;
}
/**
* Returns all Identities of the given category and type of this DiscoverInfo.
*
* @param category category the category to look for.
* @param type type the type to look for.
* @return a list of Identites with the given category and type.
*/
public List<Identity> getIdentities(String category, String type) {
List<Identity> res = new ArrayList<Identity>(identities.size());
for (Identity identity : identities) {
if (identity.getCategory().equals(category) && identity.getType().equals(type)) {
res.add(identity);
}
}
return res;
}
/**
* Returns the node attribute that supplements the 'jid' attribute. A node is merely
* something that is associated with a JID and for which the JID can provide information.<p>

View File

@ -171,11 +171,24 @@ final public class PubSubManager
info.setNode(id);
DiscoverInfo infoReply = (DiscoverInfo) con.createPacketCollectorAndSend(info).nextResultOrThrow();
if (infoReply.getIdentities().get(0).getType().equals(NodeType.leaf.toString()))
node = new LeafNode(con, id);
else
node = new CollectionNode(con, id);
if (infoReply.hasIdentity(PubSub.ELEMENT, "leaf")) {
node = new LeafNode(con, id);
}
else if (infoReply.hasIdentity(PubSub.ELEMENT, "collection")) {
node = new CollectionNode(con, id);
}
else {
// XEP-60 5.3 states that
// "The 'disco#info' result MUST include an identity with a category of 'pubsub' and a type of either 'leaf' or 'collection'."
// If this is not the case, then we are dealing with an PubSub implementation that doesn't follow the specification.
throw new AssertionError(
"PubSub service '"
+ to
+ "' returned disco info result for node '"
+ id
+ "', but it did not contain an Identity of type 'leaf' or 'collection' (and category 'pubsub'), which is not allowed according to XEP-60 5.3.");
}
node.setTo(to);
nodeMap.put(id, node);
}