View Javadoc

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 }