KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jivesoftware > messenger > handler > IQRosterHandler


1 /**
2  * $RCSfile: IQRosterHandler.java,v $
3  * $Revision: 1.20 $
4  * $Date: 2005/03/14 18:59:37 $
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.handler;
13
14 import org.jivesoftware.messenger.*;
15 import org.jivesoftware.messenger.auth.UnauthorizedException;
16 import org.jivesoftware.messenger.disco.ServerFeaturesProvider;
17 import org.jivesoftware.messenger.roster.Roster;
18 import org.jivesoftware.messenger.roster.RosterItem;
19 import org.jivesoftware.messenger.user.User;
20 import org.jivesoftware.messenger.user.UserAlreadyExistsException;
21 import org.jivesoftware.messenger.user.UserManager;
22 import org.jivesoftware.messenger.user.UserNotFoundException;
23 import org.jivesoftware.util.LocaleUtils;
24 import org.jivesoftware.util.Log;
25 import org.xmpp.packet.IQ;
26 import org.xmpp.packet.JID;
27 import org.xmpp.packet.Packet;
28 import org.xmpp.packet.PacketError;
29
30 import java.util.ArrayList JavaDoc;
31 import java.util.Iterator JavaDoc;
32
33 /**
34  * Implements the TYPE_IQ jabber:iq:roster protocol. Clients
35  * use this protocol to retrieve, update, and rosterMonitor roster
36  * entries (buddy lists). The server manages the basics of
37  * roster subscriptions and roster updates based on presence
38  * and iq:roster packets, while the client maintains the user
39  * interface aspects of rosters such as organizing roster
40  * entries into groups.
41  * <p/>
42  * A 'get' query retrieves a snapshot of the roster.
43  * A 'set' query updates the roster (typically with new group info).
44  * The server sends 'set' updates asynchronously when roster
45  * entries change status.
46  * <p/>
47  * Currently an empty implementation to allow usage with normal
48  * clients. Future implementation needed.
49  * <p/>
50  * <h2>Assumptions</h2>
51  * This handler assumes that the request is addressed to the server.
52  * An appropriate TYPE_IQ tag matcher should be placed in front of this
53  * one to route TYPE_IQ requests not addressed to the server to
54  * another channel (probably for direct delivery to the recipient).
55  * <p/>
56  * <h2>Warning</h2>
57  * There should be a way of determining whether a session has
58  * authorization to access this feature. I'm not sure it is a good
59  * idea to do authorization in each handler. It would be nice if
60  * the framework could assert authorization policies across channels.
61  *
62  * @author Iain Shigeoka
63  */

