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 import java.util.List;
25
26 import org.apache.velocity.VelocityContext;
27 import org.apache.velocity.app.event.EventCartridge;
28 import org.apache.velocity.runtime.RuntimeConstants;
29 import org.apache.velocity.runtime.RuntimeServices;
30 import org.apache.velocity.runtime.resource.Resource;
31 import org.apache.velocity.util.ClassUtils;
32 import org.apache.velocity.util.introspection.IntrospectionCacheData;
33
34 /**
35 * This is a special, internal-use-only context implementation to be
36 * used for the #evaluate directive.
37 *
38 * We use this context to chain the existing context, preventing any changes
39 * from impacting the parent context. By separating this context into a
40 * separate class it also allows for the future possibility of changing
41 * the context behavior for the #evaluate directive.
42 *
43 * Note that the context used to store values local to #evaluate()
44 * is user defined but defaults to {@link VelocityContext}.
45 *
46 * @author <a href="mailto:wglass@forio.com">Will Glass-Husain</a>
47 * @version $Id: EvaluateContext.java 691519 2008-09-03 05:36:11Z nbubna $
48 * @since 1.6
49 */
50 public class EvaluateContext extends ChainedInternalContextAdapter
51 {
52 /** container for any local items */
53 Context localContext;
54 boolean allowRendering = true;
55
56 /**
57 * CTOR, wraps an ICA
58 * @param inner context for parent template
59 * @param rsvc
60 */
61 public EvaluateContext( InternalContextAdapter inner, RuntimeServices rsvc )
62 {
63 super(inner);
64 initContext(rsvc);
65 }
66
67 /**
68 * Initialize the context based on user-configured class
69 * @param rsvc
70 */
71 private void initContext( RuntimeServices rsvc )
72 {
73 String contextClass = rsvc.getString(RuntimeConstants.EVALUATE_CONTEXT_CLASS);
74
75 if (contextClass != null && contextClass.length() > 0)
76 {
77 Object o = null;
78
79 try
80 {
81 o = ClassUtils.getNewInstance( contextClass );
82 }
83 catch (ClassNotFoundException cnfe)
84 {
85 String err = "The specified class for #evaluate() context (" + contextClass
86 + ") does not exist or is not accessible to the current classloader.";
87 rsvc.getLog().error(err);
88 throw new RuntimeException(err,cnfe);
89 }
90 catch (Exception e)
91 {
92 String err = "The specified class for #evaluate() context (" + contextClass
93 + ") can not be loaded.";
94 rsvc.getLog().error(err,e);
95 throw new RuntimeException(err);
96 }
97
98 if (!(o instanceof Context))
99 {
100 String err = "The specified class for #evaluate() context (" + contextClass
101 + ") does not implement " + Context.class.getName() + ".";
102 rsvc.getLog().error(err);
103 throw new RuntimeException(err);
104 }
105
106 localContext = (Context) o;
107
108 }
109 else
110 {
111 String err = "No class specified for #evaluate() context.";
112 rsvc.getLog().error(err);
113 throw new RuntimeException(err);
114 }
115
116 }
117
118 /**
119 * Put method also stores values in local scope
120 *
121 * @param key name of item to set
122 * @param value object to set to key
123 * @return old stored object
124 */
125 public Object put(String key, Object value)
126 {
127 /*
128 * just put in the local context
129 */
130 return localContext.put(key, value);
131
132 }
133
134 /**
135 * Retrieves from local or global context.
136 *
137 * @param key name of item to get
138 * @return stored object or null
139 */
140 public Object get( String key )
141 {
142 /*
143 * always try the local context then innerContext
144 */
145
146 Object o = localContext.get( key );
147
148 if ( o == null)
149 {
150 o = super.get( key );
151 }
152
153 return o;
154 }
155
156 /**
157 * @see org.apache.velocity.context.Context#containsKey(java.lang.Object)
158 */
159 public boolean containsKey(Object key)
160 {
161 return localContext.containsKey(key) || super.containsKey(key);
162 }
163
164 /**
165 * @see org.apache.velocity.context.Context#getKeys()
166 */
167 public Object[] getKeys()
168 {
169 Set keys = new HashSet();
170 Object[] localKeys = localContext.getKeys();
171 for (int i=0; i < localKeys.length; i++)
172 {
173 keys.add(localKeys[i]);
174 }
175
176 Object[] innerKeys = super.getKeys();
177 for (int i=0; i < innerKeys.length; i++)
178 {
179 keys.add(innerKeys[i]);
180 }
181 return keys.toArray();
182 }
183
184 /**
185 * @see org.apache.velocity.context.Context#remove(java.lang.Object)
186 */
187 public Object remove(Object key)
188 {
189 return localContext.remove( key );
190 }
191
192 /**
193 * Allows callers to explicitly put objects in the local context.
194 * Objects added to the context through this method always end up
195 * in the top-level context of possible wrapped contexts.
196 *
197 * @param key name of item to set.
198 * @param value object to set to key.
199 * @return old stored object
200 */
201 public Object localPut(final String key, final Object value)
202 {
203 return localContext.put(key, value);
204 }
205
206 /**
207 * @see org.apache.velocity.context.InternalHousekeepingContext#getAllowRendering()
208 */
209 public boolean getAllowRendering()
210 {
211 return allowRendering && innerContext.getAllowRendering();
212 }
213
214 /**
215 * @see org.apache.velocity.context.InternalHousekeepingContext#setAllowRendering(boolean)
216 */
217 public void setAllowRendering(boolean v)
218 {
219 allowRendering = false;
220 }
221
222 }