0001: /*
0002: * Licensed to the Apache Software Foundation (ASF) under one or more
0003: * contributor license agreements. See the NOTICE file distributed with
0004: * this work for additional information regarding copyright ownership.
0005: * The ASF licenses this file to You under the Apache License, Version 2.0
0006: * (the "License"); you may not use this file except in compliance with
0007: * the License. You may obtain a copy of the License at
0008: *
0009: * http://www.apache.org/licenses/LICENSE-2.0
0010: *
0011: * Unless required by applicable law or agreed to in writing, software
0012: * distributed under the License is distributed on an "AS IS" BASIS,
0013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014: * See the License for the specific language governing permissions and
0015: * limitations under the License.
0016: *
0017: * $Header:$
0018: */
0019: package org.apache.beehive.netui.pageflow.internal;
0020:
0021: import org.apache.beehive.netui.util.internal.InternalStringBuilder;
0022:
0023: import org.apache.beehive.netui.pageflow.*;
0024: import org.apache.beehive.netui.pageflow.config.PageFlowActionMapping;
0025: import org.apache.beehive.netui.pageflow.config.PageFlowControllerConfig;
0026: import org.apache.beehive.netui.pageflow.config.PageFlowActionFormBean;
0027: import org.apache.beehive.netui.pageflow.config.DelegatingActionMapping;
0028: import org.apache.beehive.netui.pageflow.config.DelegatingExceptionConfig;
0029: import org.apache.beehive.netui.pageflow.handler.Handlers;
0030: import org.apache.beehive.netui.pageflow.handler.ReloadableClassHandler;
0031: import org.apache.beehive.netui.pageflow.handler.StorageHandler;
0032: import org.apache.beehive.netui.pageflow.scoping.ScopedServletUtils;
0033: import org.apache.beehive.netui.util.Bundle;
0034: import org.apache.beehive.netui.util.internal.ServletUtils;
0035: import org.apache.beehive.netui.util.config.ConfigUtil;
0036: import org.apache.beehive.netui.util.config.bean.MultipartHandler;
0037: import org.apache.beehive.netui.util.config.bean.PageFlowConfig;
0038: import org.apache.beehive.netui.util.logging.Logger;
0039: import org.apache.struts.Globals;
0040: import org.apache.struts.util.MessageResources;
0041: import org.apache.struts.action.*;
0042: import org.apache.struts.config.ActionConfig;
0043: import org.apache.struts.config.ControllerConfig;
0044: import org.apache.struts.config.FormBeanConfig;
0045: import org.apache.struts.config.ModuleConfig;
0046: import org.apache.struts.config.MessageResourcesConfig;
0047: import org.apache.struts.config.ExceptionConfig;
0048: import org.apache.struts.upload.MultipartRequestWrapper;
0049:
0050: import javax.servlet.ServletContext;
0051: import javax.servlet.ServletException;
0052: import javax.servlet.ServletRequest;
0053: import javax.servlet.ServletResponse;
0054: import javax.servlet.jsp.JspContext;
0055: import javax.servlet.jsp.PageContext;
0056: import javax.servlet.http.HttpServletRequest;
0057: import javax.servlet.http.HttpServletResponse;
0058: import javax.servlet.http.HttpSession;
0059: import java.io.IOException;
0060: import java.lang.reflect.Field;
0061: import java.lang.reflect.Method;
0062: import java.util.HashMap;
0063: import java.util.Iterator;
0064: import java.util.LinkedHashMap;
0065: import java.util.Map;
0066: import java.util.Locale;
0067:
0068: public class InternalUtils implements PageFlowConstants,
0069: InternalConstants {
0070: private static final Logger _log = Logger
0071: .getInstance(InternalUtils.class);
0072:
0073: private static final String BEA_XMLOBJECT_CLASSNAME = "com.bea.xml.XmlObject";
0074: private static final String APACHE_XMLOBJECT_CLASSNAME = "org.apache.xmlbeans.XmlObject";
0075: private static final Class BEA_XMLOBJECT_CLASS = loadClassNonFatal(BEA_XMLOBJECT_CLASSNAME);
0076: private static final Class APACHE_XMLOBJECT_CLASS = loadClassNonFatal(APACHE_XMLOBJECT_CLASSNAME);
0077: private static final String LONGLIVED_PAGEFLOWS_ATTR_PREFIX = ATTR_PREFIX
0078: + "longLivedPageFlow:";
0079: private static final String ACTIONOUTPUT_MAP_ATTR = ATTR_PREFIX
0080: + "actionOutputs";
0081: private static final String BINDING_UPDATE_ERRORS_ATTR = ATTR_PREFIX
0082: + "bindingUpdateErrors";
0083: private static final String SHARED_FLOW_CLASSNAME_ATTR = ATTR_PREFIX
0084: + "sharedFlowClass";
0085: private static final String SERVLET_CONTEXT_ATTR = ATTR_PREFIX
0086: + "servletContext";
0087: private static final String AVOID_DIRECT_RESPONSE_OUTPUT_ATTR = ATTR_PREFIX
0088: + "_avoidDirectResponseOutput";
0089: private static final String FORWARDED_FORMBEAN_ATTR = ATTR_PREFIX
0090: + "forwardedForm";
0091: private static final String FORWARDING_MODULE_ATTR = ATTR_PREFIX
0092: + "fwdModule";
0093: private static final String IGNORE_INCLUDE_SERVLET_PATH_ATTR = ATTR_PREFIX
0094: + "ignoreIncludeServletPath";
0095:
0096: /**
0097: * If not in production mode, write an error to the response; otherwise, set a response error code.
0098: */
0099: public static void sendDevTimeError(String messageKey,
0100: Throwable cause, int productionTimeErrorCode,
0101: ServletRequest request, ServletResponse response,
0102: ServletContext servletContext, Object[] messageArgs)
0103: throws IOException {
0104: sendDevTimeError(messageKey, messageArgs, cause,
0105: productionTimeErrorCode, request, response,
0106: servletContext);
0107: }
0108:
0109: /**
0110: * If not in production mode, write an error to the response; otherwise, set a response error code.
0111: * @deprecated Use {@link #sendDevTimeError(String, Throwable, int, ServletRequest, ServletResponse, ServletContext, Object[])}
0112: */
0113: public static void sendDevTimeError(String messageKey,
0114: Object[] messageArgs, Throwable cause,
0115: int productionTimeErrorCode, ServletRequest request,
0116: ServletResponse response, ServletContext servletContext)
0117: throws IOException {
0118: boolean prodMode = AdapterManager.getServletContainerAdapter(
0119: servletContext).isInProductionMode();
0120: boolean avoidDirectResponseOutput = avoidDirectResponseOutput(request);
0121:
0122: if (prodMode && !avoidDirectResponseOutput
0123: && response instanceof HttpServletResponse) {
0124: if (_log.isErrorEnabled()) {
0125: _log.error("Error (message key " + messageKey
0126: + ") occurred. Response error was set to "
0127: + productionTimeErrorCode, cause);
0128: }
0129:
0130: ((HttpServletResponse) response)
0131: .sendError(productionTimeErrorCode);
0132: } else {
0133: sendError(messageKey, messageArgs, request, response,
0134: cause, prodMode || avoidDirectResponseOutput);
0135: }
0136: }
0137:
0138: /**
0139: * Write an error to the response.
0140: */
0141: public static void sendError(String messageKey, Throwable cause,
0142: ServletRequest request, HttpServletResponse response,
0143: Object[] messageArgs) throws IOException {
0144: // TODO: the following null check will be unnecessary once the deprecated
0145: // FlowController.sendError(String, HttpServletResponse) is removed.
0146: boolean avoidDirectResponseOutput = request != null ? avoidDirectResponseOutput(request)
0147: : false;
0148: sendError(messageKey, messageArgs, request, response, cause,
0149: avoidDirectResponseOutput);
0150: }
0151:
0152: /**
0153: * Write an error to the response.
0154: */
0155: public static void sendError(String messageKey,
0156: Object[] messageArgs, ServletRequest request,
0157: ServletResponse response, Throwable cause,
0158: boolean avoidDirectResponseOutput) throws IOException {
0159: assert messageArgs.length == 0
0160: || !(messageArgs[0] instanceof Object[]) : "Object[] passed to sendError; this is probably a mistaken use of varargs";
0161:
0162: // request may be null because of deprecated FlowController.sendError().
0163: if (request != null && avoidDirectResponseOutput) {
0164: String baseMessage = Bundle.getString(messageKey
0165: + "_Message", messageArgs);
0166: throw new ResponseOutputException(baseMessage, cause);
0167: }
0168:
0169: // Filter the message args to prevent cross-site scripting (XSS) attacks (e.g., if one of the args is something
0170: // that ultimately came from the user request, and it contains something like <script>[some sscript]</script>.
0171: for (int i = 0; i < messageArgs.length; i++) {
0172: Object messageArg = messageArgs[i];
0173: messageArgs[i] = messageArg != null ? filterValue(messageArg
0174: .toString())
0175: : null;
0176: }
0177:
0178: String html = Bundle.getString(messageKey + "_Page",
0179: messageArgs);
0180: response.setContentType("text/html;charset=UTF-8");
0181: response.getWriter().println(html);
0182: ServletUtils.preventCache(response);
0183: }
0184:
0185: /**
0186: * Filter output to prevent cross-site scripting (XSS) attacks.
0187: */
0188: private static String filterValue(String value) throws IOException {
0189: InternalStringBuilder result = new InternalStringBuilder(value
0190: .length());
0191:
0192: for (int i = 0; i < value.length(); ++i) {
0193: char c = value.charAt(i);
0194: switch (c) {
0195: case '<':
0196: result.append("<");
0197: break;
0198: case '>':
0199: result.append(">");
0200: break;
0201: case '&':
0202: result.append("&");
0203: break;
0204: default:
0205: result.append(c);
0206: }
0207: }
0208:
0209: return result.toString();
0210: }
0211:
0212: /**
0213: * We unwrap two special form types: XmlBeanActionForm and AnyBeanActionForm.
0214: */
0215: // TODO: make this pluggable
0216: public static Object unwrapFormBean(ActionForm form) {
0217: if (form == null)
0218: return null;
0219:
0220: if (form instanceof AnyBeanActionForm) {
0221: return ((AnyBeanActionForm) form).getBean();
0222: }
0223:
0224: return form;
0225: }
0226:
0227: public static ActionForm wrapFormBean(Object formBean) {
0228: if (formBean == null)
0229: return null;
0230:
0231: if (formBean instanceof ActionForm) {
0232: return (ActionForm) formBean;
0233: } else {
0234: Class formClass = formBean.getClass();
0235:
0236: if (BEA_XMLOBJECT_CLASS != null
0237: && BEA_XMLOBJECT_CLASS.isAssignableFrom(formClass)) {
0238: return new XmlBeanActionForm(formBean);
0239: } else if (APACHE_XMLOBJECT_CLASS != null
0240: && APACHE_XMLOBJECT_CLASS
0241: .isAssignableFrom(formClass)) {
0242: return new XmlBeanActionForm(formBean);
0243: }
0244:
0245: return new AnyBeanActionForm(formBean);
0246: }
0247: }
0248:
0249: private static Class loadClassNonFatal(String className) {
0250: try {
0251: return Class.forName(className);
0252: } catch (ClassNotFoundException e) {
0253: // Not fatal -- we don't require this to be there. Only if the user wants to use it.
0254:
0255: if (_log.isDebugEnabled()) {
0256: _log.debug("Could not load class " + className);
0257: }
0258: }
0259:
0260: return null;
0261: }
0262:
0263: /**
0264: * Get a Method in a Class.
0265: *
0266: * @param parentClass the Class in which to find the Method.
0267: * @param methodName the name of the Method.
0268: * @param signature the argument types for the Method.
0269: * @return the Method with the given name and signature, or <code>null</code> if the method does not exist.
0270: */
0271: public static Method lookupMethod(Class parentClass,
0272: String methodName, Class[] signature) {
0273: try {
0274: return parentClass.getDeclaredMethod(methodName, signature);
0275: } catch (NoSuchMethodException e) {
0276: Class super Class = parentClass.getSuperclass();
0277: return super Class != null ? lookupMethod(super Class,
0278: methodName, signature) : null;
0279: }
0280: }
0281:
0282: /**
0283: * Get a Field in a Class.
0284: *
0285: * @param parentClass the Class in which to find the Field.
0286: * @param fieldName the name of the Field.
0287: * @return the Field with the given name, or <code>null</code> if the field does not exist.
0288: */
0289: public static Field lookupField(Class parentClass, String fieldName) {
0290: try {
0291: return parentClass.getDeclaredField(fieldName);
0292: } catch (NoSuchFieldException e) {
0293: Class super Class = parentClass.getSuperclass();
0294: return super Class != null ? lookupField(super Class,
0295: fieldName) : null;
0296: }
0297: }
0298:
0299: public static String getFlowControllerClassName(String modulePath,
0300: ServletRequest request, ServletContext context) {
0301: //
0302: // We're going to look in the struts config to get the PageFlowController class.
0303: //
0304: ModuleConfig mc = ensureModuleConfig(modulePath, context);
0305: return mc != null ? getFlowControllerClassName(mc) : null;
0306: }
0307:
0308: public static String getFlowControllerClassName(ModuleConfig mc) {
0309: ControllerConfig cc = mc.getControllerConfig();
0310: return cc instanceof PageFlowControllerConfig ? ((PageFlowControllerConfig) cc)
0311: .getControllerClass()
0312: : null;
0313: }
0314:
0315: /**
0316: * Tell whether the given module is a long-lived page flow.
0317: */
0318: public static boolean isLongLived(ModuleConfig moduleConfig) {
0319: ControllerConfig cc = moduleConfig.getControllerConfig();
0320:
0321: if (cc instanceof PageFlowControllerConfig) {
0322: return ((PageFlowControllerConfig) cc)
0323: .isLongLivedPageFlow();
0324: } else {
0325: return false;
0326: }
0327: }
0328:
0329: /**
0330: * Tell whether the given module is a nested page flow.
0331: */
0332: public static boolean isNestable(ModuleConfig moduleConfig) {
0333: ControllerConfig cc = moduleConfig.getControllerConfig();
0334: return cc instanceof PageFlowControllerConfig
0335: && ((PageFlowControllerConfig) cc).isNestedPageFlow();
0336: }
0337:
0338: public static String getLongLivedFlowAttr(String modulePath) {
0339: return LONGLIVED_PAGEFLOWS_ATTR_PREFIX + modulePath;
0340: }
0341:
0342: public static void setCurrentPageFlow(PageFlowController jpf,
0343: HttpServletRequest request, ServletContext servletContext) {
0344: setCurrentActionResolver(jpf, request, servletContext);
0345: }
0346:
0347: public static void removeCurrentPageFlow(
0348: HttpServletRequest request, ServletContext servletContext) {
0349: StorageHandler sh = Handlers.get(servletContext)
0350: .getStorageHandler();
0351: HttpServletRequest unwrappedRequest = PageFlowUtils
0352: .unwrapMultipart(request);
0353: RequestContext rc = new RequestContext(unwrappedRequest, null);
0354: String currentJpfAttrName = ScopedServletUtils
0355: .getScopedSessionAttrName(CURRENT_JPF_ATTR,
0356: unwrappedRequest);
0357: String currentLongLivedAttrName = ScopedServletUtils
0358: .getScopedSessionAttrName(CURRENT_LONGLIVED_ATTR,
0359: unwrappedRequest);
0360:
0361: sh.removeAttribute(rc, currentJpfAttrName);
0362: sh.removeAttribute(rc, currentLongLivedAttrName);
0363: }
0364:
0365: public static void removeCurrentFacesBackingBean(
0366: HttpServletRequest request, ServletContext servletContext) {
0367: StorageHandler sh = Handlers.get(servletContext)
0368: .getStorageHandler();
0369: HttpServletRequest unwrappedRequest = PageFlowUtils
0370: .unwrapMultipart(request);
0371: RequestContext rc = new RequestContext(unwrappedRequest, null);
0372: String attrName = ScopedServletUtils.getScopedSessionAttrName(
0373: FACES_BACKING_ATTR, unwrappedRequest);
0374:
0375: sh.removeAttribute(rc, attrName);
0376: }
0377:
0378: public static String getDecodedURI(HttpServletRequest request) {
0379: return request.getContextPath()
0380: + getDecodedServletPath(request);
0381: }
0382:
0383: public static String getDecodedServletPath(
0384: HttpServletRequest request) {
0385: if (ignoreIncludeServletPath(request))
0386: return request.getServletPath();
0387:
0388: String servletIncludePath = (String) request
0389: .getAttribute(RequestProcessor.INCLUDE_SERVLET_PATH);
0390: return servletIncludePath != null ? servletIncludePath
0391: : request.getServletPath();
0392: }
0393:
0394: public static void addActionOutputs(Map toAdd,
0395: ServletRequest request, boolean overwrite) {
0396: if (toAdd != null) {
0397: Map map = getActionOutputMap(request, true);
0398:
0399: for (Iterator i = toAdd.entrySet().iterator(); i.hasNext();) {
0400: Map.Entry entry = (Map.Entry) i.next();
0401: String name = (String) entry.getKey();
0402: boolean alreadyExists = map.containsKey(name);
0403:
0404: if (overwrite || !alreadyExists) {
0405: if (alreadyExists) {
0406: if (_log.isWarnEnabled()) {
0407: _log.warn("Overwriting action output \""
0408: + name + "\".");
0409: }
0410: }
0411:
0412: map.put(name, entry.getValue());
0413: }
0414: }
0415: }
0416: }
0417:
0418: public static void addActionError(String propertyName,
0419: ActionMessage error, ServletRequest request) {
0420: ActionMessages errors = (ActionMessages) request
0421: .getAttribute(Globals.ERROR_KEY);
0422: if (errors == null)
0423: request.setAttribute(Globals.ERROR_KEY,
0424: errors = new ActionMessages());
0425: errors.add(propertyName, error);
0426: }
0427:
0428: public static Object newReloadableInstance(String className,
0429: ServletContext servletContext)
0430: throws ClassNotFoundException, InstantiationException,
0431: IllegalAccessException {
0432: return getReloadableClass(className, servletContext)
0433: .newInstance();
0434: }
0435:
0436: public static Class getReloadableClass(String className,
0437: ServletContext servletContext)
0438: throws ClassNotFoundException {
0439: ReloadableClassHandler handler = Handlers.get(servletContext)
0440: .getReloadableClassHandler();
0441: return handler.loadClass(className);
0442: }
0443:
0444: public static Map getActionOutputMap(ServletRequest request,
0445: boolean createIfNotExist) {
0446: Map map = (Map) request.getAttribute(ACTIONOUTPUT_MAP_ATTR);
0447:
0448: if (map == null && createIfNotExist) {
0449: map = new HashMap();
0450: request.setAttribute(ACTIONOUTPUT_MAP_ATTR, map);
0451: }
0452:
0453: return map;
0454: }
0455:
0456: public static Map getPageInputMap(ServletRequest request,
0457: ServletContext servletContext) {
0458: Map actionOutputsFromPageFlow = getActionOutputMap(request,
0459: false);
0460: if (actionOutputsFromPageFlow != null)
0461: return actionOutputsFromPageFlow;
0462: FacesBackingBean fbb = getFacesBackingBean(request,
0463: servletContext);
0464: return fbb != null ? fbb.getPageInputMap() : null;
0465: }
0466:
0467: public static Map getPageInputMap(ServletRequest request) {
0468: Map actionOutputsFromPageFlow = getActionOutputMap(request,
0469: false);
0470: if (actionOutputsFromPageFlow != null)
0471: return actionOutputsFromPageFlow;
0472: FacesBackingBean fbb = getFacesBackingBean(request,
0473: getServletContext(request));
0474: return fbb != null ? fbb.getPageInputMap() : null;
0475: }
0476:
0477: /**
0478: * Get the Struts ModuleConfig for the given module path.
0479: */
0480: public static ModuleConfig getModuleConfig(String modulePath,
0481: ServletContext context) {
0482: return (ModuleConfig) context.getAttribute(Globals.MODULE_KEY
0483: + modulePath);
0484: }
0485:
0486: /**
0487: * Get the Struts ModuleConfig for the given module path. If there is none registered,
0488: * and if it is possible to register one automatically, do so.
0489: */
0490: public static ModuleConfig ensureModuleConfig(String modulePath,
0491: ServletContext context) {
0492: try {
0493: ModuleConfig ret = getModuleConfig(modulePath, context);
0494:
0495: if (ret != null) {
0496: return ret;
0497: } else {
0498: ActionServlet as = getActionServlet(context);
0499:
0500: if (as instanceof AutoRegisterActionServlet) {
0501: return ((AutoRegisterActionServlet) as)
0502: .ensureModuleRegistered(modulePath);
0503: }
0504: }
0505: } catch (IOException e) {
0506: _log.error("Error while registering Struts module "
0507: + modulePath, e);
0508: } catch (ServletException e) {
0509: _log.error("Error while registering Struts module "
0510: + modulePath, e);
0511: }
0512:
0513: return null;
0514: }
0515:
0516: /**
0517: * Initialize delegating action configs and exception configs for a Struts module that should delegate
0518: * to one generated from a superclass.
0519: */
0520: public static void initDelegatingConfigs(ModuleConfig moduleConfig,
0521: ServletContext servletContext) {
0522: ActionConfig[] actionConfigs = moduleConfig.findActionConfigs();
0523:
0524: // Initialize action configs.
0525: for (int i = 0; i < actionConfigs.length; i++) {
0526: ActionConfig actionConfig = actionConfigs[i];
0527: if (actionConfig instanceof DelegatingActionMapping) {
0528: ((DelegatingActionMapping) actionConfig)
0529: .init(servletContext);
0530: } else {
0531: // Initialize action-level exception configs.
0532: ExceptionConfig[] exceptionConfigs = actionConfig
0533: .findExceptionConfigs();
0534: for (int j = 0; j < exceptionConfigs.length; j++) {
0535: ExceptionConfig exceptionConfig = exceptionConfigs[j];
0536: if (exceptionConfig instanceof DelegatingExceptionConfig) {
0537: ((DelegatingExceptionConfig) exceptionConfig)
0538: .init(servletContext);
0539: }
0540: }
0541: }
0542: }
0543:
0544: // Initialize module-level exception configs.
0545: ExceptionConfig[] exceptionConfigs = moduleConfig
0546: .findExceptionConfigs();
0547: for (int i = 0; i < exceptionConfigs.length; i++) {
0548: ExceptionConfig exceptionConfig = exceptionConfigs[i];
0549: if (exceptionConfig instanceof DelegatingExceptionConfig) {
0550: ((DelegatingExceptionConfig) exceptionConfig)
0551: .init(servletContext);
0552: }
0553: }
0554: }
0555:
0556: /**
0557: * Get the current ActionServlet.
0558: *
0559: * @param context the current ServletContext
0560: * @return the ActionServlet that is stored as an attribute in the ServletContext
0561: */
0562: public static ActionServlet getActionServlet(ServletContext context) {
0563: if (context == null)
0564: return null;
0565: return (ActionServlet) context
0566: .getAttribute(Globals.ACTION_SERVLET_KEY);
0567: }
0568:
0569: /**
0570: * Add a BindingUpdateError to the request.
0571: *
0572: * @param request the current ServletRequest.
0573: * @param expression the expression associated with this error.
0574: * @param message the error message.
0575: * @param cause the Throwable that caused the error.
0576: */
0577: public static void addBindingUpdateError(ServletRequest request,
0578: String expression, String message, Throwable cause) {
0579: Map errors = (Map) request
0580: .getAttribute(BINDING_UPDATE_ERRORS_ATTR);
0581:
0582: if (errors == null) {
0583: errors = new LinkedHashMap();
0584: request.setAttribute(BINDING_UPDATE_ERRORS_ATTR, errors);
0585: }
0586:
0587: errors.put(expression, new BindingUpdateError(expression,
0588: message, cause));
0589: }
0590:
0591: /**
0592: * Get a map of BindingUpdateErrors stored in the request.
0593: *
0594: * @return a Map of expression (String) -> BindingUpdateError.
0595: */
0596: public static Map getBindingUpdateErrors(ServletRequest request) {
0597: return (Map) request.getAttribute(BINDING_UPDATE_ERRORS_ATTR);
0598: }
0599:
0600: public static void setCurrentModule(ModuleConfig mc,
0601: ServletRequest request) {
0602: request.setAttribute(Globals.MODULE_KEY, mc);
0603: }
0604:
0605: public static ActionForm createActionForm(ActionMapping mapping,
0606: ModuleConfig moduleConfig, ActionServlet actionServlet,
0607: ServletContext servletContext) {
0608: String formName = mapping.getName();
0609: if (formName == null)
0610: return null;
0611: FormBeanConfig config = moduleConfig
0612: .findFormBeanConfig(formName);
0613: if (config == null)
0614: return null;
0615:
0616: try {
0617: ActionForm bean;
0618:
0619: if (config.getDynamic()) {
0620: if (_log.isDebugEnabled()) {
0621: _log
0622: .debug("Creating new DynaActionForm instance of type "
0623: + config.getType());
0624: }
0625:
0626: DynaActionFormClass dynaClass = DynaActionFormClass
0627: .createDynaActionFormClass(config);
0628: bean = (ActionForm) dynaClass.newInstance();
0629: ((DynaActionForm) bean).initialize(mapping);
0630: } else {
0631: if (_log.isDebugEnabled()) {
0632: _log
0633: .debug("Creating new ActionForm instance of type "
0634: + config.getType());
0635: }
0636:
0637: bean = (ActionForm) newReloadableInstance(config
0638: .getType(), servletContext);
0639: }
0640:
0641: bean.setServlet(actionServlet);
0642: return bean;
0643: } catch (Exception e) {
0644: if (_log.isErrorEnabled()) {
0645: _log.error("Error creating action form of type "
0646: + config.getType(), e);
0647: }
0648:
0649: return null;
0650: }
0651: }
0652:
0653: /**
0654: * Set the given form in either the request or session, as appropriate, so Struts/NetUI
0655: * tags will have access to it.
0656: */
0657: public static void setFormInScope(String formName, ActionForm form,
0658: ActionMapping mapping, HttpServletRequest request,
0659: boolean overwrite) {
0660: if (formName != null && form != null) {
0661: if (isSessionScope(mapping)) {
0662: HttpSession session = request.getSession();
0663:
0664: if (overwrite || session.getAttribute(formName) == null) {
0665: session.setAttribute(formName, form);
0666: }
0667: } else {
0668: if (overwrite || request.getAttribute(formName) == null) {
0669: request.setAttribute(formName, form);
0670: }
0671: }
0672: }
0673: }
0674:
0675: public static boolean isSessionScope(ActionMapping mapping) {
0676: return (mapping.getScope() == null || mapping.getScope()
0677: .equals("session"));
0678: }
0679:
0680: public static ActionForm getFormBean(ActionMapping mapping,
0681: ServletRequest request) {
0682: String formBeanName = mapping.getAttribute();
0683:
0684: if (formBeanName != null) {
0685: if (isSessionScope(mapping)) {
0686: HttpSession session = getHttpSession(request, false);
0687: return session != null ? (ActionForm) session
0688: .getAttribute(formBeanName) : null;
0689: } else {
0690: return (ActionForm) request.getAttribute(formBeanName);
0691: }
0692: }
0693:
0694: return null;
0695: }
0696:
0697: /**
0698: * Set the current {@link ActionResolver} (or {@link PageFlowController}) in the user session.
0699: *
0700: * @param resolver the {@link ActionResolver} to set as the current one in the user session.
0701: * @deprecated Will be removed in the next version.
0702: */
0703: public static void setCurrentActionResolver(
0704: ActionResolver resolver, HttpServletRequest request,
0705: ServletContext servletContext) {
0706: StorageHandler sh = Handlers.get(servletContext)
0707: .getStorageHandler();
0708: HttpServletRequest unwrappedRequest = PageFlowUtils
0709: .unwrapMultipart(request);
0710: RequestContext rc = new RequestContext(unwrappedRequest, null);
0711: String currentJpfAttrName = ScopedServletUtils
0712: .getScopedSessionAttrName(CURRENT_JPF_ATTR,
0713: unwrappedRequest);
0714: String currentLongLivedJpfAttrName = ScopedServletUtils
0715: .getScopedSessionAttrName(CURRENT_LONGLIVED_ATTR,
0716: unwrappedRequest);
0717:
0718: //
0719: // This case occurs when the previous page flow is no longer active and there is no new page flow
0720: //
0721: if (resolver == null) {
0722: sh.removeAttribute(rc, currentJpfAttrName);
0723: sh.removeAttribute(rc, currentLongLivedJpfAttrName);
0724: return;
0725: }
0726:
0727: //
0728: // If this is a long-lived page flow, also store the instance in an attribute that never goes away.
0729: //
0730: if (resolver.isPageFlow()
0731: && isLongLived(((PageFlowController) resolver)
0732: .theModuleConfig())) {
0733: String longLivedAttrName = getLongLivedFlowAttr(resolver
0734: .getModulePath());
0735: longLivedAttrName = ScopedServletUtils
0736: .getScopedSessionAttrName(longLivedAttrName,
0737: unwrappedRequest);
0738:
0739: // Only set this attribute if it's not already there. We want to avoid our onDestroy() callback that's
0740: // invoked when the page flow's session attribute is unbound.
0741: if (sh.getAttribute(rc, longLivedAttrName) != resolver) {
0742: sh.setAttribute(rc, longLivedAttrName, resolver);
0743: }
0744:
0745: sh.setAttribute(rc, currentLongLivedJpfAttrName, resolver
0746: .getModulePath());
0747: sh.removeAttribute(rc, currentJpfAttrName);
0748: }
0749: //
0750: // Default case for removing a previous page flow in the presence of a new page flow.
0751: //
0752: else {
0753: sh.setAttribute(rc, currentJpfAttrName, resolver);
0754: sh.removeAttribute(rc, currentLongLivedJpfAttrName);
0755: }
0756: }
0757:
0758: public static boolean isSharedFlowModule(ModuleConfig mc) {
0759: ControllerConfig cc = mc.getControllerConfig();
0760: return cc instanceof PageFlowControllerConfig
0761: && ((PageFlowControllerConfig) cc).isSharedFlow();
0762: }
0763:
0764: public static FacesBackingBean getFacesBackingBean(
0765: ServletRequest request, ServletContext servletContext) {
0766: if (request instanceof HttpServletRequest) {
0767: StorageHandler sh = Handlers.get(servletContext)
0768: .getStorageHandler();
0769: HttpServletRequest unwrappedRequest = PageFlowUtils
0770: .unwrapMultipart((HttpServletRequest) request);
0771: RequestContext rc = new RequestContext(unwrappedRequest,
0772: null);
0773: String attrName = ScopedServletUtils
0774: .getScopedSessionAttrName(FACES_BACKING_ATTR,
0775: unwrappedRequest);
0776: return (FacesBackingBean) sh.getAttribute(rc, attrName);
0777: }
0778:
0779: return null;
0780: }
0781:
0782: public static String inferModulePathFromClassName(String className) {
0783: int lastDot = className.lastIndexOf('.');
0784:
0785: if (lastDot != -1) {
0786: className = className.substring(0, lastDot);
0787: return '/' + className.replace('.', '/');
0788: } else {
0789: return "";
0790: }
0791: }
0792:
0793: public static boolean isMultipartHandlingEnabled(
0794: ServletRequest request) {
0795: ModuleConfig moduleConfig = (ModuleConfig) request
0796: .getAttribute(Globals.MODULE_KEY);
0797: return moduleConfig.getControllerConfig().getMultipartClass() != null;
0798: }
0799:
0800: public static MultipartHandler getMultipartHandlerType() {
0801: PageFlowConfig pfConfig = ConfigUtil.getConfig()
0802: .getPageFlowConfig();
0803: return pfConfig != null ? pfConfig.getMultipartHandler() : null;
0804: }
0805:
0806: public static void setServletContext(ServletRequest request,
0807: ServletContext servletContext) {
0808: ScopedServletUtils.getOuterServletRequest(request)
0809: .setAttribute(SERVLET_CONTEXT_ATTR, servletContext);
0810: }
0811:
0812: public static ServletContext getServletContext(ServletRequest req) {
0813: HttpSession session = getHttpSession(req, false);
0814: return session != null ? session.getServletContext()
0815: : (ServletContext) ScopedServletUtils
0816: .getOuterServletRequest(req).getAttribute(
0817: SERVLET_CONTEXT_ATTR);
0818: }
0819:
0820: public static HttpSession getHttpSession(ServletRequest request,
0821: boolean create) {
0822: if (!(request instanceof HttpServletRequest))
0823: return null;
0824: return ((HttpServletRequest) request).getSession(create);
0825: }
0826:
0827: public static String createActionPath(ServletRequest request,
0828: String qualifiedAction) {
0829: ModuleConfig appConfig = (ModuleConfig) request
0830: .getAttribute(Globals.MODULE_KEY);
0831:
0832: if (appConfig != null) {
0833: InternalStringBuilder value = new InternalStringBuilder(
0834: qualifiedAction.length() + 16);
0835: value.append(appConfig.getPrefix());
0836: value.append(qualifiedAction);
0837: return value.toString();
0838: }
0839:
0840: return qualifiedAction;
0841: }
0842:
0843: public static String qualifyAction(ServletContext servletContext,
0844: String action) {
0845: assert action != null;
0846: InternalStringBuilder sb = null;
0847:
0848: String queryString = null;
0849: int question = action.indexOf('?');
0850: if (question >= 0)
0851: queryString = action.substring(question);
0852:
0853: String actionMapping = getActionMappingName(action);
0854: sb = new InternalStringBuilder(action.length()
0855: + ACTION_EXTENSION_LEN + 1);
0856: sb.append(actionMapping);
0857: sb.append(ACTION_EXTENSION);
0858: if (queryString != null)
0859: sb.append(queryString);
0860:
0861: return sb.toString();
0862: }
0863:
0864: /**
0865: * Return the form action converted into an action mapping path. The
0866: * value of the <code>action</code> property is manipulated as follows in
0867: * computing the name of the requested mapping:
0868: * <ul>
0869: * <li>Any filename extension is removed (on the theory that extension
0870: * mapping is being used to select the controller servlet).</li>
0871: * <li>If the resulting value does not start with a slash, then a
0872: * slash is prepended.</li>
0873: * </ul>
0874: *
0875: * @param action the action name to be converted.
0876: * @return an action path, suitable for lookup in the Struts configuration file.
0877: */
0878: public static String getActionMappingName(String action) {
0879: return getCleanActionName(action, true);
0880: }
0881:
0882: public static String getCleanActionName(String action,
0883: boolean prependSlash) {
0884: int question = action.indexOf('?');
0885: if (question >= 0) {
0886: action = action.substring(0, question);
0887: }
0888:
0889: if (action.endsWith(ACTION_EXTENSION)) {
0890: action = action.substring(0, action.length()
0891: - ACTION_EXTENSION_LEN);
0892: }
0893:
0894: if (action.charAt(0) == '/') {
0895: if (!prependSlash)
0896: action = action.substring(1);
0897: } else {
0898: if (prependSlash)
0899: action = '/' + action;
0900: }
0901:
0902: return action;
0903: }
0904:
0905: /**
0906: * Add a parameter to the given URL. Assumes there is no trailing
0907: * anchor/fragment indicated with a '#'.
0908: *
0909: * @param url the URL to which to append.
0910: * @param paramName the name of the parameter to add.
0911: * @param paramVal the value of the parameter to add.
0912: * @return the URL, with the given parameter added.
0913: */
0914: public static String addParam(String url, String paramName,
0915: String paramVal) {
0916: return url + (url.indexOf('?') != -1 ? '&' : '?') + paramName
0917: + '=' + paramVal;
0918: }
0919:
0920: public static String getActionName(ActionMapping mapping) {
0921: if (mapping == null)
0922: return null;
0923:
0924: String actionName = mapping.getPath();
0925: if (actionName.charAt(0) == '/')
0926: actionName = actionName.substring(1);
0927:
0928: //
0929: // Look to see if we need are in a disambiguated action, i.e., one whose name is qualified
0930: // by the form. If so, we need to restore the unqualified action name.
0931: //
0932: if (mapping instanceof PageFlowActionMapping) {
0933: String unqualifiedAction = ((PageFlowActionMapping) mapping)
0934: .getUnqualifiedActionName();
0935: if (unqualifiedAction != null)
0936: actionName = unqualifiedAction;
0937: }
0938:
0939: return actionName;
0940: }
0941:
0942: public static ActionMapping getCurrentActionMapping(
0943: ServletRequest request) {
0944: return (ActionMapping) request
0945: .getAttribute(Globals.MAPPING_KEY);
0946: }
0947:
0948: public static ActionForm getCurrentActionForm(ServletRequest request) {
0949: ActionMapping mapping = getCurrentActionMapping(request);
0950: String attribute = mapping != null ? mapping.getAttribute()
0951: : null;
0952: if (attribute == null)
0953: return null;
0954:
0955: if ("request".equals(mapping.getScope())) {
0956: return (ActionForm) request.getAttribute(attribute);
0957: } else {
0958: HttpSession session = getHttpSession(request, false);
0959: return session != null ? (ActionForm) session
0960: .getAttribute(attribute) : null;
0961: }
0962: }
0963:
0964: public static boolean sessionExpired(ServletRequest servletRequest) {
0965: if (servletRequest instanceof HttpServletRequest) {
0966: HttpServletRequest request = (HttpServletRequest) servletRequest;
0967: String requestedSessionID = request.getRequestedSessionId();
0968:
0969: if (requestedSessionID != null) {
0970: HttpSession session = request.getSession(false);
0971: return session == null
0972: || !requestedSessionID.equals(session.getId());
0973: }
0974: }
0975:
0976: return false;
0977: }
0978:
0979: public static void throwPageFlowException(PageFlowException ex) {
0980: throwPageFlowException(ex, null);
0981: }
0982:
0983: public static void throwPageFlowException(PageFlowException effect,
0984: ServletRequest request) throws PageFlowException {
0985: if (request != null && effect.causeMayBeSessionExpiration()
0986: && sessionExpired(request)) {
0987: PageFlowConfig pfc = ConfigUtil.getConfig()
0988: .getPageFlowConfig();
0989: if (pfc == null || pfc.isThrowSessionExpiredException()) {
0990: throw new SessionExpiredException(effect);
0991: }
0992: }
0993:
0994: throw effect;
0995: }
0996:
0997: /**
0998: * Get the Struts ActionConfig for the given action config path and module path.
0999: */
1000: public static ActionConfig findActionConfig(
1001: String actionConfigPath, String modulePath,
1002: ServletContext context) {
1003: ModuleConfig moduleConfig = getModuleConfig(modulePath, context);
1004: assert moduleConfig != null;
1005: return moduleConfig.findActionConfig(actionConfigPath);
1006: }
1007:
1008: /**
1009: * Get the Struts ActionMapping path from the ActionMapping that is in the request under the key
1010: * Globals.MAPPING_KEY.
1011: *
1012: * @return the path for the ActionMapping, as found with ActionMapping.getPath()
1013: */
1014: public static String getActionMappingPath(ServletRequest request) {
1015: ActionMapping actionMapping = (ActionMapping) request
1016: .getAttribute(Globals.MAPPING_KEY);
1017: return actionMapping != null ? actionMapping.getPath() : null;
1018: }
1019:
1020: /**
1021: * Gets the Struts module path from the input request. If a ModuleConfig
1022: * object has been populated into the request it is used to get the module prefix,
1023: * otherwise getModulePath is called, which derives the module path from
1024: * the request URI.
1025: */
1026: public static String getModulePathFromReqAttr(
1027: HttpServletRequest request) {
1028: //
1029: // If a config was in the request, use its associated prefix; otherwise, fall back to the URI.
1030: //
1031: ModuleConfig config = (ModuleConfig) request
1032: .getAttribute(Globals.MODULE_KEY);
1033: return config != null ? config.getPrefix() : PageFlowUtils
1034: .getModulePath(request);
1035: }
1036:
1037: /**
1038: * Set the forwarded form. This overrides the auto-generated form created by processActionForm
1039: * and populated by processPopulate (in PageFlowRequestProcessor).
1040: */
1041: public static void setForwardedFormBean(ServletRequest request,
1042: ActionForm form) {
1043: if (form == null) {
1044: request.removeAttribute(FORWARDED_FORMBEAN_ATTR);
1045: } else {
1046: request.setAttribute(FORWARDED_FORMBEAN_ATTR, form);
1047: }
1048: }
1049:
1050: public static ActionForm getForwardedFormBean(
1051: ServletRequest request, boolean removeFromRequest) {
1052: ActionForm form = (ActionForm) request
1053: .getAttribute(FORWARDED_FORMBEAN_ATTR);
1054: if (removeFromRequest)
1055: request.removeAttribute(FORWARDED_FORMBEAN_ATTR);
1056: return form;
1057: }
1058:
1059: /**
1060: * Tell whether a special request attribute was set, indicating that we should avoid writing to the response (or
1061: * setting response error codes).
1062: */
1063: public static boolean avoidDirectResponseOutput(
1064: ServletRequest request) {
1065: Boolean avoid = (Boolean) request
1066: .getAttribute(AVOID_DIRECT_RESPONSE_OUTPUT_ATTR);
1067: return avoid != null && avoid.booleanValue();
1068: }
1069:
1070: /**
1071: * Set a special request attribute to indicate that we should avoid writing to the response (or
1072: * setting response error codes).
1073: */
1074: public static void setAvoidDirectResponseOutput(
1075: ServletRequest request) {
1076: request.setAttribute(AVOID_DIRECT_RESPONSE_OUTPUT_ATTR,
1077: Boolean.TRUE);
1078: }
1079:
1080: /**
1081: * Set the module prefix for the ModuleConfig that is performing a forward in this request.
1082: */
1083: public static void setForwardingModule(ServletRequest request,
1084: String modulePrefix) {
1085: request.setAttribute(FORWARDING_MODULE_ATTR, modulePrefix);
1086: }
1087:
1088: /**
1089: * Set the module prefix for the ModuleConfig that is performing a forward in this request.
1090: */
1091: public static String getForwardingModule(ServletRequest request) {
1092: return (String) request.getAttribute(FORWARDING_MODULE_ATTR);
1093: }
1094:
1095: public static String getFormBeanType(FormBeanConfig formBeanConfig) {
1096: String formBeanType = null;
1097:
1098: // First, try to read the form bean type from our custom property, which supports the any-bean feature.
1099: if (formBeanConfig instanceof PageFlowActionFormBean) {
1100: formBeanType = ((PageFlowActionFormBean) formBeanConfig)
1101: .getActualType();
1102: }
1103:
1104: // If we didn't find it there, this is a normal Struts ActionForm. Just get it from the type attr.
1105: if (formBeanType == null)
1106: formBeanType = formBeanConfig.getType();
1107:
1108: return formBeanType;
1109: }
1110:
1111: /**
1112: * Tell {@link #getDecodedServletPath} (and all that call it) to ignore the attribute that specifies the Servlet
1113: * Include path, which is set when a Servlet include is done through RequestDispatcher. Normally,
1114: * getDecodedServletPath tries the Servlet Include path before falling back to getServletPath() on the request.
1115: * Note that this is basically a stack of instructions to ignore the include path, and this method expects each
1116: * call with <code>ignore</code>==<code>true</code> to be balanced by a call with
1117: * <code>ignore</code>==<code>false</code>.
1118: */
1119: public static void setIgnoreIncludeServletPath(
1120: ServletRequest request, boolean ignore) {
1121: Integer depth = (Integer) request
1122: .getAttribute(IGNORE_INCLUDE_SERVLET_PATH_ATTR);
1123:
1124: if (ignore) {
1125: if (depth == null)
1126: depth = new Integer(0);
1127: request.setAttribute(IGNORE_INCLUDE_SERVLET_PATH_ATTR,
1128: new Integer(depth.intValue() + 1));
1129: } else {
1130: assert depth != null : "call to setIgnoreIncludeServletPath() was imbalanced";
1131: depth = new Integer(depth.intValue() - 1);
1132:
1133: if (depth.intValue() == 0) {
1134: request
1135: .removeAttribute(IGNORE_INCLUDE_SERVLET_PATH_ATTR);
1136: } else {
1137: request.setAttribute(IGNORE_INCLUDE_SERVLET_PATH_ATTR,
1138: depth);
1139: }
1140: }
1141: }
1142:
1143: public static boolean ignoreIncludeServletPath(
1144: ServletRequest request) {
1145: return request.getAttribute(IGNORE_INCLUDE_SERVLET_PATH_ATTR) != null;
1146: }
1147:
1148: /**
1149: * If the given request is a MultipartRequestWrapper (Struts class that doesn't extend
1150: * HttpServletRequestWrapper), return the wrapped request; otherwise, return the given request.
1151: */
1152: public static ServletRequest unwrapMultipart(ServletRequest request) {
1153: if (request instanceof MultipartRequestWrapper) {
1154: request = ((MultipartRequestWrapper) request).getRequest();
1155: }
1156:
1157: return request;
1158: }
1159:
1160: /**
1161: * Set the given Struts module in the request, and expose its set of MessageResources as request attributes.
1162: *
1163: * @param prefix the prefix of the desired module.
1164: * @param request the current HttpServletRequest.
1165: * @param servletContext the current ServletContext.
1166: * @return the selected ModuleConfig, or <code>null</code> if there is none for the given module prefix.
1167: */
1168: public static ModuleConfig selectModule(String prefix,
1169: HttpServletRequest request, ServletContext servletContext) {
1170: ModuleConfig moduleConfig = getModuleConfig(prefix,
1171: servletContext);
1172:
1173: if (moduleConfig == null) {
1174: request.removeAttribute(Globals.MODULE_KEY);
1175: return null;
1176: }
1177:
1178: // If this module came from an abstract page flow controller class, don't select it.
1179: ControllerConfig cc = moduleConfig.getControllerConfig();
1180: if (cc instanceof PageFlowControllerConfig
1181: && ((PageFlowControllerConfig) cc).isAbstract()) {
1182: return moduleConfig;
1183: }
1184:
1185: // Just return it if it's already registered.
1186: if (request.getAttribute(Globals.MODULE_KEY) == moduleConfig)
1187: return moduleConfig;
1188: request.setAttribute(Globals.MODULE_KEY, moduleConfig);
1189:
1190: MessageResourcesConfig[] mrConfig = moduleConfig
1191: .findMessageResourcesConfigs();
1192: Object formBean = unwrapFormBean(getCurrentActionForm(request));
1193:
1194: for (int i = 0; i < mrConfig.length; i++) {
1195: String key = mrConfig[i].getKey();
1196: MessageResources resources = (MessageResources) servletContext
1197: .getAttribute(key + prefix);
1198:
1199: if (resources != null) {
1200: if (!(resources instanceof ExpressionAwareMessageResources)) {
1201: resources = new ExpressionAwareMessageResources(
1202: resources, formBean, request,
1203: servletContext);
1204: }
1205:
1206: request.setAttribute(key, resources);
1207: } else {
1208: request.removeAttribute(key);
1209: }
1210: }
1211:
1212: return moduleConfig;
1213: }
1214:
1215: public static MessageResources getMessageResources(
1216: String bundleName, ServletRequest request,
1217: ServletContext servletContext) {
1218: MessageResources resources = (MessageResources) request
1219: .getAttribute(bundleName);
1220:
1221: if (resources == null) {
1222: String qualified = getQualifiedBundleName(bundleName,
1223: request);
1224: resources = (MessageResources) servletContext
1225: .getAttribute(qualified);
1226: }
1227:
1228: // If we can't find resources with this name, try them at the root (unqualified).
1229: if (resources == null)
1230: resources = (MessageResources) servletContext
1231: .getAttribute(bundleName);
1232:
1233: return resources;
1234: }
1235:
1236: /**
1237: * Qualify the given bundle name with the current module path to return a full bundle name.
1238: *
1239: * @return the qualified Bundle name
1240: */
1241: public static String getQualifiedBundleName(String bundleName,
1242: ServletRequest request) {
1243: if (bundleName != null) {
1244: if (bundleName.indexOf('/') == -1) {
1245: ModuleConfig mc = (ModuleConfig) request
1246: .getAttribute(Globals.MODULE_KEY);
1247:
1248: // Note that we don't append the module path for the root module.
1249: if (mc != null && mc.getPrefix() != null
1250: && mc.getPrefix().length() > 1) {
1251: bundleName += mc.getPrefix();
1252: }
1253: } else if (bundleName.endsWith("/")) {
1254: // Special handling for bundles referring to the root module -- they should not have
1255: // the module path ("/") at the end.
1256: bundleName = bundleName.substring(0, bundleName
1257: .length() - 1);
1258: }
1259: }
1260:
1261: return bundleName;
1262: }
1263:
1264: public static Locale lookupLocale(JspContext jspContext) {
1265: assert jspContext instanceof PageContext : "Found JspContext of type \""
1266: + (jspContext != null ? jspContext.getClass().getName()
1267: : "null") + "\"";
1268: return lookupLocale(((PageContext) jspContext).getRequest());
1269: }
1270:
1271: public static Locale lookupLocale(ServletRequest request) {
1272: assert request instanceof HttpServletRequest : "Found servlet request of type \""
1273: + (request != null ? request.getClass().getName()
1274: : "null") + "\"";
1275:
1276: Locale locale = null;
1277: HttpServletRequest httpServletRequest = (HttpServletRequest) request;
1278: HttpSession session = httpServletRequest.getSession(false);
1279: if (session != null)
1280: locale = (Locale) session.getAttribute(Globals.LOCALE_KEY);
1281:
1282: if (locale == null)
1283: locale = request.getLocale();
1284:
1285: return locale;
1286: }
1287:
1288: }
|