/** | |
* All rights reserved. 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 java.util.List; | |
import java.util.Map; | |
import java.util.concurrent.ConcurrentHashMap; | |
import org.jivesoftware.smack.Connection; | |
import org.jivesoftware.smack.XMPPException; | |
import org.jivesoftware.smack.packet.IQ.Type; | |
import org.jivesoftware.smack.packet.Packet; | |
import org.jivesoftware.smack.packet.PacketExtension; | |
import org.jivesoftware.smackx.Form; | |
import org.jivesoftware.smackx.FormField; | |
import org.jivesoftware.smackx.ServiceDiscoveryManager; | |
import org.jivesoftware.smackx.packet.DiscoverInfo; | |
import org.jivesoftware.smackx.packet.DiscoverItems; | |
import org.jivesoftware.smackx.pubsub.packet.PubSub; | |
import org.jivesoftware.smackx.pubsub.packet.PubSubNamespace; | |
import org.jivesoftware.smackx.pubsub.packet.SyncPacketSend; | |
import org.jivesoftware.smackx.pubsub.util.NodeUtils; | |
/** | |
* This is the starting point for access to the pubsub service. It | |
* will provide access to general information about the service, as | |
* well as create or retrieve pubsub {@link LeafNode} instances. These | |
* instances provide the bulk of the functionality as defined in the | |
* pubsub specification <a href="http://xmpp.org/extensions/xep-0060.html">XEP-0060</a>. | |
* | |
* @author Robin Collier | |
*/ | |
final public class PubSubManager | |
{ | |
private Connection con; | |
private String to; | |
private Map<String, Node> nodeMap = new ConcurrentHashMap<String, Node>(); | |
/** | |
* Create a pubsub manager associated to the specified connection. Defaults the service | |
* name to <i>pubsub</i> | |
* | |
* @param connection The XMPP connection | |
*/ | |
public PubSubManager(Connection connection) | |
{ | |
con = connection; | |
to = "pubsub." + connection.getServiceName(); | |
} | |
/** | |
* Create a pubsub manager associated to the specified connection where | |
* the pubsub requests require a specific to address for packets. | |
* | |
* @param connection The XMPP connection | |
* @param toAddress The pubsub specific to address (required for some servers) | |
*/ | |
public PubSubManager(Connection connection, String toAddress) | |
{ | |
con = connection; | |
to = toAddress; | |
} | |
/** | |
* Creates an instant node, if supported. | |
* | |
* @return The node that was created | |
* @exception XMPPException | |
*/ | |
public LeafNode createNode() | |
throws XMPPException | |
{ | |
PubSub reply = (PubSub)sendPubsubPacket(Type.SET, new NodeExtension(PubSubElementType.CREATE)); | |
NodeExtension elem = (NodeExtension)reply.getExtension("create", PubSubNamespace.BASIC.getXmlns()); | |
LeafNode newNode = new LeafNode(con, elem.getNode()); | |
newNode.setTo(to); | |
nodeMap.put(newNode.getId(), newNode); | |
return newNode; | |
} | |
/** | |
* Creates a node with default configuration. | |
* | |
* @param id The id of the node, which must be unique within the | |
* pubsub service | |
* @return The node that was created | |
* @exception XMPPException | |
*/ | |
public LeafNode createNode(String id) | |
throws XMPPException | |
{ | |
return (LeafNode)createNode(id, null); | |
} | |
/** | |
* Creates a node with specified configuration. | |
* | |
* Note: This is the only way to create a collection node. | |
* | |
* @param name The name of the node, which must be unique within the | |
* pubsub service | |
* @param config The configuration for the node | |
* @return The node that was created | |
* @exception XMPPException | |
*/ | |
public Node createNode(String name, Form config) | |
throws XMPPException | |
{ | |
PubSub request = createPubsubPacket(to, Type.SET, new NodeExtension(PubSubElementType.CREATE, name)); | |
boolean isLeafNode = true; | |
if (config != null) | |
{ | |
request.addExtension(new FormNode(FormNodeType.CONFIGURE, config)); | |
FormField nodeTypeField = config.getField(ConfigureNodeFields.node_type.getFieldName()); | |
if (nodeTypeField != null) | |
isLeafNode = nodeTypeField.getValues().next().equals(NodeType.leaf.toString()); | |
} | |
// Errors will cause exceptions in getReply, so it only returns | |
// on success. | |
sendPubsubPacket(con, to, Type.SET, request); | |
Node newNode = isLeafNode ? new LeafNode(con, name) : new CollectionNode(con, name); | |
newNode.setTo(to); | |
nodeMap.put(newNode.getId(), newNode); | |
return newNode; | |
} | |
/** | |
* Retrieves the requested node, if it exists. It will throw an | |
* exception if it does not. | |
* | |
* @param id - The unique id of the node | |
* @return the node | |
* @throws XMPPException The node does not exist | |
*/ | |
public <T extends Node> T getNode(String id) | |
throws XMPPException | |
{ | |
Node node = nodeMap.get(id); | |
if (node == null) | |
{ | |
DiscoverInfo info = new DiscoverInfo(); | |
info.setTo(to); | |
info.setNode(id); | |
DiscoverInfo infoReply = (DiscoverInfo)SyncPacketSend.getReply(con, info); | |
if (infoReply.getIdentities().next().getType().equals(NodeType.leaf.toString())) | |
node = new LeafNode(con, id); | |
else | |
node = new CollectionNode(con, id); | |
node.setTo(to); | |
nodeMap.put(id, node); | |
} | |
return (T) node; | |
} | |
/** | |
* Get all the nodes that currently exist as a child of the specified | |
* collection node. If the service does not support collection nodes | |
* then all nodes will be returned. | |
* | |
* To retrieve contents of the root collection node (if it exists), | |
* or there is no root collection node, pass null as the nodeId. | |
* | |
* @param nodeId - The id of the collection node for which the child | |
* nodes will be returned. | |
* @return {@link DiscoverItems} representing the existing nodes | |
* | |
* @throws XMPPException | |
*/ | |
public DiscoverItems discoverNodes(String nodeId) | |
throws XMPPException | |
{ | |
DiscoverItems items = new DiscoverItems(); | |
if (nodeId != null) | |
items.setNode(nodeId); | |
items.setTo(to); | |
DiscoverItems nodeItems = (DiscoverItems)SyncPacketSend.getReply(con, items); | |
return nodeItems; | |
} | |
/** | |
* Gets the subscriptions on the root node. | |
* | |
* @return List of exceptions | |
* | |
* @throws XMPPException | |
*/ | |
public List<Subscription> getSubscriptions() | |
throws XMPPException | |
{ | |
Packet reply = sendPubsubPacket(Type.GET, new NodeExtension(PubSubElementType.SUBSCRIPTIONS)); | |
SubscriptionsExtension subElem = (SubscriptionsExtension)reply.getExtension(PubSubElementType.SUBSCRIPTIONS.getElementName(), PubSubElementType.SUBSCRIPTIONS.getNamespace().getXmlns()); | |
return subElem.getSubscriptions(); | |
} | |
/** | |
* Gets the affiliations on the root node. | |
* | |
* @return List of affiliations | |
* | |
* @throws XMPPException | |
*/ | |
public List<Affiliation> getAffiliations() | |
throws XMPPException | |
{ | |
PubSub reply = (PubSub)sendPubsubPacket(Type.GET, new NodeExtension(PubSubElementType.AFFILIATIONS)); | |
AffiliationsExtension listElem = (AffiliationsExtension)reply.getExtension(PubSubElementType.AFFILIATIONS); | |
return listElem.getAffiliations(); | |
} | |
/** | |
* Delete the specified node | |
* | |
* @param nodeId | |
* @throws XMPPException | |
*/ | |
public void deleteNode(String nodeId) | |
throws XMPPException | |
{ | |
sendPubsubPacket(Type.SET, new NodeExtension(PubSubElementType.DELETE, nodeId), PubSubElementType.DELETE.getNamespace()); | |
nodeMap.remove(nodeId); | |
} | |
/** | |
* Returns the default settings for Node configuration. | |
* | |
* @return configuration form containing the default settings. | |
*/ | |
public ConfigureForm getDefaultConfiguration() | |
throws XMPPException | |
{ | |
// Errors will cause exceptions in getReply, so it only returns | |
// on success. | |
PubSub reply = (PubSub)sendPubsubPacket(Type.GET, new NodeExtension(PubSubElementType.DEFAULT), PubSubElementType.DEFAULT.getNamespace()); | |
return NodeUtils.getFormFromPacket(reply, PubSubElementType.DEFAULT); | |
} | |
/** | |
* Gets the supported features of the servers pubsub implementation | |
* as a standard {@link DiscoverInfo} instance. | |
* | |
* @return The supported features | |
* | |
* @throws XMPPException | |
*/ | |
public DiscoverInfo getSupportedFeatures() | |
throws XMPPException | |
{ | |
ServiceDiscoveryManager mgr = ServiceDiscoveryManager.getInstanceFor(con); | |
return mgr.discoverInfo(to); | |
} | |
private Packet sendPubsubPacket(Type type, PacketExtension ext, PubSubNamespace ns) | |
throws XMPPException | |
{ | |
return sendPubsubPacket(con, to, type, ext, ns); | |
} | |
private Packet sendPubsubPacket(Type type, PacketExtension ext) | |
throws XMPPException | |
{ | |
return sendPubsubPacket(type, ext, null); | |
} | |
static PubSub createPubsubPacket(String to, Type type, PacketExtension ext) | |
{ | |
return createPubsubPacket(to, type, ext, null); | |
} | |
static PubSub createPubsubPacket(String to, Type type, PacketExtension ext, PubSubNamespace ns) | |
{ | |
PubSub request = new PubSub(); | |
request.setTo(to); | |
request.setType(type); | |
if (ns != null) | |
{ | |
request.setPubSubNamespace(ns); | |
} | |
request.addExtension(ext); | |
return request; | |
} | |
static Packet sendPubsubPacket(Connection con, String to, Type type, PacketExtension ext) | |
throws XMPPException | |
{ | |
return sendPubsubPacket(con, to, type, ext, null); | |
} | |
static Packet sendPubsubPacket(Connection con, String to, Type type, PacketExtension ext, PubSubNamespace ns) | |
throws XMPPException | |
{ | |
return SyncPacketSend.getReply(con, createPubsubPacket(to, type, ext, ns)); | |
} | |
static Packet sendPubsubPacket(Connection con, String to, Type type, PubSub packet) | |
throws XMPPException | |
{ | |
return sendPubsubPacket(con, to, type, packet, null); | |
} | |
static Packet sendPubsubPacket(Connection con, String to, Type type, PubSub packet, PubSubNamespace ns) | |
throws XMPPException | |
{ | |
return SyncPacketSend.getReply(con, packet); | |
} | |
} |