KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jivesoftware > messenger > component > InternalComponentManager


1 /**
2  * $RCSfile: InternalComponentManager.java,v $
3  * $Revision: 1.1 $
4  * $Date: 2005/06/24 05:02:35 $
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.component;
13
14 import org.dom4j.Element;
15 import org.xmpp.component.Component;
16 import org.xmpp.component.ComponentManager;
17 import org.xmpp.component.ComponentManagerFactory;
18 import org.xmpp.component.ComponentException;
19 import org.xmpp.packet.IQ;
20 import org.xmpp.packet.JID;
21 import org.xmpp.packet.Packet;
22 import org.xmpp.packet.Presence;
23 import org.jivesoftware.util.Log;
24 import org.jivesoftware.util.JiveGlobals;
25 import org.jivesoftware.messenger.component.ComponentSession;
26 import org.jivesoftware.messenger.RoutableChannelHandler;
27 import org.jivesoftware.messenger.XMPPServer;
28 import org.jivesoftware.messenger.PacketRouter;
29 import org.jivesoftware.messenger.PacketException;
30
31 import java.util.Map JavaDoc;
32 import java.util.concurrent.ConcurrentHashMap JavaDoc;
33
34 /**
35  * Manages the registration and delegation of Components. The ComponentManager
36  * is responsible for managing registration and delegation of {@link Component Components},
37  * as well as offering a facade around basic server functionallity such as sending and
38  * receiving of packets.<p>
39  *
40  * This component manager will be an internal service whose JID will be component.[domain]. So the
41  * component manager will be able to send packets to other internal or external components and also
42  * receive packets from other components or even from trusted clients (e.g. ad-hoc commands).
43  *
44  * @author Derek DeMoro
45  */

