2 Replies Latest reply on Jun 7, 2010 12:43 PM by Walt Corey

    Factory with SelectOneMenu

    Walt Corey Newbie

      There is a lot of confusion on this over the web and even on here.
      I have successfully used @Factory in previous Seam Apps.


      According to Dan, one really really really wants to use @Factory. In this particular case I am trying to populate a SelectOneMenu on a page.


      Here is the xhtml:




          <h:form id="QueryPerformanceSheetForm">
      
              <rich:panel>
                  <f:facet name="header">queryPerformanceSheet</f:facet>
      
                              <s:decorate id="monthChoice" template="layout/display.xhtml">
                                      <ui:define name="label">Month</ui:define>
                                      <h:selectOneMenu id="monthList"  value="#month}">
                                              <f:selectItems value="#monthList}"></f:selectItems>
                                      </h:selectOneMenu>
                              </s:decorate>
       
                  <div style="clear:both"/>
      
              </rich:panel>
      
              <div class="actionButtons">
                  <h:commandButton id="queryPerformance" value="Display"
                          action="#{QueryPerformanceSheet.queryPerformance}"/>
              </div>
      
          </h:form>
      


      The issue is I keep getting either ...expected selectItems/selectItem child of.... or propertyNotFoundException on monthList.


      In the example in Dan's book as the output value (selected value) is defined as @DataModelSelector followed by @Out for the selectedGolfer...er...month and the List of SelectedItem is defined under @DataModel and the actual list attribute is defined under the @Factory why is Seam still looking for a property called monthList?


      My latest error is:
      Expected a child component type of UISelectItem/UISelectItems for component type javax.faces.SelectOne(monthList).  Found org.jboss.seam.jsf.ListDataModel.



      My Code is:


      @Name("QueryPerformanceSheet")
      public class QueryPerformanceSheetBean implements QueryPerformanceSheet {
              private static String monthQuery = "select distinct month(date) from Httpquery q";
              @Logger
              private Log log;
      
              @In
              StatusMessages statusMessages;
              @In
              protected EntityManager entityManager;
              
              private String value;
      
              @DataModelSelection
              @Out(required=false)
              public String month = "";
              
              @DataModel(scope = ScopeType.PAGE)
              public List<SelectItem>monthList;
              
              public void queryPerformance() {
                      monthList = new ArrayList<SelectItem>();
                      // implement your business logic here
                      log
                                      .info("QueryPerformanceSheet.queryPerformance() action called with: #{QueryPerformanceSheet.value}");
                      statusMessages.add("queryPerformance #{QueryPerformanceSheet.value}");
              }
              
      
              // add additional action methods
              public void setMonth(String month) {
                      this.month = month;
              }
      
              @Length(max = 10)
              public String getValue() {
                      return value;
              }
      
              public void setValue(String value) {
                      this.value = value;
              }
      
              @Remove
              public void destroy() {
              }
      
              @SuppressWarnings("unchecked")
              @Factory("monthList")
              public void initForm() {
                      if (monthList == null) {
                              monthList = new ArrayList<SelectItem>();
                      }
                      ArrayList<Integer> tmp = 
                      (ArrayList)entityManager.createQuery(monthQuery).getResultList();
                      for (Integer month:tmp) {
                              System.out.println("Month = " + month);
                              SelectItem si = new SelectItem(month.toString(), month.toString());
                              monthList.add(si);
                      }
      
              }
      




      My question is two-fold:


      What's wrong with this code?


      What is the intelligent way to produce this as a component

        • 1. Re: Factory with SelectOneMenu
          Pablo Palazon Newbie

          Hi Walt!!, I see your code and I've found some syntax errors:


          <f:selectItems value="#monthList}"></f:selectItems>
          



          will be



          <f:selectItems value="#{monthList}"></f:selectItems>
          


          You have this problem in #month}, too


          The month variable need JavaBeans getter and setter public method for use with EL expression in h:selectOneMenu value.


          I hope that I can help you. Best regards!!

          • 2. Re: Factory with SelectOneMenu
            Walt Corey Newbie
            Thank you for your input Pablo!

            Here is the current section for the selectOneMenu items



            `<h:form id="QueryPerformanceSheetForm">

                <rich:panel>
                 <f:facet name="header">queryPerformanceSheet</f:facet>

                 <s:decorate id="monthChoice" template="layout/display.xhtml">
                      <ui:define name="label">Month</ui:define>
                 <h:selectOneMenu id="monthList" value="#{queryPerformanceSheet.month}">
                 <f:selectItems value="#{QueryPerformanceSheet.monthList}"></f:selectItems>
                 </h:selectOneMenu>
                 </s:decorate>

                 <s:decorate id="countryChoice" template="layout/display.xhtml">
                 <ui:define name="label">Country</ui:define>
                 <h:selectOneMenu id="countryList" value="#{queryPerformanceSheet.country}">
                 <f:selectItems value="#{QueryPerformanceSheet.countryList}"></f:selectItems>
                 </h:selectOneMenu>
                 </s:decorate>

                 <s:decorate id="engineChoice" template="layout/display.xhtml">
                 <ui:define name="label">Engine</ui:define>
                 <h:selectOneMenu id="engineList" value="#{queryPerformanceSheet.engine}">
                 <f:selectItems value="#{QueryPerformanceSheet.engineList}"></f:selectItems>
                 </h:selectOneMenu>
                 </s:decorate>
                 <div style="clear: both" />

                </rich:panel>
            `
            I tried using @RequestParameters but ran into a problem there and created a queryPerformance.page.xml as follows:
            <?xml version="1.0" encoding="UTF-8"?>
            <page xmlns="http://jboss.com/products/seam/pages"
                  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                  xsi:schemaLocation="http://jboss.com/products/seam/pages http://jboss.com/products/seam/pages-2.2.xsd">
                 <param name="engine" value="#{QueryPerformanceSheet.engine}"/>
                 <param name="country" value="#{QueryPerformanceSheet.country}"/>
                 <param name="month" value="#{QueryPerformanceSheet.month}"/>
                <action execute="#{QueryPerformanceSheet.onDisplay}"/> 
                 
            </page>     

            In the component I have accessors around all three and a factory method for the two lists. I could not get factory methods to for the selectItems and figured it was due to it not being a UIData or such.

            Oddly, and I say oddly because I don't know why, but now I see the parameters coming in at action method invocation. My problem now is the controls are not getting synchronized with how they were left. One thing I did was notice that the invocations of the getters were not at all happy when the values came back null. I consequently placed conditional test for setting the value if it were null at invocation.

            Here is the current bean.




            `
            import java.util.ArrayList;
            import java.util.Calendar;
            import java.util.List;
            import java.util.TreeMap;

            import javax.faces.model.SelectItem;
            import javax.persistence.EntityManager;

            import org.jboss.seam.ScopeType;
            import org.jboss.seam.annotations.Factory;
            import org.jboss.seam.annotations.Name;
            import org.jboss.seam.annotations.In;
            import org.jboss.seam.annotations.Logger;
            import org.jboss.seam.annotations.Scope;
            import org.jboss.seam.annotations.datamodel.DataModel;
            import org.jboss.seam.log.Log;
            import org.jboss.seam.international.StatusMessages;

            @Name("QueryPerformanceSheet")
            @Scope(ScopeType.CONVERSATION)
            public class QueryPerformanceSheetBean implements QueryPerformanceSheet {
                 private static final String monthQuery = "select distinct month(date) from Httpquery q";
                 private static final String countryQuery = "select c.country from Country c order by c.id";
                 private static final String fullCorpusQuery = "";
                 private static final String ltQuery = "";
                 private static final String fullCorpusQueryClassic = "";
                 private static final String ltQueryClassic = "";
                 private static final String fullCorpusQueryPower = "";
                 private static final String ltQueryPower = "";
                 private String fullQuery;
                 private String subQuery;
                 @Logger
                 private Log log;

                 @In
                 StatusMessages statusMessages;
                 @In
                 protected EntityManager entityManager;
                 
                 private String engine;
                 
                 private String month;

                 private String country;
                 
                 public List<SelectItem> monthList;

                 public List<SelectItem> countryList;
                 
                 public List<SelectItem> engineList;
                 
                 private List<Object[]> fullCorpusList;
                 private List<Object[]> ltSixList;
                 private List<Object[]> ltEightList;
                 private List<Object[]> ltTenList;
                 
                 @DataModel(scope = ScopeType.PAGE, value="bedfordList")
                 private List<PercentageDay>bedfordList;
                 
                 
                 private TreeMap<String, PercentageDay> daysBedfordTree;
                 
                 @DataModel(scope = ScopeType.PAGE, value="maynardList")
                 private List<PercentageDay>maynardList;
                 
                 
                 private TreeMap<String, PercentageDay> daysMaynardTree;

                 public void queryPerformanceSheetBean() {
                      if (daysBedfordTree == null) {
                           daysBedfordTree = new TreeMap<String, PercentageDay>();
                      }
                      if (daysMaynardTree == null) {
                           daysMaynardTree = new TreeMap<String, PercentageDay>();
                      }

                 }

                 @SuppressWarnings("unchecked")
                 public void onDisplay() {
                 }
                 /**
                  * @return the days for Bedford
                  */
                 @Factory("bedfordList")
                 public void getDaysBedford() {
                      bedfordList = new ArrayList<PercentageDay>();
                      if (daysBedfordTree == null) {
                           daysBedfordTree = new TreeMap<String, PercentageDay>();
                      }
                      for (String day : daysBedfordTree.keySet()) {
                           PercentageDay aDay = daysBedfordTree.get(day);
                           bedfordList.add(aDay);
                      }
                 }

                 /**
                  * @return the days for Maynard
                  */
                 @Factory("maynardList")
                 public void getDaysMaynard() {
                      maynardList = new ArrayList<PercentageDay>();
                      if (daysMaynardTree == null) {
                           daysMaynardTree = new TreeMap<String, PercentageDay>();               
                      }
                      for (String day : daysMaynardTree.keySet()) {
                           PercentageDay aDay = daysMaynardTree.get(day);
                           maynardList.add(aDay);
                      }
                 }

                 /*
                  * return proper color
                  */
                 public String getColor(Integer cell) {
                      String color = "pink";
                      int tmp = cell.intValue();
                      if (tmp > 77) {
                           color = "lightgreen";
                      } else {
                           if (tmp > 57) {
                                color = "lightyellow";
                           }
                      }
                      return color;
                 }

                 public void createTables(int site, int sequence, List<Object[]> list,
                           TreeMap<String, PercentageDay> tree) {
                      /*
                       * we are going to call this method multiple times varying the list
                       * (output list from full, six, eight, or 10 sec result sets from db and
                       * setting whether we want set the total, six, eight, or 10 sec bucket
                       * in the hourly
                       *
                       * we determine count and hour from the list.
                       *
                       * the tree we pass in will be, for instance, the bedford or maynard
                       * tree.
                       */
                      for (Object object[] : list) {
                           Integer location = (Integer) object[0];
                           if (location.intValue() != site) {
                                continue;
                           }
                           String year = ((Integer) object[1]).toString();
                           String month = ((Integer) object[2]).toString();
                           String day = ((Integer) object[3]).toString();
                           if (month.length() == 1)
                                month = "0" + month;
                           if (day.length() == 1)
                                day = "0" + day;
                           String date = year + "-" + month + "-" + day;
                           Integer ihour = (Integer) object[4];
                           Long count = (Long) object[5];
                           PercentageDay aDay = tree.get(date);
                           if (aDay == null) {
                                aDay = new PercentageDay();
                                aDay.setDate(date);
                                tree.put(date, aDay);
                           }
                           HourlyPerfData hour = aDay.getHour(ihour);
                           switch (sequence) {
                           case 0: // totals
                                hour.setTotal(count.intValue());
                                break;
                           case 1: // 6 seconds
                                hour.setSixSecond(count.intValue());
                                break;
                           case 2: // 8 seconds
                                hour.setEightSecond(count.intValue());
                                break;
                           case 3: // 10 seconds;
                                hour.setTenSecond(count.intValue());

                           }
                      }
                 }

                 // add additional action methods

                 public List<SelectItem> getMonthList() {
                      if (monthList == null) {
                           monthList = new ArrayList<SelectItem>();
                           initMonths();
                      }
                      return monthList;
                 }

                 public List<SelectItem> getCountryList() {
                      if (countryList == null) {
                           countryList = new ArrayList<SelectItem>();
                           initCountries();
                      }
                      return countryList;
                 }

                 public List<SelectItem> getEngineList() {
                      if (engineList == null) {
                           engineList = new ArrayList<SelectItem>();
                           initEngines();
                      }
                      return engineList;
                 }
                 
                 @SuppressWarnings("unchecked")
                 public void initMonths() {
                      if (monthList == null) {
                           monthList = new ArrayList<SelectItem>();
                      }
                      ArrayList<Integer> tmp = (ArrayList) entityManager.createQuery(
                                monthQuery).getResultList();
                      for (Integer month : tmp) {
                           System.out.println("Month = " + month);
                           SelectItem si = new SelectItem(month.toString(), month.toString());
                           monthList.add(si);
                      }

                 }

                 @Factory("engineList")
                 public void initEngines() {
                      if (engineList == null) {
                           engineList = new ArrayList<SelectItem>();
                      }
                      engineList.add(new SelectItem("Both", "Both"));
                      engineList.add(new SelectItem("Classic", "Classic"));
                      engineList.add(new SelectItem("Power", "Power"));
                 }
                 
                 
                 @SuppressWarnings("unchecked")
                 public void initCountries() {
                      if (countryList == null) {
                           countryList = new ArrayList<SelectItem>();
                      }
                      ArrayList<String> tmp = (ArrayList) entityManager.createQuery(
                                countryQuery).getResultList();
                      for (String country : tmp) {
                           System.out.println("Country = " + country);
                           SelectItem si = new SelectItem(country, country);
                           countryList.add(si);
                      }

                 }

                 /**
                  * @return the bedfordList
                  */
                 public List<PercentageDay> getBedfordList() {
                      return bedfordList;
                 }

                 /**
                  * @return the maynardList
                  */
                 public List<PercentageDay> getMaynardList() {
                      return maynardList;
                 }

                 /**
                  * @return the engine
                  */
                 public String getEngine() {
                      if (engine == null) {
                           engine = "Power";
                      }
                      return engine;
                 }

                 /**
                  * @param engine the engine to set
                  */
                 public void setEngine(String engine) {
                      this.engine = engine;
                 }

                 /**
                  * @return the country
                  */
                 public String getCountry() {
                      if (country == null) {
                           country = "US";
                      }
                      return country;
                 }

                 /**
                  * @param country the country to set
                  */
                 public void setCountry(String country) {
                      this.country = country;
                 }

                 public String getMonth() {
                      if (month == null) {
                           Calendar cal = Calendar.getInstance();
                           month = Integer.toString(cal.get(Calendar.MONTH));
                      }
                      return month;
                 }

                 public void setMonth(String month) {
                      this.month = month;
                 }

            }

            I cut out a lot of the code in the hopes it would make the important stuff more obvious.
            I also changed the h:command to s:button and added, in the xxx.page.xml an action for the button. I think my remaining issue is synchronizing the controls with what the user input had set it to, after the action completes.
            `