KickJava   Java API By Example, From Geeks To Geeks.

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


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
25 // Java stuff
26
import java.util.*;
27
28 // TopLink stuff
29
import oracle.toplink.essentials.exceptions.EJBQLException;
30 import oracle.toplink.essentials.expressions.*;
31 import oracle.toplink.essentials.queryframework.*;
32 import oracle.toplink.essentials.internal.localization.*;
33 import oracle.toplink.essentials.internal.sessions.AbstractSession;
34
35 /**
36  * INTERNAL
37  * <p><b>Purpose</b>: A ParseTree contains Node(s). This contains a root Node and provides traversal utilities.
38  * <p><b>Responsibilities</b>:<ul>
39  * <li> Add parameters to the query
40  * <li> Generate an expression for the query
41  * <li> Answer true if the tree has parameters
42  * <li> Maintain the primary class name for the query
43  * <li> Maintain the root of the parse tree
44  * <li> Maintain the context for the parse tree
45  * <li> Maintainthe distinct state for the parse tree
46  * <li> Print the contents of the parse tree on a string
47  * </ul>
48  * @author Jon Driscoll and Joel Lucuik
49  * @since TopLink 4.0
50  */

51 public class ParseTree {
52     private ParseTreeContext context;
53     private QueryNode queryNode;
54     private FromNode fromNode;
55     private SetNode setNode;
56     private WhereNode whereNode;
57     private OrderByNode orderByNode = null;
58     private GroupByNode groupByNode = null;
59     private HavingNode havingNode = null;
60     private ClassLoader JavaDoc classLoader = null;
61     private short distinctState = ObjectLevelReadQuery.UNCOMPUTED_DISTINCT;
62     private boolean validated = false;
63     private Set unusedVariables = null;
64
65     /**
66      * Return a new ParseTree.
67      */

68     public ParseTree() {
69         super();
70     }
71
72     /**
73       * INTERNAL
74       * Adjust the reference class of the passed query if necessary
75       *
76       * Need to test this for Employee, employee.getAddress(), report query
77       */

78     public void adjustReferenceClassForQuery(DatabaseQuery theQuery, GenerationContext generationContext) {
79         Class JavaDoc referenceClass = getReferenceClass(theQuery, generationContext);
80         if ((referenceClass != null) && (referenceClass != theQuery.getReferenceClass())) {
81             if (theQuery.isObjectLevelReadQuery()) {
82                 // The referenceClass needs to be changed.
83
// This should only happen in an ejbSelect...
84
((ObjectLevelReadQuery)theQuery).setReferenceClass(referenceClass);
85                 generationContext.setBaseQueryClass(referenceClass);
86                 ((ObjectLevelReadQuery)theQuery).changeDescriptor(generationContext.getSession());
87             } else if (theQuery.isUpdateAllQuery()) {
88                 ((UpdateAllQuery)theQuery).setReferenceClass(referenceClass);
89             } else if (theQuery.isDeleteAllQuery()) {
90                 ((DeleteAllQuery)theQuery).setReferenceClass(referenceClass);
91             }
92         }
93     }
94
95     /**
96      * INTERNAL
97      * Initialize the base expression in the generation context.
98      */

99     public void initBaseExpression(ObjectLevelReadQuery theQuery, GenerationContext generationContext) {
100         String JavaDoc variable = getFromNode().getFirstVariable();
101         ParseTreeContext context = generationContext.getParseTreeContext();
102         if (context.isRangeVariable(variable)) {
103             Class JavaDoc referenceClass = theQuery.getReferenceClass();
104             // Create a new expression builder for the reference class
105
ExpressionBuilder builder = new ExpressionBuilder(referenceClass);
106             // Use the expression builder as the default expression builder for the query
107
theQuery.setExpressionBuilder(builder);
108             // Add the expression builder to the expression cache in the context
109
generationContext.setBaseExpression(variable, builder);
110         } else {
111             // Get the declaring node for the variable
112
Node path = context.pathForVariable(variable);
113             // Get the ExpressionBuilder of the ranle variable for the path
114
Class JavaDoc baseClass = getBaseExpressionClass(path, generationContext);
115             // Use the base ExpressionBuilder as the default for the query
116
theQuery.setExpressionBuilder(new ExpressionBuilder(baseClass));
117             // and change the refernce class accordingly
118
theQuery.setReferenceClass(baseClass);
119             theQuery.changeDescriptor(generationContext.getSession());
120             generationContext.setBaseQueryClass(baseClass);
121             // Set the node expression as base expression
122
generationContext.setBaseExpression(
123                 variable, path.generateExpression(generationContext));
124         }
125     }
126
127     /**
128      * INTERNAL
129      * Initialize the base expression in the generation context.
130      */

131     public void initBaseExpression(ModifyAllQuery theQuery, GenerationContext generationContext) {
132         ModifyNode queryNode = (ModifyNode)getQueryNode();
133         String JavaDoc variable = queryNode.getAbstractSchemaIdentifier();
134         if (variable == null) {
135             // UPDATE and DELETE may not define a variable =>
136
// use schema name as variable
137
variable = queryNode.getAbstractSchemaName();
138         }
139         Class JavaDoc referenceClass = theQuery.getReferenceClass();
140         // Create a new expression builder for the reference class
141
ExpressionBuilder builder = new ExpressionBuilder(referenceClass);
142         // Use the expression builder as the default expression builder for the query
143
theQuery.setExpressionBuilder(builder);
144         // Add the expression builder to the expression cache in the context
145
generationContext.setBaseExpression(variable, builder);
146     }
147     
148     /** */
149     private Class JavaDoc getBaseExpressionClass(Node node, GenerationContext generationContext) {
150         ParseTreeContext context = generationContext.getParseTreeContext();
151         Class JavaDoc clazz = null;
152         if (node == null) {
153             clazz = null;
154         } else if (node.isDotNode()) {
155             // DotNode: delegate to left
156
clazz = getBaseExpressionClass(node.getLeft(), generationContext);
157         } else if (node.isVariableNode()) {
158             // VariableNode
159
String JavaDoc variable = ((VariableNode)node).getVariableName();
160             if (!context.isRangeVariable(variable)) {
161                 Node path = context.pathForVariable(variable);
162                 // Variable is defined in JOIN/IN clause =>
163
// return the Class from its definition
164
clazz = getBaseExpressionClass(path, generationContext);
165             } else {
166                 // Variable is defined in range variable decl =>
167
// return its class
168
String JavaDoc schema = context.schemaForVariable(variable);
169                 if (schema != null) {
170                     clazz = context.classForSchemaName(schema, generationContext);
171                 }
172             }
173         }
174         return clazz;
175     }
176
177     /**
178      * INTERNAL
179      * Validate the parse tree.
180      */

181     protected void validate(AbstractSession session, ClassLoader JavaDoc classLoader) {
182         validate(new TypeHelperImpl(session, classLoader));
183     }
184
185     /**
186      * INTERNAL
187      * Validate the parse tree.
188      */

189     public void validate(TypeHelper typeHelper) {
190         ParseTreeContext context = getContext();
191         context.setTypeHelper(typeHelper);
192         validate(context);
193     }
194     
195     /**
196      * INTERNAL
197      * Validate the parse tree.
198      */

199     public void validate(ParseTreeContext context) {
200         if (validated) {
201             // already validated => return
202
return;
203         }
204         
205         validated = true;
206         context.enterScope();
207         if (fromNode != null) {
208             fromNode.validate(context);
209         }
210         queryNode.validate(context);
211         if (setNode != null) {
212             setNode.validate(context);
213         }
214         if (whereNode != null) {
215             whereNode.validate(context);
216         }
217         if (hasOrderBy()) {
218             orderByNode.validate(context, (SelectNode)queryNode);
219         }
220         if (hasGroupBy()) {
221             groupByNode.validate(context, (SelectNode)queryNode);
222         }
223         if (hasHaving()) {
224             havingNode.validate(context, groupByNode);
225         }
226         // store the set od unused variable for later use
227
unusedVariables = context.getUnusedVariables();
228         context.leaveScope();
229     }
230
231     /**
232      * INTERNAL
233      * Add the ordering to the passed query
234      */

235     public void addOrderingToQuery(ObjectLevelReadQuery theQuery, GenerationContext generationContext) {
236         if (hasOrderBy()) {
237             ((OrderByNode)getOrderByNode()).addOrderingToQuery(theQuery, generationContext);
238         }
239     }
240
241     /**
242      * INTERNAL
243      * Add the grouping to the passed query
244      */

245     public void addGroupingToQuery(ObjectLevelReadQuery theQuery, GenerationContext generationContext) {
246         if (hasGroupBy()) {
247             ((GroupByNode)getGroupByNode()).addGroupingToQuery(theQuery, generationContext);
248         }
249     }
250
251     /**
252      * INTERNAL
253      * Add the having to the passed query
254      */

255     public void addHavingToQuery(ObjectLevelReadQuery theQuery, GenerationContext generationContext) {
256         if (hasHaving()) {
257             ((HavingNode)getHavingNode()).addHavingToQuery(theQuery, generationContext);
258         }
259     }
260
261     /**
262      * INTERNAL
263      */

264     public void addNonFetchJoinAttributes(ObjectLevelReadQuery theQuery, GenerationContext generationContext) {
265         ParseTreeContext context = generationContext.getParseTreeContext();
266         for (Iterator i = unusedVariables.iterator(); i.hasNext();) {
267             String JavaDoc variable = (String JavaDoc)i.next();
268             Expression expr = null;
269             if (!context.isRangeVariable(variable)) {
270                 Node path = context.pathForVariable(variable);
271                 expr = path.generateExpression(generationContext);
272                 theQuery.addNonFetchJoinedAttribute(expr);
273             } else {
274                 // unused range variable => not supported yet
275
throw EJBQLException.notYetImplemented(
276                     "Variable [" + variable + "] is defined in a range variable declaration, but not used in the rest of the query.");
277             }
278         }
279     }
280
281     /**
282      * INTERNAL
283      * Add the updates to the passed query
284      */

285     public void addUpdatesToQuery(UpdateAllQuery theQuery, GenerationContext generationContext) {
286         if (getSetNode() != null) {
287             ((SetNode)getSetNode()).addUpdatesToQuery(theQuery, generationContext);
288         }
289     }
290
291     /**
292      * INTERNAL
293      * Add parameters to the query
294      */

295     public void addParametersToQuery(DatabaseQuery query) {
296         //Bug#4646580 Add arguments to query
297
if (context.hasParameters()) {
298             for (Iterator i = context.getParameterNames().iterator(); i.hasNext();) {
299                 String JavaDoc param = (String JavaDoc)i.next();
300                 Class JavaDoc type = (Class JavaDoc)context.getParameterType(param);
301                 if (type == null) {
302                     type = Object JavaDoc.class;
303                 }
304                 query.addArgument(param, type);
305             }
306         }
307     }
308     
309     /**
310      * INTERNAL
311      * Apply the select or update to the passed query.
312      * If there is a single attribute being selected, add it to the query result set
313      * If an aggregate is being used, add it to the query result set
314      */

315     public void applyQueryNodeToQuery(DatabaseQuery theQuery, GenerationContext generationContext) {
316         getQueryNode().applyToQuery(theQuery, generationContext);
317     }
318
319     /**
320      * INTERNAL
321      * Build the context to be used when generating the expression from the parse tree
322      */

323     public GenerationContext buildContext(DatabaseQuery query, AbstractSession sessionForContext) {
324         if (query.isObjectLevelReadQuery()) {
325             return buildContextForReadQuery(sessionForContext);
326         } else if (query.isUpdateAllQuery() || query.isDeleteAllQuery()) {
327             return new GenerationContext(getContext(), sessionForContext, this);
328         }
329         return null;
330     }
331
332     /**
333      * INTERNAL
334      * Build the context to be used when generating the expression from the parse tree
335      */

336     public GenerationContext buildContextForReadQuery(AbstractSession sessionForContext) {
337         return new SelectGenerationContext(getContext(), sessionForContext, this);
338     }
339
340     /**
341      * INTERNAL
342      * Build a context for the expression generation
343      */

344     public Expression generateExpression(DatabaseQuery readQuery, GenerationContext generationContext) {
345         Expression selectExpression = getQueryNode().generateExpression(generationContext);
346         if (getWhereNode() == null) {
347             return selectExpression;
348         }
349         Expression whereExpression = getWhereNode().generateExpression(generationContext);
350
351         selectExpression = getQueryNode().generateExpression(generationContext);
352         if (selectExpression != null) {
353             whereExpression = selectExpression.and(whereExpression);
354         }
355         return whereExpression;
356     }
357
358     /**
359      * Return the context for this parse tree
360      */

361     public ParseTreeContext getContext() {
362         return context;
363     }
364
365     /**
366      * INTERNAL
367      * Return the FROM Node
368      */

369     public FromNode getFromNode() {
370         return fromNode;
371     }
372
373     /**
374      * INTERNAL
375      * Return a class loader
376      * @return java.lang.ClassLoader
377      */

378     public ClassLoader JavaDoc getClassLoader() {
379         if (classLoader == null) {
380             return oracle.toplink.essentials.internal.helper.ConversionManager.getDefaultManager().getLoader();
381         } else {
382             return classLoader;
383         }
384     }
385
386     /**
387      * INTERNAL
388      * Return the OrderByNode
389      */

390     public OrderByNode getOrderByNode() {
391         return orderByNode;
392     }
393
394     /**
395      * INTERNAL
396      * Return the GroupByNode
397      */

398     public GroupByNode getGroupByNode() {
399         return groupByNode;
400     }
401
402     /**
403      * INTERNAL
404      * Return the HavingNode
405      */

406     public HavingNode getHavingNode() {
407         return havingNode;
408     }
409
410     /**
411      * getReferenceClass(): Answer the class which will be the reference class for the query.
412      * Resolve this using the node parsed from the "SELECT" of the EJBQL query string
413      */

414     public Class JavaDoc getReferenceClass(DatabaseQuery query, GenerationContext generationContext) {
415         if (getQueryNode() == null) {
416             return null;
417         }
418         return getQueryNode().getReferenceClass(generationContext);
419     }
420
421     /**
422      * INTERNAL
423      * Return the root node for the tree
424      */

425     public QueryNode getQueryNode() {
426         return queryNode;
427     }
428
429     /**
430      * INTERNAL
431      * Return the set node for the tree
432      */

433     public SetNode getSetNode() {
434         return setNode;
435     }
436
437     /**
438      * INTERNAL
439      * Return the Where node
440      */

441     public WhereNode getWhereNode() {
442         return whereNode;
443     }
444
445     /**
446      * INTERNAL
447      * Return the DISTINCT state for the tree
448      */

449     public short getDistinctState() {
450         return distinctState;
451     }
452
453     /**
454      * INTERNAL
455      * Does this EJBQL have an Ordering Clause
456      */

457     public boolean hasOrderBy() {
458         return getOrderByNode() != null;
459     }
460
461     /**
462      * INTERNAL
463      * Does this EJBQL have a Grouping Clause
464      */

465     public boolean hasGroupBy() {
466         return getGroupByNode() != null;
467     }
468
469     /**
470      * INTERNAL
471      * Does this EJBQL have a Having Clause
472      */

473     public boolean hasHaving() {
474         return getHavingNode() != null;
475     }
476
477     /**
478      * INTERNAL:
479      * Set the class loader for this parse tree
480      * @param loader
481      */

482     public void setClassLoader(ClassLoader JavaDoc loader){
483         this.classLoader = loader;
484     }
485
486     /**
487      * INTERNAL
488      * Set the context for this parse tree
489      */

490     public void setContext(ParseTreeContext newContext) {
491         context = newContext;
492     }
493
494     /**
495      * INTERNAL
496      * Set the FROM node for the query
497      */

498     public void setFromNode(FromNode fromNode) {
499         this.fromNode = fromNode;
500     }
501
502     /**
503      * INTERNAL
504      * Set the Order by node
505      */

506     public void setOrderByNode(OrderByNode newOrderByNode) {
507         orderByNode = newOrderByNode;
508     }
509
510     /**
511      * INTERNAL
512      * Set the Group by node
513      */

514     public void setGroupByNode(GroupByNode newGroupByNode) {
515         groupByNode = newGroupByNode;
516     }
517
518     /**
519      * INTERNAL
520      * Set the Having node
521      */

522     public void setHavingNode(HavingNode newHavingNode) {
523         havingNode = newHavingNode;
524     }
525
526     public void setSelectionCriteriaForQuery(DatabaseQuery theQuery, GenerationContext generationContext) {
527         theQuery.setSelectionCriteria(generateExpression(theQuery, generationContext));
528     }
529
530     /**
531      * INTERNAL
532      * Set the Select node
533      */

534     public void setQueryNode(QueryNode newQueryNode) {
535         queryNode = newQueryNode;
536     }
537
538     /**
539      * INTERNAL
540      * Set the Where node
541      */

542     public void setSetNode(SetNode newSetNode) {
543         setNode = newSetNode;
544     }
545
546     /**
547      * INTERNAL
548      * Set the Where node
549      */

550     public void setWhereNode(WhereNode newWhereNode) {
551         whereNode = newWhereNode;
552     }
553
554     /**
555      * INTERNAL
556      * Set the DISTINCT state for the tree
557      */

558     public void setDistinctState(short newDistinctState) {
559         distinctState = newDistinctState;
560     }
561
562     /**
563      * INTERNAL
564      * Print the contents of the parse tree on a string
565      */

566     public String JavaDoc toString() {
567         StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
568         buffer.append(getContext().toString());
569         return ToStringLocalization.buildMessage("context", (Object JavaDoc[])null) + " " + buffer.toString();
570     }
571
572     /**
573      * INTERNAL
574      * Verify that the alias in the SELECT is valid.
575      * Invalid: SELECT OBJECT(badAlias) FROM Employee employee....
576      * Valid: SELECT OBJECT(employee) FROM Employee employee....
577      */

578     public void verifySelect(DatabaseQuery theQuery, GenerationContext generationContext) {
579         if (theQuery.isObjectLevelReadQuery()) {
580             //verify the selected alias,
581
//this will throw an error if the alias is bad
582
((SelectNode)getQueryNode()).verifySelectedAlias(generationContext);
583         }
584     }
585
586     /**
587      * INTERNAL
588      * Answer true if DISTINCT has been chosen.
589      */

590     public boolean usesDistinct() {
591         return distinctState == ObjectLevelReadQuery.USE_DISTINCT;
592     }
593 }
594
Popular Tags