Maintainer.java :  » Web-Server » simple » simple » page » Java Open Source

Java Open Source » Web Server » simple 
simple » simple » page » Maintainer.java
/*
 * Maintainer.java February 2006
 *
 * Copyright (C) 2006, Niall Gallagher <niallg@users.sf.net>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General 
 * Public License along with this library; if not, write to the 
 * Free Software Foundation, Inc., 59 Temple Place, Suite 330, 
 * Boston, MA  02111-1307  USA
 */

package simple.page;

import simple.page.translate.Translator;
import simple.page.translate.Reference;
import simple.page.translate.Source;
import simple.page.compile.Compiler;
import simple.http.serve.Context;
import simple.page.Workspace;
import java.util.Hashtable;
import java.util.Set;
import java.io.File;

/**
 * The <code>Maintainer</code> object is used to perform background 
 * compilation of expired JSP sources. This will peroidically check
 * all source references to determine whether the JSP sources that
 * have been used to create a page class have been modified. If the
 * JSP sources have been modified it will recompile and reload the
 * page class, with the new JSP sources.
 *
 * @author Niall Gallagher
 */ 
final class Maintainer extends Thread {

   /**
    * This is the translator used to convert JSP sources.
    */         
   private Translator translator;      
   
   /**
    * This is the compiler used to compile translated sources.
    */ 
   private Compiler compiler;

   /**
    * This is the cache used to store the compiled classes.
    */ 
   private Hashtable cache;

   /**
    * Constructor for the <code>Maintainer</code> object. This will
    * construct a background compiler, which is used to check the
    * JSP sources for modification. All references are acquired from
    * the translator, which may mark several files for monitoring.
    *
    * @param project this is the project used to locate files
    */ 
   public Maintainer(Workspace project) throws Exception {
      this.compiler = new Compiler(project);            
      this.translator = new Translator(project);           
      this.cache = new Hashtable();
      this.start();
   }
   
   /**
    * This will acquire the compiled <code>Class</code> representing
    * the requested JSP. If the class file has not been found in the 
    * cache this will translate and compile the JSP before caching it.
    *
    * @param target this is the URI path to the requested JSP
    */  
   public synchronized Class retrieve(String target) throws Exception{
      Entry entry = (Entry)cache.get(target);

      if(entry == null) {
         entry = load(target);
      } 
      return entry.getType();
   }

   /**
    * This method is used to load the JSP class without compiling it.
    * If the class does not exist then it is compiled. This is used
    * for a batch translate and compile step, which allows the JSP
    * engine to share an ant compile task across multiple targets.
    * 
    * @param source this is the translated JSP source target
    * @param target this is the target that is to be compiled
    */ 
   private synchronized Entry load(String target) throws Exception{
      Source source = translator.translate(target);
      
      try {
         Class type = compiler.load(source);     
         Entry entry = new Entry(source, type);
      
         cache.put(target, entry);  
      }catch(Exception e) {
         return produce(target, source);                 
      }
      return (Entry)cache.get(target);      
      
   }
   
   /**
    * This method is used to perform the translation and compilation
    * of the referenced JSP. This returns an entry, which contains 
    * the class file for the JSP as will as a reference to all files
    * used to compose the class.
    *
    * @param target this is the URI path to the requested JSP
    */ 
   private synchronized Entry produce(String target) throws Exception{
      return produce(target, translator.translate(target));           
   }

   
   /**
    * This method is used to perform the translation and compilation
    * of the referenced JSP. This returns an entry, which contains 
    * the class file for the JSP as will as a reference to all files
    * used to compose the class.
    *
    * @param target this is the URI path to the requested JSP
    * @param source this is the source file for the translated JSP
    */ 
   private synchronized Entry produce(String target, Source source) throws Exception{
      try {
         Class type = compiler.compile(source);
         Entry entry = new Entry(source, type);
         
         cache.put(target, entry);              
      }finally {
         if(!cache.containsKey(target)) {
            source.getSource().delete(); 
         }            
      }         
      return (Entry)cache.get(target);
   }

   /**
    * This method will iterate over the keys acquired from the cache.
    * This makes use of an immutable list of keys to avoid concurrent
    * modifications to the cache. Each key checks the cache for an
    * entry, if an entry exists the JSP sources are checked.
    */ 
   private synchronized void maintain() {
      Set set = cache.keySet();

      if(!set.isEmpty()) {
         refresh(set.toArray());
      }         
   }

   /**
    * This method will iterate over the keys acquired from the cache.
    * This is handed the cache keys for each maintained JSP source.
    * If the key references a modified source it is re-reanslated 
    * and compiled in the background. All failed files are deleted.
    *
    * @param list this is the list of target JSP names to produce
    */    
   private synchronized void refresh(Object[] list) {
      for(int i = 0; i < list.length; i++){
         Entry entry = (Entry)cache.get(list[i]);

         try {
            if(entry.isModified()) {
               produce(list[i].toString());                          
            }         
         } catch(Exception e) {
            cache.remove(list[i]);
            entry.delete();                 
         }            
      }           
   }

   /**
    * This checks all compiled JSP sources every five seconds to
    * determine whether the sources have changed. If any sources have
    * changed then this will re-translate and re-compile the source.
    * If a compilation or translation error occurs with any of the
    * maintained sources, that source is deleted to avoid errors.
    */ 
   public void run() {
      while(true){
         try{
            maintain();
            Thread.sleep(5000);            
         }catch(Exception e){
            e.printStackTrace();                  
         }
      }           
   }
   
   /**
    * The <code>Entry</code> object represents a cachable container
    * for compiled sources. It keeps track of JSP sources, so that
    * they can be checked for modifications, it also keeps the class
    * file for the most recent compilation of the JSP target.
    *
    * @see simple.page.translate.Reference
    */ 
   private class Entry {

      /**
       * Represents the reference for the collection of JSP files.
       */ 
      private Reference marker;

      /**
       * Represents the OS file system location of the source file.
       */ 
      private File source;

      /**
       * Represents the loaded class for for a compiled JSP.
       */ 
      private Class type;      

      /**
       * Constructor for the <code>Entry</code> object. This is used
       * to create a cachable container, to keep all required data
       * for a compiled JSP file. 
       *
       * @param source this is the source for the translated JSP
       * @param type this represents the loaded class for the JSP
       */ 
      public Entry(Source source, Class type) {
         this.marker = source.getReference();
         this.source = source.getSource();
         this.type = type;         
      }

      /**
       * Checks to see if the sources for the JSP have been recently
       * been modified. If the sources have been modified this will
       * return true, this also returns true if the JSP is deleted.
       *
       * @return true if the JSP source files have been modified
       */ 
      public boolean isModified() {
         return marker.isModified();   
      }

      /**
       * Returns the compiled and loaded class for the JSP sources.
       * This ensures that a page can be served, even if the JSP
       * source files are being re-compiled in the background.
       *
       * @return this returns the compiled and loaded page class
       */ 
      public Class getType() {
         return type;              
      }

      /**
       * This method is used to delete the source file for this entry.
       * This is used when the compilation of a source file fails, it
       * ensures that the Ant compiler does not constantly fail.
       */ 
      public void delete() {
         source.delete();              
      }
   }
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.