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 java.io.IOException;
24 import java.io.InputStream;
25 import java.math.BigDecimal;
26 import java.math.BigInteger;
27 import java.net.URL;
28 import java.util.ArrayList;
29 import java.util.Arrays;
30 import java.util.Enumeration;
31 import java.util.List;
32 import java.util.MissingResourceException;
33
34 import jakarta.servlet.ServletContext;
35 import jakarta.servlet.ServletException;
36 import jakarta.servlet.UnavailableException;
37 import jakarta.servlet.http.HttpServlet;
38 import jakarta.servlet.http.HttpServletRequest;
39 import jakarta.servlet.http.HttpServletResponse;
40
41 import org.apache.commons.beanutils.BeanUtils;
42 import org.apache.commons.beanutils.ConvertUtils;
43 import org.apache.commons.beanutils.PropertyUtils;
44 import org.apache.commons.beanutils.SuppressPropertiesBeanIntrospector;
45 import org.apache.commons.beanutils.converters.BigDecimalConverter;
46 import org.apache.commons.beanutils.converters.BigIntegerConverter;
47 import org.apache.commons.beanutils.converters.BooleanConverter;
48 import org.apache.commons.beanutils.converters.ByteConverter;
49 import org.apache.commons.beanutils.converters.CharacterConverter;
50 import org.apache.commons.beanutils.converters.DoubleConverter;
51 import org.apache.commons.beanutils.converters.FloatConverter;
52 import org.apache.commons.beanutils.converters.IntegerConverter;
53 import org.apache.commons.beanutils.converters.LongConverter;
54 import org.apache.commons.beanutils.converters.ShortConverter;
55 import org.apache.commons.chain.CatalogFactory;
56 import org.apache.commons.chain.config.ConfigParser;
57 import org.apache.commons.digester.Digester;
58 import org.apache.commons.digester.RuleSet;
59 import org.apache.commons.logging.LogFactory;
60 import org.apache.struts.Globals;
61 import org.apache.struts.chain.ComposableRequestProcessor;
62 import org.apache.struts.config.ActionConfig;
63 import org.apache.struts.config.BaseConfig;
64 import org.apache.struts.config.ConfigRuleSet;
65 import org.apache.struts.config.ExceptionConfig;
66 import org.apache.struts.config.FormBeanConfig;
67 import org.apache.struts.config.FormPropertyConfig;
68 import org.apache.struts.config.ForwardConfig;
69 import org.apache.struts.config.MessageResourcesConfig;
70 import org.apache.struts.config.ModuleConfig;
71 import org.apache.struts.config.ModuleConfigFactory;
72 import org.apache.struts.config.ModuleConfigPostProcessor;
73 import org.apache.struts.config.PlugInConfig;
74 import org.apache.struts.util.MessageResources;
75 import org.apache.struts.util.MessageResourcesFactory;
76 import org.apache.struts.util.ModuleUtils;
77 import org.apache.struts.util.RequestUtils;
78 import org.slf4j.Logger;
79 import org.slf4j.LoggerFactory;
80 import org.xml.sax.SAXException;
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205 public class ActionServlet extends HttpServlet {
206 private static final long serialVersionUID = 7124895651996600297L;
207
208
209
210
211
212
213
214
215
216
217
218
219 private final static SuppressPropertiesBeanIntrospector SUPPRESS_CLASSES =
220 new SuppressPropertiesBeanIntrospector(
221 Arrays.asList("class", "multipartRequestHandler", "resultValueMap"));
222
223
224
225
226
227
228 private transient final Logger log =
229 LoggerFactory.getLogger(ActionServlet.class);
230
231
232
233
234
235
236
237 protected String config = "/WEB-INF/struts-config.xml";
238
239
240
241
242
243
244 protected String chainConfig = "org/apache/struts/chain/chain-config.xml";
245
246
247
248
249
250
251
252 protected Digester configDigester = null;
253
254
255
256
257
258
259
260 protected boolean convertNull = false;
261
262
263
264
265 protected MessageResources internal = null;
266
267
268
269
270
271
272 protected String internalName = "org.apache.struts.action.ActionResources";
273
274
275
276
277
278
279 protected String[] registrations =
280 {
281 "-//Apache Software Foundation//DTD Struts Configuration 1.0//EN",
282 "/org/apache/struts/resources/struts-config_1_0.dtd",
283 "-//Apache Software Foundation//DTD Struts Configuration 1.1//EN",
284 "/org/apache/struts/resources/struts-config_1_1.dtd",
285 "-//Apache Software Foundation//DTD Struts Configuration 1.2//EN",
286 "/org/apache/struts/resources/struts-config_1_2.dtd",
287 "-//Apache Software Foundation//DTD Struts Configuration 1.3//EN",
288 "/org/apache/struts/resources/struts-config_1_3.dtd",
289 "-//Apache Software Foundation//DTD Struts Configuration 1.4//EN",
290 "/org/apache/struts/resources/struts-config_1_4.dtd",
291 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN",
292 "/org/apache/struts/resources/web-app_2_3.dtd"
293 };
294
295
296
297
298
299 protected String servletMapping = null;
300
301
302
303
304
305 protected String servletName = null;
306
307
308
309
310
311
312
313 public void destroy() {
314 log.atDebug().log(() -> internal.getMessage("finalizing"));
315
316 destroyModules();
317 destroyInternal();
318 getServletContext().removeAttribute(Globals.ACTION_SERVLET_KEY);
319
320 CatalogFactory.clear();
321 PropertyUtils.clearDescriptors();
322
323
324 ClassLoader classLoader =
325 Thread.currentThread().getContextClassLoader();
326
327 if (classLoader == null) {
328 classLoader = ActionServlet.class.getClassLoader();
329 }
330
331 try {
332 LogFactory.release(classLoader);
333 } catch (Throwable t) {
334 ;
335
336
337
338
339
340
341
342
343
344
345
346 }
347 }
348
349
350
351
352
353
354
355
356 public void init() throws ServletException {
357 final String configPrefix = "config/";
358 final int configPrefixLength = configPrefix.length() - 1;
359
360
361
362
363 try {
364 initInternal();
365 initOther();
366 initServlet();
367 initChain();
368
369 getServletContext().setAttribute(Globals.ACTION_SERVLET_KEY, this);
370 initModuleConfigFactory();
371
372
373 ModuleConfig moduleConfig = initModuleConfig("", config);
374
375 initModuleMessageResources(moduleConfig);
376 initModulePlugIns(moduleConfig);
377 initModuleFormBeans(moduleConfig);
378 initModuleForwards(moduleConfig);
379 initModuleExceptionConfigs(moduleConfig);
380 initModuleActions(moduleConfig);
381 postProcessConfig(moduleConfig);
382 moduleConfig.freeze();
383
384 Enumeration<String> names = getServletConfig().getInitParameterNames();
385
386 while (names.hasMoreElements()) {
387 String name = names.nextElement();
388
389 if (!name.startsWith(configPrefix)) {
390 continue;
391 }
392
393 String prefix = name.substring(configPrefixLength);
394
395 moduleConfig =
396 initModuleConfig(prefix,
397 getServletConfig().getInitParameter(name));
398 initModuleMessageResources(moduleConfig);
399 initModulePlugIns(moduleConfig);
400 initModuleFormBeans(moduleConfig);
401 initModuleForwards(moduleConfig);
402 initModuleExceptionConfigs(moduleConfig);
403 initModuleActions(moduleConfig);
404 postProcessConfig(moduleConfig);
405 moduleConfig.freeze();
406 }
407
408 this.initModulePrefixes(this.getServletContext());
409
410 this.destroyConfigDigester();
411 } catch (UnavailableException ex) {
412 throw ex;
413 } catch (Throwable t) {
414
415
416
417 log.error("Unable to initialize Struts ActionServlet due to an "
418 + "unexpected exception or error thrown, so marking the "
419 + "servlet as unavailable. Most likely, this is due to an "
420 + "incorrect or missing library dependency.", t);
421 UnavailableException t2 = new UnavailableException(t.getMessage());
422 t2.initCause(t);
423 throw t2;
424 }
425 }
426
427
428
429
430
431
432
433
434
435 protected void initModulePrefixes(ServletContext context) {
436 ArrayList<String> prefixList = new ArrayList<>();
437
438 Enumeration<String> names = context.getAttributeNames();
439
440 while (names.hasMoreElements()) {
441 String name = names.nextElement();
442
443 if (!name.startsWith(Globals.MODULE_KEY)) {
444 continue;
445 }
446
447 String prefix = name.substring(Globals.MODULE_KEY.length());
448
449 if (prefix.length() > 0) {
450 prefixList.add(prefix);
451 }
452 }
453
454 String[] prefixes = prefixList.toArray(new String[0]);
455
456 context.setAttribute(Globals.MODULE_PREFIXES_KEY, prefixes);
457 }
458
459
460
461
462
463
464
465
466
467 public void doGet(HttpServletRequest request, HttpServletResponse response)
468 throws IOException, ServletException {
469 process(request, response);
470 }
471
472
473
474
475
476
477
478
479
480 public void doPost(HttpServletRequest request, HttpServletResponse response)
481 throws IOException, ServletException {
482 process(request, response);
483 }
484
485
486
487
488
489
490
491
492
493
494 public void addServletMapping(String servletName, String urlPattern) {
495 if (servletName == null) {
496 return;
497 }
498
499 if (servletName.equals(this.servletName)) {
500 log.debug("Process servletName={}, urlPattern={}",
501 servletName, urlPattern);
502
503 this.servletMapping = urlPattern;
504 }
505 }
506
507
508
509
510
511
512
513
514
515 public MessageResources getInternal() {
516 return (this.internal);
517 }
518
519
520
521
522
523
524
525
526
527 protected void destroyModules() {
528 ArrayList<String> values = new ArrayList<>();
529 Enumeration<String> names = getServletContext().getAttributeNames();
530
531 while (names.hasMoreElements()) {
532 values.add(names.nextElement());
533 }
534
535 for (String name : values) {
536 Object value = getServletContext().getAttribute(name);
537
538 if (!(value instanceof ModuleConfig)) {
539 continue;
540 }
541
542 ModuleConfig config = (ModuleConfig) value;
543
544 if (this.getProcessorForModule(config) != null) {
545 this.getProcessorForModule(config).destroy();
546 }
547
548 getServletContext().removeAttribute(name);
549
550 PlugIn[] plugIns =
551 (PlugIn[]) getServletContext().getAttribute(Globals.PLUG_INS_KEY
552 + config.getPrefix());
553
554 if (plugIns != null) {
555 for (int i = 0; i < plugIns.length; i++) {
556 int j = plugIns.length - (i + 1);
557
558 plugIns[j].destroy();
559 }
560
561 getServletContext().removeAttribute(Globals.PLUG_INS_KEY
562 + config.getPrefix());
563 }
564 }
565 }
566
567
568
569
570
571
572
573 protected void destroyConfigDigester() {
574 configDigester = null;
575 }
576
577
578
579
580 protected void destroyInternal() {
581 internal = null;
582 }
583
584
585
586
587
588
589
590
591
592
593 protected ModuleConfig getModuleConfig(HttpServletRequest request) {
594 ModuleConfig config =
595 (ModuleConfig) request.getAttribute(Globals.MODULE_KEY);
596
597 if (config == null) {
598 config =
599 (ModuleConfig) getServletContext().getAttribute(Globals.MODULE_KEY);
600 }
601
602 return (config);
603 }
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619 protected synchronized RequestProcessor getRequestProcessor(
620 ModuleConfig config) throws ServletException {
621 RequestProcessor processor = this.getProcessorForModule(config);
622
623 if (processor == null) {
624 try {
625 processor =
626 (RequestProcessor) RequestUtils.applicationInstance(config.getControllerConfig()
627 .getProcessorClass());
628 } catch (Exception e) {
629 UnavailableException e2 = new UnavailableException(
630 "Cannot initialize RequestProcessor of class "
631 + config.getControllerConfig().getProcessorClass());
632 e2.initCause(e);
633 throw e2;
634 }
635
636
637
638
639 if (!(processor instanceof ComposableRequestProcessor)) {
640 log.warn("Use of the classic RequestProcessor is not recommended. " +
641 "Please upgrade to the ComposableRequestProcessor to " +
642 "receive the advantage of modern enhancements and fixes.");
643 }
644
645 processor.init(this, config);
646
647 String key = Globals.REQUEST_PROCESSOR_KEY + config.getPrefix();
648
649 getServletContext().setAttribute(key, processor);
650 }
651
652 return (processor);
653 }
654
655
656
657
658
659
660
661
662
663 private RequestProcessor getProcessorForModule(ModuleConfig config) {
664 String key = Globals.REQUEST_PROCESSOR_KEY + config.getPrefix();
665
666 return (RequestProcessor) getServletContext().getAttribute(key);
667 }
668
669
670
671
672
673
674 protected void initModuleConfigFactory() {
675 String configFactory =
676 getServletConfig().getInitParameter("configFactory");
677
678 if (configFactory != null) {
679 ModuleConfigFactory.setFactoryClass(configFactory);
680 }
681 }
682
683
684
685
686
687
688
689
690
691
692
693
694 protected ModuleConfig initModuleConfig(String prefix, String paths)
695 throws ServletException {
696 log.debug("Initializing module path '{}' configuration from '{}'",
697 prefix, paths);
698
699
700 ModuleConfigFactory factoryObject = ModuleConfigFactory.createFactory();
701 ModuleConfig config = factoryObject.createModuleConfig(prefix);
702
703
704 Digester digester = initConfigDigester();
705
706 List<URL> urls = splitAndResolvePaths(paths);
707
708 for (URL url : urls) {
709 digester.push(config);
710 this.parseModuleConfigFile(digester, url);
711 }
712
713 getServletContext().setAttribute(Globals.MODULE_KEY
714 + config.getPrefix(), config);
715
716 return config;
717 }
718
719
720
721
722
723
724
725
726
727
728
729 @Deprecated
730 protected void parseModuleConfigFile(Digester digester, String path)
731 throws UnavailableException {
732 try {
733 List<URL> paths = splitAndResolvePaths(path);
734
735 if (paths.size() > 0) {
736
737 URL url = paths.get(0);
738
739 parseModuleConfigFile(digester, url);
740 } else {
741 throw new UnavailableException("Cannot locate path " + path);
742 }
743 } catch (UnavailableException ex) {
744 throw ex;
745 } catch (ServletException ex) {
746 handleConfigException(path, ex);
747 }
748 }
749
750
751
752
753
754
755
756
757
758 protected void parseModuleConfigFile(Digester digester, URL url)
759 throws UnavailableException {
760
761 try {
762 digester.parse(url);
763 } catch (IOException e) {
764 handleConfigException(url.toString(), e);
765 } catch (SAXException e) {
766 handleConfigException(url.toString(), e);
767 }
768 }
769
770
771
772
773
774
775
776
777
778 private void handleConfigException(String path, Exception e)
779 throws UnavailableException {
780 String msg = internal.getMessage("configParse", path);
781
782 log.error(msg, e);
783 UnavailableException e2 = new UnavailableException(msg);
784 e2.initCause(e);
785 throw e2;
786 }
787
788
789
790
791
792
793
794
795
796 private void handleCreationException(String className, Exception e)
797 throws ServletException {
798 String errorMessage =
799 internal.getMessage("configExtends.creation", className);
800
801 log.error(errorMessage, e);
802 UnavailableException e2 = new UnavailableException(errorMessage);
803 e2.initCause(e);
804 throw e2;
805 }
806
807
808
809
810
811
812
813
814
815
816 private void handleGeneralExtensionException(String configType,
817 String configName, Exception e)
818 throws ServletException {
819 String errorMessage =
820 internal.getMessage("configExtends", configType, configName);
821
822 log.error(errorMessage, e);
823 UnavailableException e2 = new UnavailableException(errorMessage);
824 e2.initCause(e);
825 throw e2;
826 }
827
828
829
830
831
832
833
834
835
836
837
838 private void handleValueRequiredException(String field, String configType,
839 String configName) throws ServletException {
840 String errorMessage =
841 internal.getMessage("configFieldRequired", field, configType,
842 configName);
843
844 log.error(errorMessage);
845 throw new UnavailableException(errorMessage);
846 }
847
848
849
850
851
852
853
854
855 protected void initModulePlugIns(ModuleConfig config)
856 throws ServletException {
857 log.debug("Initializing module path '{}' plug ins",
858 config.getPrefix());
859
860 PlugInConfig[] plugInConfigs = config.findPlugInConfigs();
861 PlugIn[] plugIns = new PlugIn[plugInConfigs.length];
862
863 getServletContext().setAttribute(Globals.PLUG_INS_KEY
864 + config.getPrefix(), plugIns);
865
866 for (int i = 0; i < plugIns.length; i++) {
867 try {
868 plugIns[i] =
869 (PlugIn) RequestUtils.applicationInstance(plugInConfigs[i]
870 .getClassName());
871 BeanUtils.populate(plugIns[i], plugInConfigs[i].getProperties());
872
873
874
875
876 try {
877 PropertyUtils.setProperty(plugIns[i],
878 "currentPlugInConfigObject", plugInConfigs[i]);
879 } catch (Exception e) {
880 ;
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895 }
896
897 plugIns[i].init(this, config);
898 } catch (ServletException e) {
899 throw e;
900 } catch (Exception e) {
901 String errMsg =
902 internal.getMessage("plugIn.init",
903 plugInConfigs[i].getClassName());
904
905 log(errMsg, e);
906 UnavailableException e2 = new UnavailableException(errMsg);
907 e2.initCause(e);
908 throw e2;
909 }
910 }
911 }
912
913
914
915
916
917
918
919
920 protected void initModuleFormBeans(ModuleConfig config)
921 throws ServletException {
922 log.debug("Initializing module path '{}' form beans",
923 config.getPrefix());
924
925
926 FormBeanConfig[] formBeans = config.findFormBeanConfigs();
927
928 for (int i = 0; i < formBeans.length; i++) {
929 FormBeanConfig beanConfig = formBeans[i];
930
931 postProcessConfig(beanConfig, config, true);
932 processFormBeanExtension(beanConfig, config);
933 postProcessConfig(beanConfig, config, false);
934 }
935
936 for (int i = 0; i < formBeans.length; i++) {
937 FormBeanConfig formBean = formBeans[i];
938
939
940 if (formBean.getType() == null) {
941 handleValueRequiredException("type", formBean.getName(),
942 "form bean");
943 }
944
945
946 FormPropertyConfig[] fpcs = formBean.findFormPropertyConfigs();
947
948 for (int j = 0; j < fpcs.length; j++) {
949 FormPropertyConfig property = fpcs[j];
950
951 if (property.getType() == null) {
952 handleValueRequiredException("type", property.getName(),
953 "form property");
954 }
955 }
956
957
958
959 if (formBean.getDynamic()) {
960 formBean.getDynaActionFormClass();
961 }
962 }
963 }
964
965
966
967
968
969
970
971
972 protected void processFormBeanExtension(FormBeanConfig beanConfig,
973 ModuleConfig moduleConfig)
974 throws ServletException {
975 try {
976 if (!beanConfig.isExtensionProcessed()) {
977 log.debug("Processing extensions for '{}'",
978 beanConfig.getName());
979
980 beanConfig =
981 processFormBeanConfigClass(beanConfig, moduleConfig);
982
983 beanConfig.processExtends(moduleConfig);
984 }
985 } catch (ServletException e) {
986 throw e;
987 } catch (Exception e) {
988 handleGeneralExtensionException("FormBeanConfig",
989 beanConfig.getName(), e);
990 }
991 }
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005 protected FormBeanConfig processFormBeanConfigClass(
1006 FormBeanConfig beanConfig, ModuleConfig moduleConfig)
1007 throws ServletException {
1008 String ancestor = beanConfig.getExtends();
1009
1010 if (ancestor == null) {
1011
1012 return beanConfig;
1013 }
1014
1015
1016 FormBeanConfig baseConfig = moduleConfig.findFormBeanConfig(ancestor);
1017
1018 if (baseConfig == null) {
1019 throw new UnavailableException("Unable to find " + "form bean '"
1020 + ancestor + "' to extend.");
1021 }
1022
1023
1024 if (beanConfig.getClass().equals(FormBeanConfig.class)) {
1025
1026 if (!baseConfig.getClass().equals(beanConfig.getClass())) {
1027
1028 FormBeanConfig newBeanConfig = null;
1029 String baseConfigClassName = baseConfig.getClass().getName();
1030
1031 try {
1032 newBeanConfig =
1033 (FormBeanConfig) RequestUtils.applicationInstance(baseConfigClassName);
1034
1035
1036 BeanUtils.copyProperties(newBeanConfig, beanConfig);
1037
1038 FormPropertyConfig[] fpc =
1039 beanConfig.findFormPropertyConfigs();
1040
1041 for (int i = 0; i < fpc.length; i++) {
1042 newBeanConfig.addFormPropertyConfig(fpc[i]);
1043 }
1044 } catch (Exception e) {
1045 handleCreationException(baseConfigClassName, e);
1046 }
1047
1048
1049 moduleConfig.removeFormBeanConfig(beanConfig);
1050 moduleConfig.addFormBeanConfig(newBeanConfig);
1051 beanConfig = newBeanConfig;
1052 }
1053 }
1054
1055 return beanConfig;
1056 }
1057
1058
1059
1060
1061
1062
1063
1064 protected void initModuleForwards(ModuleConfig config)
1065 throws ServletException {
1066 log.debug("Initializing module path '{}' forwards",
1067 config.getPrefix());
1068
1069
1070 ForwardConfig[] forwards = config.findForwardConfigs();
1071
1072 for (int i = 0; i < forwards.length; i++) {
1073 ForwardConfig forward = forwards[i];
1074
1075 postProcessConfig(forward, config, true);
1076 processForwardExtension(forward, config, null);
1077 postProcessConfig(forward, config, false);
1078 }
1079
1080 for (int i = 0; i < forwards.length; i++) {
1081 ForwardConfig forward = forwards[i];
1082
1083
1084 if (forward.getPath() == null) {
1085 handleValueRequiredException("path", forward.getName(),
1086 "global forward");
1087 }
1088 }
1089 }
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102 protected void processForwardExtension(ForwardConfig forwardConfig,
1103 ModuleConfig moduleConfig, ActionConfig actionConfig)
1104 throws ServletException {
1105 try {
1106 if (!forwardConfig.isExtensionProcessed()) {
1107 log.debug("Processing extensions for '{}'",
1108 forwardConfig.getName());
1109
1110 forwardConfig =
1111 processForwardConfigClass(forwardConfig, moduleConfig,
1112 actionConfig);
1113
1114 forwardConfig.processExtends(moduleConfig, actionConfig);
1115 }
1116 } catch (ServletException e) {
1117 throw e;
1118 } catch (Exception e) {
1119 handleGeneralExtensionException("Forward", forwardConfig.getName(),
1120 e);
1121 }
1122 }
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140 protected ForwardConfig processForwardConfigClass(
1141 ForwardConfig forwardConfig, ModuleConfig moduleConfig,
1142 ActionConfig actionConfig)
1143 throws ServletException {
1144 String ancestor = forwardConfig.getExtends();
1145
1146 if (ancestor == null) {
1147
1148 return forwardConfig;
1149 }
1150
1151
1152 ForwardConfig baseConfig = null;
1153 if (actionConfig != null) {
1154
1155 baseConfig = actionConfig.findForwardConfig(ancestor);
1156 }
1157
1158 if (baseConfig == null) {
1159
1160
1161 baseConfig = moduleConfig.findForwardConfig(ancestor);
1162 }
1163
1164 if (baseConfig == null) {
1165 throw new UnavailableException("Unable to find " + "forward '"
1166 + ancestor + "' to extend.");
1167 }
1168
1169
1170 if (forwardConfig.getClass().equals(ActionForward.class)) {
1171
1172 if (!baseConfig.getClass().equals(forwardConfig.getClass())) {
1173
1174 ForwardConfig newForwardConfig = null;
1175 String baseConfigClassName = baseConfig.getClass().getName();
1176
1177 try {
1178 newForwardConfig =
1179 (ForwardConfig) RequestUtils.applicationInstance(
1180 baseConfigClassName);
1181
1182
1183 BeanUtils.copyProperties(newForwardConfig, forwardConfig);
1184 } catch (Exception e) {
1185 handleCreationException(baseConfigClassName, e);
1186 }
1187
1188
1189 if (actionConfig != null) {
1190 actionConfig.removeForwardConfig(forwardConfig);
1191 actionConfig.addForwardConfig(newForwardConfig);
1192 } else {
1193
1194 moduleConfig.removeForwardConfig(forwardConfig);
1195 moduleConfig.addForwardConfig(newForwardConfig);
1196 }
1197 forwardConfig = newForwardConfig;
1198 }
1199 }
1200
1201 return forwardConfig;
1202 }
1203
1204
1205
1206
1207
1208
1209
1210
1211 protected void initModuleExceptionConfigs(ModuleConfig config)
1212 throws ServletException {
1213 log.debug("Initializing module path '{}' forwards",
1214 config.getPrefix());
1215
1216
1217 ExceptionConfig[] exceptions = config.findExceptionConfigs();
1218
1219 for (int i = 0; i < exceptions.length; i++) {
1220 ExceptionConfig exception = exceptions[i];
1221
1222 postProcessConfig(exception, config, true);
1223 processExceptionExtension(exception, config, null);
1224 postProcessConfig(exception, config, false);
1225 }
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237 }
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250 protected void processExceptionExtension(ExceptionConfig exceptionConfig,
1251 ModuleConfig moduleConfig, ActionConfig actionConfig)
1252 throws ServletException {
1253 try {
1254 if (!exceptionConfig.isExtensionProcessed()) {
1255 log.debug("Processing extensions for '{}'",
1256 exceptionConfig.getType());
1257
1258 exceptionConfig =
1259 processExceptionConfigClass(exceptionConfig, moduleConfig,
1260 actionConfig);
1261
1262 exceptionConfig.processExtends(moduleConfig, actionConfig);
1263 }
1264 } catch (ServletException e) {
1265 throw e;
1266 } catch (Exception e) {
1267 handleGeneralExtensionException("Exception",
1268 exceptionConfig.getType(), e);
1269 }
1270 }
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287 protected ExceptionConfig processExceptionConfigClass(
1288 ExceptionConfig exceptionConfig, ModuleConfig moduleConfig,
1289 ActionConfig actionConfig)
1290 throws ServletException {
1291 String ancestor = exceptionConfig.getExtends();
1292
1293 if (ancestor == null) {
1294
1295 return exceptionConfig;
1296 }
1297
1298
1299 ExceptionConfig baseConfig = null;
1300 if (actionConfig != null) {
1301 baseConfig = actionConfig.findExceptionConfig(ancestor);
1302 }
1303
1304 if (baseConfig == null) {
1305
1306
1307 baseConfig = moduleConfig.findExceptionConfig(ancestor);
1308 }
1309
1310 if (baseConfig == null) {
1311 throw new UnavailableException("Unable to find "
1312 + "exception config '" + ancestor + "' to extend.");
1313 }
1314
1315
1316 if (exceptionConfig.getClass().equals(ExceptionConfig.class)) {
1317
1318 if (!baseConfig.getClass().equals(exceptionConfig.getClass())) {
1319
1320 ExceptionConfig newExceptionConfig = null;
1321 String baseConfigClassName = baseConfig.getClass().getName();
1322
1323 try {
1324 newExceptionConfig =
1325 (ExceptionConfig) RequestUtils.applicationInstance(
1326 baseConfigClassName);
1327
1328
1329 BeanUtils.copyProperties(newExceptionConfig,
1330 exceptionConfig);
1331 } catch (Exception e) {
1332 handleCreationException(baseConfigClassName, e);
1333 }
1334
1335
1336 if (actionConfig != null) {
1337 actionConfig.removeExceptionConfig(exceptionConfig);
1338 actionConfig.addExceptionConfig(newExceptionConfig);
1339 } else {
1340 moduleConfig.removeExceptionConfig(exceptionConfig);
1341 moduleConfig.addExceptionConfig(newExceptionConfig);
1342 }
1343 exceptionConfig = newExceptionConfig;
1344 }
1345 }
1346
1347 return exceptionConfig;
1348 }
1349
1350
1351
1352
1353
1354
1355
1356
1357 protected void initModuleActions(ModuleConfig config)
1358 throws ServletException {
1359 log.debug("Initializing module path '{}' action configs",
1360 config.getPrefix());
1361
1362
1363 ActionConfig[] actionConfigs = config.findActionConfigs();
1364
1365 for (int i = 0; i < actionConfigs.length; i++) {
1366 ActionConfig actionConfig = actionConfigs[i];
1367
1368 postProcessConfig(actionConfig, config, true);
1369 processActionConfigExtension(actionConfig, config);
1370 postProcessConfig(actionConfig, config, false);
1371
1372
1373
1374
1375 String formName = actionConfig.getName();
1376 if (formName != null) {
1377 FormBeanConfig formConfig = config.findFormBeanConfig(formName);
1378 if (formConfig == null) {
1379 log.atWarn().log(() -> getInternal().getMessage("actionFormUnknown",
1380 actionConfig.getPath(), formName));
1381 }
1382 }
1383 }
1384
1385 for (int i = 0; i < actionConfigs.length; i++) {
1386 ActionConfig actionConfig = actionConfigs[i];
1387
1388
1389
1390 ForwardConfig[] forwards = actionConfig.findForwardConfigs();
1391
1392 for (int j = 0; j < forwards.length; j++) {
1393 ForwardConfig forward = forwards[j];
1394
1395 if (forward.getPath() == null) {
1396 handleValueRequiredException("path", forward.getName(),
1397 "action forward");
1398 }
1399 }
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413 }
1414 }
1415
1416
1417
1418
1419
1420
1421
1422
1423 protected void processActionConfigExtension(ActionConfig actionConfig,
1424 ModuleConfig moduleConfig)
1425 throws ServletException {
1426 try {
1427 if (!actionConfig.isExtensionProcessed()) {
1428 log.debug("Processing extensions for '{}'",
1429 actionConfig.getPath());
1430
1431 actionConfig =
1432 processActionConfigClass(actionConfig, moduleConfig);
1433
1434 actionConfig.processExtends(moduleConfig);
1435 }
1436
1437
1438 ForwardConfig[] forwards = actionConfig.findForwardConfigs();
1439 for (int i = 0; i < forwards.length; i++) {
1440 ForwardConfig forward = forwards[i];
1441 processForwardExtension(forward, moduleConfig, actionConfig);
1442 }
1443
1444
1445 ExceptionConfig[] exceptions = actionConfig.findExceptionConfigs();
1446 for (int i = 0; i < exceptions.length; i++) {
1447 ExceptionConfig exception = exceptions[i];
1448 processExceptionExtension(exception, moduleConfig,
1449 actionConfig);
1450 }
1451 } catch (ServletException e) {
1452 throw e;
1453 } catch (Exception e) {
1454 handleGeneralExtensionException("Action", actionConfig.getPath(), e);
1455 }
1456 }
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469 protected ActionConfig processActionConfigClass(ActionConfig actionConfig,
1470 ModuleConfig moduleConfig)
1471 throws ServletException {
1472 String ancestor = actionConfig.getExtends();
1473
1474 if (ancestor == null) {
1475
1476 return actionConfig;
1477 }
1478
1479
1480 ActionConfig baseConfig = moduleConfig.findActionConfig(ancestor);
1481 if (baseConfig == null) {
1482 baseConfig = moduleConfig.findActionConfigId(ancestor);
1483 }
1484
1485 if (baseConfig == null) {
1486 throw new UnavailableException("Unable to find "
1487 + "action config for '" + ancestor + "' to extend.");
1488 }
1489
1490
1491 if (actionConfig.getClass().equals(ActionMapping.class)) {
1492
1493 if (!baseConfig.getClass().equals(actionConfig.getClass())) {
1494
1495 ActionConfig newActionConfig = null;
1496 String baseConfigClassName = baseConfig.getClass().getName();
1497
1498 try {
1499 newActionConfig =
1500 (ActionConfig) RequestUtils.applicationInstance(baseConfigClassName);
1501
1502
1503 BeanUtils.copyProperties(newActionConfig, actionConfig);
1504
1505
1506 ForwardConfig[] forwards =
1507 actionConfig.findForwardConfigs();
1508
1509 for (int i = 0; i < forwards.length; i++) {
1510 newActionConfig.addForwardConfig(forwards[i]);
1511 }
1512
1513 ExceptionConfig[] exceptions =
1514 actionConfig.findExceptionConfigs();
1515
1516 for (int i = 0; i < exceptions.length; i++) {
1517 newActionConfig.addExceptionConfig(exceptions[i]);
1518 }
1519 } catch (Exception e) {
1520 handleCreationException(baseConfigClassName, e);
1521 }
1522
1523
1524 moduleConfig.removeActionConfig(actionConfig);
1525 moduleConfig.addActionConfig(newActionConfig);
1526 actionConfig = newActionConfig;
1527 }
1528 }
1529
1530 return actionConfig;
1531 }
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541 protected void initModuleMessageResources(ModuleConfig config)
1542 throws ServletException {
1543 MessageResourcesConfig[] mrcs = config.findMessageResourcesConfigs();
1544
1545 for (int i = 0; i < mrcs.length; i++) {
1546 if ((mrcs[i].getFactory() == null)
1547 || (mrcs[i].getParameter() == null)) {
1548 continue;
1549 }
1550
1551 postProcessConfig(mrcs[i], config, true);
1552 log.debug("Initializing module path '{}' "
1553 + "message resources from '{}'",
1554 config.getPrefix(), mrcs[i].getParameter());
1555
1556 String factory = mrcs[i].getFactory();
1557
1558 MessageResourcesFactory.setFactoryClass(factory);
1559
1560 MessageResourcesFactory factoryObject =
1561 MessageResourcesFactory.createFactory();
1562
1563 factoryObject.setConfig(mrcs[i]);
1564
1565 MessageResources resources =
1566 factoryObject.createResources(mrcs[i].getParameter());
1567
1568 resources.setReturnNull(mrcs[i].getNull());
1569 resources.setEscape(mrcs[i].isEscape());
1570
1571 postProcessConfig(mrcs[i], config, false);
1572 getServletContext().setAttribute(mrcs[i].getKey()
1573 + config.getPrefix(), resources);
1574 }
1575 }
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587 protected Digester initConfigDigester()
1588 throws ServletException {
1589
1590
1591 if (configDigester != null) {
1592 return (configDigester);
1593 }
1594
1595
1596 configDigester = new Digester();
1597 configDigester.setNamespaceAware(true);
1598 configDigester.setValidating(this.isValidating());
1599 configDigester.setUseContextClassLoader(true);
1600 configDigester.addRuleSet(new ConfigRuleSet());
1601
1602 for (int i = 0; i < registrations.length; i += 2) {
1603 URL url = this.getClass().getResource(registrations[i + 1]);
1604
1605 if (url != null) {
1606 configDigester.register(registrations[i], url.toString());
1607 }
1608 }
1609
1610 this.addRuleSets();
1611
1612
1613 return (configDigester);
1614 }
1615
1616
1617
1618
1619
1620
1621
1622 private void addRuleSets()
1623 throws ServletException {
1624 String rulesets = getServletConfig().getInitParameter("rulesets");
1625
1626 if (rulesets == null) {
1627 rulesets = "";
1628 }
1629
1630 rulesets = rulesets.trim();
1631
1632 String ruleset;
1633
1634 while (rulesets.length() > 0) {
1635 int comma = rulesets.indexOf(",");
1636
1637 if (comma < 0) {
1638 ruleset = rulesets.trim();
1639 rulesets = "";
1640 } else {
1641 ruleset = rulesets.substring(0, comma).trim();
1642 rulesets = rulesets.substring(comma + 1).trim();
1643 }
1644
1645 log.debug("Configuring custom Digester Ruleset of type {}",
1646 ruleset);
1647
1648 try {
1649 RuleSet instance =
1650 (RuleSet) RequestUtils.applicationInstance(ruleset);
1651
1652 this.configDigester.addRuleSet(instance);
1653 } catch (Exception e) {
1654 log.error("Exception configuring custom Digester RuleSet", e);
1655 throw new ServletException(e);
1656 }
1657 }
1658 }
1659
1660
1661
1662
1663
1664
1665
1666 private boolean isValidating() {
1667 boolean validating = true;
1668 String value = getServletConfig().getInitParameter("validating");
1669
1670 if ("false".equalsIgnoreCase(value) || "no".equalsIgnoreCase(value)
1671 || "n".equalsIgnoreCase(value) || "0".equalsIgnoreCase(value)) {
1672 validating = false;
1673 }
1674
1675 return validating;
1676 }
1677
1678
1679
1680
1681
1682
1683
1684 protected void initInternal()
1685 throws ServletException {
1686 try {
1687 internal = MessageResources.getMessageResources(internalName);
1688 } catch (MissingResourceException e) {
1689 log.error("Cannot load internal resources from '{}'",
1690 internalName, e);
1691 UnavailableException e2 = new UnavailableException(
1692 "Cannot load internal resources from '" + internalName + "'");
1693 e2.initCause(e);
1694 throw e2;
1695 }
1696 }
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706 protected void initChain()
1707 throws ServletException {
1708
1709 try {
1710 String value;
1711
1712 value = getServletConfig().getInitParameter("chainConfig");
1713
1714 if (value != null) {
1715 chainConfig = value;
1716 }
1717
1718 ConfigParser parser = new ConfigParser();
1719 List<URL> urls = splitAndResolvePaths(chainConfig);
1720
1721 for (URL resource : urls) {
1722 log.info("Loading chain catalog from {}", resource);
1723 parser.parse(resource);
1724 }
1725 } catch (Exception e) {
1726 log.error("Exception loading resources", e);
1727 throw new ServletException(e);
1728 }
1729 }
1730
1731
1732
1733
1734
1735
1736
1737 protected void initOther()
1738 throws ServletException {
1739 PropertyUtils.addBeanIntrospector(SUPPRESS_CLASSES);
1740 PropertyUtils.clearDescriptors();
1741
1742 String value;
1743
1744 value = getServletConfig().getInitParameter("config");
1745
1746 if (value != null) {
1747 config = value;
1748 }
1749
1750
1751
1752 value = getServletConfig().getInitParameter("convertNull");
1753
1754 if ("true".equalsIgnoreCase(value) || "yes".equalsIgnoreCase(value)
1755 || "on".equalsIgnoreCase(value) || "y".equalsIgnoreCase(value)
1756 || "1".equalsIgnoreCase(value)) {
1757 convertNull = true;
1758 }
1759
1760 if (convertNull) {
1761 ConvertUtils.deregister();
1762 ConvertUtils.register(new BigDecimalConverter(null),
1763 BigDecimal.class);
1764 ConvertUtils.register(new BigIntegerConverter(null),
1765 BigInteger.class);
1766 ConvertUtils.register(new BooleanConverter(null), Boolean.class);
1767 ConvertUtils.register(new ByteConverter(null), Byte.class);
1768 ConvertUtils.register(new CharacterConverter(null), Character.class);
1769 ConvertUtils.register(new DoubleConverter(null), Double.class);
1770 ConvertUtils.register(new FloatConverter(null), Float.class);
1771 ConvertUtils.register(new IntegerConverter(null), Integer.class);
1772 ConvertUtils.register(new LongConverter(null), Long.class);
1773 ConvertUtils.register(new ShortConverter(null), Short.class);
1774 }
1775 }
1776
1777
1778
1779
1780
1781
1782
1783
1784 protected void initServlet()
1785 throws ServletException {
1786
1787 this.servletName = getServletConfig().getServletName();
1788
1789
1790 Digester digester = new Digester();
1791
1792 digester.push(this);
1793 digester.setNamespaceAware(true);
1794 digester.setValidating(false);
1795
1796
1797 for (int i = 0; i < registrations.length; i += 2) {
1798 URL url = this.getClass().getResource(registrations[i + 1]);
1799
1800 if (url != null) {
1801 digester.register(registrations[i], url.toString());
1802 }
1803 }
1804
1805
1806 digester.addCallMethod("web-app/servlet-mapping", "addServletMapping", 2);
1807 digester.addCallParam("web-app/servlet-mapping/servlet-name", 0);
1808 digester.addCallParam("web-app/servlet-mapping/url-pattern", 1);
1809
1810
1811 log.debug("Scanning web.xml for controller servlet mapping");
1812
1813 try (InputStream input = getServletContext().getResourceAsStream("/WEB-INF/web.xml")) {
1814 if (input == null) {
1815 log.atError().log(() -> internal.getMessage("configWebXml"));
1816 throw new ServletException(internal.getMessage("configWebXml"));
1817 }
1818 digester.parse(input);
1819 } catch (IOException e) {
1820 log.atError()
1821 .setMessage(() -> internal.getMessage("configWebXml"))
1822 .setCause(e).log();
1823 throw new ServletException(e);
1824 } catch (SAXException e) {
1825 log.atError()
1826 .setMessage(() -> internal.getMessage("configWebXml"))
1827 .setCause(e).log();
1828 throw new ServletException(e);
1829 }
1830
1831
1832 log.debug("Mapping for servlet '{}' = '{}'",
1833 servletName, servletMapping);
1834
1835 if (servletMapping != null) {
1836 getServletContext().setAttribute(Globals.SERVLET_KEY, servletMapping);
1837 }
1838 }
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851 protected List<URL> splitAndResolvePaths(String paths)
1852 throws ServletException {
1853 ClassLoader loader = Thread.currentThread().getContextClassLoader();
1854
1855 if (loader == null) {
1856 loader = this.getClass().getClassLoader();
1857 }
1858
1859 ArrayList<URL> resolvedUrls = new ArrayList<>();
1860
1861 URL resource;
1862 String path = null;
1863
1864 try {
1865
1866 while (paths.length() > 0) {
1867 resource = null;
1868
1869 int comma = paths.indexOf(',');
1870
1871 if (comma >= 0) {
1872 path = paths.substring(0, comma).trim();
1873 paths = paths.substring(comma + 1);
1874 } else {
1875 path = paths.trim();
1876 paths = "";
1877 }
1878
1879 if (path.length() < 1) {
1880 break;
1881 }
1882
1883 if (path.charAt(0) == '/') {
1884 resource = getServletContext().getResource(path);
1885 }
1886
1887 if (resource == null) {
1888 log.debug("Unable to locate {}"
1889 + " in the servlet context, "
1890 + "trying classloader.", path);
1891
1892 Enumeration<URL> e = loader.getResources(path);
1893
1894 if (!e.hasMoreElements()) {
1895 String msg = internal.getMessage("configMissing", path);
1896
1897 log.error(msg);
1898 throw new UnavailableException(msg);
1899 } else {
1900 while (e.hasMoreElements()) {
1901 resolvedUrls.add(e.nextElement());
1902 }
1903 }
1904 } else {
1905 resolvedUrls.add(resource);
1906 }
1907 }
1908 } catch (IOException e) {
1909 handleConfigException(path, e);
1910 }
1911
1912 return resolvedUrls;
1913 }
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924 protected void process(HttpServletRequest request,
1925 HttpServletResponse response)
1926 throws IOException, ServletException {
1927 ModuleUtils.getInstance().selectModule(request, getServletContext());
1928
1929 ModuleConfig config = getModuleConfig(request);
1930
1931 RequestProcessor processor = getProcessorForModule(config);
1932
1933 if (processor == null) {
1934 processor = getRequestProcessor(config);
1935 }
1936
1937 processor.process(request, response);
1938 }
1939
1940
1941
1942
1943
1944
1945
1946 private PlugIn[] getModulePlugIns(ModuleConfig moduleConfig) {
1947 try {
1948 String plugInKey = Globals.PLUG_INS_KEY + moduleConfig.getPrefix();
1949 return (PlugIn[]) getServletContext().getAttribute(plugInKey);
1950 } catch (NullPointerException | IllegalStateException e) {
1951 return null;
1952 }
1953 }
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964 private void postProcessConfig(BaseConfig config, ModuleConfig moduleConfig,
1965 boolean before) {
1966 PlugIn[] plugIns = getModulePlugIns(moduleConfig);
1967 if ((plugIns == null) || (plugIns.length == 0)) {
1968 return;
1969 }
1970
1971 for (int i = 0; i < plugIns.length; i++) {
1972 PlugIn plugIn = plugIns[i];
1973 if (plugIn instanceof ModuleConfigPostProcessor) {
1974 ModuleConfigPostProcessor p = (ModuleConfigPostProcessor) plugIn;
1975 if (before) {
1976 p.postProcessBeforeInitialization(config, moduleConfig);
1977 } else {
1978 p.postProcessAfterInitialization(config, moduleConfig);
1979 }
1980 }
1981 }
1982 }
1983
1984
1985
1986
1987
1988
1989 private void postProcessConfig(ModuleConfig moduleConfig) {
1990 PlugIn[] plugIns = getModulePlugIns(moduleConfig);
1991 if ((plugIns == null) || (plugIns.length == 0)) {
1992 return;
1993 }
1994
1995 for (int i = 0; i < plugIns.length; i++) {
1996 PlugIn plugIn = plugIns[i];
1997 if (plugIn instanceof ModuleConfigPostProcessor) {
1998 ((ModuleConfigPostProcessor) plugIn).postProcessAfterInitialization(moduleConfig);
1999 }
2000 }
2001 }
2002 }