1
2
3
4
5
6
7
8 /
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77 public class LinkTool
78 {
79 /*** utf encoding. */
80 public static final String PARAMETER_ENCODING = "UTF-8";
81
82 /*** query string parameter values and content paths encoder. */
83 private static final org.objectledge.encodings.URLEncoder URL_ENCODER =
84 new org.objectledge.encodings.URLEncoder();
85
86 /*** configuration. */
87 protected LinkTool.Configuration config;
88
89 /*** the http context. */
90 protected HttpContext httpContext;
91
92 /*** the mvc context. */
93 protected MVCContext mvcContext;
94
95 /*** the request parameters. */
96 protected RequestParameters requestParameters;
97
98 /*** view, null for current request parameters view value, empty string for unset value */
99 private String view;
100
101 /*** the action, empty string for unset value */
102 private String action;
103
104 /*** is content link switch */
105 private boolean contentLink;
106
107 /*** include session information */
108 private boolean includeSession;
109
110 /*** show the protocol in link */
111 private boolean showProtocolName;
112
113 /*** protocol name */
114 private String protocolName;
115
116 /*** host name */
117 private String host;
118
119 /*** the port */
120 private int port;
121
122 /*** the content path */
123 private String path;
124
125 /*** the special path info suffix */
126 private String pathInfoSuffix;
127
128 /*** the fragment part of the url */
129 private String fragment;
130
131 /*** the parameters */
132 private Parameters parameters;
133
134 /*** the string buffer */
135 private StringBuilder sb;
136
137 /***
138 * Tool constructor.
139 *
140 * @param httpContext the http context.
141 * @param mvcContext the mvc context.
142 * @param requestParameters the request parameters.
143 * @param config the link tool configuraiton.
144 */
145 public LinkTool(HttpContext httpContext, MVCContext mvcContext,
146 RequestParameters requestParameters, LinkTool.Configuration config)
147 {
148 this.config = config;
149 this.httpContext = httpContext;
150 this.mvcContext = mvcContext;
151 this.requestParameters = requestParameters;
152 contentLink = false;
153 includeSession = true;
154 showProtocolName = false;
155 protocolName = "";
156 port = 0;
157 host = null;
158
159 view = null;
160 action = "";
161 pathInfoSuffix = null;
162 fragment = null;
163 if(config.stickyParameterNames.size() > 0)
164 {
165 parameters = new SortedParameters(requestParameters);
166 parameters.removeExcept(config.stickyParameterNames);
167 }
168 else
169 {
170 parameters = new SortedParameters();
171 }
172 }
173
174 /***
175 * Set the protocol to http with default port on 80.
176 *
177 * @return the link tool.
178 */
179 public LinkTool http()
180 {
181 return http(80);
182 }
183
184 /***
185 * Set the protocol to http with specified port.
186 *
187 * @param port the port.
188 * @return the link tool.
189 */
190 public LinkTool http(int port)
191 {
192 LinkTool target = getLinkTool(this);
193 target.showProtocolName = true;
194 target.protocolName = "http";
195 target.port = port;
196 return target;
197 }
198
199 /***
200 * Set the protocol to https with default port on 443.
201 *
202 * @return the link tool.
203 */
204 public LinkTool https()
205 {
206 return https(443);
207 }
208
209 /***
210 * Set the protocol to https with specified port.
211 *
212 * @param port the port.
213 * @return the link tool.
214 */
215 public LinkTool https(int port)
216 {
217 LinkTool target = getLinkTool(this);
218 target.showProtocolName = true;
219 target.protocolName = "https";
220 target.port = port;
221 return target;
222 }
223
224 /***
225 * Generate an absolute link including protocol name (schema), server name and port number.
226 *
227 * @return the link tool.
228 */
229 public LinkTool absolute()
230 {
231 LinkTool target = getLinkTool(this);
232 target.showProtocolName = true;
233 if(target.port == 0)
234 {
235 target.port = httpContext.getRequest().getServerPort();
236 }
237 if(target.protocolName == null || target.protocolName.length()==0)
238 {
239 if(httpContext.getRequest().isSecure())
240 {
241 target.protocolName = "https";
242 }
243 else
244 {
245 target.protocolName = "http";
246 }
247 }
248 return target;
249 }
250
251 /***
252 * Geneate an absolute link to another host.
253 *
254 * @param host the host domain name.
255 * @return the link tool.
256 */
257 public LinkTool host(String host)
258 {
259 LinkTool target = absolute();
260 target.host = host;
261 return target;
262 }
263
264 /***
265 * Avoid session information in link - useful for content served using external HTTP server.
266 *
267 * @return the link tool.
268 */
269 public LinkTool sessionless()
270 {
271 LinkTool target = getLinkTool(this);
272 target.includeSession = false;
273 return target;
274 }
275
276 /***
277 * Set link to point to the content stored in <code>/</code> directory of servlet context.
278 * May be used to generate relative content paths (not recommended).
279 *
280 * @param path the path to content.
281 * @return the link tool.
282 */
283 public LinkTool rootContent(String path)
284 {
285 LinkTool target = getLinkTool(this);
286 target.contentLink = true;
287 target.includeSession = this.includeSession && !config.externalContent;
288 target.path = path;
289 return target;
290 }
291
292 /***
293 * Set link to point to the content stored in configured content (<code>/content</code>)
294 * directory of servlet context.
295 *
296 * @param path the relative path to content.
297 * @return the link tool.
298 */
299 public LinkTool content(String path)
300 {
301 if (path.length() == 0)
302 {
303 path = config.baseContentPath;
304 }
305 else if (path.charAt(0) != '/')
306 {
307 path = config.baseContentPath + '/' + path;
308 }
309 else
310 {
311 path = config.baseContentPath + path;
312 }
313 return rootContent(path);
314 }
315
316
317
318 /***
319 * Sets a request parameter, replacing previously set value.
320 * Unless configured differently it will be rendered in the link as query string parameter.
321 *
322 * @param name the name of the parameter.
323 * @param value the value of the parameter.
324 * @return the link tool.
325 */
326 public LinkTool set(String name, String value)
327 {
328 LinkTool target = getSetTargetLinkTool(name);
329 target.parameters.set(name, value);
330 return target;
331 }
332
333 /***
334 * Sets a request parameter, replacing previously set value.
335 * Unless configured differently it will be rendered in the link as query string parameter.
336 *
337 * @param name the name of the parameter.
338 * @param value the value of the parameter.
339 * @return the link tool.
340 */
341 public LinkTool set(String name, int value)
342 {
343 LinkTool target = getSetTargetLinkTool(name);
344 target.parameters.set(name, value);
345 return target;
346 }
347
348 /***
349 * Sets a request parameter, replacing previously set value.
350 * Unless configured differently it will be rendered in the link as query string parameter.
351 *
352 * @param name the name of the parameter.
353 * @param value the value of the parameter.
354 * @return the link tool.
355 */
356 public LinkTool set(String name, long value)
357 {
358 LinkTool target = getSetTargetLinkTool(name);
359 target.parameters.set(name, value);
360 return target;
361 }
362
363 /***
364 * Sets a request parameter, replacing previously set value.
365 * Unless configured differently it will be rendered in the link as query string parameter.
366 *
367 * @param name the name of the parameter.
368 * @param value the value of the parameter.
369 * @return the link tool.
370 */
371 public LinkTool set(String name, float value)
372 {
373 LinkTool target = getSetTargetLinkTool(name);
374 target.parameters.set(name, value);
375 return target;
376 }
377
378 /***
379 * Sets a request parameter, replacing previously set value.
380 * Unless configured differently it will be rendered in the link as query string parameter.
381 *
382 * @param name the name of the parameter.
383 * @param value the value of the parameter.
384 * @return the link tool.
385 */
386 public LinkTool set(String name, boolean value)
387 {
388 LinkTool target = getSetTargetLinkTool(name);
389 target.parameters.set(name, value);
390 return target;
391 }
392
393 /***
394 * Sets multiple values of a parameter using a {@link java.util.List}.
395 *
396 * @param name the name of the parameter.
397 * @param list a list of parameter values.
398 * @return the link tool.
399 */
400 public LinkTool set(String name, List<String> list)
401 {
402 LinkTool target = getSetTargetLinkTool(name);
403 target.parameters.remove(name);
404 for (String value : list)
405 {
406 target.parameters.add(name, value);
407 }
408 return target;
409 }
410
411 /***
412 * Adds a set of parameters defined as a {@link java.util.Map} to the request.
413 * Removes old values of the parameters.
414 *
415 * @param map a set of parametres as a Map.
416 * @return the link tool.
417 */
418 public LinkTool set(Map<String, String> map)
419 {
420 if (map.containsKey(config.viewToken))
421 {
422 checkSetParamName(config.viewToken);
423 }
424 else if (map.containsKey(config.actionToken))
425 {
426 checkSetParamName(config.actionToken);
427 }
428 LinkTool target = getLinkTool(this);
429 for (Iterator<Map.Entry<String, String>> iter = map.entrySet().iterator(); iter.hasNext();)
430 {
431 Map.Entry<String, String> e = iter.next();
432 target.parameters.remove(e.getKey());
433 target.parameters.add(e.getKey(), e.getValue());
434 }
435 return target;
436 }
437
438
439
440 /***
441 * Sets the request parameters to be equal to contents of the specified
442 * parameter container.
443 *
444 * @param parameters a set of paramters
445 * @return the link tool.
446 */
447 public LinkTool set(Parameters parameters)
448 {
449 if (parameters.isDefined(config.viewToken))
450 {
451 checkSetParamName(config.viewToken);
452 }
453 else if (parameters.isDefined(config.actionToken))
454 {
455 checkSetParamName(config.actionToken);
456 }
457 LinkTool target = getLinkTool(this);
458 target.parameters = new SortedParameters(parameters);
459 return target;
460 }
461
462 /***
463 * Checks the name of the set parameter and returns target link tool.
464 * Method created for code reuse.
465 *
466 * @param paramName checked name of the set parameter.
467 * @return target link tool
468 */
469 private LinkTool getSetTargetLinkTool(String paramName)
470 {
471 checkSetParamName(paramName);
472 return getLinkTool(this);
473 }
474
475
476
477 /***
478 * Sets the path info suffix for this link.
479 * May be used for file download links.
480 *
481 * @param pathInfoSuffix the path info suffix.
482 * @return the link tool.
483 */
484 public LinkTool pathInfoSuffix(String pathInfoSuffix)
485 {
486 LinkTool target = getLinkTool(this);
487 target.pathInfoSuffix = pathInfoSuffix;
488 return target;
489 }
490
491 /***
492 * Returns the path info suffix for this link.
493 *
494 * @return the path info suffx in the current link
495 */
496 public String pathInfoSuffix()
497 {
498 return pathInfoSuffix;
499 }
500
501 /***
502 * Sets the fragment for this link.
503 * Fragment is appended as <code>#fragment-value</code> to the rendered link.
504 *
505 * @param fragment the fragment.
506 * @return the link tool.
507 */
508 public LinkTool fragment(String fragment)
509 {
510 LinkTool target = getLinkTool(this);
511 target.fragment = fragment;
512 return target;
513 }
514
515 /***
516 * Returns the fragment for this link.
517 *
518 * @return the fragment in the current link
519 */
520 public String fragment()
521 {
522 return fragment;
523 }
524
525 /***
526 * Sets the parameters to be equal to the paremeters of the
527 * current request.
528 *
529 * <p>WARN: This method creates links different from the request URI if some of the parameters
530 * were passed as path info parameters and not configured as such.</p>
531 *
532 * @return the link tool.
533 */
534 public LinkTool self()
535 {
536 LinkTool target = getLinkTool(this);
537 target.parameters.remove(config.stickyParameterNames);
538 target.parameters.add(requestParameters, true);
539 target.parameters.remove(config.viewToken);
540 target.parameters.remove(config.actionToken);
541 String url = httpContext.getRequest().getRequestURI();
542 if (url.indexOf('#') > 0)
543 {
544 target.fragment = url.substring(url.lastIndexOf('#') + 1);
545 }
546 return target;
547 }
548
549 /***
550 * Prepare link tool pointed to referer page
551 * @return the link tool
552 */
553 public LinkTool getReferer()
554 {
555 Enumeration enumeration = httpContext.getRequest().getHeaders("referer");
556 if( enumeration != null && enumeration.hasMoreElements())
557 {
558 return parseURL(enumeration.nextElement().toString());
559 }
560 else
561 {
562 return null;
563 }
564 }
565
566 /***
567 * Parse given string to obtain link tool object
568 * @param url - string of the toString() shape
569 * @return the link tool
570 * @see #toString()
571 */
572 private LinkTool parseURL(String url)
573 {
574 LinkTool target = getLinkTool(this);
575 int index = url.indexOf(config.viewToken+"/");
576 if( StringUtils.isEmpty(url) || index < 0)
577 {
578 return target;
579 }
580 Map<String,String> paramsMap = parseURLParams(url.substring(index), "&=?/");
581
582 for( String name: paramsMap.keySet())
583 {
584 if(config.viewToken.equals(name))
585 {
586 target.view = paramsMap.get(name);
587 continue;
588 }
589 if( config.actionToken.equals(name))
590 {
591 target.action = paramsMap.get(name);
592 continue;
593 }
594 target.parameters.add(name, paramsMap.get(name));
595 }
596 return target;
597 }
598
599 private static final int START = 0;
600 private static final int NAME = 1;
601 private static final int SEPARATOR_AFTER_NAME = 2;
602 private static final int VALUE = 3;
603 private static final int SEPARATOR_AFTER_VALUE = 4;
604
605 private Map<String,String> parseURLParams(String urlPart, String separator)
606 {
607 Map<String, String> paramsMap = new HashMap<String, String>();
608 if (urlPart == null)
609 {
610 return paramsMap;
611 }
612
613 try
614 {
615 StringTokenizer st = new StringTokenizer(urlPart, separator, true);
616 int state = START;
617 String name = null;
618 while (st.hasMoreTokens())
619 {
620 String token = st.nextToken();
621
622 if(token.length() == 1 && separator.indexOf(token.charAt(0)) > -1 )
623 {
624 switch(state)
625 {
626 case START:
627 state = NAME;
628 break;
629 case SEPARATOR_AFTER_NAME:
630 state = VALUE;
631 break;
632 case SEPARATOR_AFTER_VALUE:
633 state = NAME;
634 break;
635 case VALUE:
636 add(name, "");
637 name = null;
638 state = NAME;
639 break;
640 case NAME:
641 throw new IllegalStateException("empty parameter name");
642 default:
643 throw new IllegalStateException(
644 "illegal state while parsing params");
645 }
646 }
647
648 else
649 {
650 switch(state)
651 {
652 case START:
653 case NAME:
654 name = URLDecoder.decode(token, LinkTool.PARAMETER_ENCODING);
655 paramsMap.put(name,"");
656 state = SEPARATOR_AFTER_NAME;
657 break;
658 case VALUE:
659 paramsMap.put(name, URLDecoder.decode(token, LinkTool.PARAMETER_ENCODING));
660 name = null;
661 state = SEPARATOR_AFTER_VALUE;
662 break;
663 default:
664 break;
665 }
666 }
667 }
668 return paramsMap;
669 }
670
671 catch (UnsupportedEncodingException e)
672 {
673 throw new IllegalArgumentException("Unsupported encoding exception " + e.getMessage());
674 }
675
676 }
677
678
679
680 /***
681 * Adds a request parameter, extending it's values set.
682 *
683 * @param name the name of the parameter.
684 * @param value the value of the parameter.
685 * @return the link tool.
686 */
687 public LinkTool add(String name, String value)
688 {
689 LinkTool target = getAddTargetLinkTool(name);
690 target.parameters.add(name, value);
691 return target;
692 }
693
694 /***
695 * Adds a request parameter, extending it's values set.
696 *
697 * @param name the name of the parameter.
698 * @param value the value of the parameter.
699 * @return the link tool.
700 */
701 public LinkTool add(String name, int value)
702 {
703 LinkTool target = getAddTargetLinkTool(name);
704 target.parameters.add(name, value);
705 return target;
706 }
707
708 /***
709 * Adds a request parameter, extending it's values set.
710 *
711 * @param name the name of the parameter.
712 * @param value the value of the parameter.
713 * @return the link tool.
714 */
715 public LinkTool add(String name, long value)
716 {
717 LinkTool target = getAddTargetLinkTool(name);
718 target.parameters.add(name, value);
719 return target;
720 }
721
722 /***
723 * Adds a request parameter, extending it's values set.
724 *
725 * @param name the name of the parameter.
726 * @param value the value of the parameter.
727 * @return the link tool.
728 */
729 public LinkTool add(String name, float value)
730 {
731 LinkTool target = getAddTargetLinkTool(name);
732 target.parameters.add(name, value);
733 return target;
734 }
735
736 /***
737 * Adds a request parameter, extending it's values set.
738 *
739 * @param name the name of the parameter.
740 * @param value the value of the parameter.
741 * @return the link tool.
742 */
743 public LinkTool add(String name, boolean value)
744 {
745 LinkTool target = getAddTargetLinkTool(name);
746 target.parameters.add(name, value);
747 return target;
748 }
749
750 /***
751 * Adds multiple parameter values using a {@link java.util.List}.
752 *
753 * @param name the name of the parameter.
754 * @param list a set of parameter values.
755 * @return the link tool.
756 */
757 public LinkTool add(String name, List<String> list)
758 {
759 LinkTool target = getAddTargetLinkTool(name);
760 for (String value : list)
761 {
762 target.parameters.add(name, value);
763 }
764 return target;
765 }
766
767 /***
768 * Adds a set of parameters defined as a {@link java.util.Map} to the request.
769 *
770 * @param map a set of parametres as a Map.
771 * @return the link tool.
772 */
773 public LinkTool add(Map<String, String> map)
774 {
775 if (map.containsKey(config.viewToken))
776 {
777 checkAddParamName(config.viewToken);
778 }
779 else if (map.containsKey(config.actionToken))
780 {
781 checkAddParamName(config.actionToken);
782 }
783 LinkTool target = getLinkTool(this);
784 for (Iterator<Map.Entry<String, String>> iter = map.entrySet().iterator(); iter.hasNext();)
785 {
786 Map.Entry<String, String> e = iter.next();
787 target.parameters.add(e.getKey(), e.getValue());
788 }
789 return target;
790 }
791
792 /***
793 * Adds a set of parameters to the request.
794 *
795 * @param parameters a set of paremteres.
796 * @return the link tool.
797 */
798 public LinkTool add(Parameters parameters)
799 {
800 if (parameters.isDefined(config.viewToken))
801 {
802 checkAddParamName(config.viewToken);
803 }
804 else if (parameters.isDefined(config.actionToken))
805 {
806 checkAddParamName(config.actionToken);
807 }
808 LinkTool target = getLinkTool(this);
809 target.parameters.add(parameters, false);
810 return target;
811 }
812
813 /***
814 * Checks the name of the set parameter and returns target link tool.
815 * Method created for code reuse.
816 *
817 * @param paramName checked name of the set parameter.
818 * @return target link tool
819 */
820 private LinkTool getAddTargetLinkTool(String paramName)
821 {
822 checkAddParamName(paramName);
823 return getLinkTool(this);
824 }
825
826
827
828 /***
829 * Removes all values of a request parameter.
830 *
831 * @param name the name of the parameter.
832 * @return the link tool.
833 */
834 public LinkTool unset(String name)
835 {
836 LinkTool target = getLinkTool(this);
837 if (name.equals(config.viewToken))
838 {
839 throw new IllegalArgumentException("to unset the value of the view parameter, " +
840 "call the unsetView() method");
841 }
842 else if (name.equals(config.actionToken))
843 {
844 throw new IllegalArgumentException("to unset the value of the action parameter, " +
845 "call the unsetAction() method");
846 }
847 else
848 {
849 target.parameters.remove(name);
850 }
851 return target;
852 }
853
854 /***
855 * Sets the view parameter in the link.
856 *
857 * @param view the view.
858 * @return the link tool.
859 */
860 public LinkTool view(String view)
861 {
862 LinkTool target = getLinkTool(this);
863 target.view = view;
864 return target;
865 }
866
867 /***
868 * Sets the action parameter in the link.
869 *
870 * @param action the action.
871 * @return the link tool.
872 */
873 public LinkTool action(String action)
874 {
875 LinkTool target = getLinkTool(this);
876 target.action = action;
877 return target;
878 }
879
880 /***
881 * @return the name of the action parameter.
882 */
883 public String actionParam()
884 {
885 return config.actionToken;
886 }
887
888 /***
889 * @return the name of the view parameter.
890 */
891 public String viewParam()
892 {
893 return config.viewToken;
894 }
895
896 /***
897 * Removes the view parameter.
898 *
899 * @return the link tool.
900 */
901 public LinkTool unsetView()
902 {
903 LinkTool target = getLinkTool(this);
904 target.view = "";
905 return target;
906 }
907
908 /***
909 * Removes the action parameter.
910 *
911 * @return the link tool.
912 */
913 public LinkTool unsetAction()
914 {
915 LinkTool target = getLinkTool(this);
916 target.action = "";
917 return target;
918 }
919
920
921
922 /***
923 * Produces a {@link java.lang.String} representation of this link.
924 *
925 * @return the link.
926 */
927 public String toString()
928 {
929 if(sb != null)
930 {
931 sb.setLength(0);
932 }
933 else
934 {
935 sb = new StringBuilder();
936 }
937
938 try
939 {
940
941 appendServerPart(sb);
942
943
944 sb.append(getContextPath());
945
946 if (contentLink)
947 {
948 appendContentLink(sb);
949 }
950 else
951 {
952 sb.append(getServletPath());
953
954 Parameters parametersTmp = getParameters();
955 String[] keys = parametersTmp.getParameterNames();
956 appendPathInfo(sb, keys, parametersTmp);
957 appendPathInfoSuffix(sb);
958 appendQueryString(sb, keys, parametersTmp);
959 }
960
961 if (fragment != null)
962 {
963 sb.append('#').append(fragment);
964 }
965
966
967 String link = sb.toString();
968 if (includeSession)
969 {
970 link = httpContext.getResponse().encodeURL(link);
971 }
972 return link;
973 }
974
975 catch (UnsupportedEncodingException e)
976 {
977 throw new RuntimeException("Exception occurred", e);
978 }
979
980 }
981
982 /***
983 * Allows other Tools to check link properties and
984 * creaton of subclasses which can override action name
985 * rendered in {@link #toString()} method.
986 *
987 * <p>WARN: This implementation only returns a reference to this <code>LinkTool</code>'s
988 * parameters field. If the subclass needs to change the rendered parameters, it should copy
989 * the parameters object.</p>
990 *
991 * @return the overriden parameters container
992 */
993 public Parameters getParameters()
994 {
995 return parameters;
996 }
997
998 private void appendServerPart(StringBuilder sb)
999 {
1000 if (showProtocolName)
1001 {
1002 final String protocolNameTmp = getProtocolName();
1003 sb.append(protocolNameTmp);
1004 sb.append("://");
1005 sb.append(getServerName());
1006 final int portTmp = getPort();
1007 if (mustAppendPort(protocolNameTmp, portTmp))
1008 {
1009 sb.append(':').append(portTmp);
1010 }
1011 }
1012 }
1013
1014 /***
1015 * Allows subclasses to override protocol name rendered in {@link #toString()} method.
1016 *
1017 * @return the overriden protocol name
1018 */
1019 protected String getProtocolName()
1020 {
1021 return protocolName;
1022 }
1023
1024 /***
1025 * Allows subclasses to override server name rendered in {@link #toString()} method.
1026 *
1027 * @return the overriden server name
1028 */
1029 protected String getServerName()
1030 {
1031 if(host == null)
1032 {
1033 return httpContext.getRequest().getServerName();
1034 }
1035 else
1036 {
1037 return host;
1038 }
1039 }
1040
1041 /***
1042 * Allows subclasses to override cotext path name rendered in {@link #toString()} method.
1043 *
1044 * @return the overriden context path
1045 */
1046 protected String getContextPath()
1047 {
1048 if(config.rewrite)
1049 {
1050
1051 return "";
1052 }
1053 else
1054 {
1055 return httpContext.getRequest().getContextPath();
1056 }
1057 }
1058
1059 /***
1060 * Allows subclasses to override servlet path name rendered in {@link #toString()} method.
1061 *
1062 * @return the overriden serlvet path
1063 */
1064 protected String getServletPath()
1065 {
1066 if(config.rewrite)
1067 {
1068
1069 return "";
1070 }
1071 else
1072 {
1073 return httpContext.getRequest().getServletPath();
1074 }
1075 }
1076
1077 /***
1078 * Allows subclasses to override check for port number inclusion requirement in
1079 * {@link #toString()} method.
1080 * This implementation returns <code>true</code> if port number is different from default
1081 * protocol port (default port number for http is 80, for https 443).
1082 *
1083 * @param protocolNameTmp appended protocol name
1084 * @param portTmp appended (or not) port number
1085 * @return <code>true</code> if port number must be appended.
1086 */
1087 protected boolean mustAppendPort(String protocolNameTmp, int portTmp)
1088 {
1089 return ((protocolNameTmp.length() == 0 || protocolNameTmp.equals("http")) && portTmp != 80)
1090 || (protocolNameTmp.equals("https") && portTmp != 443)
1091 || (protocolNameTmp.length() > 0
1092 && !protocolNameTmp.equals("https") && !protocolNameTmp.equals("http"));
1093 }
1094
1095 /***
1096 * Allows subclasses to override port number rendered in {@link #toString()} method.
1097 *
1098 * @return the overriden port number
1099 */
1100 protected int getPort()
1101 {
1102 return port;
1103 }
1104
1105
1106 private void appendContentLink(StringBuilder sb)
1107 throws UnsupportedEncodingException
1108 {
1109 final String pathTmp = getPath();
1110 if (pathTmp.length() > 0)
1111 {
1112 if (pathTmp.charAt(0) != '/')
1113 {
1114 sb.append('/');
1115 }
1116 sb.append(URL_ENCODER.encodeContentPath(pathTmp, PARAMETER_ENCODING));
1117 }
1118 }
1119
1120 /***
1121 * Allows subclasses to override static content path rendered in {@link #toString()} method.
1122 *
1123 * @return the overriden content path
1124 */
1125 protected String getPath()
1126 {
1127 return path;
1128 }
1129
1130 private void appendPathInfo(StringBuilder sb, String[] keys, Parameters parametersTmp)
1131 throws UnsupportedEncodingException
1132 {
1133 String outView = getView();
1134 if (outView == null)
1135 {
1136 outView = mvcContext.getView();
1137 }
1138 if (outView != null && outView.length() > 0)
1139 {
1140 sb.append('/').append(config.viewToken).append('/').append(outView);
1141 }
1142
1143 for (int i = 0; i < keys.length; i++)
1144 {
1145 String key = keys[i];
1146 if (config.pathinfoParameterNames.contains(key))
1147 {
1148 String[] values = parametersTmp.getStrings(key);
1149 for (int j = 0; j < values.length; j++)
1150 {
1151 sb.append('/').append(URLEncoder.encode(key, PARAMETER_ENCODING));
1152 sb.append('/').append(URLEncoder.encode(values[j], PARAMETER_ENCODING));
1153 }
1154 }
1155 }
1156 }
1157
1158 /***
1159 * Allows other Tools to check link properties and
1160 * creaton of subclasses which can override action name
1161 * rendered in {@link #toString()} method.
1162 *
1163 * @return the overriden view name or <code>null</code> if it should be replaced with view
1164 * from current request.
1165 */
1166 public String getView()
1167 {
1168 return view;
1169 }
1170
1171 private void appendPathInfoSuffix(StringBuilder sb)
1172 throws UnsupportedEncodingException
1173 {
1174 String pathInfoSuffixTmp = getPathInfoSuffix();
1175 if(pathInfoSuffixTmp != null && pathInfoSuffixTmp.length() > 0)
1176 {
1177 if(pathInfoSuffixTmp.charAt(0) != '/')
1178 {
1179 sb.append('/');
1180 }
1181 pathInfoSuffixTmp = URLEncoder.encode(pathInfoSuffixTmp, PARAMETER_ENCODING);
1182
1183 pathInfoSuffixTmp = pathInfoSuffixTmp.replace("%2F","/");
1184 sb.append(pathInfoSuffixTmp);
1185 }
1186 }
1187
1188 /***
1189 * Allows subclasses to override pathinfo suffix rendered in {@link #toString()} method.
1190 *
1191 * @return the overriden pathinfo suffix
1192 */
1193 protected String getPathInfoSuffix()
1194 {
1195 return pathInfoSuffix;
1196 }
1197
1198 private void appendQueryString(StringBuilder sb, String[] keys, Parameters parametersTmp)
1199 throws UnsupportedEncodingException
1200 {
1201 String querySeparator = "?";
1202 final String querySeparator2 = config.queryStringSeparator;
1203
1204 String actionTmp = getAction();
1205 if (actionTmp != null && actionTmp.length() > 0)
1206 {
1207 sb.append(querySeparator);
1208 sb.append(config.actionToken).append('=').append(actionTmp);
1209 querySeparator = querySeparator2;
1210 }
1211
1212 for (int i = 0; i < keys.length; i++)
1213 {
1214 String key = keys[i];
1215 if (!config.pathinfoParameterNames.contains(key))
1216 {
1217 String[] values = parametersTmp.getStrings(key);
1218 for (int j = 0; j < values.length; j++)
1219 {
1220 sb.append(querySeparator);
1221
1222 sb.append(URLEncoder.encode(key, PARAMETER_ENCODING));
1223 sb.append('=');
1224 sb.append(URL_ENCODER
1225 .encodeQueryStringValue(values[j], PARAMETER_ENCODING));
1226
1227 querySeparator = querySeparator2;
1228 }
1229 }
1230 }
1231 }
1232
1233 /***
1234 * Allows other Tools to check link properties and
1235 * creaton of subclasses which can override action name
1236 * rendered in {@link #toString()} method.
1237 *
1238 * @return the overriden action name
1239 */
1240 public String getAction()
1241 {
1242 return action;
1243 }
1244
1245
1246
1247 /***
1248 * Clone the given LinkTool.
1249 *
1250 * @param source to LinkTool to clone
1251 * @return the clone.
1252 */
1253 private LinkTool getLinkTool(LinkTool source)
1254 {
1255 LinkTool target = createInstance(source);
1256 target.view = source.view;
1257 target.action = source.action;
1258 target.contentLink = source.contentLink;
1259 target.includeSession = source.includeSession;
1260 target.showProtocolName = source.showProtocolName;
1261 target.protocolName = source.protocolName;
1262 target.port = source.port;
1263 target.host = source.host;
1264 target.path = source.path;
1265 target.pathInfoSuffix = source.pathInfoSuffix;
1266 target.fragment = source.fragment;
1267 target.parameters = new SortedParameters(source.parameters);
1268 return target;
1269 }
1270
1271 /***
1272 * Creates the LinkTool instance for copying. This method is intended to be overriden by
1273 * extending classes in order to provide LinkTool instances of proper class.
1274 *
1275 * @param source copied object
1276 * @return created instance of the linktool.
1277 */
1278 protected LinkTool createInstance(LinkTool source)
1279 {
1280 return new LinkTool(source.httpContext, source.mvcContext, source.requestParameters,
1281 source.config);
1282 }
1283
1284 private void checkSetParamName(String name)
1285 {
1286 if (name.equals(config.viewToken))
1287 {
1288 throw new IllegalArgumentException("to set the value of the view parameter, " +
1289 "call the view(String) method");
1290 }
1291 else if (name.equals(config.actionToken))
1292 {
1293 throw new IllegalArgumentException("to set the value of the action parameter, " +
1294 "call the action(String) method");
1295 }
1296 }
1297
1298 private void checkAddParamName(String name)
1299 {
1300 if (name.equals(config.viewToken))
1301 {
1302 throw new IllegalArgumentException("to set the value of the view parameter, " +
1303 "call the view(String) method");
1304 }
1305 else if (name.equals(config.actionToken))
1306 {
1307 throw new IllegalArgumentException("to set the value of the action parameter, " +
1308 "call the action(String) method");
1309 }
1310 }
1311
1312 /***
1313 * Represents the shared configuration of the LinkTools.
1314 *
1315 * <p>Created on Jan 14, 2004</p>
1316 * @author <a href="Rafal.Krzewski">rafal@caltha.pl</a>
1317 */
1318 public static class Configuration
1319 implements Configurable
1320 {
1321 /*** the default query separator. */
1322 public static final String DEFAULT_QUERY_SEPARATOR = "&";
1323
1324 /*** the default base content path. */
1325 public static final String DEFAULT_BASE_CONTENT_PATH = "/content";
1326
1327 /*** the sticky parameters keys */
1328 private Set stickyParameterNames = new HashSet();
1329
1330 /*** the pathinfo parameters keys */
1331 private Set pathinfoParameterNames = new HashSet();
1332
1333 /*** the query separator */
1334 private String queryStringSeparator;
1335
1336 /*** external content switch */
1337 private boolean externalContent;
1338
1339 /*** rewrite (drop context and servlet path from URLs) switch. */
1340 private boolean rewrite;
1341
1342 /*** the web configurator. */
1343 private WebConfigurator webConfigurator;
1344
1345 /*** base content path */
1346 private String baseContentPath;
1347
1348 /*** currently used view parameter name */
1349 private String viewToken;
1350
1351 /*** currently used action parameter name */
1352 private String actionToken;
1353
1354 /***
1355 * Initializes the configuraiton object.
1356 *
1357 * @param config DNA configuration
1358 * @param webConfigurator the configuration of the web subsystem.
1359 * @throws ConfigurationException if the configuration is invalid.
1360 */
1361 public Configuration(org.jcontainer.dna.Configuration config,
1362 WebConfigurator webConfigurator)
1363 throws ConfigurationException
1364 {
1365 this.webConfigurator = webConfigurator;
1366 configure(config);
1367 }
1368
1369 /***
1370 * Initializes the internal state from DNA configuration object.
1371 *
1372 * <p>This method may be used to reconfigure link tool at runtime.</p>
1373 *
1374 * @param config DNA configuration
1375 * @throws ConfigurationException if the configuration is invalid.
1376 */
1377 public void configure(org.jcontainer.dna.Configuration config)
1378 throws ConfigurationException
1379 {
1380 try
1381 {
1382 org.jcontainer.dna.Configuration[] keys =
1383 config.getChild("sticky").getChildren("key");
1384 for (int i = 0; i < keys.length; i++)
1385 {
1386 stickyParameterNames.add(keys[i].getValue());
1387 }
1388 keys = config.getChild("pathinfo").getChildren("key");
1389 for (int i = 0; i < keys.length; i++)
1390 {
1391 pathinfoParameterNames.add(keys[i].getValue());
1392 }
1393 baseContentPath =
1394 config.getChild("base_content_path").getValue(DEFAULT_BASE_CONTENT_PATH);
1395 }
1396
1397 catch (ConfigurationException e)
1398 {
1399 throw new ComponentInitializationError("failed to configure the component", e);
1400 }
1401
1402 queryStringSeparator = config.getChild("query_separator").
1403 getValue(DEFAULT_QUERY_SEPARATOR);
1404 externalContent = config.getChild("external_content").getValueAsBoolean(false);
1405 rewrite = config.getChild("rewrite").getValueAsBoolean(false);
1406
1407 viewToken = webConfigurator.getViewToken();
1408 actionToken = webConfigurator.getActionToken();
1409 }
1410 }
1411 }