Rework DiscoverInfo

Make Feature and Identity immutable and allow fast lookup of those two
in DiscoverInfo.
This commit is contained in:
Florian Schmaus 2014-10-31 22:22:22 +01:00
parent b60b20e312
commit 6fec813ec0
5 changed files with 100 additions and 95 deletions

View File

@ -49,7 +49,6 @@ import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream.StreamHostUs
import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
import org.jivesoftware.smackx.disco.packet.DiscoverInfo;
import org.jivesoftware.smackx.disco.packet.DiscoverItems;
import org.jivesoftware.smackx.disco.packet.DiscoverInfo.Identity;
import org.jivesoftware.smackx.disco.packet.DiscoverItems.Item;
import org.jivesoftware.smackx.filetransfer.FileTransferManager;
@ -572,20 +571,14 @@ public final class Socks5BytestreamManager implements BytestreamManager {
continue;
}
// item must have category "proxy" and type "bytestream"
for (Identity identity : proxyInfo.getIdentities()) {
if ("proxy".equalsIgnoreCase(identity.getCategory())
&& "bytestreams".equalsIgnoreCase(identity.getType())) {
proxies.add(item.getEntityID());
break;
}
if (proxyInfo.hasIdentity("proxy", "bytestreams")) {
proxies.add(item.getEntityID());
} else {
/*
* server is not a SOCKS5 proxy, blacklist server to skip next time a Socks5
* bytestream should be established
*/
this.proxyBlacklist.add(item.getEntityID());
}
}

View File

