11 Replies Latest reply on Oct 9, 2009 2:45 PM by Stefan Woerner

    Problem with h:message or s:message or h:messages

    Stefan Woerner Newbie

      Hello,


      i have some problems with the h:message or s:message tag. On a XHTML page i have two sections for messages, one for error messages and one for info messages. All messages are added in a stateful session bean.


      The error messages code:


      m_facesMessages.addFromResourceBundle( Severity.ERROR, "messages.error" );



      The info message code:


      m_facesMessages.addToControlFromResourceBundle( "infoMessagesSection", Severity.INFO, "messages.info" );



      To divide the two message types i thought of adding error messages as global messages and info messages for a special info messages id called infoMessagesSection. So in my XHTML page i have the following code:


      <s:div id="errorMessages" styleClass="contentsection error">
        <h4><h:outputText value="#{messages['error.caption']}" /></h4>
          <h:messages globalOnly="true" />
      </s:div>
      
      ...
                      
      <s:div id="infoMessages" styleClass="contentsection info">
        <h4><h:outputText value="#{messages['info.caption']}" /></h4>
        <h:form>
          <h:inputHidden id="infoMessagesSection" />
          <h:message for="infoMessagesSection" />
        </h:form>
      </s:div>



      the error message section works fine, alle error messages are displayed. But the info section doesn't display anything. Only in the log file i can see:


      INFO  [lifecycle] WARNING: FacesMessage(s) have been enqueued, but may not have been displayed.
      sourceId=infoMessagesSection[severity=(INFO 0), summary=(Test), detail=(Test)]



      what am i doing wrong here? Or is there another way to achieve these two sections? I also tried the s:message tag but got the same result.


      Greetz Stefan

        • 1. Re: Problem with h:message or s:message or h:messages
          Stefan Woerner Newbie

          Doesn't anyone have a solution for my problem?

          • 2. Re: Problem with h:message or s:message or h:messages
            Oğuzhan Ceylan Newbie

            difference is h:messages-h:message. GlobalOnly attribute may be catching facesMessage, if this hypotesis true, you can try reRendering infoMessages div.

            • 3. Re: Problem with h:message or s:message or h:messages
              Nikos Paraskevopoulos Novice

              Hi,


              Stefan did you try what Oguzhan Ceylan said, i.e. reRender the container of the <h:message>?


              Also please note that <h:message> will only display the first message of a control, as per specs.


              In the application I am currently working on, I have replaced the renderers for h:message/h:messages. It wasn't hard at all. Based on this experience, I suggest you extend the default messages renderer and add something like a threshold attribute. If this attribute is present, the renderer will only render messages of the appropriate level. If it is not present, it will switch to the default behaviour.


              I'd happily provide you with more details, if you are interested.

              • 4. Re: Problem with h:message or s:message or h:messages
                Stefan Woerner Newbie

                Hi Oguzhan, hi Nikos.


                sorry for replying that late. The last view days i had to do some other things and had no time to test it out.
                Unfortunately the rerendering doesn't solve my problem, looks like the message tag isn't designed for my purpose. The option you mentioned Nikos, sounds interesting, but i have to say that i didn't have that much experience in developing web applications in seam. I don't know how to extend the default message by an new attribute, so if you could help me at this point would be very nice :)


                Thanks a lot,
                Greetings Stefan

                • 5. Re: Problem with h:message or s:message or h:messages
                  Nikos Paraskevopoulos Novice

                  Hi Stefan,


                  Here are instructions and as much code as possible. I suggest you download the source code of the JSF implementation you are using, it provides valuable clues. Anyway, the following Java code is based on the JSF RI from Sun. I also assume you will only be using Facelets. Developing the tag handler and taglib descriptor for JSPs is only pain.


                  1) Extend the standard renderer for UIMessages. It is com.sun.faces.renderkit.html_basic.MessagesRenderer for the RI:


                  public class ThresholdMessagesRenderer extends MessagesRenderer
                  {
                    public void encodeEnd(FacesContext context, UIComponent component) throws IOException {
                      ...
                    }
                  }
                  



                  Encoding, i.e. rendering of the messages, happens in the method shown above. Try running it in a debugger and you will find out how the standard renderer does it.


                  2) You need to re-implement this method to take into account the severity thresholds. Relevant code:


                    public void encodeEnd(FacesContext fctx, UIComponent component) throws IOException {
                      ...
                      String lowerThreshold = readStringValue(fctx, component, "low");
                      String upperThreshold = readStringValue(fctx, component, "high");
                      ...
                      Iterator messageIter = getMessageIter(fctx, clientId, component); // see orig. source for clientId
                      ...
                      while (messageIter.hasNext()) {
                        FacesMessage curMessage = (FacesMessage) messageIter.next();
                        if( !isSeverityWithinBounds(curMessage.getSeverity(), lowerThreshold, upperThreshold) ) {
                          continue;
                        }
                        ...
                      }
                    }
                    
                    private String readStringValue(FacesContext fctx, UIComponent component, String name) {
                      Object ret = null;
                      ValueExpression ve = component.getValueExpression(name);
                      if( ve != null ) ret = ve.getValue(fctx.getELContext());
                      else ret = component.getAttributes().get(name);
                      return ret != null ? ret.toString() : null;
                    }
                    
                    private isSeverityWithinBounds(FacesMessage.Severity severity, String low, String high) {
                      ...
                    }
                  



                  With the help of the two utility methods, encodeEnd() reads the threshold attributes from the component and filters out the messages with irrelevant severity.


                  3) Now you must register the renderer in faces-config.xml, overriding the default one:


                  <faces-config>
                    ...
                    <render-kit>
                      ...
                      <renderer>
                        <component-family>javax.faces.Messages</component-family>
                        <renderer-type>javax.faces.Messages</renderer-type>
                        <renderer-class>foo.bar.ThresholdMessagesRenderer</renderer-class>
                      </renderer>
                      ...
                    </render-kit>
                  </faces-config>
                  



                  Finally, you would use the new renderer with the standard <h:messages> tag:


                  <h:messages ... low="INFO" high="ERROR" />
                  



                  The names of the attributes low and high are specified in the code for ThresholdMessagesRenderer.


                  Hope this helps.

                  • 6. Re: Problem with h:message or s:message or h:messages
                    Stefan Woerner Newbie

                    First of all, thank you very much for your help!!
                    I will try this tomorrow, and will post the results of course.


                    Greetings Stefan

                    • 7. Re: Problem with h:message or s:message or h:messages
                      Nikos Paraskevopoulos Novice

                      One more thing:


                      In addition to the server-side solution presented above, you could use client-side techniques.


                      1) The simplest is to specify a non-visible CSS style or class for message severities that should not be shown, e.g.:


                      <h:messages infoStyle="display:none" />
                      



                      This would hide all info messages. However the content would still be generated and transfered, so two <h:messages> would double the size of the messages.


                      2) You could differentiate messages using classes, then move them to another location using Javascript. E.g. for this:


                      <h:messages id="msg_A" infoClass="inf" errorClass="err" />
                      
                      <ul id="msg_B"></ul>
                      



                      a jQuery line like this:


                      jQuery("#msg_A li.inf").appendTo("#msg_B")
                      



                      would move all <li class="inf">, i.e. info messages, to the second container.

                      • 8. Re: Problem with h:message or s:message or h:messages
                        Serkan Eskici Novice
                        Just use <rich:messages level="INFO, ERROR" /> instead.

                        Cheers.
                        • 9. Re: Problem with h:message or s:message or h:messages
                          Serkan Eskici Novice
                          Just use <rich:messages level="INFO, ERROR" /> instead.
                          • 10. Re: Problem with h:message or s:message or h:messages
                            Stefan Woerner Newbie

                            Hi Nikos,


                            I've tested the server side solution and it works perfectly!! Now i can display to sections in my page:


                            <h:messages msgSeverityLevel="error" />
                            
                            ...
                            
                            <h:messages msgSeverityLevel="info" />



                            and getting the info messages displayed in the info section and the error messages in the error section. So that's exactly what i wanted to have :)


                            your second solution i haven't tried out, because i have expanded the server side rendering by some other attributes, so that i get an all in one solution for my messages problems.


                            So, thank you very much for your help!



                            @Serkan
                            Thanks for your suggestion, but that's not exactly what i wanted to have. It's better than h:messages of course, but not as good as the re-implementation of the message renderer for me.

                            • 11. Re: Problem with h:message or s:message or h:messages
                              Stefan Woerner Newbie

                              Hey,


                              now another problem occurs which i couldn't find a solution for.
                              I have the messages adaptations described above running and working. On a page i have a form with a submit button, which executes a method which throws an exception if something wrong happend. Therefor i wrote an Exception class and annotated it by:


                              @ApplicationException(end = false, rollback = false)
                              @Redirect(viewId = "errorpage.xhtml")



                              The exception has a localized message which is displayed on the errorpage.xhtml page successfully. But the severity of this message is INFO and not ERROR. I found out, that in the AnnotationRedirectHandler class the severity is read:


                              @Override
                              protected Severity getMessageSeverity(Exception e)
                              {
                                return FacesMessage.SEVERITY_INFO;
                              }



                              so the basic implementation in seam is always INFO. But how can i switch this to ERROR? I need to do this programmatically in my action method or via the exception class, because i get dynamically the messages and sometimes the severity should be INFO and sometimes it should be ERROR. I saw that in the page.xml i can define an attribute for message-tag inside the exception-tag where i can set the severity. But how do i do this in my method or exception class?


                              thanks and greetings
                              Stefan