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.HashMap; 23 24 import org.apache.velocity.runtime.RuntimeServices; 25 import org.apache.velocity.runtime.RuntimeConstants; 26 import org.apache.velocity.runtime.directive.VMProxyArg; 27 import org.apache.velocity.util.introspection.IntrospectionCacheData; 28 import org.apache.velocity.runtime.resource.Resource; 29 import org.apache.velocity.app.event.EventCartridge; 30 import org.apache.velocity.exception.MethodInvocationException; 31 32 /** 33 * This is a special, internal-use-only context implementation to be 34 * used for the new Velocimacro implementation. 35 * 36 * The main distinguishing feature is the management of the VMProxyArg objects 37 * in the put() and get() methods. 38 * 39 * Further, this context also supports the 'VM local context' mode, where 40 * any put() of references that aren't args to the VM are considered 41 * local to the vm, protecting the global context. 42 * 43 * @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a> 44 * @version $Id: VMContext.java 471908 2006-11-06 22:39:28Z henning $ 45 */ 46 public class VMContext implements InternalContextAdapter 47 { 48 /** container for our VMProxy Objects */ 49 HashMap vmproxyhash = new HashMap(); 50 51 /** container for any local or constant VMProxy items */ 52 HashMap localcontext = new HashMap(); 53 54 /** the base context store. This is the 'global' context */ 55 InternalContextAdapter innerContext = null; 56 57 /** context that we are wrapping */ 58 InternalContextAdapter wrappedContext = null; 59 60 /** support for local context scope feature, where all references are local */ 61 private boolean localcontextscope = false; 62 63 /** 64 * CTOR, wraps an ICA 65 * @param inner 66 * @param rsvc 67 */ 68 public VMContext( InternalContextAdapter inner, RuntimeServices rsvc ) 69 { 70 localcontextscope = rsvc.getBoolean( RuntimeConstants.VM_CONTEXT_LOCALSCOPE, false ); 71 72 wrappedContext = inner; 73 innerContext = inner.getBaseContext(); 74 } 75 76 /** 77 * Return the inner / user context. 78 * @return The inner / user context. 79 */ 80 public Context getInternalUserContext() 81 { 82 return innerContext.getInternalUserContext(); 83 } 84 85 /** 86 * @see org.apache.velocity.context.InternalWrapperContext#getBaseContext() 87 */ 88 public InternalContextAdapter getBaseContext() 89 { 90 return innerContext.getBaseContext(); 91 } 92 93 /** 94 * Used to put VMProxyArgs into this context. It separates 95 * the VMProxyArgs into constant and non-constant types 96 * pulling out the value of the constant types so they can 97 * be modified w/o damaging the VMProxyArg, and leaving the 98 * dynamic ones, as they modify context rather than their own 99 * state 100 * @param vmpa VMProxyArg to add 101 * @throws MethodInvocationException 102 */ 103 public void addVMProxyArg( VMProxyArg vmpa ) throws MethodInvocationException 104 { 105 /* 106 * ask if it's a constant : if so, get the value and put into the 107 * local context, otherwise, put the vmpa in our vmproxyhash 108 */ 109 110 String key = vmpa.getContextReference(); 111 112 if ( vmpa.isConstant() ) 113 { 114 localcontext.put( key, vmpa.getObject( wrappedContext ) ); 115 } 116 else 117 { 118 vmproxyhash.put( key, vmpa ); 119 } 120 } 121 122 /** 123 * Impl of the Context.put() method. 124 * 125 * @param key name of item to set 126 * @param value object to set to key 127 * @return old stored object 128 */ 129 public Object put(final String key, final Object value) 130 { 131 return put(key, value, localcontextscope); 132 } 133 134 /** 135 * Allows callers to explicitly put objects in the local context, 136 * no matter what the velocimacro.context.local setting says. Needed 137 * e.g. for loop variables in foreach. 138 * 139 * @param key name of item to set. 140 * @param value object to set to key. 141 * @return old stored object 142 */ 143 public Object localPut(final String key, final Object value) 144 { 145 return put(key, value, true); 146 } 147 148 /** 149 * Internal put method to select between local and global scope. 150 * 151 * @param key name of item to set 152 * @param value object to set to key 153 * @param forceLocal True forces the object into the local scope. 154 * @return old stored object 155 */ 156 protected Object put(final String key, final Object value, final boolean forceLocal) 157 { 158 /* 159 * first see if this is a vmpa 160 */ 161 162 VMProxyArg vmpa = (VMProxyArg) vmproxyhash.get( key ); 163 164 if( vmpa != null) 165 { 166 return vmpa.setObject( wrappedContext, value ); 167 } 168 else 169 { 170 if(forceLocal) 171 { 172 /* 173 * just put in the local context 174 */ 175 return localcontext.put(key, value); 176 } 177 else 178 { 179 /* 180 * ok, how about the local context? 181 */ 182 183 if (localcontext.containsKey(key)) 184 { 185 return localcontext.put(key, value); 186 } 187 else 188 { 189 /* 190 * otherwise, let them push it into the 'global' context 191 */ 192 193 return innerContext.put(key, value); 194 } 195 } 196 } 197 } 198 199 /** 200 * Impl of the Context.gut() method. 201 * 202 * @param key name of item to get 203 * @return stored object or null 204 */ 205 public Object get( String key ) 206 { 207 /* 208 * first, see if it's a VMPA 209 */ 210 211 Object o = null; 212 213 VMProxyArg vmpa = (VMProxyArg) vmproxyhash.get( key ); 214 215 if( vmpa != null ) 216 { 217 o = vmpa.getObject( wrappedContext ); 218 } 219 else 220 { 221 /* 222 * always try the local context then innerContext--even if localcontextscope 223 */ 224 225 o = localcontext.get( key ); 226 227 if ( o == null) 228 { 229 /* 230 * last chance 231 */ 232 233 o = innerContext.get( key ); 234 } 235 } 236 237 return o; 238 } 239 240 /** 241 * @see org.apache.velocity.context.Context#containsKey(java.lang.Object) 242 */ 243 public boolean containsKey(Object key) 244 { 245 return false; 246 } 247 248 /** 249 * @see org.apache.velocity.context.Context#getKeys() 250 */ 251 public Object[] getKeys() 252 { 253 return vmproxyhash.keySet().toArray(); 254 } 255 256 /** 257 * @see org.apache.velocity.context.Context#remove(java.lang.Object) 258 */ 259 public Object remove(Object key) 260 { 261 return vmproxyhash.remove( key ); 262 } 263 264 /** 265 * @see org.apache.velocity.context.InternalHousekeepingContext#pushCurrentTemplateName(java.lang.String) 266 */ 267 public void pushCurrentTemplateName( String s ) 268 { 269 innerContext.pushCurrentTemplateName( s ); 270 } 271 272 /** 273 * @see org.apache.velocity.context.InternalHousekeepingContext#popCurrentTemplateName() 274 */ 275 public void popCurrentTemplateName() 276 { 277 innerContext.popCurrentTemplateName(); 278 } 279 280 /** 281 * @see org.apache.velocity.context.InternalHousekeepingContext#getCurrentTemplateName() 282 */ 283 public String getCurrentTemplateName() 284 { 285 return innerContext.getCurrentTemplateName(); 286 } 287 288 /** 289 * @see org.apache.velocity.context.InternalHousekeepingContext#getTemplateNameStack() 290 */ 291 public Object[] getTemplateNameStack() 292 { 293 return innerContext.getTemplateNameStack(); 294 } 295 296 /** 297 * @see org.apache.velocity.context.InternalHousekeepingContext#icacheGet(java.lang.Object) 298 */ 299 public IntrospectionCacheData icacheGet( Object key ) 300 { 301 return innerContext.icacheGet( key ); 302 } 303 304 /** 305 * @see org.apache.velocity.context.InternalHousekeepingContext#icachePut(java.lang.Object, org.apache.velocity.util.introspection.IntrospectionCacheData) 306 */ 307 public void icachePut( Object key, IntrospectionCacheData o ) 308 { 309 innerContext.icachePut( key, o ); 310 } 311 312 /** 313 * @see org.apache.velocity.context.InternalHousekeepingContext#getAllowRendering() 314 */ 315 public boolean getAllowRendering() 316 { 317 return innerContext.getAllowRendering(); 318 } 319 320 /** 321 * @see org.apache.velocity.context.InternalHousekeepingContext#setAllowRendering(boolean) 322 */ 323 public void setAllowRendering(boolean v) 324 { 325 innerContext.setAllowRendering(v); 326 } 327 328 /** 329 * @see org.apache.velocity.context.InternalEventContext#attachEventCartridge(org.apache.velocity.app.event.EventCartridge) 330 */ 331 public EventCartridge attachEventCartridge( EventCartridge ec ) 332 { 333 EventCartridge cartridge = innerContext.attachEventCartridge( ec ); 334 return cartridge; 335 } 336 337 /** 338 * @see org.apache.velocity.context.InternalEventContext#getEventCartridge() 339 */ 340 public EventCartridge getEventCartridge() 341 { 342 return innerContext.getEventCartridge(); 343 } 344 345 346 /** 347 * @see org.apache.velocity.context.InternalHousekeepingContext#setCurrentResource(org.apache.velocity.runtime.resource.Resource) 348 */ 349 public void setCurrentResource( Resource r ) 350 { 351 innerContext.setCurrentResource( r ); 352 } 353 354 /** 355 * @see org.apache.velocity.context.InternalHousekeepingContext#getCurrentResource() 356 */ 357 public Resource getCurrentResource() 358 { 359 return innerContext.getCurrentResource(); 360 } 361 } 362 363 364