1d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/**
2d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * $RCSfile$
3d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * $Revision$
4d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * $Date$
5d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen *
6d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Copyright 2009 Robin Collier.
7d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen *
8d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
9d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * you may not use this file except in compliance with the License.
10d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * You may obtain a copy of the License at
11d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen *
12d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen *     http://www.apache.org/licenses/LICENSE-2.0
13d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen *
14d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Unless required by applicable law or agreed to in writing, software
15d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * distributed under the License is distributed on an "AS IS" BASIS,
16d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * See the License for the specific language governing permissions and
18d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * limitations under the License.
19d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */
20d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpackage org.jivesoftware.smackx.pubsub;
21d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
22d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.util.ArrayList;
23d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.util.Collection;
24d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.util.Iterator;
25d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.util.List;
26d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.util.concurrent.ConcurrentHashMap;
27d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
28d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smack.PacketListener;
29d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smack.Connection;
30d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smack.XMPPException;
31d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smack.filter.OrFilter;
32d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smack.filter.PacketFilter;
33d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smack.packet.Message;
34d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smack.packet.Packet;
35d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smack.packet.PacketExtension;
36d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smack.packet.IQ.Type;
37d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smackx.Form;
38d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smackx.packet.DelayInformation;
39d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smackx.packet.DiscoverInfo;
40d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smackx.packet.Header;
41d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smackx.packet.HeadersExtension;
42d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smackx.pubsub.listener.ItemDeleteListener;
43d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smackx.pubsub.listener.ItemEventListener;
44d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smackx.pubsub.listener.NodeConfigListener;
45d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smackx.pubsub.packet.PubSub;
46d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smackx.pubsub.packet.PubSubNamespace;
47d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smackx.pubsub.packet.SyncPacketSend;
48d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smackx.pubsub.util.NodeUtils;
49d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
50d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenabstract public class Node
51d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen{
52d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	protected Connection con;
53d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	protected String id;
54d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	protected String to;
55d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
56d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	protected ConcurrentHashMap<ItemEventListener<Item>, PacketListener> itemEventToListenerMap = new ConcurrentHashMap<ItemEventListener<Item>, PacketListener>();
57d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	protected ConcurrentHashMap<ItemDeleteListener, PacketListener> itemDeleteToListenerMap = new ConcurrentHashMap<ItemDeleteListener, PacketListener>();
58d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	protected ConcurrentHashMap<NodeConfigListener, PacketListener> configEventToListenerMap = new ConcurrentHashMap<NodeConfigListener, PacketListener>();
59d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
60d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	/**
61d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * Construct a node associated to the supplied connection with the specified
62d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * node id.
63d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 *
64d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * @param connection The connection the node is associated with
65d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * @param nodeName The node id
66d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 */
67d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	Node(Connection connection, String nodeName)
68d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	{
69d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		con = connection;
70d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		id = nodeName;
71d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
72d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
73d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	/**
74d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * Some XMPP servers may require a specific service to be addressed on the
75d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * server.
76d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 *
77d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 *   For example, OpenFire requires the server to be prefixed by <b>pubsub</b>
78d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 */
79d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	void setTo(String toAddress)
80d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	{
81d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		to = toAddress;
82d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
83d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
84d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	/**
85d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * Get the NodeId
86d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 *
87d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * @return the node id
88d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 */
89d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	public String getId()
90d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	{
91d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		return id;
92d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
93d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	/**
94d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * Returns a configuration form, from which you can create an answer form to be submitted
95d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * via the {@link #sendConfigurationForm(Form)}.
96d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 *
97d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * @return the configuration form
98d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 */
99d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	public ConfigureForm getNodeConfiguration()
100d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		throws XMPPException
101d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	{
102d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		Packet reply = sendPubsubPacket(Type.GET, new NodeExtension(PubSubElementType.CONFIGURE_OWNER, getId()), PubSubNamespace.OWNER);
103d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		return NodeUtils.getFormFromPacket(reply, PubSubElementType.CONFIGURE_OWNER);
104d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
105d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
106d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	/**
107d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * Update the configuration with the contents of the new {@link Form}
108d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 *
109d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * @param submitForm
110d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 */
111d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	public void sendConfigurationForm(Form submitForm)
112d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		throws XMPPException
113d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	{
114d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		PubSub packet = createPubsubPacket(Type.SET, new FormNode(FormNodeType.CONFIGURE_OWNER, getId(), submitForm), PubSubNamespace.OWNER);
115d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		SyncPacketSend.getReply(con, packet);
116d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
117d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
118d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	/**
119d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * Discover node information in standard {@link DiscoverInfo} format.
120d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 *
121d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * @return The discovery information about the node.
122d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 *
123d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * @throws XMPPException
124d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 */
125d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	public DiscoverInfo discoverInfo()
126d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		throws XMPPException
127d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	{
128d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		DiscoverInfo info = new DiscoverInfo();
129d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		info.setTo(to);
130d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		info.setNode(getId());
131d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		return (DiscoverInfo)SyncPacketSend.getReply(con, info);
132d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
133d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
134d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	/**
135d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * Get the subscriptions currently associated with this node.
136d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 *
137d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * @return List of {@link Subscription}
138d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 *
139d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * @throws XMPPException
140d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 */
141d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	public List<Subscription> getSubscriptions()
142d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		throws XMPPException
143d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	{
144d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		PubSub reply = (PubSub)sendPubsubPacket(Type.GET, new NodeExtension(PubSubElementType.SUBSCRIPTIONS, getId()));
145d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		SubscriptionsExtension subElem = (SubscriptionsExtension)reply.getExtension(PubSubElementType.SUBSCRIPTIONS);
146d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		return subElem.getSubscriptions();
147d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
148d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
149d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	/**
150d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * The user subscribes to the node using the supplied jid.  The
151d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * bare jid portion of this one must match the jid for the connection.
152d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 *
153d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * Please note that the {@link Subscription.State} should be checked
154d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * on return since more actions may be required by the caller.
155d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * {@link Subscription.State#pending} - The owner must approve the subscription
156d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * request before messages will be received.
157d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * {@link Subscription.State#unconfigured} - If the {@link Subscription#isConfigRequired()} is true,
158d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * the caller must configure the subscription before messages will be received.  If it is false
159d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * the caller can configure it but is not required to do so.
160d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * @param jid The jid to subscribe as.
161d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * @return The subscription
162d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * @exception XMPPException
163d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 */
164d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	public Subscription subscribe(String jid)
165d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		throws XMPPException
166d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	{
167d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		PubSub reply = (PubSub)sendPubsubPacket(Type.SET, new SubscribeExtension(jid, getId()));
168d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		return (Subscription)reply.getExtension(PubSubElementType.SUBSCRIPTION);
169d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
170d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
171d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	/**
172d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * The user subscribes to the node using the supplied jid and subscription
173d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * options.  The bare jid portion of this one must match the jid for the
174d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * connection.
175d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 *
176d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * Please note that the {@link Subscription.State} should be checked
177d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * on return since more actions may be required by the caller.
178d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * {@link Subscription.State#pending} - The owner must approve the subscription
179d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * request before messages will be received.
180d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * {@link Subscription.State#unconfigured} - If the {@link Subscription#isConfigRequired()} is true,
181d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * the caller must configure the subscription before messages will be received.  If it is false
182d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * the caller can configure it but is not required to do so.
183d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * @param jid The jid to subscribe as.
184d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * @return The subscription
185d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * @exception XMPPException
186d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 */
187d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	public Subscription subscribe(String jid, SubscribeForm subForm)
188d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		throws XMPPException
189d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	{
190d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		PubSub request = createPubsubPacket(Type.SET, new SubscribeExtension(jid, getId()));
191d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		request.addExtension(new FormNode(FormNodeType.OPTIONS, subForm));
192d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		PubSub reply = (PubSub)PubSubManager.sendPubsubPacket(con, jid, Type.SET, request);
193d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		return (Subscription)reply.getExtension(PubSubElementType.SUBSCRIPTION);
194d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
195d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
196d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	/**
197d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * Remove the subscription related to the specified JID.  This will only
198d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * work if there is only 1 subscription.  If there are multiple subscriptions,
199d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * use {@link #unsubscribe(String, String)}.
200d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 *
201d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * @param jid The JID used to subscribe to the node
202d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 *
203d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * @throws XMPPException
204d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 */
205d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	public void unsubscribe(String jid)
206d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		throws XMPPException
207d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	{
208d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		unsubscribe(jid, null);
209d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
210d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
211d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	/**
212d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * Remove the specific subscription related to the specified JID.
213d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 *
214d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * @param jid The JID used to subscribe to the node
215d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * @param subscriptionId The id of the subscription being removed
216d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 *
217d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * @throws XMPPException
218d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 */
219d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	public void unsubscribe(String jid, String subscriptionId)
220d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		throws XMPPException
221d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	{
222d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		sendPubsubPacket(Type.SET, new UnsubscribeExtension(jid, getId(), subscriptionId));
223d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
224d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
225d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	/**
226d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * Returns a SubscribeForm for subscriptions, from which you can create an answer form to be submitted
227d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * via the {@link #sendConfigurationForm(Form)}.
228d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 *
229d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * @return A subscription options form
230d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 *
231d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * @throws XMPPException
232d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 */
233d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	public SubscribeForm getSubscriptionOptions(String jid)
234d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		throws XMPPException
235d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	{
236d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		return getSubscriptionOptions(jid, null);
237d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
238d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
239d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
240d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	/**
241d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * Get the options for configuring the specified subscription.
242d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 *
243d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * @param jid JID the subscription is registered under
244d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * @param subscriptionId The subscription id
245d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 *
246d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * @return The subscription option form
247d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 *
248d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * @throws XMPPException
249d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 */
250d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	public SubscribeForm getSubscriptionOptions(String jid, String subscriptionId)
251d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		throws XMPPException
252d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	{
253d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		PubSub packet = (PubSub)sendPubsubPacket(Type.GET, new OptionsExtension(jid, getId(), subscriptionId));
254d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		FormNode ext = (FormNode)packet.getExtension(PubSubElementType.OPTIONS);
255d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		return new SubscribeForm(ext.getForm());
256d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
257d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
258d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	/**
259d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * Register a listener for item publication events.  This
260d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * listener will get called whenever an item is published to
261d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * this node.
262d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 *
263d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * @param listener The handler for the event
264d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 */
265d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	public void addItemEventListener(ItemEventListener listener)
266d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	{
267d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		PacketListener conListener = new ItemEventTranslator(listener);
268d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		itemEventToListenerMap.put(listener, conListener);
269d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		con.addPacketListener(conListener, new EventContentFilter(EventElementType.items.toString(), "item"));
270d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
271d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
272d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	/**
273d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * Unregister a listener for publication events.
274d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 *
275d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * @param listener The handler to unregister
276d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 */
277d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	public void removeItemEventListener(ItemEventListener listener)
278d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	{
279d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		PacketListener conListener = itemEventToListenerMap.remove(listener);
280d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
281d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		if (conListener != null)
282d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			con.removePacketListener(conListener);
283d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
284d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
285d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	/**
286d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * Register a listener for configuration events.  This listener
287d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * will get called whenever the node's configuration changes.
288d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 *
289d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * @param listener The handler for the event
290d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 */
291d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	public void addConfigurationListener(NodeConfigListener listener)
292d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	{
293d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		PacketListener conListener = new NodeConfigTranslator(listener);
294d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		configEventToListenerMap.put(listener, conListener);
295d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		con.addPacketListener(conListener, new EventContentFilter(EventElementType.configuration.toString()));
296d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
297d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
298d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	/**
299d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * Unregister a listener for configuration events.
300d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 *
301d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * @param listener The handler to unregister
302d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 */
303d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	public void removeConfigurationListener(NodeConfigListener listener)
304d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	{
305d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		PacketListener conListener = configEventToListenerMap .remove(listener);
306d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
307d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		if (conListener != null)
308d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			con.removePacketListener(conListener);
309d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
310d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
311d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	/**
312d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * Register an listener for item delete events.  This listener
313d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * gets called whenever an item is deleted from the node.
314d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 *
315d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * @param listener The handler for the event
316d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 */
317d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	public void addItemDeleteListener(ItemDeleteListener listener)
318d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	{
319d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		PacketListener delListener = new ItemDeleteTranslator(listener);
320d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		itemDeleteToListenerMap.put(listener, delListener);
321d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		EventContentFilter deleteItem = new EventContentFilter(EventElementType.items.toString(), "retract");
322d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		EventContentFilter purge = new EventContentFilter(EventElementType.purge.toString());
323d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
324d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		con.addPacketListener(delListener, new OrFilter(deleteItem, purge));
325d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
326d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
327d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	/**
328d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * Unregister a listener for item delete events.
329d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 *
330d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * @param listener The handler to unregister
331d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 */
332d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	public void removeItemDeleteListener(ItemDeleteListener listener)
333d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	{
334d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		PacketListener conListener = itemDeleteToListenerMap .remove(listener);
335d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
336d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		if (conListener != null)
337d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			con.removePacketListener(conListener);
338d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
339d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
340d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	@Override
341d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	public String toString()
342d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	{
343d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		return super.toString() + " " + getClass().getName() + " id: " + id;
344d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
345d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
346d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	protected PubSub createPubsubPacket(Type type, PacketExtension ext)
347d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	{
348d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		return createPubsubPacket(type, ext, null);
349d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
350d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
351d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	protected PubSub createPubsubPacket(Type type, PacketExtension ext, PubSubNamespace ns)
352d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	{
353d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		return PubSubManager.createPubsubPacket(to, type, ext, ns);
354d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
355d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
356d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	protected Packet sendPubsubPacket(Type type, NodeExtension ext)
357d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		throws XMPPException
358d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	{
359d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		return PubSubManager.sendPubsubPacket(con, to, type, ext);
360d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
361d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
362d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	protected Packet sendPubsubPacket(Type type, NodeExtension ext, PubSubNamespace ns)
363d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		throws XMPPException
364d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	{
365d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		return PubSubManager.sendPubsubPacket(con, to, type, ext, ns);
366d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
367d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
368d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
369d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	private static List<String> getSubscriptionIds(Packet packet)
370d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	{
371d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		HeadersExtension headers = (HeadersExtension)packet.getExtension("headers", "http://jabber.org/protocol/shim");
372d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		List<String> values = null;
373d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
374d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		if (headers != null)
375d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		{
376d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			values = new ArrayList<String>(headers.getHeaders().size());
377d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
378d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			for (Header header : headers.getHeaders())
379d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			{
380d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				values.add(header.getValue());
381d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			}
382d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		}
383d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		return values;
384d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
385d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
386d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	/**
387d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * This class translates low level item publication events into api level objects for
388d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * user consumption.
389d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 *
390d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * @author Robin Collier
391d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 */
392d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	public class ItemEventTranslator implements PacketListener
393d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	{
394d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		private ItemEventListener listener;
395d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
396d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		public ItemEventTranslator(ItemEventListener eventListener)
397d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		{
398d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			listener = eventListener;
399d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		}
400d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
401d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		public void processPacket(Packet packet)
402d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		{
403d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	        EventElement event = (EventElement)packet.getExtension("event", PubSubNamespace.EVENT.getXmlns());
404d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			ItemsExtension itemsElem = (ItemsExtension)event.getEvent();
405d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			DelayInformation delay = (DelayInformation)packet.getExtension("delay", "urn:xmpp:delay");
406d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
407d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			// If there was no delay based on XEP-0203, then try XEP-0091 for backward compatibility
408d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			if (delay == null)
409d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			{
410d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				delay = (DelayInformation)packet.getExtension("x", "jabber:x:delay");
411d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			}
412d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			ItemPublishEvent eventItems = new ItemPublishEvent(itemsElem.getNode(), (List<Item>)itemsElem.getItems(), getSubscriptionIds(packet), (delay == null ? null : delay.getStamp()));
413d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			listener.handlePublishedItems(eventItems);
414d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		}
415d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
416d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
417d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	/**
418d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * This class translates low level item deletion events into api level objects for
419d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * user consumption.
420d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 *
421d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * @author Robin Collier
422d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 */
423d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	public class ItemDeleteTranslator implements PacketListener
424d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	{
425d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		private ItemDeleteListener listener;
426d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
427d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		public ItemDeleteTranslator(ItemDeleteListener eventListener)
428d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		{
429d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			listener = eventListener;
430d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		}
431d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
432d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		public void processPacket(Packet packet)
433d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		{
434d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	        EventElement event = (EventElement)packet.getExtension("event", PubSubNamespace.EVENT.getXmlns());
435d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
436d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	        List<PacketExtension> extList = event.getExtensions();
437d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
438d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	        if (extList.get(0).getElementName().equals(PubSubElementType.PURGE_EVENT.getElementName()))
439d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	        {
440d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	        	listener.handlePurge();
441d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	        }
442d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	        else
443d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	        {
444d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				ItemsExtension itemsElem = (ItemsExtension)event.getEvent();
445d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				Collection<? extends PacketExtension> pubItems = itemsElem.getItems();
446d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				Iterator<RetractItem> it = (Iterator<RetractItem>)pubItems.iterator();
447d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				List<String> items = new ArrayList<String>(pubItems.size());
448d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
449d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				while (it.hasNext())
450d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				{
451d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen					RetractItem item = it.next();
452d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen					items.add(item.getId());
453d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				}
454d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
455d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				ItemDeleteEvent eventItems = new ItemDeleteEvent(itemsElem.getNode(), items, getSubscriptionIds(packet));
456d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				listener.handleDeletedItems(eventItems);
457d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	        }
458d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		}
459d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
460d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
461d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	/**
462d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * This class translates low level node configuration events into api level objects for
463d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * user consumption.
464d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 *
465d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * @author Robin Collier
466d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 */
467d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	public class NodeConfigTranslator implements PacketListener
468d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	{
469d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		private NodeConfigListener listener;
470d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
471d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		public NodeConfigTranslator(NodeConfigListener eventListener)
472d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		{
473d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			listener = eventListener;
474d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		}
475d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
476d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		public void processPacket(Packet packet)
477d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		{
478d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	        EventElement event = (EventElement)packet.getExtension("event", PubSubNamespace.EVENT.getXmlns());
479d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			ConfigurationEvent config = (ConfigurationEvent)event.getEvent();
480d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
481d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			listener.handleNodeConfiguration(config);
482d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		}
483d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
484d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
485d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	/**
486d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * Filter for {@link PacketListener} to filter out events not specific to the
487d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * event type expected for this node.
488d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 *
489d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 * @author Robin Collier
490d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	 */
491d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	class EventContentFilter implements PacketFilter
492d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	{
493d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		private String firstElement;
494d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		private String secondElement;
495d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
496d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		EventContentFilter(String elementName)
497d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		{
498d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			firstElement = elementName;
499d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		}
500d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
501d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		EventContentFilter(String firstLevelEelement, String secondLevelElement)
502d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		{
503d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			firstElement = firstLevelEelement;
504d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			secondElement = secondLevelElement;
505d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		}
506d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
507d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		public boolean accept(Packet packet)
508d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		{
509d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			if (!(packet instanceof Message))
510d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				return false;
511d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
512d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			EventElement event = (EventElement)packet.getExtension("event", PubSubNamespace.EVENT.getXmlns());
513d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
514d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			if (event == null)
515d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				return false;
516d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
517d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			NodeExtension embedEvent = event.getEvent();
518d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
519d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			if (embedEvent == null)
520d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				return false;
521d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
522d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			if (embedEvent.getElementName().equals(firstElement))
523d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			{
524d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				if (!embedEvent.getNode().equals(getId()))
525d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen					return false;
526d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
527d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				if (secondElement == null)
528d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen					return true;
529d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
530d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				if (embedEvent instanceof EmbeddedPacketExtension)
531d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				{
532d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen					List<PacketExtension> secondLevelList = ((EmbeddedPacketExtension)embedEvent).getExtensions();
533d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
534d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen					if (secondLevelList.size() > 0 && secondLevelList.get(0).getElementName().equals(secondElement))
535d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen						return true;
536d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen				}
537d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			}
538d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			return false;
539d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		}
540d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
541d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
542