1 package org.apache.turbine.util.uri;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.net.URLEncoder;
23
24 import java.util.ArrayList;
25 import java.util.Collection;
26 import java.util.Iterator;
27 import java.util.List;
28
29 import org.apache.commons.lang.StringUtils;
30
31 import org.apache.commons.logging.Log;
32 import org.apache.commons.logging.LogFactory;
33
34 import org.apache.turbine.util.RunData;
35 import org.apache.turbine.util.ServerData;
36 import org.apache.turbine.util.parser.ParameterParser;
37 import org.apache.turbine.util.parser.ParserUtils;
38
39 /***
40 * This class allows you to keep all the information needed for a single
41 * link at one place. It keeps your query data, path info, the server
42 * scheme, name, port and the script path.
43 *
44 * If you must generate a Turbine Link, use this class.
45 *
46 * @author <a href="mailto:jon@clearink.com">Jon S. Stevens</a>
47 * @author <a href="mailto:jvanzyl@periapt.com">Jason van Zyl</a>
48 * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
49 * @version $Id: TurbineURI.java 534527 2007-05-02 16:10:59Z tv $
50 */
51
52 public class TurbineURI
53 extends BaseURI
54 {
55 /*** Logging */
56 private static Log log = LogFactory.getLog(TurbineURI.class);
57
58 /*** Contains the PathInfo and QueryData vectors */
59 private List [] dataVectors = null;
60
61
62
63
64
65
66
67
68
69
70 /***
71 * Empty C'tor. Uses Turbine.getDefaultServerData().
72 */
73 public TurbineURI()
74 {
75 super();
76 init();
77 }
78
79 /***
80 * Constructor with a RunData object.
81 *
82 * @param runData A RunData object
83 */
84 public TurbineURI(RunData runData)
85 {
86 super(runData);
87 init();
88 }
89
90 /***
91 * Constructor, set explicit redirection.
92 *
93 * @param runData A RunData object
94 * @param redirect True if redirection allowed.
95 */
96 public TurbineURI(RunData runData, boolean redirect)
97 {
98 super(runData, redirect);
99 init();
100 }
101
102 /***
103 * Constructor, set Screen.
104 *
105 * @param runData A RunData object
106 * @param screen A Screen Name
107 */
108 public TurbineURI(RunData runData, String screen)
109 {
110 this(runData);
111 setScreen(screen);
112 }
113
114 /***
115 * Constructor, set Screen, set explicit redirection.
116 *
117 * @param runData A RunData object
118 * @param screen A Screen Name
119 * @param redirect True if redirection allowed.
120 */
121 public TurbineURI(RunData runData, String screen, boolean redirect)
122 {
123 this(runData, redirect);
124 setScreen(screen);
125 }
126
127 /***
128 * Constructor, set Screen and Action.
129 *
130 * @param runData A RunData object
131 * @param screen A Screen Name
132 * @param action An Action Name
133 */
134 public TurbineURI(RunData runData, String screen, String action)
135 {
136 this(runData, screen);
137 setAction(action);
138 }
139
140 /***
141 * Constructor, set Screen and Action, set explicit redirection.
142 *
143 * @param runData A RunData object
144 * @param screen A Screen Name
145 * @param action An Action Name
146 * @param redirect True if redirection allowed.
147 */
148 public TurbineURI(RunData runData, String screen, String action, boolean redirect)
149 {
150 this(runData, screen, redirect);
151 setAction(action);
152 }
153
154 /***
155 * Constructor with a ServerData object.
156 *
157 * @param serverData A ServerData object
158 */
159 public TurbineURI(ServerData serverData)
160 {
161 super(serverData);
162 init();
163 }
164
165 /***
166 * Constructor, set explicit redirection.
167 *
168 * @param serverData A ServerData object
169 * @param redirect True if redirection allowed.
170 */
171 public TurbineURI(ServerData serverData, boolean redirect)
172 {
173 super(serverData, redirect);
174 init();
175 }
176
177 /***
178 * Constructor, set Screen.
179 *
180 * @param serverData A ServerData object
181 * @param screen A Screen Name
182 */
183 public TurbineURI(ServerData serverData, String screen)
184 {
185 this(serverData);
186 setScreen(screen);
187 }
188
189 /***
190 * Constructor, set Screen, set explicit redirection.
191 *
192 * @param serverData A ServerData object
193 * @param screen A Screen Name
194 * @param redirect True if redirection allowed.
195 */
196 public TurbineURI(ServerData serverData, String screen, boolean redirect)
197 {
198 this(serverData, redirect);
199 setScreen(screen);
200 }
201
202 /***
203 * Constructor, set Screen and Action.
204 *
205 * @param serverData A ServerData object
206 * @param screen A Screen Name
207 * @param action An Action Name
208 */
209 public TurbineURI(ServerData serverData, String screen, String action)
210 {
211 this(serverData, screen);
212 setAction(action);
213 }
214
215 /***
216 * Constructor, set Screen and Action, set explicit redirection.
217 *
218 * @param serverData A ServerData object
219 * @param screen A Screen Name
220 * @param action An Action Name
221 * @param redirect True if redirection allowed.
222 */
223 public TurbineURI(ServerData serverData, String screen, String action,
224 boolean redirect)
225 {
226 this(serverData, screen, redirect);
227 setAction(action);
228 }
229
230 /***
231 * Constructor, user Turbine.getDefaultServerData(), set Screen and Action.
232 *
233 * @param screen A Screen Name
234 * @param action An Action Name
235 */
236 public TurbineURI(String screen, String action)
237 {
238 this();
239 setScreen(screen);
240 setAction(action);
241 }
242
243
244
245
246
247
248
249
250
251
252 /***
253 * Init the TurbineURI.
254 */
255 private void init()
256 {
257 dataVectors = new List[2];
258 dataVectors[PATH_INFO] = new ArrayList();
259 dataVectors[QUERY_DATA] = new ArrayList();
260 }
261
262 /***
263 * Sets the action= value for this URL.
264 *
265 * By default it adds the information to the path_info instead
266 * of the query data. An empty value (null or "") cleans out
267 * an existing value.
268 *
269 * @param action A String with the action value.
270 */
271 public void setAction(String action)
272 {
273 if(StringUtils.isNotEmpty(action))
274 {
275 add(PATH_INFO, CGI_ACTION_PARAM, action);
276 }
277 else
278 {
279 clearAction();
280 }
281 }
282
283 /***
284 * Sets the fired eventSubmit= value for this URL.
285 *
286 * @param event The event to fire.
287 *
288 */
289 public void setEvent(String event)
290 {
291 add(PATH_INFO, EVENT_PREFIX + event, event);
292 }
293
294 /***
295 * Sets the action= and eventSubmit= values for this URL.
296 *
297 * By default it adds the information to the path_info instead
298 * of the query data. An empty value (null or "") for the action cleans out
299 * an existing value. An empty value (null or "") for the event has no
300 * effect.
301 *
302 * @param action A String with the action value.
303 * @param event A string with the event name.
304 */
305 public void setActionEvent(String action, String event)
306 {
307 setAction(action);
308 if(StringUtils.isNotEmpty(event))
309 {
310 setEvent(event);
311 }
312 }
313
314 /***
315 * Clears the action= value for this URL.
316 */
317 public void clearAction()
318 {
319 removePathInfo(CGI_ACTION_PARAM);
320 }
321
322 /***
323 * Sets the screen= value for this URL.
324 *
325 * By default it adds the information to the path_info instead
326 * of the query data. An empty value (null or "") cleans out
327 * an existing value.
328 *
329 * @param screen A String with the screen value.
330 */
331 public void setScreen(String screen)
332 {
333 if(StringUtils.isNotEmpty(screen))
334 {
335 add(PATH_INFO, CGI_SCREEN_PARAM, screen);
336 }
337 else
338 {
339 clearScreen();
340 }
341 }
342
343 /***
344 * Clears the screen= value for this URL.
345 */
346 public void clearScreen()
347 {
348 removePathInfo(CGI_SCREEN_PARAM);
349 }
350
351
352
353
354
355
356
357
358
359
360 /***
361 * Adds a name=value pair for every entry in a ParameterParser
362 * object to the path_info string.
363 *
364 * @param pp A ParameterParser.
365 */
366 public void addPathInfo(ParameterParser pp)
367 {
368 add(PATH_INFO, pp);
369 }
370
371 /***
372 * Adds an existing List of URIParam objects to
373 * the path_info string.
374 *
375 * @param list A list with URIParam objects.
376 */
377 public void addPathInfo(List list)
378 {
379 add(PATH_INFO, list);
380 }
381
382 /***
383 * Adds a name=value pair to the path_info string.
384 *
385 * @param name A String with the name to add.
386 * @param value An Object with the value to add.
387 */
388 public void addPathInfo(String name, Object value)
389 {
390 add(PATH_INFO, name, value.toString());
391 }
392
393 /***
394 * Adds a name=value pair to the path_info string.
395 *
396 * @param name A String with the name to add.
397 * @param value A String with the value to add.
398 */
399 public void addPathInfo(String name, String value)
400 {
401 add(PATH_INFO, name, value);
402 }
403
404 /***
405 * Adds a name=value pair to the path_info string.
406 *
407 * @param name A String with the name to add.
408 * @param value A double with the value to add.
409 */
410 public void addPathInfo(String name, double value)
411 {
412 add(PATH_INFO, name, Double.toString(value));
413 }
414
415 /***
416 * Adds a name=value pair to the path_info string.
417 *
418 * @param name A String with the name to add.
419 * @param value An int with the value to add.
420 */
421 public void addPathInfo(String name, int value)
422 {
423 add(PATH_INFO, name, Integer.toString(value));
424 }
425
426 /***
427 * Adds a name=value pair to the path_info string.
428 *
429 * @param name A String with the name to add.
430 * @param value A long with the value to add.
431 */
432 public void addPathInfo(String name, long value)
433 {
434 add(PATH_INFO, name, Long.toString(value));
435 }
436
437 /***
438 * Adds a name=value pair to the query string.
439 *
440 * @param name A String with the name to add.
441 * @param value An Object with the value to add.
442 */
443 public void addQueryData(String name, Object value)
444 {
445 add(QUERY_DATA, name, value.toString());
446 }
447
448 /***
449 * Adds a name=value pair to the query string.
450 *
451 * @param name A String with the name to add.
452 * @param value A String with the value to add.
453 */
454 public void addQueryData(String name, String value)
455 {
456 add(QUERY_DATA, name, value);
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 A double with the value to add.
464 */
465 public void addQueryData(String name, double value)
466 {
467 add(QUERY_DATA, name, Double.toString(value));
468 }
469
470 /***
471 * Adds a name=value pair to the query string.
472 *
473 * @param name A String with the name to add.
474 * @param value An int with the value to add.
475 */
476 public void addQueryData(String name, int value)
477 {
478 add(QUERY_DATA, name, Integer.toString(value));
479 }
480
481 /***
482 * Adds a name=value pair to the query string.
483 *
484 * @param name A String with the name to add.
485 * @param value A long with the value to add.
486 */
487 public void addQueryData(String name, long value)
488 {
489 add(QUERY_DATA, name, Long.toString(value));
490 }
491
492 /***
493 * Adds a name=value pair for every entry in a ParameterParser
494 * object to the query string.
495 *
496 * @param pp A ParameterParser.
497 */
498 public void addQueryData(ParameterParser pp)
499 {
500 add(QUERY_DATA, pp);
501 }
502
503 /***
504 * Adds an existing List of URIParam objects to the query data.
505 *
506 * @param list A list with URIParam objects.
507 */
508 public void addQueryData(List list)
509 {
510 add(QUERY_DATA, list);
511 }
512
513 /***
514 * Is Path Info data set in this URI?
515 *
516 * @return true if Path Info has values
517 */
518 public boolean hasPathInfo()
519 {
520 return !dataVectors[PATH_INFO].isEmpty();
521 }
522
523 /***
524 * Removes all the path info elements.
525 */
526 public void removePathInfo()
527 {
528 dataVectors[PATH_INFO].clear();
529 }
530
531 /***
532 * Removes a name=value pair from the path info.
533 *
534 * @param name A String with the name to be removed.
535 */
536 public void removePathInfo(String name)
537 {
538 remove(PATH_INFO, name);
539 }
540
541 /***
542 * Is Query data set in this URI?
543 *
544 * @return true if Query data has values
545 */
546 public boolean hasQueryData()
547 {
548 return !dataVectors[QUERY_DATA].isEmpty();
549 }
550
551 /***
552 * Removes all the query string elements.
553 */
554 public void removeQueryData()
555 {
556 dataVectors[QUERY_DATA].clear();
557 }
558
559 /***
560 * Removes a name=value pair from the query string.
561 *
562 * @param name A String with the name to be removed.
563 */
564 public void removeQueryData(String name)
565 {
566 remove (QUERY_DATA, name);
567 }
568
569 /***
570 * Template Link and friends want to be able to turn the encoding
571 * of the servlet container off. After calling this method,
572 * the no encoding will happen any longer. If you think, that you
573 * need this outside a template context, think again.
574 */
575 public void clearResponse()
576 {
577 setResponse(null);
578 }
579
580
581 /***
582 * Builds the URL with all of the data URL-encoded as well as
583 * encoded using HttpServletResponse.encodeUrl(). The resulting
584 * URL is absolute; it starts with http/https...
585 *
586 * <p>
587 * <code><pre>
588 * TurbineURI tui = new TurbineURI (data, "UserScreen");
589 * tui.addPathInfo("user","jon");
590 * tui.getAbsoluteLink();
591 * </pre></code>
592 *
593 * The above call to absoluteLink() would return the String:
594 *
595 * <p>
596 * http://www.server.com/servlets/Turbine/screen/UserScreen/user/jon
597 *
598 * @return A String with the built URL.
599 */
600 public String getAbsoluteLink()
601 {
602 StringBuffer output = new StringBuffer();
603
604 getSchemeAndPort(output);
605
606 buildRelativeLink(output);
607
608
609
610
611 return encodeResponse(output.toString());
612 }
613
614 /***
615 * Builds the URL with all of the data URL-encoded as well as
616 * encoded using HttpServletResponse.encodeUrl(). The resulting
617 * URL is relative to the webserver root.
618 *
619 * <p>
620 * <code><pre>
621 * TurbineURI tui = new TurbineURI (data, "UserScreen");
622 * tui.addPathInfo("user","jon");
623 * tui.getRelativeLink();
624 * </pre></code>
625 *
626 * The above call to relativeLink() would return the String:
627 *
628 * <p>
629 * /servlets/Turbine/screen/UserScreen/user/jon
630 *
631 * @return A String with the built URL.
632 */
633 public String getRelativeLink()
634 {
635 StringBuffer output = new StringBuffer();
636
637 buildRelativeLink(output);
638
639
640
641
642 return encodeResponse(output.toString());
643 }
644
645 /***
646 * Add everything needed for a relative link to the passed StringBuffer.
647 *
648 * @param output A Stringbuffer
649 */
650 private void buildRelativeLink(StringBuffer output)
651 {
652 getContextAndScript(output);
653
654 if (hasPathInfo())
655 {
656 output.append('/');
657 getPathInfoAsString(output);
658 }
659
660 if (hasReference())
661 {
662 output.append('#');
663 output.append(getReference());
664 }
665
666 if (hasQueryData())
667 {
668 output.append('?');
669 getQueryDataAsString(output);
670 }
671 }
672
673 /***
674 * Gets the current Query Data List.
675 *
676 * @return A List which contains all query data keys. The keys
677 * are URIParam objects.
678 */
679 public List getPathInfo()
680 {
681 return dataVectors[PATH_INFO];
682 }
683
684 /***
685 * Sets the Query Data List. Replaces the current query data list
686 * with the one supplied. The list must contain only URIParam
687 * objects!
688 *
689 * @param pathInfo A List with new param objects.
690 */
691
692 public void setPathInfo(List pathInfo)
693 {
694 dataVectors[PATH_INFO] = pathInfo;
695 }
696
697 /***
698 * Gets the current Query Data List.
699 *
700 * @return A List which contains all query data keys. The keys
701 * are URIParam objects.
702 */
703 public List getQueryData()
704 {
705 return dataVectors[QUERY_DATA];
706 }
707
708 /***
709 * Sets the Query Data List. Replaces the current query data list
710 * with the one supplied. The list must contain only URIParam
711 * objects!
712 *
713 * @param queryData A List with new param objects.
714 */
715
716 public void setQueryData(List queryData)
717 {
718 dataVectors[QUERY_DATA] = queryData;
719 }
720
721 /***
722 * Simply calls getAbsoluteLink(). You should not use this in your
723 * code unless you have to. Use getAbsoluteLink.
724 *
725 * @return This URI as a String
726 *
727 */
728 public String toString()
729 {
730 return getAbsoluteLink();
731 }
732
733
734
735
736
737
738
739
740
741
742 /***
743 * Returns the Path Info data as a String.
744 *
745 * @param output The StringBuffer that should hold the path info.
746 */
747 private void getPathInfoAsString(StringBuffer output)
748 {
749 doEncode(output, dataVectors[PATH_INFO], '/', '/');
750 }
751
752 /***
753 * Returns the Query data as a String.
754 *
755 * @param output The StringBuffer that should hold the query data.
756 */
757 private void getQueryDataAsString(StringBuffer output)
758 {
759 doEncode(output, dataVectors[QUERY_DATA], '&', '=');
760 }
761
762 /***
763 * Does the actual encoding for pathInfoAsString and queryDataAsString.
764 *
765 * @param output The Stringbuffer that should contain the information.
766 * @param list A Collection
767 * @param fieldDelim A char which is used to separate key/value pairs
768 * @param valueDelim A char which is used to separate key and value
769 */
770 private void doEncode(StringBuffer output, Collection list, char fieldDelim, char valueDelim)
771 {
772 if(!list.isEmpty())
773 {
774 for(Iterator it = list.iterator(); it.hasNext();)
775 {
776 URIParam uriParam = (URIParam) it.next();
777 String key = URLEncoder.encode(uriParam.getKey());
778 String val = String.valueOf(uriParam.getValue());
779
780 output.append(key);
781 output.append(valueDelim);
782
783 if(StringUtils.isEmpty(val))
784 {
785 if (val == null && log.isDebugEnabled())
786 {
787 log.debug("Found a null value for " + key);
788 }
789 output.append(val);
790 }
791 else
792 {
793 output.append(URLEncoder.encode(val));
794 }
795
796 if (it.hasNext())
797 {
798 output.append(fieldDelim);
799 }
800 }
801 }
802 }
803
804 /***
805 * If the type is PATH_INFO, then add name/value to the pathInfo
806 * hashtable.
807 * <p>
808 * If the type is QUERY_DATA, then add name/value to the queryData
809 * hashtable.
810 *
811 * @param type Type (PATH_INFO or QUERY_DATA) of insertion.
812 * @param name A String with the name to add.
813 * @param value A String with the value to add.
814 */
815 protected void add(int type,
816 String name,
817 String value)
818 {
819 URIParam uriParam = new URIParam(ParserUtils.convertAndTrim(name), value);
820
821 dataVectors[type].add(uriParam);
822 }
823
824 /***
825 * Method for a quick way to add all the parameters in a
826 * ParameterParser.
827 *
828 * <p>If the type is P (0), then add name/value to the pathInfo
829 * hashtable.
830 *
831 * <p>If the type is Q (1), then add name/value to the queryData
832 * hashtable.
833 *
834 * @param type Type of insertion (@see #add(char type, String name, String value))
835 * @param pp A ParameterParser.
836 */
837 protected void add(int type,
838 ParameterParser pp)
839 {
840 for(Iterator it = pp.keySet().iterator(); it.hasNext();)
841 {
842 String key = (String) it.next();
843
844 if (!key.equalsIgnoreCase(CGI_ACTION_PARAM) &&
845 !key.equalsIgnoreCase(CGI_SCREEN_PARAM))
846 {
847 String[] values = pp.getStrings(key);
848 if(values != null)
849 {
850 for (int i = 0; i < values.length; i++)
851 {
852 add(type, key, values[i]);
853 }
854 }
855 else
856 {
857 add(type, key, "");
858 }
859 }
860 }
861 }
862
863 /***
864 * Method for a quick way to add all the parameters in a
865 * List with URIParam objects.
866 *
867 * <p>If the type is P (0), then add name/value to the pathInfo
868 * hashtable.
869 *
870 * <p>If the type is Q (1), then add name/value to the queryData
871 * hashtable.
872 *
873 * @param type Type of insertion (@see #add(char type, String name, String value))
874 * @param list A List of URIParam objects
875 */
876 protected void add(int type,
877 List list)
878 {
879 for (Iterator it = list.iterator(); it.hasNext();)
880 {
881
882
883
884 URIParam uriParam = (URIParam) it.next();
885 dataVectors[type].add(uriParam);
886 }
887 }
888
889 /***
890 * If the type is P (0), then remove name/value from the
891 * pathInfo hashtable.
892 *
893 * <p>If the type is Q (1), then remove name/value from the
894 * queryData hashtable.
895 *
896 * @param type Type (P or Q) of removal.
897 * @param name A String with the name to be removed.
898 */
899 protected void remove (int type,
900 String name)
901 {
902 Collection c = dataVectors[type];
903 String key = ParserUtils.convertAndTrim(name);
904
905 for (Iterator it = c.iterator(); it.hasNext();)
906 {
907 URIParam uriParam = (URIParam) it.next();
908
909 if (key.equals(uriParam.getKey()))
910 {
911 it.remove();
912 }
913 }
914 }
915 }