KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > beehive > netui > core > urls > MutableURI


1 /*
2  * Copyright 2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  * $Header:$
17  */

18 package org.apache.beehive.netui.core.urls;
19
20 import org.apache.beehive.netui.util.internal.InternalStringBuilder;
21
22 import org.apache.beehive.netui.core.URLCodec;
23
24 import java.net.URI JavaDoc;
25 import java.net.URISyntaxException JavaDoc;
26 import java.net.URL JavaDoc;
27 import java.util.ArrayList JavaDoc;
28 import java.util.Collections JavaDoc;
29 import java.util.Iterator JavaDoc;
30 import java.util.LinkedHashMap JavaDoc;
31 import java.util.List JavaDoc;
32 import java.util.Map JavaDoc;
33 import java.util.StringTokenizer JavaDoc;
34 import java.util.HashMap JavaDoc;
35
36 /**
37  * Mutable class for creating URIs.
38  *
39  * <p> There is little checking that an instance of this class produces a legal
40  * URI reference as defined by <a HREF="http://www.ietf.org/rfc/rfc2396.txt">
41  * <i>RFC&nbsp;2396: Uniform Resource Identifiers (URI): Generic Syntax</i></a>.
42  * The minimal checking for syntax is on constructors that take a String
43  * representation or the URI, a {@link URI}, or a {@link URL}.
44  * To avoid the cost of continually checking the syntax, it is up to the
45  * user to ensure that the components are set correctly. </p>
46  *
47  * <p> The setters of this class also assume that the data components are
48  * already encoded correctly for the given encoding of this URI, unless noted
49  * otherwise as in the methods to add unecoded parameters to the query.
50  * Then this class will handle the encoding.
51  * See {@link #addParameter( String name, String value, boolean encoded )}
52  * and {@link #addParameters( Map newParams, boolean encoded )}
53  * </p>
54  *
55  * <p> There is a static convenience method in this class so callers can
56  * easily encode unencoded components before setting it in this object. </p>
57  *
58  * TODO... We need to implement some conditions for opaque URIs like mailto, etc.
59  * to determine what to do about values of path when (path == null) => opaque and
60  * URI.getPath() would return "" for non-opaue URIs.
61  */

