View Javadoc

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 java.util.AbstractMap;
23  import java.util.HashMap;
24  import java.util.Map;
25  import java.util.Set;
26  import org.apache.velocity.Template;
27  
28  /**
29   * This handles context scoping and metadata for directives.
30   *
31   * @author Nathan Bubna
32   * @version $Id$
33   */
34  public class Scope extends AbstractMap
35  {
36      private Map storage;
37      private Object replaced;
38      private Scope parent;
39      private Info info;
40      protected final Object owner;
41  
42      public Scope(Object owner, Object previous)
43      {
44          this.owner = owner;
45          if (previous != null)
46          {
47              try
48              {
49                  this.parent = (Scope)previous;
50              }
51              catch (ClassCastException cce)
52              {
53                  this.replaced = previous;
54              }
55          }
56      }
57  
58      private Map getStorage()
59      {
60          if (storage == null)
61          {
62              storage = new HashMap();
63          }
64          return storage;
65      }
66  
67      public Set entrySet()
68      {
69          return getStorage().entrySet();
70      }
71  
72      public Object get(Object key)
73      {
74          Object o = super.get(key);
75          if (o == null && parent != null && !containsKey(key))
76          {
77              return parent.get(key);
78          }
79          return o;
80      }
81  
82      public Object put(Object key, Object value)
83      {
84          return getStorage().put(key, value);
85      }
86  
87      /**
88       * Allows #stop to easily trigger the proper StopCommand for this scope.
89       */
90      protected void stop()
91      {
92          throw new StopCommand(owner);
93      }
94  
95      /**
96       * Returns the number of control arguments of this type
97       * that are stacked up.  This is the distance between this
98       * instance and the topmost instance, plus one. This value
99       * will never be negative or zero.
100      */
101     protected int getDepth()
102     {
103         if (parent == null)
104         {
105             return 1;
106         }
107         return parent.getDepth() + 1;
108     }
109 
110     /**
111      * Returns the topmost parent control reference, retrieved
112      * by simple recursion on {@link #getParent}.
113      */
114     public Scope getTopmost()
115     {
116         if (parent == null)
117         {
118             return this;
119         }
120         return parent.getTopmost();
121     }
122 
123     /**
124      * Returns the parent control reference overridden by the placement
125      * of this instance in the context.
126      */
127     public Scope getParent()
128     {
129         return parent;
130     }
131 
132     /**
133      * Returns the user's context reference overridden by the placement
134      * of this instance in the context.  If there was none (as is hoped),
135      * then this will return null.  This never returns parent controls;
136      * those are returned by {@link #getParent}.
137      */
138     public Object getReplaced()
139     {
140         if (replaced == null && parent != null)
141         {
142             return parent.getReplaced();
143         }
144         return replaced;
145     }
146 
147     /**
148      * Returns info about the current scope for debugging purposes.
149      */
150     public Info getInfo()
151     {
152         if (info == null)
153         {
154             info = new Info(this, owner);
155         }
156         return info;
157     }
158 
159     /**
160      * Class to encapsulate and provide access to info about
161      * the current scope for debugging.
162      */
163     public static class Info
164     {
165         private Scope scope;
166         private Directive directive;
167         private Template template;
168 
169         public Info(Scope scope, Object owner)
170         {
171             if (owner instanceof Directive)
172             {
173                 directive = (Directive)owner;
174             }
175             if (owner instanceof Template)
176             {
177                 template = (Template)owner;
178             }
179             this.scope = scope;
180         }
181 
182         public String getName()
183         {
184             if (directive != null)
185             {
186                 return directive.getName();
187             }
188             if (template != null)
189             {
190                 return template.getName();
191             }
192             return null;
193         }
194 
195         public String getType()
196         {
197             if (directive != null)
198             {
199                 switch (directive.getType())
200                 {
201                     case Directive.BLOCK:
202                         return "block";
203                     case Directive.LINE:
204                         return "line";
205                 }
206             }
207             if (template != null)
208             {
209                 return template.getEncoding();
210             }
211             return null;
212         }
213 
214         public int getDepth()
215         {
216             return scope.getDepth();
217         }
218 
219         public String getTemplate()
220         {
221             if (directive != null)
222             {
223                 return directive.getTemplateName();
224             }
225             if (template != null)
226             {
227                 return template.getName();
228             }
229             return null;
230         }
231 
232         public int getLine()
233         {
234             if (directive != null)
235             {
236                 return directive.getLine();
237             }
238             return 0;
239         }
240 
241         public int getColumn()
242         {
243             if (directive != null)
244             {
245                 return directive.getColumn();
246             }
247             return 0;
248         }
249 
250         public String toString()
251         {
252             StringBuffer sb = new StringBuffer();
253             if (directive != null)
254             {
255                 sb.append('#');
256             }
257             sb.append(getName());
258             sb.append("[type:").append(getType());
259             int depth = getDepth();
260             if (depth > 1)
261             {
262                 sb.append(" depth:").append(depth);
263             }
264             if (template == null)
265             {
266                 String vtl = getTemplate();
267                 sb.append(" template:");
268                 if (vtl.indexOf(" ") < 0)
269                 {
270                     sb.append(vtl);
271                 }
272                 else
273                 {
274                     sb.append('"').append(vtl).append('"');
275                 }
276                 sb.append(" line:").append(getLine());
277                 sb.append(" column:").append(getColumn());
278             }
279             sb.append(']');
280             return sb.toString();
281         }
282     }
283 
284 }