KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > lib > cvsclient > connection > PServerConnection


1 /*****************************************************************************
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14
15  * The Original Software is the CVS Client Library.
16  * The Initial Developer of the Original Software is Robert Greig.
17  * Portions created by Robert Greig are Copyright (C) 2000.
18  * All Rights Reserved.
19
20  * Contributor(s): Robert Greig.
21  *****************************************************************************/

22 package org.netbeans.lib.cvsclient.connection;
23
24 import java.io.*;
25 import java.net.*;
26 import java.text.*;
27 import java.util.Map JavaDoc;
28 import java.util.HashMap JavaDoc;
29
30 import org.netbeans.lib.cvsclient.CVSRoot;
31 import org.netbeans.lib.cvsclient.request.*;
32 import org.netbeans.lib.cvsclient.command.CommandAbortedException;
33 import org.netbeans.lib.cvsclient.command.CommandException;
34 import org.netbeans.lib.cvsclient.util.*;
35
36 import javax.net.SocketFactory;
37
38 /**
39  * Implements a connection to a pserver. See the cvs documents for more
40  * information about different connection methods. PServer is popular where
41  * security is not an issue. For secure connections, consider using a
42  * kserver (Kerberos) or the GSSAPI.
43  *
44  * @author Robert Greig
45  */