62 public class MutableURI
63 {
64     /** Value used to set the port as undefined. */
65     public static final int UNDEFINED_PORT = -1;
66
67     /** Value used to set the encoding as undefined. */
68     public static final String JavaDoc DEFAULT_ENCODING = "UTF-8";
69
70     /** Character encoding used for the URI. */
71     private String JavaDoc _encoding;
72
73     /** Protocol scheme. */
74     private String JavaDoc _scheme;
75
76     /**
77      * User information "may consist of a user name and, optionally,
78      * scheme-specific information about how to gain authorization to
79      * access the server.
80      */

81     private String JavaDoc _userInfo;
82
83     /** Host */
84     private String JavaDoc _host;
85
86     /** Port */
87     private int _port = UNDEFINED_PORT;
88
89     /** Path */
90     private String JavaDoc _path;
91
92     /** Query parameters */
93     private LinkedHashMap JavaDoc/*< String, List< String > >*/ _params;
94
95     /** Fragment */
96     private String JavaDoc _fragment;
97
98     /* Separators for query parameters */
99     private static final String JavaDoc AMP_ENTITY = "&amp;";
100     private static final String JavaDoc AMP_CHAR = "&";
101
102     private static final Map JavaDoc/*< String, List< String > >*/ EMPTY_MAP =
103             Collections.unmodifiableMap( new HashMap JavaDoc/*< String, List< String > >*/() );
104     
105     /**
106      * Constructs a <code>MutableURI</code>.
107      */

108     public MutableURI()
109     {
110     }
111
112     /**
113      * Constructs a <code>MutableURI</code>.
114      *
115      * @param uriString the string to be parsed into a URI
116      * @param encoded Flag indicating whether the string is
117      * already encoded.
118      */

119     public MutableURI( String JavaDoc uriString, boolean encoded ) throws URISyntaxException JavaDoc
120     {
121         assert uriString != null : "The uri cannot be null.";
122
123         if ( uriString == null )
124         {
125             throw new IllegalArgumentException JavaDoc( "The URI cannot be null." );
126         }
127
128         URI JavaDoc uri = null;
129
130         if ( encoded )
131         {
132             // Get (parse) the components using java.net.URI
133
uri = new URI JavaDoc( uriString );
134         }
135         else
136         {
137             // Parse, then encode this string into its components using URI
138
uri = encodeURI( uriString );
139         }
140
141         setURI( uri );
142     }
143
144     /**
145      * Constructs a <code>MutableURI</code>. Assumes the individual components
146      * are already encoded and escaped.
147      *
148      * @param scheme the name of the protocol to use
149      * @param userInfo the username and password
150      * @param host the name of the host
151      * @param port the port number on the host
152      * @param path the file on the host
153      * @param query the query part of this URI
154      * @param fragment the fragment part of this URI (internal reference in the URL)
155      */

156     public MutableURI( String JavaDoc scheme, String JavaDoc userInfo, String JavaDoc host, int port,
157                        String JavaDoc path, String JavaDoc query, String JavaDoc fragment )
158     {
159         setScheme( scheme );
160         setUserInfo( userInfo );
161         setHost( host );
162         setPort( port );
163         setPath( path );
164         setQuery( query );
165         setFragment( fragment );
166     }
167
168     /**
169      * Constructs a <code>MutableURI</code>.
170      *
171      * @param uri the initial value for this mutable URI
172      */

173     public MutableURI( URI JavaDoc uri )
174     {
175         assert uri != null : "The URI cannot be null.";
176
177         if ( uri == null )
178         {
179             throw new IllegalArgumentException JavaDoc( "The URI cannot be null." );
180         }
181
182         setURI( uri );
183     }
184
185     /**
186      * Constructs a <code>MutableURI</code>.
187      *
188      * <p> This is just a convenience constructor that functions the same as
189      * {@link #MutableURI(URI)} constructor with
190      * {@link java.net.URL#toURI()} as the argument. </p>
191      *
192      * <p>Note, any URL instance that complies with RFC 2396 can be converted
193      * to a URI. However, some URLs that are not strictly in compliance
194      * can not be converted to a URI. See {@link java.net.URL} </p>
195      *
196      * @param url the initial value for this mutable URI
197      * @exception URISyntaxException if this URL is not formatted strictly
198      * to RFC2396 and cannot be converted to a URI.
199      * @see java.net.URL#toURI()
200      */

201     public MutableURI( URL JavaDoc url ) throws URISyntaxException JavaDoc
202     {
203         assert url != null : "The URL cannot be null.";
204
205         if ( url == null )
206         {
207             throw new IllegalArgumentException JavaDoc( "The URL cannot be null." );
208         }
209
210         URI JavaDoc uri = url.toURI();
211         setURI( uri );
212     }
213
214     /**
215      * Set the value of the <code>MutableURI</code>.
216      *
217      * <p> This method can also be used to clear the <code>MutableURI</code>. </p>
218      *
219      * @param uriString the string to be parsed into a URI
220      * @param encoded Flag indicating whether the string is
221      * already encoded.
222      */

223     public void setURI( String JavaDoc uriString, boolean encoded ) throws URISyntaxException JavaDoc
224     {
225         if ( uriString == null )
226         {
227             setScheme( null );
228             setUserInfo( null );
229             setHost( null );
230             setPort( UNDEFINED_PORT );
231             setPath( null );
232             setQuery( null );
233             setFragment( null );
234         }
235         else
236         {
237             URI JavaDoc uri = null;
238
239             if ( encoded )
240             {
241                 // Get (parse) the components using java.net.URI
242
uri = new URI JavaDoc( uriString );
243             }
244             else
245             {
246                 // Parse, then encode this string into its components using URI
247
uri = encodeURI( uriString );
248             }
249
250             setURI( uri );
251         }
252     }
253
254     /**
255      * Set the value of the <code>MutableURI</code>.
256      *
257      * <p> This method can also be used to clear the <code>MutableURI</code>. </p>
258      *
259      * @param uri the URI
260      */

261     public void setURI( URI JavaDoc uri )
262     {
263         setScheme( uri.getScheme() );
264         setUserInfo( uri.getRawUserInfo() );
265         setHost( uri.getHost() );
266         setPort( uri.getPort() );
267         setPath( uri.getRawPath() );
268         setQuery( uri.getRawQuery() );
269         setFragment( uri.getRawFragment() );
270     }
271
272     /**
273      * Set the encoding used when adding unencoded parameters.
274      *
275      * @param encoding
276      */

277     public void setEncoding( String JavaDoc encoding )
278     {
279         _encoding = encoding;
280     }
281
282     /**
283      * Returns the character encoding that is used when adding unencoded parameters.
284      *
285      * @return encoding
286      */

287     public String JavaDoc getEncoding()
288     {
289         return _encoding;
290     }
291
292     /**
293      * Sets the protocol/scheme.
294      *
295      * @param scheme protocol/scheme
296      */

297     public void setScheme( String JavaDoc scheme )
298     {
299         _scheme = null;
300         if ( scheme != null && scheme.length() > 0 )
301         {
302             _scheme = scheme;
303         }
304     }
305
306     /**
307      * Returns the protocol/scheme. If no protocol was previously set,
308      * returns null.
309      *
310      * @return protocol/scheme
311      */

312     public String JavaDoc getScheme()
313     {
314         return _scheme;
315     }
316
317     /**
318      * Sets the userInfo. Assumes this component is already escaped.
319      *
320      * @param userInfo userInfo
321      */

322     public void setUserInfo( String JavaDoc userInfo )
323     {
324         _userInfo = null;
325         if ( userInfo != null && userInfo.length() > 0 )
326         {
327             _userInfo = userInfo;
328         }
329     }
330
331     /**
332      * Returns the userInfo. If no host was previously set, returns
333      * null.
334      *
335      * @return userInfo
336      */

337     public String JavaDoc getUserInfo()
338     {
339         return _userInfo;
340     }
341
342     /**
343      * Sets the host.
344      *
345      * @param host host
346      */

347     public void setHost( String JavaDoc host )
348     {
349         _host = null;
350         if ( host != null && host.length() > 0 )
351         {
352             //
353
// Here's some very minimal support for IPv6 addresses.
354
// If the literal IPv6 address is not enclosed in square brackets
355
// then add them.
356
//
357
boolean needBrackets = ( ( host.indexOf( ':' ) >= 0 )
358                     && !host.startsWith( "[" )
359                     && !host.endsWith( "]" ) );
360
361             if ( needBrackets )
362             {
363                 _host = '[' + host + ']';
364             }
365             else
366             {
367                 _host = host;
368             }
369         }
370
371         if ( _host == null )
372         {
373             setUserInfo( null );
374             setPort( UNDEFINED_PORT );
375         }
376     }
377
378     /**
379      * Returns the host. If no host was previously set, returns
380      * null.
381      *
382      * @return host
383      */

384     public String JavaDoc getHost()
385     {
386         return _host;
387     }
388
389     /**
390      * Sets the port.
391      *
392      * @param port port
393      */

394     public void setPort( int port )
395     {
396         assert ( port >= 0 && port <= 65535 ) || ( port == UNDEFINED_PORT )
397                  : "Invalid port" ;
398
399         if ( ( port > 65535 ) || ( port < 0 && port != UNDEFINED_PORT ) )
400         {
401              throw new IllegalArgumentException JavaDoc( "A port must be between 0 and 65535 or equal to "
402                                                  + UNDEFINED_PORT + ".");
403         }
404
405         _port = port;
406     }
407
408     /**
409      * Returns the port. If no port was previously set, returns
410      * null.
411      *
412      * @return port
413      */

414     public int getPort()
415     {
416         return _port;
417     }
418
419     /**
420      * Sets the path. Assumes this component is already escaped.
421      *
422      * @param path path
423      */

424     public void setPath( String JavaDoc path )
425     {
426         // Note that an empty path is OK
427
if ( path == null )
428         {
429             _path = null;
430             setQuery( null );
431             setFragment( null );
432         }
433         else
434         {
435             _path = path;
436         }
437     }
438
439     /**
440      * Returns the path.
441      *
442      * @return path
443      */

444     public String JavaDoc getPath()
445     {
446         return _path;
447     }
448
449     /**
450      * Sets (and resets) the query string.
451      * This method assumes that the query is already encoded and
452      * escaped.
453      *
454      * @param query Query string
455      */

456     public void setQuery( String JavaDoc query )
457     {
458         _params = null;
459
460         if ( query == null || query.length() == 0 ) { return; }
461
462         for ( StringTokenizer JavaDoc tok = new StringTokenizer JavaDoc( query, "&" ); tok.hasMoreElements(); )
463         {
464             String JavaDoc queryItem = tok.nextToken();
465
466             if ( queryItem.startsWith( "amp;" ) )
467             {
468                 queryItem = queryItem.substring( 4 );
469             }
470
471             int eq = queryItem.indexOf( '=' );
472             if ( eq != -1 )
473             {
474                 addParameter( queryItem.substring( 0, eq ) , queryItem.substring( eq + 1 ), true );
475             }
476             else
477             {
478                 addParameter( queryItem, null, true );
479             }
480         }
481     }
482
483     /**
484      * Returns the query string (encoded/escaped).
485      *
486      * <p> The context states whether or not to use the default delimiter,
487      * usually the &quot;&amp;amp;&quot; entity, to separate the parameters.
488      * Otherwise, the &quot;&amp;&quot; character is used. </p>
489      *
490      * @param uriContext has property indicating if we use the HTML Amp entity
491      * to separate the query parameters.
492      * @return encoded query string.
493      */

494     public String JavaDoc getQuery( URIContext uriContext )
495     {
496         if ( _params == null || _params.isEmpty() ) { return null; }
497
498         String JavaDoc paramSeparator = AMP_ENTITY;
499         if ( uriContext == null )
500         {
501             uriContext = getDefaultContext();
502         }
503
504         if ( !uriContext.useAmpEntity() )
505         {
506             paramSeparator = AMP_CHAR;
507         }
508
509         InternalStringBuilder query = new InternalStringBuilder( 64 );
510         boolean firstParam = true;
511         for ( Iterator JavaDoc i = _params.keySet().iterator(); i.hasNext(); )
512         {
513             String JavaDoc name = ( String JavaDoc ) i.next();
514             
515             for ( Iterator JavaDoc j = ( ( List JavaDoc ) _params.get( name ) ).iterator(); j.hasNext(); )
516             {
517                 String JavaDoc value = ( String JavaDoc ) j.next();
518                 
519                 if ( firstParam )
520                 {
521                     firstParam = false;
522                 }
523                 else
524                 {
525                     query.append( paramSeparator );
526                 }
527
528                 query.append( name );
529
530                 if ( value != null ) { query.append( '=' ).append( value ); }
531             }
532         }
533
534         return query.toString();
535     }
536
537     /**
538      * Add a parameter for the query string.
539      * <p> If the encoded flag is true then this method assumes that
540      * the name and value do not need encoding or are already encoded
541      * correctly. Otherwise, it translates the name and value with the
542      * character encoding of this URI and adds them to the set of
543      * parameters for the query. If the encoding for this URI has
544      * not been set, then the default encoding used is "UTF-8". </p>
545      * <p> Multiple values for the same parameter can be set by
546      * calling this method multiple times with the same name. </p>
547      *
548      * @param name name
549      * @param value value
550      * @param encoded Flag indicating whether the names and values are
551      * already encoded.
552      */

553     public void addParameter( String JavaDoc name, String JavaDoc value, boolean encoded )
554     {
555         if ( name == null ) throw new IllegalArgumentException JavaDoc( "A parameter name may not be null." );
556
557         if ( !encoded )
558         {
559             name = encode( name );
560             value = encode( value );
561         }
562
563         if ( _params == null ) _params = new LinkedHashMap JavaDoc/*< String, List< String > >*/();
564         List JavaDoc/*< String >*/ values = ( List JavaDoc ) _params.get( name );
565         
566         if ( values == null )
567         {
568             values = new ArrayList JavaDoc/*< String >*/();
569             _params.put( name, values );
570         }
571
572         values.add( value );
573     }
574
575     /**
576      * Add a parameter to the query string.
577      * <p> If the encoded flag is true then this method assumes that
578      * the name and value do not need encoding or are already encoded
579      * correctly. Otherwise, it translates the name and value with the
580      * character encoding of this URI and adds them to the set of
581      * parameters for the query. If the encoding for this URI has
582      * not been set, then the default encoding used is "UTF-8". </p>
583      *
584      * @param newParams the map of new parameters to add to the URI
585      * @param encoded Flag indicating whether the names and values are
586      * already encoded.
587      */

588     public void addParameters( Map JavaDoc newParams, boolean encoded )
589     {
590         if ( newParams == null )
591         {
592             throw new IllegalArgumentException JavaDoc( "Cannot add null map of parameters." );
593         }
594         
595         if ( newParams.size() == 0 )
596         {
597             return;
598         }
599
600         if ( _params == null )
601         {
602             _params = new LinkedHashMap JavaDoc/*< String, List< String > >*/();
603         }
604
605         Iterator JavaDoc keys = newParams.keySet().iterator();
606         while ( keys.hasNext() )
607         {
608             String JavaDoc name = ( String JavaDoc ) keys.next();
609             String JavaDoc encodedName = name;
610
611             if ( !encoded ) { encodedName = encode( name ); }
612
613             List JavaDoc/*< String >*/ values = ( List JavaDoc ) _params.get( encodedName );
614             if ( values == null )
615             {
616                 values = new ArrayList JavaDoc/*< String >*/();
617                 _params.put( encodedName, values );
618             }
619
620             Object JavaDoc newValue = newParams.get( name );
621             if ( newValue == null )
622             {
623                 values.add( null );
624             }
625             else if ( newValue instanceof String JavaDoc )
626             {
627                 addValue( values, ( String JavaDoc ) newValue, encoded );
628             }
629             else if ( newValue instanceof String JavaDoc[] )
630             {
631                 String JavaDoc newValues[] = ( String JavaDoc[] ) newValue;
632                 for ( int i = 0; i < newValues.length; i++ )
633                 {
634                     addValue( values, newValues[i], encoded );
635                 }
636             }
637             else if ( newValue instanceof List JavaDoc )
638             {
639                 Iterator JavaDoc newValues = ( ( List JavaDoc ) newValue ).iterator();
640                 while ( newValues.hasNext() )
641                 {
642                     addValue( values, newValues.next().toString(), encoded );
643                 }
644             }
645             else /* Convert other objects to a string */
646             {
647                 addValue( values, newValue.toString(), encoded );
648             }
649         }
650     }
651
652     private void addValue( List JavaDoc/*< String >*/ list, String JavaDoc value, boolean encoded )
653     {
654         if ( !encoded )
655         {
656             value = encode( value );
657         }
658
659         list.add( value );
660     }
661
662     /**
663      * Returns the value of the parameter. If the parameter has
664      * several values, returns the first value.
665      *
666      * @param name name of the parameter
667      * @return value of the given parameter name (or just the first in the list
668      * if there are multiple values for the given name)
669      */

670     public String JavaDoc getParameter( String JavaDoc name )
671     {
672         if ( _params == null ) { return null; }
673
674         List JavaDoc/*< String >*/ values = ( List JavaDoc ) _params.get( name );
675         if ( values != null && values.size() > 0 )
676         {
677             return ( String JavaDoc ) values.get( 0 );
678         }
679         else
680         {
681             return null;
682         }
683     }
684
685     /**
686      * Returns the values of the given parameter.
687      *
688      * @param name name of the parameter
689      * @return an unmodifable {@link java.util.List} of values for the given parameter name
690      */

691     public List JavaDoc/*< String >*/ getParameters( String JavaDoc name )
692     {
693         if ( _params == null )
694         {
695             return Collections.EMPTY_LIST;
696         }
697         else
698         {
699             List JavaDoc/*< String >*/ values = ( List JavaDoc ) _params.get( name );
700
701             if ( values == null )
702             {
703                 return Collections.EMPTY_LIST;
704             }
705             else
706             {
707                 return Collections.unmodifiableList( values );
708             }
709         }
710     }
711
712     /**
713      * Returns an unmodifiable Map of all parameters.
714      *
715      * @return an unmodifiable {@link java.util.Map} of names and values for all parameters
716      */

717     public Map JavaDoc/*< String, List< String > >*/ getParameters()
718     {
719         if ( _params == null )
720         {
721             return EMPTY_MAP;
722         }
723         else
724         {
725             return Collections.unmodifiableMap( _params );
726         }
727     }
728
729     /**
730      * Removes the given parameter.
731      *
732      * @param name name
733      */

734     public void removeParameter( String JavaDoc name )
735     {
736         if ( _params == null ) { return; }
737
738         _params.remove( name );
739     }
740
741     /**
742      * Sets the fragment.
743      *
744      * @param fragment fragment
745      */

746     public void setFragment( String JavaDoc fragment )
747     {
748         _fragment = null;
749         if ( fragment != null && fragment.length() > 0 )
750         {
751             _fragment = fragment;
752         }
753     }
754
755     /**
756      * Returns the fragment.
757      *
758      * @return fragment
759      */

760     public String JavaDoc getFragment()
761     {
762         return _fragment;
763     }
764
765     /**
766      * Tells whether or not this URI is absolute.
767      *
768      * <p> A URI is absolute if, and only if, it has a scheme component. </p>
769      *
770      * @return <tt>true</tt> if, and only if, this URI is absolute
771      */

772     public boolean isAbsolute() {
773         return getScheme() != null;
774     }
775
776     /**
777      * Returns a string form of this URI. The {@link URIContext}
778      * encapsulates the data needed to write out the string form.
779      *
780      * <p> E.g. Defines if the &quot;&amp;amp;&quot; entity or the
781      * '&amp;' character should be used to separate quary parameters. </p>
782      *
783      * @param uriContext data required to write out the string form.
784      * @return the URI as a <code>String</code>
785      */

786     public String JavaDoc getURIString( URIContext uriContext )
787     {
788         InternalStringBuilder buf = new InternalStringBuilder( 128 );
789
790         // Append the scheme
791
if ( getScheme() != null )
792         {
793             buf.append( getScheme() ).append( ':' );
794         }
795
796         // Append the user info, host and, port
797
if ( getHost() != null)
798         {
799             buf.append( "//" );
800
801             if ( getUserInfo() != null )
802             {
803                 buf.append( getUserInfo() );
804                 buf.append( '@' );
805             }
806
807             buf.append( getHost() );
808
809             if ( getPort() != UNDEFINED_PORT )
810             {
811                 buf.append( ':' ).append( getPort() );
812             }
813         }
814
815         // Append the path.
816
if ( getPath() != null )
817         {
818             if ( isAbsolute() )
819             {
820                 // absolute URI so
821
appendEnsureSeparator( buf, getPath() );
822             }
823             else
824             {
825                 buf.append( getPath() );
826             }
827         }
828
829         // Append the parameters (the query)
830
if ( _params != null && _params.size() > 0 )
831         {
832             buf.append( '?' );
833             buf.append( getQuery( uriContext ) );
834         }
835
836         // Append the fragment
837
if ( getFragment() != null && getFragment().length() > 0 )
838         {
839             buf.append( '#' ).append( getFragment() );
840         }
841
842         String JavaDoc url = buf.toString();
843
844         return url;
845     }
846
847     /**
848      * Returns a default <code>URIContext</code>.
849      *
850      * @return the URIContext with default data.
851      */

852     public static URIContext getDefaultContext()
853     {
854         URIContext uriContext = new URIContext();
855         uriContext.setUseAmpEntity( true );
856
857         return uriContext;
858     }
859
860     private static void appendEnsureSeparator( InternalStringBuilder buf, String JavaDoc token )
861     {
862         if ( token != null && token.length() > 0 )
863         {
864             if ( buf.charAt( buf.length() - 1 ) != '/' && token.charAt( 0 ) != '/' )
865             {
866                 buf.append( '/' );
867             }
868             if ( buf.charAt( buf.length() - 1 ) == '/' && token.charAt( 0 ) == '/' )
869             {
870                 token = token.substring( 1 );
871             }
872             buf.append( token );
873         }
874     }
875
876     /**
877      * Convenience method to encode unencoded components of a URI.
878      *
879      * @param url the string to be encoded by {@link URLCodec}
880      * @param encoding the character encoding to use
881      * @return the encoded string
882      */

883     public static String JavaDoc encode( String JavaDoc url, String JavaDoc encoding )
884     {
885         String JavaDoc encodedURL = null;
886         try
887         {
888             encodedURL = URLCodec.encode( url, encoding );
889         }
890         catch ( java.io.UnsupportedEncodingException JavaDoc e )
891         {
892             // try utf-8 as a default encoding
893
try
894             {
895                 encodedURL = URLCodec.encode( url, DEFAULT_ENCODING );
896             }
897             catch ( java.io.UnsupportedEncodingException JavaDoc ignore )
898             {
899             }
900         }
901         return encodedURL;
902     }
903
904     /**
905      * Convenience method to encode unencoded components of a URI.
906      * This implementation uses the value of the character encoding
907      * field of this instance.
908      *
909      * @param url the string to be encoded by {@link URLCodec}
910      * @return the encoded string
911      */

912     public String JavaDoc encode( String JavaDoc url )
913     {
914         return encode( url, _encoding );
915     }
916
917     /**
918      * Determines if the passed-in Object is equivalent to this MutableURI.
919      *
920      * @param object the Object to test for equality.
921      * @return true if object is a MutableURI with all values equal to this
922      * MutableURI, false otherwise
923      */

924     
925     public boolean equals( Object JavaDoc object )
926     {
927         if ( object == this ) { return true; }
928
929         if ( object == null || !object.getClass().equals( this.getClass() ) )
930         {
931             return false;
932         }
933
934         MutableURI testURI = ( MutableURI ) object;
935
936         if ( ( _scheme == testURI.getScheme() || ( _scheme != null && _scheme.equalsIgnoreCase( testURI.getScheme() ) ) ) &&
937                 ( _userInfo == testURI.getUserInfo() || ( _userInfo != null && _userInfo.equals( testURI.getUserInfo() ) ) ) &&
938                 ( _host == testURI.getHost() || ( _host != null && _host.equalsIgnoreCase( testURI.getHost() ) ) ) &&
939                 _port == testURI.getPort() &&
940                 ( _path == testURI.getPath() || ( _path != null && _path.equals( testURI.getPath() ) ) ) &&
941                 ( _fragment == testURI.getFragment() || ( _fragment != null && _fragment.equals( testURI.getFragment() ) ) ) &&
942                 ( _encoding == testURI.getEncoding() || ( _encoding != null && _encoding.equals( testURI.getEncoding() ) ) ) )
943         {
944             Map JavaDoc/*< String, List< String > >*/ params = getParameters();
945             Map JavaDoc/*< String, List< String > >*/ testParams = testURI.getParameters();
946
947             if ( params == testParams || ( params != null && params.equals( testParams ) ) ) {
948                 return true;
949             }
950         }
951
952         return false;
953     }
954
955     /**
956      * Returns a hash code value for the object.
957      * <p> Implemented in conjunction with equals() override. </p>
958      * <p> This is a mutable class implying that we're basing the hash
959      * code on the member data that can change. Therefor it's important
960      * not to use this class as a key in a hashtable as it would still
961      * appear with an enumeration but not when calling contains.
962      * I.E. The object could get lost in the hashtable. A call for the
963      * hashcode would return a different value than when it was first
964      * placed in the hashtable. </p>
965      *
966      * <p> With this in mind, we simply return the same value to support
967      * the rules of equality. </p>
968      *
969      * @return a hash code value for this object.
970      */

971     
972     public int hashCode()
973     {
974         return 0;
975     }
976
977     /**
978      * Parse a URI reference, as a <code>String</code>, into its
979      * components and use {@link java.net.URI} to encode the
980      * components correctly. This comes from the parsing
981      * algorithm of the Apache Commons HttpClient code for
982      * its URI class.
983      *
984      * @param original the original character sequence
985      * @throws URISyntaxException If an error occurs.
986      */

987     protected static URI JavaDoc encodeURI( String JavaDoc original ) throws URISyntaxException JavaDoc
988     {
989         if ( original == null )
990         {
991             throw new IllegalArgumentException JavaDoc( "URI-Reference required" );
992         }
993
994         String JavaDoc scheme = null;
995         String JavaDoc authority = null;
996         String JavaDoc path = null;
997         String JavaDoc query = null;
998         String JavaDoc fragment = null;
999         String JavaDoc tmp = original.trim();
1000        int length = tmp.length();
1001        int from = 0;
1002
1003        // The test flag whether the URI is started from the path component.
1004
boolean isStartedFromPath = false;
1005        int atColon = tmp.indexOf( ':' );
1006        int atSlash = tmp.indexOf( '/' );
1007
1008        if ( atColon < 0 || ( atSlash >= 0 && atSlash < atColon ) )
1009        {
1010            isStartedFromPath = true;
1011        }
1012
1013        int at = indexFirstOf( tmp, isStartedFromPath ? "/?#" : ":/?#", from );
1014
1015        if ( at == -1 )
1016        {
1017            at = 0;
1018        }
1019
1020        // Parse the scheme.
1021
if ( at < length && tmp.charAt( at ) == ':' )
1022        {
1023            scheme = tmp.substring( 0, at ).toLowerCase();
1024            from = ++at;
1025        }
1026
1027        // Parse the authority component.
1028
if ( 0 <= at && at < length )
1029        {
1030            if ( tmp.charAt( at ) == '/' )
1031            {
1032                if ( at + 2 < length && tmp.charAt( at + 1 ) == '/' )
1033                {
1034                    // the temporary index to start the search from
1035
int next = indexFirstOf( tmp, "/?#", at + 2 );
1036                    if ( next == -1 )
1037                    {
1038                        next = ( tmp.substring( at + 2 ).length() == 0 ) ? at + 2 : tmp.length();
1039                    }
1040                    authority = tmp.substring( at + 2, next );
1041                    from = at = next;
1042                }
1043            }
1044            else if ( scheme != null && tmp.indexOf( '/', at + 1 ) < 0 )
1045            {
1046                int next = tmp.indexOf( '#', at );
1047                if ( next == -1 )
1048                {
1049                    next = length;
1050                }
1051                String JavaDoc ssp = tmp.substring( at, next );
1052                if ( next != length )
1053                {
1054                    fragment = tmp.substring( next + 1 );
1055                }
1056                return new URI JavaDoc( scheme, ssp, fragment );
1057            }
1058        }
1059
1060        // Parse the path component.
1061
if ( from < length )
1062        {
1063            int next = indexFirstOf( tmp, "?#", from );
1064            if ( next == -1 )
1065            {
1066                next = length;
1067            }
1068            path = tmp.substring( from, next );
1069            at = next;
1070        }
1071
1072        // Parse the query component.
1073
if ( 0 <= at && at + 1 < length && tmp.charAt( at ) == '?' )
1074        {
1075            int next = tmp.indexOf( '#', at + 1 );
1076            if ( next == -1 )
1077            {
1078                next = length;
1079            }
1080            query = tmp.substring( at + 1, next );
1081            at = next;
1082        }
1083
1084        // Parse the fragment component.
1085
if ( 0 <= at && at + 1 <= length && tmp.charAt( at ) == '#' )
1086        {
1087            if ( at + 1 == length )
1088            { // empty fragment
1089
fragment = "";
1090            }
1091            else
1092            {
1093                fragment = tmp.substring( at + 1 );
1094            }
1095        }
1096
1097        // Use java.net.URI to encode components and return.
1098
return new URI JavaDoc( scheme, authority, path, query, fragment );
1099    }
1100
1101    /**
1102     * Get the earliest index, searching for the first occurrance of
1103     * any one of the given delimiters.
1104     *
1105     * @param s the string to be indexed
1106     * @param delims the delimiters used to index
1107     * @param offset the from index
1108     * @return the earlier index if there are delimiters
1109     */

1110    protected static int indexFirstOf( String JavaDoc s, String JavaDoc delims, int offset )
1111    {
1112        if ( s == null || s.length() == 0 )
1113        {
1114            return -1;
1115        }
1116        if ( delims == null || delims.length() == 0 )
1117        {
1118            return -1;
1119        }
1120
1121        // check boundaries
1122
if ( offset < 0 )
1123        {
1124            offset = 0;
1125        }
1126        else if ( offset > s.length() )
1127        {
1128            return -1;
1129        }
1130
1131        // s is never null
1132
int min = s.length();
1133        char[] delim = delims.toCharArray();
1134        for ( int i = 0; i < delim.length; i++ )
1135        {
1136            int at = s.indexOf( delim[i], offset );
1137            if ( at >= 0 && at < min )
1138            {
1139                min = at;
1140            }
1141        }
1142
1143        return ( min == s.length() ) ? -1 : min;
1144    }
1145}
1146
Popular Tags