46 public class InternalComponentManager implements ComponentManager, RoutableChannelHandler {
47
48     private Map JavaDoc<String JavaDoc, Component> components = new ConcurrentHashMap JavaDoc<String JavaDoc, Component>();
49     private Map JavaDoc<JID, JID> presenceMap = new ConcurrentHashMap JavaDoc<JID, JID>();
50
51     private static InternalComponentManager instance = new InternalComponentManager();
52     /**
53      * XMPP address of this internal service. The address is of the form: component.[domain]
54      */

55     private JID serviceAddress;
56     /**
57      * Holds the domain of the server. We are using an iv since we use this value many times
58      * in many methods.
59      */

60     private String JavaDoc serverDomain;
61
62     public static InternalComponentManager getInstance() {
63         return instance;
64     }
65
66     public void start() {
67         // Set this ComponentManager as the current component manager
68
ComponentManagerFactory.setComponentManager(instance);
69
70         XMPPServer server = XMPPServer.getInstance();
71         serverDomain = server.getServerInfo().getName();
72         // Set the address of this internal service. component.[domain]
73
serviceAddress = new JID(null, "component." + serverDomain, null);
74         if (!server.isSetupMode()) {
75             // Add a route to this service
76
server.getRoutingTable().addRoute(getAddress(), this);
77         }
78     }
79
80     public void addComponent(String JavaDoc subdomain, Component component) throws ComponentException {
81         components.put(subdomain, component);
82
83         JID componentJID = new JID(subdomain + "." + serverDomain);
84
85         // Add the route to the new service provided by the component
86
XMPPServer.getInstance().getRoutingTable().addRoute(componentJID,
87                 new RoutableComponent(componentJID, component));
88
89         // Initialize the new component
90
try {
91             component.initialize(componentJID, this);
92             component.start();
93         }
94         catch (ComponentException e) {
95             // Remove the route
96
XMPPServer.getInstance().getRoutingTable().removeRoute(componentJID);
97             // Rethrow the exception
98
throw e;
99         }
100
101         // Check for potential interested users.
102
checkPresences();
103         // Send a disco#info request to the new component. If the component provides information
104
// then it will be added to the list of discoverable server items.
105
checkDiscoSupport(component, componentJID);
106     }
107
108     public void removeComponent(String JavaDoc subdomain) {
109         components.remove(subdomain);
110
111         JID componentJID = new JID(subdomain + "." + serverDomain);
112
113         // Remove the route for the service provided by the component
114
if (XMPPServer.getInstance().getRoutingTable() != null) {
115             XMPPServer.getInstance().getRoutingTable().removeRoute(componentJID);
116         }
117
118         // Remove the disco item from the server for the component that is being removed
119
if (XMPPServer.getInstance().getIQDiscoItemsHandler() != null) {
120             XMPPServer.getInstance().getIQDiscoItemsHandler().removeComponentItem(componentJID.toBareJID());
121         }
122     }
123
124     public void sendPacket(Component component, Packet packet) {
125         PacketRouter router;
126         router = XMPPServer.getInstance().getPacketRouter();
127         if (router != null) {
128             router.route(packet);
129         }
130     }
131
132     public String JavaDoc getProperty(String JavaDoc name) {
133         return JiveGlobals.getProperty(name);
134     }
135
136     public void setProperty(String JavaDoc name, String JavaDoc value) {
137         //To change body of implemented methods use File | Settings | File Templates.
138
}
139
140     public String JavaDoc getServerName() {
141         return serverDomain;
142     }
143
144     public String JavaDoc getHomeDirectory() {
145         return JiveGlobals.getHomeDirectory();
146     }
147
148     public boolean isExternalMode() {
149         return false; //To change body of implemented methods use File | Settings | File Templates.
150
}
151
152     public org.xmpp.component.Log getLog() {
153         return new org.xmpp.component.Log() {
154             public void error(String JavaDoc msg) {
155                 Log.error(msg);
156             }
157
158             public void error(String JavaDoc msg, Throwable JavaDoc throwable) {
159                 Log.error(msg, throwable);
160             }
161
162             public void error(Throwable JavaDoc throwable) {
163                 Log.error(throwable);
164             }
165
166             public void warn(String JavaDoc msg) {
167                 Log.warn(msg);
168             }
169
170             public void warn(String JavaDoc msg, Throwable JavaDoc throwable) {
171                 Log.warn(msg, throwable);
172             }
173
174             public void warn(Throwable JavaDoc throwable) {
175                 Log.warn(throwable);
176             }
177
178             public void info(String JavaDoc msg) {
179                 Log.info(msg);
180             }
181
182             public void info(String JavaDoc msg, Throwable JavaDoc throwable) {
183                 Log.info(msg, throwable);
184             }
185
186             public void info(Throwable JavaDoc throwable) {
187                 Log.info(throwable);
188             }
189
190             public void debug(String JavaDoc msg) {
191                 Log.debug(msg);
192             }
193
194             public void debug(String JavaDoc msg, Throwable JavaDoc throwable) {
195                 Log.debug(msg, throwable);
196             }
197
198             public void debug(Throwable JavaDoc throwable) {
199                 Log.debug(throwable);
200             }
201         };
202     }
203
204     /**
205      * Retrieves the <code>Component</code> which is mapped
206      * to the specified JID.
207      *
208      * @param componentJID the jid mapped to the component.
209      * @return the component with the specified id.
210      */

211     public Component getComponent(JID componentJID) {
212         String JavaDoc jid = componentJID.toBareJID();
213         if (components.containsKey(jid)) {
214             return components.get(jid);
215         }
216         else {
217             String JavaDoc serverName = new JID(jid).getDomain();
218             int index = serverName.indexOf(".");
219             if (index != -1) {
220                 String JavaDoc serviceName = serverName.substring(0, index);
221                 jid = serviceName;
222             }
223         }
224         return components.get(jid);
225     }
226
227     /**
228      * Retrieves the <code>Component</code> which is mapped
229      * to the specified JID.
230      *
231      * @param jid the jid mapped to the component.
232      * @return the component with the specified id.
233      */

234     public Component getComponent(String JavaDoc jid) {
235         return getComponent(new JID(jid));
236     }
237
238     /**
239      * Registers Probeers who have not yet been serviced.
240      *
241      * @param prober the jid probing.
242      * @param probee the presence being probed.
243      */

244     public void addPresenceRequest(JID prober, JID probee) {
245         presenceMap.put(prober, probee);
246     }
247
248     private void checkPresences() {
249         for (JID prober : presenceMap.keySet()) {
250             JID probee = presenceMap.get(prober);
251
252             Component component = getComponent(probee.toBareJID());
253             if (component != null) {
254                 Presence presence = new Presence();
255                 presence.setFrom(prober);
256                 presence.setTo(probee);
257                 component.processPacket(presence);
258
259                 // No reason to hold onto prober reference.
260
presenceMap.remove(prober);
261             }
262         }
263     }
264
265     /**
266      * Send a disco#info request to the new component. If the component provides information
267      * then it will be added to the list of discoverable server items.
268      *
269      * @param component the new component that was added to this manager.
270      * @param componentJID the XMPP address of the new component.
271      */

272     private void checkDiscoSupport(Component component, JID componentJID) {
273         // Build a disco#info request that will be sent to the component
274
IQ iq = new IQ(IQ.Type.get);
275         iq.setFrom(getAddress());
276         iq.setTo(componentJID);
277         iq.setChildElement("query", "http://jabber.org/protocol/disco#info");
278         // Send the disco#info request to the component. The reply (if any) will be processed in
279
// #process(Packet)
280
sendPacket(component, iq);
281     }
282
283     public JID getAddress() {
284         return serviceAddress;
285     }
286
287     /**
288      * Processes packets that were sent to this service. Currently only packets that were sent from
289      * registered components are being processed. In the future, we may also process packet of
290      * trusted clients. Trusted clients may be able to execute ad-hoc commands such as adding or
291      * removing components.
292      *
293      * @param packet the packet to process.
294      */

295     public void process(Packet packet) throws PacketException {
296         Component component = getComponent(packet.getFrom().getDomain());
297         // Only process packets that were sent by registered components
298
if (component != null) {
299             if (packet instanceof IQ && IQ.Type.result == ((IQ) packet).getType()) {
300                 IQ iq = (IQ) packet;
301                 Element childElement = iq.getChildElement();
302                 String JavaDoc namespace = null;
303                 if (childElement != null) {
304                     namespace = childElement.getNamespaceURI();
305                 }
306                 if ("http://jabber.org/protocol/disco#info".equals(namespace)) {
307                     // Add a disco item to the server for the component that supports disco
308
Element identity = childElement.element("identity");
309                     XMPPServer.getInstance().getIQDiscoItemsHandler().addComponentItem(packet.getFrom()
310                             .toBareJID(),
311                             identity.attributeValue("name"));
312                     if (component instanceof ComponentSession.ExternalComponent) {
313                         ComponentSession.ExternalComponent externalComponent =
314                                 (ComponentSession.ExternalComponent) component;
315                         externalComponent.setName(identity.attributeValue("name"));
316                         externalComponent.setType(identity.attributeValue("type"));
317                         externalComponent.setCategory(identity.attributeValue("category"));
318                     }
319                 }
320             }
321         }
322     }
323
324     /**
325      * Exposes a Component as a RoutableChannelHandler.
326      */

327     public static class RoutableComponent implements RoutableChannelHandler {
328
329         private JID jid;
330         private Component component;
331
332         public RoutableComponent(JID jid, Component component) {
333             this.jid = jid;
334             this.component = component;
335         }
336
337         public JID getAddress() {
338             return jid;
339         }
340
341         public void process(Packet packet) throws PacketException {
342             component.processPacket(packet);
343         }
344     }
345 }
Popular Tags