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 }
180
181 public int getDepth()
182 {
183 return scope.getDepth();
184 }
185
186 public String getName()
187 {
188 if (directive != null)
189 {
190 return directive.getName();
191 }
192 if (template != null)
193 {
194 return template.getName();
195 }
196 return null;
197 }
198
199 public int getLine()
200 {
201 if (directive != null)
202 {
203 return directive.getLine();
204 }
205 return 0;
206 }
207
208 public int getColumn()
209 {
210 if (directive != null)
211 {
212 return directive.getColumn();
213 }
214 return 0;
215 }
216
217 public String getType()
218 {
219 if (directive != null)
220 {
221 switch (directive.getType())
222 {
223 case Directive.BLOCK:
224 return "block";
225 case Directive.LINE:
226 return "line";
227 }
228 }
229 if (template != null)
230 {
231 return template.getEncoding();
232 }
233 return null;
234 }
235
236 public String getTemplate()
237 {
238 if (directive != null)
239 {
240 return directive.getTemplateName();
241 }
242 if (template != null)
243 {
244 return template.getName();
245 }
246 return null;
247 }
248 }
249
250 }