KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jivesoftware > messenger > disco > IQDiscoItemsHandler


1 /**
2  * $RCSfile: IQDiscoItemsHandler.java,v $
3  * $Revision: 1.19 $
4  * $Date: 2005/07/26 05:23:45 $
5  *
6  * Copyright (C) 2004 Jive Software. All rights reserved.
7  *
8  * This software is published under the terms of the GNU Public License (GPL),
9  * a copy of which is included in this distribution.
10  */

11
12 package org.jivesoftware.messenger.disco;
13
14 import org.dom4j.DocumentHelper;
15 import org.dom4j.Element;
16 import org.dom4j.QName;
17 import org.jivesoftware.messenger.IQHandlerInfo;
18 import org.jivesoftware.messenger.Session;
19 import org.jivesoftware.messenger.SessionManager;
20 import org.jivesoftware.messenger.XMPPServer;
21 import org.jivesoftware.messenger.auth.UnauthorizedException;
22 import org.jivesoftware.messenger.handler.IQHandler;
23 import org.jivesoftware.messenger.roster.RosterItem;
24 import org.jivesoftware.messenger.user.User;
25 import org.jivesoftware.messenger.user.UserManager;
26 import org.jivesoftware.messenger.user.UserNotFoundException;
27 import org.xmpp.packet.IQ;
28 import org.xmpp.packet.JID;
29 import org.xmpp.packet.PacketError;
30
31 import java.util.*;
32 import java.util.concurrent.ConcurrentHashMap JavaDoc;
33
34 /**
35  * IQDiscoItemsHandler is responsible for handling disco#items requests. This class holds a map with
36  * the main entities and the associated DiscoItemsProvider. We are considering the host of the
37  * recipient JIDs as main entities. It's the DiscoItemsProvider responsibility to provide the items
38  * associated with the JID's name together with any possible requested node.<p>
39  * <p/>
40  * For example, let's have in the entities map the following entries: "localhost" and
41  * "conference.localhost". Associated with each entry we have different DiscoItemsProvider. Now we
42  * receive a disco#items request for the following JID: "room@conference.localhost" which is a disco
43  * request for a MUC room. So IQDiscoItemsHandler will look for the DiscoItemsProvider associated
44  * with the JID's host which in this case is "conference.localhost". Once we have located the
45  * provider we will delegate to the provider the responsibility to provide the items specific to
46  * the JID's name which in this case is "room". Depending on the implementation, the items could be
47  * the list of existing occupants if that information is publicly available. Finally, after we have
48  * collected all the items provided by the provider we will add them to the reply. On the other
49  * hand, if no provider was found or the provider has no information for the requested name/node
50  * then a not-found error will be returned.<p>
51  * <p/>
52  * Publishing of client items is still not supported.
53  *
54  * @author Gaston Dombiak
55  */

