• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package org.apache.velocity.runtime.directive;
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 org.apache.velocity.Template;
23 
24 import java.util.AbstractMap;
25 import java.util.HashMap;
26 import java.util.Map;
27 import java.util.Set;
28 
29 /**
30  * This handles context scoping and metadata for directives.
31  *
32  * @author Nathan Bubna
33  * @version $Id$
34  */
35 public class Scope extends AbstractMap<Object, Object>
36 {
37     private static final String setReturnValue = "";
38     private Map<Object, Object> storage;
39     private Object replaced;
40     private Scope parent;
41     private Info info;
42     protected final Object owner;
43 
44     /**
45      * @param owner
46      * @param previous
47      */
Scope(Object owner, Object previous)48     public Scope(Object owner, Object previous)
49     {
50         this.owner = owner;
51         if (previous != null)
52         {
53             try
54             {
55                 this.parent = (Scope)previous;
56             }
57             catch (ClassCastException cce)
58             {
59                 this.replaced = previous;
60             }
61         }
62     }
63 
getStorage()64     private Map<Object, Object> getStorage()
65     {
66         if (storage == null)
67         {
68             storage = new HashMap<>();
69         }
70         return storage;
71     }
72 
73     /**
74      * @return entry set
75      */
76     @Override
entrySet()77     public Set<Map.Entry<Object, Object>> entrySet()
78     {
79         return getStorage().entrySet();
80     }
81 
82     /**
83      * getter
84      * @param key
85      * @return found value
86      */
87     @Override
get(Object key)88     public Object get(Object key)
89     {
90         Object o = super.get(key);
91         if (o == null && parent != null && !containsKey(key))
92         {
93             return parent.get(key);
94         }
95         return o;
96     }
97 
98     /**
99      * setter
100      * @param key
101      * @param value
102      * @return previous value
103      */
104     @Override
put(Object key, Object value)105     public Object put(Object key, Object value)
106     {
107         return getStorage().put(key, value);
108     }
109 
110     /**
111      * Convenience method to call put(key,val) in a template
112      * without worrying about what is returned/rendered by the call.
113      * This should ALWAYS return an empty string.
114      * @param key
115      * @param value
116      * @return empty string
117      */
set(Object key, Object value)118     public String set(Object key, Object value)
119     {
120         put(key, value);
121         return setReturnValue;
122     }
123 
124     /**
125      * Allows #stop to easily trigger the proper StopCommand for this scope.
126      */
stop()127     protected void stop()
128     {
129         throw new StopCommand(owner);
130     }
131 
132     /**
133      * Returns the number of control arguments of this type
134      * that are stacked up.  This is the distance between this
135      * instance and the topmost instance, plus one. This value
136      * will never be negative or zero.
137      * @return depth
138      */
getDepth()139     protected int getDepth()
140     {
141         if (parent == null)
142         {
143             return 1;
144         }
145         return parent.getDepth() + 1;
146     }
147 
148     /**
149      * Returns the topmost parent control reference, retrieved
150      * by simple recursion on {@link #getParent}.
151      * @return top-most scope
152      */
getTopmost()153     public Scope getTopmost()
154     {
155         if (parent == null)
156         {
157             return this;
158         }
159         return parent.getTopmost();
160     }
161 
162     /**
163      * Returns the parent control reference overridden by the placement
164      * of this instance in the context.
165      * @return parent scope
166      */
getParent()167     public Scope getParent()
168     {
169         return parent;
170     }
171 
172     /**
173      * Returns the user's context reference overridden by the placement
174      * of this instance in the context.  If there was none (as is hoped),
175      * then this will return null.  This never returns parent controls;
176      * those are returned by {@link #getParent}.
177      * @return replaced reference value, or null
178      */
getReplaced()179     public Object getReplaced()
180     {
181         if (replaced == null && parent != null)
182         {
183             return parent.getReplaced();
184         }
185         return replaced;
186     }
187 
188     /**
189      * Returns info about the current scope for debugging purposes.
190      * @return template debugging infos
191      */
getInfo()192     public Info getInfo()
193     {
194         if (info == null)
195         {
196             info = new Info(this, owner);
197         }
198         return info;
199     }
200 
201     /**
202      * Class to encapsulate and provide access to info about
203      * the current scope for debugging.
204      */
205     public static class Info
206     {
207         private Scope scope;
208         private Directive directive;
209         private Template template;
210 
211         /**
212          * c'tor
213          * @param scope
214          * @param owner
215          */
Info(Scope scope, Object owner)216         public Info(Scope scope, Object owner)
217         {
218             if (owner instanceof Directive)
219             {
220                 directive = (Directive)owner;
221             }
222             if (owner instanceof Template)
223             {
224                 template = (Template)owner;
225             }
226             this.scope = scope;
227         }
228 
229         /**
230          * name getter
231          * @return name
232          */
getName()233         public String getName()
234         {
235             if (directive != null)
236             {
237                 return directive.getName();
238             }
239             if (template != null)
240             {
241                 return template.getName();
242             }
243             return null;
244         }
245 
246         /**
247          * type getter
248          * @return scope type
249          */
getType()250         public String getType()
251         {
252             if (directive != null)
253             {
254                 switch (directive.getType())
255                 {
256                     case Directive.BLOCK:
257                         return "block";
258                     case Directive.LINE:
259                         return "line";
260                 }
261             }
262             if (template != null)
263             {
264                 return template.getEncoding();
265             }
266             return null;
267         }
268 
269         /**
270          * current depth
271          * @return depth
272          */
getDepth()273         public int getDepth()
274         {
275             return scope.getDepth();
276         }
277 
278         /**
279          * template name getter
280          * @return template name
281          */
getTemplate()282         public String getTemplate()
283         {
284             if (directive != null)
285             {
286                 return directive.getTemplateName();
287             }
288             if (template != null)
289             {
290                 return template.getName();
291             }
292             return null;
293         }
294 
295         /**
296          * line getter
297          * @return line number
298          */
getLine()299         public int getLine()
300         {
301             if (directive != null)
302             {
303                 return directive.getLine();
304             }
305             return 0;
306         }
307 
308         /**
309          * column getter
310          * @return column number
311          */
getColumn()312         public int getColumn()
313         {
314             if (directive != null)
315             {
316                 return directive.getColumn();
317             }
318             return 0;
319         }
320 
321         /**
322          * string representation getter
323          * @return string representation
324          */
toString()325         public String toString()
326         {
327             StringBuilder sb = new StringBuilder();
328             if (directive != null)
329             {
330                 sb.append('#'); // parser characters substitution is not handled here
331             }
332             sb.append(getName());
333             sb.append("[type:").append(getType());
334             int depth = getDepth();
335             if (depth > 1)
336             {
337                 sb.append(" depth:").append(depth);
338             }
339             if (template == null)
340             {
341                 String vtl = getTemplate();
342                 sb.append(" template:");
343                 if (!vtl.contains(" "))
344                 {
345                     sb.append(vtl);
346                 }
347                 else
348                 {
349                     sb.append('"').append(vtl).append('"');
350                 }
351                 sb.append(" line:").append(getLine());
352                 sb.append(" column:").append(getColumn());
353             }
354             sb.append(']');
355             return sb.toString();
356         }
357     }
358 
359 }
360