cocoon-cvs mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From un...@apache.org
Subject cvs commit: cocoon-2.1/src/blocks/scratchpad/java/org/apache/cocoon/components/source/impl InspectableTraversableCachingSource.java TraversableCachingSource.java CachingSource.java UpdateTarget.java CachingSourceFactory.java
Date Thu, 01 Jul 2004 14:24:37 GMT
unico       2004/07/01 07:24:37

  Modified:    src/blocks/scratchpad/java/org/apache/cocoon/components/source/impl
                        TraversableCachingSource.java CachingSource.java
                        UpdateTarget.java CachingSourceFactory.java
  Added:       src/blocks/scratchpad/java/org/apache/cocoon/components/source/impl
                        InspectableTraversableCachingSource.java
  Log:
  caching source refactorings:
  - add support for caching source properties
  - move all refresh functionality to refresh() method
  - remove dependency from CachingSource -> TraversableCachingSource
  
  Revision  Changes    Path
  1.6       +105 -17   cocoon-2.1/src/blocks/scratchpad/java/org/apache/cocoon/components/source/impl/TraversableCachingSource.java
  
  Index: TraversableCachingSource.java
  ===================================================================
  RCS file: /home/cvs/cocoon-2.1/src/blocks/scratchpad/java/org/apache/cocoon/components/source/impl/TraversableCachingSource.java,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- TraversableCachingSource.java	24 Mar 2004 17:31:12 -0000	1.5
  +++ TraversableCachingSource.java	1 Jul 2004 14:24:36 -0000	1.6
  @@ -18,9 +18,9 @@
   import java.io.IOException;
   import java.util.ArrayList;
   import java.util.Collection;
  +import java.util.Iterator;
   
   import org.apache.avalon.framework.container.ContainerUtil;
  -import org.apache.avalon.framework.parameters.Parameters;
   import org.apache.excalibur.source.Source;
   import org.apache.excalibur.source.SourceException;
   import org.apache.excalibur.source.TraversableSource;
  @@ -33,12 +33,12 @@
       private TraversableSource tsource;
       
       public TraversableCachingSource(String protocol,
  -                                    String location,
  +                                    String uri,
                                       TraversableSource source,
  -                                    Parameters params,
                                       int expires,
  +                                    String cacheName,
                                       boolean async) {
  -        super(protocol, location, source, params, expires, async);
  +        super(protocol, uri, source, expires, cacheName, async);
           this.tsource = source;
       }
       
  @@ -148,18 +148,26 @@
   
       // ---------------------------------------------------- helper methods
   
  -    private TraversableCachingSource createSource(String uri, Source wrapped) 
  +    
  +    
  +    protected final TraversableCachingSource createSource(String uri, Source wrapped) 
       throws SourceException {
  -        final TraversableCachingSource source = 
  -            new TraversableCachingSource(super.protocol,
  -                                         uri,
  -                                         (TraversableSource) wrapped,
  -                                         new Parameters().merge(super.parameters),
  -                                         super.expires,
  -                                         super.async);
  +        final TraversableCachingSource source = newSource(uri, wrapped);
  +        initializeSource(source);
  +        return source;
  +    }
  +
  +    protected TraversableCachingSource newSource(String uri, Source wrapped) {
  +        return  new TraversableCachingSource(super.protocol,
  +                                             uri,
  +                                             (TraversableSource) wrapped,
  +                                             super.expires,
  +                                             super.cacheName,
  +                                             super.async);
  +    }
  +
  +    protected void initializeSource(TraversableCachingSource source) throws SourceException {
           source.cache = super.cache;
  -        source.resolver = super.resolver;
  -        source.refresher = super.refresher;
           ContainerUtil.enableLogging(source, getLogger());
           try {
               ContainerUtil.service(source, super.manager);
  @@ -167,14 +175,64 @@
           } catch (Exception e) {
               throw new SourceException("Unable to initialize source.", e);
           }
  -        return source;
       }
       
  +    protected SourceMeta createMeta() {
  +        return new TraversableSourceMeta();
  +    }
  +    
  +    protected void initMeta(SourceMeta meta, Source source) throws IOException {
  +        super.initMeta(meta, source);
  +
  +        final TraversableSource tsource = (TraversableSource) source;
  +        final TraversableSourceMeta tmeta = (TraversableSourceMeta) meta;
  +
  +        tmeta.setName(tsource.getName());
  +        tmeta.setIsCollection(tsource.isCollection());
  +
  +        if (tmeta.isCollection()) {
  +            final Collection children = tsource.getChildren();
  +            if (children != null) {
  +                final String[] names = new String[children.size()];
  +                final Iterator iter = children.iterator();
  +                int count = 0;
  +                while(iter.hasNext()) {
  +                    TraversableSource child = (TraversableSource) iter.next();
  +                    names[count] = child.getName();
  +                    count++;
  +                }
  +                tmeta.setChildren(names);
  +            }
  +        }
  +
  +    }
  +    
  +    protected void remove() {
  +        remove(true);
  +    }
  +
  +    /**
  +     * The parent's cached response needs to be removed from cache
  +     * as well because it's cached list of children is no longer valid.
  +     */
  +    private void remove(boolean flag) {
  +        super.remove();
  +        if (flag) {
  +            try {
  +                TraversableCachingSource parent = (TraversableCachingSource) getParent();
  +                parent.remove(false);
  +            }
  +            catch (SourceException e) {
  +                getLogger().error("Error removing parent's cached response");
  +            }
  +        }
  +    }
  +
       /**
        * Calculate the cached child URI based on a parent URI
        * and a child name.
        */
  -    private String getChildURI(String parentURI, String childName) {
  +    private static String getChildURI(String parentURI, String childName) {
           
           // separate query string from rest of parentURI
           String rest, qs;
  @@ -203,7 +261,7 @@
       /**
        * Calculate the cached parent URI based on a child URI.
        */
  -    private String getParentURI(String childURI) {
  +    private static String getParentURI(String childURI) {
           
           // separate query string from rest of uri
           String rest, qs;
  @@ -228,6 +286,36 @@
           }
           
           return parentUri + qs;
  +    }
  +
  +    protected static class TraversableSourceMeta extends SourceMeta {
  +        private String   m_name;
  +        private boolean  m_isCollection;
  +        private String[] m_children;
  +
  +        protected String getName() {
  +            return m_name;
  +        }
  +
  +        protected void setName(String name) {
  +            m_name = name;
  +        }
  +
  +        protected boolean isCollection() {
  +            return m_isCollection;
  +        }
  +
  +        protected void setIsCollection(boolean isCollection) {
  +            m_isCollection = isCollection;
  +        }
  +
  +        protected String[] getChildren() {
  +            return m_children;
  +        }
  +
  +        protected void setChildren(String[] children) {
  +            m_children = children;
  +        }
       }
   
   }
  
  
  
  1.13      +141 -184  cocoon-2.1/src/blocks/scratchpad/java/org/apache/cocoon/components/source/impl/CachingSource.java
  
  Index: CachingSource.java
  ===================================================================
  RCS file: /home/cvs/cocoon-2.1/src/blocks/scratchpad/java/org/apache/cocoon/components/source/impl/CachingSource.java,v
  retrieving revision 1.12
  retrieving revision 1.13
  diff -u -r1.12 -r1.13
  --- CachingSource.java	11 Jun 2004 12:18:23 -0000	1.12
  +++ CachingSource.java	1 Jul 2004 14:24:36 -0000	1.13
  @@ -20,12 +20,9 @@
   import java.io.IOException;
   import java.io.InputStream;
   import java.io.Serializable;
  -import java.util.Collection;
  -import java.util.Iterator;
   
   import org.apache.avalon.framework.activity.Initializable;
   import org.apache.avalon.framework.logger.AbstractLogEnabled;
  -import org.apache.avalon.framework.parameters.Parameters;
   import org.apache.avalon.framework.service.ServiceException;
   import org.apache.avalon.framework.service.ServiceManager;
   import org.apache.avalon.framework.service.Serviceable;
  @@ -40,9 +37,7 @@
   import org.apache.excalibur.source.Source;
   import org.apache.excalibur.source.SourceException;
   import org.apache.excalibur.source.SourceNotFoundException;
  -import org.apache.excalibur.source.SourceResolver;
   import org.apache.excalibur.source.SourceValidity;
  -import org.apache.excalibur.source.TraversableSource;
   import org.apache.excalibur.source.impl.validity.ExpiresValidity;
   import org.apache.excalibur.source.impl.validity.TimeStampValidity;
   import org.apache.excalibur.xml.sax.XMLizable;
  @@ -76,18 +71,19 @@
   public class CachingSource extends AbstractLogEnabled
   implements Source, Serviceable, Initializable, XMLizable {
   
  +    // ---------------------------------------------------- Constants
  +    
  +    public static final String CACHE_EXPIRES_PARAM = "cache-expires";
  +    public static final String CACHE_NAME_PARAM = "cache-name";
  +    
  +    // ---------------------------------------------------- Instance variables
  +    
       /** The ServiceManager */
       protected ServiceManager manager;
   
  -    /** The SourceResolver to resolve the wrapped Source */
  -    protected SourceResolver resolver;
  -
       /** The current cache */
       protected Cache cache;
   
  -    /** The refresher for asynchronous updates */
  -    protected Refresher refresher;
  -
       /** The source object for the real content */
       protected Source source;
   
  @@ -105,13 +101,13 @@
   
       /** The key used in the store */
       final protected IdentifierCacheKey cacheKey;
  -
  +    
       /** number of seconds before cached object becomes invalid */
       final protected int expires;
  -
  -    /** Parameters */
  -    final protected Parameters parameters;
  -
  +    
  +    /** cache key extension */
  +    final protected String cacheName;
  +    
       /** asynchronic refresh strategy ? */
       final protected boolean async;
   
  @@ -121,18 +117,17 @@
       public CachingSource(final String protocol,
                            final String uri,
                            final Source source,
  -                         final Parameters parameters,
                            final int expires,
  +                         final String cacheName,
                            final boolean async) {
           this.protocol = protocol;
           this.uri = uri;
           this.source = source;
           this.expires = expires;
  +        this.cacheName = cacheName;
           this.async = async;
  -        this.parameters = parameters;
  -
  +        
           String key = "source:" + source.getURI();
  -        String cacheName = parameters.getParameter("cache-name", null);
           if (cacheName != null) {
               key += ":" + cacheName;
           }
  @@ -161,87 +156,44 @@
   
           if (this.async && this.expires != 0) {
               if (getLogger().isDebugEnabled()) {
  -                getLogger().debug("Not invalidating cached response " +
  -                    "for asynch source " + getSourceURI());
  +                getLogger().debug("Using cached response if available.");
               }
               checkValidity = false;
           }
   
           this.response = (CachedSourceResponse) this.cache.get(this.cacheKey);
  +
           if (this.response == null) {
               if (getLogger().isDebugEnabled()) {
  -                getLogger().debug("No cached response found " +
  -                    "for source " + getSourceURI());
  +                getLogger().debug("No cached response found.");
               }
               checkValidity = false;
           }
   
  -        if (checkValidity) {
  -
  -            final ExpiresValidity cacheValidity = (ExpiresValidity) this.response.getValidityObjects()[0];
  -            final SourceValidity sourceValidity = this.response.getValidityObjects()[1];
  -
  -            boolean remove = false;
  -            if (this.expires == 0) {
  -                if (getLogger().isDebugEnabled()) {
  -                    getLogger().debug("Force invalidation of cached response" +
  -                        " of source " + getSourceURI());
  -                }
  -                remove = true;
  -            }
  -            else {
  -                boolean expired = cacheValidity.isValid() != SourceValidity.VALID;
  -                if (expired) {
  -                    if (getLogger().isDebugEnabled()) {
  -                        getLogger().debug("Cached response of source "
  -                            + getSourceURI() + " is expired.");
  -                    }
  -                    boolean invalid = !isValid(sourceValidity, this.source);
  -                    if (invalid) {
  -                        if (getLogger().isDebugEnabled()) {
  -                            getLogger().debug("Cached response of source "
  -                                + getSourceURI() + " is invalid.");
  -                        }
  -                        remove = true;
  -                    }
  -                    else {
  -                        if (getLogger().isDebugEnabled()) {
  -                            getLogger().debug("Cached response of source "
  -                                + getSourceURI() + " is still valid.");
  -                        }
  -                        // set new expiration period
  -                        this.response.getValidityObjects()[0] = new ExpiresValidity(getExpiration());
  -                    }
  -                }
  +        if (this.expires == 0) {
  +            if (getLogger().isDebugEnabled()) {
  +                getLogger().debug("Not using cached response.");
               }
  +            this.response = null;
  +            checkValidity = false;
  +        }
   
  -            if (remove) {
  -                this.response = null;
  -                // remove it if it no longer exists
  -                if (!exists()) {
  -                    this.cache.remove(this.cacheKey);
  -                }
  +        if (checkValidity && !checkValidity()) {
  +            this.response = null;
  +            // remove it if it no longer exists
  +            if (!this.source.exists()) {
  +                remove();
               }
           }
  -        if (this.async && this.expires > 0) {
  -            // schedule it with the refresher
  -            this.refresher.refresh(this.cacheKey,
  -                                   getSourceURI(),
  -                                   this.parameters.getParameter("cache-role", null),
  -                                   this.parameters);
  -        }
  +
       }
   
       /**
        * Cleanup.
        */
       public void dispose() {
  -        if (this.source != null) {
  -            this.resolver.release(this.source);
  -            this.source = null;
  -        }
  +        this.source = null;
           this.manager = null;
  -        this.resolver = null;
           this.cache = null;
       }
   
  @@ -254,22 +206,15 @@
           boolean storeResponse = false;
           CachedSourceResponse response = this.response;
           if (response == null) {
  -            if (this.expires != 0) {
  -                final SourceValidity cacheValidity = new ExpiresValidity(getExpiration());
  -                final SourceValidity sourceValidity = source.getValidity();
  -                response = new CachedSourceResponse(new SourceValidity[] {cacheValidity, sourceValidity});
  -                storeResponse = true;
  -            }
  -            else {
  -                response = new CachedSourceResponse(null);
  -            }
  +            response = new CachedSourceResponse(new SourceValidity[] { new ExpiresValidity(getExpiration()), source.getValidity() });
  +            storeResponse = true;
           }
           if (response.getExtra() == null) {
               response.setExtra(readMeta(this.source));
               this.freshMeta = true;
           }
  +        this.response = response;
           if (storeResponse) {
  -            this.response = response;
               try {
                   this.cache.store(this.cacheKey, this.response);
               }
  @@ -289,25 +234,19 @@
           /* delay caching the response until we have a valid new one */
           CachedSourceResponse response = this.response;
           if (response == null) {
  -            if (this.expires != 0) {
  -                final SourceValidity cacheValidity = new ExpiresValidity(getExpiration());
  -                final SourceValidity sourceValidity = source.getValidity();
  -                response = new CachedSourceResponse(new SourceValidity[] {cacheValidity, sourceValidity});
  -                storeResponse = true;
  -            }
  -            else {
  -                response = new CachedSourceResponse(null);
  -            }
  +            response = new CachedSourceResponse(new SourceValidity[] { new ExpiresValidity(getExpiration()), source.getValidity()});
  +            storeResponse = true;
           }
           if (response.getBinaryResponse() == null) {
               response.setBinaryResponse(readBinaryResponse(this.source));
               if (!this.freshMeta) {
                   /* always refresh meta in this case */
                   response.setExtra(readMeta(this.source));
  +                this.freshMeta = true;
               }
           }
  +        this.response = response;
           if (storeResponse) {
  -            this.response = response;
               try {
                   this.cache.store(this.cacheKey, this.response);
               }
  @@ -330,15 +269,8 @@
           /* delay caching the response until we have a valid new one */
           CachedSourceResponse response = this.response;
           if (response == null) {
  -            if (this.expires != 0) {
  -                final SourceValidity cacheValidity = new ExpiresValidity(getExpiration());
  -                final SourceValidity sourceValidity = source.getValidity();
  -                response = new CachedSourceResponse(new SourceValidity[] {cacheValidity, sourceValidity});
  -                storeResponse = true;
  -            }
  -            else {
  -                response = new CachedSourceResponse(null);
  -            }
  +            response = new CachedSourceResponse(new SourceValidity[] { new ExpiresValidity(getExpiration()), source.getValidity() });
  +            storeResponse = true;
           }
           if (response.getXMLResponse() == null || refresh) {
               byte[] binary = response.getBinaryResponse();
  @@ -346,10 +278,11 @@
               if (!this.freshMeta) {
                   /* always refresh meta in this case */
                   response.setExtra(readMeta(this.source));
  +                this.freshMeta = true;
               }
           }
  +        this.response = response;
           if (storeResponse) {
  -            this.response = response;
               try {
                   this.cache.store(this.cacheKey, this.response);
               }
  @@ -446,13 +379,57 @@
   
       /**
        * Refresh this object and update the last modified date
  -     * and content length.
  +     * and content length. This method will try to refresh the
  +     * cached contents.
        */
       public void refresh() {
  -        this.response = null;
           this.source.refresh();
  +        if (response != null && checkValidity()) {
  +            if (getLogger().isDebugEnabled()) {
  +                getLogger().debug("Cached response is still valid for source " + this.uri + ".");
  +            }
  +        }
  +        else {
  +            if (this.source.exists()) {
  +                CachedSourceResponse response = this.response;
  +                try {
  +                    if (response == null) {
  +                        // create a new cached response
  +                        response = new CachedSourceResponse(new SourceValidity[] { 
  +                                new ExpiresValidity(getExpiration()), source.getValidity()});
  +                    }
  +                    // only create objects that are cached
  +                    if (response.getBinaryResponse() != null) {
  +                        response.setBinaryResponse(readBinaryResponse(source));
  +                    }
  +                    if (response.getXMLResponse() != null) {
  +                        response.setXMLResponse(readXMLResponse(
  +                                source, response.getBinaryResponse(), this.manager));
  +                    }
  +                    // always refresh meta data
  +                    response.setExtra(readMeta(source));
  +                    this.response = response;
  +                    cache.store(this.cacheKey, response);
  +                }
  +                catch (Exception e) {
  +                    getLogger().warn("Error refreshing source " + this.uri +
  +                        "Cached response (if any) may be stale.", e);
  +                }
  +            }
  +            else if (this.response != null) {
  +                if (getLogger().isDebugEnabled()) {
  +                    getLogger().debug("Source " + this.uri + " no longer exists." +
  +                        " Throwing out cached response.");
  +                }
  +                remove();
  +            }
  +        }
       }
  -
  +    
  +    protected void remove() {
  +        this.cache.remove(this.cacheKey);
  +    }
  +    
       // ---------------------------------------------------- XMLizable implementation
   
       /**
  @@ -511,7 +488,7 @@
        * @throws IOException
        * @throws CascadingIOException
        */
  -    protected static byte[] readXMLResponse(Source source, byte[] binary, ServiceManager manager)
  +    protected byte[] readXMLResponse(Source source, byte[] binary, ServiceManager manager)
       throws SAXException, IOException, CascadingIOException {
           XMLSerializer serializer = null;
           XMLizer xmlizer = null;
  @@ -552,7 +529,7 @@
        * @throws IOException
        * @throws SourceNotFoundException
        */
  -    protected static byte[] readBinaryResponse(Source source)
  +    protected byte[] readBinaryResponse(Source source)
       throws IOException, SourceNotFoundException {
           final ByteArrayOutputStream baos = new ByteArrayOutputStream();
           final byte[] buffer = new byte[2048];
  @@ -572,38 +549,17 @@
        * @return source meta data
        * @throws IOException
        */
  -    protected static SourceMeta readMeta(Source source) throws IOException {
  -        SourceMeta meta;
  -
  -        if (source instanceof TraversableSource) {
  -
  -            final TraversableSourceMeta tmeta = new TraversableSourceMeta();
  -            final TraversableSource tsource = (TraversableSource) source;
  -
  -            tmeta.setName(tsource.getName());
  -            tmeta.setIsCollection(tsource.isCollection());
  -
  -            if (tmeta.isCollection()) {
  -                final Collection children = tsource.getChildren();
  -                if (children != null) {
  -                    final String[] names = new String[children.size()];
  -                    final Iterator iter = children.iterator();
  -                    int count = 0;
  -                    while(iter.hasNext()) {
  -                        TraversableSource child = (TraversableSource) iter.next();
  -                        names[count] = child.getName();
  -                        count++;
  -                    }
  -                    tmeta.setChildren(names);
  -                }
  -            }
  -
  -            meta = tmeta;
  -        }
  -        else {
  -            meta = new SourceMeta();
  -        }
  -
  +    protected final SourceMeta readMeta(Source source) throws IOException {
  +        SourceMeta meta = createMeta();
  +        initMeta(meta, source);
  +        return meta;
  +    }
  +    
  +    protected SourceMeta createMeta() {
  +        return new SourceMeta();
  +    }
  +    
  +    protected void initMeta(SourceMeta meta, Source source) throws IOException {
           final long lastModified = source.getLastModified();
           if (lastModified > 0) {
               meta.setLastModified(lastModified);
  @@ -612,15 +568,46 @@
               meta.setLastModified(System.currentTimeMillis());
           }
           meta.setMimeType(source.getMimeType());
  -
  -        return meta;
       }
   
  -    protected static boolean isValid(SourceValidity validity, Source source) {
  -        if (validity == null) return false;
  -        return validity.isValid() == SourceValidity.VALID ||
  -              (validity.isValid() == SourceValidity.UNKNOWN &&
  -               validity.isValid(source.getValidity()) == SourceValidity.VALID);
  +    private boolean checkValidity() {
  +        if (this.response == null) return false;
  +        
  +        final ExpiresValidity expiresValidity = (ExpiresValidity) this.response.getValidityObjects()[0];
  +        final SourceValidity sourceValidity = this.response.getValidityObjects()[1];
  +
  +        boolean valid = true;
  +        
  +        if (expiresValidity.isValid() != SourceValidity.VALID) {
  +            if (getLogger().isDebugEnabled()) {
  +                getLogger().debug("Cached response of source " + getSourceURI() + " is expired.");
  +            }
  +            if (!isValid(sourceValidity, source.getValidity())) {
  +                if (getLogger().isDebugEnabled()) {
  +                    getLogger().debug("Cached response of source " + getSourceURI() + " is invalid.");
  +                }
  +                valid = false;
  +            }
  +            else {
  +                if (getLogger().isDebugEnabled()) {
  +                    getLogger().debug("Cached response of source " + getSourceURI() + " is still valid.");
  +                }
  +                // set new expiration period
  +                this.response.getValidityObjects()[0] = new ExpiresValidity(getExpiration());
  +            }
  +        }
  +        else {
  +            if (getLogger().isDebugEnabled()) {
  +                getLogger().debug("Cached response of source " + getSourceURI() + " is NOT expired.");
  +            }
  +        }
  +        return valid;
  +    }
  +    
  +    private static boolean isValid(SourceValidity oldValidity, SourceValidity newValidity) {
  +        return (oldValidity.isValid() == SourceValidity.VALID ||
  +                (oldValidity.isValid() == SourceValidity.UNKNOWN &&
  +                 oldValidity.isValid(newValidity) == SourceValidity.VALID));
       }
   
       /**
  @@ -656,36 +643,6 @@
               m_exists = exists;
           }
   
  -    }
  -
  -    protected static class TraversableSourceMeta extends SourceMeta {
  -        private String   m_name;
  -        private boolean  m_isCollection;
  -        private String[] m_children;
  -
  -        protected String getName() {
  -            return m_name;
  -        }
  -
  -        protected void setName(String name) {
  -            m_name = name;
  -        }
  -
  -        protected boolean isCollection() {
  -            return m_isCollection;
  -        }
  -
  -        protected void setIsCollection(boolean isCollection) {
  -            m_isCollection = isCollection;
  -        }
  -
  -        protected String[] getChildren() {
  -            return m_children;
  -        }
  -
  -        protected void setChildren(String[] children) {
  -            m_children = children;
  -        }
       }
   
   }
  
  
  
  1.7       +33 -86    cocoon-2.1/src/blocks/scratchpad/java/org/apache/cocoon/components/source/impl/UpdateTarget.java
  
  Index: UpdateTarget.java
  ===================================================================
  RCS file: /home/cvs/cocoon-2.1/src/blocks/scratchpad/java/org/apache/cocoon/components/source/impl/UpdateTarget.java,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -r1.6 -r1.7
  --- UpdateTarget.java	15 Apr 2004 08:05:56 -0000	1.6
  +++ UpdateTarget.java	1 Jul 2004 14:24:36 -0000	1.7
  @@ -15,6 +15,7 @@
    */
   package org.apache.cocoon.components.source.impl;
   
  +import java.io.IOException;
   import java.util.Map;
   
   import org.apache.avalon.framework.logger.AbstractLogEnabled;
  @@ -23,12 +24,8 @@
   import org.apache.avalon.framework.service.ServiceManager;
   import org.apache.avalon.framework.service.Serviceable;
   import org.apache.cocoon.caching.Cache;
  -import org.apache.cocoon.caching.IdentifierCacheKey;
   import org.apache.cocoon.components.cron.ConfigurableCronJob;
  -import org.apache.excalibur.source.Source;
   import org.apache.excalibur.source.SourceResolver;
  -import org.apache.excalibur.source.SourceValidity;
  -import org.apache.excalibur.source.impl.validity.ExpiresValidity;
   
   /**
    * A target updating a cache entry.
  @@ -48,11 +45,7 @@
    *  The time in seconds the cached content is valid
    * </li>
    * <li>
  - *  <code>fail-safe (boolean)</code>
  - *  Whether to invalidate the cached response when updating it failed.
  - * </li>
  - * <li>
  - *  <code>cache-key (SimpleCacheKey)</code>: 
  + *  <code>cache-name (String)</code>: 
    *  The key used to cache the content
    * </li>
    * </ul>
  @@ -71,10 +64,7 @@
       private String uri;
       private String cacheRole;
       private int expires;
  -    private boolean failSafe;
  -    
  -    // the key under which to store the CachedResponse in the Cache
  -    private IdentifierCacheKey cacheKey;
  +    private String cacheName;
       
           
       // ---------------------------------------------------- Lifecycle
  @@ -96,14 +86,13 @@
       public void setup(Parameters pars, Map objects) {
           this.uri = pars.getParameter("uri", null);
           this.cacheRole = pars.getParameter("cache-role", Cache.ROLE);
  -        this.expires = pars.getParameterAsInteger("cache-expires", 60);
  -        this.failSafe = pars.getParameterAsBoolean("fail-safe", true);
  -        this.cacheKey = (IdentifierCacheKey) objects.get("cache-key");
  +        this.expires = pars.getParameterAsInteger("cache-expires", 0);
  +        this.cacheName = pars.getParameter("cache-name", null);
       }
       
       
       // ---------------------------------------------------- CronJob implementation
  -    
  +
       /* (non-Javadoc)
        * @see org.apache.avalon.cornerstone.services.scheduler.Target#targetTriggered(java.lang.String)
        */
  @@ -112,78 +101,36 @@
               if (this.getLogger().isDebugEnabled()) {
                   this.getLogger().debug("Refreshing " + this.uri);
               }
  -            
  -            Source source = null;
               Cache cache = null;
  +            CachingSource source = null;
               try {
  -                
  -                cache = (Cache) this.manager.lookup(this.cacheRole);
  -                source = this.resolver.resolveURI(this.uri);
  -                
  -                // check if the source is really expired and invalid
  -                CachedSourceResponse response = (CachedSourceResponse) cache.get(this.cacheKey);
  -                if (response != null) {
  -                    final SourceValidity sourceValidity = response.getValidityObjects()[1];
  -                    if (CachingSource.isValid(sourceValidity, source)) {
  -                        if (getLogger().isDebugEnabled()) {
  -                            getLogger().debug("Cached response is still valid " +
                                "for source " + this.uri + ".");
  -                        }
  -                        response.getValidityObjects()[0] = new ExpiresValidity(this.expires * 1000);
  -                        return;
  -                    }
  -                }
  -                
  -                if (source.exists()) {
  -                    
  -                    // what is in the cached response?
  -                    byte[] binary = null;
  -                    byte[] xml = null;
  -                    if (response != null) {
  -                        binary = response.getBinaryResponse();
  -                        xml = response.getXMLResponse();
  -                    }
  -                    
  -                    // create a new cached response
  -                    final ExpiresValidity cacheValidity = new ExpiresValidity(this.expires * 1000);
  -                    final SourceValidity sourceValidity = source.getValidity();
  -                    response = new CachedSourceResponse(new SourceValidity[] {cacheValidity, sourceValidity});
  -                    
  -                    // only create objects that have previously been used
  -                    if (binary != null) {
  -                        binary = CachingSource.readBinaryResponse(source);
  -                        response.setBinaryResponse(binary);
  -                    }
  -                    if (xml != null) {
  -                        xml = CachingSource.readXMLResponse(source, binary, this.manager);
  -                        response.setXMLResponse(xml);
  -                    }
  -                    // meta info is always set
  -                    response.setExtra(CachingSource.readMeta(source));
  -                    cache.store(this.cacheKey, response);
  -                }
  -                else if (response != null) {
  -                    // FIXME: There is a potential problem when the parent
  -                    // source has not yet been updated thus listing this
  -                    // source still as one of its children. We'll have to remove 
  -                    // the parent's cached response here too.
  -                    if (getLogger().isDebugEnabled()) {
  -                        getLogger().debug("Source " + this.uri + " no longer exists." +
                            " Throwing out cached response.");
  -                    }
  -                    cache.remove(this.cacheKey);
  -                }
  -            } catch (Exception e) {
  -                if (!failSafe) {
  -                    // the content expires, so remove it
  -                    cache.remove(cacheKey);
  -                    getLogger().warn("Exception during updating of source " + this.uri, e);
  +                cache = (Cache) manager.lookup(cacheRole);
  +                source = CachingSourceFactory.newCachingSource(
  +                                               this.resolver.resolveURI(this.uri),
  +                                               "cached",
  +                                               "cached:" + uri,
  +                                               expires,
  +                                               cacheName,
  +                                               true,
  +                                               cache,
  +                                               getLogger(),
  +                                               this.manager);
  +                                               
  +                source.refresh();
  +            }
  +            catch (IOException e) {
  +                getLogger().error("Error refreshing source", e);
  +            }
  +            catch (ServiceException e) {
  +                getLogger().error("Error refreshing source", e);
  +            }
  +            finally {
  +                if (cache != null) {
  +                    manager.release(cache);
                   }
  -                else {
  -                    getLogger().warn("Updating of source " + this.uri + " failed. " +
  -                        "Cached response (if any) will be stale.", e);
  +                if (source != null) {
  +                    this.resolver.release(source);
                   }
  -            } finally {
  -                this.resolver.release(source);
  -                this.manager.release(cache);
               }
           }
       }
  
  
  
  1.12      +83 -29    cocoon-2.1/src/blocks/scratchpad/java/org/apache/cocoon/components/source/impl/CachingSourceFactory.java
  
  Index: CachingSourceFactory.java
  ===================================================================
  RCS file: /home/cvs/cocoon-2.1/src/blocks/scratchpad/java/org/apache/cocoon/components/source/impl/CachingSourceFactory.java,v
  retrieving revision 1.11
  retrieving revision 1.12
  diff -u -r1.11 -r1.12
  --- CachingSourceFactory.java	11 Jun 2004 12:18:23 -0000	1.11
  +++ CachingSourceFactory.java	1 Jul 2004 14:24:36 -0000	1.12
  @@ -26,12 +26,14 @@
   import org.apache.avalon.framework.configuration.ConfigurationException;
   import org.apache.avalon.framework.container.ContainerUtil;
   import org.apache.avalon.framework.logger.AbstractLogEnabled;
  +import org.apache.avalon.framework.logger.Logger;
   import org.apache.avalon.framework.parameters.Parameters;
   import org.apache.avalon.framework.service.ServiceException;
   import org.apache.avalon.framework.service.ServiceManager;
   import org.apache.avalon.framework.service.Serviceable;
   import org.apache.avalon.framework.thread.ThreadSafe;
   import org.apache.cocoon.caching.Cache;
  +import org.apache.cocoon.components.source.InspectableSource;
   import org.apache.excalibur.source.Source;
   import org.apache.excalibur.source.SourceException;
   import org.apache.excalibur.source.SourceFactory;
  @@ -112,6 +114,16 @@
   implements SourceFactory, URIAbsolutizer, Serviceable, Configurable, Disposable, ThreadSafe
   {
   
  +    // ---------------------------------------------------- Constants
  +    
  +    public static final String ASYNC_PARAM = "async";
  +    public static final String FAILSAFE_PARAM = "failsafe";
  +    public static final String CACHE_ROLE_PARAM = "cache-role";
  +    public static final String REFRESHER_ROLE_PARAM = "refresher-role";
  +    public static final String DEFAULT_EXPIRES_PARAM = "default-expires";
  +
  +    // ---------------------------------------------------- Instance variables
  +
       /** Protocol prefix / factory name */
       private String scheme;
   
  @@ -159,23 +171,23 @@
           Parameters parameters = Parameters.fromConfiguration(configuration);
   
           // 'async' parameter
  -        this.async = parameters.getParameterAsBoolean("async", false);
  -
  +        this.async = parameters.getParameterAsBoolean(ASYNC_PARAM, false);
  +        
           // 'cache-role' parameter
  -        this.cacheRole = parameters.getParameter("cache-role", Cache.ROLE);
  +        this.cacheRole = parameters.getParameter(CACHE_ROLE_PARAM, Cache.ROLE);
           if (this.getLogger().isDebugEnabled()) {
               this.getLogger().debug("Using cache " + this.cacheRole);
           }
   
           // 'refresher-role' parameter
           if (this.async) {
  -            this.refresherRole = parameters.getParameter("refresher-role", Refresher.ROLE);
  +            this.refresherRole = parameters.getParameter(REFRESHER_ROLE_PARAM, Refresher.ROLE);
               if (this.getLogger().isDebugEnabled()) {
                   this.getLogger().debug("Using refresher " + this.refresherRole);
               }
           }
   
  -        this.defaultExpires = parameters.getParameterAsInteger("default-expires", -1);
  +        this.defaultExpires = parameters.getParameterAsInteger(DEFAULT_EXPIRES_PARAM, -1);
       }
   
       /**
  @@ -281,50 +293,91 @@
               }
           }
   
  -        int expires = params.getParameterAsInteger("cache-expires", -1);
  -        if (expires == -1) {
  -            expires = this.defaultExpires;
  -            params.setParameter("cache-expires", String.valueOf(this.defaultExpires));
  -        }
  -        params.setParameter("cache-role", this.cacheRole);
  +        int expires = params.getParameterAsInteger(CachingSource.CACHE_EXPIRES_PARAM, this.defaultExpires);
  +        String cacheName = params.getParameter(CachingSource.CACHE_NAME_PARAM, null);
   
  -        final Source wrappedSource = this.resolver.resolveURI(uri);
  +        final CachingSource source = newCachingSource(this.resolver.resolveURI(uri),
  +                                                      this.scheme,
  +                                                      location,
  +                                                      expires,
  +                                                      cacheName,
  +                                                      this.async,
  +                                                      this.cache,
  +                                                      getLogger(),
  +                                                      manager);
  +        
  +        if (this.async && expires > 0) {
  +
  +            params.setParameter(CachingSource.CACHE_EXPIRES_PARAM, String.valueOf(expires));
  +            params.setParameter(CachingSource.CACHE_NAME_PARAM, cacheName);
  +            params.setParameter(CACHE_ROLE_PARAM, this.cacheRole);
  +
  +            // schedule it with the refresher
  +            this.refresher.refresh(source.getCacheKey(),
  +                                   source.getSourceURI(),
  +                                   this.cacheRole,
  +                                   params);
  +        }
  +        
  +        return source;
  +    }
  +    
  +    /**
  +     * Factory method for creating a new CachingSource.
  +     */
  +    public static CachingSource newCachingSource(Source wrappedSource, 
  +                                                 String scheme,
  +                                                 String uri,
  +                                                 int expires,
  +                                                 String cacheName,
  +                                                 boolean async,
  +                                                 Cache cache,
  +                                                 Logger logger,
  +                                                 ServiceManager manager)
  +    throws SourceException {
  +        
           CachingSource source;
           if (wrappedSource instanceof TraversableSource) {
  -            source = new TraversableCachingSource(scheme,
  -                                                  location,
  -                                                  (TraversableSource) wrappedSource,
  -                                                  params,
  -                                                  expires,
  -                                                  this.async);
  +            if (wrappedSource instanceof InspectableSource) {
  +                source = new InspectableTraversableCachingSource(scheme,
  +                                                                 uri,
  +                                                                 (InspectableSource) wrappedSource,
  +                                                                 expires,
  +                                                                 cacheName,
  +                                                                 async);
  +            } else {
  +                source = new TraversableCachingSource(scheme,
  +                                                      uri,
  +                                                      (TraversableSource) wrappedSource,
  +                                                      expires,
  +                                                      cacheName,
  +                                                      async);
  +            }
           } else {
               source = new CachingSource(scheme,
  -                                       location,
  +                                       uri,
                                          wrappedSource,
  -                                       params,
                                          expires,
  -                                       this.async);
  +                                       cacheName,
  +                                       async);
           }
   
           // set the required components directly for speed
  -        source.cache = this.cache;
  -        source.resolver = this.resolver;
  -        source.refresher = this.refresher;
  +        source.cache = cache;
   
  -        ContainerUtil.enableLogging(source, this.getLogger());
  +        ContainerUtil.enableLogging(source, logger);
           try {
               // call selected avalon lifecycle interfaces. Mmmh.
  -            ContainerUtil.service(source, this.manager);
  +            ContainerUtil.service(source, manager);
               ContainerUtil.initialize(source);
           } catch (ServiceException se) {
               throw new SourceException("Unable to initialize source.", se);
           } catch (Exception e) {
               throw new SourceException("Unable to initialize source.", e);
           }
  -
           return source;
       }
  -
  +    
       /**
        * Release a {@link Source} object.
        */
  @@ -333,6 +386,7 @@
               if (this.getLogger().isDebugEnabled() ) {
                   this.getLogger().debug("Releasing source " + source.getURI());
               }
  +            resolver.release(((CachingSource) source).source);
               ((CachingSource) source).dispose();
           }
       }
  
  
  
  1.1                  cocoon-2.1/src/blocks/scratchpad/java/org/apache/cocoon/components/source/impl/InspectableTraversableCachingSource.java
  
  Index: InspectableTraversableCachingSource.java
  ===================================================================
  /*
   * Copyright 1999-2004 The Apache Software Foundation.
   * 
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   * 
   *      http://www.apache.org/licenses/LICENSE-2.0
   * 
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  package org.apache.cocoon.components.source.impl;
  
  import java.io.IOException;
  import java.util.Collection;
  import java.util.Collections;
  import java.util.HashMap;
  import java.util.Map;
  
  import org.apache.cocoon.components.source.InspectableSource;
  import org.apache.cocoon.components.source.helpers.SourceProperty;
  import org.apache.excalibur.source.Source;
  import org.apache.excalibur.source.SourceException;
  import org.apache.excalibur.source.TraversableSource;
  
  /**
   * TraversableCachingSource that adds support for SourceProperty caching.
   */
  public class InspectableTraversableCachingSource extends TraversableCachingSource
  implements InspectableSource {
  
      private InspectableSource isource;
  
      public InspectableTraversableCachingSource(String protocol,
                                                 String uri,
                                                 InspectableSource source, 
                                                 int expires,
                                                 String cacheName,
                                                 boolean async) {
          super(protocol, uri, (TraversableSource) source, expires, cacheName, async);
          this.isource = source;
      }
  
      public SourceProperty getSourceProperty(String namespace, String name) throws SourceException {
          try {
              initMetaResponse();
          }
          catch (IOException e) {
              if (getLogger().isDebugEnabled()) {
                  getLogger().debug("Failure initializing inspectable response", e);
              }
              return null;
          }
          final InspectableSourceMeta imeta = ((InspectableSourceMeta) super.response.getExtra());
          SourceProperty property = imeta.getSourceProperty(namespace, name);
          if (property == null) {
              property = isource.getSourceProperty(namespace, name);
              if (property == null) {
                  // remember that this property is null
                  property = InspectableSourceMeta.NULL_PROPERTY;
              }
              imeta.setSourceProperty(property);
          }
          if (InspectableSourceMeta.NULL_PROPERTY.equals(property)) {
              return null;
          }
          return property;
      }
  
      public void setSourceProperty(SourceProperty property) throws SourceException {
          isource.setSourceProperty(property);
          try {
              initMetaResponse();
          }
          catch (IOException e) {
              if (getLogger().isDebugEnabled()) {
                  getLogger().debug("Failure initializing inspectable response", e);
              }
          }
          final InspectableSourceMeta imeta = ((InspectableSourceMeta) super.response.getExtra());
          imeta.setSourceProperty(property);
      }
  
      public SourceProperty[] getSourceProperties() throws SourceException {
          try {
              initMetaResponse();
          }
          catch (IOException e) {
              if (getLogger().isDebugEnabled()) {
                  getLogger().debug("Failure initializing inspectable response", e);
              }
              return null;
          }
          final InspectableSourceMeta imeta = ((InspectableSourceMeta) super.response.getExtra());
          SourceProperty[] properties = imeta.getSourceProperties();
          if (properties == null) {
              properties = isource.getSourceProperties();
              imeta.setSourceProperties(properties);
          }
          return properties;
      }
  
      public void removeSourceProperty(String namespace, String name) throws SourceException {
          isource.removeSourceProperty(namespace, name);
          try {
              initMetaResponse();
          }
          catch (IOException e) {
              if (getLogger().isDebugEnabled()) {
                  getLogger().debug("Failure initializing inspectable response", e);
              }
          }
          final InspectableSourceMeta imeta = ((InspectableSourceMeta) super.response.getExtra());
          imeta.removeSourceProperty(namespace, name);
      }
      
      protected SourceMeta createMeta() {
          return new InspectableSourceMeta();
      }
      
      protected TraversableCachingSource newSource(String uri, Source wrapped) {
          return  new InspectableTraversableCachingSource(super.protocol,
                                                          uri,
                                                          (InspectableSource) wrapped,
                                                          super.expires,
                                                          super.cacheName,
                                                          super.async);
      }
      
      protected static class InspectableSourceMeta extends TraversableSourceMeta {
          
          protected static final SourceProperty NULL_PROPERTY = new SourceProperty("cocoon","isnull");
          
          private Map properties;
          
          /* flag for determining whether we have all properties */
          private boolean all;
          
          protected SourceProperty getSourceProperty(String namespace, String name) {
              if (properties == null) return null;
              final String key = namespace + "#" + name;
              return (SourceProperty) properties.get(key);
          }
          
          protected void setSourceProperty(SourceProperty property) {
              if (this.properties == null) {
                  this.properties = Collections.synchronizedMap(new HashMap(11));
              }
              final String key = property.getNamespace() + "#" + property.getName();
              properties.put(key, property);
          }
  
          protected SourceProperty[] getSourceProperties() {
              if (this.properties == null || !all) return null;
              final Collection values = this.properties.values();
              return (SourceProperty[]) values.toArray(new SourceProperty[values.size()]);
          }
  
          protected void setSourceProperties(SourceProperty[] props) {
              if (this.properties == null) {
                  this.properties = Collections.synchronizedMap(new HashMap(props.length));
              }
              for (int i = 0; i < props.length; i++) {
                  setSourceProperty(props[i]);
              }
              all = true;
          }
          
          protected void removeSourceProperty(String namespace, String name) {
              if (this.properties != null) {
                  final String key = namespace + "#" + name;
                  properties.remove(key);
              }
          }
      }
  }
  
  
  

Mime
View raw message