Make PubSub elements namespace aware

Also fixes SMACK-814.
This commit is contained in:
Florian Schmaus 2018-04-19 11:05:43 +02:00
parent acc64ffc2d
commit 31244ae982
25 changed files with 354 additions and 173 deletions

View File

@ -18,6 +18,7 @@ package org.jivesoftware.smackx.pubsub;
import org.jivesoftware.smack.XMPPConnection; import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.packet.ExtensionElement; import org.jivesoftware.smack.packet.ExtensionElement;
import org.jivesoftware.smack.util.Objects;
import org.jivesoftware.smack.util.StringUtils; import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.smack.util.XmlStringBuilder; import org.jivesoftware.smack.util.XmlStringBuilder;
@ -38,10 +39,30 @@ import org.jxmpp.jid.BareJid;
public class Affiliation implements ExtensionElement { public class Affiliation implements ExtensionElement {
public static final String ELEMENT = "affiliation"; public static final String ELEMENT = "affiliation";
public enum AffiliationNamespace {
basic(PubSubElementType.AFFILIATIONS),
owner(PubSubElementType.AFFILIATIONS_OWNER),
;
public final PubSubElementType type;
AffiliationNamespace(PubSubElementType type) {
this.type = type;
}
public static AffiliationNamespace fromXmlns(String xmlns) {
for (AffiliationNamespace affiliationsNamespace : AffiliationNamespace.values()) {
if (affiliationsNamespace.type.getNamespace().getXmlns().equals(xmlns)) {
return affiliationsNamespace;
}
}
throw new IllegalArgumentException("Invalid affiliations namespace: " + xmlns);
}
}
private final BareJid jid; private final BareJid jid;
private final String node; private final String node;
private final Type affiliation; private final Type affiliation;
private final PubSubNamespace namespace; private final AffiliationNamespace namespace;
public enum Type { public enum Type {
member, none, outcast, owner, publisher member, none, outcast, owner, publisher
@ -54,14 +75,21 @@ public class Affiliation implements ExtensionElement {
* @param affiliation the optional affiliation. * @param affiliation the optional affiliation.
*/ */
public Affiliation(String node, Type affiliation) { public Affiliation(String node, Type affiliation) {
this(node, affiliation, affiliation == null ? AffiliationNamespace.basic : AffiliationNamespace.owner);
}
/**
* Constructs an affiliation.
*
* @param node The node the user is affiliated with.
* @param affiliation the optional affiliation.
* @param namespace the affiliation's namespace.
*/
public Affiliation(String node, Type affiliation, AffiliationNamespace namespace) {
this.node = StringUtils.requireNotNullOrEmpty(node, "node must not be null or empty"); this.node = StringUtils.requireNotNullOrEmpty(node, "node must not be null or empty");
this.affiliation = affiliation; this.affiliation = affiliation;
this.jid = null; this.jid = null;
if (affiliation != null) { this.namespace = Objects.requireNonNull(namespace);
namespace = PubSubNamespace.BASIC;
} else {
namespace = PubSubNamespace.OWNER;
}
} }
/** /**
@ -71,10 +99,10 @@ public class Affiliation implements ExtensionElement {
* @param affiliation * @param affiliation
*/ */
public Affiliation(BareJid jid, Type affiliation) { public Affiliation(BareJid jid, Type affiliation) {
this(jid, affiliation, PubSubNamespace.OWNER); this(jid, affiliation, AffiliationNamespace.owner);
} }
public Affiliation(BareJid jid, Type affiliation, PubSubNamespace namespace) { public Affiliation(BareJid jid, Type affiliation, AffiliationNamespace namespace) {
this.jid = jid; this.jid = jid;
this.affiliation = affiliation; this.affiliation = affiliation;
this.node = null; this.node = null;
@ -124,11 +152,11 @@ public class Affiliation implements ExtensionElement {
@Override @Override
public String getNamespace() { public String getNamespace() {
return namespace.getXmlns(); return getPubSubNamespace().getXmlns();
} }
public PubSubNamespace getPubSubNamespace() { public PubSubNamespace getPubSubNamespace() {
return namespace; return namespace.type.getNamespace();
} }
/** /**
@ -139,7 +167,7 @@ public class Affiliation implements ExtensionElement {
*/ */
public boolean isAffiliationModification() { public boolean isAffiliationModification() {
if (jid != null && affiliation != null) { if (jid != null && affiliation != null) {
assert (node == null && namespace == PubSubNamespace.OWNER); assert (node == null && namespace == AffiliationNamespace.owner);
return true; return true;
} }
return false; return false;

View File

@ -21,6 +21,8 @@ import java.util.List;
import org.jivesoftware.smack.util.XmlStringBuilder; import org.jivesoftware.smack.util.XmlStringBuilder;
import org.jivesoftware.smackx.pubsub.Affiliation.AffiliationNamespace;
/** /**
* Represents the <b>affiliations</b> element of the reply to a request for affiliations. * Represents the <b>affiliations</b> element of the reply to a request for affiliations.
* It is defined in the specification in section <a href="http://xmpp.org/extensions/xep-0060.html#entity-affiliations">5.7 Retrieve Affiliations</a> and * It is defined in the specification in section <a href="http://xmpp.org/extensions/xep-0060.html#entity-affiliations">5.7 Retrieve Affiliations</a> and
@ -33,15 +35,23 @@ public class AffiliationsExtension extends NodeExtension {
private final String node; private final String node;
public AffiliationsExtension() { public AffiliationsExtension() {
this(null, null); this(null);
} }
public AffiliationsExtension(List<Affiliation> subList) { public AffiliationsExtension(List<Affiliation> subList) {
this(subList, null); this(subList, null);
} }
public AffiliationsExtension(AffiliationNamespace affiliationsNamespace, List<Affiliation> subList) {
this(affiliationsNamespace, subList, null);
}
public AffiliationsExtension(List<Affiliation> subList, String node) { public AffiliationsExtension(List<Affiliation> subList, String node) {
super(PubSubElementType.AFFILIATIONS); this(AffiliationNamespace.basic, subList, node);
}
public AffiliationsExtension(AffiliationNamespace affiliationsNamespace, List<Affiliation> subList, String node) {
super(affiliationsNamespace.type);
items = subList; items = subList;
this.node = node; this.node = node;
} }

View File

@ -42,7 +42,7 @@ public class EventElement implements EmbeddedPacketExtension {
/** /**
* The constant String "http://jabber.org/protocol/pubsub#event". * The constant String "http://jabber.org/protocol/pubsub#event".
*/ */
public static final String NAMESPACE = PubSubNamespace.EVENT.getXmlns(); public static final String NAMESPACE = PubSubNamespace.event.getXmlns();
private final EventElementType type; private final EventElementType type;
private final NodeExtension ext; private final NodeExtension ext;
@ -72,7 +72,7 @@ public class EventElement implements EmbeddedPacketExtension {
@Override @Override
public String getNamespace() { public String getNamespace() {
return PubSubNamespace.EVENT.getXmlns(); return PubSubNamespace.event.getXmlns();
} }
@Override @Override

View File

@ -43,7 +43,7 @@ public enum FormNodeType {
} }
public static FormNodeType valueOfFromElementName(String elem, String configNamespace) { public static FormNodeType valueOfFromElementName(String elem, String configNamespace) {
if ("configure".equals(elem) && PubSubNamespace.OWNER.getXmlns().equals(configNamespace)) { if ("configure".equals(elem) && PubSubNamespace.owner.getXmlns().equals(configNamespace)) {
return CONFIGURE_OWNER; return CONFIGURE_OWNER;
} }
return valueOf(elem.toUpperCase(Locale.US)); return valueOf(elem.toUpperCase(Locale.US));

View File

@ -17,6 +17,7 @@
package org.jivesoftware.smackx.pubsub; package org.jivesoftware.smackx.pubsub;
import org.jivesoftware.smack.packet.Message; import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.util.XmlStringBuilder;
import org.jivesoftware.smackx.pubsub.provider.ItemProvider; import org.jivesoftware.smackx.pubsub.provider.ItemProvider;
@ -50,7 +51,27 @@ import org.jivesoftware.smackx.pubsub.provider.ItemProvider;
* @author Robin Collier * @author Robin Collier
*/ */
public class Item extends NodeExtension { public class Item extends NodeExtension {
private String id; public enum ItemNamespace {
pubsub(PubSubElementType.ITEM),
event(PubSubElementType.ITEM_EVENT),
;
private final PubSubElementType type;
ItemNamespace(PubSubElementType type) {
this.type = type;
}
public static ItemNamespace fromXmlns(String xmlns) {
for (ItemNamespace itemNamespace : ItemNamespace.values()) {
if (itemNamespace.type.getNamespace().getXmlns().equals(xmlns)) {
return itemNamespace;
}
}
throw new IllegalArgumentException("Invalid item namespace: " + xmlns);
}
}
private final String itemId;
/** /**
* Create an empty <tt>Item</tt> with no id. This is a valid item for nodes which are configured * Create an empty <tt>Item</tt> with no id. This is a valid item for nodes which are configured
@ -60,7 +81,7 @@ public class Item extends NodeExtension {
* method in this case. * method in this case.
*/ */
public Item() { public Item() {
super(PubSubElementType.ITEM); this(ItemNamespace.pubsub, null, null);
} }
/** /**
@ -71,9 +92,18 @@ public class Item extends NodeExtension {
* Passing null is the equivalent of calling {@link #Item()}. * Passing null is the equivalent of calling {@link #Item()}.
*/ */
public Item(String itemId) { public Item(String itemId) {
// The element type is actually irrelevant since we override getNamespace() to return null this(ItemNamespace.pubsub, itemId, null);
super(PubSubElementType.ITEM); }
id = itemId;
/**
* Create an <tt>Item</tt> with an id but no payload. This is a valid item for nodes which are configured
* so that {@link ConfigureForm#isDeliverPayloads()} is false.
*
* @param itemId The id if the item. It must be unique within the node unless overwriting and existing item.
* Passing null is the equivalent of calling {@link #Item()}.
*/
public Item(ItemNamespace itemNamespace, String itemId) {
this(itemNamespace, itemId, null);
} }
/** /**
@ -88,8 +118,23 @@ public class Item extends NodeExtension {
* @param nodeId The id of the node which the item was published to. * @param nodeId The id of the node which the item was published to.
*/ */
public Item(String itemId, String nodeId) { public Item(String itemId, String nodeId) {
super(PubSubElementType.ITEM_EVENT, nodeId); this(ItemNamespace.pubsub, itemId, nodeId);
id = itemId; }
/**
* Create an <tt>Item</tt> with an id and a node id.
* <p>
* <b>Note:</b> This is not valid for publishing an item to a node, only receiving from
* one as part of {@link Message}. If used to create an Item to publish
* (via {@link LeafNode#publish(Item)}, the server <i>may</i> return an
* error for an invalid packet.
*
* @param itemId The id of the item.
* @param nodeId The id of the node which the item was published to.
*/
public Item(ItemNamespace itemNamespace, String itemId, String nodeId) {
super(itemNamespace.type, nodeId);
this.itemId = itemId;
} }
/** /**
@ -98,36 +143,30 @@ public class Item extends NodeExtension {
* @return The id * @return The id
*/ */
public String getId() { public String getId() {
return id; return itemId;
} }
@Override @Override
public String getNamespace() { public XmlStringBuilder toXML() {
return null; XmlStringBuilder xml = getCommonXml();
xml.closeEmptyElement();
return xml;
} }
@Override protected final XmlStringBuilder getCommonXml() {
public String toXML() { XmlStringBuilder xml = new XmlStringBuilder(this);
StringBuilder builder = new StringBuilder("<item");
if (id != null) { xml.optAttribute("id", getId());
builder.append(" id='"); xml.optAttribute("node", getNode());
builder.append(id);
builder.append('\'');
}
if (getNode() != null) { return xml;
builder.append(" node='");
builder.append(getNode());
builder.append('\'');
}
builder.append("/>");
return builder.toString();
} }
@Override @Override
public String toString() { public String toString() {
return getClass().getName() + " | Content [" + toXML() + "]"; return getClass().getName() + " | Content [" + toXML() + "]";
} }
} }

View File

@ -19,6 +19,7 @@ package org.jivesoftware.smackx.pubsub;
import java.util.List; import java.util.List;
import org.jivesoftware.smack.packet.ExtensionElement; import org.jivesoftware.smack.packet.ExtensionElement;
import org.jivesoftware.smack.packet.NamedElement;
/** /**
* This class is used for multiple purposes. * This class is used for multiple purposes.
@ -37,7 +38,7 @@ import org.jivesoftware.smack.packet.ExtensionElement;
public class ItemsExtension extends NodeExtension implements EmbeddedPacketExtension { public class ItemsExtension extends NodeExtension implements EmbeddedPacketExtension {
protected ItemsElementType type; protected ItemsElementType type;
protected Boolean notify; protected Boolean notify;
protected List<? extends ExtensionElement> items; protected List<? extends NamedElement> items;
public enum ItemsElementType { public enum ItemsElementType {
/** An items element, which has an optional <b>max_items</b> attribute when requesting items. */ /** An items element, which has an optional <b>max_items</b> attribute when requesting items. */
@ -82,7 +83,7 @@ public class ItemsExtension extends NodeExtension implements EmbeddedPacketExten
* @param nodeId The node to which the items are being sent or deleted * @param nodeId The node to which the items are being sent or deleted
* @param items The list of {@link Item} or {@link RetractItem} * @param items The list of {@link Item} or {@link RetractItem}
*/ */
public ItemsExtension(ItemsElementType itemsType, String nodeId, List<? extends ExtensionElement> items) { public ItemsExtension(ItemsElementType itemsType, String nodeId, List<? extends NamedElement> items) {
super(itemsType.getNodeElement(), nodeId); super(itemsType.getNodeElement(), nodeId);
type = itemsType; type = itemsType;
this.items = items; this.items = items;
@ -134,7 +135,7 @@ public class ItemsExtension extends NodeExtension implements EmbeddedPacketExten
* *
* @return List of {@link Item}, {@link RetractItem}, or null * @return List of {@link Item}, {@link RetractItem}, or null
*/ */
public List<? extends ExtensionElement> getItems() { public List<? extends NamedElement> getItems() {
return items; return items;
} }
@ -167,7 +168,7 @@ public class ItemsExtension extends NodeExtension implements EmbeddedPacketExten
} }
else { else {
builder.append("'>"); builder.append("'>");
for (ExtensionElement item : items) { for (NamedElement item : items) {
builder.append(item.toXML()); builder.append(item.toXML());
} }
} }

View File

@ -341,7 +341,7 @@ public class LeafNode extends Node {
* @throws InterruptedException * @throws InterruptedException
*/ */
public void deleteAllItems() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { public void deleteAllItems() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
PubSub request = createPubsubPacket(Type.set, new NodeExtension(PubSubElementType.PURGE_OWNER, getId()), PubSubElementType.PURGE_OWNER.getNamespace()); PubSub request = createPubsubPacket(Type.set, new NodeExtension(PubSubElementType.PURGE_OWNER, getId()));
pubSubManager.getConnection().createStanzaCollectorAndSend(request).nextResultOrThrow(); pubSubManager.getConnection().createStanzaCollectorAndSend(request).nextResultOrThrow();
} }

View File

@ -34,6 +34,8 @@ import org.jivesoftware.smack.packet.Stanza;
import org.jivesoftware.smackx.delay.DelayInformationManager; import org.jivesoftware.smackx.delay.DelayInformationManager;
import org.jivesoftware.smackx.disco.packet.DiscoverInfo; import org.jivesoftware.smackx.disco.packet.DiscoverInfo;
import org.jivesoftware.smackx.pubsub.Affiliation.AffiliationNamespace;
import org.jivesoftware.smackx.pubsub.SubscriptionsExtension.SubscriptionsNamespace;
import org.jivesoftware.smackx.pubsub.listener.ItemDeleteListener; import org.jivesoftware.smackx.pubsub.listener.ItemDeleteListener;
import org.jivesoftware.smackx.pubsub.listener.ItemEventListener; import org.jivesoftware.smackx.pubsub.listener.ItemEventListener;
import org.jivesoftware.smackx.pubsub.listener.NodeConfigListener; import org.jivesoftware.smackx.pubsub.listener.NodeConfigListener;
@ -84,7 +86,7 @@ public abstract class Node {
*/ */
public ConfigureForm getNodeConfiguration() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { public ConfigureForm getNodeConfiguration() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
PubSub pubSub = createPubsubPacket(Type.get, new NodeExtension( PubSub pubSub = createPubsubPacket(Type.get, new NodeExtension(
PubSubElementType.CONFIGURE_OWNER, getId()), PubSubNamespace.OWNER); PubSubElementType.CONFIGURE_OWNER, getId()));
Stanza reply = sendPubsubPacket(pubSub); Stanza reply = sendPubsubPacket(pubSub);
return NodeUtils.getFormFromPacket(reply, PubSubElementType.CONFIGURE_OWNER); return NodeUtils.getFormFromPacket(reply, PubSubElementType.CONFIGURE_OWNER);
} }
@ -100,7 +102,7 @@ public abstract class Node {
*/ */
public void sendConfigurationForm(Form submitForm) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { public void sendConfigurationForm(Form submitForm) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
PubSub packet = createPubsubPacket(Type.set, new FormNode(FormNodeType.CONFIGURE_OWNER, PubSub packet = createPubsubPacket(Type.set, new FormNode(FormNodeType.CONFIGURE_OWNER,
getId(), submitForm), PubSubNamespace.OWNER); getId(), submitForm));
pubSubManager.getConnection().createStanzaCollectorAndSend(packet).nextResultOrThrow(); pubSubManager.getConnection().createStanzaCollectorAndSend(packet).nextResultOrThrow();
} }
@ -152,7 +154,7 @@ public abstract class Node {
*/ */
public List<Subscription> getSubscriptions(List<ExtensionElement> additionalExtensions, Collection<ExtensionElement> returnedExtensions) public List<Subscription> getSubscriptions(List<ExtensionElement> additionalExtensions, Collection<ExtensionElement> returnedExtensions)
throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
return getSubscriptions(additionalExtensions, returnedExtensions, null); return getSubscriptions(SubscriptionsNamespace.basic, additionalExtensions, returnedExtensions);
} }
/** /**
@ -197,13 +199,15 @@ public abstract class Node {
public List<Subscription> getSubscriptionsAsOwner(List<ExtensionElement> additionalExtensions, public List<Subscription> getSubscriptionsAsOwner(List<ExtensionElement> additionalExtensions,
Collection<ExtensionElement> returnedExtensions) throws NoResponseException, XMPPErrorException, Collection<ExtensionElement> returnedExtensions) throws NoResponseException, XMPPErrorException,
NotConnectedException, InterruptedException { NotConnectedException, InterruptedException {
return getSubscriptions(additionalExtensions, returnedExtensions, PubSubNamespace.OWNER); return getSubscriptions(SubscriptionsNamespace.owner, additionalExtensions, returnedExtensions);
} }
private List<Subscription> getSubscriptions(List<ExtensionElement> additionalExtensions, private List<Subscription> getSubscriptions(SubscriptionsNamespace subscriptionsNamespace, List<ExtensionElement> additionalExtensions,
Collection<ExtensionElement> returnedExtensions, PubSubNamespace pubSubNamespace) Collection<ExtensionElement> returnedExtensions)
throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
PubSub pubSub = createPubsubPacket(Type.get, new NodeExtension(PubSubElementType.SUBSCRIPTIONS, getId()), pubSubNamespace); PubSubElementType pubSubElementType = subscriptionsNamespace.type;
PubSub pubSub = createPubsubPacket(Type.get, new NodeExtension(pubSubElementType, getId()));
if (additionalExtensions != null) { if (additionalExtensions != null) {
for (ExtensionElement pe : additionalExtensions) { for (ExtensionElement pe : additionalExtensions) {
pubSub.addExtension(pe); pubSub.addExtension(pe);
@ -213,7 +217,7 @@ public abstract class Node {
if (returnedExtensions != null) { if (returnedExtensions != null) {
returnedExtensions.addAll(reply.getExtensions()); returnedExtensions.addAll(reply.getExtensions());
} }
SubscriptionsExtension subElem = reply.getExtension(PubSubElementType.SUBSCRIPTIONS); SubscriptionsExtension subElem = reply.getExtension(pubSubElementType);
return subElem.getSubscriptions(); return subElem.getSubscriptions();
} }
@ -237,8 +241,7 @@ public abstract class Node {
throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
PubSub pubSub = createPubsubPacket(Type.set, PubSub pubSub = createPubsubPacket(Type.set,
new SubscriptionsExtension(getId(), changedSubs), new SubscriptionsExtension(SubscriptionsNamespace.owner, getId(), changedSubs));
PubSubNamespace.OWNER);
return sendPubsubPacket(pubSub); return sendPubsubPacket(pubSub);
} }
@ -275,7 +278,7 @@ public abstract class Node {
public List<Affiliation> getAffiliations(List<ExtensionElement> additionalExtensions, Collection<ExtensionElement> returnedExtensions) public List<Affiliation> getAffiliations(List<ExtensionElement> additionalExtensions, Collection<ExtensionElement> returnedExtensions)
throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
return getAffiliations(PubSubNamespace.BASIC, additionalExtensions, returnedExtensions); return getAffiliations(AffiliationNamespace.basic, additionalExtensions, returnedExtensions);
} }
/** /**
@ -315,14 +318,15 @@ public abstract class Node {
public List<Affiliation> getAffiliationsAsOwner(List<ExtensionElement> additionalExtensions, Collection<ExtensionElement> returnedExtensions) public List<Affiliation> getAffiliationsAsOwner(List<ExtensionElement> additionalExtensions, Collection<ExtensionElement> returnedExtensions)
throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
return getAffiliations(PubSubNamespace.OWNER, additionalExtensions, returnedExtensions); return getAffiliations(AffiliationNamespace.owner, additionalExtensions, returnedExtensions);
} }
private List<Affiliation> getAffiliations(PubSubNamespace namespace, List<ExtensionElement> additionalExtensions, private List<Affiliation> getAffiliations(AffiliationNamespace affiliationsNamespace, List<ExtensionElement> additionalExtensions,
Collection<ExtensionElement> returnedExtensions) throws NoResponseException, XMPPErrorException, Collection<ExtensionElement> returnedExtensions) throws NoResponseException, XMPPErrorException,
NotConnectedException, InterruptedException { NotConnectedException, InterruptedException {
PubSubElementType pubSubElementType = affiliationsNamespace.type;
PubSub pubSub = createPubsubPacket(Type.get, new NodeExtension(PubSubElementType.AFFILIATIONS, getId()), namespace); PubSub pubSub = createPubsubPacket(Type.get, new NodeExtension(pubSubElementType, getId()));
if (additionalExtensions != null) { if (additionalExtensions != null) {
for (ExtensionElement pe : additionalExtensions) { for (ExtensionElement pe : additionalExtensions) {
pubSub.addExtension(pe); pubSub.addExtension(pe);
@ -332,7 +336,7 @@ public abstract class Node {
if (returnedExtensions != null) { if (returnedExtensions != null) {
returnedExtensions.addAll(reply.getExtensions()); returnedExtensions.addAll(reply.getExtensions());
} }
AffiliationsExtension affilElem = reply.getExtension(PubSubElementType.AFFILIATIONS); AffiliationsExtension affilElem = reply.getExtension(pubSubElementType);
return affilElem.getAffiliations(); return affilElem.getAffiliations();
} }
@ -355,13 +359,12 @@ public abstract class Node {
public PubSub modifyAffiliationAsOwner(List<Affiliation> affiliations) throws NoResponseException, public PubSub modifyAffiliationAsOwner(List<Affiliation> affiliations) throws NoResponseException,
XMPPErrorException, NotConnectedException, InterruptedException { XMPPErrorException, NotConnectedException, InterruptedException {
for (Affiliation affiliation : affiliations) { for (Affiliation affiliation : affiliations) {
if (affiliation.getPubSubNamespace() != PubSubNamespace.OWNER) { if (affiliation.getPubSubNamespace() != PubSubNamespace.owner) {
throw new IllegalArgumentException("Must use Affiliation(BareJid, Type) affiliations"); throw new IllegalArgumentException("Must use Affiliation(BareJid, Type) affiliations");
} }
} }
PubSub pubSub = createPubsubPacket(Type.set, new AffiliationsExtension(affiliations, getId()), PubSub pubSub = createPubsubPacket(Type.set, new AffiliationsExtension(AffiliationNamespace.owner, affiliations, getId()));
PubSubNamespace.OWNER);
return sendPubsubPacket(pubSub); return sendPubsubPacket(pubSub);
} }
@ -567,12 +570,8 @@ public abstract class Node {
return super.toString() + " " + getClass().getName() + " id: " + id; return super.toString() + " " + getClass().getName() + " id: " + id;
} }
protected PubSub createPubsubPacket(Type type, ExtensionElement ext) { protected PubSub createPubsubPacket(Type type, NodeExtension ext) {
return createPubsubPacket(type, ext, null); return PubSub.createPubsubPacket(pubSubManager.getServiceJid(), type, ext);
}
protected PubSub createPubsubPacket(Type type, ExtensionElement ext, PubSubNamespace ns) {
return PubSub.createPubsubPacket(pubSubManager.getServiceJid(), type, ext, ns);
} }
protected PubSub sendPubsubPacket(PubSub packet) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { protected PubSub sendPubsubPacket(PubSub packet) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
@ -611,7 +610,7 @@ public abstract class Node {
@Override @Override
@SuppressWarnings({ "rawtypes", "unchecked" }) @SuppressWarnings({ "rawtypes", "unchecked" })
public void processStanza(Stanza packet) { public void processStanza(Stanza packet) {
EventElement event = packet.getExtension("event", PubSubNamespace.EVENT.getXmlns()); EventElement event = packet.getExtension("event", PubSubNamespace.event.getXmlns());
ItemsExtension itemsElem = (ItemsExtension) event.getEvent(); ItemsExtension itemsElem = (ItemsExtension) event.getEvent();
ItemPublishEvent eventItems = new ItemPublishEvent(itemsElem.getNode(), itemsElem.getItems(), getSubscriptionIds(packet), DelayInformationManager.getDelayTimestamp(packet)); ItemPublishEvent eventItems = new ItemPublishEvent(itemsElem.getNode(), itemsElem.getItems(), getSubscriptionIds(packet), DelayInformationManager.getDelayTimestamp(packet));
// TODO: Use AsyncButOrdered (with Node as Key?) // TODO: Use AsyncButOrdered (with Node as Key?)
@ -635,7 +634,7 @@ public abstract class Node {
@Override @Override
public void processStanza(Stanza packet) { public void processStanza(Stanza packet) {
// CHECKSTYLE:OFF // CHECKSTYLE:OFF
EventElement event = packet.getExtension("event", PubSubNamespace.EVENT.getXmlns()); EventElement event = packet.getExtension("event", PubSubNamespace.event.getXmlns());
List<ExtensionElement> extList = event.getExtensions(); List<ExtensionElement> extList = event.getExtensions();
@ -674,7 +673,7 @@ public abstract class Node {
@Override @Override
public void processStanza(Stanza packet) { public void processStanza(Stanza packet) {
EventElement event = packet.getExtension("event", PubSubNamespace.EVENT.getXmlns()); EventElement event = packet.getExtension("event", PubSubNamespace.event.getXmlns());
ConfigurationEvent config = (ConfigurationEvent) event.getEvent(); ConfigurationEvent config = (ConfigurationEvent) event.getEvent();
// TODO: Use AsyncButOrdered (with Node as Key?) // TODO: Use AsyncButOrdered (with Node as Key?)

View File

@ -18,6 +18,8 @@ package org.jivesoftware.smackx.pubsub;
import org.jivesoftware.smack.packet.ExtensionElement; import org.jivesoftware.smack.packet.ExtensionElement;
import org.jivesoftware.smackx.pubsub.packet.PubSubNamespace;
/** /**
* A class which represents a common element within the pubsub defined * A class which represents a common element within the pubsub defined
* schemas. One which has a <b>node</b> as an attribute. This class is * schemas. One which has a <b>node</b> as an attribute. This class is
@ -66,9 +68,13 @@ public class NodeExtension implements ExtensionElement {
return element.getElementName(); return element.getElementName();
} }
public PubSubNamespace getPubSubNamespace() {
return element.getNamespace();
}
@Override @Override
public String getNamespace() { public final String getNamespace() {
return element.getNamespace().getXmlns(); return getPubSubNamespace().getXmlns();
} }
@Override @Override

View File

@ -18,6 +18,7 @@ package org.jivesoftware.smackx.pubsub;
import org.jivesoftware.smack.packet.ExtensionElement; import org.jivesoftware.smack.packet.ExtensionElement;
import org.jivesoftware.smack.packet.Message; import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.util.XmlStringBuilder;
import org.jivesoftware.smackx.pubsub.provider.ItemProvider; import org.jivesoftware.smackx.pubsub.provider.ItemProvider;
@ -93,7 +94,25 @@ public class PayloadItem<E extends ExtensionElement> extends Item {
* @param payloadExt A {@link ExtensionElement} which represents the payload data. * @param payloadExt A {@link ExtensionElement} which represents the payload data.
*/ */
public PayloadItem(String itemId, String nodeId, E payloadExt) { public PayloadItem(String itemId, String nodeId, E payloadExt) {
super(itemId, nodeId); this(ItemNamespace.pubsub, itemId, nodeId, payloadExt);
}
/**
* Create an <tt>Item</tt> with an id, node id and payload.
*
* <p>
* <b>Note:</b> This is not valid for publishing an item to a node, only receiving from
* one as part of {@link Message}. If used to create an Item to publish
* (via {@link LeafNode#publish(Item)}, the server <i>may</i> return an
* error for an invalid packet.
* </p>
*
* @param itemId The id of this item.
* @param nodeId The id of the node the item was published to.
* @param payloadExt A {@link ExtensionElement} which represents the payload data.
*/
public PayloadItem(ItemNamespace itemNamespace, String itemId, String nodeId, E payloadExt) {
super(itemNamespace, itemId, nodeId);
if (payloadExt == null) if (payloadExt == null)
throw new IllegalArgumentException("payload cannot be 'null'"); throw new IllegalArgumentException("payload cannot be 'null'");
@ -111,25 +130,14 @@ public class PayloadItem<E extends ExtensionElement> extends Item {
} }
@Override @Override
public String toXML() { public XmlStringBuilder toXML() {
StringBuilder builder = new StringBuilder("<item"); XmlStringBuilder xml = getCommonXml();
if (getId() != null) { xml.rightAngleBracket();
builder.append(" id='"); xml.append(payload.toXML());
builder.append(getId()); xml.closeElement(this);
builder.append('\'');
}
if (getNode() != null) { return xml;
builder.append(" node='");
builder.append(getNode());
builder.append('\'');
}
builder.append('>');
builder.append(payload.toXML());
builder.append("</item>");
return builder.toString();
} }
@Override @Override

View File

@ -27,28 +27,30 @@ import org.jivesoftware.smackx.pubsub.packet.PubSubNamespace;
* @author Robin Collier * @author Robin Collier
*/ */
public enum PubSubElementType { public enum PubSubElementType {
CREATE("create", PubSubNamespace.BASIC), CREATE("create", PubSubNamespace.basic),
DELETE("delete", PubSubNamespace.OWNER), DELETE("delete", PubSubNamespace.owner),
DELETE_EVENT("delete", PubSubNamespace.EVENT), DELETE_EVENT("delete", PubSubNamespace.event),
CONFIGURE("configure", PubSubNamespace.BASIC), CONFIGURE("configure", PubSubNamespace.basic),
CONFIGURE_OWNER("configure", PubSubNamespace.OWNER), CONFIGURE_OWNER("configure", PubSubNamespace.owner),
CONFIGURATION("configuration", PubSubNamespace.EVENT), CONFIGURATION("configuration", PubSubNamespace.event),
OPTIONS("options", PubSubNamespace.BASIC), OPTIONS("options", PubSubNamespace.basic),
DEFAULT("default", PubSubNamespace.OWNER), DEFAULT("default", PubSubNamespace.owner),
ITEMS("items", PubSubNamespace.BASIC), ITEMS("items", PubSubNamespace.basic),
ITEMS_EVENT("items", PubSubNamespace.EVENT), ITEMS_EVENT("items", PubSubNamespace.event),
ITEM("item", PubSubNamespace.BASIC), ITEM("item", PubSubNamespace.basic),
ITEM_EVENT("item", PubSubNamespace.EVENT), ITEM_EVENT("item", PubSubNamespace.event),
PUBLISH("publish", PubSubNamespace.BASIC), PUBLISH("publish", PubSubNamespace.basic),
PUBLISH_OPTIONS("publish-options", PubSubNamespace.BASIC), PUBLISH_OPTIONS("publish-options", PubSubNamespace.basic),
PURGE_OWNER("purge", PubSubNamespace.OWNER), PURGE_OWNER("purge", PubSubNamespace.owner),
PURGE_EVENT("purge", PubSubNamespace.EVENT), PURGE_EVENT("purge", PubSubNamespace.event),
RETRACT("retract", PubSubNamespace.BASIC), RETRACT("retract", PubSubNamespace.basic),
AFFILIATIONS("affiliations", PubSubNamespace.BASIC), AFFILIATIONS("affiliations", PubSubNamespace.basic),
SUBSCRIBE("subscribe", PubSubNamespace.BASIC), AFFILIATIONS_OWNER("affiliations", PubSubNamespace.owner),
SUBSCRIPTION("subscription", PubSubNamespace.BASIC), SUBSCRIBE("subscribe", PubSubNamespace.basic),
SUBSCRIPTIONS("subscriptions", PubSubNamespace.BASIC), SUBSCRIPTION("subscription", PubSubNamespace.basic),
UNSUBSCRIBE("unsubscribe", PubSubNamespace.BASIC); SUBSCRIPTIONS("subscriptions", PubSubNamespace.basic),
SUBSCRIPTIONS_OWNER("subscriptions", PubSubNamespace.owner),
UNSUBSCRIBE("unsubscribe", PubSubNamespace.basic);
private final String eName; private final String eName;
private final PubSubNamespace nSpace; private final PubSubNamespace nSpace;

View File

@ -157,7 +157,7 @@ public final class PubSubManager extends Manager {
*/ */
public LeafNode createNode() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { public LeafNode createNode() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
PubSub reply = sendPubsubPacket(Type.set, new NodeExtension(PubSubElementType.CREATE), null); PubSub reply = sendPubsubPacket(Type.set, new NodeExtension(PubSubElementType.CREATE), null);
NodeExtension elem = reply.getExtension("create", PubSubNamespace.BASIC.getXmlns()); NodeExtension elem = reply.getExtension("create", PubSubNamespace.basic.getXmlns());
LeafNode newNode = new LeafNode(this, elem.getNode()); LeafNode newNode = new LeafNode(this, elem.getNode());
nodeMap.put(newNode.getId(), newNode); nodeMap.put(newNode.getId(), newNode);
@ -195,7 +195,7 @@ public final class PubSubManager extends Manager {
* @throws InterruptedException * @throws InterruptedException
*/ */
public Node createNode(String nodeId, Form config) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { public Node createNode(String nodeId, Form config) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
PubSub request = PubSub.createPubsubPacket(pubSubService, Type.set, new NodeExtension(PubSubElementType.CREATE, nodeId), null); PubSub request = PubSub.createPubsubPacket(pubSubService, Type.set, new NodeExtension(PubSubElementType.CREATE, nodeId));
boolean isLeafNode = true; boolean isLeafNode = true;
if (config != null) { if (config != null) {

View File

@ -50,7 +50,7 @@ public class RetractItem implements ExtensionElement {
@Override @Override
public String getNamespace() { public String getNamespace() {
return PubSubNamespace.EVENT.getXmlns(); return PubSubNamespace.event.getXmlns();
} }
@Override @Override

View File

@ -25,6 +25,26 @@ import java.util.List;
* @author Robin Collier * @author Robin Collier
*/ */
public class SubscriptionsExtension extends NodeExtension { public class SubscriptionsExtension extends NodeExtension {
public enum SubscriptionsNamespace {
basic(PubSubElementType.SUBSCRIPTIONS),
owner(PubSubElementType.SUBSCRIPTIONS_OWNER),
;
public final PubSubElementType type;
SubscriptionsNamespace(PubSubElementType type) {
this.type = type;
}
public static SubscriptionsNamespace fromXmlns(String xmlns) {
for (SubscriptionsNamespace subscriptionsNamespace : SubscriptionsNamespace.values()) {
if (subscriptionsNamespace.type.getNamespace().getXmlns().equals(xmlns)) {
return subscriptionsNamespace;
}
}
throw new IllegalArgumentException("Invalid Subscription namespace: " + xmlns);
}
}
protected List<Subscription> items = Collections.emptyList(); protected List<Subscription> items = Collections.emptyList();
/** /**
@ -33,10 +53,7 @@ public class SubscriptionsExtension extends NodeExtension {
* @param subList The list of subscriptions * @param subList The list of subscriptions
*/ */
public SubscriptionsExtension(List<Subscription> subList) { public SubscriptionsExtension(List<Subscription> subList) {
super(PubSubElementType.SUBSCRIPTIONS); this(SubscriptionsNamespace.basic, null, subList);
if (subList != null)
items = subList;
} }
/** /**
@ -46,7 +63,19 @@ public class SubscriptionsExtension extends NodeExtension {
* @param subList The list of subscriptions * @param subList The list of subscriptions
*/ */
public SubscriptionsExtension(String nodeId, List<Subscription> subList) { public SubscriptionsExtension(String nodeId, List<Subscription> subList) {
super(PubSubElementType.SUBSCRIPTIONS, nodeId); this(SubscriptionsNamespace.basic, nodeId, subList);
}
/**
* Subscriptions to the specified node.
*
* @param subscriptionsNamespace the namespace used by this element
* @param nodeId The node subscribed to
* @param subList The list of subscriptions
* @since 4.3
*/
public SubscriptionsExtension(SubscriptionsNamespace subscriptionsNamespace, String nodeId, List<Subscription> subList) {
super(subscriptionsNamespace.type, nodeId);
if (subList != null) if (subList != null)
items = subList; items = subList;

View File

@ -19,6 +19,7 @@ package org.jivesoftware.smackx.pubsub.packet;
import org.jivesoftware.smack.packet.ExtensionElement; import org.jivesoftware.smack.packet.ExtensionElement;
import org.jivesoftware.smack.packet.IQ; import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smackx.pubsub.NodeExtension;
import org.jivesoftware.smackx.pubsub.PubSubElementType; import org.jivesoftware.smackx.pubsub.PubSubElementType;
import org.jxmpp.jid.Jid; import org.jxmpp.jid.Jid;
@ -43,7 +44,7 @@ public class PubSub extends IQ {
} }
public PubSub(Jid to, Type type, PubSubNamespace ns) { public PubSub(Jid to, Type type, PubSubNamespace ns) {
super(ELEMENT, (ns == null ? PubSubNamespace.BASIC : ns).getXmlns()); super(ELEMENT, (ns == null ? PubSubNamespace.basic : ns).getXmlns());
setTo(to); setTo(to);
setType(type); setType(type);
} }
@ -78,8 +79,8 @@ public class PubSub extends IQ {
return xml; return xml;
} }
public static PubSub createPubsubPacket(Jid to, Type type, ExtensionElement extension, PubSubNamespace ns) { public static PubSub createPubsubPacket(Jid to, Type type, NodeExtension extension) {
PubSub pubSub = new PubSub(to, type, ns); PubSub pubSub = new PubSub(to, type, extension.getPubSubNamespace());
pubSub.addExtension(extension); pubSub.addExtension(extension);
return pubSub; return pubSub;
} }

View File

@ -16,8 +16,6 @@
*/ */
package org.jivesoftware.smackx.pubsub.packet; package org.jivesoftware.smackx.pubsub.packet;
import java.util.Locale;
/** /**
* Defines all the valid namespaces that are used with the {@link PubSub} packet * Defines all the valid namespaces that are used with the {@link PubSub} packet
* as defined by the specification. * as defined by the specification.
@ -25,10 +23,10 @@ import java.util.Locale;
* @author Robin Collier * @author Robin Collier
*/ */
public enum PubSubNamespace { public enum PubSubNamespace {
BASIC(null), basic(null),
ERROR("errors"), error("errors"),
EVENT("event"), event("event"),
OWNER("owner"); owner("owner");
private final String fragment; private final String fragment;
private final String fullNamespace; private final String fullNamespace;
@ -54,10 +52,17 @@ public enum PubSubNamespace {
int index = ns.lastIndexOf('#'); int index = ns.lastIndexOf('#');
if (index != -1) { if (index != -1) {
String suffix = ns.substring(ns.lastIndexOf('#') + 1); // We found an extended namespace.
return valueOf(suffix.toUpperCase(Locale.US)); if (index > ns.length()) {
throw new IllegalArgumentException(ns + " is not a valid PubSub namespace");
}
String suffix = ns.substring(index + 1);
return valueOf(suffix);
} }
else
return BASIC; if (!PubSub.NAMESPACE.equals(ns)) {
throw new IllegalArgumentException(ns + " is not a valid PubSub namespace");
}
return basic;
} }
} }

View File

@ -21,7 +21,7 @@ import org.jivesoftware.smack.provider.ExtensionElementProvider;
import org.jivesoftware.smack.util.ParserUtils; import org.jivesoftware.smack.util.ParserUtils;
import org.jivesoftware.smackx.pubsub.Affiliation; import org.jivesoftware.smackx.pubsub.Affiliation;
import org.jivesoftware.smackx.pubsub.packet.PubSubNamespace; import org.jivesoftware.smackx.pubsub.Affiliation.AffiliationNamespace;
import org.jxmpp.jid.BareJid; import org.jxmpp.jid.BareJid;
import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParser;
@ -39,6 +39,8 @@ public class AffiliationProvider extends ExtensionElementProvider<Affiliation> {
throws Exception { throws Exception {
String node = parser.getAttributeValue(null, "node"); String node = parser.getAttributeValue(null, "node");
BareJid jid = ParserUtils.getBareJidAttribute(parser); BareJid jid = ParserUtils.getBareJidAttribute(parser);
String namespaceString = parser.getNamespace();
AffiliationNamespace namespace = AffiliationNamespace.fromXmlns(namespaceString);
String affiliationString = parser.getAttributeValue(null, "affiliation"); String affiliationString = parser.getAttributeValue(null, "affiliation");
Affiliation.Type affiliationType = null; Affiliation.Type affiliationType = null;
@ -48,10 +50,9 @@ public class AffiliationProvider extends ExtensionElementProvider<Affiliation> {
Affiliation affiliation; Affiliation affiliation;
if (node != null && jid == null) { if (node != null && jid == null) {
// affiliationType may be empty // affiliationType may be empty
affiliation = new Affiliation(node, affiliationType); affiliation = new Affiliation(node, affiliationType, namespace);
} }
else if (node == null && jid != null) { else if (node == null && jid != null) {
PubSubNamespace namespace = null; // TODO
affiliation = new Affiliation(jid, affiliationType, namespace); affiliation = new Affiliation(jid, affiliationType, namespace);
} }
else { else {

View File

@ -23,6 +23,7 @@ import org.jivesoftware.smack.packet.ExtensionElement;
import org.jivesoftware.smack.provider.EmbeddedExtensionProvider; import org.jivesoftware.smack.provider.EmbeddedExtensionProvider;
import org.jivesoftware.smackx.pubsub.Affiliation; import org.jivesoftware.smackx.pubsub.Affiliation;
import org.jivesoftware.smackx.pubsub.Affiliation.AffiliationNamespace;
import org.jivesoftware.smackx.pubsub.AffiliationsExtension; import org.jivesoftware.smackx.pubsub.AffiliationsExtension;
/** /**
@ -34,7 +35,8 @@ import org.jivesoftware.smackx.pubsub.AffiliationsExtension;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Override @Override
protected AffiliationsExtension createReturnExtension(String currentElement, String currentNamespace, Map<String, String> attributeMap, List<? extends ExtensionElement> content) { protected AffiliationsExtension createReturnExtension(String currentElement, String currentNamespace, Map<String, String> attributeMap, List<? extends ExtensionElement> content) {
return new AffiliationsExtension((List<Affiliation>) content); AffiliationNamespace affiliationsNamespace = AffiliationNamespace.fromXmlns(currentNamespace);
return new AffiliationsExtension(affiliationsNamespace, (List<Affiliation>) content);
} }
} }

View File

@ -35,6 +35,7 @@ import org.jivesoftware.smackx.pubsub.NodeExtension;
public class EventProvider extends EmbeddedExtensionProvider<EventElement> { public class EventProvider extends EmbeddedExtensionProvider<EventElement> {
@Override @Override
protected EventElement createReturnExtension(String currentElement, String currentNamespace, Map<String, String> attMap, List<? extends ExtensionElement> content) { protected EventElement createReturnExtension(String currentElement, String currentNamespace, Map<String, String> attMap, List<? extends ExtensionElement> content) {
// TODO: Shouldn't be an embedded extension provider.
return new EventElement(EventElementType.valueOf(content.get(0).getElementName()), (NodeExtension) content.get(0)); return new EventElement(EventElementType.valueOf(content.get(0).getElementName()), (NodeExtension) content.get(0));
} }
} }

View File

@ -22,6 +22,7 @@ import org.jivesoftware.smack.provider.ProviderManager;
import org.jivesoftware.smack.util.PacketParserUtils; import org.jivesoftware.smack.util.PacketParserUtils;
import org.jivesoftware.smackx.pubsub.Item; import org.jivesoftware.smackx.pubsub.Item;
import org.jivesoftware.smackx.pubsub.Item.ItemNamespace;
import org.jivesoftware.smackx.pubsub.PayloadItem; import org.jivesoftware.smackx.pubsub.PayloadItem;
import org.jivesoftware.smackx.pubsub.SimplePayload; import org.jivesoftware.smackx.pubsub.SimplePayload;
import org.jivesoftware.smackx.pubsub.packet.PubSubNamespace; import org.jivesoftware.smackx.pubsub.packet.PubSubNamespace;
@ -29,8 +30,8 @@ import org.jivesoftware.smackx.pubsub.packet.PubSubNamespace;
import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParser;
/** /**
* Parses an <b>item</b> element as is defined in both the {@link PubSubNamespace#BASIC} and * Parses an <b>item</b> element as is defined in both the {@link PubSubNamespace#basic} and
* {@link PubSubNamespace#EVENT} namespaces. To parse the item contents, it will use whatever * {@link PubSubNamespace#event} namespaces. To parse the item contents, it will use whatever
* {@link ExtensionElementProvider} is registered in <b>smack.providers</b> for its element name and namespace. If no * {@link ExtensionElementProvider} is registered in <b>smack.providers</b> for its element name and namespace. If no
* provider is registered, it will return a {@link SimplePayload}. * provider is registered, it will return a {@link SimplePayload}.
* *
@ -42,11 +43,13 @@ public class ItemProvider extends ExtensionElementProvider<Item> {
throws Exception { throws Exception {
String id = parser.getAttributeValue(null, "id"); String id = parser.getAttributeValue(null, "id");
String node = parser.getAttributeValue(null, "node"); String node = parser.getAttributeValue(null, "node");
String xmlns = parser.getNamespace();
ItemNamespace itemNamespace = ItemNamespace.fromXmlns(xmlns);
int tag = parser.next(); int tag = parser.next();
if (tag == XmlPullParser.END_TAG) { if (tag == XmlPullParser.END_TAG) {
return new Item(id, node); return new Item(itemNamespace, id, node);
} }
else { else {
String payloadElemName = parser.getName(); String payloadElemName = parser.getName();
@ -54,11 +57,12 @@ public class ItemProvider extends ExtensionElementProvider<Item> {
final ExtensionElementProvider<ExtensionElement> extensionProvider = ProviderManager.getExtensionProvider(payloadElemName, payloadNS); final ExtensionElementProvider<ExtensionElement> extensionProvider = ProviderManager.getExtensionProvider(payloadElemName, payloadNS);
if (extensionProvider == null) { if (extensionProvider == null) {
// TODO: Should we use StandardExtensionElement in this case? And probably remove SimplePayload all together.
CharSequence payloadText = PacketParserUtils.parseElement(parser, true); CharSequence payloadText = PacketParserUtils.parseElement(parser, true);
return new PayloadItem<>(id, node, new SimplePayload(payloadElemName, payloadNS, payloadText)); return new PayloadItem<>(itemNamespace, id, node, new SimplePayload(payloadElemName, payloadNS, payloadText));
} }
else { else {
return new PayloadItem<>(id, node, extensionProvider.parse(parser)); return new PayloadItem<>(itemNamespace, id, node, extensionProvider.parse(parser));
} }
} }
} }

View File

@ -24,6 +24,7 @@ import org.jivesoftware.smack.provider.EmbeddedExtensionProvider;
import org.jivesoftware.smackx.pubsub.Subscription; import org.jivesoftware.smackx.pubsub.Subscription;
import org.jivesoftware.smackx.pubsub.SubscriptionsExtension; import org.jivesoftware.smackx.pubsub.SubscriptionsExtension;
import org.jivesoftware.smackx.pubsub.SubscriptionsExtension.SubscriptionsNamespace;
/** /**
* Parses the <b>subscriptions</b> element out of the PubSub IQ message from * Parses the <b>subscriptions</b> element out of the PubSub IQ message from
@ -35,7 +36,9 @@ public class SubscriptionsProvider extends EmbeddedExtensionProvider<Subscriptio
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Override @Override
protected SubscriptionsExtension createReturnExtension(String currentElement, String currentNamespace, Map<String, String> attributeMap, List<? extends ExtensionElement> content) { protected SubscriptionsExtension createReturnExtension(String currentElement, String currentNamespace, Map<String, String> attributeMap, List<? extends ExtensionElement> content) {
return new SubscriptionsExtension(attributeMap.get("node"), (List<Subscription>) content); SubscriptionsNamespace subscriptionsNamespace = SubscriptionsNamespace.fromXmlns(currentNamespace);
String nodeId = attributeMap.get("node");
return new SubscriptionsExtension(subscriptionsNamespace, nodeId, (List<Subscription>) content);
} }
} }

View File

@ -22,6 +22,7 @@ import static org.junit.Assert.assertTrue;
import org.jivesoftware.smack.ThreadedDummyConnection; import org.jivesoftware.smack.ThreadedDummyConnection;
import org.jivesoftware.smack.packet.ExtensionElement; import org.jivesoftware.smack.packet.ExtensionElement;
import org.jivesoftware.smack.packet.NamedElement;
import org.jivesoftware.smack.packet.Stanza; import org.jivesoftware.smack.packet.Stanza;
import org.jivesoftware.smack.util.PacketParserUtils; import org.jivesoftware.smack.util.PacketParserUtils;
@ -60,16 +61,16 @@ public class ItemValidationTest extends InitExtensions {
@Test @Test
public void verifyBasicItem() throws Exception { public void verifyBasicItem() throws Exception {
Item simpleItem = new Item(); Item simpleItem = new Item();
String simpleCtrl = "<item />"; String simpleCtrl = "<item xmlns='http://jabber.org/protocol/pubsub' />";
assertXMLEqual(simpleCtrl, simpleItem.toXML()); assertXMLEqual(simpleCtrl, simpleItem.toXML().toString());
Item idItem = new Item("uniqueid"); Item idItem = new Item("uniqueid");
String idCtrl = "<item id='uniqueid'/>"; String idCtrl = "<item xmlns='http://jabber.org/protocol/pubsub' id='uniqueid'/>";
assertXMLEqual(idCtrl, idItem.toXML()); assertXMLEqual(idCtrl, idItem.toXML().toString());
Item itemWithNodeId = new Item("testId", "testNode"); Item itemWithNodeId = new Item("testId", "testNode");
String nodeIdCtrl = "<item id='testId' node='testNode' />"; String nodeIdCtrl = "<item xmlns='http://jabber.org/protocol/pubsub' id='testId' node='testNode' />";
assertXMLEqual(nodeIdCtrl, itemWithNodeId.toXML()); assertXMLEqual(nodeIdCtrl, itemWithNodeId.toXML().toString());
} }
@Test @Test
@ -77,16 +78,16 @@ public class ItemValidationTest extends InitExtensions {
SimplePayload payload = new SimplePayload(null, null, "<data>This is the payload</data>"); SimplePayload payload = new SimplePayload(null, null, "<data>This is the payload</data>");
PayloadItem<SimplePayload> simpleItem = new PayloadItem<>(payload); PayloadItem<SimplePayload> simpleItem = new PayloadItem<>(payload);
String simpleCtrl = "<item>" + payload.toXML() + "</item>"; String simpleCtrl = "<item xmlns='http://jabber.org/protocol/pubsub'>" + payload.toXML() + "</item>";
assertXMLEqual(simpleCtrl, simpleItem.toXML()); assertXMLEqual(simpleCtrl, simpleItem.toXML().toString());
PayloadItem<SimplePayload> idItem = new PayloadItem<>("uniqueid", payload); PayloadItem<SimplePayload> idItem = new PayloadItem<>("uniqueid", payload);
String idCtrl = "<item id='uniqueid'>" + payload.toXML() + "</item>"; String idCtrl = "<item xmlns='http://jabber.org/protocol/pubsub' id='uniqueid'>" + payload.toXML() + "</item>";
assertXMLEqual(idCtrl, idItem.toXML()); assertXMLEqual(idCtrl, idItem.toXML().toString());
PayloadItem<SimplePayload> itemWithNodeId = new PayloadItem<>("testId", "testNode", payload); PayloadItem<SimplePayload> itemWithNodeId = new PayloadItem<>("testId", "testNode", payload);
String nodeIdCtrl = "<item id='testId' node='testNode'>" + payload.toXML() + "</item>"; String nodeIdCtrl = "<item xmlns='http://jabber.org/protocol/pubsub' id='testId' node='testNode'>" + payload.toXML() + "</item>";
assertXMLEqual(nodeIdCtrl, itemWithNodeId.toXML()); assertXMLEqual(nodeIdCtrl, itemWithNodeId.toXML().toString());
} }
@Test @Test
@ -101,7 +102,7 @@ public class ItemValidationTest extends InitExtensions {
"</message>"); "</message>");
Stanza message = PacketParserUtils.parseMessage(parser); Stanza message = PacketParserUtils.parseMessage(parser);
ExtensionElement eventExt = message.getExtension(PubSubNamespace.EVENT.getXmlns()); ExtensionElement eventExt = message.getExtension(PubSubNamespace.event.getXmlns());
assertTrue(eventExt instanceof EventElement); assertTrue(eventExt instanceof EventElement);
EventElement event = (EventElement) eventExt; EventElement event = (EventElement) eventExt;
@ -110,7 +111,7 @@ public class ItemValidationTest extends InitExtensions {
assertTrue(event.getExtensions().get(0) instanceof ItemsExtension); assertTrue(event.getExtensions().get(0) instanceof ItemsExtension);
assertEquals(1, ((ItemsExtension) event.getExtensions().get(0)).items.size()); assertEquals(1, ((ItemsExtension) event.getExtensions().get(0)).items.size());
ExtensionElement itemExt = ((ItemsExtension) event.getExtensions().get(0)).items.get(0); NamedElement itemExt = ((ItemsExtension) event.getExtensions().get(0)).items.get(0);
assertTrue(itemExt instanceof Item); assertTrue(itemExt instanceof Item);
assertEquals("testid1", ((Item) itemExt).getId()); assertEquals("testid1", ((Item) itemExt).getId());
} }
@ -131,9 +132,9 @@ public class ItemValidationTest extends InitExtensions {
"</message>"); "</message>");
Stanza message = PacketParserUtils.parseMessage(parser); Stanza message = PacketParserUtils.parseMessage(parser);
ExtensionElement eventExt = message.getExtension(PubSubNamespace.EVENT.getXmlns()); ExtensionElement eventExt = message.getExtension(PubSubNamespace.event.getXmlns());
EventElement event = (EventElement) eventExt; EventElement event = (EventElement) eventExt;
ExtensionElement itemExt = ((ItemsExtension) event.getExtensions().get(0)).items.get(0); NamedElement itemExt = ((ItemsExtension) event.getExtensions().get(0)).items.get(0);
assertTrue(itemExt instanceof PayloadItem<?>); assertTrue(itemExt instanceof PayloadItem<?>);
PayloadItem<?> item = (PayloadItem<?>) itemExt; PayloadItem<?> item = (PayloadItem<?>) itemExt;
@ -177,9 +178,9 @@ public class ItemValidationTest extends InitExtensions {
"</message>"); "</message>");
Stanza message = PacketParserUtils.parseMessage(parser); Stanza message = PacketParserUtils.parseMessage(parser);
ExtensionElement eventExt = message.getExtension(PubSubNamespace.EVENT.getXmlns()); ExtensionElement eventExt = message.getExtension(PubSubNamespace.event.getXmlns());
EventElement event = (EventElement) eventExt; EventElement event = (EventElement) eventExt;
ExtensionElement itemExt = ((ItemsExtension) event.getExtensions().get(0)).items.get(0); NamedElement itemExt = ((ItemsExtension) event.getExtensions().get(0)).items.get(0);
assertTrue(itemExt instanceof PayloadItem<?>); assertTrue(itemExt instanceof PayloadItem<?>);
PayloadItem<?> item = (PayloadItem<?>) itemExt; PayloadItem<?> item = (PayloadItem<?>) itemExt;
@ -209,7 +210,7 @@ public class ItemValidationTest extends InitExtensions {
"</message>"); "</message>");
Stanza message = PacketParserUtils.parseMessage(parser); Stanza message = PacketParserUtils.parseMessage(parser);
ExtensionElement eventExt = message.getExtension(PubSubNamespace.EVENT.getXmlns()); ExtensionElement eventExt = message.getExtension(PubSubNamespace.event.getXmlns());
assertTrue(eventExt instanceof EventElement); assertTrue(eventExt instanceof EventElement);
EventElement event = (EventElement) eventExt; EventElement event = (EventElement) eventExt;
@ -218,7 +219,7 @@ public class ItemValidationTest extends InitExtensions {
assertTrue(event.getExtensions().get(0) instanceof ItemsExtension); assertTrue(event.getExtensions().get(0) instanceof ItemsExtension);
assertEquals(1, ((ItemsExtension) event.getExtensions().get(0)).items.size()); assertEquals(1, ((ItemsExtension) event.getExtensions().get(0)).items.size());
ExtensionElement itemExt = ((ItemsExtension) event.getExtensions().get(0)).items.get(0); NamedElement itemExt = ((ItemsExtension) event.getExtensions().get(0)).items.get(0);
assertTrue(itemExt instanceof PayloadItem<?>); assertTrue(itemExt instanceof PayloadItem<?>);
PayloadItem<?> item = (PayloadItem<?>) itemExt; PayloadItem<?> item = (PayloadItem<?>) itemExt;

View File

@ -1,6 +1,6 @@
/** /**
* *
* Copyright 2018 Timothy Pitt * Copyright 2018 Timothy Pitt, Florian Schmaus
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -24,17 +24,25 @@ import java.util.List;
import org.jivesoftware.smack.SmackException; import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.ThreadedDummyConnection; import org.jivesoftware.smack.ThreadedDummyConnection;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException; import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.packet.IQ.Type;
import org.jivesoftware.smack.test.util.SmackTestSuite;
import org.jivesoftware.smack.test.util.TestUtils; import org.jivesoftware.smack.test.util.TestUtils;
import org.jivesoftware.smack.util.PacketParserUtils; import org.jivesoftware.smack.util.PacketParserUtils;
import org.jivesoftware.smackx.pubsub.packet.PubSub;
import org.jivesoftware.smackx.pubsub.Affiliation.AffiliationNamespace;
import org.jivesoftware.smackx.pubsub.packet.PubSub;
import org.jivesoftware.smackx.pubsub.packet.PubSubNamespace;
import org.jivesoftware.util.ConnectionUtils;
import org.jivesoftware.util.Protocol;
import org.junit.Test; import org.junit.Test;
import org.jxmpp.jid.JidTestUtil; import org.jxmpp.jid.JidTestUtil;
import org.jxmpp.jid.impl.JidCreate; import org.jxmpp.jid.impl.JidCreate;
import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParser;
public class PubSubNodeTest { public class PubSubNodeTest extends SmackTestSuite {
@Test @Test
public void modifySubscriptionsAsOwnerTest() throws InterruptedException, SmackException, IOException, XMPPException, Exception { public void modifySubscriptionsAsOwnerTest() throws InterruptedException, SmackException, IOException, XMPPException, Exception {
@ -55,7 +63,7 @@ public class PubSubNodeTest {
XmlPullParser parser = TestUtils.getIQParser(request.toXML().toString()); XmlPullParser parser = TestUtils.getIQParser(request.toXML().toString());
PubSub pubsubResult = (PubSub) PacketParserUtils.parseIQ(parser); PubSub pubsubResult = (PubSub) PacketParserUtils.parseIQ(parser);
SubscriptionsExtension subElem = pubsubResult.getExtension(PubSubElementType.SUBSCRIPTIONS); SubscriptionsExtension subElem = pubsubResult.getExtension(PubSubElementType.SUBSCRIPTIONS_OWNER);
List<Subscription> subscriptions = subElem.getSubscriptions(); List<Subscription> subscriptions = subElem.getSubscriptions();
assertEquals(2, subscriptions.size()); assertEquals(2, subscriptions.size());
@ -67,4 +75,36 @@ public class PubSubNodeTest {
assertEquals("juliet@capulet.org", sub2.getJid().toString()); assertEquals("juliet@capulet.org", sub2.getJid().toString());
assertEquals(Subscription.State.none, sub2.getState()); assertEquals(Subscription.State.none, sub2.getState());
} }
@Test
public void getAffiliationsAsOwnerTest() throws InterruptedException, SmackException, IOException, XMPPException, Exception {
Protocol protocol = new Protocol();
XMPPConnection connection = ConnectionUtils.createMockedConnection(protocol, JidTestUtil.FULL_JID_1_RESOURCE_1);
PubSubManager mgr = new PubSubManager(connection, JidTestUtil.PUBSUB_EXAMPLE_ORG);
Node testNode = new LeafNode(mgr, "princely_musings");
List<Affiliation> affiliations = Arrays.asList(
new Affiliation(JidTestUtil.BARE_JID_1, Affiliation.Type.member),
new Affiliation(JidTestUtil.BARE_JID_2, Affiliation.Type.publisher)
);
AffiliationsExtension affiliationsExtension = new AffiliationsExtension(AffiliationNamespace.owner, affiliations);
PubSub response = new PubSub(JidTestUtil.PUBSUB_EXAMPLE_ORG, Type.result, PubSubNamespace.owner);
response.addExtension(affiliationsExtension);
protocol.addResponse(response);
List<Affiliation> returnedAffiliations = testNode.getAffiliationsAsOwner();
PubSub request = (PubSub) protocol.getRequests().get(0);
assertEquals("http://jabber.org/protocol/pubsub#owner", request.getChildElementNamespace());
assertEquals("pubsub", request.getChildElementName());
Affiliation affiliationOne = returnedAffiliations.get(0);
assertEquals(affiliationOne.getJid(), JidTestUtil.BARE_JID_1);
assertEquals(affiliationOne.getAffiliation(), Affiliation.Type.member);
Affiliation affiliationTwo = returnedAffiliations.get(1);
assertEquals(affiliationTwo.getJid(), JidTestUtil.BARE_JID_2);
assertEquals(affiliationTwo.getAffiliation(), Affiliation.Type.publisher);
}
} }

View File

@ -50,7 +50,7 @@ public class PubSubProviderTest {
// @formatter:on // @formatter:on
XmlPullParser parser = TestUtils.getIQParser(resultStanza); XmlPullParser parser = TestUtils.getIQParser(resultStanza);
PubSub pubsubResult = (PubSub) PacketParserUtils.parseIQ(parser); PubSub pubsubResult = (PubSub) PacketParserUtils.parseIQ(parser);
SubscriptionsExtension subElem = pubsubResult.getExtension(PubSubElementType.SUBSCRIPTIONS); SubscriptionsExtension subElem = pubsubResult.getExtension(PubSubElementType.SUBSCRIPTIONS_OWNER);
List<Subscription> subscriptions = subElem.getSubscriptions(); List<Subscription> subscriptions = subElem.getSubscriptions();
assertEquals(2, subscriptions.size()); assertEquals(2, subscriptions.size());

View File

@ -39,6 +39,7 @@ import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException; import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.packet.ExtensionElement; import org.jivesoftware.smack.packet.ExtensionElement;
import org.jivesoftware.smack.packet.Message; import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.NamedElement;
import org.jivesoftware.smack.packet.Stanza; import org.jivesoftware.smack.packet.Stanza;
import org.jivesoftware.smack.util.Async; import org.jivesoftware.smack.util.Async;
import org.jivesoftware.smackx.carbons.CarbonManager; import org.jivesoftware.smackx.carbons.CarbonManager;
@ -776,7 +777,7 @@ public final class OmemoManager extends Manager {
continue; continue;
} }
for (ExtensionElement item : ((ItemsExtension) items).getItems()) { for (NamedElement item : ((ItemsExtension) items).getItems()) {
if (!(item instanceof PayloadItem<?>)) { if (!(item instanceof PayloadItem<?>)) {
continue; continue;
} }