1 package org.apache.velocity.runtime.directive;
2
3 /*
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements. See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership. The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the
9 * "License"); you may not use this file except in compliance
10 * with the License. You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 * KIND, either express or implied. See the License for the
18 * specific language governing permissions and limitations
19 * under the License.
20 */
21
22 import java.io.Writer;
23 import java.io.IOException;
24
25 import org.apache.velocity.runtime.RuntimeConstants;
26 import org.apache.velocity.runtime.RuntimeServices;
27
28 import org.apache.velocity.context.InternalContextAdapter;
29 import org.apache.velocity.runtime.parser.node.Node;
30
31 import org.apache.velocity.exception.MethodInvocationException;
32 import org.apache.velocity.exception.ParseErrorException;
33 import org.apache.velocity.exception.ResourceNotFoundException;
34 import org.apache.velocity.exception.TemplateInitException;
35
36
37 /**
38 * Base class for all directives used in Velocity.
39 *
40 * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a>
41 * @author Nathan Bubna
42 * @version $Id: Directive.java 778045 2009-05-23 22:17:46Z nbubna $
43 */
44 public abstract class Directive implements DirectiveConstants, Cloneable
45 {
46 private int line = 0;
47 private int column = 0;
48 private boolean provideScope = false;
49 private String templateName;
50
51 /**
52 *
53 */
54 protected RuntimeServices rsvc = null;
55
56 /**
57 * Return the name of this directive.
58 * @return The name of this directive.
59 */
60 public abstract String getName();
61
62 /**
63 * Get the directive type BLOCK/LINE.
64 * @return The directive type BLOCK/LINE.
65 */
66 public abstract int getType();
67
68 /**
69 * Allows the template location to be set.
70 * @param line
71 * @param column
72 */
73 public void setLocation( int line, int column )
74 {
75 this.line = line;
76 this.column = column;
77 }
78
79 /**
80 * Allows the template location to be set.
81 * @param line
82 * @param column
83 */
84 public void setLocation(int line, int column, String templateName)
85 {
86 setLocation(line, column);
87 this.templateName = templateName;
88 }
89
90 /**
91 * for log msg purposes
92 * @return The current line for log msg purposes.
93 */
94 public int getLine()
95 {
96 return line;
97 }
98
99 /**
100 * for log msg purposes
101 * @return The current column for log msg purposes.
102 */
103 public int getColumn()
104 {
105 return column;
106 }
107
108 /**
109 * @return The template file name this directive was defined in, or null if not
110 * defined in a file.
111 */
112 public String getTemplateName()
113 {
114 return templateName;
115 }
116
117 /**
118 * @returns the name to be used when a scope control is provided for this
119 * directive.
120 */
121 public String getScopeName()
122 {
123 return getName();
124 }
125
126 /**
127 * @return true if there will be a scope control injected into the context
128 * when rendering this directive.
129 */
130 public boolean isScopeProvided()
131 {
132 return provideScope;
133 }
134
135 /**
136 * How this directive is to be initialized.
137 * @param rs
138 * @param context
139 * @param node
140 * @throws TemplateInitException
141 */
142 public void init( RuntimeServices rs, InternalContextAdapter context,
143 Node node)
144 throws TemplateInitException
145 {
146 rsvc = rs;
147
148 String property = getScopeName()+'.'+RuntimeConstants.PROVIDE_SCOPE_CONTROL;
149 this.provideScope = rsvc.getBoolean(property, provideScope);
150 }
151
152 /**
153 * How this directive is to be rendered
154 * @param context
155 * @param writer
156 * @param node
157 * @return True if the directive rendered successfully.
158 * @throws IOException
159 * @throws ResourceNotFoundException
160 * @throws ParseErrorException
161 * @throws MethodInvocationException
162 */
163 public abstract boolean render( InternalContextAdapter context,
164 Writer writer, Node node )
165 throws IOException, ResourceNotFoundException, ParseErrorException,
166 MethodInvocationException;
167
168
169 /**
170 * This creates and places the scope control for this directive
171 * into the context (if scope provision is turned on).
172 */
173 protected void preRender(InternalContextAdapter context)
174 {
175 if (isScopeProvided())
176 {
177 String name = getScopeName();
178 Object previous = context.get(name);
179 context.put(name, makeScope(previous));
180 }
181 }
182
183 protected Scope makeScope(Object prev)
184 {
185 return new Scope(this, prev);
186 }
187
188 /**
189 * This cleans up any scope control for this directive after rendering,
190 * assuming the scope control was turned on.
191 */
192 protected void postRender(InternalContextAdapter context)
193 {
194 if (isScopeProvided())
195 {
196 String name = getScopeName();
197 Object obj = context.get(name);
198
199 try
200 {
201 Scope scope = (Scope)obj;
202 if (scope.getParent() != null)
203 {
204 context.put(name, scope.getParent());
205 }
206 else if (scope.getReplaced() != null)
207 {
208 context.put(name, scope.getReplaced());
209 }
210 else
211 {
212 context.remove(name);
213 }
214 }
215 catch (ClassCastException cce)
216 {
217 // the user can override the scope with a #set,
218 // since that means they don't care about a replaced value
219 // and obviously aren't too keen on their scope control,
220 // and especially since #set is meant to be handled globally,
221 // we'll assume they know what they're doing and not worry
222 // about replacing anything superseded by this directive's scope
223 }
224 }
225 }
226
227 }