Don't use instanceof in a parse(IQ|PacketExtension)

Instead of using instanceof *every time* we parse an IQ or
PacketExtension, we now check the type of the Provider only once when
adding it.
This commit is contained in:
Florian Schmaus 2014-09-26 10:42:38 +02:00
parent 7977f119e8
commit 47dd63e6b2
2 changed files with 76 additions and 44 deletions

View File

@ -17,13 +17,15 @@
package org.jivesoftware.smack.provider; package org.jivesoftware.smack.provider;
import java.util.Collection; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import org.jivesoftware.smack.SmackConfiguration; import org.jivesoftware.smack.SmackConfiguration;
import org.jivesoftware.smack.packet.IQ; import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.PacketExtension;
import org.jxmpp.util.XmppStringUtils; import org.jxmpp.util.XmppStringUtils;
/** /**
@ -107,8 +109,10 @@ import org.jxmpp.util.XmppStringUtils;
*/ */
public final class ProviderManager { public final class ProviderManager {
private static final Map<String, Object> extensionProviders = new ConcurrentHashMap<String, Object>(); private static final Map<String, PacketExtensionProvider> extensionProviders = new ConcurrentHashMap<String, PacketExtensionProvider>();
private static final Map<String, Object> iqProviders = new ConcurrentHashMap<String, Object>(); private static final Map<String, IQProvider> iqProviders = new ConcurrentHashMap<String, IQProvider>();
private static final Map<String, Class<?>> extensionIntrospectionProviders = new ConcurrentHashMap<String, Class<?>>();
private static final Map<String, Class<?>> iqIntrospectionProviders = new ConcurrentHashMap<String, Class<?>>();
private static final Map<String, StreamFeatureProvider> streamFeatureProviders = new ConcurrentHashMap<String, StreamFeatureProvider>(); private static final Map<String, StreamFeatureProvider> streamFeatureProviders = new ConcurrentHashMap<String, StreamFeatureProvider>();
static { static {
@ -122,13 +126,13 @@ public final class ProviderManager {
public static void addLoader(ProviderLoader loader) { public static void addLoader(ProviderLoader loader) {
if (loader.getIQProviderInfo() != null) { if (loader.getIQProviderInfo() != null) {
for (IQProviderInfo info : loader.getIQProviderInfo()) { for (IQProviderInfo info : loader.getIQProviderInfo()) {
iqProviders.put(getKey(info.getElementName(), info.getNamespace()), info.getProvider()); addIQProvider(info.getElementName(), info.getNamespace(), info.getProvider());
} }
} }
if (loader.getExtensionProviderInfo() != null) { if (loader.getExtensionProviderInfo() != null) {
for (ExtensionProviderInfo info : loader.getExtensionProviderInfo()) { for (ExtensionProviderInfo info : loader.getExtensionProviderInfo()) {
extensionProviders.put(getKey(info.getElementName(), info.getNamespace()), info.getProvider()); addExtensionProvider(info.getElementName(), info.getNamespace(), info.getProvider());
} }
} }
} }
@ -153,11 +157,16 @@ public final class ProviderManager {
* @param namespace the XML namespace. * @param namespace the XML namespace.
* @return the IQ provider. * @return the IQ provider.
*/ */
public static Object getIQProvider(String elementName, String namespace) { public static IQProvider getIQProvider(String elementName, String namespace) {
String key = getKey(elementName, namespace); String key = getKey(elementName, namespace);
return iqProviders.get(key); return iqProviders.get(key);
} }
public static Class<?> getIQIntrospectionProvider(String elementName, String namespace) {
String key = getKey(elementName, namespace);
return iqIntrospectionProviders.get(key);
}
/** /**
* Returns an unmodifiable collection of all IQProvider instances. Each object * Returns an unmodifiable collection of all IQProvider instances. Each object
* in the collection will either be an IQProvider instance, or a Class object * in the collection will either be an IQProvider instance, or a Class object
@ -165,8 +174,11 @@ public final class ProviderManager {
* *
* @return all IQProvider instances. * @return all IQProvider instances.
*/ */
public static Collection<Object> getIQProviders() { public static List<Object> getIQProviders() {
return Collections.unmodifiableCollection(iqProviders.values()); List<Object> providers = new ArrayList<Object>(iqProviders.size() + iqIntrospectionProviders.size());
providers.addAll(iqProviders.values());
providers.addAll(iqIntrospectionProviders.values());
return Collections.unmodifiableList(providers);
} }
/** /**
@ -181,14 +193,16 @@ public final class ProviderManager {
public static void addIQProvider(String elementName, String namespace, public static void addIQProvider(String elementName, String namespace,
Object provider) Object provider)
{ {
if (!(provider instanceof IQProvider || (provider instanceof Class && // First remove existing providers
IQ.class.isAssignableFrom((Class<?>)provider)))) String key = removeIQProvider(elementName, namespace);
{ if (provider instanceof IQProvider) {
iqProviders.put(key, (IQProvider) provider);
} else if (provider instanceof Class && IQ.class.isAssignableFrom((Class<?>) provider)) {
iqIntrospectionProviders.put(key, (Class<?>) provider);
} else {
throw new IllegalArgumentException("Provider must be an IQProvider " + throw new IllegalArgumentException("Provider must be an IQProvider " +
"or a Class instance sublcassing IQ."); "or a Class instance sublcassing IQ.");
} }
String key = getKey(elementName, namespace);
iqProviders.put(key, provider);
} }
/** /**
@ -198,10 +212,13 @@ public final class ProviderManager {
* *
* @param elementName the XML element name. * @param elementName the XML element name.
* @param namespace the XML namespace. * @param namespace the XML namespace.
* @return the key of the removed IQ Provider
*/ */
public static void removeIQProvider(String elementName, String namespace) { public static String removeIQProvider(String elementName, String namespace) {
String key = getKey(elementName, namespace); String key = getKey(elementName, namespace);
iqProviders.remove(key); iqProviders.remove(key);
iqIntrospectionProviders.remove(key);
return key;
} }
/** /**
@ -223,11 +240,16 @@ public final class ProviderManager {
* @param namespace namespace associated with extension provider. * @param namespace namespace associated with extension provider.
* @return the extenion provider. * @return the extenion provider.
*/ */
public static Object getExtensionProvider(String elementName, String namespace) { public static PacketExtensionProvider getExtensionProvider(String elementName, String namespace) {
String key = getKey(elementName, namespace); String key = getKey(elementName, namespace);
return extensionProviders.get(key); return extensionProviders.get(key);
} }
public static Class<?> getExtensionIntrospectionProvider(String elementName, String namespace) {
String key = getKey(elementName, namespace);
return extensionIntrospectionProviders.get(key);
}
/** /**
* Adds an extension provider with the specified element name and name space. The provider * Adds an extension provider with the specified element name and name space. The provider
* will override any providers loaded through the classpath. The provider must be either * will override any providers loaded through the classpath. The provider must be either
@ -240,12 +262,16 @@ public final class ProviderManager {
public static void addExtensionProvider(String elementName, String namespace, public static void addExtensionProvider(String elementName, String namespace,
Object provider) Object provider)
{ {
if (!(provider instanceof PacketExtensionProvider || provider instanceof Class)) { // First remove existing providers
String key = removeExtensionProvider(elementName, namespace);
if (provider instanceof PacketExtensionProvider) {
extensionProviders.put(key, (PacketExtensionProvider) provider);
} else if (provider instanceof Class && PacketExtension.class.isAssignableFrom((Class<?>) provider)) {
extensionIntrospectionProviders.put(key, (Class<?>) provider);
} else {
throw new IllegalArgumentException("Provider must be a PacketExtensionProvider " + throw new IllegalArgumentException("Provider must be a PacketExtensionProvider " +
"or a Class instance."); "or a Class instance.");
} }
String key = getKey(elementName, namespace);
extensionProviders.put(key, provider);
} }
/** /**
@ -255,10 +281,13 @@ public final class ProviderManager {
* *
* @param elementName the XML element name. * @param elementName the XML element name.
* @param namespace the XML namespace. * @param namespace the XML namespace.
* @return the key of the removed packet extension provider
*/ */
public static void removeExtensionProvider(String elementName, String namespace) { public static String removeExtensionProvider(String elementName, String namespace) {
String key = getKey(elementName, namespace); String key = getKey(elementName, namespace);
extensionProviders.remove(key); extensionProviders.remove(key);
extensionIntrospectionProviders.remove(key);
return key;
} }
/** /**
@ -268,8 +297,11 @@ public final class ProviderManager {
* *
* @return all PacketExtensionProvider instances. * @return all PacketExtensionProvider instances.
*/ */
public static Collection<Object> getExtensionProviders() { public static List<Object> getExtensionProviders() {
return Collections.unmodifiableCollection(extensionProviders.values()); List<Object> providers = new ArrayList<Object>(extensionProviders.size() + extensionIntrospectionProviders.size());
providers.addAll(extensionProviders.values());
providers.addAll(extensionIntrospectionProviders.values());
return Collections.unmodifiableList(providers);
} }
public static StreamFeatureProvider getStreamFeatureProvider(String elementName, String namespace) { public static StreamFeatureProvider getStreamFeatureProvider(String elementName, String namespace) {

View File

@ -543,23 +543,25 @@ public class PacketParserUtils {
// Otherwise, see if there is a registered provider for // Otherwise, see if there is a registered provider for
// this element name and namespace. // this element name and namespace.
else { else {
Object provider = ProviderManager.getIQProvider(elementName, namespace); IQProvider provider = ProviderManager.getIQProvider(elementName, namespace);
if (provider != null) { if (provider != null) {
if (provider instanceof IQProvider) { iqPacket =provider.parseIQ(parser);
iqPacket = ((IQProvider)provider).parseIQ(parser); } else {
Class<?> introspectionProvider = ProviderManager.getIQIntrospectionProvider(
elementName, namespace);
if (introspectionProvider != null) {
iqPacket = (IQ) PacketParserUtils.parseWithIntrospection(
elementName, introspectionProvider,
parser);
} }
else if (provider instanceof Class) { // Only handle unknown IQs of type result. Types of 'get' and 'set' which are not understood
iqPacket = (IQ)PacketParserUtils.parseWithIntrospection(elementName, // have to be answered with an IQ error response. See the code a few lines below
(Class<?>)provider, parser); else if (IQ.Type.result == type){
// No Provider found for the IQ stanza, parse it to an UnparsedIQ instance
// so that the content of the IQ can be examined later on
iqPacket = new UnparsedResultIQ(parseContent(parser));
} }
} }
// Only handle unknown IQs of type result. Types of 'get' and 'set' which are not understood
// have to be answered with an IQ error response. See the code a few lines below
else if (IQ.Type.result == type){
// No Provider found for the IQ stanza, parse it to an UnparsedIQ instance
// so that the content of the IQ can be examined later on
iqPacket = new UnparsedResultIQ(parseContent(parser));
}
} }
} }
else if (eventType == XmlPullParser.END_TAG) { else if (eventType == XmlPullParser.END_TAG) {
@ -885,15 +887,13 @@ public class PacketParserUtils {
public static PacketExtension parsePacketExtension(String elementName, String namespace, public static PacketExtension parsePacketExtension(String elementName, String namespace,
XmlPullParser parser) throws Exception { XmlPullParser parser) throws Exception {
// See if a provider is registered to handle the extension. // See if a provider is registered to handle the extension.
Object provider = ProviderManager.getExtensionProvider(elementName, namespace); PacketExtensionProvider provider = ProviderManager.getExtensionProvider(elementName, namespace);
if (provider != null) { if (provider != null) {
if (provider instanceof PacketExtensionProvider) { return provider.parseExtension(parser);
return ((PacketExtensionProvider)provider).parseExtension(parser); }
} Class<?> introspectionProvider = ProviderManager.getExtensionIntrospectionProvider(elementName, namespace);
else if (provider instanceof Class) { if (introspectionProvider != null) {
return (PacketExtension)parseWithIntrospection( return (PacketExtension)parseWithIntrospection(elementName, introspectionProvider, parser);
elementName, (Class<?>)provider, parser);
}
} }
// No providers registered, so use a default extension. // No providers registered, so use a default extension.
DefaultPacketExtension extension = new DefaultPacketExtension(elementName, namespace); DefaultPacketExtension extension = new DefaultPacketExtension(elementName, namespace);