View Javadoc

1   /*
2    * $HeadURL: https://svn.apache.org/repos/asf/httpcomponents/oac.hc3x/trunk/src/java/org/apache/commons/httpclient/HttpURL.java $
3    * $Revision$
4    * $Date$
5    *
6    * ====================================================================
7    *
8    *  Licensed to the Apache Software Foundation (ASF) under one or more
9    *  contributor license agreements.  See the NOTICE file distributed with
10   *  this work for additional information regarding copyright ownership.
11   *  The ASF licenses this file to You under the Apache License, Version 2.0
12   *  (the "License"); you may not use this file except in compliance with
13   *  the License.  You may obtain a copy of the License at
14   *
15   *      http://www.apache.org/licenses/LICENSE-2.0
16   *
17   *  Unless required by applicable law or agreed to in writing, software
18   *  distributed under the License is distributed on an "AS IS" BASIS,
19   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20   *  See the License for the specific language governing permissions and
21   *  limitations under the License.
22   * ====================================================================
23   *
24   * This software consists of voluntary contributions made by many
25   * individuals on behalf of the Apache Software Foundation.  For more
26   * information on the Apache Software Foundation, please see
27   * <http://www.apache.org/>.
28   *
29   */
30  
31  package org.apache.commons.httpclient;
32  
33  import org.apache.commons.httpclient.util.URIUtil;
34  
35  /***
36   * The HTTP URL.
37   *
38   * @author <a href="mailto:jericho at apache.org">Sung-Gu</a>
39   * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
40   */
41  public class HttpURL extends URI {
42  
43      // ----------------------------------------------------------- Constructors
44  
45      /*** Create an instance as an internal use. */
46      protected HttpURL() {
47      }
48  
49  
50      /***
51       * Construct a HTTP URL as an escaped form of a character array with the
52       * given charset to do escape encoding.
53       *
54       * @param escaped the HTTP URL character sequence
55       * @param charset the charset string to do escape encoding
56       * @throws URIException If {@link #checkValid()} fails
57       * @throws NullPointerException if <code>escaped</code> is <code>null</code>
58       * @see #getProtocolCharset
59       */
60      public HttpURL(char[] escaped, String charset)
61          throws URIException, NullPointerException {
62          protocolCharset = charset;
63          parseUriReference(new String(escaped), true);
64          checkValid();
65      }
66  
67  
68      /***
69       * Construct a HTTP URL as an escaped form of a character array.
70       *
71       * @param escaped the HTTP URL character sequence
72       * @throws URIException If {@link #checkValid()} fails
73       * @throws NullPointerException if <code>escaped</code> is <code>null</code>
74       * @see #getDefaultProtocolCharset
75       */
76      public HttpURL(char[] escaped) throws URIException, NullPointerException {
77          parseUriReference(new String(escaped), true);
78          checkValid();
79      }
80  
81  
82      /***
83       * Construct a HTTP URL from a given string with the given charset to do
84       * escape encoding.
85       *
86       * @param original the HTTP URL string
87       * @param charset the charset string to do escape encoding
88       * @throws URIException If {@link #checkValid()} fails
89       * @see #getProtocolCharset
90       */
91      public HttpURL(String original, String charset) throws URIException {
92          protocolCharset = charset;
93          parseUriReference(original, false);
94          checkValid();
95      }
96  
97  
98      /***
99       * Construct a HTTP URL from a given string.
100      *
101      * @param original the HTTP URL string
102      * @throws URIException If {@link #checkValid()} fails
103      * @see #getDefaultProtocolCharset
104      */
105     public HttpURL(String original) throws URIException {
106         parseUriReference(original, false);
107         checkValid();
108     }
109 
110 
111     /***
112      * Construct a HTTP URL from given components.
113      *
114      * @param host the host string
115      * @param port the port number
116      * @param path the path string
117      * @throws URIException If {@link #checkValid()} fails
118      * @see #getDefaultProtocolCharset
119      */
120     public HttpURL(String host, int port, String path) throws URIException {
121         this(null, null, host, port, path, null, null);
122     }
123 
124 
125     /***
126      * Construct a HTTP URL from given components.
127      *
128      * @param host the host string
129      * @param port the port number
130      * @param path the path string
131      * @param query the query string
132      * @throws URIException If {@link #checkValid()} fails
133      * @see #getDefaultProtocolCharset
134      */
135     public HttpURL(String host, int port, String path, String query)
136         throws URIException {
137 
138         this(null, null, host, port, path, query, null);
139     }
140 
141 
142     /***
143      * Construct a HTTP URL from given components.
144      *
145      * @param user the user name
146      * @param password his or her password
147      * @param host the host string
148      * @throws URIException If {@link #checkValid()} fails
149      * @see #getDefaultProtocolCharset
150      */
151     public HttpURL(String user, String password, String host)
152         throws URIException {
153 
154         this(user, password, host, -1, null, null, null);
155     }
156 
157 
158     /***
159      * Construct a HTTP URL from given components.
160      *
161      * @param user the user name
162      * @param password his or her password
163      * @param host the host string
164      * @param port the port number
165      * @throws URIException If {@link #checkValid()} fails
166      * @see #getDefaultProtocolCharset
167      */
168     public HttpURL(String user, String password, String host, int port)
169         throws URIException {
170 
171         this(user, password, host, port, null, null, null);
172     }
173 
174 
175     /***
176      * Construct a HTTP URL from given components.
177      *
178      * @param user the user name
179      * @param password his or her password
180      * @param host the host string
181      * @param port the port number
182      * @param path the path string
183      * @throws URIException If {@link #checkValid()} fails
184      * @see #getDefaultProtocolCharset
185      */
186     public HttpURL(String user, String password, String host, int port,
187             String path) throws URIException {
188 
189         this(user, password, host, port, path, null, null);
190     }
191 
192 
193     /***
194      * Construct a HTTP URL from given components.
195      *
196      * @param user the user name
197      * @param password his or her password
198      * @param host the host string
199      * @param port the port number
200      * @param path the path string
201      * @param query The query string.
202      * @throws URIException If {@link #checkValid()} fails
203      * @see #getDefaultProtocolCharset
204      */
205     public HttpURL(String user, String password, String host, int port,
206             String path, String query) throws URIException {
207 
208         this(user, password, host, port, path, query, null);
209     }
210 
211 
212     /***
213      * Construct a HTTP URL from given components.
214      *
215      * @param host the host string
216      * @param path the path string
217      * @param query the query string
218      * @param fragment the fragment string
219      * @throws URIException If {@link #checkValid()} fails
220      * @see #getDefaultProtocolCharset
221      */
222     public HttpURL(String host, String path, String query, String fragment)
223         throws URIException {
224 
225         this(null, null, host, -1, path, query, fragment);
226     }
227 
228 
229     /***
230      * Construct a HTTP URL from given components.
231      * 
232      * Note: The <code>userinfo</code> format is normally
233      * <code>&lt;username&gt;:&lt;password&gt;</code> where
234      * username and password must both be URL escaped. 
235      *
236      * @param userinfo the userinfo string whose parts are URL escaped
237      * @param host the host string
238      * @param path the path string
239      * @param query the query string
240      * @param fragment the fragment string
241      * @throws URIException If {@link #checkValid()} fails
242      * @see #getDefaultProtocolCharset
243      */
244     public HttpURL(String userinfo, String host, String path, String query,
245             String fragment) throws URIException {
246 
247         this(userinfo, host, -1, path, query, fragment);
248     }
249 
250 
251     /***
252      * Construct a HTTP URL from given components.
253      *
254      * Note: The <code>userinfo</code> format is normally
255      * <code>&lt;username&gt;:&lt;password&gt;</code> where
256      * username and password must both be URL escaped.
257      *  
258      * @param userinfo the userinfo string whose parts are URL escaped
259      * @param host the host string
260      * @param port the port number
261      * @param path the path string
262      * @throws URIException If {@link #checkValid()} fails
263      * @see #getDefaultProtocolCharset
264      */
265     public HttpURL(String userinfo, String host, int port, String path)
266         throws URIException {
267 
268         this(userinfo, host, port, path, null, null);
269     }
270 
271 
272     /***
273      * Construct a HTTP URL from given components.
274      *
275      * Note: The <code>userinfo</code> format is normally
276      * <code>&lt;username&gt;:&lt;password&gt;</code> where
277      * username and password must both be URL escaped.
278      *  
279      * @param userinfo the userinfo string whose parts are URL escaped
280      * @param host the host string
281      * @param port the port number
282      * @param path the path string
283      * @param query the query string
284      * @throws URIException If {@link #checkValid()} fails
285      * @see #getDefaultProtocolCharset
286      */
287     public HttpURL(String userinfo, String host, int port, String path,
288             String query) throws URIException {
289 
290         this(userinfo, host, port, path, query, null);
291     }
292 
293 
294     /***
295      * Construct a HTTP URL from given components.
296      *
297      * Note: The <code>userinfo</code> format is normally
298      * <code>&lt;username&gt;:&lt;password&gt;</code> where
299      * username and password must both be URL escaped.
300      *  
301      * @param userinfo the userinfo string whose parts are URL escaped
302      * @param host the host string
303      * @param port the port number
304      * @param path the path string
305      * @param query the query string
306      * @param fragment the fragment string
307      * @throws URIException If {@link #checkValid()} fails
308      * @see #getDefaultProtocolCharset
309      */
310     public HttpURL(String userinfo, String host, int port, String path,
311             String query, String fragment) throws URIException {
312 
313         // validate and contruct the URI character sequence
314         StringBuffer buff = new StringBuffer();
315         if (userinfo != null || host != null || port != -1) {
316             _scheme = DEFAULT_SCHEME; // in order to verify the own protocol
317             buff.append(_default_scheme);
318             buff.append("://");
319             if (userinfo != null) {
320                 buff.append(userinfo);
321                 buff.append('@');
322             }
323             if (host != null) {
324                 buff.append(URIUtil.encode(host, URI.allowed_host));
325                 if (port != -1 || port != DEFAULT_PORT) {
326                     buff.append(':');
327                     buff.append(port);
328                 }
329             }
330         }
331         if (path != null) {  // accept empty path
332             if (scheme != null && !path.startsWith("/")) {
333                 throw new URIException(URIException.PARSING,
334                         "abs_path requested");
335             }
336             buff.append(URIUtil.encode(path, URI.allowed_abs_path));
337         }
338         if (query != null) {
339             buff.append('?');
340             buff.append(URIUtil.encode(query, URI.allowed_query));
341         }
342         if (fragment != null) {
343             buff.append('#');
344             buff.append(URIUtil.encode(fragment, URI.allowed_fragment));
345         }
346         parseUriReference(buff.toString(), true);
347         checkValid();
348     }
349 
350 
351     /***
352      * Construct a HTTP URL from given components.
353      *
354      * @param user the user name
355      * @param password his or her password
356      * @param host the host string
357      * @param port the port number
358      * @param path the path string
359      * @param query the query string
360      * @param fragment the fragment string
361      * @throws URIException If {@link #checkValid()} fails
362      * @see #getDefaultProtocolCharset
363      */
364     public HttpURL(String user, String password, String host, int port,
365             String path, String query, String fragment) throws URIException {
366         this(toUserinfo(user, password), host, port, path, query, fragment);
367     }
368     
369     protected static String toUserinfo(String user, String password) throws URIException {
370         if (user == null) return null;
371         StringBuffer usrinfo = new StringBuffer(20); //sufficient for real world
372         usrinfo.append(URIUtil.encode(user, URI.allowed_within_userinfo));
373         if (password == null) return usrinfo.toString();
374         usrinfo.append(':');
375         usrinfo.append(URIUtil.encode(password, URI.allowed_within_userinfo));
376         return usrinfo.toString();
377     }
378 
379 
380     /***
381      * Construct a HTTP URL with a given relative URL string.
382      *
383      * @param base the base HttpURL
384      * @param relative the relative HTTP URL string
385      * @throws URIException If {@link #checkValid()} fails
386      */
387     public HttpURL(HttpURL base, String relative) throws URIException {
388         this(base, new HttpURL(relative));
389     }
390 
391 
392     /***
393      * Construct a HTTP URL with a given relative URL.
394      *
395      * @param base the base HttpURL
396      * @param relative the relative HttpURL
397      * @throws URIException If {@link #checkValid()} fails
398      */
399     public HttpURL(HttpURL base, HttpURL relative) throws URIException {
400         super(base, relative);
401         checkValid();
402     }
403 
404     // -------------------------------------------------------------- Constants
405 
406     /***
407      * Default scheme for HTTP URL.
408      */
409     public static final char[] DEFAULT_SCHEME = { 'h', 't', 't', 'p' };
410 
411     /***
412      * Default scheme for HTTP URL.
413      * @deprecated Use {@link #DEFAULT_SCHEME} instead.  This one doesn't
414      * conform to the project naming conventions.
415      */
416     public static final char[] _default_scheme = DEFAULT_SCHEME;
417 
418     /***
419      * Default port for HTTP URL.
420      */
421     public static final int DEFAULT_PORT = 80;
422 
423     /***
424      * Default port for HTTP URL.
425      * @deprecated Use {@link #DEFAULT_PORT} instead.  This one doesn't conform
426      * to the project naming conventions.
427      */
428     public static final int _default_port = DEFAULT_PORT;
429 
430     /***
431      * The serialVersionUID.
432      */
433     static final long serialVersionUID = -7158031098595039459L;
434 
435     // ------------------------------------------------------------- The scheme
436 
437     /***
438      * Get the scheme.  You can get the scheme explicitly.
439      *
440      * @return the scheme
441      */
442     public char[] getRawScheme() {
443         return (_scheme == null) ? null : HttpURL.DEFAULT_SCHEME;
444     }
445 
446 
447     /***
448      * Get the scheme.  You can get the scheme explicitly.
449      *
450      * @return the scheme null if empty or undefined
451      */
452     public String getScheme() {
453         return (_scheme == null) ? null : new String(HttpURL.DEFAULT_SCHEME);
454     }
455 
456     // --------------------------------------------------------------- The port
457 
458     /***
459      * Get the port number.
460      * @return the port number
461      */
462     public int getPort() {
463         return (_port == -1) ? HttpURL.DEFAULT_PORT : _port;
464     }
465 
466     // ----------------------------------------------------------- The userinfo
467 
468     /***
469      * Set the raw-escaped user and password.
470      *
471      * @param escapedUser the raw-escaped user
472      * @param escapedPassword the raw-escaped password; could be null
473      * @throws URIException escaped user not valid or user required; escaped
474      * password not valid or username missed
475      */
476     public void setRawUserinfo(char[] escapedUser, char[] escapedPassword)
477         throws URIException {
478 
479         if (escapedUser == null || escapedUser.length == 0) {
480             throw new URIException(URIException.PARSING, "user required");
481         }
482         if (!validate(escapedUser, within_userinfo) 
483             || ((escapedPassword != null) 
484             && !validate(escapedPassword, within_userinfo))) {
485             throw new URIException(URIException.ESCAPING,
486                     "escaped userinfo not valid");
487         }
488         String username = new String(escapedUser);
489         String password = (escapedPassword == null) 
490             ? null : new String(escapedPassword);
491         String userinfo = username + ((password == null) ? "" : ":" + password);
492         String hostname = new String(getRawHost());
493         String hostport = (_port == -1) ? hostname : hostname + ":" + _port;
494         String authority = userinfo + "@" + hostport;
495         _userinfo = userinfo.toCharArray();
496         _authority = authority.toCharArray();
497         setURI();
498     }
499 
500 
501     /***
502      * Set the raw-escaped user and password.
503      *
504      * @param escapedUser the escaped user
505      * @param escapedPassword the escaped password; could be null
506      * @throws URIException escaped user not valid or user required; escaped
507      * password not valid or username missed
508      * @throws NullPointerException null user
509      */
510     public void setEscapedUserinfo(String escapedUser, String escapedPassword)
511         throws URIException, NullPointerException {
512 
513         setRawUserinfo(escapedUser.toCharArray(), (escapedPassword == null) 
514             ? null : escapedPassword.toCharArray());
515     }
516 
517 
518     /***
519      * Set the user and password.
520      *
521      * @param user the user
522      * @param password the password; could be null
523      * @throws URIException encoding error or username missed
524      * @throws NullPointerException null user
525      */
526     public void setUserinfo(String user, String password) 
527         throws URIException, NullPointerException {
528         // set the charset to do escape encoding
529         String charset = getProtocolCharset();
530         setRawUserinfo(encode(user, within_userinfo, charset),
531                 (password == null) 
532                 ? null 
533                 : encode(password, within_userinfo, charset));
534     }
535 
536 
537     /***
538      * Set the raw-escaped user.
539      *
540      * @param escapedUser the raw-escaped user
541      * @throws URIException escaped user not valid or user required
542      */
543     public void setRawUser(char[] escapedUser) throws URIException {
544         if (escapedUser == null || escapedUser.length == 0) {
545             throw new URIException(URIException.PARSING, "user required");
546         }
547         if (!validate(escapedUser, within_userinfo)) {
548             throw new URIException(URIException.ESCAPING,
549                     "escaped user not valid");
550         }
551         String username = new String(escapedUser);
552         char[] rawPassword = getRawPassword();
553 		String password = rawPassword == null ? null : new String(rawPassword);
554         String userinfo = username + ((password == null) ? "" : ":" + password);
555         String hostname = new String(getRawHost());
556         String hostport = (_port == -1) ? hostname : hostname + ":" + _port;
557         String authority = userinfo + "@" + hostport;
558         _userinfo = userinfo.toCharArray();
559         _authority = authority.toCharArray();
560         setURI();
561     }
562 
563 
564     /***
565      * Set the escaped user string.
566      *
567      * @param escapedUser the escaped user string
568      * @throws URIException escaped user not valid
569      * @throws NullPointerException null user
570      */
571     public void setEscapedUser(String escapedUser)
572         throws URIException, NullPointerException {
573         setRawUser(escapedUser.toCharArray());
574     }
575 
576 
577     /***
578      * Set the user string.
579      *
580      * @param user the user string
581      * @throws URIException user encoding error
582      * @throws NullPointerException null user
583      */
584     public void setUser(String user) throws URIException, NullPointerException {
585         setRawUser(encode(user, allowed_within_userinfo, getProtocolCharset()));
586     }
587 
588 
589     /***
590      * Get the raw-escaped user.
591      *
592      * @return the raw-escaped user
593      */
594     public char[] getRawUser() {
595         if (_userinfo == null || _userinfo.length == 0) {
596             return null;
597         }
598         int to = indexFirstOf(_userinfo, ':');
599         // String.indexOf(':', 0, _userinfo.length, _userinfo, 0, 1, 0);
600         if (to == -1) {
601             return _userinfo; // only user.
602         }
603         char[] result = new char[to];
604         System.arraycopy(_userinfo, 0, result, 0, to);
605         return result;
606     }
607 
608 
609     /***
610      * Get the escaped user
611      *
612      * @return the escaped user
613      */
614     public String getEscapedUser() {
615         char[] user = getRawUser();
616         return (user == null) ? null : new String(user);
617     }
618 
619 
620     /***
621      * Get the user.
622      *
623      * @return the user name
624      * @throws URIException If {@link #decode} fails
625      */
626     public String getUser() throws URIException {
627         char[] user = getRawUser();
628         return (user == null) ? null : decode(user, getProtocolCharset());
629     }
630 
631 
632     /***
633      * Set the raw-escaped password.
634      *
635      * @param escapedPassword the raw-escaped password; could be null
636      * @throws URIException escaped password not valid or username missed
637      */
638     public void setRawPassword(char[] escapedPassword) throws URIException {
639         if (escapedPassword != null 
640             && !validate(escapedPassword, within_userinfo)) {
641             throw new URIException(URIException.ESCAPING,
642                "escaped password not valid");
643         }
644         if (getRawUser() == null || getRawUser().length == 0) {
645             throw new URIException(URIException.PARSING, "username required");
646         }
647         String username = new String(getRawUser());
648         String password = escapedPassword == null ? null : new String(escapedPassword);
649         // an emtpy string is allowed as a password
650         String userinfo = username + ((password == null) ? "" : ":" + password);
651         String hostname = new String(getRawHost());
652         String hostport = (_port == -1) ? hostname : hostname + ":" + _port;
653         String authority = userinfo + "@" + hostport;
654         _userinfo = userinfo.toCharArray();
655         _authority = authority.toCharArray();
656         setURI();
657     }
658 
659 
660     /***
661      * Set the escaped password string.
662      *
663      * @param escapedPassword the escaped password string; could be null
664      * @throws URIException escaped password not valid or username missed
665      */
666     public void setEscapedPassword(String escapedPassword) throws URIException {
667         setRawPassword((escapedPassword == null) ? null 
668             : escapedPassword.toCharArray());
669     }
670 
671 
672     /***
673      * Set the password string.
674      *
675      * @param password the password string; could be null
676      * @throws URIException encoding error or username missed
677      */
678     public void setPassword(String password) throws URIException {
679         setRawPassword((password == null) ? null : encode(password,
680                     allowed_within_userinfo, getProtocolCharset()));
681     }
682 
683 
684     /***
685      * Get the raw-escaped password.
686      *
687      * @return the raw-escaped password
688      */
689     public char[] getRawPassword() {
690         int from = indexFirstOf(_userinfo, ':');
691         if (from == -1) {
692             return null; // null or only user.
693         }
694         int len = _userinfo.length - from - 1;
695         char[] result = new char[len];
696         System.arraycopy(_userinfo, from + 1, result, 0, len);
697         return result;
698     }
699 
700 
701     /***
702      * Get the escaped password.
703      *
704      * @return the escaped password
705      */
706     public String getEscapedPassword() {
707         char[] password = getRawPassword();
708         return (password == null) ? null : new String(password);
709     }
710 
711 
712     /***
713      * Get the password.
714      *
715      * @return the password
716      * @throws URIException If {@link #decode(char[],String)} fails.
717      */
718     public String getPassword() throws URIException {
719         char[] password = getRawPassword();
720         return (password == null) ? null : decode(password,
721                 getProtocolCharset());
722     }
723 
724     // --------------------------------------------------------------- The path
725 
726     /***
727      * Get the raw-escaped current hierarchy level.
728      *
729      * @return the raw-escaped current hierarchy level
730      * @throws URIException If {@link #getRawCurrentHierPath(char[])} fails.
731      */
732     public char[] getRawCurrentHierPath() throws URIException {
733         return (_path == null || _path.length == 0) ? rootPath 
734             : super.getRawCurrentHierPath(_path);
735     }
736 
737 
738     /***
739      * Get the level above the this hierarchy level.
740      *
741      * @return the raw above hierarchy level
742      * @throws URIException If {@link #getRawCurrentHierPath(char[])} fails.
743      */
744     public char[] getRawAboveHierPath() throws URIException {
745         char[] path = getRawCurrentHierPath();
746         return (path == null || path.length == 0) ? rootPath : getRawCurrentHierPath(path);
747     }
748 
749 
750     /***
751      * Get the raw escaped path.
752      *
753      * @return the path '/' if empty or undefined
754      */
755     public char[] getRawPath() {
756         char[] path =  super.getRawPath();
757         return (path == null || path.length == 0) ? rootPath : path;
758     }
759 
760     // -------------------------------------------------------------- The query
761 
762     /***
763      * Set the query as the name and value pair.
764      *
765      * @param queryName the query string.
766      * @param queryValue the query string.
767      * @throws URIException incomplete trailing escape pattern
768      * Or unsupported character encoding
769      * @throws NullPointerException null query
770      * @see #encode
771      */
772     public void setQuery(String queryName, String queryValue)
773         throws URIException, NullPointerException {
774 
775         StringBuffer buff = new StringBuffer();
776         // set the charset to do escape encoding
777         String charset = getProtocolCharset();
778         buff.append(encode(queryName, allowed_within_query, charset));
779         buff.append('=');
780         buff.append(encode(queryValue, allowed_within_query, charset));
781         _query = buff.toString().toCharArray();
782         setURI();
783     }
784 
785 
786     /***
787      * Set the query as the name and value pairs.
788      *
789      * @param queryName the array of the query string.
790      * @param queryValue the array of the query string.
791      * @throws URIException incomplete trailing escape pattern,
792      * unsupported character encoding or wrong array size
793      * @throws NullPointerException null query
794      * @see #encode
795      */
796     public void setQuery(String[] queryName, String[] queryValue)
797         throws URIException, NullPointerException {
798 
799         int length = queryName.length;
800         if (length != queryValue.length) {
801             throw new URIException("wrong array size of query");
802         }
803 
804         StringBuffer buff = new StringBuffer();
805         // set the charset to do escape encoding
806         String charset = getProtocolCharset();
807         for (int i = 0; i < length; i++) {
808             buff.append(encode(queryName[i], allowed_within_query, charset));
809             buff.append('=');
810             buff.append(encode(queryValue[i], allowed_within_query, charset));
811             if (i + 1 < length) { 
812                 buff.append('&');
813             }
814         }
815         _query = buff.toString().toCharArray();
816         setURI();
817     }
818 
819     // ---------------------------------------------------------------- Utility
820 
821     /***
822      * Verify the valid class use for construction.
823      *
824      * @throws URIException the wrong scheme use
825      */
826     protected void checkValid() throws URIException {
827         // could be explicit protocol or undefined.
828         if (!(equals(_scheme, DEFAULT_SCHEME) || _scheme == null)) {
829             throw new URIException(URIException.PARSING, "wrong class use");
830         }
831     }
832 
833     /***
834      * Once it's parsed successfully, set this URI.
835      *
836      * @see #getRawURI
837      */
838     protected void setURI() {
839         // set _uri
840         StringBuffer buf = new StringBuffer();
841         // ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
842         if (_scheme != null) {
843             buf.append(_scheme);
844             buf.append(':');
845         }
846         if (_is_net_path) {
847             buf.append("//");
848             if (_authority != null) { // has_authority
849                 if (_userinfo != null) { // by default, remove userinfo part
850                     if (_host != null) {
851                         buf.append(_host);
852                         if (_port != -1) {
853                             buf.append(':');
854                             buf.append(_port);
855                         }
856                     }
857                 } else {
858                     buf.append(_authority);
859                 }
860             }
861         }
862         if (_opaque != null && _is_opaque_part) {
863             buf.append(_opaque);
864         } else if (_path != null) {
865             // _is_hier_part or _is_relativeURI
866             if (_path.length != 0) {
867                 buf.append(_path);
868             }
869         }
870         if (_query != null) { // has_query
871             buf.append('?');
872             buf.append(_query);
873         }
874         // ignore the fragment identifier
875         _uri = buf.toString().toCharArray();
876         hash = 0;
877     }
878     
879 }
880