1 package org.apache.velocity.runtime.parser.node;
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.IOException;
23 import java.io.Writer;
24
25 import org.apache.commons.lang.builder.ToStringBuilder;
26 import org.apache.velocity.context.InternalContextAdapter;
27 import org.apache.velocity.exception.MethodInvocationException;
28 import org.apache.velocity.exception.ParseErrorException;
29 import org.apache.velocity.exception.ResourceNotFoundException;
30 import org.apache.velocity.exception.TemplateInitException;
31 import org.apache.velocity.runtime.directive.Directive;
32 import org.apache.velocity.runtime.directive.RuntimeMacro;
33 import org.apache.velocity.runtime.parser.ParseException;
34 import org.apache.velocity.runtime.parser.Parser;
35 import org.apache.velocity.util.ExceptionUtils;
36
37 /**
38 * This class is responsible for handling the pluggable
39 * directives in VTL.
40 *
41 * For example : #foreach()
42 *
43 * Please look at the Parser.jjt file which is
44 * what controls the generation of this class.
45 *
46 * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a>
47 * @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a>
48 * @author <a href="mailto:kav@kav.dk">Kasper Nielsen</a>
49 * @version $Id: ASTDirective.java 724825 2008-12-09 18:56:06Z nbubna $
50 */
51 public class ASTDirective extends SimpleNode
52 {
53 private Directive directive = null;
54 private String directiveName = "";
55 private boolean isDirective;
56 private boolean isInitialized;
57
58 /**
59 * @param id
60 */
61 public ASTDirective(int id)
62 {
63 super(id);
64 }
65
66 /**
67 * @param p
68 * @param id
69 */
70 public ASTDirective(Parser p, int id)
71 {
72 super(p, id);
73 }
74
75
76 /**
77 * @see org.apache.velocity.runtime.parser.node.SimpleNode#jjtAccept(org.apache.velocity.runtime.parser.node.ParserVisitor, java.lang.Object)
78 */
79 public Object jjtAccept(ParserVisitor visitor, Object data)
80 {
81 return visitor.visit(this, data);
82 }
83
84 /**
85 * @see org.apache.velocity.runtime.parser.node.SimpleNode#init(org.apache.velocity.context.InternalContextAdapter, java.lang.Object)
86 */
87 public synchronized Object init( InternalContextAdapter context, Object data)
88 throws TemplateInitException
89 {
90 /** method is synchronized to avoid concurrent directive initialization **/
91
92 if (!isInitialized)
93 {
94 super.init( context, data );
95
96 /*
97 * only do things that are not context dependent
98 */
99
100 if (parser.isDirective( directiveName ))
101 {
102 isDirective = true;
103
104 try
105 {
106 directive = (Directive) parser.getDirective( directiveName )
107 .getClass().newInstance();
108 }
109 catch (InstantiationException e)
110 {
111 throw ExceptionUtils.createRuntimeException("Couldn't initialize " +
112 "directive of class " +
113 parser.getDirective(directiveName).getClass().getName(),
114 e);
115 }
116 catch (IllegalAccessException e)
117 {
118 throw ExceptionUtils.createRuntimeException("Couldn't initialize " +
119 "directive of class " +
120 parser.getDirective(directiveName).getClass().getName(),
121 e);
122 }
123
124 directive.setLocation(getLine(), getColumn(), getTemplateName());
125 directive.init(rsvc, context,this);
126 }
127 else
128 {
129 /**
130 * Create a new RuntimeMacro
131 */
132 directive = new RuntimeMacro(directiveName, getTemplateName());
133 directive.setLocation(getLine(), getColumn(), getTemplateName());
134
135 /**
136 * Initialize it
137 */
138 try
139 {
140 directive.init( rsvc, context, this );
141 }
142
143 /**
144 * correct the line/column number if an exception is caught
145 */
146 catch (TemplateInitException die)
147 {
148 throw new TemplateInitException(die.getMessage(),
149 (ParseException) die.getWrappedThrowable(),
150 die.getTemplateName(),
151 die.getColumnNumber() + getColumn(),
152 die.getLineNumber() + getLine());
153 }
154 isDirective = true;
155 }
156
157 isInitialized = true;
158 }
159
160 return data;
161 }
162
163 /**
164 * @see org.apache.velocity.runtime.parser.node.SimpleNode#render(org.apache.velocity.context.InternalContextAdapter, java.io.Writer)
165 */
166 public boolean render( InternalContextAdapter context, Writer writer)
167 throws IOException,MethodInvocationException, ResourceNotFoundException, ParseErrorException
168 {
169 /*
170 * normal processing
171 */
172
173 if (isDirective)
174 {
175 directive.render(context, writer, this);
176 }
177 else
178 {
179 if (context.getAllowRendering())
180 {
181 writer.write( "#");
182 writer.write( directiveName );
183 }
184 }
185
186 return true;
187 }
188
189 /**
190 * Sets the directive name. Used by the parser. This keeps us from having to
191 * dig it out of the token stream and gives the parse the change to override.
192 * @param str
193 */
194 public void setDirectiveName( String str )
195 {
196 directiveName = str;
197 }
198
199 /**
200 * Gets the name of this directive.
201 * @return The name of this directive.
202 */
203 public String getDirectiveName()
204 {
205 return directiveName;
206 }
207
208 /**
209 * @since 1.5
210 */
211 public String toString()
212 {
213 return new ToStringBuilder(this)
214 .appendSuper(super.toString())
215 .append("directiveName", getDirectiveName())
216 .toString();
217 }
218
219 }
220
221
222