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 638205 2008-03-18 04:10:39Z seade $
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, null == value ? null : 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, null == value ? null : 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 = null == uriParam.getValue()
779 ? null : String.valueOf(uriParam.getValue());
780
781 output.append(key);
782 output.append(valueDelim);
783
784 if(StringUtils.isEmpty(val))
785 {
786 if (val == null)
787 {
788 if (log.isWarnEnabled())
789 {
790 log.warn("Found a null value for " + key);
791 }
792
793 val = "null";
794 }
795 output.append(val);
796 }
797 else
798 {
799 output.append(URLEncoder.encode(val));
800 }
801
802 if (it.hasNext())
803 {
804 output.append(fieldDelim);
805 }
806 }
807 }
808 }
809
810 /***
811 * If the type is PATH_INFO, then add name/value to the pathInfo
812 * hashtable.
813 * <p>
814 * If the type is QUERY_DATA, then add name/value to the queryData
815 * hashtable.
816 *
817 * @param type Type (PATH_INFO or QUERY_DATA) of insertion.
818 * @param name A String with the name to add.
819 * @param value A String with the value to add.
820 */
821 protected void add(int type,
822 String name,
823 String value)
824 {
825 URIParam uriParam = new URIParam(ParserUtils.convertAndTrim(name), value);
826
827 dataVectors[type].add(uriParam);
828 }
829
830 /***
831 * Method for a quick way to add all the parameters in a
832 * ParameterParser.
833 *
834 * <p>If the type is P (0), then add name/value to the pathInfo
835 * hashtable.
836 *
837 * <p>If the type is Q (1), then add name/value to the queryData
838 * hashtable.
839 *
840 * @param type Type of insertion (@see #add(char type, String name, String value))
841 * @param pp A ParameterParser.
842 */
843 protected void add(int type,
844 ParameterParser pp)
845 {
846 for(Iterator it = pp.keySet().iterator(); it.hasNext();)
847 {
848 String key = (String) it.next();
849
850 if (!key.equalsIgnoreCase(CGI_ACTION_PARAM) &&
851 !key.equalsIgnoreCase(CGI_SCREEN_PARAM))
852 {
853 String[] values = pp.getStrings(key);
854 if(values != null)
855 {
856 for (int i = 0; i < values.length; i++)
857 {
858 add(type, key, values[i]);
859 }
860 }
861 else
862 {
863 add(type, key, "");
864 }
865 }
866 }
867 }
868
869 /***
870 * Method for a quick way to add all the parameters in a
871 * List with URIParam objects.
872 *
873 * <p>If the type is P (0), then add name/value to the pathInfo
874 * hashtable.
875 *
876 * <p>If the type is Q (1), then add name/value to the queryData
877 * hashtable.
878 *
879 * @param type Type of insertion (@see #add(char type, String name, String value))
880 * @param list A List of URIParam objects
881 */
882 protected void add(int type,
883 List list)
884 {
885 for (Iterator it = list.iterator(); it.hasNext();)
886 {
887
888
889
890 URIParam uriParam = (URIParam) it.next();
891 dataVectors[type].add(uriParam);
892 }
893 }
894
895 /***
896 * If the type is P (0), then remove name/value from the
897 * pathInfo hashtable.
898 *
899 * <p>If the type is Q (1), then remove name/value from the
900 * queryData hashtable.
901 *
902 * @param type Type (P or Q) of removal.
903 * @param name A String with the name to be removed.
904 */
905 protected void remove (int type,
906 String name)
907 {
908 Collection c = dataVectors[type];
909 String key = ParserUtils.convertAndTrim(name);
910
911 for (Iterator it = c.iterator(); it.hasNext();)
912 {
913 URIParam uriParam = (URIParam) it.next();
914
915 if (key.equals(uriParam.getKey()))
916 {
917 it.remove();
918 }
919 }
920 }
921 }