8 Replies Latest reply on Mar 7, 2019 8:31 PM by trytrysin

    Fail to display updated cache value on different pages

    trytrysin

      Dear All,

      In brief I faced a problem on two different pages using same cache value, but display different value.

      Please takes some time to advise what the problem is. Thanks.

       

      I am working on a project that management expected multiple applications (war file) can share usage of a single cache (as all the war will sit on the same container, and only single node is provided).

       

      i.e. I plan to prepare a Utility jar to create a local mode infinispan cache for different wars to use.

       

      a singleton startup bean is built, try to ensure all applications using same cache source

      package cmm.bean.impl;
      
      
      import javax.annotation.PreDestroy;
      import javax.ejb.Singleton;
      import javax.ejb.Startup;
      
      
      import org.apache.logging.log4j.LogManager;
      import org.apache.logging.log4j.Logger;
      import org.infinispan.Cache;
      import org.infinispan.configuration.cache.ConfigurationBuilder;
      import org.infinispan.manager.DefaultCacheManager;
      
      
      @Singleton
      @Startup
      public class testCacheManagerProvider {
      
      private static final Logger logger = LogManager.getLogger(testCacheManagerProvider.class);
      
      private DefaultCacheManager manager;
      
      private Cache testCache;
      
      public DefaultCacheManager getCacheManager() {
          if (manager == null) {
              manager = new DefaultCacheManager();
          }
          return manager;
      }
      
      public Cache getCache() {
      if (manager == null) {
      manager = new DefaultCacheManager();
      
      if (manager.cacheExists("testCache") ) {
      logger.info("testCache already exist");
      } else {
      logger.info("testCache create");
      manager.defineConfiguration("testCache", new ConfigurationBuilder().build() );
      }
      
      testCache = manager.getCache("testCache");
              } else {
              logger.info("TC Debug, cacheManager is NOT null");
              }
              return testCache;
      }
      
      @PreDestroy
          public void cleanUp() {
              manager.stop();
              manager = null;
          }
      }

       

      another bean is built to trigger the provider

      @Singleton
      @Startup
      public class testCacheApplicationBean {
          @Inject
          testCacheManagerProvider cacheManagerProvider;
      
          @Produces
      public Cache getTestCache() {
          return cacheManagerProvider.getCache();
          }
      }

       

      a utility bean is created to maintain the cache content

      package cmm.bean;
      
      
      import java.util.List;
      import java.util.Map;
      import org.apache.logging.log4j.LogManager;
      import org.apache.logging.log4j.Logger;
      
      
      import javax.annotation.PostConstruct;
      import javax.ejb.EJB;
      import javax.ejb.Singleton;
      // import javax.ejb.Startup;
      import javax.inject.Inject;
      
      
      import org.apache.commons.collections4.MapUtils;
      // import org.infinispan.Cache;
      // import org.infinispan.manager.DefaultCacheManager;
      
      
      import cmm.bean.impl.testCacheApplicationBean;
      import cmm.dao.CSysPostDao;
      import cmm.dao.CSysRoleDao;
      import cmm.entity.CSysPost;
      import entity.CSysRole;
      
      
      @Singleton
      // @Startup
      public class CSysAppCacheService {
      
      
      @Inject
      private testCacheApplicationBean beanCache;
      
      @EJB(name = "postService")
      private CSysPostDao postService;
      
      @EJB(name = "roleService")
      private CSysRoleDao roleService;
      
      
      private static final Logger logger = LogManager.getLogger(CSysAppCacheService.class);
      
      protected Map> sysRoleMap;
      protected Map> sysPostMap;
      protected List sysRoleList;
      protected List sysPostList;
      
      
      @PostConstruct
      public void init() {
      preloadCache();
          }
      
      // Pre-load cache when server startup
      public void preloadCache() {
      for (CacheKey ck : CacheKey.values()) {
      resetCache(ck);
      }
      }
      
      public void resetCache(CacheKey key) {
      if (key == null) {
      for (CacheKey ck : CacheKey.values()) {
      resetCache(ck);
      }
      } else if (key.equals(CacheKey.SYS_ROLE_LIST)) {
      this.sysRoleList = roleService.findAllRole();
      setupCacheList(CacheKey.SYS_ROLE_LIST, sysRoleList);
      } else if (key.equals(CacheKey.SYS_POST_LIST)) {
      this.sysPostList = postService.findAllPost();
      setupCacheList(CacheKey.SYS_POST_LIST, sysPostList);
      }
      }
      
      protected  void setupCacheList(CacheKey key, List list) {
      beanCache.getTestCache().put(key, list);
      }
      
      public List

      getCacheList(CacheKey key) {
      return (List) beanCache.getTestCache().get(key);
      }

      public List getCacheList(String keyString) {
      return (List) beanCache.getTestCache().get(keyString);
      }

      @SuppressWarnings("unchecked")
      public <k, v=""> Map<k, v=""> getCacheMap(CacheKey key) {
      return (Map<k, v="">) beanCache.getTestCache().get(key);
      }

      public Map<string, list<csysrole="">> getCSysRoleMap() {
      sysRoleMap = getCacheMap(CacheKey.SYS_ROLE_LIST);
      if (MapUtils.isEmpty(sysRoleMap)) {
      resetCache(CacheKey.SYS_ROLE_LIST);
      }
      return sysRoleMap;
      }

      public Map<string, list<csyspost="">> getCSysPostMap() {
      sysRoleMap = getCacheMap(CacheKey.SYS_POST_LIST);
      if (MapUtils.isEmpty(sysPostMap)) {
      resetCache(CacheKey.SYS_POST_LIST);
      }
      return sysPostMap;
      }
      }

       

      2 separate view class is built for front-end display (both are similiar but in different war file, so I put one class only)

      package stf.view;
      
      
      import java.io.Serializable;
      import java.util.ArrayList;
      import java.util.List;
      // import java.util.Map;
      
      
      import javax.annotation.PostConstruct;
      import javax.ejb.EJB;
      // import javax.faces.bean.ManagedBean;
      import javax.faces.view.ViewScoped;
      // import javax.inject.Inject;
      import javax.inject.Named;
      
      
      import org.apache.logging.log4j.LogManager;
      import org.apache.logging.log4j.Logger;
      
      
      import cmm.bean.CSysAppCacheService;
      import cmm.bean.CacheKey;
      
      
      @ViewScoped
      @Named
      public class CacheView implements Serializable {
      
      
      /**
      * 
      */
      private static final long serialVersionUID = 2504596409107933525L;
      
      
      private static final Logger logger = LogManager.getLogger(CacheView.class);
      
      
      public static final String FNCT_ID = "SAMPLCACH";
      
      
      private List cacheKeyList;
      
      private CacheKey selectedKey;
      private List

      selectedList;


      @EJB CSysAppCacheService appScopeCache;

      @PostConstruct
      public void init() {
      List cacheKeyArrayList = new ArrayList();
              for (CacheKey cacheKey : CacheKey.values()) {
      cacheKeyArrayList.add(cacheKey.toString());
              }
              setCacheKeyList(cacheKeyArrayList);
             
              appScopeCache.init();
      }

      public List getCacheKeyList() {
      return cacheKeyList;
      }


      public void setCacheKeyList(List cacheKeyList) {
      this.cacheKeyList = cacheKeyList;
      }

      public CacheKey getSelectedKey() {
      return selectedKey;
      }

      public void setSelectedKey(CacheKey selectedKey) {
      this.selectedList = appScopeCache.getCacheList(selectedKey);
      }

      public List getSelectedList() {
      return selectedList;
      }


      public void setSelectedList(List selectedList, CacheKey key) {
      String keyString = String.valueOf(key);
      setSelectedKey(key);
      this.selectedList = selectedList;
      }

      public String reloadAction() {

      this.cacheKeyList.clear();

      appScopeCache.preloadCache();

      List cacheKeyArrayList = new ArrayList();
              for (CacheKey cacheKey : CacheKey.values()) {
      cacheKeyArrayList.add(cacheKey.toString());
              }

      setCacheKeyList(cacheKeyArrayList );

      return "cache.xhtml?faces-redirect=true";
      }

      public String reloadAction(CacheKey inputcacheKey) {
      // init();

      this.cacheKeyList.clear();

      appScopeCache.resetCache(inputcacheKey);

      List cacheKeyArrayList = new ArrayList();
              for (CacheKey cacheKey : CacheKey.values()) {
      cacheKeyArrayList.add(cacheKey.toString());
              }

      setCacheKeyList(cacheKeyArrayList );

      return "cache.xhtml?faces-redirect=true";
      }

      public String clearAction() {
      return "cache.xhtml?faces-redirect=true";
      }

      public String showDetailAction() {
      return "cache.xhtml?faces-redirect=true";
      }

      }

       

      The 1st time I load the 2 pages, they show the identical values

      Then I updated the database, and reload cache via one of the page.

      The page reload page get the updated value, while the other page (not reload one) still keep the old value.

       

      Please advise how I should fix it.

      Thanks.

        • 1. Re: Fail to display updated cache value on different pages
          pferraro

          In the code above, each web application will use its own cache instance rather than sharing a single cache instance.  If you want each application to use a shared cache, you should instead configure a server managed cache instance and inject it into each application.

           

          e.g. from standalone.xml:

           

          <subsystem xmlns="urn:jboss:domain:infinispan:8.0">

             <cache-container name="foo">

                 <local-cache name="bar"/>

             </cache-container>

          </subsystem>

           

          In your application, reference the cache via a resource reference:

          e.g. from web.xml

           

          <resource-ref>

             <res-ref-name>cache</res-ref-name>

             <lookup-name>java:jboss/infinispan/cache/foo/bar</lookup-name>

          </resource-ref>

           

          To reference the server-managed cache Into your application, you can simply inject the cache via:

           

          @Resource(name="cache")

          private Cache<?, ?> cache;

           

          The injected cache will already be started, its lifecycle managed entirely by the container.

          • 2. Re: Fail to display updated cache value on different pages
            trytrysin

            Thanks for your information, pferraro

            I successfully created a single cache container, together with a single cache created, which can shared among application.

            But the issue is not resolved.

             

            I tried to put values into cache created via the first page, and checked the eclipse debugger with content like this.

             

            It looks fine, but when I tried to load the second page, the eclipse debugger shown 2 more entries are created in the cache, with the same key name (but different key id) of the previous page created.

             

            I go through the code via debugger and spotted that the issue should due to the function "cache.containsKey(key)" failed to match the value I pass-in.

            in result duplicate entries are created (in procedure setupCacheList)

            (the value passed in is a enum value and should be identicial)

             

            Code as below

             

            package stf.view;
            
            
            import java.io.Serializable;
            import java.util.ArrayList;
            import java.util.Date;
            import java.util.List;
            
            
            import javax.annotation.PostConstruct;
            import javax.annotation.Resource;
            import javax.ejb.EJB;
            import javax.faces.view.ViewScoped;
            import javax.inject.Inject;
            import javax.inject.Named;
            
            
            import org.apache.logging.log4j.LogManager;
            import org.apache.logging.log4j.Logger;
            import org.infinispan.Cache;
            import org.infinispan.manager.DefaultCacheManager;
            
            
            import cmm.bean.CSysAppCacheService;
            import cmm.bean.CacheKey;
            import cmm.dao.CSysPostDao;
            import cmm.dao.CSysRoleDao;
            import cmm.entity.CSysPost;
            import cmm.entity.CSysRole;
            
            
            @ViewScoped
            @Named
            public class CacheView2 implements Serializable {
            
            
            
            
            /**
            * 
            */
            private static final long serialVersionUID = -8391029706938407282L;
            
            
            private static final Logger logger = LogManager.getLogger(CacheView2.class);
            
            
            public static final String FNCT_ID = "SAMPLCACH";
            
            
            private List<String> cacheKeyList;
            
            // private Map<K, V> selectedMap;
            private CacheKey selectedKey;
            private List<Object> selectedList;
            
            
            // temporary for testing cache
            @EJB
            CSysPostDao postService;
            
            @EJB
            CSysRoleDao roleService;
            
            protected List<CSysRole> sysRoleList;
            protected List<CSysPost> sysPostList;
            
            @Resource(name="cache")
            Cache cache;
            
            @PostConstruct
            public void init() {
            List<String> cacheKeyArrayList = new ArrayList<String>();
                    for (CacheKey cacheKey : CacheKey.values()) {
            // if(cacheKey != CacheKey.OFFR_LOGIN_SESSION_MAP){
            cacheKeyArrayList.add(cacheKey.toString());
            // }
                    }
                    setCacheKeyList(cacheKeyArrayList);
                    
                    preloadCache();
            
            }
            
            public List<String> getCacheKeyList() {
            return cacheKeyList;
            }
            
            
            public void setCacheKeyList(List<String> cacheKeyList) {
            this.cacheKeyList = cacheKeyList;
            }
            
            public CacheKey getSelectedKey() {
            return selectedKey;
            }
            
            public void setSelectedKey(CacheKey selectedKey) {
            logger.info("TC Debug stf setSelectedKey, selectedKey " + selectedKey);
            this.selectedKey = selectedKey;
            setSelectedList(getCacheList(selectedKey) );
            logger.info("TC Debug stf selectedList size " + selectedList.size() );
            }
            
            public List<Object> getSelectedList() {
            return selectedList;
            }
            
            public void setSelectedList(List<Object> selectedList) {
            logger.info("TC Debug stf setSelectedList 1 " );
            this.selectedList = selectedList;
            logger.info("TC Debug stf setSelectedList 1 " + selectedList.size() );
            }
            
            
            public void setSelectedList(List<Object> selectedList, CacheKey key) {
            String keyString = String.valueOf(key);
            setSelectedKey(key);
            this.selectedList = selectedList;
            }
            
            public String reloadAction() {
            this.cacheKeyList.clear();
            
            
            preloadCache();
            
            List<String> cacheKeyArrayList = new ArrayList<String>();
                    for (CacheKey cacheKey : CacheKey.values()) {
            cacheKeyArrayList.add(cacheKey.toString());
                    }
            
            setCacheKeyList(cacheKeyArrayList );
            
            
            return "cache.xhtml?faces-redirect=true";
            }
            
            public String reloadAction(CacheKey inputcacheKey) {
            resetCache2(inputcacheKey);
            
            return "cache.xhtml?faces-redirect=true";
            }
            
            public String clearAction() {
            return "cache.xhtml?faces-redirect=true";
            }
            
            public String showDetailAction() {
            return "cache.xhtml?faces-redirect=true";
            }
            
            
            // temporary for testing cache
            
            
            // Pre-load cache when server startup
            public void preloadCache() {
            for (CacheKey ck : CacheKey.values()) {
            resetCache2(ck);
            }
            }
            
            public void resetCache2(CacheKey key) {
            logger.info("TC Debug resetCache for " + key);
            if (key == null) {
            for (CacheKey ck : CacheKey.values()) {
            resetCache2(ck);
            }
            } else if (key.equals(CacheKey.SYS_ROLE_LIST)) {
            sysRoleList = roleService.findAllRole();
            // setupCacheList(CacheKey.SYS_ROLE_LIST, sysRoleList);
            setupCacheList(CacheKey.SYS_ROLE_LIST, roleService.findAllRole() );
            } else if (key.equals(CacheKey.SYS_POST_LIST)) {
            sysPostList = postService.findAllPost();
            // setupCacheList(CacheKey.SYS_POST_LIST, sysPostList);
            setupCacheList(CacheKey.SYS_POST_LIST, postService.findAllPost() );
            }
            logger.info("TC Debug resetCache end");
            }
            
            public <T> void setupCacheList(CacheKey key, List<T> list) {
            if (cache.containsKey(key)) {
            cache.replace(key, list);
            } else {
            cache.put(key, list);
            }
            }
            
            public List<Object> getCacheList(CacheKey key) {
            // return (List<Object>) beanCache.getTestCache().get(key);
            return (List<Object>) cache.get(key);
            }
            
            public List<Object> getCacheList(String keyString) {
            // return (List<Object>) beanCache.getTestCache().get(keyString);
            return (List<Object>) cache.get(keyString);
            }
            
            }
            

             

            Would you suggest how I should solve the issue?

            Thanks!

            • 3. Re: Fail to display updated cache value on different pages
              pferraro

              Where is your CacheKey class located?  Is the class contained within a shared library?  How is that library packaged in each deployment?  What does its equals method look like?

              • 4. Re: Fail to display updated cache value on different pages
                trytrysin

                We figured what the problem is and solved.

                 

                It is due to we passed in enum as cache key, while same enum passed in are treated as different value.

                I changed it to string and duplicate cache entry is gone.

                 

                 

                // cache.put(key, list);
                cache.put(key.name(), list);

                 

                Thanks a lot for your input

                • 5. Re: Fail to display updated cache value on different pages
                  jaikiran

                  trytrysin  wrote:

                   

                  We figured what the problem is and solved.

                   

                  It is due to we passed in enum as cache key, while same enum passed in are treated as different value.

                  That doesn't sound right to me. IMO, the enum equality checks should have worked. Can you post the code of your enum?

                  • 6. Re: Fail to display updated cache value on different pages
                    trytrysin

                    Dear jaikiran,

                     

                    The enum code is as simple as this

                     

                    package cmm.bean;
                    
                    
                    import java.io.Serializable;
                    
                    
                    public enum CacheKey implements Serializable {
                    SYS_POST_LIST, SYS_ROLE_LIST
                        ;
                    private static final long serialVersionUID = 1L;
                    }
                    
                    • 7. Re: Fail to display updated cache value on different pages
                      pferraro

                      Unless the CacheKey is contained within the same module accessible to both deployments (e.g. a jar referenced by different web apps within an EAR), they will loaded by separate modules (every deployment is its own module), thus they will fail instanceof checks.

                       

                      N.B. In Java, enums are implicitly serializable, so you they don't need to implement Serializable.

                      • 8. Re: Fail to display updated cache value on different pages
                        trytrysin

                        Thanks for your update pferraro.

                         

                        As they are embedded in separate war files (for the ease of deployment from our S.A.), then the Cachekey is failed on instance of checks.