1 2 Previous Next 22 Replies Latest reply on Jul 19, 2006 11:26 AM by ben.wang

    PojoCache 2.0 Interface

      Now that the underlying Cache API has stablized, I am also publishing the PojoCache 2.0 APIs. The main changes are:

      1. API name changes like putObject to attach and removeObject to detach.
      2. Decouple from underlying plain cache implementation. That is the new PojoCache implementation will implment both PojoCache and Cache interfaces. But there is no direct coupling of PojoCache API to Cache one, e.g., Fqn of the tree structure. For the key to identify the POJO in the cache system, I am using a String id now.

      /*
       * JBoss, the OpenSource J2EE webOS
       *
       * Distributable under LGPL license.
       * See terms of license at gnu.org.
       */
      package org.jboss.cache.pojo;
      
      import java.util.Map;
      
      /**
       * <p>Main PojoCache APIs. PojoCache is an in-memory, transactional, fine-grained, and
       * object-oriented POJO (plain old Java object) distributed cache system. It
       * differs from the traditional generic distributed cache library by operating on the
       * POJO level directly without requiring that object to be serializable. It can preserve
       * object graph relationship during replication or persistency. It also track the
       * replication via fine-grained maner, i.e., only modified fields are replicated.</p>
       *
       * @author Ben Wang
       * @since 2.0
       */
      public interface PojoCache {
       /**
       * <p>Attach a POJO into PojoCache. It will also recursively put any sub-POJO into
       * the cache system. A POJO can be the following and have the consqeuences when attached:</p>
       *
       * <li>it is PojoCacheable, that is, it has been annotated with
       * {@see org.jboss.cache.aop.annotation.PojoCacheable} annotation (or via XML), and has
       * been "instrumented" either compile- or load-time. The POJO will be mapped recursively to
       * the system and fine-grained replication will be performed.</li>
       * <li>It is Serializable. The POJO will still be stored in the cache system. However, it is
       * treated as an "opaque" object per se. That is, the POJO will neither be intercepted
       * (for fine-grained operation) or object relantionship will be maintained.</li>
       * <li>Neither of above. In this case, a user can specify whether it wants this POJO to be
       * stored (e.g., replicated or persistent). If not, a PojoCacheException will be thrown.
       *
       * @param id An id String to identify the object in the cache. For conveient, the id can
       * be hierarchical separating by "/" separation, for example.
       * @param pojo object to be inerted into the cache. If null, it will nullify the fqn node.
       * @return Existing POJO or null if there is not.
       * @throws PojoCacheException Throws if there is an error related to the cache operation, e.g.,
       * {@link org.jboss.cache.lock.TimeoutException}.
       */
       Object attach(String id, Object pojo) throws PojoCacheException;
      
       /**
       * Remove POJO object from the cache.
       *
       * @param id Is string that associates with this node.
       * @return Original value object from this node.
       * @throws PojoCacheException Throws if there is an error related to the cache operation, e.g.,
       * {@see org.jboss.cache.lock.TimeoutException}.
       */
       Object detach(String id) throws PojoCacheException;
      
       /**
       * Remove POJO object from the cache.
       *
       * @param pojo The managed POJO.
       * @return Original value object from this node.
       * @throws PojoCacheException Throws if there is an error related to the cache operation, e.g.,
       * {@see org.jboss.cache.lock.TimeoutException}.
       */
       Object detach(Object pojo) throws PojoCacheException;
      
       /**
       * Retrieve pojo from the cache. Return null if object does not exist in the cache.
       * Note that this operation is fast if there is already an POJO instance attached to the cache.
       *
       * @param id that associates with this node.
       * @return Current content value. Null if does not exist.
       * @throws PojoCacheException Throws if there is an error related to the cache operation, e.g.,
       * {@see org.jboss.cache.lock.TimeoutException}.
       */
       Object find(String id) throws PojoCacheException;
      
       /**
       * Query all managed pojo objects under the id recursively. Note that this will not return
       * the sub-object pojos, e.g., if Person has a sub-object of Address, it won't return
       * Address pojo. Also note also that this operation is not thread-safe now. In addition,
       * it assumes that once a pojo is found with a fqn, no more pojo is stored under the children
       * of the fqn. That is, we don't mixed the fqn with different pojos.
       *
       * @param id The starting place to find all pojos.
       * @return Map of all pojos found with (fqn, pojo) pair. Return size of 0, if not found.
       * @throws PojoCacheException Throws if there is an error related to the cache operation, e.g.,
       * {@see org.jboss.cache.lock.TimeoutException}.
       */
       Map findAll(String id) throws PojoCacheException;
      }
      




        • 1. Re: PojoCache 2.0 Interface

          This is a sample usage that I can envision:

          PojoCache cache = PojoCacheFactory.getInstnace(PojoConfig);
          
          Person p = new Person();
          String id = "/person/p");
          
          cache.attach(id, p);
          
          Person p1 = (Person)cache.find(id);
          
          cache.detach(p);
          or
          cache.detach(id);
          



          • 2. Re: PojoCache 2.0 Interface

            Finally, I am thinking the underlying PojoCacheImpl will implement both PojoCache and Cache API such that:

            pulbic class PojoCacheImpl implements PojoCache, Cache
            


            and to switch between PojoCache and Cache interface, you can do like:

            PojoCache pc = PojoCacheFactory(PojoCacheConfig);
            
            pc.attach(pojo);
            ...
            
            // Switch to plain Cache
            
            Cache c = (Cache)pc;
            c.put(fqn, blah, blah);
            


            True that to use plain Cache, you will need to cast it explicitly. But I don't see the frequent usage of Cache api under PojoCache anyway so I think this present a clear separation of interfaces.

            What do people think?

            • 3. Re: PojoCache 2.0 Interface
              genman


              I would keep them as separate APIs. Having both seems like it would add lots of methods that you shouldn't be accessing directly. Something like this would be interesting:

              TreeCache cacheInstance = ...;
              PojoCache cache = PojoCacheFactory.getInstance(pojoConfig, cacheInstance);
              


              • 4. Re: PojoCache 2.0 Interface

                are you saying that we should have two separate cache isntances?

                • 5. Re: PojoCache 2.0 Interface
                  manik

                  No, but since PojoCache will use delegation to the cache instance, the cache instance could be passed in to the factory.

                  I agree with genman that implementing both interfaces will add a lot of clutter.

                  Perhaps even having a PojoCache.getCache() method to return the underlying Cache may be an option.

                  • 6. Re: PojoCache 2.0 Interface

                    Yeah, I think the issue basically boils down to whether we will have two separate configuration files for PojoCache (PC) and JBossCache (JBC) or not. It has pros and cons.

                    1. Have two separate configs,

                    Cache cache = CacheFactory(cacheConfig);
                    PojoCache pc = PojoCacheFactory(pojoCacheConfig, cache);
                    


                    2. Just one config containing both JBC and PC,

                    PojoCache pc = PojoCacheFactory(config);
                    Cache cache = pc.getCache();
                    


                    I prefer the second one but what do people think?


                    • 7. Re: PojoCache 2.0 Interface
                      manik

                      Even in the case of the first one, it would look like:

                      Cache cache = CacheFactory.getInstance(configFile);
                      PojoCache pc = PojoCacheFactory.getInstance(cache);
                      


                      There are no pojocache specific configurations in the config file, are there?

                      • 8. Re: PojoCache 2.0 Interface
                        manik

                        I'm happy with either approach though.

                        • 9. Re: PojoCache 2.0 Interface

                          Actually, there are additional configurations now for PojoCache and I forsee there will be more in the future.

                          • 10. Re: PojoCache 2.0 Interface
                            manik

                            ok, lets stick to PojoCache.getCache() then ...

                            • 11. Re: PojoCache 2.0 Interface

                              Another thing that I want to point out is that now we don't require to specify a Fqn that is associated directly with the underlying Cache. Instead, a String id is required.

                              This has pros and cons that I can see:

                              Cons - Since we still map Id internally to Fqn, if the id is without separator, e.g., "/justThis", then concurrency is not optimial since everything works from the root. As a result, we need to ask the user to have separator in the Id string. Not very natural.

                              Pros - It decouples from the Fqn of which is more accurate since a user should only cares about the Id of the Pojo. Semantically, this is a much better one.

                              • 12. Re: PojoCache 2.0 Interface
                                manik

                                Possibly a very silly idea, but how about creating subtrees for the ids internally?

                                E.g.,

                                id ("TEST") => Fqn (/T/TE/TEST)
                                id ("TELEVISION") => Fqn (/T/TE/TELEVISION)
                                id ("COUCH_POTATO") => Fqn (/C/CO/COUCH_POTATO)
                                id ("A") => Fqn (/A/A)

                                Like I said, possibly a silly idea ...

                                • 13. Re: PojoCache 2.0 Interface
                                  galder.zamarreno

                                  Ben, why would PojoCacheImpl need to implement Cache? Would it be so that clients could work on it from the Cache interface? Or is it to take advantage of some common actions? I personally don't see the need for it to implement Cache, but maybe there's something I'm missing...

                                  • 14. Re: PojoCache 2.0 Interface
                                    galder.zamarreno

                                    I guess semantically, a PojoCache is a Cache so it'd make sense, but as manik said, it'd clutter the implementation of PojoCache.

                                    1 2 Previous Next