You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@cocoon.apache.org by sy...@apache.org on 2003/05/13 22:19:54 UTC

cvs commit: cocoon-2.1/src/java/org/apache/cocoon/generation DirectoryGenerator.java

sylvain     2003/05/13 13:19:54

  Modified:    src/java/org/apache/cocoon/generation
                        DirectoryGenerator.java
  Log:
  DirectoryGenerator is now cacheable
  
  Revision  Changes    Path
  1.2       +91 -2     cocoon-2.1/src/java/org/apache/cocoon/generation/DirectoryGenerator.java
  
  Index: DirectoryGenerator.java
  ===================================================================
  RCS file: /home/cvs/cocoon-2.1/src/java/org/apache/cocoon/generation/DirectoryGenerator.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- DirectoryGenerator.java	9 Mar 2003 00:09:31 -0000	1.1
  +++ DirectoryGenerator.java	13 May 2003 20:19:54 -0000	1.2
  @@ -53,10 +53,12 @@
   import org.apache.avalon.framework.parameters.Parameters;
   import org.apache.cocoon.ProcessingException;
   import org.apache.cocoon.ResourceNotFoundException;
  +import org.apache.cocoon.caching.CacheableProcessingComponent;
   import org.apache.cocoon.components.source.SourceUtil;
   import org.apache.cocoon.environment.SourceResolver;
   import org.apache.excalibur.source.Source;
   import org.apache.excalibur.source.SourceException;
  +import org.apache.excalibur.source.SourceValidity;
   import org.apache.regexp.RE;
   import org.apache.regexp.RESyntaxException;
   import org.xml.sax.SAXException;
  @@ -64,9 +66,12 @@
   
   import java.io.File;
   import java.io.IOException;
  +import java.io.Serializable;
   import java.net.URL;
   import java.text.SimpleDateFormat;
  +import java.util.ArrayList;
   import java.util.Date;
  +import java.util.List;
   import java.util.Map;
   import java.util.Stack;
   import java.util.Arrays;
  @@ -109,6 +114,9 @@
    * <dd> Sets the format for the date attribute of each node, as
    * described in java.text.SimpleDateFormat. If unset, the default
    * format for the current locale will be used.
  + * <dt> <i>refreshDelay</i> (optional)
  + * <dd> Sets the delay (in seconds) between checks on the filesystem for changed content.
  + * Defaults to 1 second.
    * </dl>
    *
    * @author <a href="mailto:pier@apache.org">Pierpaolo Fumagalli</a>
  @@ -117,7 +125,7 @@
    *         (SMB GmbH) for Virbus AG
    * @version CVS $Id$
    */
  -public class DirectoryGenerator extends ComposerGenerator  {
  +public class DirectoryGenerator extends ComposerGenerator implements CacheableProcessingComponent  {
     private static final String FILE = "file:";
   
       /** The URI of the namespace of this generator. */
  @@ -152,6 +160,12 @@
       protected RE excludeRE;
   
       protected boolean isRequestedDirectory;
  +    
  +    /** The validity that is being built */
  +    protected DirValidity validity;
  +    
  +    /** The delay between checks to the filesystem */
  +    protected long refreshDelay;
   
   
       /**
  @@ -185,10 +199,14 @@
           this.reverse = par.getParameterAsBoolean("reverse", false);
   
           String rePattern = par.getParameter("root", null);
  +        
  +        this.refreshDelay = par.getParameterAsLong("refreshDelay", 1L) * 1000L;
  +        
           if (this.getLogger().isDebugEnabled()) {
               this.getLogger().debug("depth: " + this.depth);
               this.getLogger().debug("sort: " + this.sort);
               this.getLogger().debug("reverse: " + this.reverse);
  +            this.getLogger().debug("refreshDelay: " + this.refreshDelay);
           }
           try {
               this.rootRE = (rePattern == null)?null:new RE(rePattern);
  @@ -215,6 +233,26 @@
           this.attributes = new AttributesImpl();
       }
   
  +	/* (non-Javadoc)
  +	 * @see org.apache.cocoon.caching.CacheableProcessingComponent#getKey()
  +	 */
  +	public Serializable getKey()
  +	{
  +		return super.source + this.sort + this.depth + this.excludeRE + this.includeRE + this.reverse;
  +	}
  +
  +
  +	/**
  +	 * Gets the source validity, using a deferred validity object. The validity is initially empty since
  +	 * the files that define it are not known before generation has occured. So the returned object is
  +	 * kept by the generator and filled with each of the files that are traversed.
  +	 * @see DirectoryGenerator.DirValidity
  +	 */
  +	public SourceValidity getValidity()
  +	{
  +		this.validity = new DirValidity(this.refreshDelay);
  +		return this.validity;
  +	}
   
       /**
        * Generate XML data.
  @@ -404,6 +442,10 @@
        */
       protected void startNode(String nodeName, File path)
       throws SAXException {
  +		if (this.validity != null) {
  +			this.validity.addFile(path);
  +		}
  +
           setNodeAttributes(path);
           super.contentHandler.startElement(URI, nodeName, PREFIX+':'+nodeName, attributes);
       }
  @@ -523,6 +565,53 @@
          this.rootRE = null;
          this.includeRE = null;
          this.excludeRE = null;
  +       this.validity = null;
   
       }
  +
  +    /** Specific validity class, that holds all files that have been generated */
  +	public static class DirValidity implements SourceValidity {
  +		private long expiry;
  +		private long delay;
  +		List files = new ArrayList();
  +		List fileDates = new ArrayList();
  +
  +		public DirValidity(long delay) {
  +			expiry = System.currentTimeMillis() + delay;
  +			this.delay = delay;
  +		}
  +
  +		public int isValid() {
  +			if (System.currentTimeMillis() <= expiry)
  +				return 1;
  +
  +			//            System.out.println("Regenerating cache validity");
  +			expiry = System.currentTimeMillis() + delay;
  +			int len = files.size();
  +			for (int i = 0; i < len; i++) {
  +				File f = (File) files.get(i);
  +				if (!f.exists())
  +					return -1; // File was removed
  +
  +				long oldDate = ((Long) fileDates.get(i)).longValue();
  +				long newDate = f.lastModified();
  +
  +				if (oldDate != newDate)
  +					return -1;
  +			}
  +
  +			// All content is up to date : update the expiry date
  +			expiry = System.currentTimeMillis() + delay;
  +			return 1;
  +		}
  +		
  +		public int isValid(SourceValidity newValidity) {
  +			return isValid();
  +		}
  +
  +		public void addFile(File f) {
  +			files.add(f);
  +			fileDates.add(new Long(f.lastModified()));
  +		}
  +	}
   }
  
  
  

