1 package org.apache.velocity.context;
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.util.HashSet;
23 import java.util.Set;
24
25 import org.apache.velocity.VelocityContext;
26 import org.apache.velocity.app.event.EventCartridge;
27 import org.apache.velocity.runtime.RuntimeConstants;
28 import org.apache.velocity.runtime.RuntimeServices;
29 import org.apache.velocity.runtime.resource.Resource;
30 import org.apache.velocity.util.ClassUtils;
31 import org.apache.velocity.util.introspection.IntrospectionCacheData;
32
33 /**
34 * This is a special, internal-use-only context implementation to be
35 * used for the #evaluate directive.
36 *
37 * We use this context to chain the existing context, preventing any changes
38 * from impacting the parent context. By separating this context into a
39 * separate class it also allows for the future possibility of changing
40 * the context behavior for the #evaluate directive.
41 *
42 * Note that the context used to store values local to #evaluate()
43 * is user defined but defaults to {@link VelocityContext}.
44 *
45 * @author <a href="mailto:wglass@forio.com">Will Glass-Husain</a>
46 * @version $Id: EvaluateContext.java 522413 2007-03-26 04:34:15Z wglass $
47 */
48 public class EvaluateContext implements InternalContextAdapter
49 {
50 /** container for any local items */
51 Context localContext;
52
53 /** the base context store. This is the 'global' context */
54 InternalContextAdapter innerContext = null;
55
56 boolean allowRendering = true;
57
58 /**
59 * CTOR, wraps an ICA
60 * @param inner context for parent template
61 * @param rsvc
62 */
63 public EvaluateContext( InternalContextAdapter inner, RuntimeServices rsvc )
64 {
65 innerContext = inner.getBaseContext();
66 initContext(rsvc);
67 }
68
69 /**
70 * Initialize the context based on user-configured class
71 * @param rsvc
72 */
73 private void initContext( RuntimeServices rsvc )
74 {
75 String contextClass = rsvc.getString(RuntimeConstants.EVALUATE_CONTEXT_CLASS);
76
77 if (contextClass != null && contextClass.length() > 0)
78 {
79 Object o = null;
80
81 try
82 {
83 o = ClassUtils.getNewInstance( contextClass );
84 }
85 catch (ClassNotFoundException cnfe)
86 {
87 String err = "The specified class for #evaluate() context (" + contextClass
88 + ") does not exist or is not accessible to the current classloader.";
89 rsvc.getLog().error(err);
90 throw new RuntimeException(err,cnfe);
91 }
92 catch (Exception e)
93 {
94 String err = "The specified class for #evaluate() context (" + contextClass
95 + ") can not be loaded.";
96 rsvc.getLog().error(err,e);
97 throw new RuntimeException(err);
98 }
99
100 if (!(o instanceof Context))
101 {
102 String err = "The specified class for #evaluate() context (" + contextClass
103 + ") does not implement " + Context.class.getName() + ".";
104 rsvc.getLog().error(err);
105 throw new RuntimeException(err);
106 }
107
108 localContext = (Context) o;
109
110 }
111 else
112 {
113 String err = "No class specified for #evaluate() context.";
114 rsvc.getLog().error(err);
115 throw new RuntimeException(err);
116 }
117
118 }
119
120 /**
121 * Return the inner / user context.
122 * @return The inner / user context.
123 */
124 public Context getInternalUserContext()
125 {
126 return innerContext.getInternalUserContext();
127 }
128
129 /**
130 * @see org.apache.velocity.context.InternalWrapperContext#getBaseContext()
131 */
132 public InternalContextAdapter getBaseContext()
133 {
134 return innerContext.getBaseContext();
135 }
136
137 /**
138 * Put method also stores values in local scope
139 *
140 * @param key name of item to set
141 * @param value object to set to key
142 * @return old stored object
143 */
144 public Object put(String key, Object value)
145 {
146 /*
147 * just put in the local context
148 */
149 return localContext.put(key, value);
150
151 }
152
153 /**
154 * Retrieves from local or global context.
155 *
156 * @param key name of item to get
157 * @return stored object or null
158 */
159 public Object get( String key )
160 {
161 /*
162 * always try the local context then innerContext
163 */
164
165 Object o = localContext.get( key );
166
167 if ( o == null)
168 {
169 o = innerContext.get( key );
170 }
171
172 return o;
173 }
174
175 /**
176 * @see org.apache.velocity.context.Context#containsKey(java.lang.Object)
177 */
178 public boolean containsKey(Object key)
179 {
180 return localContext.containsKey(key) || innerContext.containsKey(key);
181 }
182
183 /**
184 * @see org.apache.velocity.context.Context#getKeys()
185 */
186 public Object[] getKeys()
187 {
188 Set keys = new HashSet();
189 Object[] localKeys = localContext.getKeys();
190 for (int i=0; i < localKeys.length; i++)
191 {
192 keys.add(localKeys[i]);
193 }
194
195 Object[] innerKeys = innerContext.getKeys();
196 for (int i=0; i < innerKeys.length; i++)
197 {
198 keys.add(innerKeys[i]);
199 }
200 return keys.toArray();
201 }
202
203 /**
204 * @see org.apache.velocity.context.Context#remove(java.lang.Object)
205 */
206 public Object remove(Object key)
207 {
208 return localContext.remove( key );
209 }
210
211 /**
212 * @see org.apache.velocity.context.InternalHousekeepingContext#pushCurrentTemplateName(java.lang.String)
213 */
214 public void pushCurrentTemplateName( String s )
215 {
216 innerContext.pushCurrentTemplateName( s );
217 }
218
219 /**
220 * @see org.apache.velocity.context.InternalHousekeepingContext#popCurrentTemplateName()
221 */
222 public void popCurrentTemplateName()
223 {
224 innerContext.popCurrentTemplateName();
225 }
226
227 /**
228 * @see org.apache.velocity.context.InternalHousekeepingContext#getCurrentTemplateName()
229 */
230 public String getCurrentTemplateName()
231 {
232 return innerContext.getCurrentTemplateName();
233 }
234
235 /**
236 * @see org.apache.velocity.context.InternalHousekeepingContext#getTemplateNameStack()
237 */
238 public Object[] getTemplateNameStack()
239 {
240 return innerContext.getTemplateNameStack();
241 }
242
243 /**
244 * @see org.apache.velocity.context.InternalHousekeepingContext#icacheGet(java.lang.Object)
245 */
246 public IntrospectionCacheData icacheGet( Object key )
247 {
248 return innerContext.icacheGet( key );
249 }
250
251 /**
252 * Allows callers to explicitly put objects in the local context.
253 * Objects added to the context through this method always end up
254 * in the top-level context of possible wrapped contexts.
255 *
256 * @param key name of item to set.
257 * @param value object to set to key.
258 * @return old stored object
259 */
260 public Object localPut(final String key, final Object value)
261 {
262 return localContext.put(key, value);
263 }
264
265 /**
266 * @see org.apache.velocity.context.InternalHousekeepingContext#icachePut(java.lang.Object, org.apache.velocity.util.introspection.IntrospectionCacheData)
267 */
268 public void icachePut( Object key, IntrospectionCacheData o )
269 {
270 innerContext.icachePut( key, o );
271 }
272
273 /**
274 * @see org.apache.velocity.context.InternalHousekeepingContext#getAllowRendering()
275 */
276 public boolean getAllowRendering()
277 {
278 return allowRendering && innerContext.getAllowRendering();
279 }
280
281 /**
282 * @see org.apache.velocity.context.InternalHousekeepingContext#setAllowRendering(boolean)
283 */
284 public void setAllowRendering(boolean v)
285 {
286 allowRendering = false;
287 }
288
289 /**
290 * @see org.apache.velocity.context.InternalEventContext#attachEventCartridge(org.apache.velocity.app.event.EventCartridge)
291 */
292 public EventCartridge attachEventCartridge( EventCartridge ec )
293 {
294 EventCartridge cartridge = innerContext.attachEventCartridge( ec );
295 return cartridge;
296 }
297
298 /**
299 * @see org.apache.velocity.context.InternalEventContext#getEventCartridge()
300 */
301 public EventCartridge getEventCartridge()
302 {
303 return innerContext.getEventCartridge();
304 }
305
306
307 /**
308 * @see org.apache.velocity.context.InternalHousekeepingContext#setCurrentResource(org.apache.velocity.runtime.resource.Resource)
309 */
310 public void setCurrentResource( Resource r )
311 {
312 innerContext.setCurrentResource( r );
313 }
314
315 /**
316 * @see org.apache.velocity.context.InternalHousekeepingContext#getCurrentResource()
317 */
318 public Resource getCurrentResource()
319 {
320 return innerContext.getCurrentResource();
321 }
322 }
323
324
325