forked from igniterealtime/Smack
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
replaces DefaultExtensionElement which is now deprecated. Also changes Stanza (and MultiMap) API so that there can be duplicate extension elements, as this change is required for StandardExtensionElement and by the XMPP standard.
- Loading branch information
Showing
9 changed files
with
445 additions
and
73 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
221 changes: 221 additions & 0 deletions
221
smack-core/src/main/java/org/jivesoftware/smack/packet/StandardExtensionElement.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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. | ||
* <p> | ||
* 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. | ||
* </p> | ||
* | ||
* @since 4.2 | ||
* @author Florian Schmaus | ||
*/ | ||
public final class StandardExtensionElement implements ExtensionElement { | ||
|
||
private final String name; | ||
private final String namespace; | ||
private final Map<String, String> attributes; | ||
private final String text; | ||
private final MultiMap<String, StandardExtensionElement> elements; | ||
|
||
private XmlStringBuilder xmlCache; | ||
|
||
/** | ||
* Constructs a new extension element with the given name and namespace and nothing else. | ||
* <p> | ||
* This is meant to construct extension elements used as simple flags in Stanzas. | ||
* <p> | ||
* | ||
* @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<String, String> attributes, String text, | ||
MultiMap<String, StandardExtensionElement> 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<String, String> 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<StandardExtensionElement> getElements(String element, String namespace) { | ||
if (elements == null) { | ||
return null; | ||
} | ||
String key = XmppStringUtils.generateKey(element, namespace); | ||
return elements.getAll(key); | ||
} | ||
|
||
public List<StandardExtensionElement> getElements(String element) { | ||
return getElements(element, namespace); | ||
} | ||
|
||
public List<StandardExtensionElement> 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<String, String> entry : attributes.entrySet()) { | ||
xml.attribute(entry.getKey(), entry.getValue()); | ||
} | ||
xml.rightAngleBracket(); | ||
|
||
xml.optEscape(text); | ||
|
||
if (elements != null) { | ||
for (Map.Entry<String, StandardExtensionElement> 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<String, String> attributes; | ||
private String text; | ||
private MultiMap<String, StandardExtensionElement> 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<String, String> 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); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
98 changes: 98 additions & 0 deletions
98
...k-core/src/main/java/org/jivesoftware/smack/parsing/StandardExtensionElementProvider.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<StandardExtensionElement> { | ||
|
||
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<String, String> 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(); | ||
} | ||
} |
Oops, something went wrong.