1 package org.apache.velocity.context;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.StringWriter;
23 import java.util.HashMap;
24 import java.util.List;
25 import java.util.Map;
26
27 import org.apache.velocity.app.event.EventCartridge;
28 import org.apache.velocity.exception.MethodInvocationException;
29 import org.apache.velocity.exception.VelocityException;
30 import org.apache.velocity.runtime.RuntimeServices;
31 import org.apache.velocity.runtime.parser.ParserTreeConstants;
32 import org.apache.velocity.runtime.parser.node.ASTReference;
33 import org.apache.velocity.runtime.parser.node.Node;
34 import org.apache.velocity.runtime.resource.Resource;
35 import org.apache.velocity.util.introspection.IntrospectionCacheData;
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52 public class ProxyVMContext extends ChainedInternalContextAdapter
53 {
54
55 Map vmproxyhash = new HashMap(8, 0.8f);
56
57
58 Map localcontext = new HashMap(8, 0.8f);;
59
60
61 InternalContextAdapter wrappedContext;
62
63
64 private boolean localContextScope;
65
66
67 private RuntimeServices rsvc;
68
69
70
71
72
73
74 public ProxyVMContext(InternalContextAdapter inner,
75 RuntimeServices rsvc,
76 boolean localContextScope)
77 {
78 super(inner);
79
80 this.localContextScope = localContextScope;
81 this.rsvc = rsvc;
82
83 wrappedContext = inner;
84 }
85
86
87
88
89
90
91
92
93
94
95
96 public void addVMProxyArg(InternalContextAdapter context,
97 String macroArgumentName,
98 String literalMacroArgumentName,
99 Node argumentValue) throws MethodInvocationException
100 {
101 if (isConstant(argumentValue))
102 {
103 localcontext.put(macroArgumentName, argumentValue.value(context));
104 }
105 else
106 {
107 vmproxyhash.put(macroArgumentName, argumentValue);
108 localcontext.put(literalMacroArgumentName, argumentValue);
109 }
110 }
111
112
113
114
115
116
117
118
119
120 private boolean isConstant(Node node)
121 {
122 switch (node.getType())
123 {
124 case ParserTreeConstants.JJTINTEGERRANGE:
125 case ParserTreeConstants.JJTREFERENCE:
126 case ParserTreeConstants.JJTOBJECTARRAY:
127 case ParserTreeConstants.JJTMAP:
128 case ParserTreeConstants.JJTSTRINGLITERAL:
129 case ParserTreeConstants.JJTTEXT:
130 return (false);
131 default:
132 return (true);
133 }
134 }
135
136
137
138
139
140
141
142
143 public Object put(final String key, final Object value)
144 {
145 return put(key, value, localContextScope);
146 }
147
148
149
150
151
152
153
154
155
156 public Object localPut(final String key, final Object value)
157 {
158 return put(key, value, true);
159 }
160
161
162
163
164
165
166
167
168
169 protected Object put(final String key, final Object value, final boolean forceLocal)
170 {
171 Node astNode = (Node) vmproxyhash.get(key);
172
173 if (astNode != null)
174 {
175 if (astNode.getType() == ParserTreeConstants.JJTREFERENCE)
176 {
177 ASTReference ref = (ASTReference) astNode;
178
179 if (ref.jjtGetNumChildren() > 0)
180 ref.setValue(wrappedContext, value);
181 else
182 wrappedContext.put(ref.getRootString(), value);
183
184 }
185 else
186 {
187 rsvc.getLog().error("ProxyVMContext.put() : New value cannot be assigned to a constant: "
188 + key + " / " + get("$" + key + ".literal"));
189 }
190 return null;
191 }
192 else
193 {
194 if (forceLocal)
195 {
196 return localcontext.put(key, value);
197 }
198 else
199 {
200 if (localcontext.containsKey(key))
201 {
202 return localcontext.put(key, value);
203 }
204 else
205 {
206 return super.put(key, value);
207 }
208 }
209 }
210 }
211
212
213
214
215
216
217
218 public Object get(String key)
219 {
220 Object o = null;
221
222 Node astNode = (Node) vmproxyhash.get(key);
223
224 if (astNode != null)
225 {
226 int type = astNode.getType();
227
228
229
230 if (type == ParserTreeConstants.JJTREFERENCE)
231 {
232 ASTReference ref = (ASTReference) astNode;
233
234 if (ref.jjtGetNumChildren() > 0)
235 {
236 return ref.execute(null, wrappedContext);
237 }
238 else
239 {
240 Object obj = wrappedContext.get(ref.getRootString());
241 if (obj == null && ref.strictRef)
242 {
243 if (!wrappedContext.containsKey(ref.getRootString()))
244 {
245 throw new MethodInvocationException("Parameter '" + ref.getRootString()
246 + "' not defined", null, key, ref.getTemplateName(),
247 ref.getLine(), ref.getColumn());
248 }
249 }
250 return obj;
251 }
252 }
253 else if (type == ParserTreeConstants.JJTTEXT)
254 {
255
256 try
257 {
258 StringWriter writer = new StringWriter();
259 astNode.render(wrappedContext, writer);
260
261 return writer.toString();
262 }
263 catch (RuntimeException e)
264 {
265 throw e;
266 }
267 catch (Exception e)
268 {
269 String msg = "ProxyVMContext.get() : error rendering reference";
270 rsvc.getLog().error(msg, e);
271 throw new VelocityException(msg, e);
272 }
273 }
274 else
275 {
276
277 return astNode.value(wrappedContext);
278 }
279 }
280 else
281 {
282 o = localcontext.get(key);
283
284 if (o == null)
285 {
286 o = super.get(key);
287 }
288 }
289
290 return o;
291 }
292
293
294
295
296 public boolean containsKey(Object key)
297 {
298 return vmproxyhash.containsKey(key)
299 || localcontext.containsKey(key)
300 || super.containsKey(key);
301 }
302
303
304
305
306 public Object[] getKeys()
307 {
308 return vmproxyhash.keySet().toArray();
309 }
310
311
312
313
314 public Object remove(Object key)
315 {
316 if (vmproxyhash.containsKey(key))
317 {
318 return vmproxyhash.remove(key);
319 }
320 else
321 {
322 if (localContextScope)
323 {
324 return localcontext.remove(key);
325 }
326
327 Object oldValue = localcontext.remove(key);
328 if (oldValue == null)
329 {
330 oldValue = super.remove(key);
331 }
332 return oldValue;
333 }
334 }
335
336 }