64 public class IQRosterHandler extends IQHandler implements ServerFeaturesProvider {
65
66     private IQHandlerInfo info;
67
68     private UserManager userManager;
69     private XMPPServer localServer;
70     private SessionManager sessionManager;
71     private PacketRouter router;
72
73     public IQRosterHandler() {
74         super("XMPP Roster Handler");
75         info = new IQHandlerInfo("query", "jabber:iq:roster");
76     }
77
78     /**
79      * Handles all roster queries. There are two major types of queries:
80      *
81      * <ul>
82      * <li>Roster remove - A forced removal of items from a roster. Roster
83      * removals are the only roster queries allowed to
84      * directly affect the roster from another user.
85      * </li>
86      * <li>Roster management - A local user looking up or updating their
87      * roster.
88      * </li>
89      * </ul>
90      *
91      * @param packet The update packet
92      * @return The reply or null if no reply
93      */

94     public IQ handleIQ(IQ packet) throws UnauthorizedException, PacketException {
95         try {
96             IQ returnPacket = null;
97             org.xmpp.packet.Roster roster = (org.xmpp.packet.Roster)packet;
98
99             JID recipientJID = packet.getTo();
100
101             // The packet is bound for the server and must be roster management
102
if (recipientJID == null || recipientJID.getNode() == null) {
103                 returnPacket = manageRoster(roster);
104             }
105             // The packet must be a roster removal from a foreign domain user.
106
else {
107                 removeRosterItem(roster);
108             }
109             return returnPacket;
110         }
111         catch (SharedGroupException e) {
112             IQ result = IQ.createResultIQ(packet);
113             result.setChildElement(packet.getChildElement().createCopy());
114             result.setError(PacketError.Condition.not_acceptable);
115             return result;
116         }
117         catch (Exception JavaDoc e) {
118             Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
119         }
120         return null;
121     }
122
123     /**
124      * Remove a roster item. At this stage, this is recipient who has received
125      * a roster update. We must check that it is a removal, and if so, remove
126      * the roster item based on the sender's id rather than what is in the item
127      * listing itself.
128      *
129      * @param packet The packet suspected of containing a roster removal
130      */

131     private void removeRosterItem(org.xmpp.packet.Roster packet) throws UnauthorizedException,
132             SharedGroupException {
133         JID recipientJID = packet.getTo();
134         JID senderJID = packet.getFrom();
135         try {
136             for (org.xmpp.packet.Roster.Item packetItem : packet.getItems()) {
137                 if (packetItem.getSubscription() == org.xmpp.packet.Roster.Subscription.remove) {
138                     Roster roster = userManager.getUser(recipientJID.getNode()).getRoster();
139                     RosterItem item = roster.getRosterItem(senderJID);
140                     roster.deleteRosterItem(senderJID, true);
141                     item.setSubStatus(RosterItem.SUB_REMOVE);
142                     item.setSubStatus(RosterItem.SUB_NONE);
143
144                     Packet itemPacket = packet.createCopy();
145                     sessionManager.userBroadcast(recipientJID.getNode(), itemPacket);
146                 }
147             }
148         }
149         catch (UserNotFoundException e) {
150             throw new UnauthorizedException(e);
151         }
152     }
153
154     /**
155      * The packet is a typical 'set' or 'get' update targeted at the server.
156      * Notice that the set could be a roster removal in which case we have to
157      * generate a local roster removal update as well as a new roster removal
158      * to send to the the roster item's owner.
159      *
160      * @param packet The packet that triggered this update
161      * @return Either a response to the roster update or null if the packet is corrupt and the session was closed down
162      */

163     private IQ manageRoster(org.xmpp.packet.Roster packet) throws UnauthorizedException,
164             UserAlreadyExistsException, SharedGroupException {
165
166         IQ returnPacket = null;
167         ClientSession session = sessionManager.getSession(packet.getFrom());
168
169         IQ.Type type = packet.getType();
170
171         try {
172             User sessionUser = userManager.getUser(session.getUsername());
173             Roster cachedRoster = sessionUser.getRoster();
174             if (IQ.Type.get == type) {
175                 returnPacket = cachedRoster.getReset();
176                 returnPacket.setType(IQ.Type.result);
177                 returnPacket.setTo(session.getAddress());
178                 returnPacket.setID(packet.getID());
179                 // Force delivery of the response because we need to trigger
180
// a presence probe from all contacts
181
deliverer.deliver(returnPacket);
182                 returnPacket = null;
183             }
184             else if (IQ.Type.set == type) {
185
186                 for (org.xmpp.packet.Roster.Item item : packet.getItems()) {
187                     if (item.getSubscription() == org.xmpp.packet.Roster.Subscription.remove) {
188                         removeItem(cachedRoster, packet.getFrom(), item);
189                     }
190                     else {
191                         if (cachedRoster.isRosterItem(item.getJID())) {
192                             // existing item
193
RosterItem cachedItem = cachedRoster.getRosterItem(item.getJID());
194                             cachedItem.setAsCopyOf(item);
195                             cachedRoster.updateRosterItem(cachedItem);
196                         }
197                         else {
198                             // new item
199
cachedRoster.createRosterItem(item);
200                         }
201                     }
202                 }
203                 returnPacket = IQ.createResultIQ(packet);
204             }
205         }
206         catch (UserNotFoundException e) {
207             throw new UnauthorizedException(e);
208         }
209
210         return returnPacket;
211
212     }
213
214     /**
215      * Remove the roster item from the sender's roster (and possibly the recipient's).
216      * Actual roster removal is done in the removeItem(Roster,RosterItem) method.
217      *
218      * @param roster The sender's roster.
219      * @param sender The JID of the sender of the removal request
220      * @param item The removal item element
221      */

222     private void removeItem(org.jivesoftware.messenger.roster.Roster roster, JID sender,
223             org.xmpp.packet.Roster.Item item) throws SharedGroupException {
224         JID recipient = item.getJID();
225         // Remove recipient from the sender's roster
226
roster.deleteRosterItem(item.getJID(), true);
227         // Forward set packet to the subscriber
228
if (localServer.isLocal(recipient)) { // Recipient is local so let's handle it here
229
try {
230                 Roster recipientRoster = userManager.getUser(recipient.getNode()).getRoster();
231                 recipientRoster.deleteRosterItem(sender, true);
232             }
233             catch (UserNotFoundException e) {
234             }
235         }
236         else {
237             // Recipient is remote so we just forward the packet to them
238
String JavaDoc serverDomain = localServer.getServerInfo().getName();
239             // Check if the recipient may be hosted by this server
240
if (!recipient.getDomain().contains(serverDomain)) {
241                 // TODO Implete when s2s is implemented
242
}
243             else {
244                 Packet removePacket = createRemoveForward(sender, recipient);
245                 router.route(removePacket);
246             }
247         }
248     }
249
250     /**
251      * Creates a forwarded removal packet.
252      *
253      * @param from The sender address to use
254      * @param to The recipient address to use
255      * @return The forwarded packet generated
256      */

257     private Packet createRemoveForward(JID from, JID to) {
258         org.xmpp.packet.Roster response = new org.xmpp.packet.Roster(IQ.Type.set);
259         response.setFrom(from);
260         response.setTo(to);
261         response.addItem(from, org.xmpp.packet.Roster.Subscription.remove);
262
263         return response;
264     }
265
266     public void initialize(XMPPServer server) {
267         super.initialize(server);
268         localServer = server;
269         userManager = server.getUserManager();
270         router = server.getPacketRouter();
271         sessionManager = server.getSessionManager();
272     }
273
274     public IQHandlerInfo getInfo() {
275         return info;
276     }
277
278     public Iterator JavaDoc getFeatures() {
279         ArrayList JavaDoc features = new ArrayList JavaDoc();
280         features.add("jabber:iq:roster");
281         return features.iterator();
282     }
283 }
Popular Tags