6 Replies Latest reply on Apr 30, 2008 9:32 AM by Jaime Martin

    2nd level cache (read this one, not the previous)

    Jaime Martin Apprentice

      hi,
      (Please reply to this one, in the previous I forgot to activate Notify me via e-mail of any replies)
      I want to add second level cache to my seam application (SEAM 2.0.1.GA, JBoss 4.2.2). After reading up some docs there are some config issues I´m not sure how to tackle in Seam.


      According to my needs I have finally chosen OSCache. In my persistence.xml I´ve set my provider class


      <property name="hibernate.cache.provider_class" value="com.opensymphony.oscache.hibernate.OSCacheProvider"/>       
      


      In the entities I want to cache I´ve used org.hibernate.annotations.Cache defining the strategy and include params.For now, I´m not interested in defining regions names. for instance:


      @Entity
      @Cache (usage=CacheConcurrencyStrategy.READ_WRITE, include="non-lazy")
      @Table(name = "CFG_CURRENCY", catalog = "prisk", uniqueConstraints = @UniqueConstraint(columnNames = "currency_iso"))
      public class CfgCurrency implements java.io.Serializable {
      


      But, I also want to cache some of my seam-gened based queries that look this way:


      I´ve read up about the cacheable param to be set to a query.(My seam-gened queries are org.jboss.seam.framework.EntityQuery) I´ve tried with the javax.persistence.QueryHint annotation:


      @Name("cfgCurrencyList")
      @QueryHint(name="org.hibernate.cacheable",value="true")
      public class CfgCurrencyList extends EntityQuery {
      


      With that I have this compilation error:


       annotation type not applicable to this kind of declaration
      


      So then I´ve tried this 2 ways:


       //1st way, in CfgCurrencyList.java
          @Override
          public void setHints(Map arg0) {
                  System.out.println("cfgCurrencyList - setHints!!!");
                  Map region = new TreeMap();
                  region.put("org.hibernate.cacheable", "true");    
                  //IN THE FUTURE IF I DEFINE REGION, I WOULD USE THIS
      //            region.put("org.hibernate.cacheRegion", "/CfgCurrencyListQuery");    
                  super.setHints(region);
          }        
      
          //2nd way: setting the hints from outside
          * query.setHint("org.hibernate.cacheable",
      "true")
      



      This compiles, but I´m not sure if that´s the proper way to do this because the trace cfgCurrencyList - setHints!!! is never displayed and I´m using that Query. I think my app is not taking into account it.


      am I doing it correctly? thanks in advance!.

        • 1. Re: 2nd level cache (read this one, not the previous)
          Jaime Martin Apprentice

          I´ve also tried to use namedQueries.
          For instance



          @Entity
          @Cache (usage=CacheConcurrencyStrategy.READ_WRITE)
          @NamedQueries({
          @NamedQuery(name = "cfgCurrencyList", 
          query = "select cfgCurrency from CfgCurrency cfgCurrency",
          hints = {@QueryHint(name = "org.hibernate.cacheable", value = "true")})})
          @Table(name = "CFG_CURRENCY", catalog = "prisk", uniqueConstraints = @UniqueConstraint(columnNames = "currency_iso"))
          public class CfgCurrency implements java.io.Serializable {
          



          But I don´t think this is the way, because I have my cfgCurrencyList component:



          @Name("cfgCurrencyList")
          public class CfgCurrencyList extends EntityQuery {
          
          
               private static final String[] RESTRICTIONS = {
                         "lower(cfgCurrency.currencyDes) like concat(lower(#{cfgCurrencyList.cfgCurrency.currencyDes}),'%')",
                         "lower(cfgCurrency.currencyIso) like concat(lower(#{cfgCurrencyList.cfgCurrency.currencyIso}),'%')",};
          
               private CfgCurrency cfgCurrency = new CfgCurrency();
          
               @Override
               public String getEjbql() {
                    return "select cfgCurrency from CfgCurrency cfgCurrency";
               }
          
               @Override
               public Integer getMaxResults() {
                    return 25;
               }
          
               public CfgCurrency getCfgCurrency() {
                    return cfgCurrency;
               }
                  
               @Override
               public List<String> getRestrictions() {
                    return Arrays.asList(RESTRICTIONS);
               }
          }
          
          


          I keep on thinking that there should be a way to say that my seam-gened EntityQuery cfgCurrencyList is cacheable.


          I´ve tested times with a timer class and there are not important improvements, but that could be because there is not many data right now in the table CFGCURRENCY.


          any suggestion will be welcomed! thank you!

          • 2. Re: 2nd level cache (read this one, not the previous)
            Jaime Martin Apprentice

            To set a EntityQuery child to cacheable only once, to avoid further proccessing now I´m doing it by means of overriding the validate method, as it has a create annotation this way:



              @Override
                    @SuppressWarnings("unchecked")
                    public void validate()
                    {
                        Map region = new TreeMap();
                        region.put("name=org.hibernate.cacheable", "value=true");    
                        this.setHints(region);              
                        super.validate();
                    }
            



            Is this a good way? any idea to do it better?

            • 3. Re: 2nd level cache (read this one, not the previous)
              Joao Viragine Newbie

              Jaime,


              I´m using this way:



              protected static final String CACHEABLE_HINT = "org.hibernate.cacheable";
              
              ...
              
              public List<Uf> recuperaTodos() {
                   return createNamedQuery("uf.recuperaTodos").setHint(CACHEABLE_HINT, true).getResultList();
              }
              





              • 4. Re: 2nd level cache (read this one, not the previous)
                Jaime Martin Apprentice

                thanks Joao, a further question. of what kind is the class where you are using that?
                I mean, all my seam-gened list classes extend from EntityQuery, and EntityQuery API does not allow to invoke createNamedQuery. A solution could be using entitymanager in all EntityQuery children clases I want to cache this way:(my app is war so it uses POJOs no EJBs and that is why I don´t use PersistenceContextannotattion.)



                @Name("cfgCurrencySuggestQuery")
                public class CfgCurrencySuggestQuery extends EntityQuery {
                
                        @In (create=true,required=false)
                        private EntityManager em;
                ..
                        public List getCurrencies() {
                            System.out.println("getCurrencies!!");
                            return em.createNamedQuery("cfgCurrencySuggestQuery").setHint(CACHEABLE_HINT, true).getResultList();
                        }
                



                but with it I have NullPointerException.
                any idea? thank you!


                • 5. Re: 2nd level cache (read this one, not the previous)
                  Joao Viragine Newbie

                  Jaime,


                  I’m using this method in my DAO.


                  I don’t use Seam Framework.


                  By the way, how do you declare your em in components.xml?

                  • 6. Re: 2nd level cache (read this one, not the previous)
                    Jaime Martin Apprentice

                    I declare it this way:



                        <persistence:managed-persistence-context name="entityManager"
                                                                 auto-create="true"
                                                                 entity-manager-factory="#{PRR_ONLINEV2EntityManagerFactory}"/>
                        
                        <persistence:entity-manager-factory name="PRR_ONLINEV2EntityManagerFactory"
                                                            persistence-unit-name="PRR_ONLINEV2"/>
                    



                    By the way, in my case using Seam framwork I think I´ll go on using  setHints, this way:



                                Map cacheHint = new TreeMap();
                                cacheHint.put("name=org.hibernate.cacheable", "value=true");    
                            cfgCurrencyQuery.setHints(cacheHint);
                    



                    where cfgCurrencyQuery extends EntityQuery


                    regards and thanks!