10 Replies Latest reply on Oct 21, 2010 3:46 PM by lrpieri

    Filter with selectOneMenu

    lrpieri

      Hi,


      I'd like to use a selectOneMenu as field for filter.


      For example:
      in a list of people I could have a selectOneMenu with companies to filter people by companies.


      Does anybody has any example?


      Tks

        • 1. Re: Filter with selectOneMenu
          lvdberg

          Hi,


          You can use the value-attribute of the selectOneMenu as a restriction for a EntityQuery.


          Something like:




          <framework:entity-query name="whateverQuery"
                    entity-manager="#{entityManager}" 
                    ejbql="select w from Whatever w"
                    order="w.prop asc"
                    max-results="100">
                    <framework:restrictions>
                         <value>w.company = #{yourBean.selectOneMenu.value}</value>
                    </framework:restrictions>
          </framework:entity-query>
          
          



          The query is fired whenever you change the select and you can the result as follows:




          @In(create=true) EntityQuery<Whatever> whateverQuery;
          



          Hopefully this helps.


          Leo


          P.S. the documentation and examples contain lots of guidance for this issue.


          • 2. Re: Filter with selectOneMenu
            lrpieri

            Dear Leo,
            Firstly, thanks for your attention.
            Sorry for my nescience, but I tested almost all seam examples and can't find an ocurrence of filtering using selectOneMenu, neither on documetation.


            So


            I'll reproduce my situation with more details to help you to help me. :-)


            The entity I'd like to filter is



            public class UploadedFile implements java.io.Serializable {
            ...
                private int id;
                private String path;
                private Company producer;
            ...
            }




            My EntityQuery



            public class UploadedFileList extends EntityQuery<UploadedFile> {
            
                private static final String[] RESTRICTIONS = {
                "lower(uploadedFile.path) like lower(concat('%',concat(#{uploadedFileList.uploadedFile.path},'%')))" ,
                "uploadedFile.producer.id = #{uploadedFileList.uploadedFile.id}"};
               
                private static final String EJBQL = "SELECT uploadedFile FROM UploadedFile uploadedFile WHERE uploadedFile.parent IS NULL";
            
                private UploadedFile uploadedFile = new UploadedFile();
            
                public UploadedFileList() {
                    setEjbql(EJBQL);
                    setRestrictionExpressionStrings(Arrays.asList(RESTRICTIONS));
                    setRestrictionLogicOperator("and");
                    setOrderColumn("uploadedFile.uploadedDate");
                    setOrderDirection("desc");
                    setMaxResults(25);
                }
            }





            Part of .xhtml



            <h:form id="uploadedFileSearch" styleClass="edit">
                        <rich:simpleTogglePanel label="#{messages['search.filter']}" switchType="ajax">
                            <s:decorate template="../../layout/display.xhtml">
                                <ui:define name="label">Arquivo</ui:define>
                                <h:inputText id="path" value="#{uploadedFileList.uploadedFile.path}"/>
                            </s:decorate>
                            <s:decorate template="../../layout/display.xhtml">
                                <ui:define name="label">Produtor</ui:define>
                                <h:selectOneMenu id="producer"
                                                value="#{uploadedFileList.uploadedFile.producer}"
                                                required="true">
                                    <s:selectItems value="#{pointUploadServiceHome.getProducers()}"
                                                    var="_producer"
                                                    label="#{_producer.name}"
                                                    noSelectionLabel="Selecione um produtor..."/>
                                    <s:convertEntity />
                                </h:selectOneMenu>
                            </s:decorate>
                            <s:decorate template="../../layout/display.xhtml">
                                <div class="actionButtons">
                                    <h:commandButton id="search" value="#{messages['search']}" action="/pages/upload/point/UploadedFileList.xhtml"/>
                                    <s:button id="reset" value="#{messages['reset']}" includePageParams="false"/>
                                </div>
                            </s:decorate>
                        </rich:simpleTogglePanel>
                    </h:form>
            
            



            What happend


            Opening the page of the list, no results are found, becouse it is filtering by 'provider'.


            If I choose a provider option and click to search, the follow error occurs:



            javax.el.ELException: Can't set property 'producer' of type 'br.com.mycompany.myproject.entity.Company' on class 'br.com.mycompany.myproject.entity.UploadedFile' to value 'br.com.mycompany.myproject.entity.Company@6a5afc'.
                at javax.el.BeanELResolver.setValue(BeanELResolver.java:330)
                at javax.el.CompositeELResolver.setValue(CompositeELResolver.java:275)
                at com.sun.faces.el.FacesCompositeELResolver.setValue(FacesCompositeELResolver.java:100)
                at org.jboss.el.parser.AstPropertySuffix.setValue(AstPropertySuffix.java:73)
                at org.jboss.el.parser.AstValue.setValue(AstValue.java:84)
                at org.jboss.el.ValueExpressionImpl.setValue(ValueExpressionImpl.java:249)
                at org.jboss.seam.core.Expressions$1.setValue(Expressions.java:117)
                at org.jboss.seam.navigation.Pages.applyConvertedValidatedValuesToModel(Pages.java:846)
                at org.jboss.seam.navigation.Pages.postRestore(Pages.java:443)
                at org.jboss.seam.jsf.SeamPhaseListener.postRestorePage(SeamPhaseListener.java:545)
                at org.jboss.seam.jsf.SeamPhaseListener.afterRestoreView(SeamPhaseListener.java:394)
                at org.jboss.seam.jsf.SeamPhaseListener.afterServletPhase(SeamPhaseListener.java:230)
                at org.jboss.seam.jsf.SeamPhaseListener.afterPhase(SeamPhaseListener.java:196)
                at com.sun.faces.lifecycle.Phase.handleAfterPhase(Phase.java:175)
                at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:114)
                at com.sun.faces.lifecycle.RestoreViewPhase.doPhase(RestoreViewPhase.java:103)
                at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118)
                at javax.faces.webapp.FacesServlet.service(FacesServlet.java:265)
                at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
                at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
                at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:83)
                at org.jboss.seam.web.IdentityFilter.doFilter(IdentityFilter.java:40)
                at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
                at org.jboss.seam.web.MultipartFilter.doFilter(MultipartFilter.java:90)
                at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
                at org.jboss.seam.web.ExceptionFilter.doFilter(ExceptionFilter.java:64)
                at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
                at org.jboss.seam.web.RedirectFilter.doFilter(RedirectFilter.java:45)
                at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
                at org.ajax4jsf.webapp.BaseXMLFilter.doXmlFilter(BaseXMLFilter.java:206)
                at org.ajax4jsf.webapp.BaseFilter.handleRequest(BaseFilter.java:290)
                at org.ajax4jsf.webapp.BaseFilter.processUploadsAndHandleRequest(BaseFilter.java:388)
                at org.ajax4jsf.webapp.BaseFilter.doFilter(BaseFilter.java:515)
                at org.jboss.seam.web.Ajax4jsfFilter.doFilter(Ajax4jsfFilter.java:56)
                at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
                at org.jboss.seam.web.LoggingFilter.doFilter(LoggingFilter.java:60)
                at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
                at org.jboss.seam.servlet.SeamFilter.doFilter(SeamFilter.java:158)
                at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
                at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
                at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
                at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
                at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
                at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
                at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
                at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298)
                at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:857)
                at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:588)
                at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
                at java.lang.Thread.run(Thread.java:619)
            Caused by: java.lang.IllegalArgumentException: argument type mismatch
                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:597)
                at javax.el.BeanELResolver.setValue(BeanELResolver.java:313)
            



            Thank you for your help

            • 3. Re: Filter with selectOneMenu
              lvdberg

              Hi,


              Your entityquery won't work because you're using it as a normal bean and you set the query and its options in a constructor, which is really forbidden in a Seam-environment.


              Please take some time to study the Query component and first try it out with the simple example as provided by me.


              Leo


               

              • 4. Re: Filter with selectOneMenu
                lvdberg

                Hi,


                additionally; I don't see any name-annotations on the bean, be sure that they are placed at the class level.


                Leo

                • 5. Re: Filter with selectOneMenu
                  lrpieri

                  Hi Leo,


                  More one time, thank you for your help.


                  I did not understand what you mean by normal bean.


                  About set query and options in constructor, this is the generated code by jBoss Tools plus Seam-gen:


                  @Name("uploadedFileList")
                  @Restrict(value = "#{s:hasRole(accountHome.roleNameControllerUser) || s:hasRole(accountHome.roleNameProviderUser)}")
                  public class UploadedFileList extends EntityQuery<UploadedFile> {
                  
                       private static final long serialVersionUID = -1706808665658570124L;
                  
                       private static final String[] RESTRICTIONS = { "lower(uploadedFile.path) like lower(concat('%',concat(#{uploadedFileList.uploadedFile.path},'%')))"};
                       
                       private static final String EJBQL = "SELECT uploadedFile FROM UploadedFile uploadedFile WHERE";
                  
                       private UploadedFile uploadedFile = new UploadedFile();
                       
                       public UploadedFileList() {
                            setEjbql(EJBQL);
                            setRestrictionExpressionStrings(Arrays.asList(RESTRICTIONS));
                            setMaxResults(25);
                       }
                  ...
                  }



                  I just did some modifications on EJBQL and RESTRICTIONS to adapt to my needs.


                  And about the name-annotations, yes, the classes has it. I just ignored it on post to save space.



                  @Entity
                  @Table(name="uploaded_files", schema = "public")
                  public class UploadedFile implements java.io.Serializable {
                  ...
                      private int id;
                      private String path;
                      private Company producer;
                  ...
                  }



                  @Name("uploadedFileList")
                  @Restrict(value = "#{s:hasRole(accountHome.roleNameControllerUser) || s:hasRole(accountHome.roleNameProviderUser)}")
                  public class UploadedFileList extends EntityQuery<UploadedFile> {
                  
                      private static final String[] RESTRICTIONS = {
                      "lower(uploadedFile.path) like lower(concat('%',concat(#{uploadedFileList.uploadedFile.path},'%')))" ,
                      "uploadedFile.producer.id = #{uploadedFileList.uploadedFile.id}"};
                     
                      private static final String EJBQL = "SELECT uploadedFile FROM UploadedFile uploadedFile WHERE uploadedFile.parent IS NULL";
                  
                      private UploadedFile uploadedFile = new UploadedFile();
                  
                      public UploadedFileList() {
                          setEjbql(EJBQL);
                          setRestrictionExpressionStrings(Arrays.asList(RESTRICTIONS));
                          setRestrictionLogicOperator("and");
                          setOrderColumn("uploadedFile.uploadedDate");
                          setOrderDirection("desc");
                          setMaxResults(25);
                      }
                  }
                  


                  Now more one question:


                  I've started studying the Query component and the documentation and your suggestion suggests to declare the Query on components.xml. But can I do something like follow on components.xml?



                  @Override
                  public String getEjbql() {
                       String ejbql = "SELECT uploadedFile FROM UploadedFile uploadedFile ";
                       String where = " WHERE uploadedFile.parent IS NULL";
                       if(!Identity.instance().hasRole(RoleType.CONTROLLER_USER.getName())){
                            Account account = (Account) ServletContexts.instance().getRequest().getSession().getAttribute("account");
                            Query query = getEntityManager().createNamedQuery(Company.NAMED_QUERY_FIND_BY_ACCOUNT_ID);
                            query.setParameter("idAccount", account.getId());
                            Company provider = (Company) query.getSingleResult();
                            ejbql += " JOIN uploadedFile.provider provider ";
                            where += " AND provider.id = " + provider.getId();
                            if(!Identity.instance().hasRole(RoleType.PROVIDER_ADMIN.getName()) && Identity.instance().hasRole(RoleType.PROVIDER_USER.getName())){
                                 ejbql += " JOIN uploadedFile.person person JOIN person.accounts account ";
                                 where += " AND account.id = " + account.getId();
                            }
                       }
                       ejbql += where;
                       return ejbql;
                  }




                  More one time, thank you for your help.


                  Regards


                  PS: Sorry for my english. This is not my native lenguage





                  • 6. Re: Filter with selectOneMenu
                    lvdberg

                    Hi,


                    The components.xml version is for the quick and dirty queries and certainly not for additional restiction work as stated in your last message.


                    And concerniong the use of the constructor of Seam-gen. Ok I just learnned something new!


                    Leo

                    • 7. Re: Filter with selectOneMenu
                      lvdberg

                      Hi,


                      just some thinking, but the error states:


                      Caused by: java.lang.IllegalArgumentException: argument type mismatch


                      While it tries to set the correct value. Do you have this class somewhere else in a jar or other project  in the same server. It looks like the project works with different entities.


                      Leo

                      • 8. Re: Filter with selectOneMenu
                        lrpieri

                        Hi Leo,


                        It seems that what was missing was a Converter. I did it and don't have errors more. But the filter is not working.


                        It seems that the sql instruction is been executed but it do not return any value.


                        I executed the sql instruction showed on console just changing the ? for the value that should be there in a SQL Client and it works fine. But on system not. I'm also using the http://www.elvyx.com/ to help to see the sql instructions and this is not showing that instruction. So there are something wrong here and I dont know what is.


                        Maybe a cache?


                        Do you have any idea about what can be going?


                        Thanks for all.

                        • 9. Re: Filter with selectOneMenu
                          lvdberg

                          Hi,


                          the important thing is that the query is executed. To see the produced SQL you can set a propert in persistence.xml, which results in showing all queries (with the ? placeholder off course) and the EntityQuery has a method to provide you the SQL. Try logging of all values in your code to see what is provided/read from the different methods.


                          Debugging is fun !!


                          Leo

                          • 10. Re: Filter with selectOneMenu
                            lrpieri

                            Problem resolved


                            I've the UploadedFileList, that returns a list of uploaded files.
                            The class uploaded file has a path (String) ans a provider (Company).
                            To filter by path the filter parameter was stored in uploadedFileList.uploadedFile.path but it apparently doesn't work for non primitive values as the Company provider.
                            To solve I declared a new attibute Company provider in uploadedFileList and used it for filter.


                            Could it be a bug?


                            Thanks for all help.