Struts 1
  1. Struts 1
  2. STR-2875

<s:loadMessages /> and <s:messages /> tags can find the correct bundle in a multimodule webapp

    Details

    • Type: Bug Bug
    • Status: Open
    • Priority: Major Major
    • Resolution: Unresolved
    • Affects Version/s: 1.3.4
    • Fix Version/s: None
    • Labels:
      None
    • Environment:
      struts multimodule webapp

      Description

      Hi there,

      I think that there is a bug in the implementation of the "org.apache.struts.faces.taglib.LoadMessagesTag". When working in a multimodule webapp with several <messages-resources /> per module, the <s:loadMessages /> tag can't find the appropiate MessageResources instance via "messages" attribute.

      The reason for this is the way that the tag uses to locate the appropiate MessageResources instance. This code explains it (line 76):

      public int doStartTag() {

      // Acquire the Locale to be wrapped
      Locale locale =
      FacesContext.getCurrentInstance().getViewRoot().getLocale();

      // Acquire the MessageResources to be wrapped
      MessageResources messages = null;
      if (this.messages == null) {
      messages = (MessageResources)
      pageContext.getAttribute(Globals.MESSAGES_KEY,
      PageContext.REQUEST_SCOPE );
      if (messages == null)

      { messages = (MessageResources) pageContext.getAttribute(Globals.MESSAGES_KEY, PageContext.APPLICATION_SCOPE ); }

      } else

      { messages = (MessageResources) pageContext.getAttribute(this.messages, PageContext.REQUEST_SCOPE); }

      // Expose a Map instance under the specified request attribute key
      pageContext.setAttribute(var,
      new MessagesMap(messages, locale),
      PageContext.APPLICATION_SCOPE);

      // Skip the body of this tag (if any)
      return (SKIP_BODY);

      }

      As you can see, this code doesn't supports modules.

      If we want to load a different bundle than the one configured as the default, we must use the "messages" attribute but this code tries to load that MessageResources instance from the APPLICATION_SCOPE rather that search for it inside the REQUEST_SCOPE.

      In a multimodule webapp the MessageResources instances are loaded on startup inside the APPLICATION_SCOPE with the key:
      org.apache.struts.action/MESSAGE + [modulePrefix]

      If we have more than one MessageResources instance per module the will be loaded with the key:
      [bundleKey] + [modulePrefix]

      So, the above code can't load any of those kind of messages resources. This can be solved easily:

      public int doStartTag() throws JspException {

      // Acquire the Locale to be wrapped
      Locale locale =
      FacesContext.getCurrentInstance().getViewRoot().getLocale();

      ModuleConfig modConfig = ModuleUtils.getInstance().getModuleConfig(
      (HttpServletRequest) pageContext.getRequest(), pageContext.getServletContext());

      // Acquire the MessageResources to be wrapped
      MessageResources messages = null;
      if (this.messages == null) {
      messages = (MessageResources)
      pageContext.getAttribute(Globals.MESSAGES_KEY,
      PageContext.REQUEST_SCOPE);
      if (messages == null)

      { messages = (MessageResources) pageContext.getAttribute(Globals.MESSAGES_KEY + modConfig.getPrefix(), PageContext.APPLICATION_SCOPE); }

      } else {
      messages = (MessageResources)
      pageContext.getAttribute(this.messages,
      PageContext.REQUEST_SCOPE);

      if(messages == null)

      { messages = (MessageResources) pageContext.getAttribute(this.messages + modConfig.getPrefix(), PageContext.APPLICATION_SCOPE); }

      }

      if(messages == null)
      throw new JspException("MessageResources bundle " +
      this.messages + " not found");

      // Expose a Map instance under the specified request attribute key
      pageContext.setAttribute(var,
      new MessagesMap(messages, locale),
      PageContext.REQUEST_SCOPE);

      // Skip the body of this tag (if any)
      return (SKIP_BODY);

      }

      Something similar happens with the <s:message /> tag but I don't have the solution yet

      Alonso

        Activity

        Hide
        Alonso Dominguez added a comment -

        This is related to the <s:messages /> tag. The bug responsible of the problem is at the org.apache.struts.faces.renderer.MessagesRenderer class, about line 71:

        protected String getText(FacesContext context, UIComponent component) {

        // Look up the MessageResources bundle to be used
        String bundle = (String) component.getAttributes().get("bundle");
        if (bundle == null)

        { bundle = Globals.MESSAGES_KEY; }
        MessageResources resources = (MessageResources)
        context.getExternalContext().getApplicationMap().get(bundle);
        if (resources == null) { // FIXME - i18n throw new IllegalArgumentException("MessageResources bundle " + bundle + " not found"); }

        As you can see, the bug is very similar to the one of <s:loadMessages /> tag. The problem is the lookup mechanism again, the following code tries to solve it and actually is working for me:

        String bundle = (String) component.getAttributes().get("bundle");
        if (bundle == null) { bundle = Globals.MESSAGES_KEY; }

        ModuleConfig modConfig = (ModuleConfig) context.getExternalContext()
        .getRequestMap().get(Globals.MODULE_KEY);

        MessageResources resources = (MessageResources)
        context.getExternalContext().getRequestMap().get(bundle);
        if(resources == null)

        { resources = (MessageResources) context.getExternalContext().getApplicationMap().get(bundle + modConfig.getPrefix()); }

        if (resources == null)

        { // FIXME - i18n throw new IllegalArgumentException("MessageResources bundle " + bundle + " not found"); }

        Regards,
        Alonso

        Show
        Alonso Dominguez added a comment - This is related to the <s:messages /> tag. The bug responsible of the problem is at the org.apache.struts.faces.renderer.MessagesRenderer class, about line 71: protected String getText(FacesContext context, UIComponent component) { // Look up the MessageResources bundle to be used String bundle = (String) component.getAttributes().get("bundle"); if (bundle == null) { bundle = Globals.MESSAGES_KEY; } MessageResources resources = (MessageResources) context.getExternalContext().getApplicationMap().get(bundle); if (resources == null) { // FIXME - i18n throw new IllegalArgumentException("MessageResources bundle " + bundle + " not found"); } As you can see, the bug is very similar to the one of <s:loadMessages /> tag. The problem is the lookup mechanism again, the following code tries to solve it and actually is working for me: String bundle = (String) component.getAttributes().get("bundle"); if (bundle == null) { bundle = Globals.MESSAGES_KEY; } ModuleConfig modConfig = (ModuleConfig) context.getExternalContext() .getRequestMap().get(Globals.MODULE_KEY); MessageResources resources = (MessageResources) context.getExternalContext().getRequestMap().get(bundle); if(resources == null) { resources = (MessageResources) context.getExternalContext().getApplicationMap().get(bundle + modConfig.getPrefix()); } if (resources == null) { // FIXME - i18n throw new IllegalArgumentException("MessageResources bundle " + bundle + " not found"); } Regards, Alonso

          People

          • Assignee:
            Unassigned
            Reporter:
            Alonso Dominguez
          • Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

            • Created:
              Updated:

              Development