protected static String generateVerificationString(DiscoverInfo discoverInfo, String hash) {
MessageDigest md = SUPPORTED_HASHES.get(hash.toLowerCase());
if (md == null)
return null;
DataForm extendedInfo = (DataForm) discoverInfo.getExtension(Form.ELEMENT, Form.NAMESPACE);
// 1. Initialize an empty string S ('sb' in this method).
StringBuilder sb = new StringBuilder(); // Use StringBuilder as we don't
// need thread-safe StringBuffer
// 2. Sort the service discovery identities by category and then by
// type and then by xml:lang
// (if it exists), formatted as CATEGORY '/' [TYPE] '/' [LANG] '/'
// [NAME]. Note that each slash is included even if the LANG or
// NAME is not included (in accordance with XEP-0030, the category and
// type MUST be included.
SortedSet<DiscoverInfo.Identity> sortedIdentities = new TreeSet<DiscoverInfo.Identity>();
for (Iterator<DiscoverInfo.Identity> it = discoverInfo.getIdentities(); it.hasNext();)
sortedIdentities.add(it.next());
// 3. For each identity, append the 'category/type/lang/name' to S,
// followed by the '<' character.
for (Iterator<DiscoverInfo.Identity> it = sortedIdentities.iterator(); it.hasNext();) {
DiscoverInfo.Identity identity = it.next();
sb.append(identity.getCategory());
sb.append("/");
sb.append(identity.getType());
sb.append("/");
sb.append(identity.getLanguage() == null ? "" : identity.getLanguage());
sb.append("/");
sb.append(identity.getName() == null ? "" : identity.getName());
sb.append("<");
}
// 4. Sort the supported service discovery features.
SortedSet<String> features = new TreeSet<String>();
for (Iterator<Feature> it = discoverInfo.getFeatures(); it.hasNext();)
features.add(it.next().getVar());
// 5. For each feature, append the feature to S, followed by the '<'
// character
for (String f : features) {
sb.append(f);
sb.append("<");
}
// only use the data form for calculation is it has a hidden FORM_TYPE
// field
// see XEP-0115 5.4 step 3.6
if (extendedInfo != null && extendedInfo.hasHiddenFormTypeField()) {
synchronized (extendedInfo) {
// 6. If the service discovery information response includes
// XEP-0128 data forms, sort the forms by the FORM_TYPE (i.e.,
// by the XML character data of the <value/> element).
SortedSet<FormField> fs = new TreeSet<FormField>(new Comparator<FormField>() {
public int compare(FormField f1, FormField f2) {
return f1.getVariable().compareTo(f2.getVariable());
}
});
FormField ft = null;
for (Iterator<FormField> i = extendedInfo.getFields(); i.hasNext();) {
FormField f = i.next();
if (!f.getVariable().equals("FORM_TYPE")) {
fs.add(f);
} else {
ft = f;