/*
* Copyright (c) 2003 The Visigoth Software Society. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowledgement:
* "This product includes software developed by the
* Visigoth Software Society (http://www.visigoths.org/)."
* Alternately, this acknowledgement may appear in the software itself,
* if and wherever such third-party acknowledgements normally appear.
*
* 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the
* project contributors may be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact [email protected].
*
* 5. Products derived from this software may not be called "FreeMarker" or "Visigoth"
* nor may "FreeMarker" or "Visigoth" appear in their names
* without prior written permission of the Visigoth Software Society.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Visigoth Software Society. For more
* information on the Visigoth Software Society, please see
* http://www.visigoths.org/
*/
package freemarker.core;
import freemarker.template.*;
import java.io.UnsupportedEncodingException;
import java.text.DateFormat;
import java.text.NumberFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import freemarker.template.utility.ClassUtil;
import freemarker.template.utility.StringUtil;
import freemarker.core.NodeBuiltins.*;
import freemarker.core.NumericalBuiltins.*;
import freemarker.core.SequenceBuiltins.*;
import freemarker.core.StringBuiltins.*;
/**
* The ? operator used to get the
* functionality of built-in unary operators
* @author <a href="mailto:[email protected]">Jonathan Revusky</a>
*/
abstract class BuiltIn extends Expression implements Cloneable {
Expression target;
String key;
static final HashMap builtins = new HashMap();
static {
// These are the only ones we have now.
// We throw a parse exception if it's not one of these.
builtins.put("ancestors", new ancestorsBI());
builtins.put("byte", new byteBI());
builtins.put("c", new cBI());
builtins.put("cap_first", new cap_firstBI());
builtins.put("capitalize", new capitalizeBI());
builtins.put("ceiling", new ceilingBI());
builtins.put("children", new childrenBI());
builtins.put("chop_linebreak", new chop_linebreakBI());
builtins.put("contains", new containsBI());
builtins.put("date", new dateBI(TemplateDateModel.DATE));
builtins.put("datetime", new dateBI(TemplateDateModel.DATETIME));
builtins.put("default", new defaultBI());
builtins.put("double", new doubleBI());
builtins.put("ends_with", new ends_withBI());
builtins.put("eval", new evalBI());
builtins.put("exists", new existsBI());
builtins.put("first", new firstBI());
builtins.put("float", new floatBI());
builtins.put("floor", new floorBI());
builtins.put("chunk", new chunkBI());
builtins.put("has_content", new has_contentBI());
builtins.put("html", new htmlBI());
builtins.put("if_exists", new if_existsBI());
builtins.put("index_of", new index_ofBI());
builtins.put("int", new intBI());
builtins.put("interpret", new Interpret());
builtins.put("is_boolean", new is_booleanBI());
builtins.put("is_collection", new is_collectionBI());
builtins.put("is_date", new is_dateBI());
builtins.put("is_directive", new is_directiveBI());
builtins.put("is_enumerable", new is_enumerableBI());
builtins.put("is_hash_ex", new is_hash_exBI());
builtins.put("is_hash", new is_hashBI());
builtins.put("is_indexable", new is_indexableBI());
builtins.put("is_macro", new is_macroBI());
builtins.put("is_method", new is_methodBI());
builtins.put("is_node", new is_nodeBI());
builtins.put("is_number", new is_numberBI());
builtins.put("is_sequence", new is_sequenceBI());
builtins.put("is_string", new is_stringBI());
builtins.put("is_transform", new is_transformBI());
builtins.put("j_string", new j_stringBI());
builtins.put("js_string", new js_stringBI());
builtins.put("keys", new keysBI());
builtins.put("last_index_of", new last_index_ofBI());
builtins.put("last", new lastBI());
builtins.put("left_pad", new left_padBI());
builtins.put("length", new lengthBI());
builtins.put("long", new longBI());
builtins.put("lower_case", new lower_caseBI());
builtins.put("namespace", new namespaceBI());
builtins.put("new", new NewBI());
builtins.put("node_name", new node_nameBI());
builtins.put("node_namespace", new node_namespaceBI());
builtins.put("node_type", new node_typeBI());
builtins.put("number", new numberBI());
builtins.put("parent", new parentBI());
builtins.put("replace", new replaceBI());
builtins.put("reverse", new reverseBI());
builtins.put("right_pad", new right_padBI());
builtins.put("root", new rootBI());
builtins.put("round", new roundBI());
builtins.put("rtf", new rtfBI());
builtins.put("seq_contains", new seq_containsBI());
builtins.put("seq_index_of", new seq_index_ofBI(1));
builtins.put("seq_last_index_of", new seq_index_ofBI(-1));
builtins.put("short", new shortBI());
builtins.put("size", new sizeBI());
builtins.put("sort_by", new sort_byBI());
builtins.put("sort", new sortBI());
builtins.put("split", new splitBI());
builtins.put("starts_with", new starts_withBI());
builtins.put("string", new stringBI());
builtins.put("substring", new substringBI());
builtins.put("time", new dateBI(TemplateDateModel.TIME));
builtins.put("trim", new trimBI());
builtins.put("uncap_first", new uncap_firstBI());
builtins.put("upper_case", new upper_caseBI());
builtins.put("url", new urlBI());
builtins.put("values", new valuesBI());
builtins.put("web_safe", builtins.get("html")); // deprecated; use ?html instead
builtins.put("word_list", new word_listBI());
builtins.put("xhtml", new xhtmlBI());
builtins.put("xml", new xmlBI());
try {
Class.forName("java.util.regex.Pattern");
builtins.put("matches", instantiate("freemarker.core.RegexBuiltins$matchesBI"));
builtins.put("groups", instantiate("freemarker.core.RegexBuiltins$groupsBI"));
builtins.put("replace", instantiate("freemarker.core.RegexBuiltins$replace_reBI"));
builtins.put("split", instantiate("freemarker.core.RegexBuiltins$split_reBI"));
} catch (Exception e) {}
}
private static Object instantiate(String className) throws Exception
{
return ClassUtil.forName(className).newInstance();
}
static BuiltIn newBuiltIn(Expression target, String key, Token tok, String templateName) throws ParseException {
BuiltIn bi = (BuiltIn) builtins.get(key);
if (bi == null) {
String locationInfo = "Error on line " + tok.beginLine + ", column " + tok.beginColumn + ", in template " + templateName + "\n";
StringBuffer buf = new StringBuffer("Found " + key + ", expecting one of: ");
for (Iterator it= builtins.keySet().iterator(); it.hasNext();) {
if (it.hasNext()) {
buf.append(" ");
} else {
buf.append( " or ");
}
buf.append(it.next());
if (it.hasNext()) {
buf.append(", ");
}
}
throw new ParseException(locationInfo + buf, target);
}
try {
bi = (BuiltIn) bi.clone();
}
catch (CloneNotSupportedException e) {
throw new InternalError();
}
bi.target = target;
bi.key = key;
return bi;
}
public String getCanonicalForm() {
return target.getCanonicalForm() + "?" + key;
}
boolean isLiteral() {
return false; // be on the safe side.
}
Expression _deepClone(String name, Expression subst) {
try {
BuiltIn clone = (BuiltIn)clone();
clone.target = target.deepClone(name, subst);
return clone;
}
catch (CloneNotSupportedException e) {
throw new InternalError();
}
}
static class lengthBI extends BuiltIn {
TemplateModel _getAsTemplateModel(Environment env)
throws TemplateException
{
return new SimpleNumber(target.getStringValue(env).length());
}
}
static class dateBI extends BuiltIn {
private final int dateType;
dateBI(int dateType) {
this.dateType = dateType;
}
TemplateModel _getAsTemplateModel(Environment env)
throws TemplateException
{
TemplateModel model = target.getAsTemplateModel(env);
if (model instanceof TemplateDateModel) {
TemplateDateModel dmodel = (TemplateDateModel)model;
int dtype = dmodel.getDateType();
// Any date model can be coerced into its own type
if(dateType == dtype) {
return model;
}
// unknown and datetime can be coerced into any date type
if(dtype == TemplateDateModel.UNKNOWN || dtype == TemplateDateModel.DATETIME) {
return new SimpleDate(dmodel.getAsDate(), dateType);
}
throw new TemplateException(
"Cannot convert " + TemplateDateModel.TYPE_NAMES.get(dtype)
+ " into " + TemplateDateModel.TYPE_NAMES.get(dateType), env);
}
// Otherwise, interpret as a string and attempt
// to parse it into a date.
String s = target.getStringValue(env);
return new DateParser(s, env);
}
private class DateParser
implements
TemplateDateModel,
TemplateMethodModel,
TemplateHashModel
{
private final String text;
private final Environment env;
private final DateFormat defaultFormat;
private Date cachedValue;
DateParser(String text, Environment env)
throws
TemplateModelException
{
this.text = text;
this.env = env;
this.defaultFormat = env.getDateFormatObject(dateType);
}
public Date getAsDate() throws TemplateModelException {
if(cachedValue == null) {
cachedValue = parse(defaultFormat);
}
return cachedValue;
}
public int getDateType() {
return dateType;
}
public TemplateModel get(String pattern) throws TemplateModelException {
return new SimpleDate(
parse(env.getDateFormatObject(dateType, pattern)),
dateType);
}
public Object exec(List arguments)
throws TemplateModelException {
if (arguments.size() != 1) {
throw new TemplateModelException(
"string?" + key + "(...) requires exactly 1 argument.");
}
return get((String) arguments.get(0));
}
public boolean isEmpty()
{
return false;
}
private Date parse(DateFormat df)
throws
TemplateModelException
{
try {
return df.parse(text);
}
catch(java.text.ParseException e) {
String mess = "Error: " + getStartLocation()
+ "\nExpecting a date here, found: " + text;
throw new TemplateModelException(mess);
}
}
}
}
static class stringBI extends BuiltIn {
TemplateModel _getAsTemplateModel(Environment env)
throws TemplateException
{
TemplateModel model = target.getAsTemplateModel(env);
if (model instanceof TemplateNumberModel) {
return new NumberFormatter(EvaluationUtil.getNumber((TemplateNumberModel)model, target, env), env);
}
if (model instanceof TemplateDateModel) {
TemplateDateModel dm = (TemplateDateModel)model;
int dateType = dm.getDateType();
return new DateFormatter(EvaluationUtil.getDate(dm, target, env), dateType, env);
}
if (model instanceof SimpleScalar) {
return model;
}
if (model instanceof TemplateBooleanModel) {
return new BooleanFormatter((TemplateBooleanModel) model, env);
}
if (model instanceof TemplateScalarModel) {
return new SimpleScalar(((TemplateScalarModel) model).getAsString());
}
throw invalidTypeException(model, target, env, "number, date, or string");
}
private static class NumberFormatter
implements
TemplateScalarModel,
TemplateHashModel,
TemplateMethodModel
{
private final Number number;
private final Environment env;
private final NumberFormat defaultFormat;
private String cachedValue;
NumberFormatter(Number number, Environment env)
{
this.number = number;
this.env = env;
defaultFormat = env.getNumberFormatObject(env.getNumberFormat());
}
public String getAsString()
{
if(cachedValue == null) {
cachedValue = defaultFormat.format(number);
}
return cachedValue;
}
public TemplateModel get(String key)
{
return new SimpleScalar(env.getNumberFormatObject(key).format(number));
}
public Object exec(List arguments)
throws TemplateModelException {
if (arguments.size() != 1) {
throw new TemplateModelException(
"number?string(...) requires exactly 1 argument.");
}
return get((String) arguments.get(0));
}
public boolean isEmpty()
{
return false;
}
}
private static class DateFormatter
implements
TemplateScalarModel,
TemplateHashModel,
TemplateMethodModel
{
private final Date date;
private final int dateType;
private final Environment env;
private final DateFormat defaultFormat;
private String cachedValue;
DateFormatter(Date date, int dateType, Environment env)
throws
TemplateModelException
{
this.date = date;
this.dateType = dateType;
this.env = env;
defaultFormat = env.getDateFormatObject(dateType);
}
public String getAsString()
throws
TemplateModelException
{
if(dateType == TemplateDateModel.UNKNOWN) {
throw new TemplateModelException("Can't convert the date to string, because it is not known which parts of the date variable are in use. Use ?date, ?time or ?datetime built-in, or ?string.<format> or ?string(format) built-in with this date.");
}
if(cachedValue == null) {
cachedValue = defaultFormat.format(date);
}
return cachedValue;
}
public TemplateModel get(String key)
throws
TemplateModelException
{
return new SimpleScalar(env.getDateFormatObject(dateType, key).format(date));
}
public Object exec(List arguments)
throws TemplateModelException {
if (arguments.size() != 1) {
throw new TemplateModelException(
"date?string(...) requires exactly 1 argument.");
}
return get((String) arguments.get(0));
}
public boolean isEmpty()
{
return false;
}
}
private static class BooleanFormatter
implements
TemplateScalarModel,
TemplateMethodModel
{
private final TemplateBooleanModel bool;
private final Environment env;
BooleanFormatter(TemplateBooleanModel bool, Environment env) {
this.bool = bool;
this.env = env;
}
public String getAsString() throws TemplateModelException {
if (bool instanceof TemplateScalarModel) {
return ((TemplateScalarModel) bool).getAsString();
} else {
return env.getBooleanFormat(bool.getAsBoolean());
}
}
public Object exec(List arguments)
throws TemplateModelException {
if (arguments.size() != 2) {
throw new TemplateModelException(
"boolean?string(...) requires exactly "
+ "2 arguments.");
}
return new SimpleScalar(
(String) arguments.get(bool.getAsBoolean() ? 0 : 1));
}
}
}
static class trimBI extends StringBuiltIn {
TemplateModel calculateResult(String s, Environment env) {
return new SimpleScalar(s.trim());
}
}
static class htmlBI extends StringBuiltIn {
TemplateModel calculateResult(String s, Environment env) {
return new SimpleScalar(StringUtil.HTMLEnc(s));
}
}
static class xmlBI extends StringBuiltIn {
TemplateModel calculateResult(String s, Environment env) {
return new SimpleScalar(StringUtil.XMLEnc(s));
}
}
static class xhtmlBI extends StringBuiltIn {
TemplateModel calculateResult(String s, Environment env) {
return new SimpleScalar(StringUtil.XHTMLEnc(s));
}
}
static class rtfBI extends StringBuiltIn {
TemplateModel calculateResult(String s, Environment env) {
return new SimpleScalar(StringUtil.RTFEnc(s));
}
}
static class urlBI extends StringBuiltIn {
TemplateModel calculateResult(String s, Environment env) {
return new urlBIResult(s, env);
}
static class urlBIResult implements
TemplateScalarModel, TemplateMethodModel {
private final String target;
private final Environment env;
private String cachedResult;
private urlBIResult(String target, Environment env) {
this.target = target;
this.env = env;
}
public String getAsString() throws TemplateModelException {
if (cachedResult == null) {
String cs = env.getEffectiveURLEscapingCharset();
if (cs == null) {
throw new TemplateModelException(
"To do URL encoding, the framework that encloses "
+ "FreeMarker must specify the output encoding "
+ "or the URL encoding charset, so ask the "
+ "programmers to fix it. Or, as a last chance, "
+ "you can set the url_encoding_charset setting in "
+ "the template, e.g. "
+ "<#setting url_escaping_charset='ISO-8859-1'>, or "
+ "give the charset explicitly to the buit-in, e.g. "
+ "foo?url('ISO-8859-1').");
}
try {
cachedResult = StringUtil.URLEnc(target, cs);
} catch (UnsupportedEncodingException e) {
throw new TemplateModelException(
"Failed to execute URL encoding.", e);
}
}
return cachedResult;
}
public Object exec(List args) throws TemplateModelException {
if (args.size() != 1) {
throw new TemplateModelException("The \"url\" built-in "
+ "needs exactly 1 parameter, the charset.");
}
try {
return new SimpleScalar(
StringUtil.URLEnc(target, (String) args.get(0)));
} catch (UnsupportedEncodingException e) {
throw new TemplateModelException(
"Failed to execute URL encoding.", e);
}
}
}
}
static class keysBI extends BuiltIn {
TemplateModel _getAsTemplateModel(Environment env)
throws TemplateException
{
TemplateModel model = target.getAsTemplateModel(env);
if (model instanceof TemplateHashModelEx) {
TemplateCollectionModel keys = ((TemplateHashModelEx) model).keys();
assertNonNull(keys, this, env);
if (!(keys instanceof TemplateSequenceModel))
keys = new CollectionAndSequence(keys);
return keys;
}
throw invalidTypeException(model, target, env, "extended hash");
}
}
static class valuesBI extends BuiltIn {
TemplateModel _getAsTemplateModel(Environment env)
throws TemplateException
{
TemplateModel model = target.getAsTemplateModel(env);
if (model instanceof TemplateHashModelEx) {
TemplateCollectionModel values = ((TemplateHashModelEx) model).values();
assertNonNull(values, this, env);
if (!(values instanceof TemplateSequenceModel))
values = new CollectionAndSequence(values);
return values;
}
throw invalidTypeException(model, target, env, "extended hash");
}
}
static class sizeBI extends BuiltIn {
TemplateModel _getAsTemplateModel(Environment env)
throws TemplateException
{
TemplateModel model = target.getAsTemplateModel(env);
if (model instanceof TemplateSequenceModel) {
int size = ((TemplateSequenceModel) model).size();
return new SimpleNumber(size);
}
if (model instanceof TemplateHashModelEx) {
int size = ((TemplateHashModelEx) model).size();
return new SimpleNumber(size);
}
throw invalidTypeException(model, target, env, "extended-hash or sequence");
}
}
static class existsBI extends BuiltIn {
TemplateModel _getAsTemplateModel(Environment env)
throws TemplateException
{
try {
TemplateModel model = target.getAsTemplateModel(env);
return model==null ? TemplateBooleanModel.FALSE : TemplateBooleanModel.TRUE;
} catch (InvalidReferenceException ire) {
if (target instanceof ParentheticalExpression) {
return TemplateBooleanModel.FALSE;
}
throw ire;
}
}
boolean isTrue(Environment env) throws TemplateException {
return _getAsTemplateModel(env) == TemplateBooleanModel.TRUE;
}
}
static class has_contentBI extends BuiltIn {
TemplateModel _getAsTemplateModel(Environment env)
throws TemplateException
{
try {
TemplateModel model = target.getAsTemplateModel(env);
return Expression.isEmpty(model) ?
TemplateBooleanModel.FALSE : TemplateBooleanModel.TRUE;
} catch (InvalidReferenceException ire) {
if (target instanceof ParentheticalExpression) {
return TemplateBooleanModel.FALSE;
}
throw ire;
}
}
boolean isTrue(Environment env) throws TemplateException {
return _getAsTemplateModel(env) == TemplateBooleanModel.TRUE;
}
}
static class if_existsBI extends BuiltIn {
TemplateModel _getAsTemplateModel(Environment env)
throws TemplateException
{
try {
TemplateModel model = target.getAsTemplateModel(env);
return model == null ? TemplateModel.NOTHING : model;
} catch (InvalidReferenceException ire) {
if (target instanceof ParentheticalExpression) {
return TemplateModel.NOTHING;
}
throw ire;
}
}
}
static class is_stringBI extends BuiltIn {
TemplateModel _getAsTemplateModel(Environment env) throws TemplateException {
TemplateModel tm = target.getAsTemplateModel(env);
assertNonNull(tm, target, env);
return (tm instanceof TemplateScalarModel) ?
TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE;
}
}
static class is_numberBI extends BuiltIn {
TemplateModel _getAsTemplateModel(Environment env) throws TemplateException {
TemplateModel tm = target.getAsTemplateModel(env);
assertNonNull(tm, target, env);
return (tm instanceof TemplateNumberModel) ?
TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE;
}
}
static class is_nodeBI extends BuiltIn {
TemplateModel _getAsTemplateModel(Environment env) throws TemplateException {
TemplateModel tm = target.getAsTemplateModel(env);
assertNonNull(tm, target, env);
return (tm instanceof TemplateNodeModel) ?
TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE;
}
}
static class is_booleanBI extends BuiltIn {
TemplateModel _getAsTemplateModel(Environment env) throws TemplateException {
TemplateModel tm = target.getAsTemplateModel(env);
assertNonNull(tm, target, env);
return (tm instanceof TemplateBooleanModel) ?
TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE;
}
}
static class is_dateBI extends BuiltIn {
TemplateModel _getAsTemplateModel(Environment env) throws TemplateException {
TemplateModel tm = target.getAsTemplateModel(env);
assertNonNull(tm, target, env);
return (tm instanceof TemplateDateModel) ?
TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE;
}
}
static class is_methodBI extends BuiltIn {
TemplateModel _getAsTemplateModel(Environment env) throws TemplateException {
TemplateModel tm = target.getAsTemplateModel(env);
assertNonNull(tm, target, env);
return (tm instanceof TemplateMethodModel) ?
TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE;
}
}
static class is_macroBI extends BuiltIn {
TemplateModel _getAsTemplateModel(Environment env) throws TemplateException {
TemplateModel tm = target.getAsTemplateModel(env);
assertNonNull(tm, target, env);
return (tm instanceof Macro) ?
TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE;
}
}
static class is_transformBI extends BuiltIn {
TemplateModel _getAsTemplateModel(Environment env) throws TemplateException {
TemplateModel tm = target.getAsTemplateModel(env);
assertNonNull(tm, target, env);
return (tm instanceof TemplateTransformModel) ?
TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE;
}
}
static class is_hashBI extends BuiltIn {
TemplateModel _getAsTemplateModel(Environment env) throws TemplateException {
TemplateModel tm = target.getAsTemplateModel(env);
assertNonNull(tm, target, env);
return (tm instanceof TemplateHashModel) ? TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE;
}
}
static class is_hash_exBI extends BuiltIn {
TemplateModel _getAsTemplateModel(Environment env) throws TemplateException {
TemplateModel tm = target.getAsTemplateModel(env);
assertNonNull(tm, target, env);
return (tm instanceof TemplateHashModelEx) ? TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE;
}
}
static class is_sequenceBI extends BuiltIn {
TemplateModel _getAsTemplateModel(Environment env) throws TemplateException {
TemplateModel tm = target.getAsTemplateModel(env);
assertNonNull(tm, target, env);
return (tm instanceof TemplateSequenceModel) ? TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE;
}
}
static class is_collectionBI extends BuiltIn {
TemplateModel _getAsTemplateModel(Environment env) throws TemplateException {
TemplateModel tm = target.getAsTemplateModel(env);
assertNonNull(tm, target, env);
return (tm instanceof TemplateCollectionModel) ? TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE;
}
}
static class is_indexableBI extends BuiltIn {
TemplateModel _getAsTemplateModel(Environment env) throws TemplateException {
TemplateModel tm = target.getAsTemplateModel(env);
assertNonNull(tm, target, env);
return (tm instanceof TemplateSequenceModel) ? TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE;
}
}
static class is_enumerableBI extends BuiltIn {
TemplateModel _getAsTemplateModel(Environment env) throws TemplateException {
TemplateModel tm = target.getAsTemplateModel(env);
assertNonNull(tm, target, env);
return (tm instanceof TemplateSequenceModel || tm instanceof TemplateCollectionModel) ?
TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE;
}
}
static class is_directiveBI extends BuiltIn {
TemplateModel _getAsTemplateModel(Environment env) throws TemplateException {
TemplateModel tm = target.getAsTemplateModel(env);
assertNonNull(tm, target, env);
return (tm instanceof TemplateTransformModel || tm instanceof Macro || tm instanceof TemplateDirectiveModel) ?
TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE;
}
}
static class namespaceBI extends BuiltIn {
TemplateModel _getAsTemplateModel(Environment env) throws TemplateException {
TemplateModel tm = target.getAsTemplateModel(env);
if (!(tm instanceof Macro)) {
invalidTypeException(tm, target, env, "macro");
}
return env.getMacroNamespace((Macro) tm);
}
}
static class defaultBI extends BuiltIn {
TemplateModel _getAsTemplateModel(final Environment env)
throws TemplateException
{
try {
TemplateModel model = target.getAsTemplateModel(env);
return
model == null
? FIRST_NON_NULL_METHOD
: new ConstantMethod(model);
} catch (InvalidReferenceException ire) {
if (target instanceof ParentheticalExpression) {
return FIRST_NON_NULL_METHOD;
}
throw ire;
}
}
private static class ConstantMethod implements TemplateMethodModelEx
{
private final TemplateModel constant;
ConstantMethod(TemplateModel constant) {
this.constant = constant;
}
public Object exec(List args) {
return constant;
}
}
/**
* A method that goes through the arguments one by one and returns
* the first one that is non-null. If all args are null, returns null.
*/
private static final TemplateMethodModelEx FIRST_NON_NULL_METHOD =
new TemplateMethodModelEx() {
public Object exec(List args) throws TemplateModelException {
if(args.isEmpty()) {
throw new TemplateModelException(
"?default(arg) expects at least one argument.");
}
TemplateModel result = null;
for (int i = 0; i< args.size(); i++ ) {
result = (TemplateModel) args.get(i);
if (result != null) {
break;
}
}
return result;
}
};
}
static class containsBI extends BuiltIn {
TemplateModel _getAsTemplateModel(Environment env)
throws TemplateException {
TemplateModel model = target.getAsTemplateModel(env);
if (model instanceof TemplateScalarModel) {
return new BIMethod(((TemplateScalarModel) model).getAsString());
}
throw invalidTypeException(model, target, env, "string");
}
private static class BIMethod implements TemplateMethodModelEx {
private String s;
private BIMethod(String s) {
this.s = s;
}
public Object exec(List args) throws TemplateModelException {
Object obj;
String sub;
int ln = args.size();
if (ln != 1) {
throw new TemplateModelException(
"?contains(...) expects one argument.");
}
obj = args.get(0);
if (!(obj instanceof TemplateScalarModel)) {
throw new TemplateModelException(
"?contains(...) expects a string as "
+ "its first argument.");
}
sub = ((TemplateScalarModel) obj).getAsString();
return
(s.indexOf(sub) != -1) ?
TemplateBooleanModel.TRUE :
TemplateBooleanModel.FALSE;
}
}
}
static class index_ofBI extends BuiltIn {
TemplateModel _getAsTemplateModel(Environment env)
throws TemplateException {
TemplateModel model = target.getAsTemplateModel(env);
if (model instanceof TemplateScalarModel) {
return new BIMethod(((TemplateScalarModel) model).getAsString());
}
throw invalidTypeException(model, target, env, "string");
}
private static class BIMethod implements TemplateMethodModelEx {
private String s;
private BIMethod(String s) {
this.s = s;
}
public Object exec(List args) throws TemplateModelException {
Object obj;
String sub;
int fidx;
int ln = args.size();
if (ln == 0) {
throw new TemplateModelException(
"?index_of(...) expects at least one argument.");
}
if (ln > 2) {
throw new TemplateModelException(
"?index_of(...) expects at most two arguments.");
}
obj = args.get(0);
if (!(obj instanceof TemplateScalarModel)) {
throw new TemplateModelException(
"?index_of(...) expects a string as "
+ "its first argument.");
}
sub = ((TemplateScalarModel) obj).getAsString();
if (ln > 1) {
obj = args.get(1);
if (!(obj instanceof TemplateNumberModel)) {
throw new TemplateModelException(
"?index_of(...) expects a number as "
+ "its second argument.");
}
fidx = ((TemplateNumberModel) obj).getAsNumber().intValue();
} else {
fidx = 0;
}
return new SimpleNumber(s.indexOf(sub, fidx));
}
}
}
static class last_index_ofBI extends BuiltIn {
TemplateModel _getAsTemplateModel(Environment env)
throws TemplateException {
TemplateModel model = target.getAsTemplateModel(env);
if (model instanceof TemplateScalarModel) {
return new BIMethod(((TemplateScalarModel) model).getAsString());
}
throw invalidTypeException(model, target, env, "string");
}
private static class BIMethod implements TemplateMethodModelEx {
private String s;
private BIMethod(String s) {
this.s = s;
}
public Object exec(List args) throws TemplateModelException {
Object obj;
String sub;
int ln = args.size();
if (ln == 0) {
throw new TemplateModelException(
"?last_index_of(...) expects at least one argument.");
}
if (ln > 2) {
throw new TemplateModelException(
"?last_index_of(...) expects at most two arguments.");
}
obj = args.get(0);
if (!(obj instanceof TemplateScalarModel)) {
throw new TemplateModelException(
"?last_index_of(...) expects a string as "
+ "its first argument.");
}
sub = ((TemplateScalarModel) obj).getAsString();
if (ln > 1) {
obj = args.get(1);
if (!(obj instanceof TemplateNumberModel)) {
throw new TemplateModelException(
"?last_index_of(...) expects a number as "
+ "its second argument.");
}
int fidx = ((TemplateNumberModel) obj).getAsNumber().intValue();
return new SimpleNumber(s.lastIndexOf(sub, fidx));
} else {
return new SimpleNumber(s.lastIndexOf(sub));
}
}
}
}
static class starts_withBI extends BuiltIn {
TemplateModel _getAsTemplateModel(Environment env)
throws TemplateException {
TemplateModel model = target.getAsTemplateModel(env);
if (model instanceof TemplateScalarModel) {
return new BIMethod(((TemplateScalarModel) model).getAsString());
}
throw invalidTypeException(model, target, env, "string");
}
private static class BIMethod implements TemplateMethodModelEx {
private String s;
private BIMethod(String s) {
this.s = s;
}
public Object exec(List args) throws TemplateModelException {
String sub;
if (args.size() != 1) {
throw new TemplateModelException(
"?starts_with(...) expects exactly 1 argument.");
}
Object obj = args.get(0);
if (!(obj instanceof TemplateScalarModel)) {
throw new TemplateModelException(
"?starts_with(...) expects a string argument");
}
sub = ((TemplateScalarModel) obj).getAsString();
return s.startsWith(sub) ?
TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE;
}
}
}
static class ends_withBI extends BuiltIn {
TemplateModel _getAsTemplateModel(Environment env)
throws TemplateException {
TemplateModel model = target.getAsTemplateModel(env);
if (model instanceof TemplateScalarModel) {
return new BIMethod(((TemplateScalarModel) model).getAsString());
}
throw invalidTypeException(model, target, env, "string");
}
private static class BIMethod implements TemplateMethodModelEx {
private String s;
private BIMethod(String s) {
this.s = s;
}
public Object exec(List args) throws TemplateModelException {
String sub;
if (args.size() != 1) {
throw new TemplateModelException(
"?ends_with(...) expects exactly 1 argument.");
}
Object obj = args.get(0);
if (!(obj instanceof TemplateScalarModel)) {
throw new TemplateModelException(
"?ends_with(...) expects a string argument");
}
sub = ((TemplateScalarModel) obj).getAsString();
return s.endsWith(sub) ?
TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE;
}
}
}
static class replaceBI extends BuiltIn {
TemplateModel _getAsTemplateModel(Environment env)
throws TemplateException {
TemplateModel model = target.getAsTemplateModel(env);
if (model instanceof TemplateScalarModel) {
return new BIMethod(((TemplateScalarModel) model).getAsString());
}
throw invalidTypeException(model, target, env, "string");
}
private static class BIMethod implements TemplateMethodModel {
private String s;
private BIMethod(String s) {
this.s = s;
}
public Object exec(List args) throws TemplateModelException {
int numArgs = args.size();
if (numArgs < 2 || numArgs > 3) {
throw new TemplateModelException(
"?replace(...) needs 2 or 3 arguments.");
}
String first = (String) args.get(0);
String second = (String) args.get(1);
String flags = numArgs >2 ? (String) args.get(2) : "";
boolean caseInsensitive = flags.indexOf('i') >=0;
boolean firstOnly = flags.indexOf('f') >=0;
if (flags.indexOf('r') >=0) {
throw new TemplateModelException("The regular expression classes are not available.");
}
return new SimpleScalar(StringUtil.replace(
s, first, second, caseInsensitive, firstOnly));
}
}
}
static class splitBI extends BuiltIn {
TemplateModel _getAsTemplateModel(Environment env)
throws TemplateException {
TemplateModel model = target.getAsTemplateModel(env);
if (model instanceof TemplateScalarModel) {
return new BIMethod(((TemplateScalarModel) model).getAsString());
}
throw invalidTypeException(model, target, env, "string");
}
private static class BIMethod implements TemplateMethodModel {
private String s;
private BIMethod(String s) {
this.s = s;
}
public Object exec(List args) throws TemplateModelException {
int numArgs = args.size();
if (numArgs != 1 && numArgs !=2) {
throw new TemplateModelException(
"?split(...) expects 1 or 2 arguments.");
}
String splitString = (String) args.get(0);
String flags = numArgs ==2 ? (String) args.get(1) : "";
boolean caseInsensitive = flags.indexOf('i') >=0;
if (flags.indexOf('r') >=0) {
throw new TemplateModelException("regular expression classes not available");
}
return new StringArraySequence(StringUtil.split(
s, splitString, caseInsensitive));
}
}
}
static class left_padBI extends BuiltIn {
TemplateModel _getAsTemplateModel(Environment env)
throws TemplateException {
TemplateModel model = target.getAsTemplateModel(env);
if (model instanceof TemplateScalarModel) {
return new BIMethod(((TemplateScalarModel) model).getAsString());
}
throw invalidTypeException(model, target, env, "string");
}
private static class BIMethod implements TemplateMethodModelEx {
private String s;
private BIMethod(String s) {
this.s = s;
}
public Object exec(List args) throws TemplateModelException {
Object obj;
int ln = args.size();
if (ln == 0) {
throw new TemplateModelException(
"?left_pad(...) expects at least 1 argument.");
}
if (ln > 2) {
throw new TemplateModelException(
"?left_pad(...) expects at most 2 arguments.");
}
obj = args.get(0);
if (!(obj instanceof TemplateNumberModel)) {
throw new TemplateModelException(
"?left_pad(...) expects a number as "
+ "its 1st argument.");
}
int width = ((TemplateNumberModel) obj).getAsNumber().intValue();
if (ln > 1) {
obj = args.get(1);
if (!(obj instanceof TemplateScalarModel)) {
throw new TemplateModelException(
"?left_pad(...) expects a string as "
+ "its 2nd argument.");
}
String filling = ((TemplateScalarModel) obj).getAsString();
try {
return new SimpleScalar(StringUtil.leftPad(s, width, filling));
} catch (IllegalArgumentException e) {
if (filling.length() == 0) {
throw new TemplateModelException(
"The 2nd argument of ?left_pad(...) "
+ "can't be a 0 length string.");
} else {
throw new TemplateModelException(
"Error while executing the ?left_pad(...) "
+ "built-in.", e);
}
}
} else {
return new SimpleScalar(StringUtil.leftPad(s, width));
}
}
}
}
static class right_padBI extends BuiltIn {
TemplateModel _getAsTemplateModel(Environment env)
throws TemplateException {
TemplateModel model = target.getAsTemplateModel(env);
if (model instanceof TemplateScalarModel) {
return new BIMethod(((TemplateScalarModel) model).getAsString());
}
throw invalidTypeException(model, target, env, "string");
}
private static class BIMethod implements TemplateMethodModelEx {
private String s;
private BIMethod(String s) {
this.s = s;
}
public Object exec(List args) throws TemplateModelException {
Object obj;
int ln = args.size();
if (ln == 0) {
throw new TemplateModelException(
"?right_pad(...) expects at least 1 argument.");
}
if (ln > 2) {
throw new TemplateModelException(
"?right_pad(...) expects at most 2 arguments.");
}
obj = args.get(0);
if (!(obj instanceof TemplateNumberModel)) {
throw new TemplateModelException(
"?right_pad(...) expects a number as "
+ "its 1st argument.");
}
int width = ((TemplateNumberModel) obj).getAsNumber().intValue();
if (ln > 1) {
obj = args.get(1);
if (!(obj instanceof TemplateScalarModel)) {
throw new TemplateModelException(
"?right_pad(...) expects a string as "
+ "its 2nd argument.");
}
String filling = ((TemplateScalarModel) obj).getAsString();
try {
return new SimpleScalar(StringUtil.rightPad(s, width, filling));
} catch (IllegalArgumentException e) {
if (filling.length() == 0) {
throw new TemplateModelException(
"The 2nd argument of ?right_pad(...) "
+ "can't be a 0 length string.");
} else {
throw new TemplateModelException(
"Error while executing the ?right_pad(...) "
+ "built-in.", e);
}
}
} else {
return new SimpleScalar(StringUtil.rightPad(s, width));
}
}
}
}
}
|