Skip to content

Instantly share code, notes, and snippets.

@soulfly
Created August 29, 2017 08:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save soulfly/4be1fac6177fb8993862fa5efa223f3a to your computer and use it in GitHub Desktop.
Save soulfly/4be1fac6177fb8993862fa5efa223f3a to your computer and use it in GitHub Desktop.
package com.quickblox.chat.model;
import android.text.TextUtils;
import com.quickblox.chat.propertyparsers.MessagePropertyParser;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.packet.ExtensionElement;
import org.jivesoftware.smack.provider.ExtensionElementProvider;
import org.jivesoftware.smack.util.XmlStringBuilder;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
/**
* This class provides a simple representation of additional custom parameters of chat message. Each element
* is a key in a Map with its CDATA being the value.
*/
public class QBChatMessageExtension implements ExtensionElement {
public static final String ELEMENT_NAME = "extraParams";
public static final String NAMESPACE = "jabber:client";
public static final String TAG_ATTACHMENT = "attachment";
public static final String ATTRIBUTE_NAME = "name";
public static final String ATTRIBUTE_TYPE = "type";
public static final String ATTRIBUTE_ID = "id";
public static final String ATTRIBUTE_URL = "url";
public static final String ATTRIBUTE_DATA = "data";
public static final String ATTRIBUTE_CONTENT_TYPE = "content-type";
public static final String ATTRIBUTE_SIZE = "size";
public static final String ATTRIBUTE_WIDTH = "width";
public static final String ATTRIBUTE_HEIGHT = "height";
public static final String ATTRIBUTE_DURATION = "duration";
private static Map<String, MessagePropertyParser<?>> complexPropertyParsers = new HashMap<>();
private Map<String, String> properties;
/**
* Added for capability to add in message properties complex objects
*/
private volatile Map<String, Object> complexPropertiesMap;
private List<QBAttachment> attachments;
QBChatMessageExtension() {
properties = new HashMap<>();
attachments = new ArrayList<>();
}
QBChatMessageExtension(Map<String, String> properties, List<QBAttachment> attachments, Map<String, Object> complexProperties) {
this.properties = properties;
this.attachments = attachments;
this.complexPropertiesMap = complexProperties;
}
public static void registerComplexPropertyParser(String elementName, MessagePropertyParser<?> propertyParser){
complexPropertyParsers.put(elementName, propertyParser);
}
@Override
public String getElementName() {
return ELEMENT_NAME;
}
@Override
public String getNamespace() {
return NAMESPACE;
}
@Override
public CharSequence toXML() {
XmlStringBuilder buf = new XmlStringBuilder();
buf.halfOpenElement(ELEMENT_NAME).xmlnsAttribute(NAMESPACE).rightAngleBracket();
for (QBAttachment attachment : attachments) {
buf.halfOpenElement(TAG_ATTACHMENT);
buf.attribute(ATTRIBUTE_TYPE, attachment.getType());
if (attachment.getName() != null) {
buf.attribute(ATTRIBUTE_NAME, attachment.getName());
}
if (attachment.getId() != null) {
buf.attribute(ATTRIBUTE_ID, String.valueOf(attachment.getId()));
}
if (attachment.getUrl() != null) {
buf.attribute(ATTRIBUTE_URL, attachment.getUrl());
}
if (attachment.getData() != null){
buf.attribute(ATTRIBUTE_DATA, attachment.getData());
}
if (attachment.getContentType() != null) {
buf.attribute(ATTRIBUTE_CONTENT_TYPE, attachment.getContentType());
}
if (attachment.getSize() != 0) {
buf.attribute(ATTRIBUTE_SIZE, String.valueOf(attachment.getSize()));
}
if (attachment.getWidth() != 0) {
buf.attribute(ATTRIBUTE_WIDTH, String.valueOf(attachment.getWidth()));
}
if (attachment.getHeight() != 0) {
buf.attribute(ATTRIBUTE_HEIGHT, String.valueOf(attachment.getHeight()));
}
if (attachment.getDuration() != 0) {
buf.attribute(ATTRIBUTE_DURATION, String.valueOf(attachment.getDuration()));
}
buf.rightAngleBracket();
buf.closeElement(TAG_ATTACHMENT);
}
// Add property
for (String name : getPropertyNames()) {
String value = getProperty(name);
buf.element(name, value);
}
// Add complex property
if( complexPropertiesMap != null) {
for (String key : complexPropertiesMap.keySet()) {
Object currentObject = complexPropertiesMap.get(key);
MessagePropertyParser<?> messagePropertyParser = complexPropertyParsers.get(key);
// if parser for object exists
if (messagePropertyParser != null) {
buf.append(messagePropertyParser.parseToXML(currentObject));
}
}
}
buf.closeElement(ELEMENT_NAME);
return buf;
}
public void addAttachments(Collection<QBAttachment> attachments) {
this.attachments.addAll(attachments);
}
public Collection<QBAttachment> getAttachments() {
return Collections.unmodifiableList(attachments);
}
public String getProperty(String name) {
return properties.get(name);
}
public Object getComplexProperty(String name){
return complexPropertiesMap.get(name);
}
public void setProperty(String name, String value) {
properties.put(name, value);
}
public void setComplexProperty(Map <String, Object> complexProperties) {
complexPropertiesMap = complexProperties;
}
public void setProperties(Map<String, String> properties) {
this.properties.putAll(properties);
}
private Collection<String> getPropertyNames() {
return Collections.unmodifiableSet(new HashSet<String>(properties.keySet()));
}
public Map<String, String> getProperties() {
return properties;
}
public static class Provider extends ExtensionElementProvider<QBChatMessageExtension> {
private XmlPullParser parser;
private List<QBAttachment> attachments;
private Map<String, String> properties;
private Map<String, Object> complexProperties;
@Override
public QBChatMessageExtension parse(XmlPullParser parser, int Depth) throws XmlPullParserException, IOException, SmackException {
this.parser = parser;
attachments = new ArrayList<>();
properties = new HashMap<>();
complexProperties = new HashMap<>();
int tag = parser.next();
while (isNotLastElement(tag)) {
if (isWhitespaceText(tag)){
tag = parser.next();
} else if (isAttachmentElement(tag)) {
parseAttachment();
tag = parser.next();
} else if (isPropertyStartElement(tag)) {
// Parser moves next method calls in parseProperty method
// in case of internal child exists in this property element
tag = parseProperty();
} else if (isPropertyEndElement(tag)){
tag = parser.next();
}
}
return new QBChatMessageExtension(properties, attachments, complexProperties);
}
private boolean isNotLastElement(int tag) {
return !isLastElement(tag);
}
private boolean isLastElement(int tag) {
return (((tag == XmlPullParser.END_TAG) && parser.getName().equals(
QBChatMessageExtension.ELEMENT_NAME)) || tag == XmlPullParser.END_DOCUMENT);
}
private boolean isPropertyStartElement(int tag) {
return tag == XmlPullParser.START_TAG && isNotRootElement();
}
private boolean isPropertyEndElement(int tag) {
return tag == XmlPullParser.END_TAG && isNotRootElement();
}
private boolean isWhitespaceText(int tag) throws XmlPullParserException {
return (tag == XmlPullParser.TEXT && parser.isWhitespace());
}
private boolean isNotRootElement() {
return !parser.getName().equals(QBChatMessageExtension.ELEMENT_NAME);
}
private boolean isAttachmentElement(int tag) {
return (tag == XmlPullParser.START_TAG) && parser.getName().equals(
QBChatMessageExtension.TAG_ATTACHMENT);
}
private void parseAttachment() {
String attachmentId = parser.getAttributeValue(null, QBChatMessageExtension.ATTRIBUTE_ID);
String attachmentType = parser.getAttributeValue(null, QBChatMessageExtension.ATTRIBUTE_TYPE);
String attachmentUrl = parser.getAttributeValue(null, QBChatMessageExtension.ATTRIBUTE_URL);
String attachmentData = parser.getAttributeValue(null, QBChatMessageExtension.ATTRIBUTE_DATA);
double attachmentSize = parseDouble(QBChatMessageExtension.ATTRIBUTE_SIZE);
int attachmentWidth = parseInt(QBChatMessageExtension.ATTRIBUTE_WIDTH);
int attachmentHeight = parseInt(QBChatMessageExtension.ATTRIBUTE_HEIGHT);
int attachmentDuration = parseInt(QBChatMessageExtension.ATTRIBUTE_DURATION);
String attachmentName = parser.getAttributeValue(null, QBChatMessageExtension.ATTRIBUTE_NAME);
String attachmentContentType = parser.getAttributeValue(null, QBChatMessageExtension.ATTRIBUTE_CONTENT_TYPE);
QBAttachment attachment = new QBAttachment(attachmentType);
if (attachmentId != null) {
attachment.setId(attachmentId);
}
attachment.setData(attachmentData);
attachment.setUrl(attachmentUrl);
attachment.setSize(attachmentSize);
attachment.setWidth(attachmentWidth);
attachment.setHeight(attachmentHeight);
attachment.setDuration(attachmentDuration);
attachment.setName(attachmentName);
attachment.setContentType(attachmentContentType);
attachments.add(attachment);
}
private int parseProperty() throws XmlPullParserException, IOException {
String name = parser.getName();
MessagePropertyParser<?> complexParser = null;
if ((complexParser = complexPropertyParsers.get(name)) != null){
Object object = parseComplexProperty(parser, complexParser);
complexProperties.put(name, object);
return parser.getEventType();
} else {
int tag = parser.next();
if (tag == XmlPullParser.TEXT) {
String value = parser.getText();
properties.put(name, value);
// Move to END_TAG element
parser.next();
} else {
skipCurrentComplexTag(name);
}
}
return parser.getEventType();
}
private void skipCurrentComplexTag(String closeTagName) {
int tag = 0;
String currentTagName = "";
do {
try {
tag = parser.next();
currentTagName = parser.getName();
} catch (XmlPullParserException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
} while (! (XmlPullParser.END_TAG == tag && closeTagName.equals(currentTagName)));
}
private Object parseComplexProperty(XmlPullParser parser, MessagePropertyParser<?> propertyParser) {
return propertyParser.parseFromXML(parser);
}
private int parseInt(String attributeName){
int result = 0;
String strValue = parser.getAttributeValue(null, attributeName);
if (!TextUtils.isEmpty(strValue)) {
try {
result = Integer.parseInt(strValue);
} catch (NumberFormatException e){
e.printStackTrace();
}
}
return result;
}
private double parseDouble(String attributeName){
double result = 0;
String strValue = parser.getAttributeValue(null, attributeName);
if (!TextUtils.isEmpty(strValue)) {
try {
result = Double.parseDouble(strValue);
} catch (NumberFormatException e){
e.printStackTrace();
}
}
return result;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment