Add DiscoInfoLookupShortcutMechanism and EntityCapabilitiesChangedListener

to allow for plugable XEP-0115 like mechanisms. For example XEP-0390.
This commit is contained in:
Florian Schmaus 2018-05-10 19:24:55 +02:00
parent 0e31bc8f73
commit 72de6540b2
4 changed files with 155 additions and 41 deletions

View File

@ -59,6 +59,8 @@ import org.jivesoftware.smack.util.stringencoder.Base64;
import org.jivesoftware.smackx.caps.cache.EntityCapsPersistentCache;
import org.jivesoftware.smackx.caps.packet.CapsExtension;
import org.jivesoftware.smackx.disco.AbstractNodeInformationProvider;
import org.jivesoftware.smackx.disco.DiscoInfoLookupShortcutMechanism;
import org.jivesoftware.smackx.disco.EntityCapabilitiesChangedListener;
import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
import org.jivesoftware.smackx.disco.packet.DiscoverInfo;
import org.jivesoftware.smackx.disco.packet.DiscoverInfo.Feature;
@ -128,6 +130,36 @@ public final class EntityCapsManager extends Manager {
} catch (NoSuchAlgorithmException e) {
// Ignore
}
ServiceDiscoveryManager.addDiscoInfoLookupShortcutMechanism(new DiscoInfoLookupShortcutMechanism("XEP-0115: Entity Capabilities", 100) {
@Override
public DiscoverInfo getDiscoverInfoByUser(ServiceDiscoveryManager serviceDiscoveryManager, Jid jid) {
DiscoverInfo info = EntityCapsManager.getDiscoverInfoByUser(jid);
if (info != null) {
return info;
}
NodeVerHash nodeVerHash = getNodeVerHashByJid(jid);
if (nodeVerHash == null) {
return null;
}
try {
info = serviceDiscoveryManager.discoverInfo(jid, nodeVerHash.getNodeVer());
} catch (NoResponseException | XMPPErrorException | NotConnectedException | InterruptedException e) {
// TODO log
return null;
}
if (verifyDiscoverInfoVersion(nodeVerHash.getVer(), nodeVerHash.getHash(), info)) {
addDiscoverInfoByNode(nodeVerHash.getNodeVer(), info);
} else {
// TODO log
}
return info;
}
});
}
/**
@ -148,7 +180,7 @@ public final class EntityCapsManager extends Manager {
* @param info
* DiscoverInfo for the specified node.
*/
public static void addDiscoverInfoByNode(String nodeVer, DiscoverInfo info) {
static void addDiscoverInfoByNode(String nodeVer, DiscoverInfo info) {
CAPS_CACHE.put(nodeVer, info);
if (persistentCache != null)
@ -365,7 +397,16 @@ public final class EntityCapsManager extends Manager {
connection.addStanzaInterceptor(packetInterceptor, PresenceTypeFilter.AVAILABLE);
// It's important to do this as last action. Since it changes the
// behavior of the SDM in some ways
sdm.setEntityCapsManager(this);
sdm.addEntityCapabilitiesChangedListener(new EntityCapabilitiesChangedListener() {
@Override
public void onEntityCapailitiesChanged() {
if (!entityCapsEnabled()) {
return;
}
updateLocalEntityCaps();
}
});
}
public static synchronized EntityCapsManager getInstanceFor(XMPPConnection connection) {
@ -473,7 +514,7 @@ public final class EntityCapsManager extends Manager {
* presence is send to inform others about your new Entity Caps node string.
*
*/
public void updateLocalEntityCaps() {
private void updateLocalEntityCaps() {
XMPPConnection connection = connection();
DiscoverInfo discoverInfo = new DiscoverInfo();

View File

@ -0,0 +1,54 @@
/**
*
* Copyright 2018 Florian Schmaus.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.disco;
import org.jivesoftware.smackx.disco.packet.DiscoverInfo;
import org.jxmpp.jid.Jid;
public abstract class DiscoInfoLookupShortcutMechanism implements Comparable<DiscoInfoLookupShortcutMechanism> {
private final String name;
private final int priority;
protected DiscoInfoLookupShortcutMechanism(String name, int priority) {
this.name = name;
this.priority = priority;
}
public final String getName() {
return name;
}
/**
* Get the priority of this mechanism. Lower values mean higher priority.
*
* @return the priority of this mechanism.
*/
public final int getPriority() {
return priority;
}
public abstract DiscoverInfo getDiscoverInfoByUser(ServiceDiscoveryManager serviceDiscoveryManager, Jid jid);
@Override
public final int compareTo(DiscoInfoLookupShortcutMechanism other) {
// Switch to Integer.compare(int, int) once Smack is on Android 19 or higher.
Integer ourPriority = getPriority();
return ourPriority.compareTo(other.getPriority());
}
}

View File

@ -0,0 +1,23 @@
/**
*
* Copyright 2018 Florian Schmaus.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.disco;
public interface EntityCapabilitiesChangedListener {
void onEntityCapailitiesChanged();
}

View File

@ -27,6 +27,7 @@ import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
import org.jivesoftware.smack.ConnectionCreationListener;
import org.jivesoftware.smack.Manager;
@ -44,7 +45,6 @@ import org.jivesoftware.smack.packet.StanzaError;
import org.jivesoftware.smack.util.Objects;
import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.smackx.caps.EntityCapsManager;
import org.jivesoftware.smackx.disco.packet.DiscoverInfo;
import org.jivesoftware.smackx.disco.packet.DiscoverInfo.Identity;
import org.jivesoftware.smackx.disco.packet.DiscoverItems;
@ -74,13 +74,15 @@ public final class ServiceDiscoveryManager extends Manager {
private static final String DEFAULT_IDENTITY_CATEGORY = "client";
private static final String DEFAULT_IDENTITY_TYPE = "pc";
private static final List<DiscoInfoLookupShortcutMechanism> discoInfoLookupShortcutMechanisms = new ArrayList<>(2);
private static DiscoverInfo.Identity defaultIdentity = new Identity(DEFAULT_IDENTITY_CATEGORY,
DEFAULT_IDENTITY_NAME, DEFAULT_IDENTITY_TYPE);
private final Set<DiscoverInfo.Identity> identities = new HashSet<>();
private DiscoverInfo.Identity identity = defaultIdentity;
private EntityCapsManager capsManager;
private final Set<EntityCapabilitiesChangedListener> entityCapabilitiesChangedListeners = new CopyOnWriteArraySet<>();
private static final Map<XMPPConnection, ServiceDiscoveryManager> instances = new WeakHashMap<>();
@ -488,30 +490,19 @@ public final class ServiceDiscoveryManager extends Manager {
if (entityID == null)
return discoverInfo(null, null);
// Check if the have it cached in the Entity Capabilities Manager
DiscoverInfo info = EntityCapsManager.getDiscoverInfoByUser(entityID);
if (info != null) {
// We were able to retrieve the information from Entity Caps and
// avoided a disco request, hurray!
return info;
synchronized (discoInfoLookupShortcutMechanisms) {
for (DiscoInfoLookupShortcutMechanism discoInfoLookupShortcutMechanism : discoInfoLookupShortcutMechanisms) {
DiscoverInfo info = discoInfoLookupShortcutMechanism.getDiscoverInfoByUser(this, entityID);
if (info != null) {
// We were able to retrieve the information from Entity Caps and
// avoided a disco request, hurray!
return info;
}
}
}
// Try to get the newest node#version if it's known, otherwise null is
// returned
EntityCapsManager.NodeVerHash nvh = EntityCapsManager.getNodeVerHashByJid(entityID);
// Discover by requesting the information from the remote entity
// Note that wee need to use NodeVer as argument for Node if it exists
info = discoverInfo(entityID, nvh != null ? nvh.getNodeVer() : null);
// If the node version is known, store the new entry.
if (nvh != null) {
if (EntityCapsManager.verifyDiscoverInfoVersion(nvh.getVer(), nvh.getHash(), info))
EntityCapsManager.addDiscoverInfoByNode(nvh.getNodeVer(), info);
}
return info;
// Last resort: Standard discovery.
return discoverInfo(entityID, null);
}
/**
@ -933,24 +924,29 @@ public final class ServiceDiscoveryManager extends Manager {
return findService(feature, useCache, null, null);
}
/**
* Entity Capabilities
*/
/**
* Loads the ServiceDiscoveryManager with an EntityCapsManger that speeds up certain lookups.
*
* @param manager
*/
public void setEntityCapsManager(EntityCapsManager manager) {
capsManager = manager;
public boolean addEntityCapabilitiesChangedListener(EntityCapabilitiesChangedListener entityCapabilitiesChangedListener) {
return entityCapabilitiesChangedListeners.add(entityCapabilitiesChangedListener);
}
/**
* Updates the Entity Capabilities Verification String if EntityCaps is enabled.
* Notify the {@link EntityCapabilitiesChangedListener} about changed capabilities.
*/
private void renewEntityCapsVersion() {
if (capsManager != null && capsManager.entityCapsEnabled())
capsManager.updateLocalEntityCaps();
for (EntityCapabilitiesChangedListener entityCapabilitiesChangedListener : entityCapabilitiesChangedListeners) {
entityCapabilitiesChangedListener.onEntityCapailitiesChanged();
}
}
public static void addDiscoInfoLookupShortcutMechanism(DiscoInfoLookupShortcutMechanism discoInfoLookupShortcutMechanism) {
synchronized (discoInfoLookupShortcutMechanisms) {
discoInfoLookupShortcutMechanisms.add(discoInfoLookupShortcutMechanism);
Collections.sort(discoInfoLookupShortcutMechanisms);
}
}
public static void removeDiscoInfoLookupShortcutMechanism(DiscoInfoLookupShortcutMechanism discoInfoLookupShortcutMechanism) {
synchronized (discoInfoLookupShortcutMechanisms) {
discoInfoLookupShortcutMechanisms.remove(discoInfoLookupShortcutMechanism);
}
}
}