Save This Page
Home » freemarker-2.3.13 » freemarker.ext.util » [javadoc | source]
    1   /*
    2    * Copyright (c) 2003 The Visigoth Software Society. All rights
    3    * reserved.
    4    *
    5    * Redistribution and use in source and binary forms, with or without
    6    * modification, are permitted provided that the following conditions
    7    * are met:
    8    *
    9    * 1. Redistributions of source code must retain the above copyright
   10    *    notice, this list of conditions and the following disclaimer.
   11    *
   12    * 2. Redistributions in binary form must reproduce the above copyright
   13    *    notice, this list of conditions and the following disclaimer in
   14    *    the documentation and/or other materials provided with the
   15    *    distribution.
   16    *
   17    * 3. The end-user documentation included with the redistribution, if
   18    *    any, must include the following acknowledgement:
   19    *       "This product includes software developed by the
   20    *        Visigoth Software Society (http://www.visigoths.org/)."
   21    *    Alternately, this acknowledgement may appear in the software itself,
   22    *    if and wherever such third-party acknowledgements normally appear.
   23    *
   24    * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the 
   25    *    project contributors may be used to endorse or promote products derived
   26    *    from this software without prior written permission. For written
   27    *    permission, please contact visigoths@visigoths.org.
   28    *
   29    * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth"
   30    *    nor may "FreeMarker" or "Visigoth" appear in their names
   31    *    without prior written permission of the Visigoth Software Society.
   32    *
   33    * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   34    * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   35    * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   36    * DISCLAIMED.  IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR
   37    * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   38    * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   39    * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   40    * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   41    * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   42    * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   43    * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   44    * SUCH DAMAGE.
   45    * ====================================================================
   46    *
   47    * This software consists of voluntary contributions made by many
   48    * individuals on behalf of the Visigoth Software Society. For more
   49    * information on the Visigoth Software Society, please see
   50    * http://www.visigoths.org/
   51    */
   52   
   53   package freemarker.ext.util;
   54   
   55   import java.lang.ref.ReferenceQueue;
   56   import java.lang.ref.SoftReference;
   57   import java.util.Map;
   58   
   59   import freemarker.template.TemplateModel;
   60   import freemarker.template.TemplateModelAdapter;
   61   
   62   /**
   63    * Internally used by various wrapper implementations to implement model
   64    * caching.
   65    * @version $Id: ModelCache.java,v 1.9 2003/01/12 23:40:15 revusky Exp $
   66    * @author Attila Szegedi
   67    */
   68   public abstract class ModelCache
   69   {
   70       private boolean useCache = false;
   71       private Map modelCache = null;
   72       private ReferenceQueue refQueue = null;
   73       
   74       protected ModelCache()
   75       {
   76       }
   77       
   78       /**
   79        * Sets whether this wrapper caches model instances. Default is false.
   80        * When set to true, calling {@link #getInstance(Object)} 
   81        * multiple times for the same object will return the same model.
   82        */
   83       public synchronized void setUseCache(boolean useCache)
   84       {
   85           this.useCache = useCache;
   86           if(useCache)
   87           {
   88               modelCache = new IdentityHashMap();
   89               refQueue = new ReferenceQueue();
   90           }
   91           else
   92           {
   93               modelCache = null;
   94               refQueue = null;
   95           }
   96       }
   97       
   98       public TemplateModel getInstance(Object object)
   99       {
  100           if(object instanceof TemplateModel) {
  101               return (TemplateModel)object;
  102           }
  103           if(object instanceof TemplateModelAdapter) {
  104               return ((TemplateModelAdapter)object).getTemplateModel();
  105           }
  106           if(useCache && isCacheable(object)) {
  107               TemplateModel model = lookup(object);
  108               if(model == null) {
  109                   model = create(object);
  110                   register(model, object);
  111               }
  112               return model;
  113           }
  114           else {
  115               return create(object);
  116           }
  117       }
  118       
  119       protected abstract TemplateModel create(Object object);
  120       protected abstract boolean isCacheable(Object object);
  121       
  122       public void clearCache()
  123       {
  124           if(modelCache != null)
  125           {
  126               synchronized(modelCache)
  127               {
  128                   modelCache.clear();
  129               }
  130           }
  131       }
  132   
  133       private final TemplateModel lookup(Object object)
  134       {
  135           ModelReference ref = null;
  136           // NOTE: we're doing minimal synchronizations -- which can lead to
  137           // duplicate wrapper creation. However, this has no harmful side-effects and
  138           // is a lesser performance hit.
  139           synchronized (modelCache)
  140           {
  141               ref = (ModelReference) modelCache.get(object);
  142           }
  143   
  144           if (ref != null)
  145               return ref.getModel();
  146   
  147           return null;
  148       }
  149   
  150       private final void register(TemplateModel model, Object object)
  151       {
  152           synchronized (modelCache) {
  153               // Remove cleared references
  154               for (;;) {
  155                   ModelReference queuedRef = (ModelReference) refQueue.poll();
  156                   if (queuedRef == null)
  157                       break;
  158                   modelCache.remove(queuedRef.object);
  159               }
  160               // Register new reference
  161               modelCache.put(object, new ModelReference(model, object, refQueue));
  162           }
  163       }
  164   
  165       /**
  166        * A special soft reference that is registered in the modelCache.
  167        * When it gets cleared (that is, the model became unreachable)
  168        * it will remove itself from the model cache.
  169        */
  170       private static final class ModelReference extends SoftReference
  171       {
  172           Object object;
  173   
  174           ModelReference(TemplateModel ref, Object object, ReferenceQueue refQueue)
  175           {
  176               super(ref, refQueue);
  177               this.object = object;
  178           }
  179   
  180           TemplateModel getModel()
  181           {
  182               return (TemplateModel) this.get();
  183           }
  184       }
  185   
  186   }

Save This Page
Home » freemarker-2.3.13 » freemarker.ext.util » [javadoc | source]