diff --git a/smack-core/src/main/java/org/jivesoftware/smack/packet/DefaultExtensionElement.java b/smack-core/src/main/java/org/jivesoftware/smack/packet/DefaultExtensionElement.java index cd0c0edc9..f0ab6c85c 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/packet/DefaultExtensionElement.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/packet/DefaultExtensionElement.java @@ -45,7 +45,9 @@ import org.jivesoftware.smack.util.XmlStringBuilder; * cases, a custom ExtensionElementProvider should be used. * * @author Matt Tucker + * @deprecated use {@link org.jivesoftware.smack.packet.StandardExtensionElement} instead. */ +@Deprecated public class DefaultExtensionElement implements ExtensionElement { private String elementName; diff --git a/smack-core/src/main/java/org/jivesoftware/smack/packet/StandardExtensionElement.java b/smack-core/src/main/java/org/jivesoftware/smack/packet/StandardExtensionElement.java new file mode 100644 index 000000000..a7d98a3e7 --- /dev/null +++ b/smack-core/src/main/java/org/jivesoftware/smack/packet/StandardExtensionElement.java @@ -0,0 +1,221 @@ +/** + * + * Copyright 2015 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.smack.packet; + +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import org.jivesoftware.smack.util.MultiMap; +import org.jivesoftware.smack.util.Objects; +import org.jivesoftware.smack.util.StringUtils; +import org.jivesoftware.smack.util.XmlStringBuilder; +import org.jxmpp.util.XmppStringUtils; + +/** + * An {@link ExtensionElement} modeling the often required and used XML features when using XMPP. It + * is therefore suitable for most use cases. Use + * {@link StandardExtensionElement#builder(String, String)} to build these elements. + *

+ * Note the this is only meant as catch-all if no particular extension element provider is + * registered. Protocol implementations should prefer to model their own extension elements tailored + * to their use cases. + *

+ * + * @since 4.2 + * @author Florian Schmaus + */ +public final class StandardExtensionElement implements ExtensionElement { + + private final String name; + private final String namespace; + private final Map attributes; + private final String text; + private final MultiMap elements; + + private XmlStringBuilder xmlCache; + + /** + * Constructs a new extension element with the given name and namespace and nothing else. + *

+ * This is meant to construct extension elements used as simple flags in Stanzas. + *

+ * + * @param name the name of the extension element. + * @param namespace the namespace of the extension element. + */ + public StandardExtensionElement(String name, String namespace) { + this(name, namespace, null, null, null); + } + + private StandardExtensionElement(String name, String namespace, Map attributes, String text, + MultiMap elements) { + this.name = StringUtils.requireNotNullOrEmpty(name, "Name must not be null or empty"); + this.namespace = StringUtils.requireNotNullOrEmpty(namespace, "Namespace must not be null or empty"); + if (attributes == null) { + this.attributes = Collections.emptyMap(); + } + else { + this.attributes = attributes; + } + this.text = text; + this.elements = elements; + } + + @Override + public String getElementName() { + return name; + } + + @Override + public String getNamespace() { + return namespace; + } + + public String getAttributeValue(String attribute) { + return attributes.get(attribute); + } + + public Map getAttributes() { + return Collections.unmodifiableMap(attributes); + } + + public StandardExtensionElement getFirstElement(String element, String namespace) { + if (elements == null) { + return null; + } + String key = XmppStringUtils.generateKey(element, namespace); + return elements.getFirst(key); + } + + public StandardExtensionElement getFirstElement(String element) { + return getFirstElement(element, namespace); + } + + public List getElements(String element, String namespace) { + if (elements == null) { + return null; + } + String key = XmppStringUtils.generateKey(element, namespace); + return elements.getAll(key); + } + + public List getElements(String element) { + return getElements(element, namespace); + } + + public List getElements() { + if (elements == null){ + return Collections.emptyList(); + } + return elements.values(); + } + + public String getText() { + return text; + } + + @Override + public XmlStringBuilder toXML() { + return toXML(null); + } + + public XmlStringBuilder toXML(String enclosingNamespace) { + if (xmlCache != null) { + return xmlCache; + } + XmlStringBuilder xml = new XmlStringBuilder(this, enclosingNamespace); + for (Map.Entry entry : attributes.entrySet()) { + xml.attribute(entry.getKey(), entry.getValue()); + } + xml.rightAngleBracket(); + + xml.optEscape(text); + + if (elements != null) { + for (Map.Entry entry : elements.entrySet()) { + xml.append(entry.getValue().toXML(getNamespace())); + } + } + + xml.closeElement(this); + xmlCache = xml; + return xml; + } + + public static Builder builder(String name, String namespace) { + return new Builder(name, namespace); + } + + public static final class Builder { + private final String name; + private final String namespace; + + private Map attributes; + private String text; + private MultiMap elements; + + private Builder(String name, String namespace) { + this.name = name; + this.namespace = namespace; + } + + public Builder addAttribute(String name, String value) { + StringUtils.requireNotNullOrEmpty(name, "Attribute name must be set"); + Objects.requireNonNull(value, "Attribute value must be not null"); + if (attributes == null) { + attributes = new LinkedHashMap<>(); + } + attributes.put(name, value); + return this; + } + + public Builder addAttributes(Map attributes) { + if (this.attributes == null) { + this.attributes = new LinkedHashMap<>(attributes.size()); + } + this.attributes.putAll(attributes); + return this; + } + + public Builder setText(String text) { + this.text = Objects.requireNonNull(text, "Text must be not null"); + return this; + } + + public Builder addElement(StandardExtensionElement element) { + Objects.requireNonNull(element, "Element must not be null"); + if (elements == null) { + elements = new MultiMap<>(); + } + String key = XmppStringUtils.generateKey(element.getElementName(), element.getNamespace()); + elements.put(key, element); + return this; + } + + public Builder addElement(String name, String textValue) { + StandardExtensionElement element = StandardExtensionElement.builder(name, this.namespace).setText( + textValue).build(); + return addElement(element); + } + + public StandardExtensionElement build() { + return new StandardExtensionElement(name, namespace, attributes, text, elements); + } + } +} diff --git a/smack-core/src/main/java/org/jivesoftware/smack/packet/Stanza.java b/smack-core/src/main/java/org/jivesoftware/smack/packet/Stanza.java index dbbd7a4a3..baed5d6c7 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/packet/Stanza.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/packet/Stanza.java @@ -31,7 +31,6 @@ import org.jxmpp.util.XmppStringUtils; import java.util.Collection; import java.util.List; import java.util.Locale; -import java.util.Set; /** * Base class for XMPP Stanzas, which are called Stanza(/Packet) in older versions of Smack (i.e. < 4.1). @@ -285,7 +284,7 @@ public abstract class Stanza implements TopLevelStreamElement { } /** - * Return a set of all extensions with the given element name and namespace. + * Return a list of all extensions with the given element name and namespace. *

* Changes to the returned set will update the stanza(/packet) extensions, if the returned set is not the empty set. *

@@ -295,7 +294,7 @@ public abstract class Stanza implements TopLevelStreamElement { * @return a set of all matching extensions. * @since 4.1 */ - public Set getExtensions(String elementName, String namespace) { + public List getExtensions(String elementName, String namespace) { requireNotNullOrEmpty(elementName, "elementName must not be null or empty"); requireNotNullOrEmpty(namespace, "namespace must not be null or empty"); String key = XmppStringUtils.generateKey(elementName, namespace); @@ -319,12 +318,7 @@ public abstract class Stanza implements TopLevelStreamElement { * Returns the first extension that matches the specified element name and * namespace, or null if it doesn't exist. If the provided elementName is null, * only the namespace is matched. Extensions are - * are arbitrary XML sub-documents in standard XMPP packets. By default, a - * {@link DefaultExtensionElement} instance will be returned for each extension. However, - * ExtensionElementProvider instances can be registered with the - * {@link org.jivesoftware.smack.provider.ProviderManager ProviderManager} - * class to handle custom parsing. In that case, the type of the Object - * will be determined by the provider. + * are arbitrary XML elements in standard XMPP stanzas. * * @param elementName the XML element name of the extension. (May be null) * @param namespace the XML element namespace of the extension. diff --git a/smack-core/src/main/java/org/jivesoftware/smack/parsing/StandardExtensionElementProvider.java b/smack-core/src/main/java/org/jivesoftware/smack/parsing/StandardExtensionElementProvider.java new file mode 100644 index 000000000..7785c617f --- /dev/null +++ b/smack-core/src/main/java/org/jivesoftware/smack/parsing/StandardExtensionElementProvider.java @@ -0,0 +1,98 @@ +/** + * + * Copyright 2015 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.smack.parsing; + +import java.io.IOException; +import java.util.LinkedHashMap; +import java.util.Map; + +import org.jivesoftware.smack.packet.StandardExtensionElement; +import org.jivesoftware.smack.packet.StandardExtensionElement.Builder; +import org.jivesoftware.smack.provider.ExtensionElementProvider; +import org.jivesoftware.smack.util.ParserUtils; +import org.jivesoftware.smack.util.StringUtils; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +/** + * The parser for {@link StandardExtensionElement}s. + * + * @author Florian Schmaus + * + */ +public class StandardExtensionElementProvider extends ExtensionElementProvider { + + public static StandardExtensionElementProvider INSTANCE = new StandardExtensionElementProvider(); + + @Override + public StandardExtensionElement parse(final XmlPullParser parser, final int initialDepth) + throws XmlPullParserException, IOException { + // Unlike most (all?) other providers, we don't know the name and namespace of the element + // we are parsing here. + String name = parser.getName(); + String namespace = parser.getNamespace(); + Builder builder = StandardExtensionElement.builder(name, namespace); + final int namespaceCount = parser.getNamespaceCount(initialDepth); + final int attributeCount = parser.getAttributeCount(); + final Map attributes = new LinkedHashMap<>(namespaceCount + attributeCount); + for (int i = 0; i < namespaceCount; i++) { + String nsprefix = parser.getNamespacePrefix(i); + if (nsprefix == null) { + // Skip the default namespace. + continue; + } + // XmlPullParser must either return null or a non-empty String. + assert StringUtils.isNotEmpty(nsprefix); + String nsuri = parser.getNamespaceUri(i); + attributes.put("xmlns:" + nsprefix, nsuri); + } + for (int i = 0; i < attributeCount; i++) { + String attributePrefix = parser.getAttributePrefix(i); + String attributeName = parser.getAttributeName(i); + String attributeValue = parser.getAttributeValue(i); + String attributeKey; + if (StringUtils.isNullOrEmpty(attributePrefix)) { + attributeKey = attributeName; + } + else { + attributeKey = attributePrefix + ':' + attributeName; + } + attributes.put(attributeKey, attributeValue); + } + builder.addAttributes(attributes); + + outerloop: while (true) { + int event = parser.next(); + switch (event) { + case XmlPullParser.START_TAG: + builder.addElement(parse(parser, parser.getDepth())); + break; + case XmlPullParser.TEXT: + builder.setText(parser.getText()); + break; + case XmlPullParser.END_TAG: + if (initialDepth == parser.getDepth()) { + break outerloop; + } + break; + } + } + + ParserUtils.assertAtEndTag(parser); + return builder.build(); + } +} diff --git a/smack-core/src/main/java/org/jivesoftware/smack/util/MultiMap.java b/smack-core/src/main/java/org/jivesoftware/smack/util/MultiMap.java index 480c94477..479b8c395 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/util/MultiMap.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/util/MultiMap.java @@ -27,7 +27,7 @@ import java.util.Set; /** * A lightweight implementation of a MultiMap, that is a Map that is able to hold multiple values for every key. *

- * This MultiMap uses a LinkedHashMap together with a LinkedHashSet in order to keep the order of its entries. + * This MultiMap uses a {@link LinkedHashMap} together with a {@link ArrayList} in order to keep the order of its entries. *

* * @param the type of the keys the map uses. @@ -36,13 +36,13 @@ import java.util.Set; public class MultiMap { /** - * The constant value '6'. + * The constant value {@value}. */ public static final int DEFAULT_MAP_SIZE = 6; - private static final int ENTRY_SET_SIZE = 3; + private static final int ENTRY_LIST_SIZE = 3; - private final Map> map; + private final Map> map; /** * Constructs a new MultiMap with a initial capacity of {@link #DEFAULT_MAP_SIZE}. @@ -62,8 +62,8 @@ public class MultiMap { public int size() { int size = 0; - for (Set set : map.values()) { - size += set.size(); + for (List list : map.values()) { + size += list.size(); } return size; } @@ -77,8 +77,8 @@ public class MultiMap { } public boolean containsValue(Object value) { - for (Set set : map.values()) { - if (set.contains(value)) { + for (List list : map.values()) { + if (list.contains(value)) { return true; } } @@ -92,7 +92,7 @@ public class MultiMap { * @return the first value or null. */ public V getFirst(Object key) { - Set res = getAll(key); + List res = getAll(key); if (res.isEmpty()) { return null; } else { @@ -109,24 +109,24 @@ public class MultiMap { * @param key * @return all values for the given key. */ - public Set getAll(Object key) { - Set res = map.get(key); + public List getAll(Object key) { + List res = map.get(key); if (res == null) { - res = Collections.emptySet(); + res = Collections.emptyList(); } return res; } public boolean put(K key, V value) { boolean keyExisted; - Set set = map.get(key); - if (set == null) { - set = new LinkedHashSet<>(ENTRY_SET_SIZE); - set.add(value); - map.put(key, set); + List list = map.get(key); + if (list == null) { + list = new ArrayList<>(ENTRY_LIST_SIZE); + list.add(value); + map.put(key, list); keyExisted = false; } else { - set.add(value); + list.add(value); keyExisted = true; } return keyExisted; @@ -139,7 +139,7 @@ public class MultiMap { * @return the first value of the given key or null. */ public V remove(Object key) { - Set res = map.remove(key); + List res = map.remove(key); if (res == null) { return null; } @@ -158,12 +158,12 @@ public class MultiMap { * @return true if the mapping was removed, false otherwise. */ public boolean removeOne(Object key, V value) { - Set set = map.get(key); - if (set == null) { + List list = map.get(key); + if (list == null) { return false; } - boolean res = set.remove(value); - if (set.isEmpty()) { + boolean res = list.remove(value); + if (list.isEmpty()) { // Remove the key also if the value set is now empty map.remove(key); } @@ -191,15 +191,15 @@ public class MultiMap { */ public List values() { List values = new ArrayList<>(size()); - for (Set set : map.values()) { - values.addAll(set); + for (List list : map.values()) { + values.addAll(list); } return values; } public Set> entrySet() { Set> entrySet = new LinkedHashSet<>(size()); - for (Map.Entry> entries : map.entrySet()) { + for (Map.Entry> entries : map.entrySet()) { K key = entries.getKey(); for (V value : entries.getValue()) { entrySet.add(new SimpleMapEntry<>(key, value)); diff --git a/smack-core/src/main/java/org/jivesoftware/smack/util/PacketParserUtils.java b/smack-core/src/main/java/org/jivesoftware/smack/util/PacketParserUtils.java index 172d47b57..f3f9da5d8 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/util/PacketParserUtils.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/util/PacketParserUtils.java @@ -29,7 +29,6 @@ import java.util.logging.Level; import java.util.logging.Logger; import org.jivesoftware.smack.compress.packet.Compress; -import org.jivesoftware.smack.packet.DefaultExtensionElement; import org.jivesoftware.smack.packet.EmptyResultIQ; import org.jivesoftware.smack.packet.ErrorIQ; import org.jivesoftware.smack.packet.IQ; @@ -42,6 +41,7 @@ import org.jivesoftware.smack.packet.StartTls; import org.jivesoftware.smack.packet.StreamError; import org.jivesoftware.smack.packet.UnparsedIQ; import org.jivesoftware.smack.packet.XMPPError; +import org.jivesoftware.smack.parsing.StandardExtensionElementProvider; import org.jivesoftware.smack.provider.IQProvider; import org.jivesoftware.smack.provider.ExtensionElementProvider; import org.jivesoftware.smack.provider.ProviderManager; @@ -918,34 +918,8 @@ public class PacketParserUtils { return provider.parse(parser); } - final int initialDepth = parser.getDepth(); // No providers registered, so use a default extension. - DefaultExtensionElement extension = new DefaultExtensionElement(elementName, namespace); - outerloop: while (true) { - int eventType = parser.next(); - switch (eventType) { - case XmlPullParser.START_TAG: - String name = parser.getName(); - // If an empty element, set the value with the empty string. - if (parser.isEmptyElementTag()) { - extension.setValue(name,""); - } - // Otherwise, get the the element text. - else { - eventType = parser.next(); - if (eventType == XmlPullParser.TEXT) { - String value = parser.getText(); - extension.setValue(name, value); - } - } - break; - case XmlPullParser.END_TAG: - if (parser.getDepth() == initialDepth) { - break outerloop; - } - } - } - return extension; + return StandardExtensionElementProvider.INSTANCE.parse(parser); } public static StartTls parseStartTlsFeature(XmlPullParser parser) diff --git a/smack-core/src/main/java/org/jivesoftware/smack/util/XmlStringBuilder.java b/smack-core/src/main/java/org/jivesoftware/smack/util/XmlStringBuilder.java index 394d1bc43..9dbec85b6 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/util/XmlStringBuilder.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/util/XmlStringBuilder.java @@ -45,6 +45,16 @@ public class XmlStringBuilder implements Appendable, CharSequence { halfOpenElement(e.getElementName()); } + public XmlStringBuilder(ExtensionElement ee, String enclosingNamespace) { + this(); + String namespace = ee.getNamespace(); + if (namespace.equals(enclosingNamespace)) { + halfOpenElement(ee.getElementName()); + } else { + prelude(ee); + } + } + public XmlStringBuilder escapedElement(String name, String escapedContent) { assert escapedContent != null; openElement(name); @@ -351,6 +361,13 @@ public class XmlStringBuilder implements Appendable, CharSequence { return this; } + public XmlStringBuilder optEscape(CharSequence text) { + if (text == null) { + return this; + } + return escape(text); + } + public XmlStringBuilder escape(CharSequence text) { return escape(text.toString()); } diff --git a/smack-core/src/test/java/org/jivesoftware/smack/parsing/StandardExtensionElementParserTest.java b/smack-core/src/test/java/org/jivesoftware/smack/parsing/StandardExtensionElementParserTest.java new file mode 100644 index 000000000..a807a6372 --- /dev/null +++ b/smack-core/src/test/java/org/jivesoftware/smack/parsing/StandardExtensionElementParserTest.java @@ -0,0 +1,65 @@ +/** + * + * Copyright 2015 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.smack.parsing; + +import static org.jivesoftware.smack.util.PacketParserUtils.getParserFor; +import static org.junit.Assert.assertEquals; + +import org.jivesoftware.smack.packet.StandardExtensionElement; +import org.jivesoftware.smack.packet.StandardExtensionElement.Builder; +import org.junit.Test; + +public class StandardExtensionElementParserTest { + + @Test + public void buildAndParse() throws Exception { + Builder builder = StandardExtensionElement.builder("foo", "ns1"); + builder.addAttribute("attr1", "attr1-value"); + builder.addElement(StandardExtensionElement.builder("bar", "ns2").addAttribute("attr2", "attr2-value").build()); + builder.addElement("another-element", "another-element-text"); + final String elementString = builder.build().toXML().toString(); + + StandardExtensionElement parsedElement = StandardExtensionElementProvider.INSTANCE.parse(getParserFor(elementString)); + + assertEquals("foo", parsedElement.getElementName()); + assertEquals("ns1", parsedElement.getNamespace()); + assertEquals("attr1-value", parsedElement.getAttributeValue("attr1")); + + StandardExtensionElement barNs2Element = parsedElement.getFirstElement("bar", "ns2"); + assertEquals("bar", barNs2Element.getElementName()); + assertEquals("ns2", barNs2Element.getNamespace()); + assertEquals("attr2-value", barNs2Element.getAttributeValue("attr2")); + + assertEquals("another-element-text", parsedElement.getFirstElement("another-element").getText()); + } + + @Test + public void buildWithAttrNamespacesAndParse() throws Exception { + Builder builder = StandardExtensionElement.builder("foo", "ns1-value"); + builder.addAttribute("xmlns:ns2", "ns2-value"); + builder.addAttribute("ns2:bar", "bar-ns2-value"); + final String elementString = builder.build().toXML().toString(); + + StandardExtensionElement parsedElement = StandardExtensionElementProvider.INSTANCE.parse(getParserFor(elementString)); + assertEquals("foo", parsedElement.getElementName()); + assertEquals("ns1-value", parsedElement.getNamespace()); + String barNs2Value = parsedElement.getAttributeValue("ns2:bar"); + assertEquals("bar-ns2-value", barNs2Value); + String ns2Value = parsedElement.getAttributeValue("xmlns:ns2"); + assertEquals("ns2-value", ns2Value); + } +} diff --git a/smack-legacy/src/main/java/org/jivesoftware/smackx/workgroup/agent/AgentSession.java b/smack-legacy/src/main/java/org/jivesoftware/smackx/workgroup/agent/AgentSession.java index e662294f7..2fc43d7a3 100644 --- a/smack-legacy/src/main/java/org/jivesoftware/smackx/workgroup/agent/AgentSession.java +++ b/smack-legacy/src/main/java/org/jivesoftware/smackx/workgroup/agent/AgentSession.java @@ -43,11 +43,11 @@ import org.jivesoftware.smack.filter.OrFilter; import org.jivesoftware.smack.filter.StanzaTypeFilter; import org.jivesoftware.smack.iqrequest.AbstractIqRequestHandler; import org.jivesoftware.smack.iqrequest.IQRequestHandler.Mode; -import org.jivesoftware.smack.packet.DefaultExtensionElement; import org.jivesoftware.smack.packet.IQ; import org.jivesoftware.smack.packet.Message; import org.jivesoftware.smack.packet.Stanza; import org.jivesoftware.smack.packet.Presence; +import org.jivesoftware.smack.packet.StandardExtensionElement; import org.jivesoftware.smackx.muc.packet.MUCUser; import org.jivesoftware.smackx.search.ReportedData; import org.jivesoftware.smackx.workgroup.MetaData; @@ -332,7 +332,7 @@ public class AgentSession { if (online) { presence = new Presence(Presence.Type.available); presence.setTo(workgroupJID); - presence.addExtension(new DefaultExtensionElement(AgentStatus.ELEMENT_NAME, + presence.addExtension(new StandardExtensionElement(AgentStatus.ELEMENT_NAME, AgentStatus.NAMESPACE)); PacketCollector collector = this.connection.createPacketCollectorAndSend(new AndFilter( @@ -350,7 +350,7 @@ public class AgentSession { presence = new Presence(Presence.Type.unavailable); presence.setTo(workgroupJID); - presence.addExtension(new DefaultExtensionElement(AgentStatus.ELEMENT_NAME, + presence.addExtension(new StandardExtensionElement(AgentStatus.ELEMENT_NAME, AgentStatus.NAMESPACE)); connection.sendStanza(presence); } @@ -429,11 +429,12 @@ public class AgentSession { if (status != null) { presence.setStatus(status); } + // Send information about max chats and current chats as a packet extension. - DefaultExtensionElement agentStatus = new DefaultExtensionElement(AgentStatus.ELEMENT_NAME, - AgentStatus.NAMESPACE); - agentStatus.setValue("max-chats", "" + maxChats); - presence.addExtension(agentStatus); + StandardExtensionElement.Builder builder = StandardExtensionElement.builder(AgentStatus.ELEMENT_NAME, + AgentStatus.NAMESPACE); + builder.addElement("max_chats", Integer.toString(maxChats)); + presence.addExtension(builder.build()); presence.addExtension(new MetaData(this.metaData)); PacketCollector collector = this.connection.createPacketCollectorAndSend(new AndFilter( @@ -780,10 +781,10 @@ public class AgentSession { } // Notify agent packets gives an overview of agent activity in a queue. - DefaultExtensionElement notifyAgents = (DefaultExtensionElement)presence.getExtension("notify-agents", "http://jabber.org/protocol/workgroup"); + StandardExtensionElement notifyAgents = presence.getExtension("notify-agents", "http://jabber.org/protocol/workgroup"); if (notifyAgents != null) { - int currentChats = Integer.parseInt(notifyAgents.getValue("current-chats")); - int maxChats = Integer.parseInt(notifyAgents.getValue("max-chats")); + int currentChats = Integer.parseInt(notifyAgents.getFirstElement("current-chats", "http://jabber.org/protocol/workgroup").getText()); + int maxChats = Integer.parseInt(notifyAgents.getFirstElement("max-chats", "http://jabber.org/protocol/workgroup").getText()); queue.setCurrentChats(currentChats); queue.setMaxChats(maxChats); // Fire event.