46 public class PServerConnection extends AbstractConnection {
47     /**
48      * The string that is sent at the beginning of the request to open
49      * a connection.
50      */

51     protected static final String JavaDoc OPEN_PREAMBLE = "BEGIN AUTH REQUEST\n"; //NOI18N
52

53     /**
54      * The string that is sent at the end of the request to open a connection.
55      */

56     protected static final String JavaDoc OPEN_POSTAMBLE = "END AUTH REQUEST\n"; //NOI18N
57

58
59     /**
60      * The string that is sent at the beginning of the request to
61      * verify a connection.
62      * Note the difference between opening a connection and simply verifying.
63      */

64     protected static final String JavaDoc VERIFY_PREAMBLE =
65             "BEGIN VERIFICATION REQUEST\n"; //NOI18N
66

67     /**
68      * The string that is sent at the end of a verify request.
69      */

70     protected static final String JavaDoc VERIFY_POSTAMBLE =
71             "END VERIFICATION REQUEST\n"; //NOI18N
72

73     /**
74      * A response indicating that authorisation has succeeded.
75      */

76     protected static final String JavaDoc AUTHENTICATION_SUCCEEDED_RESPONSE =
77             "I LOVE YOU"; //NOI18N
78

79     private static final String JavaDoc AUTHENTICATION_SUCCEEDED_RESPONSE_RAW =
80             "I LOVE YOU\n"; //NOI18N
81

82     /**
83      * A response indicating that the authorisation has failed.
84      */

85     protected static final String JavaDoc AUTHENTICATION_FAILED_RESPONSE =
86             "I HATE YOU"; //NOI18N
87

88     private static final String JavaDoc AUTHENTICATION_FAILED_RESPONSE_RAW =
89             "I HATE YOU\n"; //NOI18N
90

91
92
93     /**
94      * The user name to use.
95      */

96     protected String JavaDoc userName;
97
98     /**
99      * The password, encoded appropriately.
100      */

101     protected String JavaDoc encodedPassword;
102
103     /**
104      * The default port number to use.
105      */

106     public static final int DEFAULT_PORT = 2401;
107
108     /**
109      * The port number to use.
110      */

111     protected int port = DEFAULT_PORT;
112
113     /**
114      * The host to use.
115      */

116     protected String JavaDoc hostName;
117
118     /**
119      * The socket used for the connection.
120      */

121     protected Socket socket;
122
123     /**
124      * The socket factory that will be used to create sockets.
125      */

126     protected SocketFactory socketFactory;
127     
128     /**
129      * Create an uninitialized PServerConnection. All properties needs to be set
130      * explicitly by appropriate setters before this connection can be opened.
131      */

132     public PServerConnection() {
133     }
134
135     /**
136      * Create PServerConnection and setup it's properties from the supplied
137      * CVSRoot object.
138      * @throws IllegalArgumentException if the cvsRoot does not represent pserver
139      * connection type.
140      */

141     public PServerConnection(CVSRoot cvsRoot) {
142         this(cvsRoot, null);
143     }
144
145     /**
146      * Create PServerConnection and setup it's properties from the supplied
147      * CVSRoot object.
148      * @throws IllegalArgumentException if the cvsRoot does not represent pserver
149      * connection type.
150      */

151     public PServerConnection(CVSRoot cvsRoot, SocketFactory factory) {
152         if (!CVSRoot.METHOD_PSERVER.equals(cvsRoot.getMethod())) {
153             throw new IllegalArgumentException JavaDoc("CVS Root '"+cvsRoot+"' does not represent :pserver: connection type.");
154         }
155         socketFactory = factory;
156         String JavaDoc userName = cvsRoot.getUserName();
157         if (userName == null) {
158             userName = System.getProperty("user.name");
159         }
160         setUserName(userName);
161         String JavaDoc password = cvsRoot.getPassword();
162         if (password != null) {
163             setEncodedPassword(StandardScrambler.getInstance().scramble(password));
164         }
165         setHostName(cvsRoot.getHostName());
166         setRepository(cvsRoot.getRepository());
167         int port = cvsRoot.getPort();
168         if (port == 0) {
169             port = 2401; // The default pserver port
170
}
171         setPort(port);
172     }
173     
174     /**
175      * Authenticate a connection with the server, using the specified
176      * postamble and preamble.
177      *
178      * @param preamble the preamble to use
179      * @param postamble the postamble to use
180      *
181      * @throws AuthenticationException if an error occurred
182      * @return the socket used to make the connection. The socket is
183      * guaranteed to be open if an exception has not been thrown
184      */

185     private void openConnection(String JavaDoc preamble, String JavaDoc postamble)
186             throws AuthenticationException, CommandAbortedException {
187         if (hostName == null) {
188             String JavaDoc locMessage = AuthenticationException.getBundleString(
189                     "AuthenticationException.HostIsNull"); //NOI18N
190
throw new AuthenticationException("HostIsNull", locMessage); //NOI18N
191
}
192
193         try {
194             SocketFactory sf = (socketFactory != null) ? socketFactory : SocketFactory.getDefault();
195             socket = sf.createSocket(hostName, port);
196
197             BufferedOutputStream bos =
198                     new BufferedOutputStream(socket.getOutputStream(), 32768);
199             LoggedDataOutputStream outputStream = new LoggedDataOutputStream(bos);
200             setOutputStream(outputStream);
201
202             BufferedInputStream bis =
203                     new BufferedInputStream(socket.getInputStream(), 32768);
204             LoggedDataInputStream inputStream = new LoggedDataInputStream(bis);
205             setInputStream(inputStream);
206             
207             outputStream.writeBytes(preamble, "US-ASCII");
208             outputStream.writeBytes(getRepository() + "\n"); //NOI18N
209
outputStream.writeBytes(userName + "\n"); //NOI18N
210
outputStream.writeBytes(getEncodedPasswordNotNull() + "\n", "US-ASCII"); //NOI18N
211
outputStream.writeBytes(postamble, "US-ASCII");
212             outputStream.flush();
213
214             if (Thread.interrupted()) {
215                 reset();
216                 String JavaDoc localMsg = CommandException.getLocalMessage("Client.connectionAborted", null); //NOI18N
217
throw new CommandAbortedException("Aborted during connecting to the server.", localMsg); // NOI18N
218
}
219
220             // read first 11 bytes only (AUTHENTICATION_SUCCEEDED_RESPONSE\n)
221
// I observed lock caused by missing '\n' in reponse
222
// this method then blocks forever
223
byte rawResponse[] = inputStream.readBytes(AUTHENTICATION_SUCCEEDED_RESPONSE_RAW.length());
224             String JavaDoc response = new String JavaDoc(rawResponse, "utf8"); // NOI18N
225

226             if (Thread.interrupted()) {
227                 reset();
228                 String JavaDoc localMsg = CommandException.getLocalMessage("Client.connectionAborted", null); //NOI18N
229
throw new CommandAbortedException("Aborted during connecting to the server.", localMsg); // NOI18N
230
}
231
232             if (AUTHENTICATION_SUCCEEDED_RESPONSE_RAW.equals(response)) {
233                 return;
234             }
235
236             if (AUTHENTICATION_FAILED_RESPONSE_RAW.equals(response)) {
237                 String JavaDoc localizedMsg = getLocalMessage("AuthenticationException.badPassword",
238                                                       null);
239                 throw new AuthenticationException("AuthenticationFailed", //NOI18N
240
localizedMsg);
241             }
242
243             if (response == null) response = ""; // NOI18N
244
String JavaDoc locMessage = getLocalMessage("AuthenticationException.AuthenticationFailed", //NOI18N
245
new Object JavaDoc[]{ response });
246             throw new AuthenticationException("AuthenticationFailed", //NOI18N
247
locMessage);
248         }
249         catch (AuthenticationException ex) {
250             reset();
251             throw ex;
252         }
253         catch (ConnectException ex) {
254             reset();
255             String JavaDoc locMessage =
256                     getLocalMessage("AuthenticationException.ConnectException", //NOI18N
257
new Object JavaDoc[]{hostName, Integer.toString(port)});
258             throw new AuthenticationException("ConnectException", ex, //NOI18N
259
locMessage);
260         }
261         catch (NoRouteToHostException ex) {
262             reset();
263             String JavaDoc locMessage =
264                     getLocalMessage("AuthenticationException.NoRouteToHostException", //NOI18N
265
new Object JavaDoc[]{hostName});
266             throw new AuthenticationException("NoRouteToHostException", ex, //NOI18N
267
locMessage);
268         }
269         catch (IOException ex) {
270             reset();
271             String JavaDoc locMessage =
272                     getLocalMessage("AuthenticationException.IOException", //NOI18N
273
new Object JavaDoc[]{hostName});
274             throw new AuthenticationException("IOException", ex, locMessage); //NOI18N
275
}
276 /* catch (Throwable t) {
277             reset();
278             String locMessage = AuthenticationException.getBundleString(
279                     "AuthenticationException.Throwable"); //NOI18N
280             throw new AuthenticationException("General error", t, locMessage); //NOI18N
281         }
282  */

283     }
284
285     private void reset() {
286         socket = null;
287         setInputStream(null);
288         setOutputStream(null);
289     }
290
291     /**
292      * Authenticate with the server.
293      * Closes the connection immediately. Clients can use this method to ensure
294      * that they are capable of authenticating with the server. If no exception
295      * is thrown, you can assume that authentication was successful.
296      *
297      * @throws AuthenticationException if the connection with the server
298      * cannot be established
299      */

300     public void verify() throws AuthenticationException {
301         try {
302             openConnection(VERIFY_PREAMBLE, VERIFY_POSTAMBLE);
303         } catch (CommandAbortedException caex) {
304             // Ignore, follow the next steps
305
}
306         if (socket == null) {
307             return;
308         }
309
310         try {
311             socket.close();
312         }
313         catch (IOException exc) {
314             String JavaDoc locMessage = AuthenticationException.getBundleString(
315                     "AuthenticationException.Throwable"); //NOI18N
316
throw new AuthenticationException("General error", exc, locMessage); //NOI18N
317
}
318         finally {
319             reset();
320         }
321     }
322
323     /**
324      * Authenticate with the server and open a channel of communication with
325      * the server.
326      * This Client will call this method before interacting with the server. It
327      * is up to implementing classes to ensure that they are configured to talk
328      * to the server (e.g. port number etc.).
329      *
330      * @throws AutenticationException if the connection with the server
331      * cannot be established
332      */

333     public void open() throws AuthenticationException, CommandAbortedException {
334         openConnection(OPEN_PREAMBLE, OPEN_POSTAMBLE);
335     }
336
337     /**
338      * Get the username.
339      */

340     public String JavaDoc getUserName() {
341         return userName;
342     }
343
344     /**
345      * Set the userName.
346      * @param name the userName
347      */

348     public void setUserName(String JavaDoc userName) {
349         this.userName = userName;
350     }
351
352     /**
353      * Get the encoded password.
354      * @return the encoded password
355      */

356     public String JavaDoc getEncodedPassword() {
357         return encodedPassword;
358     }
359
360     private String JavaDoc getEncodedPasswordNotNull() {
361         if (encodedPassword == null) {
362             return StandardScrambler.getInstance().scramble("");
363         }
364         return encodedPassword;
365     }
366
367     /**
368      * Set the encoded password.
369      * @param password the encoded password to use for authentication
370      */

371     public void setEncodedPassword(String JavaDoc encodedPassword) {
372         this.encodedPassword = encodedPassword;
373     }
374
375     /**
376      * Get the port number to use.
377      * @return the port number
378      */

379     public int getPort() {
380         return port;
381     }
382
383     /**
384      * Set the port number to use.
385      * @param thePort the port number to use. If you do not set this, 2401
386      * is used by default for pserver.
387      */

388     public void setPort(int port) {
389         this.port = port;
390     }
391
392     /**
393      * Get the host name to use.
394      * @return the host name of the server to connect to. If you do not set
395      * this, localhost is used by default for pserver.
396      */

397     public String JavaDoc getHostName() {
398         return hostName;
399     }
400
401     /**
402      * Get the host name to use.
403      * @param theHostName the host name of the server to connect to. If you
404      * do not set this, localhost is used by default for pserver.
405      */

406     public void setHostName(String JavaDoc hostName) {
407         this.hostName = hostName;
408     }
409
410     /**
411      * Close the connection with the server.
412      */

413     public void close() throws IOException {
414         if (!isOpen()) {
415             return;
416         }
417
418         try {
419             socket.close();
420         }
421         finally {
422             reset();
423         }
424     }
425
426     /**
427      * Modify the underlying inputstream.
428      * @param modifier the connection modifier that performs the modifications
429      * @throws IOException if an error occurs modifying the streams
430      */

431     public void modifyInputStream(ConnectionModifier modifier)
432             throws IOException {
433         modifier.modifyInputStream(getInputStream());
434     }
435
436     /**
437      * Modify the underlying outputstream.
438      * @param modifier the connection modifier that performs the modifications
439      * @throws IOException if an error occurs modifying the streams
440      */

441     public void modifyOutputStream(ConnectionModifier modifier)
442             throws IOException {
443         modifier.modifyOutputStream(getOutputStream());
444     }
445
446     private String JavaDoc getLocalMessage(String JavaDoc key, Object JavaDoc[] arguments) {
447         String JavaDoc locMessage = AuthenticationException.getBundleString(key);
448         if (locMessage == null) {
449             return null;
450         }
451         locMessage = MessageFormat.format(locMessage, arguments);
452         return locMessage;
453     }
454
455     /**
456      * Returns true to indicate that the connection was successfully established.
457      */

458     public boolean isOpen() {
459         return socket != null;
460     }
461     
462 }
463
Popular Tags