1 package org.apache.velocity.runtime.directive;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import org.apache.commons.lang.text.StrBuilder;
23
24 import org.apache.velocity.context.InternalContextAdapter;
25 import org.apache.velocity.runtime.log.Log;
26 import org.apache.velocity.runtime.parser.node.Node;
27 import org.apache.velocity.runtime.parser.Token;
28 import org.apache.velocity.runtime.RuntimeConstants;
29 import org.apache.velocity.runtime.RuntimeServices;
30 import org.apache.velocity.exception.ResourceNotFoundException;
31 import org.apache.velocity.exception.ParseErrorException;
32 import org.apache.velocity.exception.MethodInvocationException;
33 import org.apache.velocity.exception.TemplateInitException;
34 import org.apache.velocity.util.introspection.Info;
35
36 import java.io.Writer;
37 import java.io.IOException;
38 import java.util.List;
39
40
41
42
43
44
45
46
47
48 public class RuntimeMacro extends Directive
49 {
50
51
52
53 private String macroName;
54
55
56
57
58 private String sourceTemplate;
59
60
61
62
63 private String literal = null;
64
65
66
67
68 private Node node = null;
69
70
71
72
73 protected boolean strictRef = false;
74
75
76
77
78
79
80
81
82 public RuntimeMacro(String macroName, String sourceTemplate)
83 {
84 if (macroName == null || sourceTemplate == null)
85 {
86 throw new IllegalArgumentException("Null arguments");
87 }
88
89 this.macroName = macroName;
90 this.sourceTemplate = sourceTemplate;
91 }
92
93
94
95
96
97
98 public String getName()
99 {
100 return macroName;
101 }
102
103
104
105
106
107
108
109 public int getType()
110 {
111 return LINE;
112 }
113
114
115
116
117
118
119
120
121
122
123 public void init(RuntimeServices rs, InternalContextAdapter context,
124 Node node)
125 {
126 super.init(rs, context, node);
127 rsvc = rs;
128 this.node = node;
129
130
131
132
133
134 Token t = node.getLastToken();
135 if (t.image.charAt(0) == ')')
136 {
137 strictRef = rsvc.getBoolean(RuntimeConstants.RUNTIME_REFERENCES_STRICT, false);
138 }
139 }
140
141
142
143
144
145
146 private String getLiteral()
147 {
148 if (literal == null)
149 {
150 StrBuilder buffer = new StrBuilder();
151 Token t = node.getFirstToken();
152
153 while (t != null && t != node.getLastToken())
154 {
155 buffer.append(t.image);
156 t = t.next;
157 }
158
159 if (t != null)
160 {
161 buffer.append(t.image);
162 }
163
164 literal = buffer.toString();
165 }
166 return literal;
167 }
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188 public boolean render(InternalContextAdapter context, Writer writer,
189 Node node)
190 throws IOException, ResourceNotFoundException,
191 ParseErrorException, MethodInvocationException
192 {
193 VelocimacroProxy vmProxy = null;
194 String renderingTemplate = context.getCurrentTemplateName();
195
196
197
198
199 Object o = rsvc.getVelocimacro(macroName, sourceTemplate, renderingTemplate);
200
201 if( o != null )
202 {
203
204
205 vmProxy = (VelocimacroProxy)o;
206 }
207
208
209
210
211 if (vmProxy == null)
212 {
213 List macroLibraries = context.getMacroLibraries();
214 if (macroLibraries != null)
215 {
216 for (int i = macroLibraries.size() - 1; i >= 0; i--)
217 {
218 o = rsvc.getVelocimacro(macroName,
219 (String)macroLibraries.get(i), renderingTemplate);
220
221
222 if (o != null)
223 {
224 vmProxy = (VelocimacroProxy) o;
225 break;
226 }
227 }
228 }
229 }
230
231 if (vmProxy != null)
232 {
233 try
234 {
235
236 vmProxy.init(rsvc, context, node);
237 }
238 catch (TemplateInitException die)
239 {
240 Info info = new Info(sourceTemplate, node.getLine(), node.getColumn());
241 throw new ParseErrorException(die.getMessage() + " at "
242 + Log.formatFileString(info), info);
243 }
244
245 try
246 {
247 return vmProxy.render(context, writer, node);
248 }
249 catch (RuntimeException e)
250 {
251
252
253
254
255
256
257
258 rsvc.getLog().error("Exception in macro #" + macroName + " at " +
259 Log.formatFileString(sourceTemplate, getLine(), getColumn()));
260 throw e;
261 }
262 catch (IOException e)
263 {
264 rsvc.getLog().error("Exception in macro #" + macroName + " at " +
265 Log.formatFileString(sourceTemplate, getLine(), getColumn()));
266 throw e;
267 }
268 }
269 else if (strictRef)
270 {
271 Info info = new Info(sourceTemplate, node.getLine(), node.getColumn());
272 throw new ParseErrorException("Macro '#" + macroName + "' is not defined at "
273 + Log.formatFileString(info), info);
274 }
275
276
277
278
279 writer.write(getLiteral());
280 return true;
281 }
282 }