KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javax > mail > URLName


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the "License"). You may not use this file except
5  * in compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * glassfish/bootstrap/legal/CDDLv1.0.txt or
9  * https://glassfish.dev.java.net/public/CDDLv1.0.html.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * HEADER in each file and include the License file at
15  * glassfish/bootstrap/legal/CDDLv1.0.txt. If applicable,
16  * add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your
18  * own identifying information: Portions Copyright [yyyy]
19  * [name of copyright owner]
20  */

21
22 /*
23  * @(#)URLName.java 1.17 05/08/29
24  *
25  * Copyright 1996-2005 Sun Microsystems, Inc. All Rights Reserved.
26  */

27
28 package javax.mail;
29
30 import java.net.*;
31
32 import java.io.ByteArrayOutputStream JavaDoc;
33 import java.io.OutputStreamWriter JavaDoc;
34 import java.io.IOException JavaDoc;
35 import java.io.UnsupportedEncodingException JavaDoc;
36 import java.util.BitSet JavaDoc;
37
38
39 /**
40  * The name of a URL. This class represents a URL name and also
41  * provides the basic parsing functionality to parse most internet
42  * standard URL schemes. <p>
43  *
44  * Note that this class differs from <code>java.net.URL</code>
45  * in that this class just represents the name of a URL, it does
46  * not model the connection to a URL.
47  *
48  * @version 1.17, 05/08/29
49  * @author Christopher Cotton
50  * @author Bill Shannon
51  */