56 public class IQDiscoItemsHandler extends IQHandler implements ServerFeaturesProvider {
57
58     private HashMap JavaDoc entities = new HashMap JavaDoc();
59     private List<Element> serverItems = new ArrayList<Element>();
60     private Map JavaDoc<String JavaDoc, DiscoItemsProvider> serverNodeProviders =
61             new ConcurrentHashMap JavaDoc<String JavaDoc, DiscoItemsProvider>();
62     private IQHandlerInfo info;
63     private IQDiscoInfoHandler infoHandler;
64
65     public IQDiscoItemsHandler() {
66         super("XMPP Disco Items Handler");
67         info = new IQHandlerInfo("query", "http://jabber.org/protocol/disco#items");
68     }
69
70     public IQHandlerInfo getInfo() {
71         return info;
72     }
73
74     public IQ handleIQ(IQ packet) throws UnauthorizedException {
75         // TODO Let configure an authorization policy (ACL?). Currently anyone can discover items.
76

77         // Create a copy of the sent pack that will be used as the reply
78
// we only need to add the requested items to the reply if any otherwise add
79
// a not found error
80
IQ reply = IQ.createResultIQ(packet);
81         
82         // TODO Implement publishing client items
83
if (IQ.Type.set == packet.getType()) {
84             reply.setChildElement(packet.getChildElement().createCopy());
85             reply.setError(PacketError.Condition.feature_not_implemented);
86             return reply;
87         }
88
89         // Look for a DiscoItemsProvider associated with the requested entity.
90
// We consider the host of the recipient JID of the packet as the entity. It's the
91
// DiscoItemsProvider responsibility to provide the items associated with the JID's name
92
// together with any possible requested node.
93
DiscoItemsProvider itemsProvider = getProvider(packet.getTo() == null ?
94                 XMPPServer.getInstance().getServerInfo().getName() : packet.getTo().getDomain());
95         if (itemsProvider != null) {
96             // Get the JID's name
97
String JavaDoc name = packet.getTo() == null ? null : packet.getTo().getNode();
98             if (name == null || name.trim().length() == 0) {
99                 name = null;
100             }
101             // Get the requested node
102
Element iq = packet.getChildElement();
103             String JavaDoc node = iq.attributeValue("node");
104
105             // Check if we have items associated with the requested name and node
106
Iterator<Element> itemsItr = itemsProvider.getItems(name, node, packet.getFrom());
107             if (itemsItr != null) {
108                 reply.setChildElement(iq.createCopy());
109                 Element queryElement = reply.getChildElement();
110
111                 // Add to the reply all the items provided by the DiscoItemsProvider
112
Element item;
113                 while (itemsItr.hasNext()) {
114                     item = itemsItr.next();
115                     item.setQName(new QName(item.getName(), queryElement.getNamespace()));
116                     queryElement.add(item.createCopy());
117                 }
118                 ;
119             }
120             else {
121                 // If the DiscoItemsProvider has no items for the requested name and node
122
// then answer a not found error
123
reply.setChildElement(packet.getChildElement().createCopy());
124                 reply.setError(PacketError.Condition.item_not_found);
125             }
126         }
127         else {
128             // If we didn't find a DiscoItemsProvider then answer a not found error
129
reply.setChildElement(packet.getChildElement().createCopy());
130             reply.setError(PacketError.Condition.item_not_found);
131         }
132
133         return reply;
134     }
135
136     /**
137      * Returns the DiscoItemsProvider responsible for providing the items related to a given entity
138      * or null if none was found.
139      *
140      * @param name the name of the identity.
141      * @return the DiscoItemsProvider responsible for providing the items related to a given entity
142      * or null if none was found.
143      */

144     private DiscoItemsProvider getProvider(String JavaDoc name) {
145         return (DiscoItemsProvider)entities.get(name);
146     }
147
148     /**
149      * Sets that a given DiscoItemsProvider will provide the items related to a given entity. This
150      * message must be used when new modules (e.g. MUC) are implemented and need to provide
151      * the items related to them.
152      *
153      * @param name the name of the entity.
154      * @param provider the DiscoItemsProvider that will provide the entity's items.
155      */

156     protected void setProvider(String JavaDoc name, DiscoItemsProvider provider) {
157         entities.put(name, provider);
158     }
159
160     /**
161      * Removes the DiscoItemsProvider related to a given entity.
162      *
163      * @param name the name of the entity.
164      */

165     protected void removeProvider(String JavaDoc name) {
166         entities.remove(name);
167     }
168
169     /**
170      * Adds the items provided by the new service that implements the ServerItemsProvider
171      * interface. This information will be used whenever a disco for items is made against
172      * the server (i.e. the packet's target is the server).
173      * Example of item is: &lt;item jid='conference.localhost' name='Public chatrooms'/&gt;
174      *
175      * @param provider the ServerItemsProvider that provides new server items.
176      */

177     private void addServerItemsProvider(ServerItemsProvider provider) {
178         DiscoServerItem discoItem;
179         for (Iterator it = provider.getItems(); it.hasNext();) {
180             discoItem = (DiscoServerItem)it.next();
181             // Create a new element based on the provided DiscoItem
182
Element element = DocumentHelper.createElement("item");
183             element.addAttribute("jid", discoItem.getJID());
184             element.addAttribute("node", discoItem.getNode());
185             element.addAttribute("name", discoItem.getName());
186             // Add the element to the list of items related to the server
187
serverItems.add(element);
188             
189             // Add the new item as a valid entity that could receive info and items disco requests
190
String JavaDoc host = new JID(discoItem.getJID()).getDomain();
191             infoHandler.setProvider(host, discoItem.getDiscoInfoProvider());
192             setProvider(host, discoItem.getDiscoItemsProvider());
193         }
194     }
195
196     /**
197      * Sets the DiscoItemsProvider to use when a disco#items packet is sent to the server itself
198      * and the specified node. For instance, if node matches "http://jabber.org/protocol/offline"
199      * then a special DiscoItemsProvider should be use to return information about offline messages.
200      *
201      * @param node the node that the provider will handle.
202      * @param provider the DiscoItemsProvider that will handle disco#items packets sent with the
203      * specified node.
204      */

205     public void setServerNodeInfoProvider(String JavaDoc node, DiscoItemsProvider provider) {
206         serverNodeProviders.put(node, provider);
207     }
208
209     /**
210      * Removes the DiscoItemsProvider to use when a disco#items packet is sent to the server itself
211      * and the specified node.
212      *
213      * @param node the node that the provider was handling.
214      */

215     public void removeServerNodeInfoProvider(String JavaDoc node) {
216         serverNodeProviders.remove(node);
217     }
218
219     /**
220      * Registers a new disco item for a component. The jid attribute of the item will match the jid
221      * of the component and the name should be the name of the component discovered using disco.
222      *
223      * @param jid the jid of the component.
224      * @param name the discovered name of the component.
225      */

226     public void addComponentItem(String JavaDoc jid, String JavaDoc name) {
227         // A component may send his disco#info many times and we only want to have one item
228
// for the component so remove any element under the requested jid
229
removeComponentItem(jid);
230
231         // Create a new element based on the provided DiscoItem
232
Element element = DocumentHelper.createElement("item");
233         element.addAttribute("jid", jid);
234         element.addAttribute("name", name);
235         // Add the element to the list of items related to the server
236
serverItems.add(element);
237     }
238
239     /**
240      * Removes a disco item for a component that has been removed from the server.
241      *
242      * @param jid the jid of the component being removed.
243      */

244     public void removeComponentItem(String JavaDoc jid) {
245         for (Iterator<Element> it = serverItems.iterator(); it.hasNext();) {
246             if (jid.equals(it.next().attributeValue("jid"))) {
247                 it.remove();
248             }
249         }
250     }
251
252     public void initialize(XMPPServer server) {
253         super.initialize(server);
254         // Track the implementors of ServerItemsProvider so that we can collect the items
255
// provided by the server
256
infoHandler = server.getIQDiscoInfoHandler();
257         setProvider(server.getServerInfo().getName(), getServerItemsProvider());
258     }
259
260     public void start() throws IllegalStateException JavaDoc {
261         super.start();
262         for (ServerItemsProvider provider : XMPPServer.getInstance().getServerItemsProviders()) {
263             addServerItemsProvider(provider);
264         }
265     }
266
267     public Iterator getFeatures() {
268         ArrayList features = new ArrayList();
269         features.add("http://jabber.org/protocol/disco#items");
270         // TODO Comment out this line when publishing of client items is implemented
271
//features.add("http://jabber.org/protocol/disco#publish");
272
return features.iterator();
273     }
274
275     private DiscoItemsProvider getServerItemsProvider() {
276         DiscoItemsProvider discoItemsProvider = new DiscoItemsProvider() {
277             public Iterator<Element> getItems(String JavaDoc name, String JavaDoc node, JID senderJID) {
278                 if (node != null) {
279                     // Check if there is a provider for the requested node
280
if (serverNodeProviders.get(node) != null) {
281                         return serverNodeProviders.get(node).getItems(name, node, senderJID);
282                     }
283                     return null;
284                 }
285                 if (name == null) {
286                     return serverItems.iterator();
287                 }
288                 else {
289                     List<Element> answer = new ArrayList<Element>();
290                     try {
291                         User user = UserManager.getInstance().getUser(name);
292                         RosterItem item = user.getRoster().getRosterItem(senderJID);
293                         // If the requesting entity is subscribed to the account's presence then
294
// answer the user's "available resources"
295
if (item.getSubStatus() == RosterItem.SUB_FROM ||
296                                 item.getSubStatus() == RosterItem.SUB_BOTH) {
297                             for (Session session : SessionManager.getInstance().getSessions(name)) {
298                                 Element element = DocumentHelper.createElement("item");
299                                 element.addAttribute("jid", session.getAddress().toString());
300                                 answer.add(element);
301                             }
302                         }
303                         return answer.iterator();
304                     }
305                     catch (UserNotFoundException e) {
306                         return answer.iterator();
307                     }
308                 }
309             }
310         };
311         return discoItemsProvider;
312     }
313 }
Popular Tags