1
0
Fork 0
mirror of https://github.com/vanitasvitae/Smack.git synced 2024-11-26 05:52:06 +01:00

Improve PubSub API

Use Manager pattern for PubSubManager.

Also improve the API of ServiceDiscoverManager.
This commit is contained in:
Florian Schmaus 2015-05-12 17:56:06 +02:00
parent 9e351f0535
commit 001e824fb9
16 changed files with 368 additions and 140 deletions

View file

@ -53,7 +53,7 @@ Create a node with default configuration and then configure it:
``` ```
// Create a pubsub manager using an existing XMPPConnection // Create a pubsub manager using an existing XMPPConnection
PubSubManager mgr = new PubSubManager(con); PubSubManager mgr = PubSubManager.getInstanceFor(con);
// Create the node // Create the node
LeafNode leaf = mgr.createNode("testNode"); LeafNode leaf = mgr.createNode("testNode");
@ -71,7 +71,7 @@ Create and configure a node:
``` ```
// Create a pubsub manager using an existing XMPPConnection // Create a pubsub manager using an existing XMPPConnection
PubSubManager mgr = new PubSubManager(con); PubSubManager mgr = PubSubManager.getInstanceFor(con);
// Create the node // Create the node
ConfigureForm form = new ConfigureForm(FormType.submit); ConfigureForm form = new ConfigureForm(FormType.submit);
@ -108,7 +108,7 @@ In this example we publish an item to a node that does not take payload:
``` ```
// Create a pubsub manager using an existing XMPPConnection // Create a pubsub manager using an existing XMPPConnection
PubSubManager mgr = new PubSubManager(con); PubSubManager mgr = PubSubManager.getInstanceFor(con);
// Get the node // Get the node
LeafNode node = mgr.getNode("testNode"); LeafNode node = mgr.getNode("testNode");
@ -124,7 +124,7 @@ In this example we publish an item to a node that does take payload:
``` ```
// Create a pubsub manager using an existing XMPPConnection // Create a pubsub manager using an existing XMPPConnection
PubSubManager mgr = new PubSubManager(con); PubSubManager mgr = PubSubManager.getInstanceFor(con);
// Get the node // Get the node
LeafNode node = mgr.getNode("testNode"); LeafNode node = mgr.getNode("testNode");
@ -167,7 +167,7 @@ subscribe for messages.
``` ```
// Create a pubsub manager using an existing XMPPConnection // Create a pubsub manager using an existing XMPPConnection
PubSubManager mgr = new PubSubManager(con); PubSubManager mgr = PubSubManager.getInstanceFor(con);
// Get the node // Get the node
LeafNode node = mgr.getNode("testNode"); LeafNode node = mgr.getNode("testNode");
@ -198,7 +198,7 @@ subscribe for item deletion messages.
``` ```
// Create a pubsub manager using an existing XMPPConnection // Create a pubsub manager using an existing XMPPConnection
PubSubManager mgr = new PubSubManager(con); PubSubManager mgr = PubSubManager.getInstanceFor(con);
// Get the node // Get the node
LeafNode node = mgr.getNode("testNode"); LeafNode node = mgr.getNode("testNode");
@ -230,7 +230,7 @@ subscribe for node configuration messages.
``` ```
// Create a pubsub manager using an existing XMPPConnection // Create a pubsub manager using an existing XMPPConnection
PubSubManager mgr = new PubSubManager(con); PubSubManager mgr = PubSubManager.getInstanceFor(con);
// Get the node // Get the node
Node node = mgr.getNode("testNode"); Node node = mgr.getNode("testNode");
@ -286,7 +286,7 @@ In this example we can see how to retrieve the existing items from a node:
``` ```
// Create a pubsub manager using an existing XMPPConnection // Create a pubsub manager using an existing XMPPConnection
PubSubManager mgr = new PubSubManager(con); PubSubManager mgr = PubSubManager.getInstanceFor(con);
// Get the node // Get the node
LeafNode node = mgr.getNode("testNode"); LeafNode node = mgr.getNode("testNode");
@ -298,7 +298,7 @@ In this example we can see how to retrieve the last N existing items:
``` ```
// Create a pubsub manager using an existing XMPPConnection // Create a pubsub manager using an existing XMPPConnection
PubSubManager mgr = new PubSubManager(con); PubSubManager mgr = PubSubManager.getInstanceFor(con);
// Get the node // Get the node
LeafNode node = mgr.getNode("testNode"); LeafNode node = mgr.getNode("testNode");
@ -310,7 +310,7 @@ In this example we can see how to retrieve the specified existing items:
``` ```
// Create a pubsub manager using an existing XMPPConnection // Create a pubsub manager using an existing XMPPConnection
PubSubManager mgr = new PubSubManager(con); PubSubManager mgr = PubSubManager.getInstanceFor(con);
// Get the node // Get the node
LeafNode node = mgr.getNode("testNode"); LeafNode node = mgr.getNode("testNode");
@ -341,7 +341,7 @@ In this example we can see how to get pubsub capabilities:
``` ```
// Create a pubsub manager using an existing XMPPConnection // Create a pubsub manager using an existing XMPPConnection
PubSubManager mgr = new PubSubManager(con); PubSubManager mgr = PubSubManager.getInstanceFor(con);
// Get the pubsub features that are supported // Get the pubsub features that are supported
DiscoverInfo supportedFeatures = mgr.getSupportedFeatures(); DiscoverInfo supportedFeatures = mgr.getSupportedFeatures();
@ -351,7 +351,7 @@ In this example we can see how to get pubsub subscriptions for all nodes:
``` ```
// Create a pubsub manager using an existing XMPPConnection // Create a pubsub manager using an existing XMPPConnection
PubSubManager mgr = new PubSubManager(con); PubSubManager mgr = PubSubManager.getInstanceFor(con);
// Get all the subscriptions in the pubsub service // Get all the subscriptions in the pubsub service
List&ltSubscription;> subscriptions = mgr.getSubscriptions(); List&ltSubscription;> subscriptions = mgr.getSubscriptions();
@ -362,7 +362,7 @@ on the pubsub service:
``` ```
// Create a pubsub manager using an existing XMPPConnection // Create a pubsub manager using an existing XMPPConnection
PubSubManager mgr = new PubSubManager(con); PubSubManager mgr = PubSubManager.getInstanceFor(con);
// Get the affiliations for the users bare JID // Get the affiliations for the users bare JID
List&ltAffiliation;> affiliations = mgr.getAffiliations(); List&ltAffiliation;> affiliations = mgr.getAffiliations();
@ -372,7 +372,7 @@ In this example we can see how to get information about the node:
``` ```
// Create a pubsub manager using an existing XMPPConnection // Create a pubsub manager using an existing XMPPConnection
PubSubManager mgr = new PubSubManager(con); PubSubManager mgr = PubSubManager.getInstanceFor(con);
Node node = mgr.getNode("testNode"); Node node = mgr.getNode("testNode");
// Get the node information // Get the node information
@ -383,7 +383,7 @@ In this example we can see how to discover the node items:
``` ```
// Create a pubsub manager using an existing XMPPConnection // Create a pubsub manager using an existing XMPPConnection
PubSubManager mgr = new PubSubManager(con); PubSubManager mgr = PubSubManager.getInstanceFor(con);
Node node = mgr.getNode("testNode"); Node node = mgr.getNode("testNode");
// Discover the node items // Discover the node items
@ -394,7 +394,7 @@ In this example we can see how to get node subscriptions:
``` ```
// Create a pubsub manager using an existing XMPPConnection // Create a pubsub manager using an existing XMPPConnection
PubSubManager mgr = new PubSubManager(con); PubSubManager mgr = PubSubManager.getInstanceFor(con);
Node node = mgr.getNode("testNode"); Node node = mgr.getNode("testNode");
// Discover the node subscriptions // Discover the node subscriptions

