1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.apache.struts.action;
22
23 import org.apache.commons.logging.Log;
24 import org.apache.commons.logging.LogFactory;
25 import org.apache.struts.Globals;
26 import org.apache.struts.config.ActionConfig;
27 import org.apache.struts.config.ExceptionConfig;
28 import org.apache.struts.config.ForwardConfig;
29 import org.apache.struts.config.ModuleConfig;
30 import org.apache.struts.upload.MultipartRequestWrapper;
31 import org.apache.struts.util.MessageResources;
32 import org.apache.struts.util.RequestUtils;
33
34 import javax.servlet.RequestDispatcher;
35 import javax.servlet.ServletContext;
36 import javax.servlet.ServletException;
37 import javax.servlet.http.HttpServletRequest;
38 import javax.servlet.http.HttpServletResponse;
39 import javax.servlet.http.HttpSession;
40
41 import java.io.IOException;
42
43 import java.util.HashMap;
44 import java.util.Iterator;
45 import java.util.Locale;
46
47
48
49
50
51
52
53
54
55
56
57 public class RequestProcessor {
58
59
60
61
62
63
64 public static final String INCLUDE_PATH_INFO =
65 "javax.servlet.include.path_info";
66
67
68
69
70
71
72 public static final String INCLUDE_SERVLET_PATH =
73 "javax.servlet.include.servlet_path";
74
75
76
77
78 protected static Log log = LogFactory.getLog(RequestProcessor.class);
79
80
81
82
83
84
85
86
87 protected HashMap actions = new HashMap();
88
89
90
91
92
93 protected ModuleConfig moduleConfig = null;
94
95
96
97
98 protected ActionServlet servlet = null;
99
100
101
102
103
104
105 public void destroy() {
106 synchronized (this.actions) {
107 Iterator actions = this.actions.values().iterator();
108
109 while (actions.hasNext()) {
110 Action action = (Action) actions.next();
111
112 action.setServlet(null);
113 }
114
115 this.actions.clear();
116 }
117
118 this.servlet = null;
119 }
120
121
122
123
124
125
126
127
128 public void init(ActionServlet servlet, ModuleConfig moduleConfig)
129 throws ServletException {
130 synchronized (actions) {
131 actions.clear();
132 }
133
134 this.servlet = servlet;
135 this.moduleConfig = moduleConfig;
136 }
137
138
139
140
141
142
143
144
145
146
147
148 public void process(HttpServletRequest request, HttpServletResponse response)
149 throws IOException, ServletException {
150
151 request = processMultipart(request);
152
153
154 String path = processPath(request, response);
155
156 if (path == null) {
157 return;
158 }
159
160 if (log.isDebugEnabled()) {
161 log.debug("Processing a '" + request.getMethod() + "' for path '"
162 + path + "'");
163 }
164
165
166 processLocale(request, response);
167
168
169 processContent(request, response);
170 processNoCache(request, response);
171
172
173 if (!processPreprocess(request, response)) {
174 return;
175 }
176
177 this.processCachedMessages(request, response);
178
179
180 ActionMapping mapping = processMapping(request, response, path);
181
182 if (mapping == null) {
183 return;
184 }
185
186
187 if (!processRoles(request, response, mapping)) {
188 return;
189 }
190
191
192 ActionForm form = processActionForm(request, response, mapping);
193
194 processPopulate(request, response, form, mapping);
195
196
197 try {
198 if (!processValidate(request, response, form, mapping)) {
199 return;
200 }
201 } catch (InvalidCancelException e) {
202 ActionForward forward = processException(request, response, e, form, mapping);
203 processForwardConfig(request, response, forward);
204 return;
205 } catch (IOException e) {
206 throw e;
207 } catch (ServletException e) {
208 throw e;
209 }
210
211
212 if (!processForward(request, response, mapping)) {
213 return;
214 }
215
216 if (!processInclude(request, response, mapping)) {
217 return;
218 }
219
220
221 Action action = processActionCreate(request, response, mapping);
222
223 if (action == null) {
224 return;
225 }
226
227
228 ActionForward forward =
229 processActionPerform(request, response, action, form, mapping);
230
231
232 processForwardConfig(request, response, forward);
233 }
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248 protected Action processActionCreate(HttpServletRequest request,
249 HttpServletResponse response, ActionMapping mapping)
250 throws IOException {
251
252 String className = mapping.getType();
253
254 if (log.isDebugEnabled()) {
255 log.debug(" Looking for Action instance for class " + className);
256 }
257
258
259
260
261 Action instance;
262
263 synchronized (actions) {
264
265 instance = (Action) actions.get(className);
266
267 if (instance != null) {
268 if (log.isTraceEnabled()) {
269 log.trace(" Returning existing Action instance");
270 }
271
272 return (instance);
273 }
274
275
276 if (log.isTraceEnabled()) {
277 log.trace(" Creating new Action instance");
278 }
279
280 try {
281 instance = (Action) RequestUtils.applicationInstance(className);
282
283
284
285 } catch (Exception e) {
286 log.error(getInternal().getMessage("actionCreate",
287 mapping.getPath()), e);
288
289 response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
290 getInternal().getMessage("actionCreate", mapping.getPath()));
291
292 return (null);
293 }
294
295 actions.put(className, instance);
296
297 if (instance.getServlet() == null) {
298 instance.setServlet(this.servlet);
299 }
300 }
301
302 return (instance);
303 }
304
305
306
307
308
309
310
311
312
313
314
315
316 protected ActionForm processActionForm(HttpServletRequest request,
317 HttpServletResponse response, ActionMapping mapping) {
318
319 ActionForm instance =
320 RequestUtils.createActionForm(request, mapping, moduleConfig,
321 servlet);
322
323 if (instance == null) {
324 return (null);
325 }
326
327
328 if (log.isDebugEnabled()) {
329 log.debug(" Storing ActionForm bean instance in scope '"
330 + mapping.getScope() + "' under attribute key '"
331 + mapping.getAttribute() + "'");
332 }
333
334 if ("request".equals(mapping.getScope())) {
335 request.setAttribute(mapping.getAttribute(), instance);
336 } else {
337 HttpSession session = request.getSession();
338
339 session.setAttribute(mapping.getAttribute(), instance);
340 }
341
342 return (instance);
343 }
344
345
346
347
348
349
350
351
352
353
354
355
356 protected void processForwardConfig(HttpServletRequest request,
357 HttpServletResponse response, ForwardConfig forward)
358 throws IOException, ServletException {
359 if (forward == null) {
360 return;
361 }
362
363 if (log.isDebugEnabled()) {
364 log.debug("processForwardConfig(" + forward + ")");
365 }
366
367 String forwardPath = forward.getPath();
368 String uri;
369
370
371 String actionIdPath = RequestUtils.actionIdURL(forward, request, servlet);
372 if (actionIdPath != null) {
373 forwardPath = actionIdPath;
374 ForwardConfig actionIdForward = new ForwardConfig(forward);
375 actionIdForward.setPath(actionIdPath);
376 forward = actionIdForward;
377 }
378
379
380
381 if (forwardPath.startsWith("/")) {
382
383 uri = RequestUtils.forwardURL(request, forward, null);
384 } else {
385 uri = forwardPath;
386 }
387
388 if (forward.getRedirect()) {
389
390 if (uri.startsWith("/")) {
391 uri = request.getContextPath() + uri;
392 }
393
394 response.sendRedirect(response.encodeRedirectURL(uri));
395 } else {
396 doForward(uri, request, response);
397 }
398 }
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420 protected ActionForward processActionPerform(HttpServletRequest request,
421 HttpServletResponse response, Action action, ActionForm form,
422 ActionMapping mapping)
423 throws IOException, ServletException {
424 try {
425 return (action.execute(mapping, form, request, response));
426 } catch (Exception e) {
427 return (processException(request, response, e, form, mapping));
428 }
429 }
430
431
432
433
434
435
436
437
438
439
440
441
442 protected void processCachedMessages(HttpServletRequest request,
443 HttpServletResponse response) {
444 HttpSession session = request.getSession(false);
445
446 if (session == null) {
447 return;
448 }
449
450
451 ActionMessages messages =
452 (ActionMessages) session.getAttribute(Globals.MESSAGE_KEY);
453
454 if (messages != null) {
455 if (messages.isAccessed()) {
456 session.removeAttribute(Globals.MESSAGE_KEY);
457 }
458 }
459
460
461 messages = (ActionMessages) session.getAttribute(Globals.ERROR_KEY);
462
463 if (messages != null) {
464 if (messages.isAccessed()) {
465 session.removeAttribute(Globals.ERROR_KEY);
466 }
467 }
468 }
469
470
471
472
473
474
475
476
477
478
479 protected void processContent(HttpServletRequest request,
480 HttpServletResponse response) {
481 String contentType =
482 moduleConfig.getControllerConfig().getContentType();
483
484 if (contentType != null) {
485 response.setContentType(contentType);
486 }
487 }
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504 protected ActionForward processException(HttpServletRequest request,
505 HttpServletResponse response, Exception exception, ActionForm form,
506 ActionMapping mapping)
507 throws IOException, ServletException {
508
509 ExceptionConfig config = mapping.findException(exception.getClass());
510
511 if (config == null) {
512 log.warn(getInternal().getMessage("unhandledException",
513 exception.getClass()));
514
515 if (exception instanceof IOException) {
516 throw (IOException) exception;
517 } else if (exception instanceof ServletException) {
518 throw (ServletException) exception;
519 } else {
520 throw new ServletException(exception);
521 }
522 }
523
524
525 try {
526 ExceptionHandler handler =
527 (ExceptionHandler) RequestUtils.applicationInstance(config
528 .getHandler());
529
530 return (handler.execute(exception, config, mapping, form, request,
531 response));
532 } catch (Exception e) {
533 throw new ServletException(e);
534 }
535 }
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550 protected boolean processForward(HttpServletRequest request,
551 HttpServletResponse response, ActionMapping mapping)
552 throws IOException, ServletException {
553
554 String forward = mapping.getForward();
555
556 if (forward == null) {
557 return (true);
558 }
559
560
561 String actionIdPath = RequestUtils.actionIdURL(forward, this.moduleConfig, this.servlet);
562 if (actionIdPath != null) {
563 forward = actionIdPath;
564 }
565
566 internalModuleRelativeForward(forward, request, response);
567
568 return (false);
569 }
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584 protected boolean processInclude(HttpServletRequest request,
585 HttpServletResponse response, ActionMapping mapping)
586 throws IOException, ServletException {
587
588 String include = mapping.getInclude();
589
590 if (include == null) {
591 return (true);
592 }
593
594
595 String actionIdPath = RequestUtils.actionIdURL(include, this.moduleConfig, this.servlet);
596 if (actionIdPath != null) {
597 include = actionIdPath;
598 }
599
600 internalModuleRelativeInclude(include, request, response);
601
602 return (false);
603 }
604
605
606
607
608
609
610
611
612
613
614 protected void processLocale(HttpServletRequest request,
615 HttpServletResponse response) {
616
617 if (!moduleConfig.getControllerConfig().getLocale()) {
618 return;
619 }
620
621
622 HttpSession session = request.getSession();
623
624 if (session.getAttribute(Globals.LOCALE_KEY) != null) {
625 return;
626 }
627
628
629 Locale locale = request.getLocale();
630
631 if (locale != null) {
632 if (log.isDebugEnabled()) {
633 log.debug(" Setting user locale '" + locale + "'");
634 }
635
636 session.setAttribute(Globals.LOCALE_KEY, locale);
637 }
638 }
639
640
641
642
643
644
645
646
647
648
649
650
651
652 protected ActionMapping processMapping(HttpServletRequest request,
653 HttpServletResponse response, String path)
654 throws IOException {
655
656 ActionMapping mapping =
657 (ActionMapping) moduleConfig.findActionConfig(path);
658
659
660 if (mapping != null) {
661 request.setAttribute(Globals.MAPPING_KEY, mapping);
662
663 return (mapping);
664 }
665
666
667 ActionConfig[] configs = moduleConfig.findActionConfigs();
668
669 for (int i = 0; i < configs.length; i++) {
670 if (configs[i].getUnknown()) {
671 mapping = (ActionMapping) configs[i];
672 request.setAttribute(Globals.MAPPING_KEY, mapping);
673
674 return (mapping);
675 }
676 }
677
678
679 String msg = getInternal().getMessage("processInvalid");
680
681 log.error(msg + " " + path);
682 response.sendError(HttpServletResponse.SC_NOT_FOUND, msg);
683
684 return null;
685 }
686
687
688
689
690
691
692
693
694
695 protected HttpServletRequest processMultipart(HttpServletRequest request) {
696 if (!"POST".equalsIgnoreCase(request.getMethod())) {
697 return (request);
698 }
699
700 String contentType = request.getContentType();
701
702 if ((contentType != null)
703 && contentType.startsWith("multipart/form-data")) {
704 return (new MultipartRequestWrapper(request));
705 } else {
706 return (request);
707 }
708 }
709
710
711
712
713
714
715
716
717
718
719 protected void processNoCache(HttpServletRequest request,
720 HttpServletResponse response) {
721 if (moduleConfig.getControllerConfig().getNocache()) {
722 response.setHeader("Pragma", "No-cache");
723 response.setHeader("Cache-Control", "no-cache,no-store,max-age=0");
724 response.setDateHeader("Expires", 1);
725 }
726 }
727
728
729
730
731
732
733
734
735
736
737
738
739 protected String processPath(HttpServletRequest request,
740 HttpServletResponse response)
741 throws IOException {
742 String path;
743
744
745 if (request.getAttribute(Globals.ORIGINAL_URI_KEY) == null) {
746 request.setAttribute(Globals.ORIGINAL_URI_KEY, request.getServletPath());
747 }
748
749
750 path = (String) request.getAttribute(INCLUDE_PATH_INFO);
751
752 if (path == null) {
753 path = request.getPathInfo();
754 }
755
756 if ((path != null) && (path.length() > 0)) {
757 return (path);
758 }
759
760
761 path = (String) request.getAttribute(INCLUDE_SERVLET_PATH);
762
763 if (path == null) {
764 path = request.getServletPath();
765 }
766
767 String prefix = moduleConfig.getPrefix();
768
769 if (!path.startsWith(prefix)) {
770 String msg = getInternal().getMessage("processPath");
771
772 log.error(msg + " " + request.getRequestURI());
773 response.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
774
775 return null;
776 }
777
778 path = path.substring(prefix.length());
779
780 int slash = path.lastIndexOf("/");
781 int period = path.lastIndexOf(".");
782
783 if ((period >= 0) && (period > slash)) {
784 path = path.substring(0, period);
785 }
786
787 return (path);
788 }
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803 protected void processPopulate(HttpServletRequest request,
804 HttpServletResponse response, ActionForm form, ActionMapping mapping)
805 throws ServletException {
806 if (form == null) {
807 return;
808 }
809
810
811 if (log.isDebugEnabled()) {
812 log.debug(" Populating bean properties from this request");
813 }
814
815 form.setServlet(this.servlet);
816 form.reset(mapping, request);
817
818 if (mapping.getMultipartClass() != null) {
819 request.setAttribute(Globals.MULTIPART_KEY,
820 mapping.getMultipartClass());
821 }
822
823 RequestUtils.populate(form, mapping.getPrefix(), mapping.getSuffix(),
824 request);
825
826
827 if ((request.getParameter(Globals.CANCEL_PROPERTY) != null)
828 || (request.getParameter(Globals.CANCEL_PROPERTY_X) != null)) {
829 request.setAttribute(Globals.CANCEL_KEY, Boolean.TRUE);
830 }
831 }
832
833
834
835
836
837
838
839
840
841
842
843
844 protected boolean processPreprocess(HttpServletRequest request,
845 HttpServletResponse response) {
846 return (true);
847 }
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863 protected boolean processRoles(HttpServletRequest request,
864 HttpServletResponse response, ActionMapping mapping)
865 throws IOException, ServletException {
866
867 String[] roles = mapping.getRoleNames();
868
869 if ((roles == null) || (roles.length < 1)) {
870 return (true);
871 }
872
873
874 for (int i = 0; i < roles.length; i++) {
875 if (request.isUserInRole(roles[i])) {
876 if (log.isDebugEnabled()) {
877 log.debug(" User '" + request.getRemoteUser()
878 + "' has role '" + roles[i] + "', granting access");
879 }
880
881 return (true);
882 }
883 }
884
885
886 if (log.isDebugEnabled()) {
887 log.debug(" User '" + request.getRemoteUser()
888 + "' does not have any required role, denying access");
889 }
890
891 response.sendError(HttpServletResponse.SC_FORBIDDEN,
892 getInternal().getMessage("notAuthorized", mapping.getPath()));
893
894 return (false);
895 }
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917 protected boolean processValidate(HttpServletRequest request,
918 HttpServletResponse response, ActionForm form, ActionMapping mapping)
919 throws IOException, ServletException, InvalidCancelException {
920 if (form == null) {
921 return (true);
922 }
923
924
925 if (!mapping.getValidate()) {
926 return (true);
927 }
928
929
930
931
932
933 if (request.getAttribute(Globals.CANCEL_KEY) != null) {
934 if (mapping.getCancellable()) {
935 if (log.isDebugEnabled()) {
936 log.debug(" Cancelled transaction, skipping validation");
937 }
938 return (true);
939 } else {
940 request.removeAttribute(Globals.CANCEL_KEY);
941 throw new InvalidCancelException();
942 }
943 }
944
945
946 if (log.isDebugEnabled()) {
947 log.debug(" Validating input form properties");
948 }
949
950 ActionMessages errors = form.validate(mapping, request);
951
952 if ((errors == null) || errors.isEmpty()) {
953 if (log.isTraceEnabled()) {
954 log.trace(" No errors detected, accepting input");
955 }
956
957 return (true);
958 }
959
960
961 if (form.getMultipartRequestHandler() != null) {
962 if (log.isTraceEnabled()) {
963 log.trace(" Rolling back multipart request");
964 }
965
966 form.getMultipartRequestHandler().rollback();
967 }
968
969
970 String input = mapping.getInput();
971
972 if (input == null) {
973 if (log.isTraceEnabled()) {
974 log.trace(" Validation failed but no input form available");
975 }
976
977 response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
978 getInternal().getMessage("noInput", mapping.getPath()));
979
980 return (false);
981 }
982
983
984 if (log.isDebugEnabled()) {
985 log.debug(" Validation failed, returning to '" + input + "'");
986 }
987
988 request.setAttribute(Globals.ERROR_KEY, errors);
989
990 if (moduleConfig.getControllerConfig().getInputForward()) {
991 ForwardConfig forward = mapping.findForward(input);
992
993 processForwardConfig(request, response, forward);
994 } else {
995 internalModuleRelativeForward(input, request, response);
996 }
997
998 return (false);
999 }
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015 protected void internalModuleRelativeForward(String uri,
1016 HttpServletRequest request, HttpServletResponse response)
1017 throws IOException, ServletException {
1018
1019 uri = moduleConfig.getPrefix() + uri;
1020
1021
1022
1023 if (log.isDebugEnabled()) {
1024 log.debug(" Delegating via forward to '" + uri + "'");
1025 }
1026
1027 doForward(uri, request, response);
1028 }
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044 protected void internalModuleRelativeInclude(String uri,
1045 HttpServletRequest request, HttpServletResponse response)
1046 throws IOException, ServletException {
1047
1048 uri = moduleConfig.getPrefix() + uri;
1049
1050
1051
1052 if (log.isDebugEnabled()) {
1053 log.debug(" Delegating via include to '" + uri + "'");
1054 }
1055
1056 doInclude(uri, request, response);
1057 }
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071 protected void doForward(String uri, HttpServletRequest request,
1072 HttpServletResponse response)
1073 throws IOException, ServletException {
1074 RequestDispatcher rd = getServletContext().getRequestDispatcher(uri);
1075
1076 if (rd == null) {
1077 response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
1078 getInternal().getMessage("requestDispatcher", uri));
1079
1080 return;
1081 }
1082
1083 rd.forward(request, response);
1084 }
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098 protected void doInclude(String uri, HttpServletRequest request,
1099 HttpServletResponse response)
1100 throws IOException, ServletException {
1101 RequestDispatcher rd = getServletContext().getRequestDispatcher(uri);
1102
1103 if (rd == null) {
1104 response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
1105 getInternal().getMessage("requestDispatcher", uri));
1106
1107 return;
1108 }
1109
1110 rd.include(request, response);
1111 }
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122 protected MessageResources getInternal() {
1123 return (servlet.getInternal());
1124 }
1125
1126
1127
1128
1129
1130
1131
1132 protected ServletContext getServletContext() {
1133 return (servlet.getServletContext());
1134 }
1135 }