11 Replies Latest reply on Oct 6, 2008 7:09 AM by jupallis

    NPE using JSTL format

    peterj

      Trying to use the format taglib in a JSP within a portlet. But use of f:message leads to:

      2006-08-08 16:27:05,734 ERROR [org.jboss.portal.core.command.ControllerCommand] Rendering portlet window default.default.ImagePortletWindow triggered the following error :
       ...
      Caused by: java.lang.NullPointerException
       at org.apache.taglibs.standard.tag.common.core.Util.getRequestLocales(Util.java:281)
       at org.apache.taglibs.standard.tag.common.fmt.BundleSupport.findMatch(BundleSupport.java:249)
       at org.apache.taglibs.standard.tag.common.fmt.BundleSupport.getLocalizationContext(BundleSupport.java:186)
       at org.apache.taglibs.standard.tag.common.fmt.BundleSupport.getLocalizationContext(BundleSupport.java:137)
       at org.apache.taglibs.standard.tag.common.fmt.MessageSupport.doEndTag(MessageSupport.java:153)
       at org.apache.jsp.WEB_002dINF.jsp.edit_jsp._jspx_meth_f_message_0(edit_jsp.java:133)
       at org.apache.jsp.WEB_002dINF.jsp.edit_jsp._jspService(edit_jsp.java:70)
       at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:97)
      . . .
      


      Looking at the Util class, I see:

      public static Enumeration getRequestLocales(HttpServletRequest request) {
       Enumeration values = request.getHeaders("accept-language");
       if (values.hasMoreElements()) { //<== line 281
       // At least one "accept-language". Simply return
       // the enumeration returned by request.getLocales().
       // System.out.println("At least one accept-language");
       return request.getLocales();
       } else {
       // No header for "accept-language". Simply return
       // the empty enumeration.
       // System.out.println("No accept-language");
       return values;
       }
      }


      It appears that the portal is stripping the language sent by the browser, and thus returning a null when asked for "accept-language". I even added a supported-locale entry in my portal.xml file, but still get the same NPE.

      Does anyone have a JSP using the format JSTL and it works?

      JBoss AS 4.0.4.GA, JBoss Portal 2.4.0CR3, Sun JDK 1.5.0_06


        • 1. Re: NPE using JSTL format
          agathon

          I'm having the exact same problem using JBoss Portal 2.2.1-SP1. I am also using the Struts Bridge provided by Apache to serve the JSPs. Has anyone found a solution yet?

          • 2. Re: NPE using JSTL format
            peterj

            Looks like we are out of luck. According to the spec, section 11.1.4:

            Depending on the underlying web-server/servlet-container and the portal/portletcontainer
            implementation, client request HTTP headers may not be always available.
            Portlets should not rely on the presence of headers to function properly.


            I have verified that the HttpRequest object does not contain any headers. So it looks like there is a conflict between the portal spec and the JSTL implementation (and possibly also the spec, but I haven't checked that). I haven't looked at the 2.0 portal spec to see if this problem is solved there.

            I have noticed, from googling, that other portal implementations support fmt:message, namely SAS, BEA, and IBM. I have found internationalization tutorials on all three that use fmt:message.

            • 3. Re: NPE using JSTL format
              peterj

              Not being one to give up easily, I came up with a workaround patch to the portal. Edit the file .\portlet\src\main\org\jboss\portal\portlet\impl\jsr168\PortletRequestDispatcherImpl.java adding the import:

              import java.util.Enumeration;


              and add the following code within the execute method (new code is in blue, other code is existing code)

              HttpServletRequest wrappedReq = new HttpServletRequestWrapper(req)
              {
               /**
               * Override the behavior from tomcat, see above.
               *
               * @return the null value per the spec
               */
               public StringBuffer getRequestURL()
               {
               // Per the spec
               Exception e = new Exception("called getRequestURL");
               e.printStackTrace();
               return null;
               }
              
               public Enumeration getHeaders(String hdr) {
               Enumeration result = null;
               if ("accept-language".equals(hdr)) {
               result = new Enumeration() {
               int i = 0;
               public boolean hasMoreElements() {return i == 0;}
               public Object nextElement() {i++; return "";}
               };
               }
               return result;
               }
              
              };


              Why does this work? Well, the JSTL code first looks to see if there is at least one accept-language header entry. It never looks at what the entry is, just if there is one. If there is, then it calls request.getLocales() and uses that information to do the localization. This patch is sufficient to fool the JSTL code into getting the locale, which, fortunately, still exists.

              My initial thought was that this is a kludge. However, it does have some advantages. First, all headers except accept-language still return null, as is done now. Second, while accept-language now returns an enumeration its contents are useless, forcing the portlet to use getProperty, as recommended in section 11.1.4 of the spec.

              Any desire to add this patch to the 2.4 source base? I could open a Jira and apply the patch.

              • 4. Re: NPE using JSTL format
                peterj

                Apparently no-one in the portal team is interested in getting the JSTL to work with the portal.* But for those poor souls who are still wrestling with this and don't want to make my suggested patch, I just came across a hidden, top secret tag** supplied by the JBoss portal: i18n. This tag provides similar functionality as the standard fmt:message tag. To see its usage, look at the file jboss-portal.sar/portal-core.war/WEB-INF/jsp/user/register.jsp. That's all for now, I'm off to convert my JSPs to use the i18n tag.

                * Actually, I understand this sentiment. Sometimes what appears to be a small, innocuous change can really cause havoc or other forms of untold misery. So I understand why the portal team would be hesitant to adopt the patch. Perhaps I should have placed a smiley face next to my comment; the comment is a jest, not a complaint.

                **I grepped for 'i18n' in the portal docs directory and did not get any hits, therefore it must be top secret.

                • 5. Re: NPE using JSTL format

                  I mustve missed the original post. I suggest you create a jira task, and assign it to Julien and point to this post. He can then evaluate whether to path or not.

                  This should probably go in the Design Forums, but its fine here for now.

                  • 6. Re: NPE using JSTL format
                    peterj

                    Thanks Roy: JBPORTAL-984.

                    To everyone else following this saga, looks like the i18n tag isn't a good alternative. Apparently the class that implements it expects an HttpRequest object to be in thread local storage, but when called from my portlet code, there is no HttpRequest object so I get an NPE:

                    2006-08-17 14:48:12,851 ERROR [org.apache.catalina.core.ContainerBase.[jboss.web].[localhost].[/image].[jsp]] Servlet.service() for servlet jsp threw exception
                    java.lang.NullPointerException
                     at org.jboss.portal.core.servlet.jsp.taglib.PortalLib.getMessage(PortalLib.java:53)
                     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
                     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
                     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
                     at java.lang.reflect.Method.invoke(Method.java:585)
                     at org.apache.commons.el.FunctionInvocation.evaluate(FunctionInvocation.java:172)
                     at org.apache.commons.el.ExpressionEvaluatorImpl.evaluate(ExpressionEvaluatorImpl.java:263)
                     at org.apache.commons.el.ExpressionEvaluatorImpl.evaluate(ExpressionEvaluatorImpl.java:190)
                     at org.apache.jasper.runtime.PageContextImpl.proprietaryEvaluate(PageContextImpl.java:932)
                     at org.apache.jsp.WEB_002dINF.jsp.edit_jsp._jspService(edit_jsp.java:98)
                     at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:97)
                    etc.


                    • 7. Re: NPE using JSTL format

                      Would the PortletRequest return the correct header value from the portal request solve the problem ?

                      getHeader() can return the value from PortletRequest.getProperties() which actually delegates to the portal request if it is not found in the properties.

                      Try the following patch and tell me what it gives you : in DispatchedHttpServletRequest replace

                      public String getHeader(String s)
                       {
                       return null;
                       }


                      by

                      public String getHeader(String s)
                       {
                       return rreq.getProperty(s);
                       }


                      This is what the portlet specification allows us to do in term of spec compliance.

                      If this works for you, I'll put it in 2.4.X branch (likely to be in 2.4.1) and HEAD (2.6).


                      • 8. Re: NPE using JSTL format
                        peterj

                        Julien,

                        Actually, the JSTL code calls getHeaders, not get Header. Not sure why, especially since it never looks at the results, except to see if the returned Enumeration has at least one entry. So the proper patch for fmt:message is:

                        public Enumeration getHeaders(String s)
                         {
                         return rreq.getProperties(s);
                         }


                        I have verified that fmt:message behaves correctly with this patch applied.

                        Of course, you could also include the getHeader patch you proposed to made the API more consistent.

                        • 9. Re: NPE using JSTL format

                          getHeaders() and getHeader() and getHeaderNames() would all be implemented delegating to getProperties(), getProperty() and getPropertyNames(), that would return portal http request values. Would that be sufficient ?

                          I am reluctant to add specific hacks for a particular library as it could conflict with some other library that would need a different return value for example.

                          • 10. Re: NPE using JSTL format
                            peterj

                            Sounds fine by me.

                            Thanks, Julien.

                            • 11. Re: NPE using JSTL format
                              jupallis

                              I'm getting this NPE again.

                              I'm using the JBoss 2.6.6 with JBoss AS 4.2.3.


                              Though the request.getHeaders("accept-language") is returning the header with browser langugage(en_us in my case). The request.getLocales() is returning 'null' because of which the JSTL tag is throwing the NPE.

                              Please find the stack trace below:
                              18:58:46,984 ERROR [[jsp]] Servlet.service() for servlet jsp threw exception
                              java.lang.NullPointerException
                               at org.apache.taglibs.standard.tag.common.fmt.BundleSupport.findMatch(Bu
                              ndleSupport.java:250)
                               at org.apache.taglibs.standard.tag.common.fmt.BundleSupport.getLocalizat
                              ionContext(BundleSupport.java:186)
                               at org.apache.taglibs.standard.tag.common.fmt.BundleSupport.doStartTag(B
                              undleSupport.java:95)
                               at org.apache.jsp.layouts.autodesk._2column_jsp._jspx_meth_fmt_005fbundl
                              e_005f0(_2column_jsp.java:563)
                               at org.apache.jsp.layouts.autodesk._2column_jsp._jspService(_2column_jsp
                              .java:180)
                               at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
                               at javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
                               at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper
                              .java:373)
                               at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:3
                              36)
                               at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:265)
                               at javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
                               at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(Appl
                              icationFilterChain.java:290)
                               at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationF
                              ilterChain.java:206)