12 Replies Latest reply on May 16, 2007 12:22 PM by anescu

    @Filter example

      Hi,

      Is there a @Filter example for Seam??? I would need a working example to get me started, I looked at some Hibernate examples but I can't figure out how to integrate them in Seam (I know how to place the filter annotation on the entity but what else?).

      Also, if the example can use some relations and/or variables from the context (for example filter entity A by the user that created them, and the value would be the currentUser, from the session context), that would be great.

      Thanks.

        • 1. Re: @Filter example
          emsa
          • 2. Re: @Filter example

             

            "emsa" wrote:
            §8.6

            http://docs.jboss.com/seam/1.2.1.GA/reference/en/html/persistence.html#d0e5589


            I already read that part. Twice. To me it's like reading chinese. HOW do you make it work??? It doesn't say even in which XML file you have to put that part.

            And it doesn't say anything about the other parts of the application (I mean, how do you use the damn filter???). As I said, I have found examples with @Filter in Hibernate, but what else needs to be configured in the Seam Java code to make it work (using annotations, like @Filter, @FilterDef and so on)

            • 3. Re: @Filter example
              fernando_jmt

              1.- Define the Filter in your Entity.

              
              @Entity
              @Table(name="NODE")
               @org.hibernate.annotations.FilterDef(
               name = "accessLevelFilter",
               parameters = {@org.hibernate.annotations.ParamDef(name = "currentAccessLevel", type="integer")}
              )
              @org.hibernate.annotations.Filter(
               name = "accessLevelFilter",
               condition = "READ_ACCESS_LEVEL <= :currentAccessLevel"
              )
              public abstract class Node implements Serializable {
              ...
              @Column(name = "READ_ACCESS_LEVEL", nullable = false)
               protected int readAccessLevel;
              
              ...
              }
              
              


              2.- Configure components.xml

               <core:filter name="accessLevelFilter">
               <core:name>accessLevelFilter</core:name>
               <core:parameters>
               <key>currentAccessLevel</key>
               <value>#{currentAccessLevel}</value>
               </core:parameters>
               </core:filter>
              
               <core:managed-persistence-context name="restrictedEntityManager"
               auto-create="true"
               entity-manager-factory="#{wikiEntityManagerFactory}">
               <core:filters><value>#{accessLevelFilter}</value></core:filters>
               </core:managed-persistence-context>
              
              
              


              3.- Set somewhere a value for #{currentAccessLevel}.
               Contexts.getSessionContext().set("currentAccessLevel", bestRole.getAccessLevel());
              


              4.- Finally use the filtered Persistence Context.

              @Name("nodeDAO")
              @AutoCreate
              @Transactional
              public class NodeDAO {
              
               // Most of the DAO methods use this
               @In protected EntityManager restrictedEntityManager;
              ...
               public Node findNode(Long nodeId) {
               restrictedEntityManager.joinTransaction();
               try {
               return (Node) restrictedEntityManager
               .createQuery("select n from Node n where n.id = :nodeId")
               .setParameter("nodeId", nodeId)
               .getSingleResult();
               } catch (EntityNotFoundException ex) {
               } catch (NoResultException ex) {
               }
               return null;
               }
              
              }
              
              



              Above steps are based on the Seam wiki example. If you want to see more, check it out.

              HTH.

              • 4. Re: @Filter example

                Thanks for the reply, I hope this will get me started.

                Where do I find the Wiki example? It's not included in 1.2.1? I looked for the CVS link but I can't find it anywhere on the site.
                Do you have any example on how to define a Class type parameter?
                I mean, is this all that is different?

                ...
                @ParamDef(name="account",type="com.abc.Account")
                ...


                Or there is more?

                • 5. Re: @Filter example
                  fernando_jmt

                  AFAIK, Wiki example is in the CVS only.

                  Regarding class type parameter, I don't have any example and I don't know much about it. Looks like Hibernate specific stuff, so see Hibernate for this (but I guess you already did it).



                  • 6. Re: @Filter example

                     

                    "fernando_jmt" wrote:
                    AFAIK, Wiki example is in the CVS only.


                    Can you point me to the Seam CVS URL? I can't find it on JBoss site :(.

                    Tnx

                    • 7. Re: @Filter example

                       

                      "fernando_jmt" wrote:

                      3.- Set somewhere a value for #{currentAccessLevel}.
                       Contexts.getSessionContext().set("currentAccessLevel", bestRole.getAccessLevel());
                      


                      4.- Finally use the filtered Persistence Context.

                      @Name("nodeDAO")
                      @AutoCreate
                      @Transactional
                      public class NodeDAO {
                      
                       // Most of the DAO methods use this
                       @In protected EntityManager restrictedEntityManager;
                      ...
                       public Node findNode(Long nodeId) {
                       restrictedEntityManager.joinTransaction();
                       try {
                       return (Node) restrictedEntityManager
                       .createQuery("select n from Node n where n.id = :nodeId")
                       .setParameter("nodeId", nodeId)
                       .getSingleResult();
                       } catch (EntityNotFoundException ex) {
                       } catch (NoResultException ex) {
                       }
                       return null;
                       }
                      
                      }
                      
                      



                      So, i did steps 1 and 2, on no 3 i have an @Out(required = false, scope = ScopeType.SESSION) which should work, but how do I use step 4? I am using a Seam generated project, i can't find anywhere a entityManager, everything is done by Seam. I suppose i have to override a method, but hell if i know which one :(.

                      Also, now, i tried to deploy with the code i have, i just defined my entityMAnager with this:

                      <core:filter name="hubFilteredChannels">
                       <core:name>hubFilteredChannels</core:name>
                       <core:parameters>
                       <key>currentHub</key>
                       <value>#{currentHub}</value>
                       </core:parameters>
                       </core:filter>
                      
                       <core:managed-persistence-context name="entityManager"
                       auto-create="true"
                       persistence-unit-jndi-name="java:/entityManagerFactory">
                       <core:filters><value>#{hubFilteredChannels}</value></core:filters>
                       </core:managed-persistence-context>


                      And now i get an error when loading the first page:

                      Caused by: org.hibernate.HibernateException: Filter [hubFilteredChannels] parameter [currentHub] value not set


                      So what is wrong? Why does Seam loads everything on startup??? If I have a bad page I cannot see a thing, the page redirects me to the debug page...


                      • 8. Re: @Filter example
                        fernando_jmt

                        Post the page where you are setting the currentHub in the session (where you are using @Out). And also post the code where you are trying to use the entityManager you have configured in components.xml.

                        • 9. Re: @Filter example

                           

                          "fernando_jmt" wrote:
                          Post the page where you are setting the currentHub in the session (where you are using @Out). And also post the code where you are trying to use the entityManager you have configured in components.xml.


                          Here is how i use the parameter. It's in a bean that renders a combo box, near the menu:

                          @Out(required = false, scope = ScopeType.SESSION)
                           private Hub currentHub = null;


                          And as i said, i just changed the generated code for the entity manager to the one that uses also the filter. The only place where we use the entityManager by ourselves is this code, in the authenticate method:

                          this.currentUser = (User) this.entityManager.createQuery("from User where username = :username and password = :password").setParameter("username", this.identity.getUsername()).setParameter("password", this.identity.getPassword().getBytes()).getSingleResult();



                          In the rest, is used under the hood by seam. As i said, i'm new to this so i don't know what i need to override to use a custom entity manager (this way i can use both of them, i guess)

                          Also, i get the error when opening the first screen (/home.seam if you want), where the menu should be displayed (as i said, the seam-gen web interface). That is why i don't understand why it's trying to load a collection of entities when i have not even authenticated into the application. That is supposed to do the filter, display only the data i'm supposed to see.

                          Also, it seems i would need to use both entity managers, as the default one seem to be used to load related entities from the DB, i would like to display in the list only the X entities that correspond to a criteria.

                          So, what methods do i need to override to use a custom entityManager instead of the default one in a Seam generated skeleton???


                          • 10. Re: @Filter example

                            Ok, I have some progress:

                            1) I defined 2 entity managers in components.xml:

                            <core:managed-persistence-context name="entityManager"
                             auto-create="true"
                             persistence-unit-jndi-name="java:/entityManagerFactory"/>
                            
                            <core:filter name="hubFilteredChannels">
                             <core:name>hubFilteredChannels</core:name>
                             <core:parameters>
                             <key>currentHub</key>
                             <value>#{currentHub}</value>
                             </core:parameters>
                            </core:filter>
                            
                            <core:managed-persistence-context name="filteredEntityManager"
                             auto-create="true"
                             entity-manager-factory="#{entityManager}">
                             <core:filters><value>#{hubFilteredChannels}</value></core:filters>
                            </core:managed-persistence-context>


                            2) Then I override the getPersistenceContextName in my entity List class:
                            @Override
                            protected String getPersistenceContextName()
                            {
                             System.out.println( "### debug step" );
                             return "filteredEntityManager";
                            }


                            3) Now i can deploy and browse the other parts of the application as before using the filter, but i get an exception when opening the entity list screen, something about a ClassCastException:


                            Caused by: java.lang.ClassCastException: org.jboss.seam.persistence.EntityManagerProxy
                             at org.jboss.seam.core.ManagedPersistenceContext.getEntityManagerFactoryFromJndiOrValueBinding(ManagedPersistenceContext.java:169)
                             at org.jboss.seam.core.ManagedPersistenceContext.initEntityManager(ManagedPersistenceContext.java:77)
                             at org.jboss.seam.core.ManagedPersistenceContext.getEntityManager(ManagedPersistenceContext.java:105)
                             at sun.reflect.GeneratedMethodAccessor137.invoke(Unknown Source)


                            • 11. Re: @Filter example
                              fernando_jmt

                              The reason you got that error resides here:

                               entity-manager-factory="#{entityManager}"
                              


                              Just change your second persistence context as follows:

                              
                              <core:managed-persistence-context name="filteredEntityManager"
                               auto-create="true"
                               persistence-unit-jndi-name="java:/entityManagerFactory">
                               <core:filters><value>#{hubFilteredChannels}</value></core:filters>
                              </core:managed-persistence-context>
                              


                              • 12. Re: @Filter example

                                Thanks,

                                I was sure i also tested with that code and failed, but apparently now it's working.
                                I was not able to make it work with an entity type parameter, it's saying something about cannot detecting the type for the parameter. So I tested with a Long parameter (the id of the entity and it's working)
                                Does anyone know any more about that? The Type would be a POJO entity.

                                Also another problem. As I said, we have a combo box and the user chooses a "current object". If i go directly on the tab that contains my filtered entity, without setting a current object first, i get this kind of error:

                                Caused by: org.hibernate.HibernateException: Filter [hubFilteredChannels] parameter [currentHubId] value not set
                                 at org.hibernate.impl.FilterImpl.validate(FilterImpl.java:145)
                                 at org.jboss.seam.persistence.HibernatePersistenceProvider.enableFilter(HibernatePersistenceProvider.java:62)


                                Why not just use the null value instead???