@ -202,18 +202,6 @@ public class ServiceDiscoveryManager extends Manager {
return identity.getName();
}
/**
* Sets the name of the client that will be returned when asked for the client identity
* in a disco request. The name could be any value you need to identity this client.
*
* @param name the name of the client that will be returned when asked for the client identity
* in a disco request.
*/
public void setIdentityName(String name) {
identity.setName(name);
renewEntityCapsVersion();
}
/**
* Sets the default identity the client will report.
*

View File

@ -17,13 +17,17 @@
package org.jivesoftware.smackx.disco.packet;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.smack.util.XmlStringBuilder;
import org.jxmpp.util.XmppStringUtils;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
/**
* A DiscoverInfo IQ packet, which is used by XMPP clients to request and receive information
@ -39,8 +43,11 @@ public class DiscoverInfo extends IQ implements Cloneable {
public static final String NAMESPACE = "http://jabber.org/protocol/disco#info";
private final List<Feature> features = new LinkedList<Feature>();
private final Set<Feature> featuresSet = new HashSet<Feature>();
private final List<Identity> identities = new LinkedList<Identity>();
private final Set<String> identitiesSet = new HashSet<String>();
private String node;
private boolean containsDuplicateFeatures;
public DiscoverInfo() {
super();
@ -72,9 +79,10 @@ public class DiscoverInfo extends IQ implements Cloneable {
* Adds a new feature to the discovered information.
*
* @param feature the discovered feature
* @return true if the feature did not already exist.
*/
public void addFeature(String feature) {
addFeature(new Feature(feature));
public boolean addFeature(String feature) {
return addFeature(new Feature(feature));
}
/**
@ -89,8 +97,13 @@ public class DiscoverInfo extends IQ implements Cloneable {
}
}
private void addFeature(Feature feature) {
public boolean addFeature(Feature feature) {
features.add(feature);
boolean featureIsNew = featuresSet.add(feature);
if (!featureIsNew) {
containsDuplicateFeatures = true;
}
return featureIsNew;
}
/**
@ -109,6 +122,7 @@ public class DiscoverInfo extends IQ implements Cloneable {
*/
public void addIdentity(Identity identity) {
identities.add(identity);
identitiesSet.add(identity.getKey());
}
/**
@ -118,7 +132,9 @@ public class DiscoverInfo extends IQ implements Cloneable {
*/
public void addIdentities(Collection<Identity> identitiesToAdd) {
if (identitiesToAdd == null) return;
identities.addAll(identitiesToAdd);
for (Identity identity : identitiesToAdd) {
addIdentity(identity);
}
}
/**
@ -138,12 +154,8 @@ public class DiscoverInfo extends IQ implements Cloneable {
* @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;
String key = XmppStringUtils.generateKey(category, type);
return identitiesSet.contains(key);
}
/**
@ -196,11 +208,7 @@ public class DiscoverInfo extends IQ implements Cloneable {
* @return true if the requestes feature has been discovered
*/
public boolean containsFeature(String feature) {
for (Feature f : getFeatures()) {
if (feature.equals(f.getVar()))
return true;
}
return false;
return features.contains(new Feature(feature));
}
@Override
@ -245,15 +253,7 @@ public class DiscoverInfo extends IQ implements Cloneable {
* @return true if duplicate identities where found, otherwise false
*/
public boolean containsDuplicateFeatures() {
List<Feature> checkedFeatures = new LinkedList<Feature>();
for (Feature f : features) {
for (Feature f2 : checkedFeatures) {
if (f.equals(f2))
return true;
}
checkedFeatures.add(f);
}
return false;
return containsDuplicateFeatures;
}
@Override
@ -273,13 +273,27 @@ public class DiscoverInfo extends IQ implements Cloneable {
public static class Identity implements Comparable<Identity>, Cloneable {
private final String category;
private String name;
private final String type;
private String lang; // 'xml:lang;
private final String key;
private final String name;
private final String lang; // 'xml:lang;
public Identity(Identity identity) {
this(identity.category, identity.name, identity.type);
lang = identity.lang;
this.category = identity.category;
this.type = identity.type;
this.key = identity.type;
this.name = identity.name;
this.lang = identity.lang;
}
/**
* Creates a new identity for an XMPP entity.
*
* @param category the entity's category (required as per XEP-30).
* @param type the entity's type (required as per XEP-30).
*/
public Identity(String category, String type) {
this(category, type, null, null);
}
/**
@ -292,12 +306,31 @@ public class DiscoverInfo extends IQ implements Cloneable {
* @param type the entity's type (required as per XEP-30).
*/
public Identity(String category, String name, String type) {
if ((category == null) || (type == null))
throw new IllegalArgumentException("category and type cannot be null");
this(category, type, name, null);
}
/**
* Creates a new identity for an XMPP entity.
* 'category' and 'type' are required by
* <a href="http://xmpp.org/extensions/xep-0030.html#schemas">XEP-30 XML Schemas</a>
*
* @param category the entity's category (required as per XEP-30).
* @param type the entity's type (required as per XEP-30).
* @param name the entity's name.
* @param lang the entity's lang.
*/
public Identity(String category, String type, String name, String lang) {
if (StringUtils.isNullOrEmpty(category)) {
throw new IllegalArgumentException("category cannot be null");
}
if (StringUtils.isNullOrEmpty(type)) {
throw new IllegalArgumentException("type cannot be null");
}
this.category = category;
this.name = name;
this.type = type;
this.key = XmppStringUtils.generateKey(category, type);
this.name = name;
this.lang = lang;
}
/**
@ -319,15 +352,6 @@ public class DiscoverInfo extends IQ implements Cloneable {
return name;
}
/**
* Set the identity's name.
*
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* Returns the entity's type. To get the official registry of values for the
* 'type' attribute refer to <a href="http://www.jabber.org/registrar/disco-categories.html">Jabber::Registrar</a>
@ -338,15 +362,6 @@ public class DiscoverInfo extends IQ implements Cloneable {
return type;
}
/**
* Sets the natural language (xml:lang) for this identity (optional)
*
* @param lang the xml:lang of this Identity
*/
public void setLanguage(String lang) {
this.lang = lang;
}
/**
* Returns the identities natural language if one is set
*
@ -356,6 +371,21 @@ public class DiscoverInfo extends IQ implements Cloneable {
return lang;
}
private String getKey() {
return key;
}
/**
* Returns true if this identity is of the given category and type.
*
* @param category the category.
* @param type the type.
* @return true if this identity is of the given category and type.
*/
public boolean isOfCategoryAndType(String category, String type) {
return this.category.equals(category) && this.type.equals(type);
}
public XmlStringBuilder toXML() {
XmlStringBuilder xml = new XmlStringBuilder();
xml.halfOpenElement("identity");
@ -382,19 +412,13 @@ public class DiscoverInfo extends IQ implements Cloneable {
return false;
DiscoverInfo.Identity other = (DiscoverInfo.Identity) obj;
if (!this.category.equals(other.category))
if (!this.key.equals(other.key))
return false;
String otherLang = other.lang == null ? "" : other.lang;
String thisLang = lang == null ? "" : lang;
if (!otherLang.equals(thisLang))
return false;
// This safeguard can be removed once the deprecated constructor is removed.
String otherType = other.type == null ? "" : other.type;
String thisType = type == null ? "" : type;
if (!otherType.equals(thisType))
return false;
String otherName = other.name == null ? "" : other.name;
String thisName = name == null ? "" : other.name;
@ -407,9 +431,8 @@ public class DiscoverInfo extends IQ implements Cloneable {
@Override
public int hashCode() {
int result = 1;
result = 37 * result + category.hashCode();
result = 37 * result + key.hashCode();
result = 37 * result + (lang == null ? 0 : lang.hashCode());
result = 37 * result + (type == null ? 0 : type.hashCode());
result = 37 * result + (name == null ? 0 : name.hashCode());
return result;
}

View File

@ -66,14 +66,13 @@ public class DiscoverInfoProvider extends IQProvider<DiscoverInfo> {
} else if (eventType == XmlPullParser.END_TAG) {
if (parser.getName().equals("identity")) {
// Create a new identity and add it to the discovered info.
identity = new DiscoverInfo.Identity(category, name, type);
if (lang != null)
identity.setLanguage(lang);
identity = new DiscoverInfo.Identity(category, type, name, lang);
discoverInfo.addIdentity(identity);
}
if (parser.getName().equals("feature")) {
// Create a new feature and add it to the discovered info.
discoverInfo.addFeature(variable);
boolean notADuplicateFeature = discoverInfo.addFeature(variable);
assert(notADuplicateFeature);
}
if (parser.getName().equals("query")) {
done = true;

View File

@ -26,6 +26,7 @@ import java.util.Collection;
import java.util.LinkedList;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.test.util.SmackTestSuite;
import org.jivesoftware.smack.util.stringencoder.Base32;
import org.jivesoftware.smack.util.stringencoder.StringEncoder;
import org.jivesoftware.smackx.InitExtensions;
@ -34,11 +35,17 @@ import org.jivesoftware.smackx.caps.cache.SimpleDirectoryPersistentCache;
import org.jivesoftware.smackx.disco.packet.DiscoverInfo;
import org.jivesoftware.smackx.xdata.FormField;
import org.jivesoftware.smackx.xdata.packet.DataForm;
import org.junit.Before;
import org.junit.Test;
public class EntityCapsManagerTest extends InitExtensions {
@Before
public void initSmackTestSuite() {
SmackTestSuite.init();
}
/**
* <a href="http://xmpp.org/extensions/xep-0115.html#ver-gen-complex">XEP-
* 0115 Complex Generation Example</a>
@ -96,11 +103,9 @@ public class EntityCapsManagerTest extends InitExtensions {
di.setType(IQ.Type.result);
Collection<DiscoverInfo.Identity> identities = new LinkedList<DiscoverInfo.Identity>();
DiscoverInfo.Identity i = new DiscoverInfo.Identity("client", "Psi 0.11", "pc");
i.setLanguage("en");
DiscoverInfo.Identity i = new DiscoverInfo.Identity("client", "pc", "Psi 0.11", "en");
identities.add(i);
i = new DiscoverInfo.Identity("client", "Ψ 0.11", "pc");
i.setLanguage("el");
i = new DiscoverInfo.Identity("client", "pc", "Ψ 0.11", "el");
identities.add(i);
di.addIdentities(identities);
@ -149,16 +154,13 @@ public class EntityCapsManagerTest extends InitExtensions {
di.setType(IQ.Type.result);
Collection<DiscoverInfo.Identity> identities = new LinkedList<DiscoverInfo.Identity>();
DiscoverInfo.Identity i = new DiscoverInfo.Identity("client", "Psi 0.11", "pc");
i.setLanguage("en");
DiscoverInfo.Identity i = new DiscoverInfo.Identity("client", "pc", "Psi 0.11", "en");
identities.add(i);
i = new DiscoverInfo.Identity("client", "Ψ 0.11", "pc");
i.setLanguage("el");
i = new DiscoverInfo.Identity("client", "pc", "Ψ 0.11", "el");
identities.add(i);
di.addIdentities(identities);
// Failure 1: Duplicate identities
i = new DiscoverInfo.Identity("client", "Ψ 0.11", "pc");
i.setLanguage("el");
i = new DiscoverInfo.Identity("client", "pc", "Ψ 0.11", "el");
identities.add(i);
di.addIdentities(identities);