1 18 19 package org.apache.struts.action; 20 21 import java.io.IOException ; 22 import java.io.InputStream ; 23 import java.math.BigDecimal ; 24 import java.math.BigInteger ; 25 import java.net.MalformedURLException ; 26 import java.net.URL ; 27 import java.util.ArrayList ; 28 import java.util.Enumeration ; 29 import java.util.Iterator ; 30 import java.util.MissingResourceException ; 31 32 import javax.servlet.ServletContext ; 33 import javax.servlet.ServletException ; 34 import javax.servlet.UnavailableException ; 35 import javax.servlet.http.HttpServlet ; 36 import javax.servlet.http.HttpServletRequest ; 37 import javax.servlet.http.HttpServletResponse ; 38 import javax.sql.DataSource ; 39 40 import org.apache.commons.beanutils.BeanUtils; 41 import org.apache.commons.beanutils.ConvertUtils; 42 import org.apache.commons.beanutils.PropertyUtils; 43 import org.apache.commons.beanutils.converters.BigDecimalConverter; 44 import org.apache.commons.beanutils.converters.BigIntegerConverter; 45 import org.apache.commons.beanutils.converters.BooleanConverter; 46 import org.apache.commons.beanutils.converters.ByteConverter; 47 import org.apache.commons.beanutils.converters.CharacterConverter; 48 import org.apache.commons.beanutils.converters.DoubleConverter; 49 import org.apache.commons.beanutils.converters.FloatConverter; 50 import org.apache.commons.beanutils.converters.IntegerConverter; 51 import org.apache.commons.beanutils.converters.LongConverter; 52 import org.apache.commons.beanutils.converters.ShortConverter; 53 import org.apache.commons.collections.FastHashMap; 54 import org.apache.commons.digester.Digester; 55 import org.apache.commons.digester.RuleSet; 56 import org.apache.commons.logging.Log; 57 import org.apache.commons.logging.LogFactory; 58 import org.apache.struts.Globals; 59 import org.apache.struts.config.ConfigRuleSet; 60 import org.apache.struts.config.DataSourceConfig; 61 import org.apache.struts.config.FormBeanConfig; 62 import org.apache.struts.config.MessageResourcesConfig; 63 import org.apache.struts.config.ModuleConfig; 64 import org.apache.struts.config.ModuleConfigFactory; 65 import org.apache.struts.config.PlugInConfig; 66 import org.apache.struts.util.MessageResources; 67 import org.apache.struts.util.MessageResourcesFactory; 68 import org.apache.struts.util.ModuleUtils; 69 import org.apache.struts.util.RequestUtils; 70 import org.apache.struts.util.ServletContextWriter; 71 import org.xml.sax.InputSource ; 72 import org.xml.sax.SAXException ; 73 74 169 public class ActionServlet extends HttpServlet { 170 171 172 174 175 179 protected String config = "/WEB-INF/struts-config.xml"; 180 181 182 188 protected Digester configDigester = null; 189 190 191 197 protected boolean convertNull = false; 198 199 200 205 protected FastHashMap dataSources = new FastHashMap(); 206 207 208 211 protected MessageResources internal = null; 212 213 214 218 protected String internalName = "org.apache.struts.action.ActionResources"; 219 220 221 226 protected static Log log = LogFactory.getLog(ActionServlet.class); 227 228 229 235 protected RequestProcessor processor = null; 236 237 238 243 protected String registrations[] = { 244 "-//Apache Software Foundation//DTD Struts Configuration 1.0//EN", 245 "/org/apache/struts/resources/struts-config_1_0.dtd", 246 "-//Apache Software Foundation//DTD Struts Configuration 1.1//EN", 247 "/org/apache/struts/resources/struts-config_1_1.dtd", 248 "-//Apache Software Foundation//DTD Struts Configuration 1.2//EN", 249 "/org/apache/struts/resources/struts-config_1_2.dtd", 250 "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN", 251 "/org/apache/struts/resources/web-app_2_2.dtd", 252 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN", 253 "/org/apache/struts/resources/web-app_2_3.dtd" 254 }; 255 256 257 261 protected String servletMapping = null; 263 264 268 protected String servletName = null; 269 270 271 273 274 278 public void destroy() { 279 280 if (log.isDebugEnabled()) { 281 log.debug(internal.getMessage("finalizing")); 282 } 283 284 destroyModules(); 285 destroyInternal(); 286 getServletContext().removeAttribute(Globals.ACTION_SERVLET_KEY); 287 288 ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); 290 if (classLoader == null) { 291 classLoader = ActionServlet.class.getClassLoader(); 292 } 293 try { 294 LogFactory.release(classLoader); 295 } catch (Throwable t) { 296 ; ; 299 306 } 307 308 PropertyUtils.clearDescriptors(); 309 310 } 311 312 313 320 public void init() throws ServletException { 321 322 try { 326 initInternal(); 327 initOther(); 328 initServlet(); 329 330 getServletContext().setAttribute(Globals.ACTION_SERVLET_KEY, this); 331 initModuleConfigFactory(); 332 ModuleConfig moduleConfig = initModuleConfig("", config); 334 initModuleMessageResources(moduleConfig); 335 initModuleDataSources(moduleConfig); 336 initModulePlugIns(moduleConfig); 337 moduleConfig.freeze(); 338 339 Enumeration names = getServletConfig().getInitParameterNames(); 340 while (names.hasMoreElements()) { 341 String name = (String ) names.nextElement(); 342 if (!name.startsWith("config/")) { 343 continue; 344 } 345 String prefix = name.substring(6); 346 moduleConfig = initModuleConfig 347 (prefix, getServletConfig().getInitParameter(name)); 348 initModuleMessageResources(moduleConfig); 349 initModuleDataSources(moduleConfig); 350 initModulePlugIns(moduleConfig); 351 moduleConfig.freeze(); 352 } 353 354 this.initModulePrefixes(this.getServletContext()); 355 356 this.destroyConfigDigester(); 357 } catch (UnavailableException ex) { 358 throw ex; 359 } catch (Throwable t) { 360 361 log.error("Unable to initialize Struts ActionServlet due to an " 365 + "unexpected exception or error thrown, so marking the " 366 + "servlet as unavailable. Most likely, this is due to an " 367 + "incorrect or missing library dependency.", t); 368 throw new UnavailableException (t.getMessage()); 369 } 370 } 371 372 380 protected void initModulePrefixes(ServletContext context) { 381 ArrayList prefixList = new ArrayList (); 382 383 Enumeration names = context.getAttributeNames(); 384 while (names.hasMoreElements()) { 385 String name = (String ) names.nextElement(); 386 if (!name.startsWith(Globals.MODULE_KEY)) { 387 continue; 388 } 389 390 String prefix = name.substring(Globals.MODULE_KEY.length()); 391 if (prefix.length() > 0) { 392 prefixList.add(prefix); 393 } 394 } 395 396 String [] prefixes = (String []) prefixList.toArray(new String [prefixList.size()]); 397 context.setAttribute(Globals.MODULE_PREFIXES_KEY, prefixes); 398 } 399 400 401 410 public void doGet(HttpServletRequest request, 411 HttpServletResponse response) 412 throws IOException , ServletException { 413 414 process(request, response); 415 416 } 417 418 419 428 public void doPost(HttpServletRequest request, 429 HttpServletResponse response) 430 throws IOException , ServletException { 431 432 process(request, response); 433 434 } 435 436 437 439 440 447 public void addServletMapping(String servletName, String urlPattern) { 448 449 if (log.isDebugEnabled()) { 450 log.debug("Process servletName=" + servletName + 451 ", urlPattern=" + urlPattern); 452 } 453 if (servletName == null) { 454 return; 455 } 456 if (servletName.equals(this.servletName)) { 457 this.servletMapping = urlPattern; 458 } 459 460 } 461 462 463 469 public MessageResources getInternal() { 470 471 return (this.internal); 472 473 } 474 475 476 478 484 protected void destroyModules() { 485 486 ArrayList values = new ArrayList (); 487 Enumeration names = getServletContext().getAttributeNames(); 488 while (names.hasMoreElements()) { 489 values.add(names.nextElement()); 490 } 491 492 Iterator keys = values.iterator(); 493 while (keys.hasNext()) { 494 String name = (String ) keys.next(); 495 Object value = getServletContext().getAttribute(name); 496 497 if (!(value instanceof ModuleConfig)) { 498 continue; 499 } 500 501 ModuleConfig config = (ModuleConfig) value; 502 503 if (this.getProcessorForModule(config) != null) { 504 this.getProcessorForModule(config).destroy(); 505 } 506 507 getServletContext().removeAttribute(name); 508 509 PlugIn plugIns[] = 510 (PlugIn[]) getServletContext().getAttribute( 511 Globals.PLUG_INS_KEY + config.getPrefix()); 512 513 if (plugIns != null) { 514 for (int i = 0; i < plugIns.length; i++) { 515 int j = plugIns.length - (i + 1); 516 plugIns[j].destroy(); 517 } 518 519 getServletContext().removeAttribute( 520 Globals.PLUG_INS_KEY + config.getPrefix()); 521 } 522 523 } 524 525 } 526 527 528 533 protected void destroyConfigDigester() { 534 535 configDigester = null; 536 537 } 538 539 540 543 protected void destroyInternal() { 544 545 internal = null; 546 547 } 548 549 556 protected ModuleConfig getModuleConfig 557 (HttpServletRequest request) { 558 559 ModuleConfig config = (ModuleConfig) 560 request.getAttribute(Globals.MODULE_KEY); 561 if (config == null) { 562 config = (ModuleConfig) 563 getServletContext().getAttribute(Globals.MODULE_KEY); 564 } 565 return (config); 566 567 } 568 569 570 581 protected synchronized RequestProcessor getRequestProcessor(ModuleConfig config) 582 throws ServletException { 583 584 586 RequestProcessor processor = this.getProcessorForModule(config); 587 588 if (processor == null) { 589 try { 590 processor = 591 (RequestProcessor) RequestUtils.applicationInstance( 592 config.getControllerConfig().getProcessorClass()); 593 594 } catch (Exception e) { 595 throw new UnavailableException ( 596 "Cannot initialize RequestProcessor of class " 597 + config.getControllerConfig().getProcessorClass() 598 + ": " 599 + e); 600 } 601 602 processor.init(this, config); 603 604 String key = Globals.REQUEST_PROCESSOR_KEY + config.getPrefix(); 605 getServletContext().setAttribute(key, processor); 606 607 } 608 609 return (processor); 610 611 } 612 613 614 620 private RequestProcessor getProcessorForModule(ModuleConfig config) { 621 String key = Globals.REQUEST_PROCESSOR_KEY + config.getPrefix(); 622 return (RequestProcessor) getServletContext().getAttribute(key); 623 } 624 625 626 630 protected void initModuleConfigFactory(){ 631 String configFactory = getServletConfig().getInitParameter("configFactory"); 632 if (configFactory != null) { 633 ModuleConfigFactory.setFactoryClass(configFactory); 634 } 635 } 636 637 638 649 protected ModuleConfig initModuleConfig(String prefix, String paths) 650 throws ServletException { 651 652 654 if (log.isDebugEnabled()) { 655 log.debug( 656 "Initializing module path '" 657 + prefix 658 + "' configuration from '" 659 + paths 660 + "'"); 661 } 662 663 ModuleConfigFactory factoryObject = ModuleConfigFactory.createFactory(); 665 ModuleConfig config = factoryObject.createModuleConfig(prefix); 666 667 Digester digester = initConfigDigester(); 669 670 while (paths.length() > 0) { 672 digester.push(config); 673 String path = null; 674 int comma = paths.indexOf(','); 675 if (comma >= 0) { 676 path = paths.substring(0, comma).trim(); 677 paths = paths.substring(comma + 1); 678 } else { 679 path = paths.trim(); 680 paths = ""; 681 } 682 683 if (path.length() < 1) { 684 break; 685 } 686 687 this.parseModuleConfigFile(digester, path); 688 } 689 690 getServletContext().setAttribute( 691 Globals.MODULE_KEY + config.getPrefix(), 692 config); 693 694 FormBeanConfig fbs[] = config.findFormBeanConfigs(); 697 for (int i = 0; i < fbs.length; i++) { 698 if (fbs[i].getDynamic()) { 699 fbs[i].getDynaActionFormClass(); 700 } 701 } 702 703 return config; 704 } 705 706 707 716 protected void parseModuleConfigFile(Digester digester, String path) 717 throws UnavailableException { 718 719 InputStream input = null; 720 try { 721 URL url = getServletContext().getResource(path); 722 723 if (url == null) { 726 url = getClass().getResource(path); 727 } 728 729 if (url == null) { 730 String msg = internal.getMessage("configMissing", path); 731 log.error(msg); 732 throw new UnavailableException (msg); 733 } 734 735 InputSource is = new InputSource (url.toExternalForm()); 736 input = url.openStream(); 737 is.setByteStream(input); 738 digester.parse(is); 739 740 } catch (MalformedURLException e) { 741 handleConfigException(path, e); 742 } catch (IOException e) { 743 handleConfigException(path, e); 744 } catch (SAXException e) { 745 handleConfigException(path, e); 746 } finally { 747 if (input != null) { 748 try { 749 input.close(); 750 } catch (IOException e) { 751 throw new UnavailableException (e.getMessage()); 752 } 753 } 754 } 755 } 756 757 758 764 private void handleConfigException(String path, Exception e) 765 throws UnavailableException { 766 767 String msg = internal.getMessage("configParse", path); 768 log.error(msg, e); 769 throw new UnavailableException (msg); 770 } 771 772 773 781 protected void initModuleDataSources(ModuleConfig config) throws ServletException { 782 783 785 if (log.isDebugEnabled()) { 786 log.debug("Initializing module path '" + config.getPrefix() + 787 "' data sources"); 788 } 789 790 ServletContextWriter scw = 791 new ServletContextWriter(getServletContext()); 792 DataSourceConfig dscs[] = config.findDataSourceConfigs(); 793 if (dscs == null) { 794 dscs = new DataSourceConfig[0]; 795 } 796 797 dataSources.setFast(false); 798 for (int i = 0; i < dscs.length; i++) { 799 if (log.isDebugEnabled()) { 800 log.debug("Initializing module path '" + config.getPrefix() + 801 "' data source '" + dscs[i].getKey() + "'"); 802 } 803 DataSource ds = null; 804 try { 805 ds = (DataSource ) 806 RequestUtils.applicationInstance(dscs[i].getType()); 807 BeanUtils.populate(ds, dscs[i].getProperties()); 808 ds.setLogWriter(scw); 809 810 } catch (Exception e) { 811 log.error(internal.getMessage("dataSource.init", dscs[i].getKey()), e); 812 throw new UnavailableException 813 (internal.getMessage("dataSource.init", dscs[i].getKey())); 814 } 815 getServletContext().setAttribute 816 (dscs[i].getKey() + config.getPrefix(), ds); 817 dataSources.put(dscs[i].getKey(), ds); 818 } 819 820 dataSources.setFast(true); 821 822 } 823 824 825 833 protected void initModulePlugIns 834 (ModuleConfig config) throws ServletException { 835 836 if (log.isDebugEnabled()) { 837 log.debug("Initializing module path '" + config.getPrefix() + "' plug ins"); 838 } 839 840 PlugInConfig plugInConfigs[] = config.findPlugInConfigs(); 841 PlugIn plugIns[] = new PlugIn[plugInConfigs.length]; 842 843 getServletContext().setAttribute(Globals.PLUG_INS_KEY + config.getPrefix(), plugIns); 844 for (int i = 0; i < plugIns.length; i++) { 845 try { 846 plugIns[i] = 847 (PlugIn)RequestUtils.applicationInstance(plugInConfigs[i].getClassName()); 848 BeanUtils.populate(plugIns[i], plugInConfigs[i].getProperties()); 849 try { 853 PropertyUtils.setProperty( 854 plugIns[i], 855 "currentPlugInConfigObject", 856 plugInConfigs[i]); 857 } catch (Exception e) { 858 868 } 869 plugIns[i].init(this, config); 870 871 } catch (ServletException e) { 872 throw e; 873 } catch (Exception e) { 874 String errMsg = 875 internal.getMessage( 876 "plugIn.init", 877 plugInConfigs[i].getClassName()); 878 879 log(errMsg, e); 880 throw new UnavailableException (errMsg); 881 } 882 } 883 884 } 885 886 887 896 protected void initModuleMessageResources(ModuleConfig config) 897 throws ServletException { 898 899 MessageResourcesConfig mrcs[] = config.findMessageResourcesConfigs(); 900 for (int i = 0; i < mrcs.length; i++) { 901 if ((mrcs[i].getFactory() == null) 902 || (mrcs[i].getParameter() == null)) { 903 continue; 904 } 905 if (log.isDebugEnabled()) { 906 log.debug( 907 "Initializing module path '" 908 + config.getPrefix() 909 + "' message resources from '" 910 + mrcs[i].getParameter() 911 + "'"); 912 } 913 914 String factory = mrcs[i].getFactory(); 915 MessageResourcesFactory.setFactoryClass(factory); 916 MessageResourcesFactory factoryObject = 917 MessageResourcesFactory.createFactory(); 918 919 MessageResources resources = 920 factoryObject.createResources(mrcs[i].getParameter()); 921 resources.setReturnNull(mrcs[i].getNull()); 922 getServletContext().setAttribute( 923 mrcs[i].getKey() + config.getPrefix(), 924 resources); 925 } 926 927 } 928 929 930 940 protected Digester initConfigDigester() throws ServletException { 941 942 944 if (configDigester != null) { 946 return (configDigester); 947 } 948 949 configDigester = new Digester(); 951 configDigester.setNamespaceAware(true); 952 configDigester.setValidating(this.isValidating()); 953 configDigester.setUseContextClassLoader(true); 954 configDigester.addRuleSet(new ConfigRuleSet()); 955 956 for (int i = 0; i < registrations.length; i += 2) { 957 URL url = this.getClass().getResource(registrations[i+1]); 958 if (url != null) { 959 configDigester.register(registrations[i], url.toString()); 960 } 961 } 962 963 this.addRuleSets(); 964 965 return (configDigester); 967 } 968 969 970 976 private void addRuleSets() throws ServletException { 977 978 String rulesets = getServletConfig().getInitParameter("rulesets"); 979 if (rulesets == null) { 980 rulesets = ""; 981 } 982 983 rulesets = rulesets.trim(); 984 String ruleset = null; 985 while (rulesets.length() > 0) { 986 int comma = rulesets.indexOf(","); 987 if (comma < 0) { 988 ruleset = rulesets.trim(); 989 rulesets = ""; 990 } else { 991 ruleset = rulesets.substring(0, comma).trim(); 992 rulesets = rulesets.substring(comma + 1).trim(); 993 } 994 995 if (log.isDebugEnabled()) { 996 log.debug("Configuring custom Digester Ruleset of type " + ruleset); 997 } 998 999 try { 1000 RuleSet instance = (RuleSet) RequestUtils.applicationInstance(ruleset); 1001 this.configDigester.addRuleSet(instance); 1002 } catch (Exception e) { 1003 log.error("Exception configuring custom Digester RuleSet", e); 1004 throw new ServletException (e); 1005 } 1006 } 1007 } 1008 1009 1010 1015 private boolean isValidating() { 1016 1017 boolean validating = true; 1018 String value = getServletConfig().getInitParameter("validating"); 1019 1020 if ("false".equalsIgnoreCase(value) 1021 || "no".equalsIgnoreCase(value) 1022 || "n".equalsIgnoreCase(value) 1023 || "0".equalsIgnoreCase(value)) { 1024 1025 validating = false; 1026 } 1027 1028 return validating; 1029 } 1030 1031 1032 1033 1038 protected void initInternal() throws ServletException { 1039 1040 1042 try { 1043 internal = MessageResources.getMessageResources(internalName); 1044 } catch (MissingResourceException e) { 1045 log.error("Cannot load internal resources from '" + internalName + "'", 1046 e); 1047 throw new UnavailableException 1048 ("Cannot load internal resources from '" + internalName + "'"); 1049 } 1050 1051 } 1052 1053 1054 1059 protected void initOther() throws ServletException { 1060 1061 String value = null; 1062 value = getServletConfig().getInitParameter("config"); 1063 if (value != null) { 1064 config = value; 1065 } 1066 1067 value = getServletConfig().getInitParameter("convertNull"); 1070 if ("true".equalsIgnoreCase(value) 1071 || "yes".equalsIgnoreCase(value) 1072 || "on".equalsIgnoreCase(value) 1073 || "y".equalsIgnoreCase(value) 1074 || "1".equalsIgnoreCase(value)) { 1075 1076 convertNull = true; 1077 } 1078 1079 if (convertNull) { 1080 ConvertUtils.deregister(); 1081 ConvertUtils.register(new BigDecimalConverter(null), BigDecimal .class); 1082 ConvertUtils.register(new BigIntegerConverter(null), BigInteger .class); 1083 ConvertUtils.register(new BooleanConverter(null), Boolean .class); 1084 ConvertUtils.register(new ByteConverter(null), Byte .class); 1085 ConvertUtils.register(new CharacterConverter(null), Character .class); 1086 ConvertUtils.register(new DoubleConverter(null), Double .class); 1087 ConvertUtils.register(new FloatConverter(null), Float .class); 1088 ConvertUtils.register(new IntegerConverter(null), Integer .class); 1089 ConvertUtils.register(new LongConverter(null), Long .class); 1090 ConvertUtils.register(new ShortConverter(null), Short .class); 1091 } 1092 1093 } 1094 1095 1096 1103 protected void initServlet() throws ServletException { 1104 1105 this.servletName = getServletConfig().getServletName(); 1107 1108 Digester digester = new Digester(); 1110 digester.push(this); 1111 digester.setNamespaceAware(true); 1112 digester.setValidating(false); 1113 1114 for (int i = 0; i < registrations.length; i += 2) { 1116 URL url = this.getClass().getResource(registrations[i+1]); 1117 if (url != null) { 1118 digester.register(registrations[i], url.toString()); 1119 } 1120 } 1121 1122 digester.addCallMethod("web-app/servlet-mapping", 1124 "addServletMapping", 2); 1125 digester.addCallParam("web-app/servlet-mapping/servlet-name", 0); 1126 digester.addCallParam("web-app/servlet-mapping/url-pattern", 1); 1127 1128 if (log.isDebugEnabled()) { 1130 log.debug("Scanning web.xml for controller servlet mapping"); 1131 } 1132 1133 InputStream input = 1134 getServletContext().getResourceAsStream("/WEB-INF/web.xml"); 1135 1136 if (input == null) { 1137 log.error(internal.getMessage("configWebXml")); 1138 throw new ServletException (internal.getMessage("configWebXml")); 1139 } 1140 1141 try { 1142 digester.parse(input); 1143 1144 } catch (IOException e) { 1145 log.error(internal.getMessage("configWebXml"), e); 1146 throw new ServletException (e); 1147 1148 } catch (SAXException e) { 1149 log.error(internal.getMessage("configWebXml"), e); 1150 throw new ServletException (e); 1151 1152 } finally { 1153 try { 1154 input.close(); 1155 } catch (IOException e) { 1156 log.error(internal.getMessage("configWebXml"), e); 1157 throw new ServletException (e); 1158 } 1159 } 1160 1161 if (log.isDebugEnabled()) { 1163 log.debug("Mapping for servlet '" + servletName + "' = '" + 1164 servletMapping + "'"); 1165 } 1166 1167 if (servletMapping != null) { 1168 getServletContext().setAttribute(Globals.SERVLET_KEY, servletMapping); 1169 } 1170 1171 } 1172 1173 1174 1184 protected void process(HttpServletRequest request, HttpServletResponse response) 1185 throws IOException , ServletException { 1186 1187 ModuleUtils.getInstance().selectModule(request, getServletContext()); 1188 ModuleConfig config = getModuleConfig(request); 1189 1190 RequestProcessor processor = getProcessorForModule(config); 1191 if (processor == null) { 1192 processor = getRequestProcessor(config); 1193 } 1194 processor.process(request, response); 1195 1196 } 1197 1198} 1199 | Popular Tags |