KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > oracle > toplink > essentials > internal > parsing > ParseTreeContext


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the "License"). You may not use this file except
5  * in compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * glassfish/bootstrap/legal/CDDLv1.0.txt or
9  * https://glassfish.dev.java.net/public/CDDLv1.0.html.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * HEADER in each file and include the License file at
15  * glassfish/bootstrap/legal/CDDLv1.0.txt. If applicable,
16  * add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your
18  * own identifying information: Portions Copyright [yyyy]
19  * [name of copyright owner]
20  */

21 // Copyright (c) 1998, 2006, Oracle. All rights reserved.
22
package oracle.toplink.essentials.internal.parsing;
23
24 import java.util.*;
25 import oracle.toplink.essentials.internal.localization.*;
26 import oracle.toplink.essentials.descriptors.ClassDescriptor;
27 import oracle.toplink.essentials.exceptions.EJBQLException;
28
29 /**
30  * INTERNAL
31  * <p><b>Purpose</b>: The ParseTreeContext holds and manages context information for the parse tree for validation.
32  * <p><b>Responsibilities</b>:<ul>
33  * <li> Associate schema names with variables
34  * <li> Associate identifier with nodes
35  * <li> Answer an alias for a variable name
36  * <li> Answer a class for a variable name
37  * <li> Answer a class loader
38  * <li> Answer true if there is a class for a variable name
39  * <li> Answer a node for a given identifier
40  * <li> Print the context on a string
41  * </ul>
42  * @see ParseTree
43  * @author Jon Driscoll and Joel Lucuik
44  * @since TopLink 4.0
45  */

