View Javadoc
1   /*
2    * $Id$
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  package org.apache.struts.validator;
22  
23  import java.util.Locale;
24  
25  import jakarta.servlet.ServletContext;
26  import jakarta.servlet.http.HttpServletRequest;
27  
28  import org.apache.commons.validator.Arg;
29  import org.apache.commons.validator.Field;
30  import org.apache.commons.validator.Msg;
31  import org.apache.commons.validator.Validator;
32  import org.apache.commons.validator.ValidatorAction;
33  import org.apache.commons.validator.ValidatorResources;
34  import org.apache.commons.validator.Var;
35  import org.apache.struts.Globals;
36  import org.apache.struts.action.ActionMessage;
37  import org.apache.struts.action.ActionMessages;
38  import org.apache.struts.config.ModuleConfig;
39  import org.apache.struts.util.MessageResources;
40  import org.apache.struts.util.ModuleUtils;
41  import org.apache.struts.util.RequestUtils;
42  import org.slf4j.Logger;
43  import org.slf4j.LoggerFactory;
44  
45  /**
46   * This class helps provides some useful methods for retrieving objects from
47   * different scopes of the application.
48   *
49   * @version $Rev$ $Date: 2005-09-16 23:34:41 -0400 (Fri, 16 Sep 2005)
50   *          $
51   * @since Struts 1.1
52   */
53  public class Resources {
54  
55      /**
56       * The message resources for this package.
57       */
58      private static MessageResources sysmsgs =
59          MessageResources.getMessageResources(
60              "org.apache.struts.validator.LocalStrings");
61  
62      /**
63       * The {@code Log} instance for this class.
64       */
65      private final static Logger LOG =
66          LoggerFactory.getLogger(Resources.class);
67  
68      /**
69       * Resources key the <code>ServletContext</code> is stored under.
70       */
71      private static String SERVLET_CONTEXT_PARAM =
72          "jakarta.servlet.ServletContext";
73  
74      /**
75       * Resources key the <code>HttpServletRequest</code> is stored under.
76       */
77      private static String HTTP_SERVLET_REQUEST_PARAM =
78          "jakarta.servlet.http.HttpServletRequest";
79  
80      /**
81       * Resources key the <code>ActionMessages</code> is stored under.
82       */
83      private static String ACTION_MESSAGES_PARAM =
84          "org.apache.struts.action.ActionMessages";
85  
86      /**
87       * Retrieve <code>ValidatorResources</code> for the current module.
88       *
89       * @param application Application Context
90       * @param request     The ServletRequest
91       */
92      public static ValidatorResources getValidatorResources(
93          ServletContext application, HttpServletRequest request) {
94          String prefix =
95              ModuleUtils.getInstance().getModuleConfig(request, application)
96                         .getPrefix();
97  
98          return (ValidatorResources) application.getAttribute(ValidatorPlugIn.VALIDATOR_KEY
99              + prefix);
100     }
101 
102     /**
103      * Retrieve <code>MessageResources</code> for the module.
104      *
105      * @param request the servlet request
106      */
107     public static MessageResources getMessageResources(
108         HttpServletRequest request) {
109         return (MessageResources) request.getAttribute(Globals.MESSAGES_KEY);
110     }
111 
112     /**
113      * Retrieve <code>MessageResources</code> for the module and bundle.
114      *
115      * @param application the servlet context
116      * @param request     the servlet request
117      * @param bundle      the bundle key
118      */
119     public static MessageResources getMessageResources(
120         ServletContext application, HttpServletRequest request, String bundle) {
121         if (bundle == null) {
122             bundle = Globals.MESSAGES_KEY;
123         }
124 
125         MessageResources resources =
126             (MessageResources) request.getAttribute(bundle);
127 
128         if (resources == null) {
129             ModuleConfig moduleConfig =
130                 ModuleUtils.getInstance().getModuleConfig(request, application);
131 
132             resources =
133                 (MessageResources) application.getAttribute(bundle
134                     + moduleConfig.getPrefix());
135         }
136 
137         if (resources == null) {
138             resources = (MessageResources) application.getAttribute(bundle);
139         }
140 
141         if (resources == null) {
142             throw new NullPointerException(
143                 "No message resources found for bundle: " + bundle);
144         }
145 
146         return resources;
147     }
148 
149     /**
150      * Get the value of a variable.
151      *
152      * @param varName   The variable name
153      * @param field     the validator Field
154      * @param validator The Validator
155      * @param request   the servlet request
156      * @param required  Whether the variable is mandatory
157      * @return The variable's value
158      */
159     public static String getVarValue(String varName, Field field,
160         Validator validator, HttpServletRequest request, boolean required) {
161         Var var = field.getVar(varName);
162 
163         if (var == null) {
164             String msg = sysmsgs.getMessage("variable.missing", varName);
165 
166             if (required) {
167                 throw new IllegalArgumentException(msg);
168             }
169 
170             LOG.debug("{}: {}", field.getProperty(), msg);
171 
172             return null;
173         }
174 
175         ServletContext application =
176             (ServletContext) validator.getParameterValue(SERVLET_CONTEXT_PARAM);
177 
178         return getVarValue(var, application, request, required);
179     }
180 
181     /**
182      * Get the value of a variable.
183      *
184      * @param var         the validator variable
185      * @param application The ServletContext
186      * @param request     the servlet request
187      * @param required    Whether the variable is mandatory
188      * @return The variables values
189      */
190     public static String getVarValue(Var var, ServletContext application,
191         HttpServletRequest request, boolean required) {
192         String varName = var.getName();
193         String varValue = var.getValue();
194 
195         // Non-resource variable
196         if (!var.isResource()) {
197             return varValue;
198         }
199 
200         // Get the message resources
201         String bundle = var.getBundle();
202         MessageResources messages =
203             getMessageResources(application, request, bundle);
204 
205         // Retrieve variable's value from message resources
206         Locale locale = RequestUtils.getUserLocale(request, null);
207         String value = messages.getMessage(locale, varValue, null);
208 
209         // Not found in message resources
210         if ((value == null) && required) {
211             throw new IllegalArgumentException(sysmsgs.getMessage(
212                     "variable.resource.notfound", varName, varValue, bundle));
213         }
214 
215         LOG.debug("Var=[{}], bundle=[{}], key=[{}], value=[{}]",
216             varName, bundle, varValue, value);
217 
218         return value;
219     }
220 
221     /**
222      * Gets the <code>Locale</code> sensitive value based on the key passed
223      * in.
224      *
225      * @param messages The Message resources
226      * @param locale   The locale.
227      * @param key      Key used to lookup the message
228      */
229     public static String getMessage(MessageResources messages, Locale locale,
230         String key) {
231         String message = null;
232 
233         if (messages != null) {
234             message = messages.getMessage(locale, key);
235         }
236 
237         return (message == null) ? "" : message;
238     }
239 
240     /**
241      * Gets the <code>Locale</code> sensitive value based on the key passed
242      * in.
243      *
244      * @param request servlet request
245      * @param key     the request key
246      */
247     public static String getMessage(HttpServletRequest request, String key) {
248         MessageResources messages = getMessageResources(request);
249 
250         return getMessage(messages, RequestUtils.getUserLocale(request, null),
251             key);
252     }
253 
254     /**
255      * Gets the locale sensitive message based on the <code>ValidatorAction</code>
256      * message and the <code>Field</code>'s arg objects.
257      *
258      * @param messages The Message resources
259      * @param locale   The locale
260      * @param va       The Validator Action
261      * @param field    The Validator Field
262      */
263     public static String getMessage(MessageResources messages, Locale locale,
264         ValidatorAction va, Field field) {
265         String[] args = getArgs(va.getName(), messages, locale, field);
266         String msg =
267             (field.getMsg(va.getName()) != null) ? field.getMsg(va.getName())
268                                                  : va.getMsg();
269 
270         return messages.getMessage(locale, msg, args);
271     }
272 
273     /**
274      * Gets the <code>Locale</code> sensitive value based on the key passed
275      * in.
276      *
277      * @param application     the servlet context
278      * @param request         the servlet request
279      * @param defaultMessages The default Message resources
280      * @param locale          The locale
281      * @param va              The Validator Action
282      * @param field           The Validator Field
283      */
284     public static String getMessage(ServletContext application,
285         HttpServletRequest request, MessageResources defaultMessages,
286         Locale locale, ValidatorAction va, Field field) {
287         Msg msg = field.getMessage(va.getName());
288 
289         if ((msg != null) && !msg.isResource()) {
290             return msg.getKey();
291         }
292 
293         String msgKey = null;
294 //      String msgBundle = null;
295         MessageResources messages = defaultMessages;
296 
297         if (msg == null) {
298             msgKey = va.getMsg();
299         } else {
300             msgKey = msg.getKey();
301 //          msgBundle = msg.getBundle();
302 
303             if (msg.getBundle() != null) {
304                 messages =
305                     getMessageResources(application, request, msg.getBundle());
306             }
307         }
308 
309         if ((msgKey == null) || (msgKey.length() == 0)) {
310             return "??? " + va.getName() + "." + field.getProperty() + " ???";
311         }
312 
313         // Get the arguments
314         Arg[] args = field.getArgs(va.getName());
315         String[] argValues =
316             getArgValues(application, request, messages, locale, args);
317 
318         // Return the message
319         return messages.getMessage(locale, msgKey, argValues);
320     }
321 
322     /**
323      * Gets the <code>ActionMessage</code> based on the
324      * <code>ValidatorAction</code> message and the <code>Field</code>'s arg
325      * objects.
326      * <p>
327      * <strong>Note:</strong> this method does not respect bundle information
328      * stored with the field's &lt;msg&gt; or &lt;arg&gt; elements, and localization
329      * will not work for alternative resource bundles. This method is
330      * deprecated for this reason, and you should use
331      * {@link #getActionMessage(Validator,HttpServletRequest,ValidatorAction,Field)}
332      * instead.
333      *
334      * @param request the servlet request
335      * @param va      Validator action
336      * @param field   the validator Field
337      * @deprecated Use getActionMessage(Validator, HttpServletRequest,
338      *    ValidatorAction, Field) method instead
339      */
340     @Deprecated
341     public static ActionMessage getActionMessage(HttpServletRequest request,
342         ValidatorAction va, Field field) {
343         String[] args =
344             getArgs(va.getName(), getMessageResources(request),
345                 RequestUtils.getUserLocale(request, null), field);
346 
347         String msg =
348             (field.getMsg(va.getName()) != null) ? field.getMsg(va.getName())
349                                                  : va.getMsg();
350 
351         return new ActionMessage(msg, args);
352     }
353 
354     /**
355      * Gets the <code>ActionMessage</code> based on the
356      * <code>ValidatorAction</code> message and the <code>Field</code>'s arg
357      * objects.
358      *
359      * @param validator the Validator
360      * @param request   the servlet request
361      * @param va        Validator action
362      * @param field     the validator Field
363      */
364     public static ActionMessage getActionMessage(Validator validator,
365         HttpServletRequest request, ValidatorAction va, Field field) {
366         Msg msg = field.getMessage(va.getName());
367 
368         if ((msg != null) && !msg.isResource()) {
369             return new ActionMessage(msg.getKey(), false);
370         }
371 
372         String msgKey = null;
373         String msgBundle = null;
374 
375         if (msg == null) {
376             msgKey = va.getMsg();
377         } else {
378             msgKey = msg.getKey();
379             msgBundle = msg.getBundle();
380         }
381 
382         if ((msgKey == null) || (msgKey.length() == 0)) {
383             return new ActionMessage("??? " + va.getName() + "."
384                 + field.getProperty() + " ???", false);
385         }
386 
387         ServletContext application =
388             (ServletContext) validator.getParameterValue(SERVLET_CONTEXT_PARAM);
389         MessageResources messages =
390             getMessageResources(application, request, msgBundle);
391         Locale locale = RequestUtils.getUserLocale(request, null);
392 
393         Arg[] args = field.getArgs(va.getName());
394         String[] argValues =
395             getArgValues(application, request, messages, locale, args);
396 
397         ActionMessage actionMessage = null;
398 
399         if (msgBundle == null) {
400             actionMessage = new ActionMessage(msgKey, argValues);
401         } else {
402             String message = messages.getMessage(locale, msgKey, argValues);
403 
404             actionMessage = new ActionMessage(message, false);
405         }
406 
407         return actionMessage;
408     }
409 
410     /**
411      * Gets the message arguments based on the current <code>ValidatorAction</code>
412      * and <code>Field</code>.
413      *
414      * @param actionName action name
415      * @param messages   message resources
416      * @param locale     the locale
417      * @param field      the validator field
418      */
419     public static String[] getArgs(String actionName,
420         MessageResources messages, Locale locale, Field field) {
421         String[] argMessages = new String[4];
422 
423         Arg[] args =
424             new Arg[] {
425                 field.getArg(actionName, 0), field.getArg(actionName, 1),
426                 field.getArg(actionName, 2), field.getArg(actionName, 3)
427             };
428 
429         for (int i = 0; i < args.length; i++) {
430             if (args[i] == null) {
431                 continue;
432             }
433 
434             if (args[i].isResource()) {
435                 argMessages[i] = getMessage(messages, locale, args[i].getKey());
436             } else {
437                 argMessages[i] = args[i].getKey();
438             }
439         }
440 
441         return argMessages;
442     }
443 
444     /**
445      * Gets the message arguments based on the current <code>ValidatorAction</code>
446      * and <code>Field</code>.
447      *
448      * @param application     the servlet context
449      * @param request         the servlet request
450      * @param defaultMessages Default message resources
451      * @param locale          the locale
452      * @param args            The arguments for the message
453      */
454     private static String[] getArgValues(ServletContext application,
455         HttpServletRequest request, MessageResources defaultMessages,
456         Locale locale, Arg[] args) {
457         if ((args == null) || (args.length == 0)) {
458             return null;
459         }
460 
461         String[] values = new String[args.length];
462 
463         for (int i = 0; i < args.length; i++) {
464             if (args[i] != null) {
465                 if (args[i].isResource()) {
466                     MessageResources messages = defaultMessages;
467 
468                     if (args[i].getBundle() != null) {
469                         messages =
470                             getMessageResources(application, request,
471                                 args[i].getBundle());
472                     }
473 
474                     values[i] = messages.getMessage(locale, args[i].getKey());
475                 } else {
476                     values[i] = args[i].getKey();
477                 }
478             }
479         }
480 
481         return values;
482     }
483 
484     /**
485      * Initialize the <code>Validator</code> to perform validation.
486      *
487      * @param key         The key that the validation rules are under (the
488      *                    form elements name attribute).
489      * @param bean        The bean validation is being performed on.
490      * @param application servlet context
491      * @param request     The current request object.
492      * @param errors      The object any errors will be stored in.
493      * @param page        This in conjunction with  the page property of a
494      *                    <code>Field<code> can control the processing of
495      *                    fields.  If the field's page is less than or equal
496      *                    to this page value, it will be processed.
497      */
498     public static Validator initValidator(String key, Object bean,
499         ServletContext application, HttpServletRequest request,
500         ActionMessages errors, int page) {
501         ValidatorResources resources =
502             Resources.getValidatorResources(application, request);
503 
504         Locale locale = RequestUtils.getUserLocale(request, null);
505 
506         Validator validator = new Validator(resources, key);
507 
508         validator.setUseContextClassLoader(true);
509 
510         validator.setPage(page);
511 
512         validator.setParameter(SERVLET_CONTEXT_PARAM, application);
513         validator.setParameter(HTTP_SERVLET_REQUEST_PARAM, request);
514         validator.setParameter(Validator.LOCALE_PARAM, locale);
515         validator.setParameter(ACTION_MESSAGES_PARAM, errors);
516         validator.setParameter(Validator.BEAN_PARAM, bean);
517 
518         return validator;
519     }
520 }