52
53 public class URLName {
54
55     /**
56      * The full version of the URL
57      */

58     protected String JavaDoc fullURL;
59
60     /**
61      * The protocol to use (ftp, http, nntp, imap, pop3 ... etc.) .
62      */

63     private String JavaDoc protocol;
64
65     /**
66      * The username to use when connecting
67      */

68     private String JavaDoc username;
69
70     /**
71      * The password to use when connecting.
72      */

73     private String JavaDoc password;
74
75     /**
76      * The host name to which to connect.
77      */

78     private String JavaDoc host;
79
80     /**
81      * The host's IP address, used in equals and hashCode.
82      * Computed on demand.
83      */

84     private InetAddress hostAddress;
85     private boolean hostAddressKnown = false;
86
87     /**
88      * The protocol port to connect to.
89      */

90     private int port = -1;
91
92     /**
93      * The specified file name on that host.
94      */

95     private String JavaDoc file;
96
97     /**
98      * # reference.
99      */

100     private String JavaDoc ref;
101
102     /**
103      * Our hash code.
104      */

105     private int hashCode = 0;
106
107     /**
108      * A way to turn off encoding, just in case...
109      */

110     private static boolean doEncode = true;
111
112     static {
113     try {
114         doEncode = !Boolean.getBoolean("mail.URLName.dontencode");
115     } catch (Exception JavaDoc ex) {
116         // ignore any errors
117
}
118     }
119
120     /**
121      * Creates a URLName object from the specified protocol,
122      * host, port number, file, username, and password. Specifying a port
123      * number of -1 indicates that the URL should use the default port for
124      * the protocol.
125      */

126     public URLName(
127     String JavaDoc protocol,
128     String JavaDoc host,
129     int port,
130     String JavaDoc file,
131     String JavaDoc username,
132     String JavaDoc password
133     )
134     {
135     this.protocol = protocol;
136     this.host = host;
137     this.port = port;
138     int refStart;
139     if (file != null && (refStart = file.indexOf('#')) != -1) {
140         this.file = file.substring(0, refStart);
141         this.ref = file.substring(refStart + 1);
142     } else {
143         this.file = file;
144         this.ref = null;
145     }
146     this.username = doEncode ? encode(username) : username;
147     this.password = doEncode ? encode(password) : password;
148     }
149
150     /**
151      * Construct a URLName from a java.net.URL object.
152      */

153     public URLName(URL url) {
154     this(url.toString());
155     }
156
157     /**
158      * Construct a URLName from the string. Parses out all the possible
159      * information (protocol, host, port, file, username, password).
160      */

161     public URLName(String JavaDoc url) {
162     parseString(url);
163     }
164
165     /**
166      * Constructs a string representation of this URLName.
167      */

168     public String JavaDoc toString() {
169     if (fullURL == null) {
170         // add the "protocol:"
171
StringBuffer JavaDoc tempURL = new StringBuffer JavaDoc();
172         if (protocol != null) {
173         tempURL.append(protocol);
174         tempURL.append(":");
175         }
176
177         if (username != null || host != null) {
178         // add the "//"
179
tempURL.append("//");
180         
181         // add the user:password@
182
// XXX - can you just have a password? without a username?
183
if (username != null) {
184             tempURL.append(username);
185         
186             if (password != null){
187             tempURL.append(":");
188             tempURL.append(password);
189             }
190         
191             tempURL.append("@");
192         }
193         
194         // add host
195
if (host != null) {
196             tempURL.append(host);
197         }
198         
199         // add port (if needed)
200
if (port != -1) {
201             tempURL.append(":");
202             tempURL.append(Integer.toString(port));
203         }
204         if (file != null)
205             tempURL.append("/");
206         }
207         
208         // add the file
209
if (file != null) {
210         tempURL.append(file);
211         }
212         
213         // add the ref
214
if (ref != null) {
215         tempURL.append("#");
216         tempURL.append(ref);
217         }
218
219         // create the fullURL now
220
fullURL = tempURL.toString();
221     }
222
223     return fullURL;
224     }
225
226     /**
227      * Method which does all of the work of parsing the string.
228      */

229     protected void parseString(String JavaDoc url) {
230     // initialize everything in case called from subclass
231
// (URLName really should be a final class)
232
protocol = file = ref = host = username = password = null;
233     port = -1;
234
235     int len = url.length();
236
237     // find the protocol
238
// XXX - should check for only legal characters before the colon
239
// (legal: a-z, A-Z, 0-9, "+", ".", "-")
240
int protocolEnd = url.indexOf(':');
241         if (protocolEnd != -1)
242         protocol = url.substring(0, protocolEnd);
243
244     // is this an Internet standard URL that contains a host name?
245
if (url.regionMatches(protocolEnd + 1, "//", 0, 2)) {
246         // find where the file starts
247
String JavaDoc fullhost = null;
248         int fileStart = url.indexOf('/', protocolEnd + 3);
249         if (fileStart != -1) {
250         fullhost = url.substring(protocolEnd + 3, fileStart);
251         if (fileStart + 1 < len)
252             file = url.substring(fileStart + 1);
253         else
254             file = "";
255         } else
256         fullhost = url.substring(protocolEnd + 3);
257
258         // examine the fullhost, for username password etc.
259
int i = fullhost.indexOf('@');
260         if (i != -1) {
261         String JavaDoc fulluserpass = fullhost.substring(0, i);
262         fullhost = fullhost.substring(i + 1);
263
264         // get user and password
265
int passindex = fulluserpass.indexOf(':');
266         if (passindex != -1) {
267             username = fulluserpass.substring(0, passindex);
268             password = fulluserpass.substring(passindex + 1);
269         } else {
270             username = fulluserpass;
271         }
272         }
273         
274         // get the port (if there)
275
int portindex;
276         if (fullhost.length() > 0 && fullhost.charAt(0) == '[') {
277         // an IPv6 address?
278
portindex = fullhost.indexOf(':', fullhost.indexOf(']'));
279         } else {
280         portindex = fullhost.indexOf(':');
281         }
282         if (portindex != -1) {
283         String JavaDoc portstring = fullhost.substring(portindex + 1);
284         if (portstring.length() > 0) {
285             try {
286             port = Integer.parseInt(portstring);
287             } catch (NumberFormatException JavaDoc nfex) {
288             port = -1;
289             }
290         }
291         
292         host = fullhost.substring(0, portindex);
293         } else {
294         host = fullhost;
295         }
296     } else {
297         if (protocolEnd + 1 < len)
298         file = url.substring(protocolEnd + 1);
299     }
300
301     // extract the reference from the file name, if any
302
int refStart;
303     if (file != null && (refStart = file.indexOf('#')) != -1) {
304         ref = file.substring(refStart + 1);
305         file = file.substring(0, refStart);
306     }
307     }
308     
309     /**
310      * Returns the port number of this URLName.
311      * Returns -1 if the port is not set.
312      */

313     public int getPort() {
314     return port;
315     }
316
317     /**
318      * Returns the protocol of this URLName.
319      * Returns null if this URLName has no protocol.
320      */

321     public String JavaDoc getProtocol() {
322     return protocol;
323     }
324
325     /**
326      * Returns the file name of this URLName.
327      * Returns null if this URLName has no file name.
328      */

329     public String JavaDoc getFile() {
330     return file;
331     }
332
333     /**
334      * Returns the reference of this URLName.
335      * Returns null if this URLName has no reference.
336      */

337     public String JavaDoc getRef() {
338     return ref;
339     }
340
341     /**
342      * Returns the host of this URLName.
343      * Returns null if this URLName has no host.
344      */

345     public String JavaDoc getHost() {
346     return host;
347     }
348
349     /**
350      * Returns the user name of this URLName.
351      * Returns null if this URLName has no user name.
352      */

353     public String JavaDoc getUsername() {
354     return doEncode ? decode(username) : username;
355     }
356
357     /**
358      * Returns the password of this URLName.
359      * Returns null if this URLName has no password.
360      */

361     public String JavaDoc getPassword() {
362     return doEncode ? decode(password) : password;
363     }
364
365     /**
366      * Constructs a URL from the URLName.
367      */

368     public URL getURL() throws MalformedURLException {
369         return new URL(getProtocol(), getHost(), getPort(), getFile());
370     }
371
372     /**
373      * Compares two URLNames. The result is true if and only if the
374      * argument is not null and is a URLName object that represents the
375      * same URLName as this object. Two URLName objects are equal if
376      * they have the same protocol and the same host,
377      * the same port number on the host, the same username,
378      * and the same file on the host. The fields (host, username,
379      * file) are also considered the same if they are both
380      * null. <p>
381      *
382      * Hosts are considered equal if the names are equal (case independent)
383      * or if host name lookups for them both succeed and they both reference
384      * the same IP address. <p>
385      *
386      * Note that URLName has no knowledge of default port numbers for
387      * particular protocols, so "imap://host" and "imap://host:143"
388      * would not compare as equal. <p>
389      *
390      * Note also that the password field is not included in the comparison,
391      * nor is any reference field appended to the filename.
392      */

393     public boolean equals(Object JavaDoc obj) {
394         if (!(obj instanceof URLName JavaDoc))
395         return false;
396     URLName JavaDoc u2 = (URLName JavaDoc)obj;
397
398     // compare protocols
399
if (u2.protocol == null || !u2.protocol.equals(protocol))
400         return false;
401
402     // compare hosts
403
InetAddress a1 = getHostAddress(), a2 = u2.getHostAddress();
404     // if we have internet address for both, and they're not the same, fail
405
if (a1 != null && a2 != null) {
406         if (!a1.equals(a2))
407         return false;
408     // else, if we have host names for both, and they're not the same, fail
409
} else if (host != null && u2.host != null) {
410         if (!host.equalsIgnoreCase(u2.host))
411         return false;
412     // else, if not both null
413
} else if (host != u2.host) {
414         return false;
415     }
416     // at this point, hosts match
417

418     // compare usernames
419
if (!(username == u2.username ||
420         (username != null && username.equals(u2.username))))
421         return false;
422
423     // Forget about password since it doesn't
424
// really denote a different store.
425

426     // compare files
427
String JavaDoc f1 = file == null ? "" : file;
428     String JavaDoc f2 = u2.file == null ? "" : u2.file;
429
430     if (!f1.equals(f2))
431         return false;
432
433     // compare ports
434
if (port != u2.port)
435         return false;
436
437     // all comparisons succeeded, they're equal
438
return true;
439     }
440
441     /**
442      * Compute the hash code for this URLName.
443      */

444     public int hashCode() {
445     if (hashCode != 0)
446         return hashCode;
447     if (protocol != null)
448         hashCode += protocol.hashCode();
449     InetAddress addr = getHostAddress();
450     if (addr != null)
451         hashCode += addr.hashCode();
452     else if (host != null)
453         hashCode += host.toLowerCase().hashCode();
454     if (username != null)
455         hashCode += username.hashCode();
456     if (file != null)
457         hashCode += file.hashCode();
458     hashCode += port;
459     return hashCode;
460     }
461
462     /**
463      * Get the IP address of our host. Look up the
464      * name the first time and remember that we've done
465      * so, whether the lookup fails or not.
466      */

467     private synchronized InetAddress getHostAddress() {
468     if (hostAddressKnown)
469         return hostAddress;
470     if (host == null)
471         return null;
472     try {
473         hostAddress = InetAddress.getByName(host);
474     } catch (UnknownHostException ex) {
475         hostAddress = null;
476     }
477     hostAddressKnown = true;
478     return hostAddress;
479     }
480
481     /**
482      * The class contains a utility method for converting a
483      * <code>String</code> into a MIME format called
484      * "<code>x-www-form-urlencoded</code>" format.
485      * <p>
486      * To convert a <code>String</code>, each character is examined in turn:
487      * <ul>
488      * <li>The ASCII characters '<code>a</code>' through '<code>z</code>',
489      * '<code>A</code>' through '<code>Z</code>', '<code>0</code>'
490      * through '<code>9</code>', and &quot;.&quot;, &quot;-&quot;,
491      * &quot;*&quot;, &quot;_&quot; remain the same.
492      * <li>The space character '<code>&nbsp;</code>' is converted into a
493      * plus sign '<code>+</code>'.
494      * <li>All other characters are converted into the 3-character string
495      * "<code>%<i>xy</i></code>", where <i>xy</i> is the two-digit
496      * hexadecimal representation of the lower 8-bits of the character.
497      * </ul>
498      *
499      * @author Herb Jellinek
500      * @version 1.16, 10/23/99
501      * @since JDK1.0
502      */

503     static BitSet JavaDoc dontNeedEncoding;
504     static final int caseDiff = ('a' - 'A');
505
506     /* The list of characters that are not encoded have been determined by
507        referencing O'Reilly's "HTML: The Definitive Guide" (page 164). */

508
509     static {
510     dontNeedEncoding = new BitSet JavaDoc(256);
511     int i;
512     for (i = 'a'; i <= 'z'; i++) {
513         dontNeedEncoding.set(i);
514     }
515     for (i = 'A'; i <= 'Z'; i++) {
516         dontNeedEncoding.set(i);
517     }
518     for (i = '0'; i <= '9'; i++) {
519         dontNeedEncoding.set(i);
520     }
521     /* encoding a space to a + is done in the encode() method */
522     dontNeedEncoding.set(' ');
523     dontNeedEncoding.set('-');
524     dontNeedEncoding.set('_');
525     dontNeedEncoding.set('.');
526     dontNeedEncoding.set('*');
527     }
528
529     /**
530      * Translates a string into <code>x-www-form-urlencoded</code> format.
531      *
532      * @param s <code>String</code> to be translated.
533      * @return the translated <code>String</code>.
534      */

535     static String JavaDoc encode(String JavaDoc s) {
536     if (s == null)
537         return null;
538     // the common case is no encoding is needed
539
for (int i = 0; i < s.length(); i++) {
540         int c = (int)s.charAt(i);
541         if (c == ' ' || !dontNeedEncoding.get(c))
542         return _encode(s);
543     }
544     return s;
545     }
546
547     private static String JavaDoc _encode(String JavaDoc s) {
548     int maxBytesPerChar = 10;
549         StringBuffer JavaDoc out = new StringBuffer JavaDoc(s.length());
550     ByteArrayOutputStream JavaDoc buf = new ByteArrayOutputStream JavaDoc(maxBytesPerChar);
551     OutputStreamWriter JavaDoc writer = new OutputStreamWriter JavaDoc(buf);
552
553     for (int i = 0; i < s.length(); i++) {
554         int c = (int)s.charAt(i);
555         if (dontNeedEncoding.get(c)) {
556         if (c == ' ') {
557             c = '+';
558         }
559         out.append((char)c);
560         } else {
561         // convert to external encoding before hex conversion
562
try {
563             writer.write(c);
564             writer.flush();
565         } catch(IOException JavaDoc e) {
566             buf.reset();
567             continue;
568         }
569         byte[] ba = buf.toByteArray();
570         for (int j = 0; j < ba.length; j++) {
571             out.append('%');
572             char ch = Character.forDigit((ba[j] >> 4) & 0xF, 16);
573             // converting to use uppercase letter as part of
574
// the hex value if ch is a letter.
575
if (Character.isLetter(ch)) {
576             ch -= caseDiff;
577             }
578             out.append(ch);
579             ch = Character.forDigit(ba[j] & 0xF, 16);
580             if (Character.isLetter(ch)) {
581             ch -= caseDiff;
582             }
583             out.append(ch);
584         }
585         buf.reset();
586         }
587     }
588
589     return out.toString();
590     }
591
592
593     /**
594      * The class contains a utility method for converting from
595      * a MIME format called "<code>x-www-form-urlencoded</code>"
596      * to a <code>String</code>
597      * <p>
598      * To convert to a <code>String</code>, each character is examined in turn:
599      * <ul>
600      * <li>The ASCII characters '<code>a</code>' through '<code>z</code>',
601      * '<code>A</code>' through '<code>Z</code>', and '<code>0</code>'
602      * through '<code>9</code>' remain the same.
603      * <li>The plus sign '<code>+</code>'is converted into a
604      * space character '<code>&nbsp;</code>'.
605      * <li>The remaining characters are represented by 3-character
606      * strings which begin with the percent sign,
607      * "<code>%<i>xy</i></code>", where <i>xy</i> is the two-digit
608      * hexadecimal representation of the lower 8-bits of the character.
609      * </ul>
610      *
611      * @author Mark Chamness
612      * @author Michael McCloskey
613      * @version 1.7, 10/22/99
614      * @since 1.2
615      */

616
617     /**
618      * Decodes a &quot;x-www-form-urlencoded&quot;
619      * to a <tt>String</tt>.
620      * @param s the <code>String</code> to decode
621      * @return the newly decoded <code>String</code>
622      */

623     static String JavaDoc decode(String JavaDoc s) {
624     if (s == null)
625         return null;
626     if (indexOfAny(s, "+%") == -1)
627         return s; // the common case
628

629         StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
630         for (int i = 0; i < s.length(); i++) {
631             char c = s.charAt(i);
632             switch (c) {
633                 case '+':
634                     sb.append(' ');
635                     break;
636                 case '%':
637                     try {
638                         sb.append((char)Integer.parseInt(
639                                         s.substring(i+1,i+3),16));
640                     } catch (NumberFormatException JavaDoc e) {
641                         throw new IllegalArgumentException JavaDoc();
642                     }
643                     i += 2;
644                     break;
645                 default:
646                     sb.append(c);
647                     break;
648             }
649         }
650         // Undo conversion to external encoding
651
String JavaDoc result = sb.toString();
652         try {
653             byte[] inputBytes = result.getBytes("8859_1");
654             result = new String JavaDoc(inputBytes);
655         } catch (UnsupportedEncodingException JavaDoc e) {
656             // The system should always have 8859_1
657
}
658         return result;
659     }
660
661     /**
662      * Return the first index of any of the characters in "any" in "s",
663      * or -1 if none are found.
664      *
665      * This should be a method on String.
666      */

667     private static int indexOfAny(String JavaDoc s, String JavaDoc any) {
668     return indexOfAny(s, any, 0);
669     }
670
671     private static int indexOfAny(String JavaDoc s, String JavaDoc any, int start) {
672     try {
673         int len = s.length();
674         for (int i = start; i < len; i++) {
675         if (any.indexOf(s.charAt(i)) >= 0)
676             return i;
677         }
678         return -1;
679     } catch (StringIndexOutOfBoundsException JavaDoc e) {
680         return -1;
681     }
682     }
683
684     /*
685     // Do not remove, this is needed when testing new URL cases
686     public static void main(String[] argv) {
687     String [] testURLNames = {
688         "protocol://userid:password@host:119/file",
689         "http://funny/folder/file.html",
690         "http://funny/folder/file.html#ref",
691         "http://funny/folder/file.html#",
692         "http://funny/#ref",
693         "imap://jmr:secret@labyrinth//var/mail/jmr",
694         "nntp://fred@labyrinth:143/save/it/now.mbox",
695         "imap://jmr@labyrinth/INBOX",
696         "imap://labryrinth",
697         "imap://labryrinth/",
698         "file:",
699         "file:INBOX",
700         "file:/home/shannon/mail/foo",
701         "/tmp/foo",
702         "//host/tmp/foo",
703         ":/tmp/foo",
704         "/really/weird:/tmp/foo#bar",
705         ""
706     };
707
708     URLName url =
709         new URLName("protocol", "host", 119, "file", "userid", "password");
710     System.out.println("Test URL: " + url.toString());
711     if (argv.length == 0) {
712         for (int i = 0; i < testURLNames.length; i++) {
713         print(testURLNames[i]);
714         System.out.println();
715         }
716     } else {
717         for (int i = 0; i < argv.length; i++) {
718         print(argv[i]);
719         System.out.println();
720         }
721         if (argv.length == 2) {
722         URLName u1 = new URLName(argv[0]);
723         URLName u2 = new URLName(argv[1]);
724         System.out.println("URL1 hash code: " + u1.hashCode());
725         System.out.println("URL2 hash code: " + u2.hashCode());
726         if (u1.equals(u2))
727             System.out.println("success, equal");
728         else
729             System.out.println("fail, not equal");
730         if (u2.equals(u1))
731             System.out.println("success, equal");
732         else
733             System.out.println("fail, not equal");
734         if (u1.hashCode() == u2.hashCode())
735             System.out.println("success, hashCodes equal");
736         else
737             System.out.println("fail, hashCodes not equal");
738         }
739     }
740     }
741
742     private static void print(String name) {
743     URLName url = new URLName(name);
744     System.out.println("Original URL: " + name);
745     System.out.println("The fullUrl : " + url.toString());
746     if (!name.equals(url.toString()))
747         System.out.println(" : NOT EQUAL!");
748     System.out.println("The protocol is: " + url.getProtocol());
749     System.out.println("The host is: " + url.getHost());
750     System.out.println("The port is: " + url.getPort());
751     System.out.println("The user is: " + url.getUsername());
752     System.out.println("The password is: " + url.getPassword());
753     System.out.println("The file is: " + url.getFile());
754     System.out.println("The ref is: " + url.getRef());
755     }
756     */

757 }
758
Popular Tags