View file

@ -283,11 +283,7 @@ public class MultipleRecipientManager {
*/ */
private static DomainBareJid getMultipleRecipienServiceAddress(XMPPConnection connection) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { private static DomainBareJid getMultipleRecipienServiceAddress(XMPPConnection connection) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
ServiceDiscoveryManager sdm = ServiceDiscoveryManager.getInstanceFor(connection); ServiceDiscoveryManager sdm = ServiceDiscoveryManager.getInstanceFor(connection);
List<DomainBareJid> services = sdm.findServices(MultipleAddresses.NAMESPACE, true, true); return sdm.findService(MultipleAddresses.NAMESPACE, true);
if (services.size() > 0) {
return services.get(0);
}
return null;
} }
/** /**

View file

@ -684,7 +684,7 @@ public final class ServiceDiscoveryManager extends Manager {
* Create a cache to hold the 25 most recently lookup services for a given feature for a period * Create a cache to hold the 25 most recently lookup services for a given feature for a period
* of 24 hours. * of 24 hours.
*/ */
private Cache<String, List<DomainBareJid>> services = new ExpirationCache<>(25, private Cache<String, List<DiscoverInfo>> services = new ExpirationCache<>(25,
24 * 60 * 60 * 1000); 24 * 60 * 60 * 1000);
/** /**
@ -699,17 +699,17 @@ public final class ServiceDiscoveryManager extends Manager {
* @throws NotConnectedException * @throws NotConnectedException
* @throws InterruptedException * @throws InterruptedException
*/ */
public List<DomainBareJid> findServices(String feature, boolean stopOnFirst, boolean useCache) public List<DiscoverInfo> findServicesDiscoverInfo(String feature, boolean stopOnFirst, boolean useCache)
throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
List<DomainBareJid> serviceAddresses = null; List<DiscoverInfo> serviceDiscoInfo = null;
DomainBareJid serviceName = connection().getServiceName(); DomainBareJid serviceName = connection().getServiceName();
if (useCache) { if (useCache) {
serviceAddresses = services.get(feature); serviceDiscoInfo = services.get(feature);
if (serviceAddresses != null) { if (serviceDiscoInfo != null) {
return serviceAddresses; return serviceDiscoInfo;
} }
} }
serviceAddresses = new LinkedList<>(); serviceDiscoInfo = new LinkedList<>();
// Send the disco packet to the server itself // Send the disco packet to the server itself
DiscoverInfo info; DiscoverInfo info;
try { try {
@ -717,17 +717,17 @@ public final class ServiceDiscoveryManager extends Manager {
} catch (XMPPErrorException e) { } catch (XMPPErrorException e) {
// Be extra robust here: Return the empty linked list and log this situation // Be extra robust here: Return the empty linked list and log this situation
LOGGER.log(Level.WARNING, "Could not discover information about service", e); LOGGER.log(Level.WARNING, "Could not discover information about service", e);
return serviceAddresses; return serviceDiscoInfo;
} }
// Check if the server supports XEP-33 // Check if the server supports the feature
if (info.containsFeature(feature)) { if (info.containsFeature(feature)) {
serviceAddresses.add(serviceName); serviceDiscoInfo.add(info);
if (stopOnFirst) { if (stopOnFirst) {
if (useCache) { if (useCache) {
// Cache the discovered information // Cache the discovered information
services.put(feature, serviceAddresses); services.put(feature, serviceDiscoInfo);
} }
return serviceAddresses; return serviceDiscoInfo;
} }
} }
DiscoverItems items; DiscoverItems items;
@ -736,7 +736,7 @@ public final class ServiceDiscoveryManager extends Manager {
items = discoverItems(serviceName); items = discoverItems(serviceName);
} catch(XMPPErrorException e) { } catch(XMPPErrorException e) {
LOGGER.log(Level.WARNING, "Could not discover items about service", e); LOGGER.log(Level.WARNING, "Could not discover items about service", e);
return serviceAddresses; return serviceDiscoInfo;
} }
for (DiscoverItems.Item item : items.getItems()) { for (DiscoverItems.Item item : items.getItems()) {
try { try {
@ -752,7 +752,8 @@ public final class ServiceDiscoveryManager extends Manager {
continue; continue;
} }
if (info.containsFeature(feature)) { if (info.containsFeature(feature)) {
serviceAddresses.add(item.getEntityID().asDomainBareJid()); serviceDiscoInfo.add(info);
//serviceAddresses.add(item.getEntityID().asDomainBareJid());
if (stopOnFirst) { if (stopOnFirst) {
break; break;
} }
@ -760,9 +761,54 @@ public final class ServiceDiscoveryManager extends Manager {
} }
if (useCache) { if (useCache) {
// Cache the discovered information // Cache the discovered information
services.put(feature, serviceAddresses); services.put(feature, serviceDiscoInfo);
} }
return serviceAddresses; return serviceDiscoInfo;
}
/**
* Find all services under the users service that provide a given feature.
*
* @param feature the feature to search for
* @param stopOnFirst if true, stop searching after the first service was found
* @param useCache if true, query a cache first to avoid network I/O
* @return a possible empty list of services providing the given feature
* @throws NoResponseException
* @throws XMPPErrorException
* @throws NotConnectedException
* @throws InterruptedException
*/
public List<DomainBareJid> findServices(String feature, boolean stopOnFirst, boolean useCache) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
List<DiscoverInfo> services = findServicesDiscoverInfo(feature, stopOnFirst, useCache);
List<DomainBareJid> res = new ArrayList<>(services.size());
for (DiscoverInfo info : services) {
res.add(info.getFrom().asDomainBareJid());
}
return res;
}
public DomainBareJid findService(String feature, boolean useCache, String category, String type)
throws NoResponseException, XMPPErrorException, NotConnectedException,
InterruptedException {
List<DiscoverInfo> services = findServicesDiscoverInfo(feature, true, useCache);
if (services.isEmpty()) {
return null;
}
DiscoverInfo info = services.get(0);
if (category != null && type != null) {
if (!info.hasIdentity(category, type)) {
return null;
}
}
else if (category != null || type != null) {
throw new IllegalArgumentException("Must specify either both, category and type, or none");
}
return info.getFrom().asDomainBareJid();
}
public DomainBareJid findService(String feature, boolean useCache) throws NoResponseException,
XMPPErrorException, NotConnectedException, InterruptedException {
return findService(feature, useCache, null, null);
} }
/** /**

View file

@ -16,13 +16,11 @@
*/ */
package org.jivesoftware.smackx.pubsub; package org.jivesoftware.smackx.pubsub;
import org.jivesoftware.smack.XMPPConnection;
public class CollectionNode extends Node public class CollectionNode extends Node
{ {
CollectionNode(XMPPConnection connection, String nodeId) CollectionNode(PubSubManager pubSubManager, String nodeId)
{ {
super(connection, nodeId); super(pubSubManager, nodeId);
} }
} }

View file

@ -22,7 +22,6 @@ import java.util.List;
import org.jivesoftware.smack.SmackException.NoResponseException; import org.jivesoftware.smack.SmackException.NoResponseException;
import org.jivesoftware.smack.SmackException.NotConnectedException; import org.jivesoftware.smack.SmackException.NotConnectedException;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException.XMPPErrorException; import org.jivesoftware.smack.XMPPException.XMPPErrorException;
import org.jivesoftware.smack.packet.IQ.Type; import org.jivesoftware.smack.packet.IQ.Type;
import org.jivesoftware.smack.packet.ExtensionElement; import org.jivesoftware.smack.packet.ExtensionElement;
@ -39,9 +38,9 @@ import org.jivesoftware.smackx.pubsub.packet.PubSub;
*/ */
public class LeafNode extends Node public class LeafNode extends Node
{ {
LeafNode(XMPPConnection connection, String nodeName) LeafNode(PubSubManager pubSubManager, String nodeId)
{ {
super(connection, nodeName); super(pubSubManager, nodeId);
} }
/** /**
@ -57,9 +56,9 @@ public class LeafNode extends Node
public DiscoverItems discoverItems() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException public DiscoverItems discoverItems() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException
{ {
DiscoverItems items = new DiscoverItems(); DiscoverItems items = new DiscoverItems();
items.setTo(to); items.setTo(pubSubManager.getServiceJid());
items.setNode(getId()); items.setNode(getId());
return (DiscoverItems) con.createPacketCollectorAndSend(items).nextResultOrThrow(); return pubSubManager.getConnection().createPacketCollectorAndSend(items).nextResultOrThrow();
} }
/** /**
@ -193,7 +192,7 @@ public class LeafNode extends Node
private <T extends Item> List<T> getItems(PubSub request, private <T extends Item> List<T> getItems(PubSub request,
List<ExtensionElement> returnedExtensions) throws NoResponseException, List<ExtensionElement> returnedExtensions) throws NoResponseException,
XMPPErrorException, NotConnectedException, InterruptedException { XMPPErrorException, NotConnectedException, InterruptedException {
PubSub result = con.createPacketCollectorAndSend(request).nextResultOrThrow(); PubSub result = pubSubManager.getConnection().createPacketCollectorAndSend(request).nextResultOrThrow();
ItemsExtension itemsElem = result.getExtension(PubSubElementType.ITEMS); ItemsExtension itemsElem = result.getExtension(PubSubElementType.ITEMS);
if (returnedExtensions != null) { if (returnedExtensions != null) {
returnedExtensions.addAll(result.getExtensions()); returnedExtensions.addAll(result.getExtensions());
@ -219,7 +218,7 @@ public class LeafNode extends Node
{ {
PubSub packet = createPubsubPacket(Type.set, new NodeExtension(PubSubElementType.PUBLISH, getId())); PubSub packet = createPubsubPacket(Type.set, new NodeExtension(PubSubElementType.PUBLISH, getId()));
con.sendStanza(packet); pubSubManager.getConnection().sendStanza(packet);
} }
/** /**
@ -266,7 +265,7 @@ public class LeafNode extends Node
{ {
PubSub packet = createPubsubPacket(Type.set, new PublishItem<T>(getId(), items)); PubSub packet = createPubsubPacket(Type.set, new PublishItem<T>(getId(), items));
con.sendStanza(packet); pubSubManager.getConnection().sendStanza(packet);
} }
/** /**
@ -290,7 +289,7 @@ public class LeafNode extends Node
{ {
PubSub packet = createPubsubPacket(Type.set, new NodeExtension(PubSubElementType.PUBLISH, getId())); PubSub packet = createPubsubPacket(Type.set, new NodeExtension(PubSubElementType.PUBLISH, getId()));
con.createPacketCollectorAndSend(packet).nextResultOrThrow(); pubSubManager.getConnection().createPacketCollectorAndSend(packet).nextResultOrThrow();
} }
/** /**
@ -347,7 +346,7 @@ public class LeafNode extends Node
{ {
PubSub packet = createPubsubPacket(Type.set, new PublishItem<T>(getId(), items)); PubSub packet = createPubsubPacket(Type.set, new PublishItem<T>(getId(), items));
con.createPacketCollectorAndSend(packet).nextResultOrThrow(); pubSubManager.getConnection().createPacketCollectorAndSend(packet).nextResultOrThrow();
} }
/** /**
@ -364,7 +363,7 @@ public class LeafNode extends Node
{ {
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()), PubSubElementType.PURGE_OWNER.getNamespace());
con.createPacketCollectorAndSend(request).nextResultOrThrow(); pubSubManager.getConnection().createPacketCollectorAndSend(request).nextResultOrThrow();
} }
/** /**
@ -401,6 +400,6 @@ public class LeafNode extends Node
items.add(new Item(id)); items.add(new Item(id));
} }
PubSub request = createPubsubPacket(Type.set, new ItemsExtension(ItemsExtension.ItemsElementType.retract, getId(), items)); PubSub request = createPubsubPacket(Type.set, new ItemsExtension(ItemsExtension.ItemsElementType.retract, getId(), items));
con.createPacketCollectorAndSend(request).nextResultOrThrow(); pubSubManager.getConnection().createPacketCollectorAndSend(request).nextResultOrThrow();
} }
} }

View file

@ -24,7 +24,6 @@ import java.util.concurrent.ConcurrentHashMap;
import org.jivesoftware.smack.StanzaListener; import org.jivesoftware.smack.StanzaListener;
import org.jivesoftware.smack.SmackException.NoResponseException; import org.jivesoftware.smack.SmackException.NoResponseException;
import org.jivesoftware.smack.SmackException.NotConnectedException; import org.jivesoftware.smack.SmackException.NotConnectedException;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException.XMPPErrorException; import org.jivesoftware.smack.XMPPException.XMPPErrorException;
import org.jivesoftware.smack.filter.OrFilter; import org.jivesoftware.smack.filter.OrFilter;
import org.jivesoftware.smack.filter.StanzaFilter; import org.jivesoftware.smack.filter.StanzaFilter;
@ -43,13 +42,11 @@ import org.jivesoftware.smackx.pubsub.util.NodeUtils;
import org.jivesoftware.smackx.shim.packet.Header; import org.jivesoftware.smackx.shim.packet.Header;
import org.jivesoftware.smackx.shim.packet.HeadersExtension; import org.jivesoftware.smackx.shim.packet.HeadersExtension;
import org.jivesoftware.smackx.xdata.Form; import org.jivesoftware.smackx.xdata.Form;
import org.jxmpp.jid.Jid;
abstract public class Node abstract public class Node
{ {
protected XMPPConnection con; protected final PubSubManager pubSubManager;
protected String id; protected final String id;
protected Jid to;
protected ConcurrentHashMap<ItemEventListener<Item>, StanzaListener> itemEventToListenerMap = new ConcurrentHashMap<ItemEventListener<Item>, StanzaListener>(); protected ConcurrentHashMap<ItemEventListener<Item>, StanzaListener> itemEventToListenerMap = new ConcurrentHashMap<ItemEventListener<Item>, StanzaListener>();
protected ConcurrentHashMap<ItemDeleteListener, StanzaListener> itemDeleteToListenerMap = new ConcurrentHashMap<ItemDeleteListener, StanzaListener>(); protected ConcurrentHashMap<ItemDeleteListener, StanzaListener> itemDeleteToListenerMap = new ConcurrentHashMap<ItemDeleteListener, StanzaListener>();
@ -62,21 +59,10 @@ abstract public class Node
* @param connection The connection the node is associated with * @param connection The connection the node is associated with
* @param nodeName The node id * @param nodeName The node id
*/ */
Node(XMPPConnection connection, String nodeName) Node(PubSubManager pubSubManager, String nodeId)
{ {
con = connection; this.pubSubManager = pubSubManager;
id = nodeName; id = nodeId;
}
/**
* Some XMPP servers may require a specific service to be addressed on the
* server.
*
* For example, OpenFire requires the server to be prefixed by <b>pubsub</b>
*/
void setTo(Jid toAddress)
{
to = toAddress;
} }
/** /**
@ -119,7 +105,7 @@ abstract public class Node
{ {
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), PubSubNamespace.OWNER);
con.createPacketCollectorAndSend(packet).nextResultOrThrow(); pubSubManager.getConnection().createPacketCollectorAndSend(packet).nextResultOrThrow();
} }
/** /**
@ -134,9 +120,9 @@ abstract public class Node
public DiscoverInfo discoverInfo() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException public DiscoverInfo discoverInfo() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException
{ {
DiscoverInfo info = new DiscoverInfo(); DiscoverInfo info = new DiscoverInfo();
info.setTo(to); info.setTo(pubSubManager.getServiceJid());
info.setNode(getId()); info.setNode(getId());
return (DiscoverInfo) con.createPacketCollectorAndSend(info).nextResultOrThrow(); return pubSubManager.getConnection().createPacketCollectorAndSend(info).nextResultOrThrow();
} }
/** /**
@ -336,7 +322,7 @@ abstract public class Node
PubSub request = createPubsubPacket(Type.set, new SubscribeExtension(jid, getId())); PubSub request = createPubsubPacket(Type.set, new SubscribeExtension(jid, getId()));
// CHECKSTYLE:ON // CHECKSTYLE:ON
request.addExtension(new FormNode(FormNodeType.OPTIONS, subForm)); request.addExtension(new FormNode(FormNodeType.OPTIONS, subForm));
PubSub reply = PubSubManager.sendPubsubPacket(con, request); PubSub reply = sendPubsubPacket(request);
return reply.getExtension(PubSubElementType.SUBSCRIPTION); return reply.getExtension(PubSubElementType.SUBSCRIPTION);
} }
@ -420,7 +406,7 @@ abstract public class Node
{ {
StanzaListener conListener = new ItemEventTranslator(listener); StanzaListener conListener = new ItemEventTranslator(listener);
itemEventToListenerMap.put(listener, conListener); itemEventToListenerMap.put(listener, conListener);
con.addSyncStanzaListener(conListener, new EventContentFilter(EventElementType.items.toString(), "item")); pubSubManager.getConnection().addSyncStanzaListener(conListener, new EventContentFilter(EventElementType.items.toString(), "item"));
} }
/** /**
@ -433,7 +419,7 @@ abstract public class Node
StanzaListener conListener = itemEventToListenerMap.remove(listener); StanzaListener conListener = itemEventToListenerMap.remove(listener);
if (conListener != null) if (conListener != null)
con.removeSyncStanzaListener(conListener); pubSubManager.getConnection().removeSyncStanzaListener(conListener);
} }
/** /**
@ -446,7 +432,7 @@ abstract public class Node
{ {
StanzaListener conListener = new NodeConfigTranslator(listener); StanzaListener conListener = new NodeConfigTranslator(listener);
configEventToListenerMap.put(listener, conListener); configEventToListenerMap.put(listener, conListener);
con.addSyncStanzaListener(conListener, new EventContentFilter(EventElementType.configuration.toString())); pubSubManager.getConnection().addSyncStanzaListener(conListener, new EventContentFilter(EventElementType.configuration.toString()));
} }
/** /**
@ -459,7 +445,7 @@ abstract public class Node
StanzaListener conListener = configEventToListenerMap .remove(listener); StanzaListener conListener = configEventToListenerMap .remove(listener);
if (conListener != null) if (conListener != null)
con.removeSyncStanzaListener(conListener); pubSubManager.getConnection().removeSyncStanzaListener(conListener);
} }
/** /**
@ -475,7 +461,7 @@ abstract public class Node
EventContentFilter deleteItem = new EventContentFilter(EventElementType.items.toString(), "retract"); EventContentFilter deleteItem = new EventContentFilter(EventElementType.items.toString(), "retract");
EventContentFilter purge = new EventContentFilter(EventElementType.purge.toString()); EventContentFilter purge = new EventContentFilter(EventElementType.purge.toString());
con.addSyncStanzaListener(delListener, new OrFilter(deleteItem, purge)); pubSubManager.getConnection().addSyncStanzaListener(delListener, new OrFilter(deleteItem, purge));
} }
/** /**
@ -488,7 +474,7 @@ abstract public class Node
StanzaListener conListener = itemDeleteToListenerMap .remove(listener); StanzaListener conListener = itemDeleteToListenerMap .remove(listener);
if (conListener != null) if (conListener != null)
con.removeSyncStanzaListener(conListener); pubSubManager.getConnection().removeSyncStanzaListener(conListener);
} }
@Override @Override
@ -504,12 +490,12 @@ abstract public class Node
protected PubSub createPubsubPacket(Type type, ExtensionElement ext, PubSubNamespace ns) protected PubSub createPubsubPacket(Type type, ExtensionElement ext, PubSubNamespace ns)
{ {
return PubSub.createPubsubPacket(to, type, ext, 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
{ {
return PubSubManager.sendPubsubPacket(con, packet); return pubSubManager.sendPubsubPacket(packet);
} }

View file

@ -17,16 +17,22 @@
package org.jivesoftware.smackx.pubsub; package org.jivesoftware.smackx.pubsub;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jivesoftware.smack.Manager;
import org.jivesoftware.smack.SmackException.NoResponseException; import org.jivesoftware.smack.SmackException.NoResponseException;
import org.jivesoftware.smack.SmackException.NotConnectedException; import org.jivesoftware.smack.SmackException.NotConnectedException;
import org.jivesoftware.smack.XMPPConnection; import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException.XMPPErrorException; import org.jivesoftware.smack.XMPPException.XMPPErrorException;
import org.jivesoftware.smack.packet.EmptyResultIQ; import org.jivesoftware.smack.packet.EmptyResultIQ;
import org.jivesoftware.smack.packet.IQ; import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.XMPPError;
import org.jivesoftware.smack.packet.IQ.Type; import org.jivesoftware.smack.packet.IQ.Type;
import org.jivesoftware.smack.packet.Stanza; import org.jivesoftware.smack.packet.Stanza;
import org.jivesoftware.smack.packet.ExtensionElement; import org.jivesoftware.smack.packet.ExtensionElement;
@ -52,23 +58,72 @@ import org.jxmpp.stringprep.XmppStringprepException;
* *
* @author Robin Collier * @author Robin Collier
*/ */
final public class PubSubManager public final class PubSubManager extends Manager {
{
private XMPPConnection con; private static final Logger LOGGER = Logger.getLogger(PubSubManager.class.getName());
private DomainBareJid to; private static final Map<XMPPConnection, Map<DomainBareJid, PubSubManager>> INSTANCES = new WeakHashMap<>();
private Map<String, Node> nodeMap = new ConcurrentHashMap<String, Node>();
/** /**
* Create a pubsub manager associated to the specified connection. Defaults the service * The JID of the PubSub service this manager manages.
* name to <i>pubsub</i>
*
* @param connection The XMPP connection
* @throws XmppStringprepException
*/ */
public PubSubManager(XMPPConnection connection) throws XmppStringprepException private final DomainBareJid pubSubService;
{
con = connection; /**
to = JidCreate.domainBareFrom("pubsub." + connection.getServiceName()); * A map of node IDs to Nodes, used to cache those Nodes. This does only cache the type of Node,
* i.e. {@link CollectionNode} or {@link LeafNode}.
*/
private final Map<String, Node> nodeMap = new ConcurrentHashMap<String, Node>();
/**
* Get a PubSub manager for the default PubSub service of the connection.
*
* @param connection
* @return the default PubSub manager.
*/
public static PubSubManager getInstance(XMPPConnection connection) {
DomainBareJid pubSubService = null;
if (connection.isAuthenticated()) {
try {
pubSubService = getPubSubService(connection);
}
catch (NoResponseException | XMPPErrorException | NotConnectedException e) {
LOGGER.log(Level.WARNING, "Could not determine PubSub service", e);
}
catch (InterruptedException e) {
LOGGER.log(Level.FINE, "Interupted while trying to determine PubSub service", e);
}
}
if (pubSubService == null) {
try {
// Perform an educated guess about what the PubSub service's domain bare JID may be
pubSubService = JidCreate.domainBareFrom("pubsub." + connection.getServiceName());
}
catch (XmppStringprepException e) {
throw new RuntimeException(e);
}
}
return getInstance(connection, pubSubService);
}
/**
* Get the PubSub manager for the given connection and PubSub service.
*
* @param connection the XMPP connection.
* @param pubSubService the PubSub service.
* @return a PubSub manager for the connection and service.
*/
public static synchronized PubSubManager getInstance(XMPPConnection connection, DomainBareJid pubSubService) {
Map<DomainBareJid, PubSubManager> managers = INSTANCES.get(connection);
if (managers == null) {
managers = new HashMap<>();
INSTANCES.put(connection, managers);
}
PubSubManager pubSubManager = managers.get(pubSubService);
if (pubSubManager == null) {
pubSubManager = new PubSubManager(connection, pubSubService);
managers.put(pubSubService, pubSubManager);
}
return pubSubManager;
} }
/** /**
@ -78,10 +133,10 @@ final public class PubSubManager
* @param connection The XMPP connection * @param connection The XMPP connection
* @param toAddress The pubsub specific to address (required for some servers) * @param toAddress The pubsub specific to address (required for some servers)
*/ */
public PubSubManager(XMPPConnection connection, DomainBareJid toAddress) PubSubManager(XMPPConnection connection, DomainBareJid toAddress)
{ {
con = connection; super(connection);
to = toAddress; pubSubService = toAddress;
} }
/** /**
@ -98,8 +153,7 @@ final public class PubSubManager
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(con, elem.getNode()); LeafNode newNode = new LeafNode(this, elem.getNode());
newNode.setTo(to);
nodeMap.put(newNode.getId(), newNode); nodeMap.put(newNode.getId(), newNode);
return newNode; return newNode;
@ -108,7 +162,7 @@ final public class PubSubManager
/** /**
* Creates a node with default configuration. * Creates a node with default configuration.
* *
* @param id The id of the node, which must be unique within the * @param nodeId The id of the node, which must be unique within the
* pubsub service * pubsub service
* @return The node that was created * @return The node that was created
* @throws XMPPErrorException * @throws XMPPErrorException
@ -116,9 +170,9 @@ final public class PubSubManager
* @throws NotConnectedException * @throws NotConnectedException
* @throws InterruptedException * @throws InterruptedException
*/ */
public LeafNode createNode(String id) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException public LeafNode createNode(String nodeId) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException
{ {
return (LeafNode)createNode(id, null); return (LeafNode) createNode(nodeId, null);
} }
/** /**
@ -126,7 +180,7 @@ final public class PubSubManager
* *
* Note: This is the only way to create a collection node. * Note: This is the only way to create a collection node.
* *
* @param name The name of the node, which must be unique within the * @param nodeId The name of the node, which must be unique within the
* pubsub service * pubsub service
* @param config The configuration for the node * @param config The configuration for the node
* @return The node that was created * @return The node that was created
@ -135,9 +189,9 @@ final public class PubSubManager
* @throws NotConnectedException * @throws NotConnectedException
* @throws InterruptedException * @throws InterruptedException
*/ */
public Node createNode(String name, Form config) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException public Node createNode(String nodeId, Form config) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException
{ {
PubSub request = PubSub.createPubsubPacket(to, Type.set, new NodeExtension(PubSubElementType.CREATE, name), null); PubSub request = PubSub.createPubsubPacket(pubSubService, Type.set, new NodeExtension(PubSubElementType.CREATE, nodeId), null);
boolean isLeafNode = true; boolean isLeafNode = true;
if (config != null) if (config != null)
@ -151,9 +205,8 @@ final public class PubSubManager
// Errors will cause exceptions in getReply, so it only returns // Errors will cause exceptions in getReply, so it only returns
// on success. // on success.
sendPubsubPacket(con, request); sendPubsubPacket(request);
Node newNode = isLeafNode ? new LeafNode(con, name) : new CollectionNode(con, name); Node newNode = isLeafNode ? new LeafNode(this, nodeId) : new CollectionNode(this, nodeId);
newNode.setTo(to);
nodeMap.put(newNode.getId(), newNode); nodeMap.put(newNode.getId(), newNode);
return newNode; return newNode;
@ -177,16 +230,16 @@ final public class PubSubManager
if (node == null) if (node == null)
{ {
DiscoverInfo info = new DiscoverInfo(); DiscoverInfo info = new DiscoverInfo();
info.setTo(to); info.setTo(pubSubService);
info.setNode(id); info.setNode(id);
DiscoverInfo infoReply = (DiscoverInfo) con.createPacketCollectorAndSend(info).nextResultOrThrow(); DiscoverInfo infoReply = connection().createPacketCollectorAndSend(info).nextResultOrThrow();
if (infoReply.hasIdentity(PubSub.ELEMENT, "leaf")) { if (infoReply.hasIdentity(PubSub.ELEMENT, "leaf")) {
node = new LeafNode(con, id); node = new LeafNode(this, id);
} }
else if (infoReply.hasIdentity(PubSub.ELEMENT, "collection")) { else if (infoReply.hasIdentity(PubSub.ELEMENT, "collection")) {
node = new CollectionNode(con, id); node = new CollectionNode(this, id);
} }
else { else {
// XEP-60 5.3 states that // XEP-60 5.3 states that
@ -194,12 +247,11 @@ final public class PubSubManager
// If this is not the case, then we are dealing with an PubSub implementation that doesn't follow the specification. // If this is not the case, then we are dealing with an PubSub implementation that doesn't follow the specification.
throw new AssertionError( throw new AssertionError(
"PubSub service '" "PubSub service '"
+ to + pubSubService
+ "' returned disco info result for node '" + "' returned disco info result for node '"
+ id + id
+ "', but it did not contain an Identity of type 'leaf' or 'collection' (and category 'pubsub'), which is not allowed according to XEP-60 5.3."); + "', but it did not contain an Identity of type 'leaf' or 'collection' (and category 'pubsub'), which is not allowed according to XEP-60 5.3.");
} }
node.setTo(to);
nodeMap.put(id, node); nodeMap.put(id, node);
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@ -229,8 +281,8 @@ final public class PubSubManager
if (nodeId != null) if (nodeId != null)
items.setNode(nodeId); items.setNode(nodeId);
items.setTo(to); items.setTo(pubSubService);
DiscoverItems nodeItems = (DiscoverItems) con.createPacketCollectorAndSend(items).nextResultOrThrow(); DiscoverItems nodeItems = connection().createPacketCollectorAndSend(items).nextResultOrThrow();
return nodeItems; return nodeItems;
} }
@ -299,6 +351,15 @@ final public class PubSubManager
return NodeUtils.getFormFromPacket(reply, PubSubElementType.DEFAULT); return NodeUtils.getFormFromPacket(reply, PubSubElementType.DEFAULT);
} }
/**
* Get the JID of the PubSub service managed by this manager.
*
* @return the JID of the PubSub service.
*/
public DomainBareJid getServiceJid() {
return pubSubService;
}
/** /**
* Gets the supported features of the servers pubsub implementation * Gets the supported features of the servers pubsub implementation
* as a standard {@link DiscoverInfo} instance. * as a standard {@link DiscoverInfo} instance.
@ -311,33 +372,92 @@ final public class PubSubManager
*/ */
public DiscoverInfo getSupportedFeatures() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException public DiscoverInfo getSupportedFeatures() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException
{ {
ServiceDiscoveryManager mgr = ServiceDiscoveryManager.getInstanceFor(con); ServiceDiscoveryManager mgr = ServiceDiscoveryManager.getInstanceFor(connection());
return mgr.discoverInfo(to); return mgr.discoverInfo(pubSubService);
}
/**
* Check if it is possible to create PubSub nodes on this service. It could be possible that the
* PubSub service allows only certain XMPP entities (clients) to create nodes and publish items
* to them.
* <p>
* Note that since XEP-60 does not provide an API to determine if an XMPP entity is allowed to
* create nodes, therefore this method creates an instant node calling {@link #createNode()} to
* determine if it is possible to create nodes.
* </p>
*
* @return <code>true</code> if it is possible to create nodes, <code>false</code> otherwise.
* @throws NoResponseException
* @throws NotConnectedException
* @throws InterruptedException
* @throws XMPPErrorException
*/
public boolean canCreateNodesAndPublishItems() throws NoResponseException, NotConnectedException, InterruptedException, XMPPErrorException {
LeafNode leafNode = null;
try {
leafNode = createNode();
}
catch (XMPPErrorException e) {
if (e.getXMPPError().getCondition() == XMPPError.Condition.forbidden) {
return false;
}
throw e;
} finally {
if (leafNode != null) {
deleteNode(leafNode.getId());
}
}
return true;
} }
private PubSub sendPubsubPacket(Type type, ExtensionElement ext, PubSubNamespace ns) private PubSub sendPubsubPacket(Type type, ExtensionElement ext, PubSubNamespace ns)
throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
return sendPubsubPacket(con, to, type, Collections.singletonList(ext), ns); return sendPubsubPacket(pubSubService, type, Collections.singletonList(ext), ns);
} }
static PubSub sendPubsubPacket(XMPPConnection con, Jid to, Type type, List<ExtensionElement> extList, PubSubNamespace ns) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException XMPPConnection getConnection() {
{ return connection();
}
PubSub sendPubsubPacket(Jid to, Type type, List<ExtensionElement> extList, PubSubNamespace ns)
throws NoResponseException, XMPPErrorException, NotConnectedException,
InterruptedException {
// CHECKSTYLE:OFF // CHECKSTYLE:OFF
PubSub pubSub = new PubSub(to, type, ns); PubSub pubSub = new PubSub(to, type, ns);
for (ExtensionElement pe : extList) { for (ExtensionElement pe : extList) {
pubSub.addExtension(pe); pubSub.addExtension(pe);
} }
// CHECKSTYLE:ON // CHECKSTYLE:ON
return sendPubsubPacket(con ,pubSub); return sendPubsubPacket(pubSub);
} }
static PubSub sendPubsubPacket(XMPPConnection con, PubSub packet) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException PubSub sendPubsubPacket(PubSub packet) throws NoResponseException, XMPPErrorException,
{ NotConnectedException, InterruptedException {
IQ resultIQ = con.createPacketCollectorAndSend(packet).nextResultOrThrow(); IQ resultIQ = connection().createPacketCollectorAndSend(packet).nextResultOrThrow();
if (resultIQ instanceof EmptyResultIQ) { if (resultIQ instanceof EmptyResultIQ) {
return null; return null;
} }
return (PubSub) resultIQ; return (PubSub) resultIQ;
} }
/**
* Get the "default" PubSub service for a given XMPP connection. The default PubSub service is
* simply an arbitrary XMPP service with the PubSub feature and an identity of category "pubsub"
* and type "service".
*
* @param connection
* @return the default PubSub service or <code>null</code>.
* @throws NoResponseException
* @throws XMPPErrorException
* @throws NotConnectedException
* @throws InterruptedException
* @see <a href="http://xmpp.org/extensions/xep-0060.html#entity-features">XEP-60 § 5.1 Discover
* Features</a>
*/
public static DomainBareJid getPubSubService(XMPPConnection connection)
throws NoResponseException, XMPPErrorException, NotConnectedException,
InterruptedException {
return ServiceDiscoveryManager.getInstanceFor(connection).findService(PubSub.NAMESPACE,
true, "pubsub", "service");
}
} }

View file

@ -16,6 +16,6 @@
*/ */
/** /**
* TODO describe me. * Listeners for Publish-Subscribe (XEP-60) events.
*/ */
package org.jivesoftware.smackx.pubsub.listener; package org.jivesoftware.smackx.pubsub.listener;

View file

@ -16,6 +16,6 @@
*/ */
/** /**
* TODO describe me. * Smack's API for XEP-60: Publish-Subscribe.
*/ */
package org.jivesoftware.smackx.pubsub; package org.jivesoftware.smackx.pubsub;

View file

@ -16,6 +16,6 @@
*/ */
/** /**
* TODO describe me. * Stanzas and extension elements for Publish-Subscribe (XEP-60).
*/ */
package org.jivesoftware.smackx.pubsub.packet; package org.jivesoftware.smackx.pubsub.packet;

View file

@ -16,6 +16,6 @@
*/ */
/** /**
* TODO describe me. * Providers for Publish-Subscribe (XEP-60).
*/ */
package org.jivesoftware.smackx.pubsub.provider; package org.jivesoftware.smackx.pubsub.provider;

View file

@ -16,6 +16,6 @@
*/ */
/** /**
* TODO describe me. * Utilities for Publish-Subscribe (XEP-60).
*/ */
package org.jivesoftware.smackx.pubsub.util; package org.jivesoftware.smackx.pubsub.util;

View file

@ -54,7 +54,7 @@ public class ConfigureFormTest
public void getConfigFormWithInsufficientPriviliges() throws XMPPException, SmackException, IOException, InterruptedException public void getConfigFormWithInsufficientPriviliges() throws XMPPException, SmackException, IOException, InterruptedException
{ {
ThreadedDummyConnection con = ThreadedDummyConnection.newInstance(); ThreadedDummyConnection con = ThreadedDummyConnection.newInstance();
PubSubManager mgr = new PubSubManager(con); PubSubManager mgr = new PubSubManager(con, PubSubManagerTest.DUMMY_PUBSUB_SERVICE);
DiscoverInfo info = new DiscoverInfo(); DiscoverInfo info = new DiscoverInfo();
Identity ident = new Identity("pubsub", null, "leaf"); Identity ident = new Identity("pubsub", null, "leaf");
info.addIdentity(ident); info.addIdentity(ident);
@ -81,7 +81,7 @@ public class ConfigureFormTest
public void getConfigFormWithTimeout() throws XMPPException, SmackException, InterruptedException, XmppStringprepException public void getConfigFormWithTimeout() throws XMPPException, SmackException, InterruptedException, XmppStringprepException
{ {
ThreadedDummyConnection con = new ThreadedDummyConnection(); ThreadedDummyConnection con = new ThreadedDummyConnection();
PubSubManager mgr = new PubSubManager(con); PubSubManager mgr = new PubSubManager(con, PubSubManagerTest.DUMMY_PUBSUB_SERVICE);
DiscoverInfo info = new DiscoverInfo(); DiscoverInfo info = new DiscoverInfo();
Identity ident = new Identity("pubsub", null, "leaf"); Identity ident = new Identity("pubsub", null, "leaf");
info.addIdentity(ident); info.addIdentity(ident);

View file

@ -25,13 +25,29 @@ import org.jivesoftware.smack.ThreadedDummyConnection;
import org.jivesoftware.smack.XMPPException; import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smackx.pubsub.packet.PubSub; import org.jivesoftware.smackx.pubsub.packet.PubSub;
import org.junit.Test; import org.junit.Test;
import org.jxmpp.jid.DomainBareJid;
import org.jxmpp.jid.impl.JidCreate;
import org.jxmpp.stringprep.XmppStringprepException;
public class PubSubManagerTest { public class PubSubManagerTest {
public static final DomainBareJid DUMMY_PUBSUB_SERVICE;
static {
DomainBareJid pubSubService;
try {
pubSubService = JidCreate.domainBareFrom("pubsub.dummy.org");
}
catch (XmppStringprepException e) {
throw new AssertionError(e);
}
DUMMY_PUBSUB_SERVICE = pubSubService;
}
@Test @Test
public void deleteNodeTest() throws InterruptedException, SmackException, IOException, XMPPException { public void deleteNodeTest() throws InterruptedException, SmackException, IOException, XMPPException {
ThreadedDummyConnection con = ThreadedDummyConnection.newInstance(); ThreadedDummyConnection con = ThreadedDummyConnection.newInstance();
PubSubManager mgr = new PubSubManager(con); PubSubManager mgr = new PubSubManager(con, DUMMY_PUBSUB_SERVICE);
mgr.deleteNode("foo@bar.org"); mgr.deleteNode("foo@bar.org");

View file

@ -0,0 +1,66 @@
/**
*
* Copyright 2015 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.pubsub;
import static org.junit.Assert.assertEquals;
import java.util.List;
import org.igniterealtime.smack.inttest.AbstractSmackIntegrationTest;
import org.igniterealtime.smack.inttest.SmackIntegrationTest;
import org.igniterealtime.smack.inttest.SmackIntegrationTestEnvironment;
import org.igniterealtime.smack.inttest.TestNotPossibleException;
import org.jivesoftware.smack.SmackException.NoResponseException;
import org.jivesoftware.smack.SmackException.NotConnectedException;
import org.jivesoftware.smack.XMPPException.XMPPErrorException;
import org.jxmpp.jid.DomainBareJid;
public class PubSubIntegrationTest extends AbstractSmackIntegrationTest {
private final PubSubManager pubSubManagerOne;
public PubSubIntegrationTest(SmackIntegrationTestEnvironment environment)
throws TestNotPossibleException, NoResponseException, XMPPErrorException,
NotConnectedException, InterruptedException {
super(environment);
DomainBareJid pubSubService = PubSubManager.getPubSubService(conOne);
if (pubSubService == null) {
throw new TestNotPossibleException("No PubSub service found");
}
pubSubManagerOne = PubSubManager.getInstance(conOne, pubSubService);
if (!pubSubManagerOne.canCreateNodesAndPublishItems()) {
throw new TestNotPossibleException("PubSub service does not allow node creation");
}
}
@SmackIntegrationTest
public void simplePubSubNodeTest() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
final String nodename = "sinttest-simple-nodename-" + testRunId;
final String itemId = "sintest-simple-itemid-" + testRunId;
LeafNode leafNode = pubSubManagerOne.createNode(nodename);
try {
leafNode.publish(new Item(itemId));
List<Item> items = leafNode.getItems();
assertEquals(1, items.size());
Item item = items.get(0);
assertEquals(itemId, item.getId());
}
finally {
pubSubManagerOne.deleteNode(nodename);
}
}
}

View file

@ -0,0 +1 @@
../../../../../../../../smack-extensions/src/main/java/org/jivesoftware/smackx/pubsub/package-info.java