2019-02-04 08:59:39 +01:00
|
|
|
/**
|
|
|
|
*
|
2021-04-18 18:58:50 +02:00
|
|
|
* Copyright 2018-2021 Florian Schmaus
|
2019-02-04 08:59:39 +01:00
|
|
|
*
|
|
|
|
* 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.smack.util;
|
|
|
|
|
2019-10-24 15:45:08 +02:00
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.Collections;
|
|
|
|
import java.util.List;
|
2019-06-12 22:30:56 +02:00
|
|
|
import java.util.logging.Logger;
|
|
|
|
|
2019-05-08 21:10:39 +02:00
|
|
|
import javax.xml.namespace.QName;
|
2019-02-04 08:59:39 +01:00
|
|
|
|
2020-08-28 09:51:07 +02:00
|
|
|
import org.jivesoftware.smack.packet.ExtensionElement;
|
|
|
|
import org.jivesoftware.smack.packet.StandardExtensionElement;
|
2021-04-18 18:58:50 +02:00
|
|
|
import org.jivesoftware.smack.packet.XmlElement;
|
2020-08-28 09:51:07 +02:00
|
|
|
import org.jivesoftware.smack.provider.ProviderManager;
|
2019-02-04 08:59:39 +01:00
|
|
|
|
2020-08-28 09:47:09 +02:00
|
|
|
import org.jxmpp.util.cache.LruCache;
|
|
|
|
|
2019-02-04 08:59:39 +01:00
|
|
|
public class XmppElementUtil {
|
|
|
|
|
2021-04-18 18:58:50 +02:00
|
|
|
private static final LruCache<Class<? extends XmlElement>, QName> CLASS_TO_QNAME_CACHE = new LruCache<>(512);
|
2020-08-28 09:47:09 +02:00
|
|
|
|
2019-06-12 22:30:56 +02:00
|
|
|
public static final Logger LOGGER = Logger.getLogger(XmppElementUtil.class.getName());
|
|
|
|
|
2021-04-18 18:58:50 +02:00
|
|
|
public static QName getQNameFor(Class<? extends XmlElement> fullyQualifiedElement) {
|
2020-08-28 09:47:09 +02:00
|
|
|
QName qname = CLASS_TO_QNAME_CACHE.get(fullyQualifiedElement);
|
|
|
|
if (qname != null) {
|
|
|
|
return qname;
|
|
|
|
}
|
|
|
|
|
2019-06-12 22:30:56 +02:00
|
|
|
try {
|
|
|
|
Object qnameObject = fullyQualifiedElement.getField("QNAME").get(null);
|
|
|
|
if (QName.class.isAssignableFrom(qnameObject.getClass())) {
|
2020-08-28 09:47:09 +02:00
|
|
|
qname = (QName) qnameObject;
|
|
|
|
CLASS_TO_QNAME_CACHE.put(fullyQualifiedElement, qname);
|
|
|
|
return qname;
|
2019-06-12 22:30:56 +02:00
|
|
|
}
|
|
|
|
LOGGER.warning("The QNAME field of " + fullyQualifiedElement + " is not of type QNAME.");
|
|
|
|
} catch (NoSuchFieldException e) {
|
2020-07-13 08:50:10 +02:00
|
|
|
LOGGER.finer("The " + fullyQualifiedElement + " has no static QNAME field. Consider adding one.");
|
2019-06-12 22:30:56 +02:00
|
|
|
// Proceed to fallback strategy.
|
|
|
|
} catch (IllegalArgumentException | IllegalAccessException | SecurityException e) {
|
|
|
|
throw new IllegalArgumentException(e);
|
|
|
|
}
|
|
|
|
|
2019-02-04 08:59:39 +01:00
|
|
|
String element, namespace;
|
|
|
|
try {
|
|
|
|
element = (String) fullyQualifiedElement.getField("ELEMENT").get(null);
|
|
|
|
namespace = (String) fullyQualifiedElement.getField("NAMESPACE").get(null);
|
|
|
|
}
|
|
|
|
catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException e) {
|
2020-07-13 08:50:10 +02:00
|
|
|
throw new IllegalArgumentException("The " + fullyQualifiedElement + " has no ELEMENT, NAMESPACE or QNAME member. Consider adding QNAME", e);
|
2019-02-04 08:59:39 +01:00
|
|
|
}
|
|
|
|
|
2020-08-28 09:47:09 +02:00
|
|
|
qname = new QName(namespace, element);
|
|
|
|
CLASS_TO_QNAME_CACHE.put(fullyQualifiedElement, qname);
|
|
|
|
return qname;
|
2019-02-04 08:59:39 +01:00
|
|
|
}
|
|
|
|
|
2020-08-28 09:51:07 +02:00
|
|
|
public static <E extends ExtensionElement> List<E> getElementsFrom(
|
2021-04-18 18:58:50 +02:00
|
|
|
MultiMap<QName, XmlElement> elementMap, Class<E> extensionElementClass) {
|
2019-10-24 15:45:08 +02:00
|
|
|
QName qname = XmppElementUtil.getQNameFor(extensionElementClass);
|
|
|
|
|
2021-04-18 18:58:50 +02:00
|
|
|
List<XmlElement> extensionElements = elementMap.getAll(qname);
|
2019-10-24 15:45:08 +02:00
|
|
|
|
|
|
|
if (extensionElements.isEmpty()) {
|
|
|
|
return Collections.emptyList();
|
|
|
|
}
|
|
|
|
|
2020-08-28 09:51:07 +02:00
|
|
|
List<E> res = new ArrayList<>(extensionElements.size());
|
2021-04-18 18:58:50 +02:00
|
|
|
for (XmlElement extensionElement : extensionElements) {
|
2020-08-28 09:51:07 +02:00
|
|
|
E e = castOrThrow(extensionElement, extensionElementClass);
|
2019-10-24 15:45:08 +02:00
|
|
|
res.add(e);
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
2020-08-28 09:51:07 +02:00
|
|
|
|
2021-04-18 18:58:50 +02:00
|
|
|
public static <E extends ExtensionElement> E castOrThrow(XmlElement extensionElement, Class<E> extensionElementClass) {
|
2020-08-28 09:51:07 +02:00
|
|
|
if (!extensionElementClass.isInstance(extensionElement)) {
|
|
|
|
final QName qname = getQNameFor(extensionElementClass);
|
|
|
|
|
|
|
|
final String detailMessage;
|
|
|
|
if (extensionElement instanceof StandardExtensionElement) {
|
|
|
|
detailMessage = "because there is no according extension element provider registered with ProviderManager for "
|
|
|
|
+ qname
|
|
|
|
+ ". WARNING: This indicates a serious problem with your Smack setup, probably causing Smack not being able to properly initialize itself.";
|
|
|
|
} else {
|
|
|
|
Object provider = ProviderManager.getExtensionProvider(qname);
|
|
|
|
detailMessage = "because there is an inconsistency with the provider registered with ProviderManager: the active provider for "
|
|
|
|
+ qname + " '" + provider.getClass()
|
|
|
|
+ "' does not return instances of type " + extensionElementClass
|
|
|
|
+ ", but instead returns instances of type " + extensionElement.getClass() + ".";
|
|
|
|
}
|
|
|
|
|
|
|
|
String message = "Extension element is not of expected class '" + extensionElementClass.getName() + "', "
|
|
|
|
+ detailMessage;
|
|
|
|
throw new IllegalStateException(message);
|
|
|
|
}
|
|
|
|
|
|
|
|
return extensionElementClass.cast(extensionElement);
|
|
|
|
}
|
|
|
|
|
2019-02-04 08:59:39 +01:00
|
|
|
}
|