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