View Javadoc

1   package org.apache.torque.generator.variable;
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.LinkedList;
23  
24  import org.apache.torque.generator.qname.Namespace;
25  import org.apache.torque.generator.qname.QualifiedName;
26  import org.apache.torque.generator.qname.QualifiedNameMap;
27  
28  /**
29   * Stores all variables which are currently accessible.
30   */
31  public class VariableStore
32  {
33      /**
34       * contains all variables with the scope
35       * <code>Variable.Scope.OUTLET<code>.
36       */
37      private QualifiedNameMap<Variable> outletScope
38              = new QualifiedNameMap<Variable>();
39  
40      /**
41       * contains all variables with the scope
42       * <code>Variable.Scope.CHILDREN<code>.
43       * The QualifiedNameMap with the largest index contains the variables added
44       * in the current outlet, and with descending index the variables added
45       * to the respective calling outlets.
46       */
47      private LinkedList<QualifiedNameMap<Variable>> childrenScopeList
48              = new LinkedList<QualifiedNameMap<Variable>>();
49  
50      /**
51       * contains all variables with the scope
52       * <code>Variable.Scope.FILE<code>.
53       */
54      private QualifiedNameMap<Variable> fileScope
55              = new QualifiedNameMap<Variable>();
56  
57      /**
58       * contains all variables with the scope
59       * <code>Variable.Scope.GLOBAL<code>.
60       */
61      private QualifiedNameMap<Variable> globalScope
62              = new QualifiedNameMap<Variable>();
63  
64      /**
65       * Sets a variable.
66       *
67       * @param variable the variable to set.
68       *
69       * @throws NullPointerException if variable is null.
70       */
71      public void set(Variable variable)
72      {
73          if (Variable.Scope.OUTLET.equals(variable.getScope()))
74          {
75              outletScope.put(variable.getName(), variable);
76          }
77          else if (Variable.Scope.CHILDREN.equals(variable.getScope()))
78          {
79              QualifiedNameMap<Variable> qualifiedNameMap
80                  = childrenScopeList.getLast();
81              qualifiedNameMap.put(variable.getName(), variable);
82          }
83          else if (Variable.Scope.FILE.equals(variable.getScope()))
84          {
85              fileScope.put(variable.getName(), variable);
86          }
87          else if (Variable.Scope.GLOBAL.equals(variable.getScope()))
88          {
89              globalScope.put(variable.getName(), variable);
90          }
91      }
92  
93      /**
94       * removes a variable from the store.
95       *
96       * @param variable the variable to remove, not null.
97       *
98       * @throws NullPointerException if variable is null.
99       */
100     public void remove(Variable variable)
101     {
102         if (Variable.Scope.OUTLET.equals(variable.getScope()))
103         {
104             outletScope.remove(variable.getName());
105         }
106         else if (Variable.Scope.CHILDREN.equals(variable.getScope()))
107         {
108             QualifiedNameMap<Variable> qualifiedNameMap
109                 = childrenScopeList.getLast();
110             qualifiedNameMap.remove(variable.getName());
111         }
112         else if (Variable.Scope.FILE.equals(variable.getScope()))
113         {
114             fileScope.remove(variable.getName());
115         }
116         else if (Variable.Scope.GLOBAL.equals(variable.getScope()))
117         {
118             globalScope.remove(variable.getName());
119         }
120     }
121 
122     /**
123      * Signals this store that the processing of a outlet has started.
124      */
125     public void startOutlet()
126     {
127         childrenScopeList.addLast(new QualifiedNameMap<Variable>());
128     }
129 
130     /**
131      * Signals this store that the processing of a outlet has ended.
132      * Removes all variables with the scope
133      * <code>Variable.Scope.OUTLET</code>,
134      * and all variables with the scope <code>Variable.Scope.CHILDREN</code>
135      * which were set by the outlet which processing ended.
136      */
137     public void endOutlet()
138     {
139         outletScope.clear();
140         childrenScopeList.removeLast();
141     }
142 
143     /**
144      * Signals this store that the processing of one file has ended.
145      * Removes all variables with the scope <code>FILE</code>.
146      */
147     public void endFile()
148     {
149         fileScope.clear();
150     }
151 
152     /**
153      * Signals this store that generation has ended. Removes the variables
154      * from all scopes.
155      */
156     public void endGeneration()
157     {
158         clear();
159     }
160 
161     /**
162      * Removes all variables from this store.
163      */
164     public void clear()
165     {
166         outletScope.clear();
167         childrenScopeList.clear();
168         fileScope.clear();
169         globalScope.clear();
170     }
171 
172     /**
173      * Returns a map with the variables contained in this store.
174      * Note that if one variable is hidden by another with a more specific
175      * scope, only the variable with the more specific scope is returned.
176      * <p>
177      * The Map is not backed by this stores, i.e. adding and removing
178      * variables to the returned nmap has no effect on this store.
179      * However, the variables in the returned map are the variables in this
180      * store, i.e. setting the value of the variable will change the variable
181      * in this store.
182      * <p>
183      * Note: The current store content is rebuilt each time this method is
184      * called. For this reason, <code>store.getInHierarchy(qualifiedName)</code>
185      * is much faster than <code>store.getContent().get(qualifiedName)<code>.
186      *
187      * @return a map with the variables contained ins this store, never null.
188      */
189     public QualifiedNameMap<Variable> getContent()
190     {
191         QualifiedNameMap<Variable> result = new QualifiedNameMap<Variable>();
192         result.putAll(globalScope);
193         result.putAll(fileScope);
194 
195         for (QualifiedNameMap<Variable> childrenScope : childrenScopeList)
196         {
197             result.putAll(childrenScope);
198         }
199 
200         result.putAll(outletScope);
201 
202         return result;
203     }
204 
205     /**
206      * Returns the most specific variable which is visible from the key's
207      * namespace and has the same name as the key's name.
208      *
209      * if several most specific variables are found in the different scopes,
210      * the one with the most specific scope is returned.
211      *
212      * @param key The key for the variable.
213      * @return the most specific matching variable, or null if no variable
214      *         matches.
215      */
216     public Variable getInHierarchy(QualifiedName key)
217     {
218         Variable inOutletScope = outletScope.getInHierarchy(key);
219         Variable inFileScope = fileScope.getInHierarchy(key);
220         Variable inGenerationScope = globalScope.getInHierarchy(key);
221 
222         // look through children, with precedence to the outlets which
223         // started later
224         Variable result = null;
225         for (QualifiedNameMap<Variable> childrenScope : childrenScopeList)
226         {
227             Variable inChildrenScope = childrenScope.getInHierarchy(key);
228             result = getMoreSpecific(inChildrenScope, result);
229         }
230         result = getMoreSpecific(inOutletScope, result);
231         result = getMoreSpecific(result, inFileScope);
232         result = getMoreSpecific(result, inGenerationScope);
233         return result;
234     }
235 
236     /**
237      * Returns the more specific variable out of two variables (the variable
238      * which hides the other variable).
239      *
240      * If one of the two variables is null, the other is returned.
241      * If both variables is null, null is returned.
242      * If both variables are in the same namespace, variable1 is returned.
243      *
244      * It is assumed that variable1 is in an ancestor namespace of
245      * variable2 or that variable 2 is in an ancestor namespace of
246      * variable1 or both variables are in the same namespace.
247      *
248      * @param variable1 the first variable to compare.
249      * @param variable2 the second variable to compare.
250      * @return the more specific variable, or null if both variable1 and
251      *         variable2 are null.
252      *
253      */
254     private Variable getMoreSpecific(Variable variable1, Variable variable2)
255     {
256         if (variable1 == null)
257         {
258             return variable2;
259         }
260         if (variable2 == null)
261         {
262             return variable1;
263         }
264         Namespace variable1Namespace
265                 = variable1.getName().getNamespace();
266         Namespace variable2Namespace
267                 = variable2.getName().getNamespace();
268         if (variable2Namespace.isVisibleFrom(variable1Namespace))
269         {
270             // variable1 is more specific or in the same naemspace
271             // as variable2, so return variable1
272             return variable1;
273         }
274         else
275         {
276             // variable2 is more specific than variable1
277             return variable2;
278         }
279     }
280 }