001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: *
017: * $Header:$
018: */
019: package org.apache.beehive.netui.pageflow;
020:
021: import org.apache.beehive.netui.pageflow.internal.InternalConstants;
022: import org.apache.beehive.netui.pageflow.internal.InternalUtils;
023: import org.apache.beehive.netui.pageflow.internal.PageFlowRequestWrapper;
024: import org.apache.beehive.netui.pageflow.internal.AdapterManager;
025: import org.apache.beehive.netui.pageflow.config.PageFlowControllerConfig;
026: import org.apache.beehive.netui.pageflow.handler.Handlers;
027: import org.apache.beehive.netui.pageflow.handler.ReloadableClassHandler;
028: import org.apache.beehive.netui.util.Bundle;
029: import org.apache.beehive.netui.util.internal.InternalStringBuilder;
030: import org.apache.beehive.netui.util.internal.DiscoveryUtils;
031: import org.apache.beehive.netui.util.internal.concurrent.InternalConcurrentHashMap;
032: import org.apache.beehive.netui.util.config.ConfigUtil;
033: import org.apache.beehive.netui.util.config.bean.PageFlowConfig;
034: import org.apache.beehive.netui.util.config.bean.ModuleConfigLocatorConfig;
035: import org.apache.beehive.netui.util.logging.Logger;
036: import org.apache.commons.digester.Digester;
037: import org.apache.struts.Globals;
038: import org.apache.struts.action.ActionServlet;
039: import org.apache.struts.action.DynaActionFormClass;
040: import org.apache.struts.action.RequestProcessor;
041: import org.apache.struts.config.ControllerConfig;
042: import org.apache.struts.config.FormBeanConfig;
043: import org.apache.struts.config.MessageResourcesConfig;
044: import org.apache.struts.config.ModuleConfig;
045: import org.apache.struts.config.ModuleConfigFactory;
046: import org.apache.struts.config.impl.ModuleConfigImpl;
047: import org.apache.struts.util.RequestUtils;
048: import org.xml.sax.InputSource;
049:
050: import javax.servlet.ServletConfig;
051: import javax.servlet.ServletContext;
052: import javax.servlet.ServletException;
053: import javax.servlet.ServletRequest;
054: import javax.servlet.ServletResponse;
055: import javax.servlet.UnavailableException;
056: import javax.servlet.http.HttpServletRequest;
057: import javax.servlet.http.HttpServletResponse;
058: import java.io.IOException;
059: import java.io.InputStream;
060: import java.io.ObjectInputStream;
061: import java.io.ObjectOutputStream;
062: import java.net.MalformedURLException;
063: import java.net.URL;
064: import java.net.URLConnection;
065: import java.util.ArrayList;
066: import java.util.Collections;
067: import java.util.Enumeration;
068: import java.util.HashMap;
069: import java.util.Map;
070: import java.util.Iterator;
071:
072: /**
073: * ActionServlet that automatically registers requested Struts modules based on a set of module configuration file
074: * locators. The user may specify {@link ModuleConfigLocator} classes in /WEB-INF/beehive-netui-config.xml using the
075: * <code><module-config-locators></code> element.
076: */
077: public class AutoRegisterActionServlet extends ActionServlet {
078: /**
079: * @deprecated To register {@link ModuleConfigLocator}s, use the <code>module-config-locators</code> element
080: * in <code>pageflow-config</code> of /WEB-INF/netui-config.xml.
081: */
082: public static String MODULE_CONFIG_LOCATOR_CLASS_ATTR = "moduleConfigLocators";
083:
084: private static final Logger _log = Logger
085: .getInstance(AutoRegisterActionServlet.class);
086:
087: private static final ModuleConfig NONEXISTANT_MODULE_CONFIG = new NonexistantModuleConfig();
088:
089: /** Map of module-path to ModuleConfig */
090: private Map/*< String, ModuleConfig >*/_registeredModules = new InternalConcurrentHashMap/*< String, ModuleConfig >*/();
091:
092: private transient Digester _cachedConfigDigester = null;
093: private Map _configParams = null;
094: private ModuleConfigLocator[] _moduleConfigLocators = null;
095: private ReloadableClassHandler _rch;
096:
097: public void init() throws ServletException {
098: _rch = Handlers.get(getServletContext())
099: .getReloadableClassHandler();
100: setupModuleConfigLocators();
101: super .init();
102: }
103:
104: private void setupModuleConfigLocators() {
105: ModuleConfigLocator[] defaultLocators = getDefaultModuleConfigLocators();
106: ArrayList/*< ModuleConfigLocator >*/locators = new ArrayList/*< ModuleConfigLocator >*/();
107:
108: for (int i = 0; i < defaultLocators.length; ++i) {
109: locators.add(defaultLocators[i]);
110: }
111:
112: //
113: // Look for ModuleConfigLocators in beehive-netui-config.xml.
114: //
115: PageFlowConfig pfConfig = ConfigUtil.getConfig()
116: .getPageFlowConfig();
117:
118: if (pfConfig != null) {
119: ModuleConfigLocatorConfig[] mcLocators = pfConfig
120: .getModuleConfigLocators();
121:
122: if (mcLocators != null) {
123: for (int i = 0; i < mcLocators.length; i++) {
124: addModuleConfigLocator(mcLocators[i]
125: .getLocatorClass().trim(), locators);
126: }
127: }
128: }
129:
130: //
131: // Look for ModuleConfigLocators specified in web.xml (deprecated method for specifying them).
132: //
133: String configLocatorList = getServletConfig().getInitParameter(
134: MODULE_CONFIG_LOCATOR_CLASS_ATTR);
135:
136: if (configLocatorList != null) {
137: if (_log.isWarnEnabled()) {
138: _log
139: .warn("Found module-config-locators list in context-parameter "
140: + MODULE_CONFIG_LOCATOR_CLASS_ATTR
141: + ", which is deprecated. Please use the <module-config-locators> element in "
142: + InternalConstants.NETUI_CONFIG_PATH
143: + " instead.");
144: }
145:
146: String[] configLocatorClassNames = configLocatorList
147: .split(",");
148:
149: for (int i = 0; i < configLocatorClassNames.length; ++i) {
150: addModuleConfigLocator(configLocatorClassNames[i]
151: .trim(), locators);
152: }
153: }
154:
155: _moduleConfigLocators = (ModuleConfigLocator[]) locators
156: .toArray(new ModuleConfigLocator[locators.size()]);
157: }
158:
159: private static void addModuleConfigLocator(String locatorClassName,
160: ArrayList/*< ModuleConfigLocator >*/locators) {
161: try {
162: Class locatorClass = DiscoveryUtils.loadImplementorClass(
163: locatorClassName, ModuleConfigLocator.class);
164:
165: if (locatorClass != null) // previous call will log an error if it can't find the class
166: {
167: ModuleConfigLocator locator = (ModuleConfigLocator) locatorClass
168: .newInstance();
169: locators.add(locator);
170: }
171: } catch (IllegalAccessException e) {
172: _log.error(
173: "Could not create an instance of specified module-config-locator "
174: + locatorClassName, e);
175: } catch (InstantiationException e) {
176: _log.error(
177: "Could not create an instance of specified module-config-locator "
178: + locatorClassName, e);
179: }
180: }
181:
182: /**
183: * Get the base list of ModuleConfigLocators, to specify locations for auto-registered Struts modules. By default,
184: * this list is empty; derived classes may override to provide locators, or the user may specify them using
185: * the "moduleConfigLocators" init-parameter. When an unrecognized Struts module is requested, each registered
186: * ModuleConfigLocator is queried for a possible path to the configuration file for the module. If the
187: * configuration file is found, the module is auto-registered against the file.
188: */
189: protected ModuleConfigLocator[] getDefaultModuleConfigLocators() {
190: return new ModuleConfigLocator[0];
191: }
192:
193: /**
194: * Get the current list of registered ModuleConfigLocators.
195: *
196: * @return an array of registered ModuleConfigLocators.
197: * @see #getDefaultModuleConfigLocators
198: */
199: public ModuleConfigLocator[] getModuleConfigLocators() {
200: return _moduleConfigLocators;
201: }
202:
203: /**
204: * Interface for specifying alternate locations for auto-registered Struts modules.
205: *
206: * @see AutoRegisterActionServlet#getDefaultModuleConfigLocators
207: */
208: public static interface ModuleConfigLocator {
209: /**
210: * Get the webapp-relative path to a Struts module config file, based on the module name.
211: *
212: * @param moduleName the name of the Struts module, e.g., "someModule" or "some/other/module".
213: * @return the webapp-relative path the the Struts module config file.
214: */
215: public String getModuleConfigPath(String moduleName);
216: }
217:
218: /**
219: * Get the webapp-relative path to the Struts module configration file for a given module path,
220: * based on registered ModuleConfigLocators.
221: *
222: * @param modulePath the Struts module path.
223: * @return a String that is the path to the Struts configuration file, relative to the web application root,
224: * or <code>null</code> if no appropriate configuration file is found.
225: * @see #getDefaultModuleConfigLocators
226: */
227: public String getModuleConfPath(String modulePath) {
228: if (_moduleConfigLocators != null) {
229: for (int i = 0; i < _moduleConfigLocators.length; ++i) {
230: ModuleConfigLocator locator = _moduleConfigLocators[i];
231: String moduleConfigPath = locator
232: .getModuleConfigPath(modulePath);
233:
234: try {
235: if (getConfigResource(moduleConfigPath) != null)
236: return moduleConfigPath;
237: } catch (MalformedURLException e) {
238: _log.error("ModuleConfigLocator "
239: + locator.getClass().getName()
240: + " returned an invalid path: "
241: + moduleConfigPath + '.', e);
242: }
243: }
244: }
245:
246: return null;
247: }
248:
249: private boolean isAutoLoadModulePath(String modulePath,
250: String prefix) {
251: if (_moduleConfigLocators != null) {
252: for (int i = 0; i < _moduleConfigLocators.length; ++i) {
253: ModuleConfigLocator locator = _moduleConfigLocators[i];
254: if (modulePath.equals(locator
255: .getModuleConfigPath(prefix)))
256: return true;
257: }
258: }
259:
260: return false;
261: }
262:
263: //
264: // For cases where the servlet is serialized/deserialized, we'll hold onto ServletConfig
265: // attributes, since the ServletConfig reference is transient. Then, we'll return these
266: // cached values if necessary in getInitParameter(), getInitParameterNames().
267: //
268: private void writeObject(ObjectOutputStream stream)
269: throws IOException {
270: if (_log.isInfoEnabled()) {
271: _log.info("serializing ActionServlet " + this );
272: }
273:
274: if (_configParams != null) {
275: stream.writeObject(_configParams);
276: } else {
277: ServletConfig servletConfig = getServletConfig();
278: assert servletConfig != null;
279: HashMap params = new HashMap();
280:
281: for (Enumeration e = servletConfig.getInitParameterNames(); e
282: .hasMoreElements();) {
283: String name = (String) e.nextElement();
284: params.put(name, servletConfig.getInitParameter(name));
285: }
286:
287: stream.writeObject(params);
288: }
289: }
290:
291: // See comments on writeObject.
292: private void readObject(ObjectInputStream stream)
293: throws IOException, ClassNotFoundException {
294: if (_log.isInfoEnabled())
295: _log.info("deserializing ActionServlet " + this );
296: _configParams = (Map) stream.readObject();
297: }
298:
299: public String getInitParameter(String s) {
300: if (getServletConfig() == null) {
301: assert _configParams != null; // see comments on writeObject
302: return (String) _configParams.get(s);
303: }
304:
305: return super .getInitParameter(s);
306: }
307:
308: public Enumeration getInitParameterNames() {
309: if (getServletConfig() == null) {
310: assert _configParams != null; // see comments on writeObject
311: return Collections.enumeration(_configParams.keySet());
312: }
313:
314: return super .getInitParameterNames();
315: }
316:
317: /**
318: * This method is almost exactly the same as the base class initModuleConfig. The only difference
319: * is that it does not throw an UnavailableException if a module configuration file is missing or
320: * invalid.
321: */
322: protected ModuleConfig initModuleConfig(String prefix, String paths)
323: throws ServletException {
324:
325: if (_log.isDebugEnabled()) {
326: _log.debug("Initializing module path '" + prefix
327: + "' configuration from '" + paths + '\'');
328: }
329:
330: // Parse the configuration for this module
331: ModuleConfig moduleConfig = null;
332: InputStream input = null;
333: String mapping;
334:
335: try {
336: ModuleConfigFactory factoryObject = ModuleConfigFactory
337: .createFactory();
338: moduleConfig = factoryObject.createModuleConfig(prefix);
339:
340: // Support for module-wide ActionMapping type override
341: mapping = getServletConfig().getInitParameter("mapping");
342: if (mapping != null) {
343: moduleConfig.setActionMappingClass(mapping);
344: }
345:
346: // Configure the Digester instance we will use
347: Digester digester = initConfigDigester();
348:
349: // Process each specified resource path
350: while (paths.length() > 0) {
351: digester.push(moduleConfig);
352: String path;
353: int comma = paths.indexOf(',');
354: if (comma >= 0) {
355: path = paths.substring(0, comma).trim();
356: paths = paths.substring(comma + 1);
357: } else {
358: path = paths.trim();
359: paths = "";
360: }
361: if (path.length() < 1) {
362: break;
363: }
364:
365: URL url = getConfigResource(path);
366:
367: //
368: // THIS IS THE MAIN DIFFERENCE: we're doing a null-check here.
369: //
370: if (url != null) {
371: URLConnection conn = url.openConnection();
372: conn.setUseCaches(false);
373: InputStream in = conn.getInputStream();
374:
375: try {
376: InputSource is = new InputSource(in);
377: is.setSystemId(url.toString());
378: input = getConfigResourceAsStream(path);
379: is.setByteStream(input);
380:
381: // also, we're not letting it fail here either.
382: try {
383: digester.parse(is);
384: getServletContext().setAttribute(
385: Globals.MODULE_KEY + prefix,
386: moduleConfig);
387: } catch (Exception e) {
388: _log.error(Bundle.getString(
389: "PageFlow_Struts_ModuleParseError",
390: path), e);
391: }
392: input.close();
393: } finally {
394: in.close();
395: }
396: } else {
397: //
398: // Special case. If this is the default (root) module and the module path is one that's normally
399: // generated by the page flow compiler, then we don't want to error out if it's missing, since
400: // this probably just means that there's no root-level page flow. Set up a default, empty,
401: // module config.
402: //
403: if (prefix.equals("")
404: && isAutoLoadModulePath(path, prefix)) {
405: if (_log.isInfoEnabled()) {
406: _log
407: .info("There is no root module at "
408: + path
409: + "; initializing a default module.");
410: }
411:
412: //
413: // Set the ControllerConfig to a MissingRootModuleControllerConfig. This is used by
414: // PageFlowRequestProcessor.
415: //
416: moduleConfig
417: .setControllerConfig(new MissingRootModuleControllerConfig());
418: } else {
419: _log.error(Bundle.getString(
420: "PageFlow_Struts_MissingModuleConfig",
421: path));
422: }
423: }
424: }
425:
426: } catch (Throwable t) {
427: _log.error(internal.getMessage("configParse", paths), t);
428: throw new UnavailableException(internal.getMessage(
429: "configParse", paths));
430: } finally {
431: if (input != null) {
432: try {
433: input.close();
434: } catch (IOException e) {
435: // ignore
436: }
437: }
438: }
439:
440: // Force creation and registration of DynaActionFormClass instances
441: // for all dynamic form beans we will be using
442: FormBeanConfig fbs[] = moduleConfig.findFormBeanConfigs();
443: for (int i = 0; i < fbs.length; i++) {
444: if (fbs[i].getDynamic()) {
445: DynaActionFormClass.createDynaActionFormClass(fbs[i]);
446: }
447: }
448:
449: // Special handling for the default module (for
450: // backwards compatibility only, will be removed later)
451: if (prefix.length() < 1) {
452: defaultControllerConfig(moduleConfig);
453: defaultMessageResourcesConfig(moduleConfig);
454: }
455:
456: // Return the completed configuration object
457: //config.freeze(); // Now done after plugins init
458: return moduleConfig;
459:
460: }
461:
462: static class MissingRootModuleControllerConfig extends
463: ControllerConfig {
464: public MissingRootModuleControllerConfig() {
465: setProcessorClass(PageFlowRequestProcessor.class.getName());
466: }
467: }
468:
469: /**
470: * Get a resource URL for a module configuration file. By default, this looks in the ServletContext
471: * and in the context classloader.
472: *
473: * @param path the path to the resource.
474: * @return an URL for the resource, or <code>null</code> if the resource is not found.
475: * @throws MalformedURLException
476: */
477: protected URL getConfigResource(String path)
478: throws MalformedURLException {
479: URL resource = getServletContext().getResource(path);
480: if (resource != null)
481: return resource;
482: if (path.startsWith("/"))
483: path = path.substring(1);
484: return _rch.getResource(path);
485: }
486:
487: /**
488: * Get a resource stream for a module configuration file. By default, this looks in the ServletContext
489: * and in the context classloader.
490: *
491: * @param path the path to the resource.
492: * @return an InputStream for the resource, or <code>null</code> if the resource is not found.
493: */
494: protected InputStream getConfigResourceAsStream(String path) {
495: InputStream stream = getServletContext().getResourceAsStream(
496: path);
497: if (stream != null)
498: return stream;
499: if (path.startsWith("/"))
500: path = path.substring(1);
501: return _rch.getResourceAsStream(path);
502: }
503:
504: /**
505: * Register a Struts module, initialized by the given configuration file.
506: *
507: * @param modulePath the module path, starting at the webapp root, e.g., "/info/help".
508: * @param configFilePath the path, starting at the webapp root, to the module configuration
509: * file (e.g., "/WEB-INF/my-generated-struts-config-info-help.xml").
510: * @return the Struts ModuleConfig that was initialized.
511: */
512: protected synchronized ModuleConfig registerModule(
513: String modulePath, String configFilePath)
514: throws ServletException {
515: if (_log.isInfoEnabled()) {
516: _log.info("Dynamically registering module " + modulePath
517: + ", config XML " + configFilePath);
518: }
519:
520: if (_log.isInfoEnabled()) {
521: InternalStringBuilder msg = new InternalStringBuilder(
522: "Dynamically registering module ")
523: .append(modulePath);
524: _log.info(msg.append(", config XML ")
525: .append(configFilePath).toString());
526: }
527:
528: if (_cachedConfigDigester == null) {
529: _cachedConfigDigester = initConfigDigester();
530: }
531:
532: configDigester = _cachedConfigDigester;
533: ModuleConfig ac = initModuleConfig(modulePath, configFilePath);
534: initModuleMessageResources(ac);
535: initModuleDataSources(ac);
536: initModulePlugIns(ac);
537: ac.freeze();
538: configDigester = null;
539:
540: // If this is a FlowController module, make a callback to the event reporter.
541: ControllerConfig cc = ac.getControllerConfig();
542: if (cc instanceof PageFlowControllerConfig) {
543: PageFlowControllerConfig pfcc = (PageFlowControllerConfig) cc;
544: PageFlowEventReporter er = AdapterManager
545: .getServletContainerAdapter(getServletContext())
546: .getEventReporter();
547: er.flowControllerRegistered(modulePath, pfcc
548: .getControllerClass(), ac);
549: }
550:
551: // Initialize any delegating action configs or exception handler configs.
552: InternalUtils.initDelegatingConfigs(ac, getServletContext());
553:
554: if (_log.isDebugEnabled()) {
555: _log.debug("Finished registering module " + modulePath
556: + ", config XML " + configFilePath);
557: }
558:
559: return ac;
560: }
561:
562: /**
563: * This override of the base class process() registers a Struts module on the fly if the
564: * config file can be found in our standard place (named in our standard way), regardless
565: * of whether the module is configured in web.xml.
566: */
567: protected void process(HttpServletRequest request,
568: HttpServletResponse response) throws IOException,
569: ServletException {
570: //
571: // First wrap the request with an object that contains request-scoped values that our runtime uses. This
572: // is faster than sticking everything into attributes on the request (then basically reading from a HashMap).
573: //
574: PageFlowRequestWrapper requestWrapper = PageFlowRequestWrapper
575: .wrapRequest(request);
576: request = requestWrapper;
577:
578: ServletContext servletContext = getServletContext();
579: String modulePath = PageFlowUtils
580: .getModulePathForRelativeURI(InternalUtils
581: .getDecodedServletPath(request));
582: ModuleConfig registeredApp;
583:
584: //
585: // Get the registered Struts module for the request.
586: //
587: registeredApp = getModuleConfig(modulePath, request, response);
588:
589: //
590: // If we've dynamically registered a module, then we need to override the base process() behavior to select the
591: // module. Note that we don't want to synchronize the call to process().
592: //
593: if (registeredApp != null) {
594: //
595: // Try to select the appropriate Struts module and delegate to its RequestProcessor.
596: //
597: ModuleConfig moduleConfig = InternalUtils.selectModule(
598: modulePath, request, servletContext);
599:
600: // If this module came from an abstract page flow controller class, send an error.
601: ControllerConfig cc = moduleConfig.getControllerConfig();
602: if (cc instanceof PageFlowControllerConfig
603: && ((PageFlowControllerConfig) cc).isAbstract()) {
604: InternalUtils.sendDevTimeError(
605: "PageFlow_AbstractPageFlow", null,
606: HttpServletResponse.SC_NOT_FOUND, request,
607: response, servletContext,
608: new Object[] { modulePath });
609: return;
610: }
611:
612: RequestProcessor requestProcessor = getRequestProcessor(moduleConfig);
613: requestProcessor.process(request, response);
614: } else {
615: //
616: // Here, we're checking to see if this was a module that was registered externally by Struts (not by this
617: // servlet). This is the same as the base process() behavior, but it checks for a missing
618: // module-configuration.
619: //
620: ModuleConfig moduleConfig = null;
621:
622: if (InternalUtils.getModuleConfig(RequestUtils
623: .getModuleName(request, servletContext),
624: servletContext) != null) {
625: String modulePrefix = RequestUtils.getModuleName(
626: request, servletContext);
627: moduleConfig = InternalUtils.selectModule(modulePrefix,
628: request, servletContext);
629: }
630:
631: String servletPath = InternalUtils
632: .getDecodedServletPath(request);
633: RequestProcessor rp = moduleConfig != null ? getRequestProcessor(moduleConfig)
634: : null;
635:
636: if (rp != null
637: && moduleCanHandlePath(moduleConfig, rp,
638: servletPath)) {
639: rp.process(request, response);
640: } else {
641: //
642: // Initialize the ServletContext in the request. Often, we need access to the ServletContext when we only
643: // have a ServletRequest.
644: //
645: InternalUtils.setServletContext(request,
646: getServletContext());
647:
648: if (processUnhandledAction(request, response,
649: servletPath))
650: return;
651:
652: String originalServletPath = requestWrapper
653: .getOriginalServletPath();
654: if (originalServletPath != null) {
655: servletPath = originalServletPath;
656: modulePath = PageFlowUtils
657: .getModulePathForRelativeURI(originalServletPath);
658: }
659:
660: if (_log.isErrorEnabled()) {
661: InternalStringBuilder msg = new InternalStringBuilder(
662: "No module configuration registered for ");
663: msg.append(servletPath).append(" (module path ")
664: .append(modulePath).append(").");
665: _log.error(msg.toString());
666: }
667:
668: //
669: // If we're not in production mode, send a diagnostic on the response; otherwise, simply send a 404.
670: //
671: if (modulePath.length() == 0)
672: modulePath = "/";
673: InternalUtils.sendDevTimeError("PageFlow_NoModuleConf",
674: null, HttpServletResponse.SC_NOT_FOUND,
675: request, response, servletContext,
676: new Object[] { servletPath, modulePath });
677: }
678: }
679: }
680:
681: /**
682: * Tell whether the given module can handle the given path. By default, this is always true.
683: */
684: protected boolean moduleCanHandlePath(ModuleConfig moduleConfig,
685: RequestProcessor rp, String servletPath) {
686: return true;
687: }
688:
689: /**
690: * @exclude
691: */
692: protected Digester initConfigDigester() throws ServletException {
693: _cachedConfigDigester = super .initConfigDigester();
694: return _cachedConfigDigester;
695: }
696:
697: public void destroy() {
698: _registeredModules.clear();
699: super .destroy();
700: }
701:
702: /**
703: * Get the Struts ModuleConfig for the given module path.
704: * @deprecated Use {@link #ensureModuleRegistered} instead.
705: *
706: * @param modulePath the module path, from the request URI.
707: * @param request the current ServletRequest
708: * @param response the current HttpServletResponse
709: * @return the Struts ModuleConfig that corresponds with <code>modulePath</code>
710: * @throws IOException
711: * @throws ServletException
712: */
713: protected ModuleConfig getModuleConfig(String modulePath,
714: ServletRequest request, ServletResponse response)
715: throws IOException, ServletException {
716: return ensureModuleRegistered(modulePath);
717: }
718:
719: /**
720: * Ensures that the Struts module for the given path is registered (dynamically, if necessary).
721: * @deprecated Use #ensureModuleRegistered(String) instead.
722: *
723: * @param modulePath the module path, from the request URI.
724: * @param request the current ServletRequest
725: * @throws IOException
726: * @throws ServletException
727: */
728: public ModuleConfig ensureModuleRegistered(String modulePath,
729: ServletRequest request) throws IOException,
730: ServletException {
731: return ensureModuleRegistered(modulePath);
732: }
733:
734: public ModuleConfig ensureModuleRegistered(String modulePath)
735: throws IOException, ServletException {
736: //
737: // Dynamically register the Struts module, if appropriate. If we've already
738: // tried to register it (_registeredModules.containsKey( modulePath )), don't
739: // try again.
740: //
741: // Note that two threads could potentially get in here at the same time, and
742: // both will register the module. This is OK -- reads from _registeredModules
743: // are consistent, and the worst that will happen is that the module will get
744: // registered with a valid ModuleConfig a few times.
745: //
746: ModuleConfig mc = (ModuleConfig) _registeredModules
747: .get(modulePath);
748:
749: if (mc == null) {
750: //
751: // See if there's an explicit initialization for this module in
752: // the webapp configuration. If there is, we'll use that.
753: //
754: mc = (ModuleConfig) getServletContext().getAttribute(
755: Globals.MODULE_KEY + modulePath);
756:
757: if (mc == null) {
758: //
759: // If we find the Struts config file for this module, we can dynamically
760: // register it.
761: //
762: String moduleConfPath = getModuleConfPath(modulePath);
763:
764: if (moduleConfPath != null) {
765: mc = registerModule(modulePath, moduleConfPath);
766: }
767: }
768:
769: if (mc == null) {
770: _registeredModules.put(modulePath,
771: NONEXISTANT_MODULE_CONFIG);
772: // ConcurrentHashMap doesn't allow null values
773: return null;
774: } else {
775: _registeredModules.put(modulePath, mc);
776: getServletContext().setAttribute(
777: Globals.MODULE_KEY + modulePath, mc);
778: return mc;
779: }
780: } else {
781: if (mc.getPrefix() == null) {
782: assert mc instanceof NonexistantModuleConfig : mc
783: .getClass().getName();
784: return null;
785: }
786:
787: return mc;
788: }
789: }
790:
791: private static class NonexistantModuleConfig extends
792: ModuleConfigImpl {
793: public NonexistantModuleConfig() {
794: super (null);
795: }
796: }
797:
798: //-----------------------------------------------------------------------------------------------------------
799: // The following methods (defaultControllerConfig, defaultMessageResourcesConfig, defaultFormBeansConfig,
800: // defaultForwardsConfig, defaultMappingsConfig) were copied straight from the Struts ActionServlet.java
801: // (they're private, not protected).
802:
803: /**
804: * Perform backwards-compatible configuration of the default module's
805: * controller configuration from servlet initialization parameters (as
806: * were used in Struts 1.0).
807: *
808: * @param config The ModuleConfig object for the default module
809: *
810: * @since Struts 1.1
811: * @deprecated Will be removed in a release after Struts 1.1.
812: */
813: private void defaultControllerConfig(ModuleConfig config) {
814:
815: String value = null;
816: ControllerConfig cc = config.getControllerConfig();
817:
818: value = getServletConfig().getInitParameter("bufferSize");
819: if (value != null) {
820: cc.setBufferSize(Integer.parseInt(value));
821: }
822:
823: value = getServletConfig().getInitParameter("content");
824: if (value != null) {
825: cc.setContentType(value);
826: }
827:
828: value = getServletConfig().getInitParameter("locale");
829: // must check for null here
830: if (value != null) {
831: if ("true".equalsIgnoreCase(value)
832: || "yes".equalsIgnoreCase(value)) {
833: cc.setLocale(true);
834: } else {
835: cc.setLocale(false);
836: }
837: }
838:
839: value = getServletConfig().getInitParameter("maxFileSize");
840: if (value != null) {
841: cc.setMaxFileSize(value);
842: }
843:
844: value = getServletConfig().getInitParameter("nocache");
845: if (value != null) {
846: if ("true".equalsIgnoreCase(value)
847: || "yes".equalsIgnoreCase(value)) {
848: cc.setNocache(true);
849: } else {
850: cc.setNocache(false);
851: }
852: }
853:
854: value = getServletConfig().getInitParameter("multipartClass");
855: if (value != null) {
856: cc.setMultipartClass(value);
857: }
858:
859: value = getServletConfig().getInitParameter("tempDir");
860: if (value != null) {
861: cc.setTempDir(value);
862: }
863:
864: }
865:
866: /**
867: * Perform backwards-compatible configuration of the default module's
868: * message resources configuration from servlet initialization parameters
869: * (as were used in Struts 1.0).
870: *
871: * @param config The ModuleConfig object for the default module
872: *
873: * @since Struts 1.1
874: * @deprecated Will be removed in a release after Struts 1.1.
875: */
876: private void defaultMessageResourcesConfig(ModuleConfig config) {
877:
878: String value = null;
879:
880: MessageResourcesConfig mrc = config
881: .findMessageResourcesConfig(Globals.MESSAGES_KEY);
882: if (mrc == null) {
883: mrc = new MessageResourcesConfig();
884: mrc.setKey(Globals.MESSAGES_KEY);
885: config.addMessageResourcesConfig(mrc);
886: }
887: value = getServletConfig().getInitParameter("application");
888: if (value != null) {
889: mrc.setParameter(value);
890: }
891: value = getServletConfig().getInitParameter("factory");
892: if (value != null) {
893: mrc.setFactory(value);
894: }
895: value = getServletConfig().getInitParameter("null");
896: if (value != null) {
897: if (value.equalsIgnoreCase("true")
898: || value.equalsIgnoreCase("yes")) {
899: mrc.setNull(true);
900: } else {
901: mrc.setNull(false);
902: }
903: }
904: }
905:
906: /**
907: * Clear the internal map of registered modules.
908: *
909: * @exclude
910: */
911: public void clearRegisteredModules() {
912: ServletContext servletContext = getServletContext();
913:
914: for (Iterator ii = _registeredModules.keySet().iterator(); ii
915: .hasNext();) {
916: String modulePrefix = (String) ii.next();
917: servletContext.removeAttribute(Globals.MODULE_KEY
918: + modulePrefix);
919: servletContext
920: .removeAttribute(Globals.REQUEST_PROCESSOR_KEY
921: + modulePrefix);
922: }
923:
924: _registeredModules.clear();
925: }
926:
927: /**
928: * Last chance to handle an unhandled action URI.
929: * @return <code>true</code> if this method handled it (by forwarding somewhere or writing to the response).
930: */
931: protected boolean processUnhandledAction(
932: HttpServletRequest request, HttpServletResponse response,
933: String uri) throws IOException, ServletException {
934: return false;
935: }
936: }
|