KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jivesoftware > messenger > ComponentSession


1 /**
2  * $RCSfile: ComponentSession.java,v $
3  * $Revision: 1.9 $
4  * $Date: 2005/04/13 17:36:12 $
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 package org.jivesoftware.messenger;
12
13 import org.xmpp.packet.Packet;
14 import org.xmpp.packet.JID;
15 import org.xmpp.packet.StreamError;
16 import org.xmpp.component.*;
17 import org.xmpp.component.ComponentManager;
18 import org.jivesoftware.messenger.auth.UnauthorizedException;
19 import org.jivesoftware.messenger.auth.AuthFactory;
20 import org.jivesoftware.util.Log;
21 import org.jivesoftware.util.LocaleUtils;
22 import org.jivesoftware.util.JiveGlobals;
23 import org.dom4j.io.XPPPacketReader;
24 import org.dom4j.Element;
25 import org.xmlpull.v1.XmlPullParser;
26 import org.xmlpull.v1.XmlPullParserException;
27
28 import java.io.Writer JavaDoc;
29 import java.io.IOException JavaDoc;
30
31 /**
32  * Represents a session between the server and a component.
33  *
34  * @author Gaston Dombiak
35  */

36 public class ComponentSession extends Session {
37
38     private ExternalComponent component = new ExternalComponent();
39
40     /**
41      * Returns a newly created session between the server and a component. The session will be
42      * created and returned only if all the checkings were correct.<p>
43      *
44      * A domain will be binded for the new connecting component. This method is following
45      * the JEP-114 where the domain to bind is sent in the TO attribute of the stream header.
46      *
47      * @param serverName the name of the server where the session is connecting to.
48      * @param reader the reader that is reading the provided XML through the connection.
49      * @param connection the connection with the component.
50      * @return a newly created session between the server and a component.
51      */

52     public static Session createSession(String JavaDoc serverName, XPPPacketReader reader,
53             Connection connection) throws UnauthorizedException, IOException JavaDoc,
54             XmlPullParserException
55     {
56         XmlPullParser xpp = reader.getXPPParser();
57         Session session;
58         String JavaDoc domain = xpp.getAttributeValue("", "to");
59
60         // Get the requested subdomain
61
String JavaDoc subdomain = domain;
62         int index = domain.indexOf(serverName);
63         if (index > -1) {
64             subdomain = domain.substring(0, index -1);
65         }
66
67         Writer JavaDoc writer = connection.getWriter();
68         // Default answer header in case of an error
69
StringBuilder JavaDoc sb = new StringBuilder JavaDoc();
70         sb.append("<?xml version='1.0' encoding='");
71         sb.append(CHARSET);
72         sb.append("'?>");
73         sb.append("<stream:stream ");
74         sb.append("xmlns:stream=\"http://etherx.jabber.org/streams\" ");
75         sb.append("xmlns=\"jabber:component:accept\" from=\"");
76         sb.append(domain);
77         sb.append("\">");
78
79         // Check that a domain was provided in the stream header
80
if (domain == null) {
81             // Include the bad-format in the response
82
StreamError error = new StreamError(StreamError.Condition.bad_format);
83             sb.append(error.toXML());
84             sb.append("</stream:stream>");
85             writer.write(sb.toString());
86             writer.flush();
87             // Close the underlying connection
88
connection.close();
89             return null;
90         }
91         // Check that a secret key was configured in the server
92
// TODO Configure the secret key in the Admin Console
93
String JavaDoc secretKey = JiveGlobals.getProperty("component.external.secretKey");
94         if (secretKey == null) {
95             Log.error("Setup for external components is incomplete. Property " +
96                     "component.external.secretKey does not exist.");
97             // Include the internal-server-error in the response
98
StreamError error = new StreamError(StreamError.Condition.internal_server_error);
99             sb.append(error.toXML());
100             sb.append("</stream:stream>");
101             writer.write(sb.toString());
102             writer.flush();
103             // Close the underlying connection
104
connection.close();
105             return null;
106         }
107         // Check that the requested subdomain is not already in use
108
if (InternalComponentManager.getInstance().getComponent(subdomain) != null) {
109             // Domain already occupied so return a conflict error and close the connection
110
// Include the conflict error in the response
111
StreamError error = new StreamError(StreamError.Condition.conflict);
112             sb.append(error.toXML());
113             sb.append("</stream:stream>");
114             writer.write(sb.toString());
115             writer.flush();
116             // Close the underlying connection
117
connection.close();
118             return null;
119         }
120
121         // Create a ComponentSession for the external component
122
session = SessionManager.getInstance().createComponentSession(connection);
123         // Set the bind address as the address of the session
124
session.setAddress(new JID(null, domain , null));
125
126         try {
127             // Build the start packet response
128
sb = new StringBuilder JavaDoc();
129             sb.append("<?xml version='1.0' encoding='");
130             sb.append(CHARSET);
131             sb.append("'?>");
132             sb.append("<stream:stream ");
133             sb.append("xmlns:stream=\"http://etherx.jabber.org/streams\" ");
134             sb.append("xmlns=\"jabber:component:accept\" from=\"");
135             sb.append(domain);
136             sb.append("\" id=\"");
137             sb.append(session.getStreamID().toString());
138             sb.append("\">");
139             writer.write(sb.toString());
140             writer.flush();
141
142             // Perform authentication. Wait for the handshake (with the secret key)
143
Element doc = reader.parseDocument().getRootElement();
144             String JavaDoc digest = "handshake".equals(doc.getName()) ? doc.getStringValue() : "";
145             String JavaDoc anticipatedDigest = AuthFactory.createDigest(session.getStreamID().getID(),
146                     secretKey);
147             // Check that the provided handshake (secret key + sessionID) is correct
148
if (!anticipatedDigest.equalsIgnoreCase(digest)) {
149                 // The credentials supplied by the initiator are not valid (answer an error
150
// and close the connection)
151
sb = new StringBuilder JavaDoc();
152                 // Include the conflict error in the response
153
StreamError error = new StreamError(StreamError.Condition.not_authorized);
154                 sb.append(error.toXML());
155                 sb.append("</stream:stream>");
156                 writer.write(sb.toString());
157                 writer.flush();
158                 // Close the underlying connection
159
connection.close();
160                 return null;
161             }
162             else {
163                 // Component has authenticated fine
164
session.setStatus(Session.STATUS_AUTHENTICATED);
165                 // Send empty handshake element to acknowledge success
166
writer.write("<handshake></handshake>");
167                 writer.flush();
168                 // Bind the domain to this component
169
ExternalComponent component = ((ComponentSession) session).getExternalComponent();
170                 InternalComponentManager.getInstance().addComponent(subdomain, component);
171                 return session;
172             }
173         }
174         catch (Exception JavaDoc e) {
175             Log.error("An error occured while creating a ComponentSession", e);
176             // Close the underlying connection
177
connection.close();
178             return null;
179         }
180     }
181
182     public ComponentSession(String JavaDoc serverName, Connection conn, StreamID id) {
183         super(serverName, conn, id);
184     }
185
186     public void process(Packet packet) throws PacketException {
187         // Since ComponentSessions are not being stored in the RoutingTable this messages is very
188
// unlikely to be sent
189
component.processPacket(packet);
190     }
191
192     public ExternalComponent getExternalComponent() {
193         return component;
194     }
195
196     /**
197      * The ExternalComponent acts as a proxy of the remote connected component. Any Packet that is
198      * sent to this component will be delivered to the real component on the other side of the
199      * connection.<p>
200      *
201      * An ExternalComponent will be added as a route in the RoutingTable for each connected
202      * external component. This implies that when the server receives a packet whose domain matches
203      * the external component services address then a route to the external component will be used
204      * and the packet will be forwarded to the component on the other side of the connection.
205      */

206     public class ExternalComponent implements Component {
207
208         public void processPacket(Packet packet) {
209             if (conn != null && !conn.isClosed()) {
210                 try {
211                     conn.deliver(packet);
212                 }
213                 catch (Exception JavaDoc e) {
214                     Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
215                     conn.close();
216                 }
217             }
218         }
219
220         public String JavaDoc getName() {
221             return null;
222         }
223
224         public String JavaDoc getDescription() {
225             return null;
226         }
227
228         public void initialize(JID jid, ComponentManager componentManager) {
229         }
230
231         public void start() {
232         }
233
234         public void shutdown() {
235         }
236     }
237
238     public void packetReceived(Packet packet) {
239         //Do nothing
240
}
241 }
Popular Tags