5 Replies Latest reply on Oct 7, 2008 7:15 PM by bashan

    Facelets component and Seam

    bashan

      Hi,


      I have this facelets component:


      <ui:component xmlns="http://www.w3.org/1999/xhtml"
                    xmlns:ui="http://java.sun.com/jsf/facelets"
                    xmlns:f="http://java.sun.com/jsf/core"
                    xmlns:h="http://java.sun.com/jsf/html"
                    xmlns:s="http://jboss.com/products/seam/taglib"
                    xmlns:t="http://myfaces.apache.org/tomahawk"
                    xmlns:a4j="http://richfaces.org/a4j"
                    xmlns:rich="http://richfaces.org/rich"
                    xmlns:view="http://com.nikonians.ui/view"
                    xmlns:path="http://com.nikonians.ui/path">
        <h:graphicImage value="img/default_portrait.gif" rendered="#{empty userService.getAvatarUrl(user)}"
                        styleClass="picture"/>
        <h:graphicImage value="#{userService.getAvatarUrl(user)}" rendered="#{not empty userService.getAvatarUrl(user)}"
                        styleClass="picture"/>
      </ui:component>



      and this class:


      @Name("userService")
      public class UserService
      {
        public String getAvatarUrl(User user)
        {
          return PathUtil.getAvatarUrl(user.getUserId());
        }
      }



      I was wondering, does Seam has a way of dealing with the method getAvatarUrl getting called several times?


      Thanks.


        • 1. Re: Facelets component and Seam
          dan.j.allen

          No, Seam does not alter the way that JSF works fundamentally. What you are observing is typical behavior of the encoding/decoding process of the UI component tree. During that process, certain attributes are evaluated multiple times. The rendered attribute is the worst offender, often called more a half dozen times (and depending on how many times you reference it, that number could go up).


          My advice to you is not to put logic in your getter methods, but rather treat them as a way to merely read the state of a component. If you do need to perform logic, I advise you to use a @Create or @Factory method, depending on what fits.

          • 2. Re: Facelets component and Seam
            bashan

            sorry, I think I didn't explain myself very well. I know that jsf got a tendency of actvating methods several times. I wanted to know if seam has a good solution to method call with parameters, like in the example I gave.
            thanks.

            • 3. Re: Facelets component and Seam
              andygibson.contact.andygibson.net

              I think you still need to clarify further. Seam does deal with method call parameters like the example you gave, assuming of course that user is a valid variable and references the user entity.


              Cheers,


              Andy

              • 4. Re: Facelets component and Seam
                bashan

                I know Seam doesn't deal with method call parameters. This is a feature of facelets...
                But, suppose I have a method with a parameter (most of the times it is one parameter, that is being passed to a Seam component...), and I want to make sure, this method will not be calculated half dozen times, like JSF tends to do, will @Factory pattern help me?

                • 5. Re: Facelets component and Seam
                  bashan

                  Right now, in order to solve this. I am injecting to the service a variable. and I make sure to initialize it. This service is used with some of my facelets component. But, what would happen, if the XHTML code will be organize in a manner, the service factory method will be called before my Action component was created?


                  This is what I am doing:




                  @Name("userService")
                  public class UserService
                  {
                    @In
                    UserDAO userDAO;
                  
                    @In User serviceUser;
                  
                    @Factory(value="avatarMedium", scope=ScopeType.CONVERSATION)
                    public String getAvatarMediumUrl()
                    {
                      return PathUtil.getAvatarMediumUrl(serviceUser.getUserId());
                    }
                  
                    @Factory(value="userVideos", scope=ScopeType.CONVERSATION)
                    public List<Video> getUserVideos()
                    {
                      return userDAO.getVideos(serviceUser);
                    }
                  }
                  



                  The serviceUser is the member I am injecting, I initialize it in an Action bean.



                  Is it a good way? is there a better solution?