mirror of
https://codeberg.org/Mercury-IM/Smack
synced 2024-11-26 08:12:05 +01:00
Move Packet 'properties' from core to extensions
Code for Jive's packet properties should not be in 'core'. Also de-serializing input from network causes some security implications, it is therefore disabled as default.
This commit is contained in:
parent
c2b214f8d8
commit
6e08a10186
11 changed files with 516 additions and 281 deletions
|
@ -20,28 +20,20 @@ package org.jivesoftware.smack.packet;
|
||||||
import org.jivesoftware.smack.util.StringUtils;
|
import org.jivesoftware.smack.util.StringUtils;
|
||||||
import org.jivesoftware.smack.util.XmlStringBuilder;
|
import org.jivesoftware.smack.util.XmlStringBuilder;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.util.ArrayList;
|
||||||
import java.io.ObjectOutputStream;
|
import java.util.Collection;
|
||||||
import java.io.Serializable;
|
import java.util.Collections;
|
||||||
import java.util.*;
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class for XMPP packets. Every packet has a unique ID (which is automatically
|
* Base class for XMPP packets. Every packet has a unique ID (which is automatically
|
||||||
* generated, but can be overriden). Optionally, the "to" and "from" fields can be set,
|
* generated, but can be overridden). Optionally, the "to" and "from" fields can be set.
|
||||||
* as well as an arbitrary number of properties.
|
|
||||||
*
|
|
||||||
* Properties provide an easy mechanism for clients to share data. Each property has a
|
|
||||||
* String name, and a value that is a Java primitive (int, long, float, double, boolean)
|
|
||||||
* or any Serializable object (a Java object is Serializable when it implements the
|
|
||||||
* Serializable interface).
|
|
||||||
*
|
*
|
||||||
* @author Matt Tucker
|
* @author Matt Tucker
|
||||||
*/
|
*/
|
||||||
public abstract class Packet {
|
public abstract class Packet {
|
||||||
private static final Logger LOGGER = Logger.getLogger(Packet.class.getName());
|
|
||||||
|
|
||||||
protected static final String DEFAULT_LANGUAGE =
|
protected static final String DEFAULT_LANGUAGE =
|
||||||
java.util.Locale.getDefault().getLanguage().toLowerCase(Locale.US);
|
java.util.Locale.getDefault().getLanguage().toLowerCase(Locale.US);
|
||||||
|
@ -88,7 +80,6 @@ public abstract class Packet {
|
||||||
private final List<PacketExtension> packetExtensions
|
private final List<PacketExtension> packetExtensions
|
||||||
= new CopyOnWriteArrayList<PacketExtension>();
|
= new CopyOnWriteArrayList<PacketExtension>();
|
||||||
|
|
||||||
private final Map<String,Object> properties = new HashMap<String, Object>();
|
|
||||||
private XMPPError error = null;
|
private XMPPError error = null;
|
||||||
|
|
||||||
public Packet() {
|
public Packet() {
|
||||||
|
@ -292,60 +283,6 @@ public abstract class Packet {
|
||||||
packetExtensions.remove(extension);
|
packetExtensions.remove(extension);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the packet property with the specified name or <tt>null</tt> if the
|
|
||||||
* property doesn't exist. Property values that were originally primitives will
|
|
||||||
* be returned as their object equivalent. For example, an int property will be
|
|
||||||
* returned as an Integer, a double as a Double, etc.
|
|
||||||
*
|
|
||||||
* @param name the name of the property.
|
|
||||||
* @return the property, or <tt>null</tt> if the property doesn't exist.
|
|
||||||
*/
|
|
||||||
public synchronized Object getProperty(String name) {
|
|
||||||
if (properties == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return properties.get(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets a property with an Object as the value. The value must be Serializable
|
|
||||||
* or an IllegalArgumentException will be thrown.
|
|
||||||
*
|
|
||||||
* @param name the name of the property.
|
|
||||||
* @param value the value of the property.
|
|
||||||
*/
|
|
||||||
public synchronized void setProperty(String name, Object value) {
|
|
||||||
if (!(value instanceof Serializable)) {
|
|
||||||
throw new IllegalArgumentException("Value must be serialiazble");
|
|
||||||
}
|
|
||||||
properties.put(name, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deletes a property.
|
|
||||||
*
|
|
||||||
* @param name the name of the property to delete.
|
|
||||||
*/
|
|
||||||
public synchronized void deleteProperty(String name) {
|
|
||||||
if (properties == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
properties.remove(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an unmodifiable collection of all the property names that are set.
|
|
||||||
*
|
|
||||||
* @return all property names.
|
|
||||||
*/
|
|
||||||
public synchronized Collection<String> getPropertyNames() {
|
|
||||||
if (properties == null) {
|
|
||||||
return Collections.emptySet();
|
|
||||||
}
|
|
||||||
return Collections.unmodifiableSet(new HashSet<String>(properties.keySet()));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the packet as XML. Every concrete extension of Packet must implement
|
* Returns the packet as XML. Every concrete extension of Packet must implement
|
||||||
* this method. In addition to writing out packet-specific data, every sub-class
|
* this method. In addition to writing out packet-specific data, every sub-class
|
||||||
|
@ -368,88 +305,6 @@ public abstract class Packet {
|
||||||
for (PacketExtension extension : getExtensions()) {
|
for (PacketExtension extension : getExtensions()) {
|
||||||
xml.append(extension.toXML());
|
xml.append(extension.toXML());
|
||||||
}
|
}
|
||||||
// Add in packet properties.
|
|
||||||
if (properties != null && !properties.isEmpty()) {
|
|
||||||
xml.halfOpenElement("properties").xmlnsAttribute("http://www.jivesoftware.com/xmlns/xmpp/properties");
|
|
||||||
xml.rightAngelBracket();
|
|
||||||
// Loop through all properties and write them out.
|
|
||||||
for (String name : getPropertyNames()) {
|
|
||||||
Object value = getProperty(name);
|
|
||||||
xml.openElement("property");
|
|
||||||
xml.element("name", name);
|
|
||||||
xml.halfOpenElement("value");
|
|
||||||
|
|
||||||
String type;
|
|
||||||
String valueStr;
|
|
||||||
if (value instanceof Integer) {
|
|
||||||
type = "integer";
|
|
||||||
valueStr = Integer.toString((Integer)value);
|
|
||||||
}
|
|
||||||
else if (value instanceof Long) {
|
|
||||||
type = "long";
|
|
||||||
valueStr = Long.toString((Long) value);
|
|
||||||
}
|
|
||||||
else if (value instanceof Float) {
|
|
||||||
type = "float";
|
|
||||||
valueStr = Float.toString((Float) value);
|
|
||||||
}
|
|
||||||
else if (value instanceof Double) {
|
|
||||||
type = "double";
|
|
||||||
valueStr = Double.toString((Double) value);
|
|
||||||
}
|
|
||||||
else if (value instanceof Boolean) {
|
|
||||||
type = "boolean";
|
|
||||||
valueStr = Boolean.toString((Boolean) value);
|
|
||||||
}
|
|
||||||
else if (value instanceof String) {
|
|
||||||
type = "string";
|
|
||||||
valueStr = (String) value;
|
|
||||||
}
|
|
||||||
// Otherwise, it's a generic Serializable object. Serialized objects are in
|
|
||||||
// a binary format, which won't work well inside of XML. Therefore, we base-64
|
|
||||||
// encode the binary data before adding it.
|
|
||||||
else {
|
|
||||||
ByteArrayOutputStream byteStream = null;
|
|
||||||
ObjectOutputStream out = null;
|
|
||||||
try {
|
|
||||||
byteStream = new ByteArrayOutputStream();
|
|
||||||
out = new ObjectOutputStream(byteStream);
|
|
||||||
out.writeObject(value);
|
|
||||||
type ="java-object";
|
|
||||||
valueStr = StringUtils.encodeBase64(byteStream.toByteArray());
|
|
||||||
}
|
|
||||||
catch (Exception e) {
|
|
||||||
LOGGER.log(Level.SEVERE, "Error encoding java object", e);
|
|
||||||
type ="java-object";
|
|
||||||
valueStr = "Serializing error: " + e.getMessage();
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
if (out != null) {
|
|
||||||
try {
|
|
||||||
out.close();
|
|
||||||
}
|
|
||||||
catch (Exception e) {
|
|
||||||
// Ignore.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (byteStream != null) {
|
|
||||||
try {
|
|
||||||
byteStream.close();
|
|
||||||
}
|
|
||||||
catch (Exception e) {
|
|
||||||
// Ignore.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
xml.attribute("type", type);
|
|
||||||
xml.rightAngelBracket();
|
|
||||||
xml.escape(valueStr);
|
|
||||||
xml.closeElement("value");
|
|
||||||
xml.closeElement("property");
|
|
||||||
}
|
|
||||||
xml.closeElement("properties");
|
|
||||||
}
|
|
||||||
return xml;
|
return xml;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -479,10 +334,6 @@ public abstract class Packet {
|
||||||
if (packetID != null ? !packetID.equals(packet.packetID) : packet.packetID != null) {
|
if (packetID != null ? !packetID.equals(packet.packetID) : packet.packetID != null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (properties != null ? !properties.equals(packet.properties)
|
|
||||||
: packet.properties != null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (to != null ? !to.equals(packet.to) : packet.to != null) { return false; }
|
if (to != null ? !to.equals(packet.to) : packet.to != null) { return false; }
|
||||||
return !(xmlns != null ? !xmlns.equals(packet.xmlns) : packet.xmlns != null);
|
return !(xmlns != null ? !xmlns.equals(packet.xmlns) : packet.xmlns != null);
|
||||||
}
|
}
|
||||||
|
@ -495,7 +346,6 @@ public abstract class Packet {
|
||||||
result = 31 * result + (to != null ? to.hashCode() : 0);
|
result = 31 * result + (to != null ? to.hashCode() : 0);
|
||||||
result = 31 * result + (from != null ? from.hashCode() : 0);
|
result = 31 * result + (from != null ? from.hashCode() : 0);
|
||||||
result = 31 * result + packetExtensions.hashCode();
|
result = 31 * result + packetExtensions.hashCode();
|
||||||
result = 31 * result + properties.hashCode();
|
|
||||||
result = 31 * result + (error != null ? error.hashCode() : 0);
|
result = 31 * result + (error != null ? error.hashCode() : 0);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,9 +16,7 @@
|
||||||
*/
|
*/
|
||||||
package org.jivesoftware.smack.util;
|
package org.jivesoftware.smack.util;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.ObjectInputStream;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
@ -56,12 +54,6 @@ import org.xmlpull.v1.XmlPullParserException;
|
||||||
public class PacketParserUtils {
|
public class PacketParserUtils {
|
||||||
private static final Logger LOGGER = Logger.getLogger(PacketParserUtils.class.getName());
|
private static final Logger LOGGER = Logger.getLogger(PacketParserUtils.class.getName());
|
||||||
|
|
||||||
/**
|
|
||||||
* Namespace used to store packet properties.
|
|
||||||
*/
|
|
||||||
private static final String PROPERTIES_NAMESPACE =
|
|
||||||
"http://www.jivesoftware.com/xmlns/xmpp/properties";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses a message packet.
|
* Parses a message packet.
|
||||||
*
|
*
|
||||||
|
@ -69,7 +61,7 @@ public class PacketParserUtils {
|
||||||
* @return a Message packet.
|
* @return a Message packet.
|
||||||
* @throws Exception if an exception occurs while parsing the packet.
|
* @throws Exception if an exception occurs while parsing the packet.
|
||||||
*/
|
*/
|
||||||
public static Packet parseMessage(XmlPullParser parser) throws Exception {
|
public static Message parseMessage(XmlPullParser parser) throws Exception {
|
||||||
Message message = new Message();
|
Message message = new Message();
|
||||||
String id = parser.getAttributeValue("", "id");
|
String id = parser.getAttributeValue("", "id");
|
||||||
message.setPacketID(id == null ? Packet.ID_NOT_AVAILABLE : id);
|
message.setPacketID(id == null ? Packet.ID_NOT_AVAILABLE : id);
|
||||||
|
@ -93,7 +85,6 @@ public class PacketParserUtils {
|
||||||
// in arbitrary sub-elements.
|
// in arbitrary sub-elements.
|
||||||
boolean done = false;
|
boolean done = false;
|
||||||
String thread = null;
|
String thread = null;
|
||||||
Map<String, Object> properties = null;
|
|
||||||
while (!done) {
|
while (!done) {
|
||||||
int eventType = parser.next();
|
int eventType = parser.next();
|
||||||
if (eventType == XmlPullParser.START_TAG) {
|
if (eventType == XmlPullParser.START_TAG) {
|
||||||
|
@ -131,11 +122,6 @@ public class PacketParserUtils {
|
||||||
else if (elementName.equals("error")) {
|
else if (elementName.equals("error")) {
|
||||||
message.setError(parseError(parser));
|
message.setError(parseError(parser));
|
||||||
}
|
}
|
||||||
else if (elementName.equals("properties") &&
|
|
||||||
namespace.equals(PROPERTIES_NAMESPACE))
|
|
||||||
{
|
|
||||||
properties = parseProperties(parser);
|
|
||||||
}
|
|
||||||
// Otherwise, it must be a packet extension.
|
// Otherwise, it must be a packet extension.
|
||||||
else {
|
else {
|
||||||
message.addExtension(
|
message.addExtension(
|
||||||
|
@ -150,12 +136,6 @@ public class PacketParserUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
message.setThread(thread);
|
message.setThread(thread);
|
||||||
// Set packet properties.
|
|
||||||
if (properties != null) {
|
|
||||||
for (String name : properties.keySet()) {
|
|
||||||
message.setProperty(name, properties.get(name));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -246,15 +226,6 @@ public class PacketParserUtils {
|
||||||
else if (elementName.equals("error")) {
|
else if (elementName.equals("error")) {
|
||||||
presence.setError(parseError(parser));
|
presence.setError(parseError(parser));
|
||||||
}
|
}
|
||||||
else if (elementName.equals("properties") &&
|
|
||||||
namespace.equals(PROPERTIES_NAMESPACE))
|
|
||||||
{
|
|
||||||
Map<String,Object> properties = parseProperties(parser);
|
|
||||||
// Set packet properties.
|
|
||||||
for (String name : properties.keySet()) {
|
|
||||||
presence.setProperty(name, properties.get(name));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Otherwise, it must be a packet extension.
|
// Otherwise, it must be a packet extension.
|
||||||
else {
|
else {
|
||||||
try {
|
try {
|
||||||
|
@ -549,87 +520,6 @@ public class PacketParserUtils {
|
||||||
return methods;
|
return methods;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse a properties sub-packet. If any errors occur while de-serializing Java object
|
|
||||||
* properties, an exception will be printed and not thrown since a thrown
|
|
||||||
* exception will shut down the entire connection. ClassCastExceptions will occur
|
|
||||||
* when both the sender and receiver of the packet don't have identical versions
|
|
||||||
* of the same class.
|
|
||||||
*
|
|
||||||
* @param parser the XML parser, positioned at the start of a properties sub-packet.
|
|
||||||
* @return a map of the properties.
|
|
||||||
* @throws Exception if an error occurs while parsing the properties.
|
|
||||||
*/
|
|
||||||
public static Map<String, Object> parseProperties(XmlPullParser parser) throws Exception {
|
|
||||||
Map<String, Object> properties = new HashMap<String, Object>();
|
|
||||||
while (true) {
|
|
||||||
int eventType = parser.next();
|
|
||||||
if (eventType == XmlPullParser.START_TAG && parser.getName().equals("property")) {
|
|
||||||
// Parse a property
|
|
||||||
boolean done = false;
|
|
||||||
String name = null;
|
|
||||||
String type = null;
|
|
||||||
String valueText = null;
|
|
||||||
Object value = null;
|
|
||||||
while (!done) {
|
|
||||||
eventType = parser.next();
|
|
||||||
if (eventType == XmlPullParser.START_TAG) {
|
|
||||||
String elementName = parser.getName();
|
|
||||||
if (elementName.equals("name")) {
|
|
||||||
name = parser.nextText();
|
|
||||||
}
|
|
||||||
else if (elementName.equals("value")) {
|
|
||||||
type = parser.getAttributeValue("", "type");
|
|
||||||
valueText = parser.nextText();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (eventType == XmlPullParser.END_TAG) {
|
|
||||||
if (parser.getName().equals("property")) {
|
|
||||||
if ("integer".equals(type)) {
|
|
||||||
value = Integer.valueOf(valueText);
|
|
||||||
}
|
|
||||||
else if ("long".equals(type)) {
|
|
||||||
value = Long.valueOf(valueText);
|
|
||||||
}
|
|
||||||
else if ("float".equals(type)) {
|
|
||||||
value = Float.valueOf(valueText);
|
|
||||||
}
|
|
||||||
else if ("double".equals(type)) {
|
|
||||||
value = Double.valueOf(valueText);
|
|
||||||
}
|
|
||||||
else if ("boolean".equals(type)) {
|
|
||||||
value = Boolean.valueOf(valueText);
|
|
||||||
}
|
|
||||||
else if ("string".equals(type)) {
|
|
||||||
value = valueText;
|
|
||||||
}
|
|
||||||
else if ("java-object".equals(type)) {
|
|
||||||
try {
|
|
||||||
byte [] bytes = StringUtils.decodeBase64(valueText);
|
|
||||||
ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(bytes));
|
|
||||||
value = in.readObject();
|
|
||||||
}
|
|
||||||
catch (Exception e) {
|
|
||||||
LOGGER.log(Level.SEVERE, "Error parsing java object", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (name != null && value != null) {
|
|
||||||
properties.put(name, value);
|
|
||||||
}
|
|
||||||
done = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (eventType == XmlPullParser.END_TAG) {
|
|
||||||
if (parser.getName().equals("properties")) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return properties;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses SASL authentication error packets.
|
* Parses SASL authentication error packets.
|
||||||
*
|
*
|
||||||
|
|
|
@ -90,6 +90,11 @@
|
||||||
<td><a href="http://www.xmpp.org/extensions/xep-0332.html">XEP-0332</a></td>
|
<td><a href="http://www.xmpp.org/extensions/xep-0332.html">XEP-0332</a></td>
|
||||||
<td>Allows to transport HTTP communication over XMPP peer-to-peer networks.</td>
|
<td>Allows to transport HTTP communication over XMPP peer-to-peer networks.</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><a href="properties.html">Jive Properties</a></td>
|
||||||
|
<td>N/A</td>
|
||||||
|
<td>TODO</td>
|
||||||
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -10,10 +10,6 @@
|
||||||
Packet Properties
|
Packet Properties
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="nav">
|
|
||||||
« <a href="index.html">Table of Contents</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Smack provides an easy mechanism for attaching arbitrary properties to packets. Each property
|
Smack provides an easy mechanism for attaching arbitrary properties to packets. Each property
|
||||||
has a String name, and a value that is a Java primitive (int, long, float, double, boolean) or
|
has a String name, and a value that is a Java primitive (int, long, float, double, boolean) or
|
||||||
|
@ -32,10 +28,13 @@ demonstrates how to set properties:
|
||||||
|
|
||||||
<div class="code"><pre>
|
<div class="code"><pre>
|
||||||
Message message = chat.createMessage();
|
Message message = chat.createMessage();
|
||||||
|
JivePropertiesExtension jpe = new JivePropertiesExtension();
|
||||||
<font color="gray"><i>// Add a Color object as a property.</i></font>
|
<font color="gray"><i>// Add a Color object as a property.</i></font>
|
||||||
message.setProperty(<font color="blue">"favoriteColor"</font>, new Color(0, 0, 255));
|
jpe.setProperty(<font color="blue">"favoriteColor"</font>, new Color(0, 0, 255));
|
||||||
<font color="gray"><i>// Add an int as a property.</i></font>
|
<font color="gray"><i>// Add an int as a property.</i></font>
|
||||||
message.setProperty(<font color="blue">"favoriteNumber"</font>, 4);
|
jpe.setProperty(<font color="blue">"favoriteNumber"</font>, 4);
|
||||||
|
<font color="gray"><i>// Add the JivePropertiesExtension to the message packet</i></font>
|
||||||
|
message.addPacketExtension(jpe);
|
||||||
chat.sendMessage(message);
|
chat.sendMessage(message);
|
||||||
</pre></div>
|
</pre></div>
|
||||||
|
|
||||||
|
@ -45,14 +44,23 @@ Getting those same properties would use the following code:
|
||||||
|
|
||||||
<div class="code"><pre>
|
<div class="code"><pre>
|
||||||
Message message = chat.nextMessage();
|
Message message = chat.nextMessage();
|
||||||
|
<font color="gray"><i>// Get the JivePropertiesExtension</i></font>
|
||||||
|
JivePropertiesExtension jpe = message.getExtension(JivePropertiesExtension.NAMESPACE);
|
||||||
<font color="gray"><i>// Get a Color object property.</i></font>
|
<font color="gray"><i>// Get a Color object property.</i></font>
|
||||||
Color favoriteColor = (Color)message.getProperty(<font color="blue">"favoriteColor"</font>);
|
Color favoriteColor = (Color)jpe.getProperty(<font color="blue">"favoriteColor"</font>);
|
||||||
<font color="gray"><i>// Get an int property. Note that properties are always returned as
|
<font color="gray"><i>// Get an int property. Note that properties are always returned as
|
||||||
// Objects, so we must cast the value to an Integer, then convert
|
// Objects, so we must cast the value to an Integer, then convert
|
||||||
// it to an int.</i></font>
|
// it to an int.</i></font>
|
||||||
int favoriteNumber = ((Integer)message.getProperty(<font color="blue">"favoriteNumber"</font>)).intValue();
|
int favoriteNumber = ((Integer)jpe.getProperty(<font color="blue">"favoriteNumber"</font>)).intValue();
|
||||||
</pre></div>
|
</pre></div>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
For convenience <code>JivePropertiesManager</code> contains two helper
|
||||||
|
methods namely <code>addProperty(Packet packet, String name, Object
|
||||||
|
value)</code> and
|
||||||
|
<code>getProperty(Packet packet, String name)</code>.
|
||||||
|
</p>
|
||||||
|
|
||||||
<p class="subheader">
|
<p class="subheader">
|
||||||
Objects as Properties
|
Objects as Properties
|
||||||
</p>
|
</p>
|
||||||
|
@ -63,10 +71,6 @@ you should keep the following in mind:
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
<li>Packet extensions are the more standard way to add extra data to XMPP stanzas. Using
|
|
||||||
properties may be more convenient in some cases, however, since Smack will do the
|
|
||||||
work of handling the XML.
|
|
||||||
|
|
||||||
<li>When you send a Java object as a property, only clients running Java will be able to
|
<li>When you send a Java object as a property, only clients running Java will be able to
|
||||||
interpret the data. So, consider using a series of primitive values to transfer data
|
interpret the data. So, consider using a series of primitive values to transfer data
|
||||||
instead.
|
instead.
|
|
@ -24,6 +24,7 @@
|
||||||
<a href="pubsub.html">PubSub</a><br>
|
<a href="pubsub.html">PubSub</a><br>
|
||||||
<a href="caps.html">Entity Capabilities</a><br>
|
<a href="caps.html">Entity Capabilities</a><br>
|
||||||
<a href="privacy.html">Privacy</a><br>
|
<a href="privacy.html">Privacy</a><br>
|
||||||
|
<a href="properties.html">JiveProperties</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|
|
@ -20,7 +20,6 @@
|
||||||
<li><a href="roster.html">Roster and Presence</a>
|
<li><a href="roster.html">Roster and Presence</a>
|
||||||
<li><a href="processing.html">Processing Incoming Packets</a>
|
<li><a href="processing.html">Processing Incoming Packets</a>
|
||||||
<li><a href="providers.html">Provider Architecture</a>
|
<li><a href="providers.html">Provider Architecture</a>
|
||||||
<li><a href="properties.html">Packet Properties</a>
|
|
||||||
<li><a href="debugging.html">Debugging with Smack</a>
|
<li><a href="debugging.html">Debugging with Smack</a>
|
||||||
<p>
|
<p>
|
||||||
<li><a href="extensions/index.html">Smack Extensions Manual</a>
|
<li><a href="extensions/index.html">Smack Extensions Manual</a>
|
||||||
|
|
|
@ -0,0 +1,77 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright 2014 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.smackx.jiveproperties;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.packet.Packet;
|
||||||
|
import org.jivesoftware.smackx.jiveproperties.packet.JivePropertiesExtension;
|
||||||
|
|
||||||
|
public class JivePropertiesManager {
|
||||||
|
|
||||||
|
private static boolean javaObjectEnabled = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enables deserialization of Java objects embedded in the 'properties' packet extension. Since
|
||||||
|
* this is a security sensitive feature, it is disabled per default in Smack. Only enable it if
|
||||||
|
* you are sure that you understand the potential security implications it can cause.
|
||||||
|
* <p>
|
||||||
|
* See also:
|
||||||
|
* <ul>
|
||||||
|
* <li> <a href="http://stackoverflow.com/questions/19054460/">"What is the security impact of deserializing untrusted data in Java?" on Stackoverflow<a>
|
||||||
|
* <ul>
|
||||||
|
* @param enabled true to enable Java object deserialization
|
||||||
|
*/
|
||||||
|
public static void setJavaObjectEnabled(boolean enabled) {
|
||||||
|
JivePropertiesManager.javaObjectEnabled = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isJavaObjectEnabled() {
|
||||||
|
return javaObjectEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience method to add a property to a packet.
|
||||||
|
*
|
||||||
|
* @param packet the packet to add the property to.
|
||||||
|
* @param name the name of the property to add.
|
||||||
|
* @param value the value of the property to add.
|
||||||
|
*/
|
||||||
|
public static void addProperty(Packet packet, String name, Object value) {
|
||||||
|
JivePropertiesExtension jpe = (JivePropertiesExtension) packet.getExtension(JivePropertiesExtension.NAMESPACE);
|
||||||
|
if (jpe == null) {
|
||||||
|
jpe = new JivePropertiesExtension();
|
||||||
|
packet.addExtension(jpe);
|
||||||
|
}
|
||||||
|
jpe.setProperty(name, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience method to get a property from a packet. Will return null if the packet contains
|
||||||
|
* not property with the given name.
|
||||||
|
*
|
||||||
|
* @param packet
|
||||||
|
* @param name
|
||||||
|
* @return the property or <tt>null</tt> if none found.
|
||||||
|
*/
|
||||||
|
public static Object getProperty(Packet packet, String name) {
|
||||||
|
Object res = null;
|
||||||
|
JivePropertiesExtension jpe = (JivePropertiesExtension) packet.getExtension(JivePropertiesExtension.NAMESPACE);
|
||||||
|
if (jpe != null) {
|
||||||
|
res = jpe.getProperty(name);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,210 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright 2003-2007 Jive Software.
|
||||||
|
*
|
||||||
|
* 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.smackx.jiveproperties.packet;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.ObjectOutputStream;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.packet.PacketExtension;
|
||||||
|
import org.jivesoftware.smack.util.StringUtils;
|
||||||
|
import org.jivesoftware.smack.util.XmlStringBuilder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Properties provide an easy mechanism for clients to share data. Each property has a
|
||||||
|
* String name, and a value that is a Java primitive (int, long, float, double, boolean)
|
||||||
|
* or any Serializable object (a Java object is Serializable when it implements the
|
||||||
|
* Serializable interface).
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class JivePropertiesExtension implements PacketExtension {
|
||||||
|
/**
|
||||||
|
* Namespace used to store packet properties.
|
||||||
|
*/
|
||||||
|
public static final String NAMESPACE = "http://www.jivesoftware.com/xmlns/xmpp/properties";
|
||||||
|
|
||||||
|
public static final String ELEMENT = "properties";
|
||||||
|
|
||||||
|
private static final Logger LOGGER = Logger.getLogger(JivePropertiesExtension.class.getName());
|
||||||
|
|
||||||
|
private final Map<String, Object> properties;
|
||||||
|
|
||||||
|
public JivePropertiesExtension() {
|
||||||
|
properties = new HashMap<String, Object>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public JivePropertiesExtension(Map<String, Object> properties) {
|
||||||
|
this.properties = properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the packet property with the specified name or <tt>null</tt> if the
|
||||||
|
* property doesn't exist. Property values that were originally primitives will
|
||||||
|
* be returned as their object equivalent. For example, an int property will be
|
||||||
|
* returned as an Integer, a double as a Double, etc.
|
||||||
|
*
|
||||||
|
* @param name the name of the property.
|
||||||
|
* @return the property, or <tt>null</tt> if the property doesn't exist.
|
||||||
|
*/
|
||||||
|
public synchronized Object getProperty(String name) {
|
||||||
|
if (properties == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return properties.get(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a property with an Object as the value. The value must be Serializable
|
||||||
|
* or an IllegalArgumentException will be thrown.
|
||||||
|
*
|
||||||
|
* @param name the name of the property.
|
||||||
|
* @param value the value of the property.
|
||||||
|
*/
|
||||||
|
public synchronized void setProperty(String name, Object value) {
|
||||||
|
if (!(value instanceof Serializable)) {
|
||||||
|
throw new IllegalArgumentException("Value must be serialiazble");
|
||||||
|
}
|
||||||
|
properties.put(name, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes a property.
|
||||||
|
*
|
||||||
|
* @param name the name of the property to delete.
|
||||||
|
*/
|
||||||
|
public synchronized void deleteProperty(String name) {
|
||||||
|
if (properties == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
properties.remove(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an unmodifiable collection of all the property names that are set.
|
||||||
|
*
|
||||||
|
* @return all property names.
|
||||||
|
*/
|
||||||
|
public synchronized Collection<String> getPropertyNames() {
|
||||||
|
if (properties == null) {
|
||||||
|
return Collections.emptySet();
|
||||||
|
}
|
||||||
|
return Collections.unmodifiableSet(new HashSet<String>(properties.keySet()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getElementName() {
|
||||||
|
return ELEMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getNamespace() {
|
||||||
|
return NAMESPACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CharSequence toXML() {
|
||||||
|
XmlStringBuilder xml = new XmlStringBuilder(this);
|
||||||
|
xml.rightAngelBracket();
|
||||||
|
// Loop through all properties and write them out.
|
||||||
|
for (String name : getPropertyNames()) {
|
||||||
|
Object value = getProperty(name);
|
||||||
|
xml.openElement("property");
|
||||||
|
xml.element("name", name);
|
||||||
|
xml.halfOpenElement("value");
|
||||||
|
|
||||||
|
String type;
|
||||||
|
String valueStr;
|
||||||
|
if (value instanceof Integer) {
|
||||||
|
type = "integer";
|
||||||
|
valueStr = Integer.toString((Integer) value);
|
||||||
|
}
|
||||||
|
else if (value instanceof Long) {
|
||||||
|
type = "long";
|
||||||
|
valueStr = Long.toString((Long) value);
|
||||||
|
}
|
||||||
|
else if (value instanceof Float) {
|
||||||
|
type = "float";
|
||||||
|
valueStr = Float.toString((Float) value);
|
||||||
|
}
|
||||||
|
else if (value instanceof Double) {
|
||||||
|
type = "double";
|
||||||
|
valueStr = Double.toString((Double) value);
|
||||||
|
}
|
||||||
|
else if (value instanceof Boolean) {
|
||||||
|
type = "boolean";
|
||||||
|
valueStr = Boolean.toString((Boolean) value);
|
||||||
|
}
|
||||||
|
else if (value instanceof String) {
|
||||||
|
type = "string";
|
||||||
|
valueStr = (String) value;
|
||||||
|
}
|
||||||
|
// Otherwise, it's a generic Serializable object. Serialized objects are in
|
||||||
|
// a binary format, which won't work well inside of XML. Therefore, we base-64
|
||||||
|
// encode the binary data before adding it.
|
||||||
|
else {
|
||||||
|
ByteArrayOutputStream byteStream = null;
|
||||||
|
ObjectOutputStream out = null;
|
||||||
|
try {
|
||||||
|
byteStream = new ByteArrayOutputStream();
|
||||||
|
out = new ObjectOutputStream(byteStream);
|
||||||
|
out.writeObject(value);
|
||||||
|
type = "java-object";
|
||||||
|
valueStr = StringUtils.encodeBase64(byteStream.toByteArray());
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
LOGGER.log(Level.SEVERE, "Error encoding java object", e);
|
||||||
|
type = "java-object";
|
||||||
|
valueStr = "Serializing error: " + e.getMessage();
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
if (out != null) {
|
||||||
|
try {
|
||||||
|
out.close();
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
// Ignore.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (byteStream != null) {
|
||||||
|
try {
|
||||||
|
byteStream.close();
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
// Ignore.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
xml.attribute("type", type);
|
||||||
|
xml.rightAngelBracket();
|
||||||
|
xml.escape(valueStr);
|
||||||
|
xml.closeElement("value");
|
||||||
|
xml.closeElement("property");
|
||||||
|
}
|
||||||
|
xml.closeElement(this);
|
||||||
|
|
||||||
|
return xml;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,127 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright 2003-2007 Jive Software.
|
||||||
|
*
|
||||||
|
* 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.smackx.jiveproperties.provider;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ObjectInputStream;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.packet.PacketExtension;
|
||||||
|
import org.jivesoftware.smack.provider.PacketExtensionProvider;
|
||||||
|
import org.jivesoftware.smack.util.StringUtils;
|
||||||
|
import org.jivesoftware.smackx.jiveproperties.JivePropertiesManager;
|
||||||
|
import org.jivesoftware.smackx.jiveproperties.packet.JivePropertiesExtension;
|
||||||
|
import org.xmlpull.v1.XmlPullParser;
|
||||||
|
|
||||||
|
public class JivePropertiesExtensionProvider implements PacketExtensionProvider {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = Logger.getLogger(JivePropertiesExtensionProvider.class.getName());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a properties sub-packet. If any errors occur while de-serializing Java object
|
||||||
|
* properties, an exception will be printed and not thrown since a thrown exception will shut
|
||||||
|
* down the entire connection. ClassCastExceptions will occur when both the sender and receiver
|
||||||
|
* of the packet don't have identical versions of the same class.
|
||||||
|
* <p>
|
||||||
|
* Note that you have to explicitly enabled Java object deserialization with @{link
|
||||||
|
* {@link JivePropertiesManager#setJavaObjectEnabled(boolean)}
|
||||||
|
*
|
||||||
|
* @param parser the XML parser, positioned at the start of a properties sub-packet.
|
||||||
|
* @return a map of the properties.
|
||||||
|
* @throws Exception if an error occurs while parsing the properties.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public PacketExtension parseExtension(XmlPullParser parser) throws Exception {
|
||||||
|
Map<String, Object> properties = new HashMap<String, Object>();
|
||||||
|
while (true) {
|
||||||
|
int eventType = parser.next();
|
||||||
|
if (eventType == XmlPullParser.START_TAG && parser.getName().equals("property")) {
|
||||||
|
// Parse a property
|
||||||
|
boolean done = false;
|
||||||
|
String name = null;
|
||||||
|
String type = null;
|
||||||
|
String valueText = null;
|
||||||
|
Object value = null;
|
||||||
|
while (!done) {
|
||||||
|
eventType = parser.next();
|
||||||
|
if (eventType == XmlPullParser.START_TAG) {
|
||||||
|
String elementName = parser.getName();
|
||||||
|
if (elementName.equals("name")) {
|
||||||
|
name = parser.nextText();
|
||||||
|
}
|
||||||
|
else if (elementName.equals("value")) {
|
||||||
|
type = parser.getAttributeValue("", "type");
|
||||||
|
valueText = parser.nextText();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (eventType == XmlPullParser.END_TAG) {
|
||||||
|
if (parser.getName().equals("property")) {
|
||||||
|
if ("integer".equals(type)) {
|
||||||
|
value = Integer.valueOf(valueText);
|
||||||
|
}
|
||||||
|
else if ("long".equals(type)) {
|
||||||
|
value = Long.valueOf(valueText);
|
||||||
|
}
|
||||||
|
else if ("float".equals(type)) {
|
||||||
|
value = Float.valueOf(valueText);
|
||||||
|
}
|
||||||
|
else if ("double".equals(type)) {
|
||||||
|
value = Double.valueOf(valueText);
|
||||||
|
}
|
||||||
|
else if ("boolean".equals(type)) {
|
||||||
|
value = Boolean.valueOf(valueText);
|
||||||
|
}
|
||||||
|
else if ("string".equals(type)) {
|
||||||
|
value = valueText;
|
||||||
|
}
|
||||||
|
else if ("java-object".equals(type)) {
|
||||||
|
if (JivePropertiesManager.isJavaObjectEnabled()) {
|
||||||
|
try {
|
||||||
|
byte[] bytes = StringUtils.decodeBase64(valueText);
|
||||||
|
ObjectInputStream in = new ObjectInputStream(
|
||||||
|
new ByteArrayInputStream(bytes));
|
||||||
|
value = in.readObject();
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
LOGGER.log(Level.SEVERE, "Error parsing java object", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
LOGGER.severe("JavaObject is not enabled. Enable with JivePropertiesManager.setJavaObjectEnabled(true)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (name != null && value != null) {
|
||||||
|
properties.put(name, value);
|
||||||
|
}
|
||||||
|
done = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (eventType == XmlPullParser.END_TAG) {
|
||||||
|
if (parser.getName().equals(JivePropertiesExtension.ELEMENT)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new JivePropertiesExtension(properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -456,4 +456,10 @@
|
||||||
<className>org.jivesoftware.smackx.amp.provider.AMPExtensionProvider</className>
|
<className>org.jivesoftware.smackx.amp.provider.AMPExtensionProvider</className>
|
||||||
</extensionProvider>
|
</extensionProvider>
|
||||||
|
|
||||||
|
<!-- JiveProperties -->
|
||||||
|
<extensionProvider>
|
||||||
|
<elementName>properties</elementName>
|
||||||
|
<namespace>http://www.jivesoftware.com/xmlns/xmpp/properties</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.jiveproperties.provider.JivePropertiesExtensionProvider</className>
|
||||||
|
</extensionProvider>
|
||||||
</smackProviders>
|
</smackProviders>
|
||||||
|
|
|
@ -0,0 +1,66 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright 2014 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.smackx.jiveproperties;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.packet.Message;
|
||||||
|
import org.jivesoftware.smack.test.util.TestUtils;
|
||||||
|
import org.jivesoftware.smack.util.PacketParserUtils;
|
||||||
|
import org.jivesoftware.smackx.InitExtensions;
|
||||||
|
import org.jivesoftware.smackx.jiveproperties.packet.JivePropertiesExtension;
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class JivePropertiesExtensionTest extends InitExtensions {
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
JivePropertiesManager.setJavaObjectEnabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void tearDown() {
|
||||||
|
JivePropertiesManager.setJavaObjectEnabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void checkProvider() throws Exception {
|
||||||
|
// @formatter:off
|
||||||
|
String properties = "<message from='romeo@example.net/orchard' to='juliet@example.com/balcony'>"
|
||||||
|
+ "<body>Neither, fair saint, if either thee dislike.</body>"
|
||||||
|
+ "<properties xmlns='http://www.jivesoftware.com/xmlns/xmpp/properties'>"
|
||||||
|
+ "<property>"
|
||||||
|
+ "<name>FooBar</name>"
|
||||||
|
+ "<value type='integer'>42</value>"
|
||||||
|
+ "</property>"
|
||||||
|
+ "</properties>"
|
||||||
|
+ "</message>";
|
||||||
|
// @formatter:on
|
||||||
|
|
||||||
|
Message message = PacketParserUtils.parseMessage(TestUtils.getMessageParser(properties));
|
||||||
|
JivePropertiesExtension jpe = (JivePropertiesExtension) message.getExtension(JivePropertiesExtension.NAMESPACE);
|
||||||
|
assertNotNull(jpe);
|
||||||
|
|
||||||
|
Integer integer = (Integer) jpe.getProperty("FooBar");
|
||||||
|
assertNotNull(integer);
|
||||||
|
int fourtytwo = integer;
|
||||||
|
assertEquals(42, fourtytwo);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue