KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > turbine > DynamicURI


1 package org.apache.turbine;
2
3 /* ====================================================================
4  * The Apache Software License, Version 1.1
5  *
6  * Copyright (c) 2001 The Apache Software Foundation. All rights
7  * reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * 1. Redistributions of source code must retain the above copyright
14  * notice, this list of conditions and the following disclaimer.
15  *
16  * 2. Redistributions in binary form must reproduce the above copyright
17  * notice, this list of conditions and the following disclaimer in
18  * the documentation and/or other materials provided with the
19  * distribution.
20  *
21  * 3. The end-user documentation included with the redistribution,
22  * if any, must include the following acknowledgment:
23  * "This product includes software developed by the
24  * Apache Software Foundation (http://www.apache.org/)."
25  * Alternately, this acknowledgment may appear in the software itself,
26  * if and wherever such third-party acknowledgments normally appear.
27  *
28  * 4. The names "Apache" and "Apache Software Foundation" and
29  * "Apache Turbine" must not be used to endorse or promote products
30  * derived from this software without prior written permission. For
31  * written permission, please contact apache@apache.org.
32  *
33  * 5. Products derived from this software may not be called "Apache",
34  * "Apache Turbine", nor may "Apache" appear in their name, without
35  * prior written permission of the Apache Software Foundation.
36  *
37  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
38  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
39  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
40  * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
41  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
42  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
43  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
44  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
45  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
46  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
47  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48  * SUCH DAMAGE.
49  * ====================================================================
50  *
51  * This software consists of voluntary contributions made by many
52  * individuals on behalf of the Apache Software Foundation. For more
53  * information on the Apache Software Foundation, please see
54  * <http://www.apache.org/>.
55  */

56
57 import java.util.ArrayList JavaDoc;
58 import java.util.Enumeration JavaDoc;
59 import java.util.Vector JavaDoc;
60
61 import javax.servlet.http.HttpServletRequest JavaDoc;
62 import javax.servlet.http.HttpServletResponse JavaDoc;
63
64 import org.apache.fulcrum.parser.ParameterParser;
65
66 /**
67  * This creates a Dynamic URI for use within the Turbine system
68  *
69  * <p>If you use this class to generate all of your href tags as well
70  * as all of your URI's, then you will not need to worry about having
71  * session data setup for you or using HttpServletRequest.encodeUrl()
72  * since this class does everything for you.
73  *
74  * <code><pre>
75  * DynamicURI dui = new DynamicURI (data, "UserScreen" );
76  * dui.setName("Click Here").addPathInfo("user","jon");
77  * dui.getA();
78  * </pre></code>
79  *
80  * The above call to getA() would return the String:
81  *
82  * &lt;A HREF="http://www.server.com:80/servlets/Turbine/screen=UserScreen&amp;amp;user=jon"&gt;Click Here&lt;/A&gt;
83  *
84  * @author <a HREF="mailto:jon@clearink.com">Jon S. Stevens</a>
85  * @author <a HREF="mailto:jvanzyl@periapt.com">Jason van Zyl</a>
86  * @author <a HREF="mailto:jmcnally@collab.net">John McNally</a>
87  * @author <a HREF="mailto:james@jamestaylor.org">James Taylor</a>
88  * @version $Id: DynamicURI.java,v 1.13 2004/11/12 10:26:28 epugh Exp $
89  */

90 public class DynamicURI
91 {
92     /** HTTP protocol. */
93     public static final String JavaDoc HTTP = "http";
94
95     /** HTTPS protocol. */
96     public static final String JavaDoc HTTPS = "https";
97
98     /** Length of static part of an A tag */
99     public static final int ANCHOR_STATIC_PART_LENGTH
100         = "<a HREF=\"\"></a>".length();
101
102     /** The RunData object. */
103     protected RunData data = null;
104
105     /** Servlet response interface. */
106     public HttpServletResponse JavaDoc res = null;
107
108     /** A Vector that contains all the path info if any. */
109     protected ArrayList JavaDoc pathInfo = new ArrayList JavaDoc();
110
111     /** A Vectory that contains all the query data if any. */
112     protected ArrayList JavaDoc queryData = new ArrayList JavaDoc();
113
114     /** Whether we want to redirect or not. */
115     protected boolean redirect = false;
116
117     /** P = 0 for path info. */
118     protected static final int PATH_INFO = 0;
119
120     /** Q = 1 for query data. */
121     protected static final int QUERY_DATA = 1;
122
123     /** true=relative url's; false=absolute url's */
124     private boolean isRelative = false;
125
126     /**
127      * true=url will be rewritten with session_id if needed; false=url will
128      * not be encoded
129      */

130     private boolean encodeUrl = true;
131
132     /**
133      * Constructor sets up some variables.
134      *
135      * @param data A Turbine RunData object.
136      */

137     public DynamicURI(RunData data)
138     {
139         init(data);
140     }
141
142     /**
143      * Default constructor - one of the init methods must be called
144      * before use.
145      */

146     public DynamicURI()
147     {
148     }
149
150     /**
151      * Constructor sets up some variables.
152      *
153      * @param data A Turbine RunData object.
154      * @param screen A String with the name of a screen.
155      */

156     public DynamicURI(RunData data,
157                       String JavaDoc screen)
158     {
159         this(data);
160         setScreen(screen);
161     }
162
163     /**
164      * Constructor sets up some variables.
165      *
166      * @param data A Turbine RunData object.
167      * @param screen A String with the name of a screen.
168      * @param action A String with the name of an action.
169      */

170     public DynamicURI(RunData data,
171                       String JavaDoc screen,
172                       String JavaDoc action)
173     {
174         this(data, screen);
175         setAction(action);
176     }
177
178     /**
179      * Constructor sets up some variables.
180      *
181      * @param data A Turbine RunData object.
182      * @param screen A String with the name of a screen.
183      * @param action A String with the name of an action.
184      * @param redirect True if it should redirect.
185      */

186     public DynamicURI(RunData data,
187                       String JavaDoc screen,
188                       String JavaDoc action,
189                       boolean redirect)
190     {
191         this(data, screen, action);
192         this.redirect = redirect;
193     }
194
195     /**
196      * Constructor sets up some variables.
197      *
198      * @param data A Turbine RunData object.
199      * @param screen A String with the name of a screen.
200      * @param redirect True if it should redirect.
201      */

202     public DynamicURI(RunData data,
203                       String JavaDoc screen,
204                       boolean redirect)
205     {
206         this(data, screen);
207         this.redirect = redirect;
208     }
209
210     /**
211      * Constructor sets up some variables.
212      *
213      * @param data A Turbine RunData object.
214      * @param redirect True if it should redirect.
215      */

216     public DynamicURI(RunData data,
217                       boolean redirect)
218     {
219         this(data);
220         this.redirect = redirect;
221     }
222
223     /**
224      * Initialize with a RunData object
225      *
226      * @param data
227      */

228     public void init(RunData data)
229     {
230         this.data = data;
231         this.res = data.getResponse();
232         init();
233     }
234
235     /**
236      * <p>If the type is P (0), then add name/value to the pathInfo
237      * hashtable.
238      *
239      * <p>If the type is Q (1), then add name/value to the queryData
240      * hashtable.
241      *
242      * @param type Type (P or Q) of insertion.
243      * @param name A String with the name to add.
244      * @param value A String with the value to add.
245      */

246     protected void add(int type,
247                        String JavaDoc name,
248                        String JavaDoc value)
249     {
250         Object JavaDoc[] tmp = new Object JavaDoc[2];
251
252         tmp[0] = data.getParameters().convertAndTrim(name);
253         tmp[1] = value;
254
255         if ( type == PATH_INFO )
256         {
257             this.pathInfo.add(tmp);
258         }
259         else if ( type == QUERY_DATA )
260         {
261             this.queryData.add(tmp);
262         }
263     }
264
265     /**
266      * Add a key value pair (in the form of a 2 object array) to the provided
267      * list
268      *
269      * @param list List to add to.
270      * @param name A String with the name to add.
271      * @param value A String with the value to add.
272      */

273     protected void addPair(ArrayList JavaDoc list,
274                            String JavaDoc name,
275                            String JavaDoc value)
276     {
277         Object JavaDoc[] tmp = new Object JavaDoc[2];
278
279         tmp[0] = data.getParameters().convertAndTrim(name);
280         tmp[1] = value;
281
282         list.add(tmp);
283     }
284
285     /**
286      * Method for a quick way to add all the parameters in a
287      * ParameterParser to a given List
288      *
289      * @param list The list of pairs to add to
290      * @param pp A ParameterParser.
291      */

292     protected void add(ArrayList JavaDoc list,
293                        ParameterParser pp)
294     {
295         Enumeration JavaDoc e = pp.keys();
296         while (e.hasMoreElements())
297         {
298             String JavaDoc key = (String JavaDoc) e.nextElement();
299
300             if (!key.equalsIgnoreCase(Turbine.ACTION) &&
301                 !key.equalsIgnoreCase(Turbine.SCREEN) &&
302                 !key.equalsIgnoreCase(Turbine.TEMPLATE))
303             {
304                 String JavaDoc[] values = pp.getStrings(key);
305                 for (int i = 0; i < values.length; i++)
306                 {
307                     addPair(list, key, values[i]);
308                 }
309             }
310         }
311     }
312
313     /**
314      * Method for a quick way to add all the parameters in a
315      * ParameterParser.
316      *
317      * <p>If the type is P (0), then add name/value to the pathInfo
318      * hashtable.
319      *
320      * <p>If the type is Q (1), then add name/value to the queryData
321      * hashtable.
322      *
323      * @param type Type (P or Q) of insertion.
324      * @param pp A ParameterParser.
325      */

326     protected void add(int type,
327                        ParameterParser pp)
328     {
329         if ( type == PATH_INFO )
330         {
331             add( pathInfo, pp);
332         }
333         else if ( type == QUERY_DATA )
334         {
335             add( queryData, pp);
336         }
337     }
338
339     /**
340      * Adds a name=value pair to the path_info string.
341      *
342      * @param name A String with the name to add.
343      * @param value An Object with the value to add.
344      */

345     public DynamicURI addPathInfo(String JavaDoc name, Object JavaDoc value)
346     {
347         addPathInfo(name, value.toString());
348         return this;
349     }
350
351     /**
352      * Adds a name=value pair to the path_info string.
353      *
354      * @param name A String with the name to add.
355      * @param value A String with the value to add.
356      */

357     public DynamicURI addPathInfo(String JavaDoc name, String JavaDoc value)
358     {
359         addPair( pathInfo, name, value);
360         return this;
361     }
362
363     /**
364      * Adds a name=value pair to the path_info string.
365      *
366      * @param name A String with the name to add.
367      * @param value A double with the value to add.
368      */

369     public DynamicURI addPathInfo(String JavaDoc name, double value)
370     {
371         addPathInfo(name, Double.toString(value));
372         return this;
373     }
374
375     /**
376      * Adds a name=value pair to the path_info string.
377      *
378      * @param name A String with the name to add.
379      * @param value An int with the value to add.
380      */

381     public DynamicURI addPathInfo(String JavaDoc name, int value)
382     {
383         addPathInfo(name, new Integer JavaDoc(value).toString());
384         return this;
385     }
386
387     /**
388      * Adds a name=value pair to the path_info string.
389      *
390      * @param name A String with the name to add.
391      * @param value A long with the value to add.
392      */

393     public DynamicURI addPathInfo(String JavaDoc name, long value)
394     {
395         addPathInfo(name, new Long JavaDoc(value).toString());
396         return this;
397     }
398
399     /**
400      * Adds a name=value pair to the path_info string.
401      *
402      * @param name A String with the name to add.
403      * @param value A double with the value to add.
404      */

405     public DynamicURI addPathInfo(String JavaDoc name, boolean value)
406     {
407         addPathInfo(name, (value ? "true" : "false"));
408         return this;
409     }
410
411     /**
412      * Adds a name=value pair for every entry in a ParameterParser
413      * object to the path_info string.
414      *
415      * @param pp A ParameterParser.
416      */

417     public DynamicURI addPathInfo(ParameterParser pp)
418     {
419         add(pathInfo, pp);
420         return this;
421     }
422
423     /**
424      * Adds a name=value pair to the query string.
425      *
426      * @param name A String with the name to add.
427      * @param value An Object with the value to add.
428      */

429     public DynamicURI addQueryData(String JavaDoc name, Object JavaDoc value)
430     {
431         addQueryData(name, value.toString());
432         return this;
433     }
434
435     /**
436      * Adds a name=value pair to the query string.
437      *
438      * @param name A String with the name to add.
439      * @param value A String with the value to add.
440      */

441     public DynamicURI addQueryData(String JavaDoc name, String JavaDoc value)
442     {
443         addPair( queryData, name, value);
444         return this;
445     }
446
447     /**
448      * Adds a name=value pair to the query string.
449      *
450      * @param name A String with the name to add.
451      * @param value A double with the value to add.
452      */

453     public DynamicURI addQueryData(String JavaDoc name, double value)
454     {
455         addQueryData(name, Double.toString(value));
456         return this;
457     }
458
459     /**
460      * Adds a name=value pair to the query string.
461      *
462      * @param name A String with the name to add.
463      * @param value An int with the value to add.
464      */

465     public DynamicURI addQueryData(String JavaDoc name, int value)
466     {
467         addQueryData(name, new Integer JavaDoc(value).toString());
468         return this;
469     }
470
471     /**
472      * Adds a name=value pair to the query string.
473      *
474      * @param name A String with the name to add.
475      * @param value A long with the value to add.
476      */

477     public DynamicURI addQueryData(String JavaDoc name, long value)
478     {
479         addQueryData(name, new Long JavaDoc(value).toString());
480         return this;
481     }
482
483     /**
484      * Adds a name=value pair for every entry in a ParameterParser
485      * object to the query string.
486      *
487      * @param pp A ParameterParser.
488      */

489     public DynamicURI addQueryData(ParameterParser pp)
490     {
491         add(queryData, pp);
492         return this;
493     }
494
495     /**
496      * Create an anchor object. This call to getA():
497      *
498      * <code><pre>
499      * DynamicURI dui = new DynamicURI (data, "UserScreen" );
500      * dui.setName("Click Here").addPathInfo("user","jon");
501      * dui.getA();
502      * </pre></code>
503      *
504      * would return the String:
505      *
506      * <p>&lt;A HREF="http://www.server.com:80/servlets/Turbine/screen=UserScreen&amp;amp;user=jon"&gt;Click Here&lt;/A&gt;
507      *
508      * @param name A String with the name for the anchor.
509      * @return The anchor as a &lt;A HREF=""&gt;name&lt;/A&gt;.
510      */

511     public String JavaDoc getA(String JavaDoc name)
512     {
513        final String JavaDoc s = this.toString();
514
515        // I'm being a pit picky about size here to avoid useless
516
// StringBuffer reallocation
517

518        final int size = ANCHOR_STATIC_PART_LENGTH + s.length() + name.length();
519
520        return new StringBuffer JavaDoc( size )
521            .append("<a HREF=\"")
522            .append(s)
523            .append("\">")
524            .append(name)
525            .append("</a>")
526            .toString();
527     }
528
529     /**
530      * Gets the script name (/servlets/Turbine).
531      *
532      * @return A String with the script name.
533      */

534     public String JavaDoc getScriptName()
535     {
536         return data.getScriptName();
537     }
538
539     /**
540      * Gets the server name.
541      *
542      * @return A String with the server name.
543      */

544     public String JavaDoc getServerName()
545     {
546         return data.getServerName();
547     }
548
549     /**
550      * Gets the server port.
551      *
552      * @return A String with the server port.
553      */

554     public int getServerPort()
555     {
556         return data.getServerPort();
557     }
558
559     /**
560      * Gets the server scheme (HTTP or HTTPS).
561      *
562      * @return A String with the server scheme.
563      */

564     public String JavaDoc getServerScheme()
565     {
566         return data.getServerScheme();
567     }
568
569     /**
570      * Initializes some common variables.
571      */

572     protected void init()
573     {
574         this.pathInfo.clear();
575         this.queryData.clear();
576     }
577
578     /**
579      * <p>If the type is P (0), then remove name/value from the
580      * pathInfo hashtable.
581      *
582      * <p>If the type is Q (1), then remove name/value from the
583      * queryData hashtable.
584      *
585      * @param type Type (P or Q) of removal.
586      * @param name A String with the name to be removed.
587      */

588     protected void remove(int type,
589                           String JavaDoc name)
590     {
591         try
592         {
593             if ( type == PATH_INFO )
594             {
595                 removePathInfo( name );
596             }
597             else if ( type == QUERY_DATA )
598             {
599                 removeQueryData( name );
600             }
601         }
602         catch (Exception JavaDoc e)
603         {
604         }
605     }
606
607     /**
608      * Helper method to remove one or more pairs by its name (ie key).
609      * It is intended to be used with <tt>queryData</tt> and <tt>pathInfo</tt>.
610      * @param pairs the list of pairs to look over for removal.
611      * @param name the name of the pair(s) to remove.
612      */

613     protected void removePairByName(ArrayList JavaDoc pairs, String JavaDoc name)
614     {
615         name = data.getParameters().convertAndTrim(name);
616         // CAUTION: the dynamic evaluation of the size is on purpose because
617
// elements may be removed on the fly.
618
for (int i = 0; i < pairs.size(); i++)
619         {
620             Object JavaDoc[] pair = (Object JavaDoc[])pairs.get(i);
621             if ( name.equals( (String JavaDoc)pair[0] ) )
622             {
623                 pairs.remove(i);
624             }
625         }
626     }
627
628     /**
629      * Removes all the path info elements.
630      */

631     public void removePathInfo()
632     {
633         this.pathInfo.clear();
634     }
635
636     /**
637      * Removes a name=value pair from the path info.
638      *
639      * @param name A String with the name to be removed.
640      */

641     public void removePathInfo(String JavaDoc name)
642     {
643         removePairByName( pathInfo, name );;
644     }
645
646     /**
647      * Removes all the query string elements.
648      */

649     public void removeQueryData()
650     {
651         this.queryData.clear();
652     }
653
654     /**
655      * Removes a name=value pair from the query string.
656      *
657      * @param name A String with the name to be removed.
658      */

659     public void removeQueryData(String JavaDoc name)
660     {
661         removePairByName( queryData, name );
662     }
663
664     /**
665      * This method takes a Vector of key/value arrays and converts it
666      * into a URL encoded querystring format.
667      *
668      * @param data A Vector of key/value arrays.
669      * @return A String with the URL encoded data.
670      * @deprecated Prefer the ArrayList / StringBuffer form.
671      */

672     protected String JavaDoc renderPathInfo(Vector JavaDoc data)
673     {
674         StringBuffer JavaDoc out = new StringBuffer JavaDoc();
675
676         renderPathInfo(new ArrayList JavaDoc(data), out);
677
678         return out.toString();
679     }
680
681     /**
682      * This method takes a Vector of key/value arrays and writes it to the
683      * supplied StringBuffer as encoded path info.
684      *
685      * @param pairs A Vector of key/value arrays.
686      * @param out Buffer to which encoded path info is written
687      */

688     protected void renderPathInfo(ArrayList JavaDoc pairs, StringBuffer JavaDoc out)
689     {
690         renderPairs( pairs, out, '/', '/' );
691     }
692
693     /**
694      * This method takes a Vector of key/value arrays and converts it
695      * into a URL encoded querystring format.
696      *
697      * @param data A Vector of key/value arrays.
698      * @return A String with the URL encoded data.
699      * @deprecated Prefer the ArrayList / StringBuffer form.
700      */

701     protected String JavaDoc renderQueryString(Vector JavaDoc data)
702     {
703         StringBuffer JavaDoc out = new StringBuffer JavaDoc();
704
705         renderQueryString(new ArrayList JavaDoc(data), out);
706
707         return out.toString();
708     }
709
710     /**
711      * This method takes a List of key/value arrays and writes it to the
712      * provided StringBuffer in encoded query string format.
713      *
714      * @param data A Vector of key/value arrays.
715      * @param out Buffer to which encoded query string is written.
716      */

717     protected void renderQueryString(ArrayList JavaDoc data, StringBuffer JavaDoc out)
718     {
719         renderPairs( data, out, '&', '=' );
720     }
721
722     /**
723      * This method takes a List of key/value arrays and converts it
724      * into a URL encoded key/value pair format with the appropriate
725      * separator.
726      *
727      * @param out the buffer to write the pairs to.
728      * @param pairs A List of key/value arrays.
729      * @param pairSep the character to use as a separator between pairs.
730      * For example for a query-like rendering it would be '&'.
731      * @param keyValSep the character to use as a separator between
732      * key and value. For example for a query-like rendering, it would be '='.
733      */

734     protected void renderPairs(ArrayList JavaDoc pairs, StringBuffer JavaDoc out,
735                                char pairSep, char keyValSep)
736     {
737         boolean first = true;
738
739         final int count = pairs.size();
740         for (int i = 0; i < count; i++)
741         {
742             Object JavaDoc[] pair = (Object JavaDoc[]) pairs.get(i);
743
744             if ( first )
745             {
746                 first = false;
747             }
748             else
749             {
750                 out.append(pairSep);
751             }
752
753             writeFastEncoded((String JavaDoc) pair[0], out);
754             out.append(keyValSep);
755             writeFastEncoded((String JavaDoc) pair[1], out);
756         }
757     }
758
759     /**
760      * Sets the action= value for this URL.
761      *
762      * <p>By default it adds the information to the path_info instead
763      * of the query data.
764      *
765      * @param action A String with the action value.
766      * @return A DynamicURI (self).
767      */

768     public DynamicURI setAction(String JavaDoc action)
769     {
770         addPathInfo(Turbine.ACTION, action);
771         return this;
772     }
773
774     /**
775      * Sets the screen= value for this URL.
776      *
777      * <p>By default it adds the information to the path_info instead
778      * of the query data.
779      *
780      * @param screen A String with the screen value.
781      * @return A DynamicURI (self).
782      */

783     public DynamicURI setScreen(String JavaDoc screen)
784     {
785         addPathInfo(Turbine.SCREEN, screen);
786         return this;
787     }
788
789     /**
790      * Sets the template = value for this URL.
791      *
792      * <p>By default it adds the information to the path_info instead
793      * of the query data.
794      *
795      * @param template A String with the template value.
796      * @return A DynamicURI (self).
797      */

798     public DynamicURI setTemplate(String JavaDoc template)
799     {
800         addPathInfo(Turbine.TEMPLATE, template);
801         return this;
802     }
803
804     /**
805      * Sets whether we want to redirect or not.
806      *
807      * @param doRedirect True if it should redirect.
808      * @return A DynamicURI (self).
809      */

810     public DynamicURI setRedirect(boolean doRedirect)
811     {
812         this.redirect = doRedirect;
813         return this;
814     }
815
816     /**
817      * Method to specify that a URI should use SSL. Whether or not it
818      * does is determined from TurbineResources.properties. Port
819      * number is 443.
820      *
821      * @return A DynamicURI (self).
822      */

823     public DynamicURI setSecure()
824     {
825         return setSecure(443);
826     }
827
828     /**
829      * Method to specify that a URI should use SSL. Whether or not it
830      * does is determined from TurbineResources.properties.
831      *
832      * @param port An int with the port number.
833      * @return A DynamicURI (self).
834      */

835     public DynamicURI setSecure(int port)
836     {
837         boolean isSSL = Turbine.getConfiguration()
838             .getBoolean(Turbine.USE_SSL, true);
839         if (isSSL)
840         {
841             data.setServerScheme(DynamicURI.HTTPS);
842             data.setServerPort(port);
843         }
844         return this;
845     }
846
847     /**
848      * if true, the scheme, domain, and port will not be included in the
849      * String representation of this uri..
850      *
851      * @param b a <code>boolean</code>
852      * @return a <code>DynamicURI</code> (self)
853      */

854     public DynamicURI setRelative(boolean b)
855     {
856         isRelative = b;
857         return this;
858     }
859
860     /**
861      * Will a call to toString() generate a relative url?
862      * where relative means no scheme, domain, and port info
863      *
864      * @return a <code>boolean</code>
865      */

866     public boolean isRelative()
867     {
868         return isRelative;
869     }
870
871     /**
872      * Can be used to disable url rewriting.
873      *
874      * @param b a <code>boolean</code>
875      * @return a <code>DynamicURI</code> (self)
876      */

877     public DynamicURI setEncodeUrl(boolean b)
878     {
879         encodeUrl = b;
880         return this;
881     }
882
883     /**
884      * Will a call to toString() add session info if needed to maintain
885      * a session. Does not determine whether the url will be rewritten,
886      * only that it might be.
887      *
888      * @return a <code>boolean</code>
889      */

890     public boolean isEncodeUrl()
891     {
892         return encodeUrl;
893     }
894
895     /**
896      * Builds the URL with all of the data URL-encoded as well as
897      * encoded using HttpServletResponse.encodeUrl().
898      *
899      * <p>
900      * <code><pre>
901      * DynamicURI dui = new DynamicURI (data, "UserScreen" );
902      * dui.addPathInfo("user","jon");
903      * dui.toString();
904      * </pre></code>
905      *
906      * The above call to toString() would return the String:
907      *
908      * <p>
909      * http://www.server.com/servlets/Turbine/screen/UserScreen/user/jon
910      *
911      * @return A String with the built URL.
912      */

913     public String JavaDoc toString()
914     {
915         StringBuffer JavaDoc output = new StringBuffer JavaDoc();
916         if (!isRelative())
917         {
918             output.append(getServerScheme());
919             output.append("://");
920             output.append(getServerName());
921             if ((getServerScheme().equals(HTTP) && getServerPort() != 80)
922                 || (getServerScheme().equals(HTTPS) && getServerPort() != 443))
923             {
924                 output.append(':');
925                 output.append(getServerPort());
926             }
927         }
928
929         output.append(getScriptName());
930
931         if (this.hasPathInfo())
932         {
933             output.append('/');
934             renderPathInfo(this.pathInfo, output);
935         }
936         if (this.hasQueryData())
937         {
938             output.append('?');
939             renderQueryString(this.queryData, output);
940         }
941
942         // There seems to be a bug in Apache JServ 1.0 where the
943
// session id is not appended to the end of the url when a
944
// cookie has not been set.
945
if (this.res != null && isEncodeUrl())
946         {
947             if (this.redirect)
948             {
949                 return res.encodeRedirectURL(output.toString());
950             }
951             else
952             {
953                 return res.encodeURL(output.toString());
954             }
955         }
956         else
957         {
958             return output.toString();
959         }
960     }
961
962     /**
963      * Given a RunData object, get a URI for the request. This is
964      * necessary sometimes when you want the exact URL and don't want
965      * DynamicURI to be too smart and remove actions, screens, etc.
966      * This also returns the Query Data where DynamicURI normally
967      * would not. This method always returns absolute url's.
968      *
969      * @param data A Turbine RunData object.
970      * @return A String with the URL representing the RunData.
971      */

972     public static String JavaDoc toString(RunData data)
973     {
974         return toString(data, true);
975     }
976
977     /**
978      * Given a RunData object, get a URI for the request. This is
979      * necessary sometimes when you want the exact URL and don't want
980      * DynamicURI to be too smart and remove actions, screens, etc.
981      * This also returns the Query Data where DynamicURI normally
982      * would not.
983      *
984      * @param data A Turbine RunData object.
985      * @param isAbsolute to determine absolute vs. relative links.
986      * @return A String with the URL representing the RunData.
987      */

988     public static String JavaDoc toString(RunData data, boolean isAbsolute)
989     {
990         StringBuffer JavaDoc output = new StringBuffer JavaDoc( 128 );
991         HttpServletRequest JavaDoc request = data.getRequest();
992
993         if (isAbsolute)
994         {
995             output.append(data.getServerScheme());
996             output.append("://");
997             output.append(data.getServerName());
998
999             if ((data.getServerScheme().equals(HTTP) &&
1000                data.getServerPort() != 80) ||
1001                (data.getServerScheme().equals(HTTPS) &&
1002                data.getServerPort() != 443))
1003            {
1004                output.append(':');
1005                output.append(data.getServerPort());
1006            }
1007        }
1008
1009        output.append(data.getScriptName());
1010
1011        if (request.getPathInfo() != null)
1012        {
1013            output.append(request.getPathInfo());
1014        }
1015
1016        if (request.getQueryString() != null)
1017        {
1018            output.append('?');
1019            output.append(request.getQueryString());
1020        }
1021        return output.toString();
1022    }
1023
1024    /**
1025     * URL encodes <code>in</code> and writes it to <code>out</code>. If the
1026     * string is null, 'null' will be written.
1027     * This method is faster if
1028     * the string does not contain any characters needing encoding. It
1029     * adds some penalty for strings which actually need to be encoded.
1030     * for short strings ~20 characters the upside is a 75% decrease. while
1031     * the penalty is a 10% increase. As many query parameters do not need
1032     * encoding even in i18n applications it should be much better to
1033     * delay the byte conversion.
1034     *
1035     * @param in String to write.
1036     * @param out Buffer to write to.
1037     */

1038    protected static final void writeFastEncoded(String JavaDoc in, StringBuffer JavaDoc out)
1039    {
1040        if (in == null || in.length() == 0)
1041        {
1042            out.append("null");
1043            return;
1044        }
1045
1046        char[] chars = in.toCharArray();
1047
1048        for (int i = 0; i < chars.length; i++)
1049        {
1050            char c = chars[i];
1051
1052            if ( c < 128 && safe[ c ] )
1053            {
1054                out.append(c);
1055            }
1056            else if (c == ' ')
1057            {
1058                out.append('+');
1059            }
1060            else
1061            {
1062                // since we need to encode we will give up on
1063
// doing it the fast way and convert to bytes.
1064
writeEncoded(new String JavaDoc(chars, i, chars.length-i), out);
1065                break;
1066            }
1067        }
1068    }
1069
1070    /**
1071     * URL encodes <code>in</code> and writes it to <code>out</code>. If the
1072     * string is null, 'null' will be written.
1073     *
1074     * @param in String to write.
1075     * @param out Buffer to write to.
1076     */

1077    protected static final void writeEncoded(String JavaDoc in, StringBuffer JavaDoc out)
1078    {
1079        if (in == null || in.length() == 0)
1080        {
1081            out.append("null");
1082            return;
1083        }
1084
1085        // This is the most expensive operation:
1086

1087        byte[] bytes = in.getBytes();
1088
1089        for (int i = 0; i < bytes.length; i++)
1090        {
1091            char c = (char) bytes[i];
1092
1093            if ( c < 128 && safe[ c ] )
1094            {
1095                out.append(c);
1096            }
1097            else if (c == ' ')
1098            {
1099                out.append('+');
1100            }
1101            else
1102            {
1103                byte toEscape = bytes[i];
1104                out.append('%');
1105                int low = (int) (toEscape & 0x0f);
1106                int high = (int) ((toEscape & 0xf0) >> 4);
1107                out.append(hexadecimal[high]);
1108                out.append(hexadecimal[low]);
1109            }
1110        }
1111    }
1112
1113    /**
1114     * Does this URI have path info.
1115     */

1116    public boolean hasPathInfo()
1117    {
1118        return ! pathInfo.isEmpty();
1119    }
1120
1121    /**
1122     * Does this URI have query data.
1123     */

1124    public boolean hasQueryData()
1125    {
1126        return ! queryData.isEmpty();
1127    }
1128
1129
1130    // ------------------------------------- private constants for url encoding
1131

1132    /**
1133     * Array mapping hexadecimal values to the corresponding ASCII characters.
1134     */

1135    private static final char[] hexadecimal =
1136        {
1137            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
1138            'A', 'B', 'C', 'D', 'E', 'F'
1139        };
1140
1141    /**
1142     * Characters that need not be encoded. This is much faster than using a
1143     * BitSet, and for such a small array the space cost seems justified.
1144     */

1145    private static boolean[] safe = new boolean[ 128 ];
1146
1147    /** Static initializer for {@link #safe} */
1148    static
1149    {
1150        for (int i = 'a'; i <= 'z'; i++)
1151        {
1152            safe[ i ] = true;
1153        }
1154        for (int i = 'A'; i <= 'Z'; i++)
1155        {
1156            safe[ i ] = true;
1157        }
1158        for (int i = '0'; i <= '9'; i++)
1159        {
1160            safe[ i ] = true;
1161        }
1162
1163        safe['-'] = true;
1164        safe['_'] = true;
1165        safe['.'] = true;
1166        safe['!'] = true;
1167        safe['~'] = true;
1168        safe['*'] = true;
1169        safe['\''] = true;
1170        safe['('] = true;
1171        safe[')'] = true;
1172    }
1173}
1174
Popular Tags