RE: cvs commit: cocoon-2.1/src/java/org/apache/cocoon/generation DirectoryGenerator.java

Posted by Geoff Howard <co...@leverageweb.com>.
Educational question: (my education, not yours ;) )

For two nearly concurrent requests, is it possible for a problem to 
occur if the second request causes Cocoon to use the incomplete 
Validity?

My first guess was that its safe unless DirectoryGenerator would implement 
ThreadSafe.  But then, the validity lookup isn't tied to the _use_ of the 
Generator.  Ok, but the cached response won't have been cached yet, so 
during the incomplete phase, the incomplete validity won't be found by the 
second request... um... right?

Forgive me while I still try to wrap my brain around how the component 
container, the caching process, etc. all interact...

Brilliantly simple solution by the way,
Geoff

> -----Original Message-----
> From: sylvain@apache.org [mailto:sylvain@apache.org]
> Sent: Tuesday, May 13, 2003 4:20 PM
> To: cocoon-2.1-cvs@apache.org
> Subject: cvs commit: cocoon-2.1/src/java/org/apache/cocoon/generation
> DirectoryGenerator.java
> 
> 
> sylvain     2003/05/13 13:19:54
> 
>   Modified:    src/java/org/apache/cocoon/generation
>                         DirectoryGenerator.java
>   Log:
>   DirectoryGenerator is now cacheable
   
...

>   +	/**
>   +	 * Gets the source validity, using a deferred validity 
> object. The validity is initially empty since
>   +	 * the files that define it are not known before generation 
> has occured. So the returned object is
>   +	 * kept by the generator and filled with each of the files 
> that are traversed.