46 public class ParseTreeContext {
47     private Map variableDecls;
48     private int currentScope;
49     private Set outerScopeVariables;
50     private Map fetchJoins;
51     private TypeHelper typeHelper;
52     private Map parameterTypes;
53     private List parameterNames;
54     
55     /**
56      * INTERNAL
57      * Return a new initialized ParseTreeContext
58      */

59     public ParseTreeContext() {
60         super();
61         variableDecls = new HashMap();
62         currentScope = 0;
63         fetchJoins = new HashMap();
64         typeHelper = null;
65         parameterTypes = new HashMap();
66         parameterNames = new ArrayList();
67     }
68
69     /**
70      * INTERNAL
71      * Associate the given schema with the given variable.
72      */

73     public void registerSchema(String JavaDoc variable, String JavaDoc schema) {
74         VariableDecl decl = (VariableDecl)variableDecls.get(variable);
75         if (decl == null) {
76             decl = new VariableDecl(variable, schema);
77             variableDecls.put(variable, decl);
78         } else {
79             String JavaDoc text = decl.isRangeVariable ? decl.schema : decl.path.getAsString();
80             throw EJBQLException.multipleVariableDeclaration(variable, text);
81         }
82     }
83
84     /**
85      * INTERNAL
86      * Associate the given path with the given variable.
87      */

88     public void registerJoinVariable(String JavaDoc variable, Node path) {
89         VariableDecl decl = (VariableDecl)variableDecls.get(variable);
90         if (decl == null) {
91             decl = new VariableDecl(variable, path);
92             variableDecls.put(variable, decl);
93         } else {
94             String JavaDoc text = decl.isRangeVariable ? decl.schema : decl.path.getAsString();
95             throw EJBQLException.multipleVariableDeclaration(variable, text);
96         }
97     }
98
99     /**
100      * INTERNAL
101      * Returns true if the specified string denotes a variable.
102      */

103     public boolean isVariable(String JavaDoc variable) {
104         VariableDecl decl = (VariableDecl)variableDecls.get(variable);
105         return decl != null;
106     }
107
108     /**
109      * INTERNAL
110      * Returns true if the specified string denotes a range variable.
111      */

112     /** */
113     public boolean isRangeVariable(String JavaDoc variable) {
114         VariableDecl decl = (VariableDecl)variableDecls.get(variable);
115         return (decl != null) && decl.isRangeVariable;
116     }
117
118     /**
119      * INTERNAL
120      * Returns the abstract schema name if the specified string denotes a
121      * range variable.
122      */

123     public String JavaDoc schemaForVariable(String JavaDoc variable) {
124         VariableDecl decl = (VariableDecl)variableDecls.get(variable);
125         return (decl != null) ? decl.schema : null;
126     }
127
128     /**
129      * INTERNAL
130      * Answer the class associated with the provided schema name
131      */

132     public Class JavaDoc classForSchemaName(String JavaDoc schemaName, GenerationContext context) {
133         ClassDescriptor descriptor = context.getSession().getDescriptorForAlias(schemaName);
134         if (descriptor == null) {
135             throw EJBQLException.missingDescriptorException(schemaName);
136         }
137         Class JavaDoc theClass = descriptor.getJavaClass();
138         if (theClass == null) {
139             throw EJBQLException.resolutionClassNotFoundException(schemaName);
140         }
141         return theClass;
142     }
143
144     /**
145      * INTERNAL
146      * getVariableNameForClass():
147      * Answer the name mapped to the specified class. Answer null if none found.
148      * SELECT OBJECT (emp) FROM Employee emp
149      * getVariableNameForClass(Employee.class) => "emp"
150      */

151     public String JavaDoc getVariableNameForClass(Class JavaDoc theClass, GenerationContext context) {
152         for (Iterator i = variableDecls.entrySet().iterator(); i.hasNext(); ) {
153             Map.Entry entry = (Map.Entry)i.next();
154             String JavaDoc nextVariable = (String JavaDoc)entry.getKey();
155             VariableDecl decl = (VariableDecl)entry.getValue();
156             if ((decl.schema != null) &&
157                 (theClass == this.classForSchemaName(decl.schema, context))) {
158                 return nextVariable;
159             }
160         }
161         return null;
162     }
163
164     /**
165      * INTERNAL
166      * Returns the path if the specified string denotes a join or collection
167      * member variable.
168      */

169     public Node pathForVariable(String JavaDoc variable) {
170         VariableDecl decl = (VariableDecl)variableDecls.get(variable);
171         return (decl != null) ? decl.path : null;
172     }
173
174     /**
175      * INTERNAL
176      * Returns true if the specified string denotes a variable declared in an
177      * outer scope.
178      */

179     public boolean isDeclaredInOuterScope(String JavaDoc variable) {
180         VariableDecl decl = (VariableDecl)variableDecls.get(variable);
181         return (decl != null) ? (decl.scope < currentScope) : false;
182     }
183
184     /**
185      * INTERNAL
186      * Sets the scope of the specified variable to the current scope.
187      */

188     public void setScopeOfVariable(String JavaDoc variable) {
189         VariableDecl decl = (VariableDecl)variableDecls.get(variable);
190         if (decl != null) {
191             decl.scope = currentScope;
192         }
193     }
194
195     /**
196      * INTERNAL
197      * Enters a new scope. This initializes the set of outer scope variables.
198      */

199     public void enterScope() {
200         currentScope++;
201         resetOuterScopeVariables();
202     }
203     
204     /**
205      * INTERNAL
206      * Leaves the current scope.
207      */

208     public void leaveScope() {
209         currentScope--;
210     }
211
212     /**
213      * INTERNAL
214      * Adds the specified variable to the set of outer scope variables.
215      */

216     public void registerOuterScopeVariable(String JavaDoc variable) {
217         outerScopeVariables.add(variable);
218     }
219
220     /**
221      * INTERNAL
222      * Returns the set of outer scope variables.
223      */

224     public Set getOuterScopeVariables() {
225         return outerScopeVariables;
226     }
227
228     /**
229      * INTERNAL
230      * Resets the set of outer scope variables.
231      */

232     public void resetOuterScopeVariables() {
233         outerScopeVariables = new HashSet();
234     }
235
236     /**
237      * INTERNAL
238      * Resets the set of outer scope variables.
239      */

240     public void resetOuterScopeVariables(Set variables) {
241         outerScopeVariables = variables;
242     }
243
244     /**
245      * Associate the given variableName with the given node representating a
246      * JOIN FETCH node.
247      */

248     public void registerFetchJoin(String JavaDoc variableName, Node node) {
249         List joins = (List)fetchJoins.get(variableName);
250         if (joins == null) {
251             joins = new ArrayList();
252             fetchJoins.put(variableName, joins);
253         }
254         joins.add(node);
255     }
256
257     /** Returns alist of FETCH JOIN nodes for the specified attached to the
258      * specified variable. */

259     public List getFetchJoins(String JavaDoc variableName) {
260         return (List)fetchJoins.get(variableName);
261     }
262
263     /** Mark the specified variable as used if it is declared in the current
264      * scope. */

265     public void usedVariable(String JavaDoc variable) {
266         VariableDecl decl = (VariableDecl)variableDecls.get(variable);
267         if ((decl != null) && (decl.scope == currentScope)) {
268             decl.used = true;
269         }
270     }
271
272     /** Returns s set of variables that are declared in the current scope,
273      * but not used in the query. */

274     public Set getUnusedVariables() {
275         Set unused = new HashSet();
276         for (Iterator i = variableDecls.entrySet().iterator(); i.hasNext();) {
277             Map.Entry entry = (Map.Entry)i.next();
278             String JavaDoc variable = (String JavaDoc)entry.getKey();
279             VariableDecl decl = (VariableDecl)entry.getValue();
280             if ((decl.scope == currentScope) && !decl.used) {
281                 unused.add(variable);
282             }
283         }
284         return unused;
285     }
286     
287     //answer true if two or more variables are mapped to the same type name in variableTypes
288
//true => "SELECT OBJECT (emp1) FROM Employee emp1, Employee emp2 WHERE ..."
289
//false => "SELECT OBJECT (emp) FROM Employee emp WHERE ..."
290
public boolean hasMoreThanOneVariablePerType() {
291         Map typeNamesToVariables = new HashMap();
292         int nrOfRangeVariables = 0;
293         //Map the Aliases to the variable names, then check the count
294
for (Iterator i = variableDecls.entrySet().iterator(); i.hasNext(); ) {
295             Map.Entry entry = (Map.Entry)i.next();
296             String JavaDoc variable = (String JavaDoc)entry.getKey();
297             VariableDecl decl = (VariableDecl)entry.getValue();
298             if (decl.isRangeVariable) {
299                 nrOfRangeVariables++;
300                 typeNamesToVariables.put(decl.schema, variable);
301             }
302         }
303         return typeNamesToVariables.size() != nrOfRangeVariables;
304     }
305
306     //answer true if two or more aliases are involved in the FROM (different types)
307
//true => "SELECT OBJECT (emp1) FROM Employee emp1, Address addr1 WHERE ..."
308
//false => "SELECT OBJECT (emp) FROM Employee emp WHERE ..."
309
//false => "SELECT OBJECT (emp1) FROM Employee emp1, Employee emp2 WHERE ..."
310
public boolean hasMoreThanOneAliasInFrom() {
311         Map typeNamesToVariables = new HashMap();
312         for (Iterator i = variableDecls.entrySet().iterator(); i.hasNext(); ) {
313             Map.Entry entry = (Map.Entry)i.next();
314             String JavaDoc variable = (String JavaDoc)entry.getKey();
315             VariableDecl decl = (VariableDecl)entry.getValue();
316             if (decl.isRangeVariable) {
317                 typeNamesToVariables.put(decl.schema, variable);
318             }
319         }
320         return typeNamesToVariables.size() > 1;
321     }
322
323     /**
324      * INTERNAL
325      * Returns the type helper stored in this context.
326      */

327     public TypeHelper getTypeHelper() {
328         return typeHelper;
329     }
330
331     /**
332      * INTERNAL
333      * Stores the specified type helper in this context.
334      */

335     public void setTypeHelper(TypeHelper typeHelper) {
336         this.typeHelper = typeHelper;
337     }
338     
339     /**
340      * INTERNAL
341      * Add a parameter.
342      */

343     public void addParameter(String JavaDoc parameterName) {
344         if (!parameterNames.contains(parameterName)){
345             parameterNames.add(parameterName);
346         }
347     }
348
349     /**
350      * INTERNAL
351      * Defines the type of the parameter with the specified name.
352      */

353     public void defineParameterType(String JavaDoc parameterName, Object JavaDoc parameterType) {
354         if (parameterTypes.containsKey(parameterName)) {
355             // existing entry
356
Object JavaDoc oldType = parameterTypes.get(parameterName);
357             if (typeHelper.isAssignableFrom(oldType, parameterType)) {
358                 // OK
359
} else if (typeHelper.isAssignableFrom(parameterType, oldType)) {
360                 // new parameter type is more general
361
parameterTypes.put(parameterName, parameterType);
362             } else {
363                 // error case old usage and new usage do not match type
364
throw EJBQLException.invalidMultipleUseOfSameParameter(
365                     parameterName, typeHelper.getTypeName(oldType),
366                     typeHelper.getTypeName(parameterType));
367             }
368         } else {
369             // new entry
370
parameterTypes.put(parameterName, parameterType);
371         }
372     }
373
374     /**
375      * INTERNAL
376      * Returns true if the query has at least one parameter.
377      */

378     public boolean hasParameters() {
379         return !parameterNames.isEmpty();
380     }
381
382     /**
383      * INTERNAL
384      * Return the type of the specified parameter.
385      */

386     public Object JavaDoc getParameterType(String JavaDoc parameter) {
387         return parameterTypes.get(parameter);
388     }
389     
390     /**
391      * INTERNAL
392      * Return the parameter names.
393      */

394     public List getParameterNames() {
395         return parameterNames;
396     }
397
398     /**
399      * INTERNAL
400      * Class defining the type of the values the variableDecls map.
401      * It holds the following values:
402      * variable - the name of the variable
403      * isRangeVariable - true if the variable is declared as range variable
404      * schema - the abstract for a range variable
405      * path - the path for join or collection member variable
406      * scope - the scope of teh variable
407      * used - true if the variable is used in any of the clauses
408      */

409     static class VariableDecl {
410         public final String JavaDoc variable;
411         public final boolean isRangeVariable;
412         public final String JavaDoc schema;
413         public final Node path;
414         public int scope;
415         public boolean used;
416         public VariableDecl(String JavaDoc variable, String JavaDoc schema) {
417             this.variable = variable;
418             this.isRangeVariable = true;
419             this.schema = schema;
420             this.path = null;
421             this.scope = scope;
422             this.used = false;
423         }
424         public VariableDecl(String JavaDoc variable, Node path) {
425             this.variable = variable;
426             this.isRangeVariable = false;
427             this.schema = null;
428             this.path = path;
429             this.scope = scope;
430             this.used = false;
431         }
432     }
433 }
434
Popular Tags