Rework smackx.address (XEP-0033: Extended Stanza Addressing)

- Make MultipleAddress.Type a enum
- Change the signature of the methods to use Collection instead of List
- Use for-each loops instead of iterators
- Switch Provider to new provider pattern (using switch-case)
- Use XmlStringBuilder (extend the API by two new methods)
This commit is contained in:
Florian Schmaus 2014-10-11 17:06:20 +02:00
parent 36da216b4a
commit fe74fc23dc
5 changed files with 108 additions and 109 deletions

View File

@ -98,6 +98,10 @@ public class XmlStringBuilder implements Appendable, CharSequence {
return this; return this;
} }
public XmlStringBuilder halfOpenElement(NamedElement namedElement) {
return halfOpenElement(namedElement.getElementName());
}
public XmlStringBuilder openElement(String name) { public XmlStringBuilder openElement(String name) {
halfOpenElement(name).rightAngleBracket(); halfOpenElement(name).rightAngleBracket();
return this; return this;
@ -207,6 +211,13 @@ public class XmlStringBuilder implements Appendable, CharSequence {
return this; return this;
} }
public XmlStringBuilder optBooleanAttribute(String name, boolean bool) {
if (bool) {
sb.append(' ').append(name).append("='true'");
}
return this;
}
public XmlStringBuilder xmlnsAttribute(String value) { public XmlStringBuilder xmlnsAttribute(String value) {
optAttribute("xmlns", value); optAttribute("xmlns", value);
return this; return this;

View File

@ -42,7 +42,7 @@ public class MultipleRecipientInfo {
* @return list of primary recipients of the packet. * @return list of primary recipients of the packet.
*/ */
public List<MultipleAddresses.Address> getTOAddresses() { public List<MultipleAddresses.Address> getTOAddresses() {
return extension.getAddressesOfType(MultipleAddresses.TO); return extension.getAddressesOfType(MultipleAddresses.Type.to);
} }
/** /**
@ -52,7 +52,7 @@ public class MultipleRecipientInfo {
* @return list of secondary recipients of the packet. * @return list of secondary recipients of the packet.
*/ */
public List<MultipleAddresses.Address> getCCAddresses() { public List<MultipleAddresses.Address> getCCAddresses() {
return extension.getAddressesOfType(MultipleAddresses.CC); return extension.getAddressesOfType(MultipleAddresses.Type.cc);
} }
/** /**
@ -65,7 +65,7 @@ public class MultipleRecipientInfo {
* no specific address was provided. * no specific address was provided.
*/ */
public String getReplyRoom() { public String getReplyRoom() {
List<MultipleAddresses.Address> replyRoom = extension.getAddressesOfType(MultipleAddresses.REPLY_ROOM); List<MultipleAddresses.Address> replyRoom = extension.getAddressesOfType(MultipleAddresses.Type.replyroom);
return replyRoom.isEmpty() ? null : ((MultipleAddresses.Address) replyRoom.get(0)).getJid(); return replyRoom.isEmpty() ? null : ((MultipleAddresses.Address) replyRoom.get(0)).getJid();
} }
@ -77,7 +77,7 @@ public class MultipleRecipientInfo {
* @return true if the received packet should not be replied. * @return true if the received packet should not be replied.
*/ */
public boolean shouldNotReply() { public boolean shouldNotReply() {
return !extension.getAddressesOfType(MultipleAddresses.NO_REPLY).isEmpty(); return !extension.getAddressesOfType(MultipleAddresses.Type.noreply).isEmpty();
} }
/** /**
@ -89,7 +89,7 @@ public class MultipleRecipientInfo {
* no specific address was provided. * no specific address was provided.
*/ */
public MultipleAddresses.Address getReplyAddress() { public MultipleAddresses.Address getReplyAddress() {
List<MultipleAddresses.Address> replyTo = extension.getAddressesOfType(MultipleAddresses.REPLY_TO); List<MultipleAddresses.Address> replyTo = extension.getAddressesOfType(MultipleAddresses.Type.replyto);
return replyTo.isEmpty() ? null : (MultipleAddresses.Address) replyTo.get(0); return replyTo.isEmpty() ? null : (MultipleAddresses.Address) replyTo.get(0);
} }
} }

View File

@ -30,7 +30,7 @@ import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
import org.jxmpp.util.XmppStringUtils; import org.jxmpp.util.XmppStringUtils;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator; import java.util.Collection;
import java.util.List; import java.util.List;
/** /**
@ -43,7 +43,7 @@ import java.util.List;
public class MultipleRecipientManager { public class MultipleRecipientManager {
/** /**
* Sends the specified packet to the list of specified recipients using the * Sends the specified packet to the collection of specified recipients using the
* specified connection. If the server has support for XEP-33 then only one * specified connection. If the server has support for XEP-33 then only one
* packet is going to be sent to the server with the multiple recipient instructions. * packet is going to be sent to the server with the multiple recipient instructions.
* However, if XEP-33 is not supported by the server then the client is going to send * However, if XEP-33 is not supported by the server then the client is going to send
@ -51,11 +51,11 @@ public class MultipleRecipientManager {
* *
* @param connection the connection to use to send the packet. * @param connection the connection to use to send the packet.
* @param packet the packet to send to the list of recipients. * @param packet the packet to send to the list of recipients.
* @param to the list of JIDs to include in the TO list or <tt>null</tt> if no TO * @param to the collection of JIDs to include in the TO list or <tt>null</tt> if no TO
* list exists. * list exists.
* @param cc the list of JIDs to include in the CC list or <tt>null</tt> if no CC * @param cc the collection of JIDs to include in the CC list or <tt>null</tt> if no CC
* list exists. * list exists.
* @param bcc the list of JIDs to include in the BCC list or <tt>null</tt> if no BCC * @param bcc the collection of JIDs to include in the BCC list or <tt>null</tt> if no BCC
* list exists. * list exists.
* @throws FeatureNotSupportedException if special XEP-33 features where requested, but the * @throws FeatureNotSupportedException if special XEP-33 features where requested, but the
* server does not support them. * server does not support them.
@ -64,22 +64,22 @@ public class MultipleRecipientManager {
* @throws NoResponseException if there was no response from the server. * @throws NoResponseException if there was no response from the server.
* @throws NotConnectedException * @throws NotConnectedException
*/ */
public static void send(XMPPConnection connection, Packet packet, List<String> to, List<String> cc, List<String> bcc) throws NoResponseException, XMPPErrorException, FeatureNotSupportedException, NotConnectedException public static void send(XMPPConnection connection, Packet packet, Collection<String> to, Collection<String> cc, Collection<String> bcc) throws NoResponseException, XMPPErrorException, FeatureNotSupportedException, NotConnectedException
{ {
send(connection, packet, to, cc, bcc, null, null, false); send(connection, packet, to, cc, bcc, null, null, false);
} }
/** /**
* Sends the specified packet to the list of specified recipients using the specified * Sends the specified packet to the collection of specified recipients using the specified
* connection. If the server has support for XEP-33 then only one packet is going to be sent to * connection. If the server has support for XEP-33 then only one packet is going to be sent to
* the server with the multiple recipient instructions. However, if XEP-33 is not supported by * the server with the multiple recipient instructions. However, if XEP-33 is not supported by
* the server then the client is going to send the packet to each recipient. * the server then the client is going to send the packet to each recipient.
* *
* @param connection the connection to use to send the packet. * @param connection the connection to use to send the packet.
* @param packet the packet to send to the list of recipients. * @param packet the packet to send to the list of recipients.
* @param to the list of JIDs to include in the TO list or <tt>null</tt> if no TO list exists. * @param to the collection of JIDs to include in the TO list or <tt>null</tt> if no TO list exists.
* @param cc the list of JIDs to include in the CC list or <tt>null</tt> if no CC list exists. * @param cc the collection of JIDs to include in the CC list or <tt>null</tt> if no CC list exists.
* @param bcc the list of JIDs to include in the BCC list or <tt>null</tt> if no BCC list * @param bcc the collection of JIDs to include in the BCC list or <tt>null</tt> if no BCC list
* exists. * exists.
* @param replyTo address to which all replies are requested to be sent or <tt>null</tt> * @param replyTo address to which all replies are requested to be sent or <tt>null</tt>
* indicating that they can reply to any address. * indicating that they can reply to any address.
@ -93,7 +93,7 @@ public class MultipleRecipientManager {
* server does not support them. * server does not support them.
* @throws NotConnectedException * @throws NotConnectedException
*/ */
public static void send(XMPPConnection connection, Packet packet, List<String> to, List<String> cc, List<String> bcc, public static void send(XMPPConnection connection, Packet packet, Collection<String> to, Collection<String> cc, Collection<String> bcc,
String replyTo, String replyRoom, boolean noReply) throws NoResponseException, XMPPErrorException, FeatureNotSupportedException, NotConnectedException { String replyTo, String replyRoom, boolean noReply) throws NoResponseException, XMPPErrorException, FeatureNotSupportedException, NotConnectedException {
String serviceAddress = getMultipleRecipienServiceAddress(connection); String serviceAddress = getMultipleRecipienServiceAddress(connection);
if (serviceAddress != null) { if (serviceAddress != null) {
@ -149,15 +149,13 @@ public class MultipleRecipientManager {
} }
else { else {
// Send reply to multiple recipients // Send reply to multiple recipients
List<String> to = new ArrayList<String>(); List<String> to = new ArrayList<String>(info.getTOAddresses().size());
List<String> cc = new ArrayList<String>(); List<String> cc = new ArrayList<String>(info.getCCAddresses().size());
for (Iterator<MultipleAddresses.Address> it = info.getTOAddresses().iterator(); it.hasNext();) { for (MultipleAddresses.Address jid : info.getTOAddresses()) {
String jid = it.next().getJid(); to.add(jid.getJid());
to.add(jid);
} }
for (Iterator<MultipleAddresses.Address> it = info.getCCAddresses().iterator(); it.hasNext();) { for (MultipleAddresses.Address jid : info.getCCAddresses()) {
String jid = it.next().getJid(); cc.add(jid.getJid());
cc.add(jid);
} }
// Add original sender as a 'to' address (if not already present) // Add original sender as a 'to' address (if not already present)
if (!to.contains(original.getFrom()) && !cc.contains(original.getFrom())) { if (!to.contains(original.getFrom()) && !cc.contains(original.getFrom())) {
@ -171,16 +169,7 @@ public class MultipleRecipientManager {
cc.remove(bareJID); cc.remove(bareJID);
} }
String serviceAddress = getMultipleRecipienServiceAddress(connection); send(connection, reply, to, cc, null, null, null, false);
if (serviceAddress != null) {
// Send packet to target users using multiple recipient service provided by the server
sendThroughService(connection, reply, to, cc, null, null, null, false,
serviceAddress);
}
else {
// Server does not support XEP-33 so try to send the packet to each recipient
sendToIndividualRecipients(connection, reply, to, cc, null);
}
} }
} }
@ -200,51 +189,45 @@ public class MultipleRecipientManager {
} }
private static void sendToIndividualRecipients(XMPPConnection connection, Packet packet, private static void sendToIndividualRecipients(XMPPConnection connection, Packet packet,
List<String> to, List<String> cc, List<String> bcc) throws NotConnectedException { Collection<String> to, Collection<String> cc, Collection<String> bcc) throws NotConnectedException {
if (to != null) { if (to != null) {
for (Iterator<String> it = to.iterator(); it.hasNext();) { for (String jid : to) {
String jid = it.next();
packet.setTo(jid); packet.setTo(jid);
connection.sendPacket(new PacketCopy(packet.toXML())); connection.sendPacket(new PacketCopy(packet.toXML()));
} }
} }
if (cc != null) { if (cc != null) {
for (Iterator<String> it = cc.iterator(); it.hasNext();) { for (String jid : cc) {
String jid = it.next();
packet.setTo(jid); packet.setTo(jid);
connection.sendPacket(new PacketCopy(packet.toXML())); connection.sendPacket(new PacketCopy(packet.toXML()));
} }
} }
if (bcc != null) { if (bcc != null) {
for (Iterator<String> it = bcc.iterator(); it.hasNext();) { for (String jid : bcc) {
String jid = it.next();
packet.setTo(jid); packet.setTo(jid);
connection.sendPacket(new PacketCopy(packet.toXML())); connection.sendPacket(new PacketCopy(packet.toXML()));
} }
} }
} }
private static void sendThroughService(XMPPConnection connection, Packet packet, List<String> to, private static void sendThroughService(XMPPConnection connection, Packet packet, Collection<String> to,
List<String> cc, List<String> bcc, String replyTo, String replyRoom, boolean noReply, Collection<String> cc, Collection<String> bcc, String replyTo, String replyRoom, boolean noReply,
String serviceAddress) throws NotConnectedException { String serviceAddress) throws NotConnectedException {
// Create multiple recipient extension // Create multiple recipient extension
MultipleAddresses multipleAddresses = new MultipleAddresses(); MultipleAddresses multipleAddresses = new MultipleAddresses();
if (to != null) { if (to != null) {
for (Iterator<String> it = to.iterator(); it.hasNext();) { for (String jid : to) {
String jid = it.next(); multipleAddresses.addAddress(MultipleAddresses.Type.to, jid, null, null, false, null);
multipleAddresses.addAddress(MultipleAddresses.TO, jid, null, null, false, null);
} }
} }
if (cc != null) { if (cc != null) {
for (Iterator<String> it = cc.iterator(); it.hasNext();) { for (String jid : cc) {
String jid = it.next(); multipleAddresses.addAddress(MultipleAddresses.Type.to, jid, null, null, false, null);
multipleAddresses.addAddress(MultipleAddresses.CC, jid, null, null, false, null);
} }
} }
if (bcc != null) { if (bcc != null) {
for (Iterator<String> it = bcc.iterator(); it.hasNext();) { for (String jid : bcc) {
String jid = it.next(); multipleAddresses.addAddress(MultipleAddresses.Type.bcc, jid, null, null, false, null);
multipleAddresses.addAddress(MultipleAddresses.BCC, jid, null, null, false, null);
} }
} }
if (noReply) { if (noReply) {
@ -253,10 +236,10 @@ public class MultipleRecipientManager {
else { else {
if (replyTo != null && replyTo.trim().length() > 0) { if (replyTo != null && replyTo.trim().length() > 0) {
multipleAddresses multipleAddresses
.addAddress(MultipleAddresses.REPLY_TO, replyTo, null, null, false, null); .addAddress(MultipleAddresses.Type.replyto, replyTo, null, null, false, null);
} }
if (replyRoom != null && replyRoom.trim().length() > 0) { if (replyRoom != null && replyRoom.trim().length() > 0) {
multipleAddresses.addAddress(MultipleAddresses.REPLY_ROOM, replyRoom, null, null, multipleAddresses.addAddress(MultipleAddresses.Type.replyroom, replyRoom, null, null,
false, null); false, null);
} }
} }

View File

@ -17,10 +17,11 @@
package org.jivesoftware.smackx.address.packet; package org.jivesoftware.smackx.address.packet;
import org.jivesoftware.smack.packet.NamedElement;
import org.jivesoftware.smack.packet.PacketExtension; import org.jivesoftware.smack.packet.PacketExtension;
import org.jivesoftware.smack.util.XmlStringBuilder;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator;
import java.util.List; import java.util.List;
/** /**
@ -33,13 +34,14 @@ public class MultipleAddresses implements PacketExtension {
public static final String NAMESPACE = "http://jabber.org/protocol/address"; public static final String NAMESPACE = "http://jabber.org/protocol/address";
public static final String ELEMENT = "addresses"; public static final String ELEMENT = "addresses";
public static final String BCC = "bcc"; public enum Type {
public static final String CC = "cc"; bcc,
public static final String NO_REPLY = "noreply"; cc,
public static final String REPLY_ROOM = "replyroom"; noreply,
public static final String REPLY_TO = "replyto"; replyroom,
public static final String TO = "to"; replyto,
to,
}
private List<Address> addresses = new ArrayList<Address>(); private List<Address> addresses = new ArrayList<Address>();
@ -54,7 +56,7 @@ public class MultipleAddresses implements PacketExtension {
* @param delivered true when the packet was already delivered to this address. * @param delivered true when the packet was already delivered to this address.
* @param uri used to specify an external system address, such as a sip:, sips:, or im: URI. * @param uri used to specify an external system address, such as a sip:, sips:, or im: URI.
*/ */
public void addAddress(String type, String jid, String node, String desc, boolean delivered, public void addAddress(Type type, String jid, String node, String desc, boolean delivered,
String uri) { String uri) {
// Create a new address with the specificed configuration // Create a new address with the specificed configuration
Address address = new Address(type); Address address = new Address(type);
@ -72,7 +74,7 @@ public class MultipleAddresses implements PacketExtension {
*/ */
public void setNoReply() { public void setNoReply() {
// Create a new address with the specificed configuration // Create a new address with the specificed configuration
Address address = new Address(NO_REPLY); Address address = new Address(Type.noreply);
// Add the new address to the list of multiple recipients // Add the new address to the list of multiple recipients
addresses.add(address); addresses.add(address);
} }
@ -84,10 +86,9 @@ public class MultipleAddresses implements PacketExtension {
* @param type Examples of address type are: TO, CC, BCC, etc. * @param type Examples of address type are: TO, CC, BCC, etc.
* @return the list of addresses that matches the specified type. * @return the list of addresses that matches the specified type.
*/ */
public List<Address> getAddressesOfType(String type) { public List<Address> getAddressesOfType(Type type) {
List<Address> answer = new ArrayList<Address>(addresses.size()); List<Address> answer = new ArrayList<Address>(addresses.size());
for (Iterator<Address> it = addresses.iterator(); it.hasNext();) { for (Address address : addresses) {
Address address = (Address) it.next();
if (address.getType().equals(type)) { if (address.getType().equals(type)) {
answer.add(address); answer.add(address);
} }
@ -96,41 +97,44 @@ public class MultipleAddresses implements PacketExtension {
return answer; return answer;
} }
@Override
public String getElementName() { public String getElementName() {
return ELEMENT; return ELEMENT;
} }
@Override
public String getNamespace() { public String getNamespace() {
return NAMESPACE; return NAMESPACE;
} }
public String toXML() { @Override
StringBuilder buf = new StringBuilder(); public XmlStringBuilder toXML() {
buf.append("<").append(getElementName()); XmlStringBuilder buf = new XmlStringBuilder(this);
buf.append(" xmlns=\"").append(NAMESPACE).append("\">"); buf.rightAngleBracket();
// Loop through all the addresses and append them to the string buffer // Loop through all the addresses and append them to the string buffer
for (Iterator<Address> i = addresses.iterator(); i.hasNext();) { for (Address address : addresses) {
Address address = (Address) i.next();
buf.append(address.toXML()); buf.append(address.toXML());
} }
buf.append("</").append(getElementName()).append(">"); buf.closeElement(this);
return buf.toString(); return buf;
} }
public static class Address { public static class Address implements NamedElement {
private String type; public static final String ELEMENT = "address";
private final Type type;
private String jid; private String jid;
private String node; private String node;
private String description; private String description;
private boolean delivered; private boolean delivered;
private String uri; private String uri;
private Address(String type) { private Address(Type type) {
this.type = type; this.type = type;
} }
public String getType() { public Type getType() {
return type; return type;
} }
@ -174,32 +178,26 @@ public class MultipleAddresses implements PacketExtension {
this.uri = uri; this.uri = uri;
} }
private String toXML() { @Override
StringBuilder buf = new StringBuilder(); public String getElementName() {
buf.append("<address type=\""); return ELEMENT;
// Append the address type (e.g. TO/CC/BCC) }
buf.append(type).append("\"");
if (jid != null) { @Override
buf.append(" jid=\""); public XmlStringBuilder toXML() {
buf.append(jid).append("\""); XmlStringBuilder buf = new XmlStringBuilder();
} buf.halfOpenElement(this).attribute("type", type);
if (node != null) { buf.optAttribute("jid", jid);
buf.append(" node=\""); buf.optAttribute("node", node);
buf.append(node).append("\""); buf.optAttribute("desc", description);
}
if (description != null && description.trim().length() > 0) { if (description != null && description.trim().length() > 0) {
buf.append(" desc=\""); buf.append(" desc=\"");
buf.append(description).append("\""); buf.append(description).append("\"");
} }
if (delivered) { buf.optBooleanAttribute("delivered", delivered);
buf.append(" delivered=\"true\""); buf.optAttribute("uri", uri);
} buf.closeEmptyElement();
if (uri != null) { return buf;
buf.append(" uri=\"");
buf.append(uri).append("\"");
}
buf.append("/>");
return buf.toString();
} }
} }
} }

View File

@ -21,6 +21,7 @@ import java.io.IOException;
import org.jivesoftware.smack.provider.PacketExtensionProvider; import org.jivesoftware.smack.provider.PacketExtensionProvider;
import org.jivesoftware.smackx.address.packet.MultipleAddresses; import org.jivesoftware.smackx.address.packet.MultipleAddresses;
import org.jivesoftware.smackx.address.packet.MultipleAddresses.Type;
import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlPullParserException;
@ -35,13 +36,16 @@ public class MultipleAddressesProvider extends PacketExtensionProvider<MultipleA
public MultipleAddresses parse(XmlPullParser parser, public MultipleAddresses parse(XmlPullParser parser,
int initialDepth) throws XmlPullParserException, int initialDepth) throws XmlPullParserException,
IOException { IOException {
boolean done = false;
MultipleAddresses multipleAddresses = new MultipleAddresses(); MultipleAddresses multipleAddresses = new MultipleAddresses();
while (!done) { outerloop: while (true) {
int eventType = parser.next(); int eventType = parser.next();
if (eventType == XmlPullParser.START_TAG) { switch (eventType) {
if (parser.getName().equals("address")) { case XmlPullParser.START_TAG:
String type = parser.getAttributeValue("", "type"); String name = parser.getName();
switch (name) {
case MultipleAddresses.Address.ELEMENT:
String typeString = parser.getAttributeValue("", "type");
Type type = Type.valueOf(typeString);
String jid = parser.getAttributeValue("", "jid"); String jid = parser.getAttributeValue("", "jid");
String node = parser.getAttributeValue("", "node"); String node = parser.getAttributeValue("", "node");
String desc = parser.getAttributeValue("", "desc"); String desc = parser.getAttributeValue("", "desc");
@ -49,11 +53,14 @@ public class MultipleAddressesProvider extends PacketExtensionProvider<MultipleA
String uri = parser.getAttributeValue("", "uri"); String uri = parser.getAttributeValue("", "uri");
// Add the parsed address // Add the parsed address
multipleAddresses.addAddress(type, jid, node, desc, delivered, uri); multipleAddresses.addAddress(type, jid, node, desc, delivered, uri);
break;
} }
} else if (eventType == XmlPullParser.END_TAG) { break;
if (parser.getName().equals(multipleAddresses.getElementName())) { case XmlPullParser.END_TAG:
done = true; if (parser.getDepth() == initialDepth) {
break outerloop;
} }
break;
} }
} }
return multipleAddresses; return multipleAddresses;