Skip to content

Commit

Permalink
Add parsing of message custom arguments
Browse files Browse the repository at this point in the history
Custom arguments are then stored via an extension
  • Loading branch information
Judas committed Feb 12, 2016
1 parent 5c00172 commit 2aab2d7
Show file tree
Hide file tree
Showing 3 changed files with 159 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/**
*
* Copyright 2016 Jules Tréhorel
*
* All rights reserved. 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.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.jivesoftware.smack.util.Objects;
import org.jivesoftware.smack.util.XmlStringBuilder;
import org.xmlpull.v1.XmlPullParser;

/**
* An {@link ExtensionElement} storing the custom attributes listed in messages stanzas root <message>
* element. As this use-case is a bad practice, this {@link ExtensionElement} allows XMPP clients to
* retrieve those (wrongly set) values in a clean way.
*
* @author Jules Tréhorel
*/
public class CustomAttributesExtension implements ExtensionElement {
public final static String NAME = "customAttributes";
public final static String NAMESPACE = "http://smack.jivesoftware.com";

private StandardExtensionElement extension;

private CustomAttributesExtension(Map<String, String> properties) {
if (properties == null || properties.isEmpty())
return;

StandardExtensionElement.Builder extensionBuilder = StandardExtensionElement.builder(NAME, NAMESPACE);
for (Map.Entry<String, String> entry : properties.entrySet()) {
extensionBuilder.addElement(entry.getKey(), entry.getValue());
}
extension = extensionBuilder.build();
}

@Override
public String getElementName() {
return NAME;
}

@Override
public String getNamespace() {
return NAMESPACE;
}

public boolean hasProperties() {
return extension != null && extension.getElements().size() > 0;
}

public boolean hasProperty(String propertyKey) {
return hasProperties() && extension.getElements(propertyKey) != null;
}

public String getPropertyValue(String propertyKey) {
if (!hasProperty(propertyKey)) {
return null;
}
return extension.getElements(propertyKey).get(0).getText(); // Only one element per key
}

@Override
public XmlStringBuilder toXML() {
return extension.toXML();
}

public static final class Builder {
private final List<String> attributesWhiteList = Arrays.asList(new String[] {"xml:lang", "id", "to", "from", "type"});

private Map<String, String> properties;

public Builder() {
}

public Builder fromParser(XmlPullParser parser) {
Objects.requireNonNull(parser, "Parser must be set");

properties = new HashMap<String, String>();
for (int i = 0; i < parser.getAttributeCount(); i++) {
String attributeName = parser.getAttributeName(i);
boolean isLangAttribute = "lang".equals(attributeName) && "xml".equals(parser.getAttributePrefix(i));
if (!attributesWhiteList.contains(attributeName) && !isLangAttribute) {
String attributeValue = parser.getAttributeValue(i);
properties.put(attributeName, attributeValue);
}
}
return this;
}

public CustomAttributesExtension build() {
return new CustomAttributesExtension(properties);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import java.util.logging.Logger;

import org.jivesoftware.smack.compress.packet.Compress;
import org.jivesoftware.smack.packet.CustomAttributesExtension;
import org.jivesoftware.smack.packet.EmptyResultIQ;
import org.jivesoftware.smack.packet.ErrorIQ;
import org.jivesoftware.smack.packet.IQ;
Expand Down Expand Up @@ -236,6 +237,12 @@ public static Message parseMessage(XmlPullParser parser)
defaultLanguage = Stanza.getDefaultLanguage();
}

// Extract custom attributes and bundle them into an extension
CustomAttributesExtension customAttributesExtension = new CustomAttributesExtension.Builder().fromParser(parser).build();
if (customAttributesExtension.hasProperties()) {
message.addExtension(customAttributesExtension);
}

// Parse sub-elements. We include extra logic to make sure the values
// are only read once. This is because it's possible for the names to appear
// in arbitrary sub-elements.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;

import org.jivesoftware.smack.packet.CustomAttributesExtension;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Stanza;
import org.jivesoftware.smack.packet.Presence;
Expand Down Expand Up @@ -816,6 +817,48 @@ public void parseElementMultipleNamespace()
assertXMLEqual(stanza, result.toString());
}

@Test
public void parseMessageWithCustomAttributes()
throws FactoryConfigurationError, Exception {
final String customAttrName = "customAttrName";
final String customAttrValue = "customAttrValue";

final String stanza = XMLBuilder.create("message")
.a("from", "romeo@montague.lit/orchard")
.a("to", "juliet@capulet.lit/balcony")
.a("id", "zid615d9")
.a("type", "chat")
.a(customAttrName, customAttrValue)
.a("xml:lang", Stanza.getDefaultLanguage())
.e("body")
.t("This is a test of the custom attributes parsing in message stanza")
.asString(outputProperties);

final String messageXmlResult = XMLBuilder.create("message")
.a("from", "romeo@montague.lit/orchard")
.a("to", "juliet@capulet.lit/balcony")
.a("id", "zid615d9")
.a("type", "chat")
.a("xml:lang", Stanza.getDefaultLanguage())
.element(CustomAttributesExtension.NAME, CustomAttributesExtension.NAMESPACE)
.element(customAttrName, CustomAttributesExtension.NAMESPACE)
.t(customAttrValue)
.up()
.up()
.e("body")
.t("This is a test of the custom attributes parsing in message stanza")
.asString(outputProperties);

Message message = PacketParserUtils.parseMessage(PacketParserUtils.getParserFor(stanza));
CustomAttributesExtension extension = message.getExtension(CustomAttributesExtension.NAME, CustomAttributesExtension.NAMESPACE);

assertFalse(extension == null);
assertTrue(extension.hasProperties());
assertTrue(extension.hasProperty(customAttrName));
assertEquals(extension.getPropertyValue(customAttrName), customAttrValue);
assertXMLEqual(messageXmlResult, message.toXML().toString());
}

@Test
public void parseSASLFailureSimple() throws FactoryConfigurationError, SAXException, IOException,
TransformerException, ParserConfigurationException, XmlPullParserException {
Expand Down

0 comments on commit 2aab2d7

Please sign in to comment.