Save This Page
Home » freemarker-2.3.13 » freemarker.core » [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.core;
   54   
   55   import java.io.IOException;
   56   import java.util.ArrayList;
   57   import java.util.Collection;
   58   
   59   import freemarker.template.SimpleNumber;
   60   import freemarker.template.TemplateBooleanModel;
   61   import freemarker.template.TemplateCollectionModel;
   62   import freemarker.template.TemplateException;
   63   import freemarker.template.TemplateModel;
   64   import freemarker.template.TemplateModelIterator;
   65   import freemarker.template.TemplateSequenceModel;
   66   
   67   /**
   68    * An instruction that processes a list or foreach block
   69    */
   70   final class IteratorBlock extends TemplateElement {
   71   
   72       private Expression listExpression;
   73       private String indexName;
   74       private boolean isForEach;
   75   
   76       /**
   77        * @param listExpression a variable referring to a sequence or collection
   78        * @param indexName an arbitrary index variable name
   79        * @param nestedBlock the nestedBlock to iterate over
   80        */
   81       IteratorBlock(Expression listExpression,
   82                     String indexName,
   83                     TemplateElement nestedBlock,
   84                     boolean isForEach) 
   85       {
   86           this.listExpression = listExpression;
   87           this.indexName = indexName;
   88           this.isForEach = isForEach;
   89           this.nestedBlock = nestedBlock;
   90       }
   91   
   92       void accept(Environment env) throws TemplateException, IOException 
   93       {
   94           TemplateModel baseModel = listExpression.getAsTemplateModel(env);
   95           if (baseModel == null) {
   96               if (env.isClassicCompatible()) {
   97                   // Classic behavior of simply ignoring null references.
   98                   return;
   99               }
  100               assertNonNull(baseModel, listExpression, env);
  101           }
  102           env.visit(new Context(baseModel));
  103       }
  104   
  105       public String getCanonicalForm() {
  106           if (isForEach) {
  107               StringBuffer buf = new StringBuffer("<#foreach ");
  108               buf.append(indexName);
  109               buf.append(" in ");
  110               buf.append(listExpression.getCanonicalForm());
  111               buf.append(">");
  112               if (nestedBlock != null) {
  113                   buf.append(nestedBlock.getCanonicalForm());
  114               }
  115               buf.append("</#foreach>");
  116               return buf.toString();
  117           }
  118           else {
  119               StringBuffer buf = new StringBuffer("<#list ");
  120               buf.append(listExpression.getCanonicalForm());
  121               buf.append(" as ");
  122               buf.append(indexName);
  123               buf.append(">");
  124               if (nestedBlock != null) {
  125                   buf.append(nestedBlock.getCanonicalForm());            
  126               }
  127               buf.append("</#list>");
  128               return buf.toString();
  129           }
  130       }
  131   
  132       public String getDescription() {
  133           if (isForEach) {
  134               return "foreach " + indexName + " in " + listExpression; 
  135   
  136           }
  137           else {
  138               return "list " + listExpression + " as " + indexName;
  139           }
  140       }
  141   
  142       /**
  143        * A helper class that holds the context of the loop.
  144        */
  145   
  146       class Context implements LocalContext {
  147           private boolean hasNext;
  148           private TemplateModel loopVar;
  149           private int index;
  150           private Collection variableNames = null;
  151           private TemplateModel list;
  152           
  153           Context(TemplateModel list) {
  154               this.list = list;
  155           }
  156           
  157           
  158           void runLoop(Environment env) throws TemplateException, IOException {
  159               if (list instanceof TemplateCollectionModel) {
  160                   TemplateCollectionModel baseListModel = (TemplateCollectionModel)list;
  161                   TemplateModelIterator it = baseListModel.iterator();
  162                   hasNext = it.hasNext();
  163                   while (hasNext) {
  164                       loopVar = it.next();
  165                       hasNext = it.hasNext();
  166                       if (nestedBlock != null) {
  167                           env.visit(nestedBlock);
  168                       }
  169                       index++;
  170                   }
  171               }
  172               else if (list instanceof TemplateSequenceModel) {
  173                   TemplateSequenceModel tsm = (TemplateSequenceModel) list;
  174                   int size = tsm.size();
  175                   for (index =0; index <size; index++) {
  176                       loopVar = tsm.get(index);
  177                       hasNext = (size > index +1);
  178                       if (nestedBlock != null) {
  179                           env.visit(nestedBlock);
  180                       }
  181                   }
  182               }
  183               else if (env.isClassicCompatible()) {
  184                   loopVar = list;
  185                   if (nestedBlock != null) {
  186                       env.visit(nestedBlock);
  187                   }
  188               }
  189               else {
  190                   throw invalidTypeException(list, listExpression, env, "collection or sequence");
  191               }
  192           }
  193   
  194           public TemplateModel getLocalVariable(String name) {
  195               if (name.startsWith(indexName)) {
  196                   switch(name.length() - indexName.length()) {
  197                       case 0: 
  198                           return loopVar;
  199                       case 6: 
  200                           if(name.endsWith("_index")) {
  201                               return new SimpleNumber(index);
  202                           }
  203                           break;
  204                       case 9: 
  205                           if(name.endsWith("_has_next")) {
  206                               return hasNext ? TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE;
  207                           }
  208                           break;
  209                   }
  210               }
  211               return null;
  212           }
  213           
  214           public Collection getLocalVariableNames() {
  215               if(variableNames == null) {
  216                   variableNames = new ArrayList(3);
  217                   variableNames.add(indexName);
  218                   variableNames.add(indexName + "_index");
  219                   variableNames.add(indexName + "_has_next");
  220               }
  221               return variableNames;
  222           }
  223       }
  224   }

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