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

View File

@ -42,7 +42,7 @@ public class MultipleRecipientInfo {
* @return list of primary recipients of the packet.
*/
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.
*/
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.
*/
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();
}
@ -77,7 +77,7 @@ public class MultipleRecipientInfo {
* @return true if the received packet should not be replied.
*/
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.
*/
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);
}
}

View File

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

View File

@ -17,10 +17,11 @@
package org.jivesoftware.smackx.address.packet;
import org.jivesoftware.smack.packet.NamedElement;
import org.jivesoftware.smack.packet.PacketExtension;
import org.jivesoftware.smack.util.XmlStringBuilder;
import java.util.ArrayList;
import java.util.Iterator;
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 ELEMENT = "addresses";
public static final String BCC = "bcc";
public static final String CC = "cc";
public static final String NO_REPLY = "noreply";
public static final String REPLY_ROOM = "replyroom";
public static final String REPLY_TO = "replyto";
public static final String TO = "to";
public enum Type {
bcc,
cc,
noreply,
replyroom,
replyto,
to,
}
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 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) {
// Create a new address with the specificed configuration
Address address = new Address(type);
@ -72,7 +74,7 @@ public class MultipleAddresses implements PacketExtension {
*/
public void setNoReply() {
// 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
addresses.add(address);
}
@ -84,10 +86,9 @@ public class MultipleAddresses implements PacketExtension {
* @param type Examples of address type are: TO, CC, BCC, etc.
* @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());
for (Iterator<Address> it = addresses.iterator(); it.hasNext();) {
Address address = (Address) it.next();
for (Address address : addresses) {
if (address.getType().equals(type)) {
answer.add(address);
}
@ -96,41 +97,44 @@ public class MultipleAddresses implements PacketExtension {
return answer;
}
@Override
public String getElementName() {
return ELEMENT;
}
@Override
public String getNamespace() {
return NAMESPACE;
}
public String toXML() {
StringBuilder buf = new StringBuilder();
buf.append("<").append(getElementName());
buf.append(" xmlns=\"").append(NAMESPACE).append("\">");
@Override
public XmlStringBuilder toXML() {
XmlStringBuilder buf = new XmlStringBuilder(this);
buf.rightAngleBracket();
// Loop through all the addresses and append them to the string buffer
for (Iterator<Address> i = addresses.iterator(); i.hasNext();) {
Address address = (Address) i.next();
for (Address address : addresses) {
buf.append(address.toXML());
}
buf.append("</").append(getElementName()).append(">");
return buf.toString();
buf.closeElement(this);
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 node;
private String description;
private boolean delivered;
private String uri;
private Address(String type) {
private Address(Type type) {
this.type = type;
}
public String getType() {
public Type getType() {
return type;
}
@ -174,32 +178,26 @@ public class MultipleAddresses implements PacketExtension {
this.uri = uri;
}
private String toXML() {
StringBuilder buf = new StringBuilder();
buf.append("<address type=\"");
// Append the address type (e.g. TO/CC/BCC)
buf.append(type).append("\"");
if (jid != null) {
buf.append(" jid=\"");
buf.append(jid).append("\"");
}
if (node != null) {
buf.append(" node=\"");
buf.append(node).append("\"");
}
@Override
public String getElementName() {
return ELEMENT;
}
@Override
public XmlStringBuilder toXML() {
XmlStringBuilder buf = new XmlStringBuilder();
buf.halfOpenElement(this).attribute("type", type);
buf.optAttribute("jid", jid);
buf.optAttribute("node", node);
buf.optAttribute("desc", description);
if (description != null && description.trim().length() > 0) {
buf.append(" desc=\"");
buf.append(description).append("\"");
}
if (delivered) {
buf.append(" delivered=\"true\"");
}
if (uri != null) {
buf.append(" uri=\"");
buf.append(uri).append("\"");
}
buf.append("/>");
return buf.toString();
buf.optBooleanAttribute("delivered", delivered);
buf.optAttribute("uri", uri);
buf.closeEmptyElement();
return buf;
}
}
}

View File

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