KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jivesoftware > messenger > spi > RoutingTableImpl


1 /**
2  * $RCSfile: RoutingTableImpl.java,v $
3  * $Revision: 1.14 $
4  * $Date: 2005/07/26 16:42:01 $
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.spi;
13
14 import org.jivesoftware.messenger.*;
15 import org.jivesoftware.messenger.component.InternalComponentManager;
16 import org.jivesoftware.messenger.server.OutgoingServerSession;
17 import org.jivesoftware.messenger.container.BasicModule;
18 import org.jivesoftware.util.Log;
19 import org.xmpp.packet.JID;
20
21 import java.util.*;
22 import java.util.concurrent.locks.ReadWriteLock JavaDoc;
23 import java.util.concurrent.locks.ReentrantReadWriteLock JavaDoc;
24 import java.util.concurrent.ConcurrentHashMap JavaDoc;
25
26 /**
27  * <p>Uses simple hashtables for table storage.</p>
28  * <p>Leaves in the tree are indicated by a PacketHandler, while branches are stored in hashtables.
29  * Traverse the tree according to an XMPPAddress' fields (host -> name -> resource) and when you
30  * hit a PacketHandler, you have found the handler for that node and all sub-nodes. </p>
31  *
32  * @author Iain Shigeoka
33  */

