/* * FreeMarker: a tool that allows Java programs to generate HTML * output using templates. * Copyright (C) 1998-2004 Benjamin Geer * Email: beroul@users.sourceforge.net * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library 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 freemarker.template.expression; import java.io.IOException; import java.io.InvalidObjectException; import java.io.ObjectInputStream; import java.io.ObjectStreamException; import java.io.Serializable; import freemarker.template.FastListRange; import freemarker.template.TemplateException; import freemarker.template.TemplateModel; import freemarker.template.TemplateWriteableHashModel; /** * An expression that represents a indexModel of list values. The from and to * expressions are held until evaluation time, then a * {@link freemarker.template.FastListRange} is created. A simple * {@link freemarker.template.FastIndexedIterator} is used to iterate over the * values. * * @version $Id: ListRange.java 1123 2005-10-04 10:48:25Z run2000 $ * @since 1.8 */ public final class ListRange implements Expression, Serializable { /** * @serial An expression that evaluates to the start of the list range. */ private final Expression fromRange; /** * @serial An expression that evaluates to the end of the list range. */ private final Expression toRange; /** Serialization UUID for this class. */ private static final long serialVersionUID = 9096757710628448671L; /** * Constructor that takes from and to values in the form of expressions. The * expressions are evaluated at template run time and converted into values * usable by the {@link freemarker.template.FastListRange}. * * @param fromRange * the start of the range, as an expression * @param toRange * the end of the range, as an expression * @throws NullPointerException * fromRange or toRange are null * @throws IllegalArgumentException * the expressions cannot be evaluated as numbers */ public ListRange(Expression fromRange, Expression toRange) { if ((fromRange.getType() & ExpressionUtils.EXPRESSION_TYPE_NUMBER) == 0 || (toRange.getType() & ExpressionUtils.EXPRESSION_TYPE_NUMBER) == 0) { throw new IllegalArgumentException("Range cannot be created from non-numeric arguments"); } this.fromRange = fromRange; this.toRange = toRange; } /** * Retrieve the list range as a template model. * * @param modelRoot * the model from which to evaluate the range of the list * @return a new <code>FastListRange</code> representing the range list * @throws TemplateException * the new range could not be created */ public TemplateModel getAsTemplateModel(TemplateWriteableHashModel modelRoot) throws TemplateException { long fromValue = ExpressionUtils.getAsNumber(fromRange.getAsTemplateModel(modelRoot)); long toValue = ExpressionUtils.getAsNumber(toRange.getAsTemplateModel(modelRoot)); return new FastListRange(fromValue, toValue); } /** * Do we have from and to values? * * @return <code>true</code> if both from and to values are specified, * otherwise <code>false</code> */ public boolean isComplete() { return true; } /** * Determine the type of result that can be calculated by this expression. * This is in the form of an integer constant ored together from values in * the {@link ExpressionUtils} class. */ public int getType() { return ExpressionUtils.EXPRESSION_TYPE_LIST; } /** * Determine whether result calculated by this expression is a constant * value. */ public boolean isConstant() { return false; } /** * For serialization purposes, resolve a deserialized instance to an * instance in the expression cache. */ private Object readResolve() throws ObjectStreamException { return ExpressionCache.cacheExpression(this); } /** * For serialization, read this object normally, then check whether either * fromRange or toRange has been deserialized to null. * * @param stream * the input stream to read serialized objects from */ private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { stream.defaultReadObject(); if ((fromRange == null) || (toRange == null)) { throw new InvalidObjectException("Cannot create a ListRange with null expressions"); } } /** * Returns a string representation of the object. * * @return a <code>String</code> representation of this expression */ public String toString() { StringBuffer buffer = new StringBuffer(); buffer.append("[ "); buffer.append(fromRange); buffer.append(" .. "); buffer.append(toRange); buffer.append(" ]"); return buffer.toString(); } /** * Determines whether this object is equal to the given object. * * @param o * the object to be compared with * @return <code>true</code> if the objects are equal, otherwise * <code>false</code> */ public boolean equals(Object o) { if (this == o) { return true; } if (!(o instanceof ListRange)) { return false; } final ListRange listRange = (ListRange) o; if (!fromRange.equals(listRange.fromRange)) return false; return toRange.equals(listRange.toRange); } /** * Returns the hash code for this operator. * * @return the hash code of this object */ public int hashCode() { int result; result = fromRange.hashCode(); result = 29 * result + toRange.hashCode(); return result; } /** * Resolves the current expression, possibly into a different expression * object. This is loosely equivalent to the serialization protocol's * <code>readResolve</code> method. Situations where this may be used are: * <ul> * <li>Caching frequently-used expression objects</li> * <li>Evaluating constant expressions, and returning a constant reference</li> * </ul> */ public Expression resolveExpression() throws TemplateException { Expression expr = this; // If the from- and to-range are constants, make this expression // a constant. if (fromRange.isConstant() && toRange.isConstant()) { long fromValue = ExpressionUtils.getAsNumber(fromRange.getAsTemplateModel(ExpressionBuilder.emptyModel)); long toValue = ExpressionUtils.getAsNumber(toRange.getAsTemplateModel(ExpressionBuilder.emptyModel)); expr = new Constant(new FastListRange(fromValue, toValue)); } return ExpressionCache.cacheExpression(expr); } }