diff options
Diffstat (limited to 'velocity-engine-core/src/main/java/org/apache/velocity/runtime/directive/Directive.java')
-rw-r--r-- | velocity-engine-core/src/main/java/org/apache/velocity/runtime/directive/Directive.java | 264 |
1 files changed, 264 insertions, 0 deletions
diff --git a/velocity-engine-core/src/main/java/org/apache/velocity/runtime/directive/Directive.java b/velocity-engine-core/src/main/java/org/apache/velocity/runtime/directive/Directive.java new file mode 100644 index 00000000..9d938f78 --- /dev/null +++ b/velocity-engine-core/src/main/java/org/apache/velocity/runtime/directive/Directive.java @@ -0,0 +1,264 @@ +package org.apache.velocity.runtime.directive; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.apache.velocity.Template; +import org.apache.velocity.context.InternalContextAdapter; +import org.apache.velocity.exception.MethodInvocationException; +import org.apache.velocity.exception.ParseErrorException; +import org.apache.velocity.exception.ResourceNotFoundException; +import org.apache.velocity.exception.TemplateInitException; +import org.apache.velocity.runtime.RuntimeServices; +import org.apache.velocity.runtime.parser.ParseException; +import org.apache.velocity.runtime.parser.Token; +import org.apache.velocity.runtime.parser.node.Node; + +import org.slf4j.Logger; + +import java.io.IOException; +import java.io.Writer; +import java.util.ArrayList; + +/** + * Base class for all directives used in Velocity. + * + * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a> + * @author Nathan Bubna + * @version $Id$ + */ +public abstract class Directive implements DirectiveConstants, Cloneable +{ + private int line = 0; + private int column = 0; + private boolean provideScope = false; + private Template template; + + protected Logger log = null; + + /** + * + */ + protected RuntimeServices rsvc = null; + + /** + * Return the name of this directive. + * @return The name of this directive. + */ + public abstract String getName(); + + /** + * Get the directive type BLOCK/LINE. + * @return The directive type BLOCK/LINE. + */ + public abstract int getType(); + + /** + * Allows the template location to be set. + * @param line + * @param column + */ + public void setLocation( int line, int column ) + { + this.line = line; + this.column = column; + } + + /** + * Allows the template location to be set. + * @param line + * @param column + * @param template + */ + public void setLocation(int line, int column, Template template) + { + setLocation(line, column); + this.template = template; + } + + /** + * returns the template in which this directive appears + * @return template + */ + public Template getTemplate() + { + return template; + } + + /** + * for log msg purposes + * @return The current line for log msg purposes. + */ + public int getLine() + { + return line; + } + + /** + * for log msg purposes + * @return The current column for log msg purposes. + */ + public int getColumn() + { + return column; + } + + /** + * @return The template file name this directive was defined in, or null if not + * defined in a file. + */ + public String getTemplateName() + { + return template.getName(); + } + + /** + * @return the name to be used when a scope control is provided for this + * directive. + */ + public String getScopeName() + { + return getName(); + } + + /** + * @return true if there will be a scope control injected into the context + * when rendering this directive. + */ + public boolean isScopeProvided() + { + return provideScope; + } + + /** + * How this directive is to be initialized. + * @param rs + * @param context + * @param node + * @throws TemplateInitException + */ + public void init( RuntimeServices rs, InternalContextAdapter context, + Node node) + throws TemplateInitException + { + rsvc = rs; + log = rsvc.getLog("directive." + getName()); + + provideScope = rsvc.isScopeControlEnabled(getScopeName()); + } + + /** + * The Parser calls this method during template parsing to check the arguments + * types. Be aware that this method is called pre init, so not all data + * is available in this method. The default implementation does not peform any + * checking. We do this so that Custom directives do not trigger any parse + * errors in IDEs. + * @param argtypes type, Array of argument types of each argument to the directive + * for example ParserTreeConstants.JJTWORD + * @param t token of directive + * @param templateName the name of the template this directive is referenced in. + * @throws ParseException + */ + public void checkArgs(ArrayList<Integer> argtypes, Token t, String templateName) + throws ParseException + { + } + + /** + * How this directive is to be rendered + * @param context + * @param writer + * @param node + * @return True if the directive rendered successfully. + * @throws IOException + * @throws ResourceNotFoundException + * @throws ParseErrorException + * @throws MethodInvocationException + */ + public abstract boolean render( InternalContextAdapter context, + Writer writer, Node node ) + throws IOException, ResourceNotFoundException, ParseErrorException, + MethodInvocationException; + + + /** + * This creates and places the scope control for this directive + * into the context (if scope provision is turned on). + * @param context + */ + protected void preRender(InternalContextAdapter context) + { + if (isScopeProvided()) + { + String name = getScopeName(); + Object previous = context.get(name); + context.put(name, makeScope(previous)); + } + } + + /** + * @param prev + * @return scope + */ + protected Scope makeScope(Object prev) + { + return new Scope(this, prev); + } + + /** + * This cleans up any scope control for this directive after rendering, + * assuming the scope control was turned on. + * @param context + */ + protected void postRender(InternalContextAdapter context) + { + if (isScopeProvided()) + { + String name = getScopeName(); + Object obj = context.get(name); + + try + { + Scope scope = (Scope)obj; + if (scope.getParent() != null) + { + context.put(name, scope.getParent()); + } + else if (scope.getReplaced() != null) + { + context.put(name, scope.getReplaced()); + } + else + { + context.remove(name); + } + } + catch (ClassCastException cce) + { + // the user can override the scope with a #set, + // since that means they don't care about a replaced value + // and obviously aren't too keen on their scope control, + // and especially since #set is meant to be handled globally, + // we'll assume they know what they're doing and not worry + // about replacing anything superseded by this directive's scope + } + } + } + +} |