34 public class RoutingTableImpl extends BasicModule implements RoutingTable {
35
36     /**
37      * We need a three level tree built of hashtables: host -> name -> resource
38      */

39     private Map JavaDoc routes = new ConcurrentHashMap JavaDoc();
40
41     /**
42      * locks access to the routing tale
43      */

44     private ReadWriteLock JavaDoc routeLock = new ReentrantReadWriteLock JavaDoc();
45     private String JavaDoc serverName;
46     private InternalComponentManager componentManager;
47
48     public RoutingTableImpl() {
49         super("Routing table");
50         componentManager = InternalComponentManager.getInstance();
51     }
52
53     public void addRoute(JID node, RoutableChannelHandler destination) {
54
55         String JavaDoc nodeJID = node.getNode() == null ? "" : node.getNode();
56         String JavaDoc resourceJID = node.getResource() == null ? "" : node.getResource();
57
58         routeLock.writeLock().lock();
59         try {
60             if (destination instanceof ClientSession) {
61                 Object JavaDoc nameRoutes = routes.get(node.getDomain());
62                 if (nameRoutes == null) {
63                     nameRoutes = new Hashtable();
64                     routes.put(node.getDomain(), nameRoutes);
65                 }
66                 Object JavaDoc resourceRoutes = ((Hashtable)nameRoutes).get(nodeJID);
67                 if (resourceRoutes == null) {
68                     resourceRoutes = new Hashtable();
69                     ((Hashtable)nameRoutes).put(nodeJID, resourceRoutes);
70                 }
71                 ((Hashtable)resourceRoutes).put(resourceJID, destination);
72             }
73             else {
74                 routes.put(node.getDomain(), destination);
75             }
76         }
77         finally {
78             routeLock.writeLock().unlock();
79         }
80     }
81
82     public RoutableChannelHandler getRoute(JID node) throws NoSuchRouteException {
83         RoutableChannelHandler route = null;
84         String JavaDoc nodeJID = node.getNode() == null ? "" : node.getNode();
85         String JavaDoc resourceJID = node.getResource() == null ? "" : node.getResource();
86
87         // Check if the address belongs to a remote server
88
if (!serverName.equals(node.getDomain()) && routes.get(node.getDomain()) == null &&
89                 componentManager.getComponent(node.getDomain()) == null) {
90             // Authenticate this hostname with the remote server so that the remote server can
91
// accept packets from this server.
92
OutgoingServerSession.authenticateDomain(serverName, node.getDomain());
93         }
94
95         routeLock.readLock().lock();
96         try {
97             Object JavaDoc nameRoutes = routes.get(node.getDomain());
98             if (nameRoutes instanceof ChannelHandler) {
99                 route = (RoutableChannelHandler)nameRoutes;
100             }
101             else {
102                 Object JavaDoc resourceRoutes = ((Hashtable)nameRoutes).get(nodeJID);
103                 if (resourceRoutes instanceof ChannelHandler) {
104                     route = (RoutableChannelHandler)resourceRoutes;
105                 }
106                 else if (resourceRoutes != null) {
107                     route = (RoutableChannelHandler) ((Hashtable)resourceRoutes).get(resourceJID);
108                 }
109                 else {
110                     throw new NoSuchRouteException(node.toString());
111                 }
112             }
113         }
114         catch (Exception JavaDoc e) {
115             throw new NoSuchRouteException(node == null ? "No node" : node.toString(), e);
116         }
117         finally {
118             routeLock.readLock().unlock();
119         }
120
121         if (route == null) {
122             throw new NoSuchRouteException(node == null ? "No node" : node.toString());
123         }
124         return route;
125     }
126
127     public Iterator getRoutes(JID node) {
128         // Check if the address belongs to a remote server
129
if (!serverName.equals(node.getDomain()) && routes.get(node.getDomain()) == null &&
130                 componentManager.getComponent(node.getDomain()) == null) {
131             // Authenticate this hostname with the remote server so that the remote server can
132
// accept packets from this server.
133
OutgoingServerSession.authenticateDomain(serverName, node.getDomain());
134         }
135
136         LinkedList list = null;
137         routeLock.readLock().lock();
138         try {
139             if (node == null || node.getDomain() == null) {
140                 list = new LinkedList();
141                 getRoutes(list, routes);
142             }
143             else {
144                 Object JavaDoc nameRoutes = routes.get(node.getDomain());
145                 if (nameRoutes != null) {
146                     if (nameRoutes instanceof ChannelHandler) {
147                         list = new LinkedList();
148                         list.add(nameRoutes);
149                     }
150                     else if (node.getNode() == null) {
151                         list = new LinkedList();
152                         getRoutes(list, (Hashtable)nameRoutes);
153                     }
154                     else {
155                         Object JavaDoc resourceRoutes =
156                                 ((Hashtable)nameRoutes).get(node.getNode());
157                         if (resourceRoutes != null) {
158                             if (resourceRoutes instanceof ChannelHandler) {
159                                 list = new LinkedList();
160                                 list.add(resourceRoutes);
161                             }
162                             else if (node.getResource() == null || node.getResource().length() == 0) {
163                                 list = new LinkedList();
164                                 getRoutes(list, (Hashtable)resourceRoutes);
165                             }
166                             else {
167                                 Object JavaDoc entry =
168                                         ((Hashtable)resourceRoutes).get(node.getResource());
169                                 if (entry != null) {
170                                     list = new LinkedList();
171                                     list.add(entry);
172                                 }
173                             }
174                         }
175                     }
176                 }
177             }
178         }
179         finally {
180             routeLock.readLock().unlock();
181         }
182         if (list == null) {
183             return Collections.EMPTY_LIST.iterator();
184         }
185         else {
186             return list.iterator();
187         }
188     }
189
190     /**
191      * <p>Recursive method to iterate through the given table (and any embedded tables)
192      * and stuff non-Hashtable values into the given list.</p>
193      * <p>There should be no recursion problems since
194      * the routing table is at most 3 levels deep.</p>
195      *
196      * @param list The list to stuff entries into
197      * @param table The hashtable who's values should be entered into the list
198      */

199     private void getRoutes(LinkedList list, Map JavaDoc table) {
200         Iterator entryIter = table.values().iterator();
201         while (entryIter.hasNext()) {
202             Object JavaDoc entry = entryIter.next();
203             if (entry instanceof Hashtable) {
204                 getRoutes(list, (Hashtable)entry);
205             }
206             else {
207                 // Do not include the same entry many times. This could be the case when the same
208
// session is associated with the bareJID and with a given resource
209
if (!list.contains(entry)) {
210                     list.add(entry);
211                 }
212             }
213         }
214     }
215
216     public ChannelHandler getBestRoute(JID node) throws NoSuchRouteException {
217
218         ChannelHandler route = null;
219         try {
220             route = getRoute(node);
221         }
222         catch (NoSuchRouteException e) {
223             JID defaultNode = new JID(node.getNode(), node.getDomain(), "");
224             route = getRoute(defaultNode);
225         }
226         if (route == null) {
227             throw new NoSuchRouteException();
228         }
229         return route;
230     }
231
232     public ChannelHandler removeRoute(JID node) {
233
234         ChannelHandler route = null;
235         String JavaDoc nodeJID = node.getNode() == null ? "" : node.getNode();
236         String JavaDoc resourceJID = node.getResource() == null ? "" : node.getResource();
237
238         routeLock.writeLock().lock();
239         try {
240             Object JavaDoc nameRoutes = routes.get(node.getDomain());
241             if (nameRoutes instanceof Hashtable) {
242                 Object JavaDoc resourceRoutes = ((Hashtable)nameRoutes).get(nodeJID);
243                 if (resourceRoutes instanceof Hashtable) {
244                     // Remove the requested resource for this user
245
route = (ChannelHandler) ((Hashtable)resourceRoutes).remove(resourceJID);
246                     if (((Hashtable)resourceRoutes).isEmpty()) {
247                         ((Hashtable)nameRoutes).remove(nodeJID);
248                         if (((Hashtable)nameRoutes).isEmpty()) {
249                             routes.remove(node.getDomain());
250
251                         }
252                     }
253                 }
254                 else {
255                     // Remove the unique route to this node
256
((Hashtable)nameRoutes).remove(nodeJID);
257                 }
258             }
259             else if (nameRoutes != null) {
260                 // The retrieved route points to a RoutableChannelHandler
261
if (((RoutableChannelHandler)nameRoutes).getAddress().equals(node)) {
262                     // Remove the route to this domain
263
routes.remove(node.getDomain());
264                 }
265             }
266         }
267         catch (Exception JavaDoc e) {
268             Log.error("Error removing route", e);
269         }
270         finally {
271             routeLock.writeLock().unlock();
272         }
273         return route;
274     }
275
276     public void initialize(XMPPServer server) {
277         super.initialize(server);
278         serverName = server.getServerInfo().getName();
279     }
280 }
Popular Tags