KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > oracle > toplink > essentials > expressions > ExpressionBuilder


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.expressions;
23
24 import java.util.*;
25 import java.io.*;
26 import oracle.toplink.essentials.exceptions.*;
27 import oracle.toplink.essentials.queryframework.*;
28 import oracle.toplink.essentials.internal.helper.*;
29 import oracle.toplink.essentials.internal.expressions.*;
30 import oracle.toplink.essentials.internal.sessions.AbstractRecord;
31 import oracle.toplink.essentials.internal.sessions.AbstractSession;
32 import oracle.toplink.essentials.descriptors.ClassDescriptor;
33
34 /**
35  * <P>
36  * <B>Purpose</B>: Allow for instances of expression to be created. Expressions are Java object-level representations of SQL "where" clauses.
37  * The expressions attempt to mirror Java code as closely as possible.</p>
38  *
39  * <P>
40  *
41  * <B>Example</B>:
42  * <PRE><BLOCKQUOTE>
43  * ExpressionBuilder employee = new ExpressionBuilder();
44  * employee.get("firstName").equal("Bob").and(employee.get("lastName").equal("Smith"))
45  *
46  * >> equivalent Java code: (employee.getFirstName().equals("Bob")) && (employee.getLastName().equals("Smith"))
47  *
48  * >> equivalent SQL: (F_NAME = 'Bob') AND (L_NAME = 'Smith')
49  * </BLOCKQUOTE></PRE>
50  *
51  * @see Expression
52  */

53 public class ExpressionBuilder extends ObjectExpression {
54     protected transient AbstractSession session;
55     protected Class JavaDoc queryClass;
56     protected SQLSelectStatement statement;
57     protected DatabaseTable viewTable;
58     protected DatabaseTable aliasedViewTable;
59     
60     protected boolean wasQueryClassSetInternally = true;
61     
62     protected boolean wasAdditionJoinCriteriaUsed = false;
63
64     /**
65      * PUBLIC:
66      * Create a new ExpressionBuilder.
67      */

68     public ExpressionBuilder() {
69         super();
70     }
71
72     /**
73      * ADVANCED:
74      * Create a new ExpressionBuilder representing instances of the argument class.
75      * This can be used for the purpose of parallel expressions.
76      * This is a type of query that searches on the relationship between to un-related objects.
77      */

78     public ExpressionBuilder(Class JavaDoc queryClass) {
79         super();
80         this.queryClass = queryClass;
81         this.wasQueryClassSetInternally = false;
82     }
83
84     /**
85      * INTERNAL: Find the alias for a given table. Handle the special case where we are bogus
86      * and it should be aliased against our derived tables instead.
87      */

88     public DatabaseTable aliasForTable(DatabaseTable table) {
89         if (hasViewTable()) {
90             return getAliasedViewTable();
91         }
92
93         if (doesNotRepresentAnObjectInTheQuery()) {
94             for (Enumeration e = derivedTables.elements(); e.hasMoreElements();) {
95                 TableExpression t = (TableExpression)e.nextElement();
96                 DatabaseTable result = t.aliasForTable(table);
97                 if (result != null) {
98                     return result;
99                 }
100             }
101         } else {
102             return super.aliasForTable(table);
103         }
104         return null;// No alias found in the derived tables
105
}
106
107     /**
108      * INTERNAL:
109      * Assign aliases to any tables which I own. Start with t<initialValue>,
110      * and return the new value of the counter , i.e. if initialValue is one
111      * and I have tables ADDRESS and EMPLOYEE I will assign them t1 and t2 respectively, and return 3.
112      */

113     public int assignTableAliasesStartingAt(int initialValue) {
114         if (hasBeenAliased()) {
115             return initialValue;
116         }
117
118         if (doesNotRepresentAnObjectInTheQuery()) {
119             return initialValue;
120         }
121
122         // This block should be removed I think.
123
// The only reason to clone might be to
124
// preserve the qualifier, but aliases need
125
// qualifiers? That seems strange.
126
// Also this will break AsOf queries. By
127
// inference if has view table the AliasTableLookup
128
// will contain one table, and that will be the
129
// table of the view...
130
if (hasViewTable()) {
131             DatabaseTable aliased = (DatabaseTable)viewTable.clone();
132             String JavaDoc alias = "t" + initialValue;
133             aliased.setName(alias);
134             assignAlias(alias, viewTable);
135             aliasedViewTable = aliased;
136             return initialValue + 1;
137         }
138         return super.assignTableAliasesStartingAt(initialValue);
139     }
140
141     /**
142      * INTERNAL:
143      * Used for debug printing.
144      */

145     public String JavaDoc descriptionOfNodeType() {
146         return "Base";
147     }
148
149     /**
150      * INTERNAL:
151      * There are cases (which we might want to eliminate?) where the expression builder
152      * doesn't actually correspond to an object to be read. Mostly this is the case where
153      * it's a data query in terms of tables, and the builder is only there to provide a base.
154      * It might be better to make tables able to serve as their own base, but it's very nice
155      * to have a known unique, shared base. In the meantime, this
156      * is a special case to make sure the builder doesn't get tables assigned.
157      */

158     public boolean doesNotRepresentAnObjectInTheQuery() {
159         return (hasDerivedTables() && !hasDerivedFields() && !hasDerivedExpressions());
160     }
161
162     /**
163      * INTERNAL:
164      */

165     public DatabaseTable getAliasedViewTable() {
166         return aliasedViewTable;
167
168     }
169
170     /**
171      * INTERNAL:
172      * Return the expression builder which is the ultimate base of this expression, or
173      * null if there isn't one (shouldn't happen if we start from a root)
174      */

175     public ExpressionBuilder getBuilder() {
176         return this;
177     }
178
179     /**
180      * INTERNAL:
181      * Only usable after the session and class have been set. Return the
182      * descriptor for the class this node represents.
183      */

184     public ClassDescriptor getDescriptor() {
185         if (descriptor == null) {
186             if (getQueryClass() == null) {
187                 return null;
188             } else {
189                 if (getSession() == null) {
190                     throw QueryException.noExpressionBuilderFound(this);
191                 }
192                 descriptor = getSession().getDescriptor(getQueryClass());
193             }
194         }
195         return descriptor;
196
197     }
198
199     /**
200      * INTERNAL:
201      */

202     public Class JavaDoc getQueryClass() {
203         return queryClass;
204     }
205
206     /**
207      * INTERNAL:
208      */

209     public AbstractSession getSession() {
210         return session;
211     }
212
213     /**
214      * INTERNAL:
215      * Return the statement that expression is for.
216      * This is used for the context in subselects.
217      */

218     public SQLSelectStatement getStatement() {
219         return statement;
220     }
221
222     /**
223      * INTERNAL:
224      */

225     public DatabaseTable getViewTable() {
226         return viewTable;
227     }
228
229     /**
230      * INTERNAL:
231      */

232     public boolean hasViewTable() {
233         return viewTable != null;
234     }
235
236     /**
237      * INTERNAL:
238      */

239     public boolean isExpressionBuilder() {
240         return true;
241     }
242
243     /**
244      * INTERNAL:
245      * Normalize the expression into a printable structure.
246      * Any joins must be added to form a new root.
247      */

248     public Expression normalize(ExpressionNormalizer normalizer) {
249         if (hasBeenNormalized()) {
250             return this;
251         } else {
252             setHasBeenNormalized(true);
253         }
254
255         // This is required for parralel selects,
256
// the session must be set and the addtional join expression added.
257
if (this.queryClass != null) {
258             Expression criteria = null;
259
260             setSession(normalizer.getSession());
261             // The descriptor must be defined at this point.
262
if (getDescriptor() == null) {
263                 throw QueryException.noExpressionBuilderFound(this);
264             }
265             if (!this.wasAdditionJoinCriteriaUsed) {
266                 criteria = getDescriptor().getQueryManager().getAdditionalJoinExpression();
267                 if (criteria != null) {
268                     criteria = twist(criteria, this);
269                 }
270             }
271
272             if (isUsingOuterJoinForMultitableInheritance() && getSession().getPlatform().shouldPrintOuterJoinInWhereClause()) {
273                 Expression childrenCriteria = getDescriptor().getInheritancePolicy().getChildrenJoinExpression();
274                 childrenCriteria = this.twist(childrenCriteria, this);
275                 childrenCriteria.convertToUseOuterJoin();
276                 if(criteria == null) {
277                     criteria = childrenCriteria;
278                 } else {
279                     criteria = criteria.and(childrenCriteria);
280                 }
281             }
282             if (isUsingOuterJoinForMultitableInheritance() && (!getSession().getPlatform().shouldPrintOuterJoinInWhereClause())) {
283                 normalizer.getStatement().getOuterJoinExpressions().addElement(null);
284                 normalizer.getStatement().getOuterJoinedMappingCriteria().addElement(null);
285                 normalizer.getStatement().getOuterJoinedAdditionalJoinCriteria().addElement(additionalExpressionCriteriaMap());
286                 normalizer.getStatement().getDescriptorsForMultitableInheritanceOnly().add(this.getDescriptor());
287                 // fall through to the main case
288
}
289             normalizer.addAdditionalExpression(criteria);
290
291
292         }
293         setStatement(normalizer.getStatement());
294         
295
296         return super.normalize(normalizer);
297     }
298
299     /**
300      * INTERNAL:
301      * Print java
302      */

303     public void printJava(ExpressionJavaPrinter printer) {
304         printer.printString(printer.getBuilderString());
305     }
306
307     /**
308      * INTERNAL:
309      * This expression is built on a different base than the one we want. Rebuild it and
310      * return the root of the new tree
311      * This assumes that the original expression has only a single builder.
312      */

313     public Expression rebuildOn(Expression newBase) {
314         return newBase;
315     }
316
317     /**
318      * INTERNAL:
319      * Override Expression.registerIn to check if the new base expression
320      * has already been provided for the clone.
321      * @see oracle.toplink.essentials.expressions.Expression#cloneUsing(Expression)
322      * @bug 2637484 INVALID QUERY KEY EXCEPTION THROWN USING BATCH READS AND PARALLEL EXPRESSIONS
323      */

324     protected Expression registerIn(Dictionary alreadyDone) {
325         // Here do a special check to see if this a cloneUsing(newBase) call.
326
Object JavaDoc value = alreadyDone.get(alreadyDone);
327         if ((value == null) || (value == alreadyDone)) {
328             // This is a normal cloning operation.
329
return super.registerIn(alreadyDone);
330         }
331         ObjectExpression copy = (ObjectExpression)value;
332
333         // copy is actually the newBase of a cloneUsing.
334
alreadyDone.put(alreadyDone, alreadyDone);
335         alreadyDone.put(this, copy);
336         // Now need to copy over the derived expressions, etc.
337
if (this.derivedExpressions != null) {
338             if (copy.derivedExpressions == null) {
339                 copy.derivedExpressions = copyCollection(this.derivedExpressions, alreadyDone);
340             } else {
341                 copy.derivedExpressions.addAll(copyCollection(this.derivedExpressions, alreadyDone));
342             }
343         }
344
345         // Do the same for these protected fields.
346
copy.postCopyIn(alreadyDone, this.derivedFields, this.derivedTables);
347         return copy;
348     }
349
350     /**
351      * INTERNAL:
352      * Set the class which this node represents.
353      */

354     public void setQueryClass(Class JavaDoc queryClass) {
355         this.queryClass = queryClass;
356         this.descriptor = null;
357     }
358
359     /**
360      * INTERNAL:
361      * Set the session in which we expect this expression to be translated.
362      */

363     public void setSession(AbstractSession session) {
364         this.session = session;
365     }
366
367     /**
368      * INTERNAL:
369      * Set the statement that expression is for.
370      * This is used for the context in subselects.
371      */

372     public void setStatement(SQLSelectStatement statement) {
373         this.statement = statement;
374     }
375
376     /**
377      * INTERNAL:
378      * This expression represents something read through a view table.
379      */

380     public void setViewTable(DatabaseTable theTable) {
381         viewTable = theTable;
382
383     }
384
385     /**
386      * INTERNAL:
387      * If the additional Join Criteria for the class this builder represents has
388      * been added to the statement then mark this as true. This will prevent
389      * TopLink from adding it again at normalization
390      */

391     public void setWasAdditionJoinCriteriaUsed(boolean joinCriteriaUsed){
392         this.wasAdditionJoinCriteriaUsed = joinCriteriaUsed;
393     }
394     
395     /**
396      * INTERNAL:
397      * Rebuild myself against the base, with the values of parameters supplied by the context
398      * expression. This is used for transforming a standalone expression (e.g. the join criteria of a mapping)
399      * into part of some larger expression. You normally would not call this directly, instead calling twist
400      * See the comment there for more details"
401      * @param newBase
402      * @param context
403      * @return
404      */

405     public Expression twistedForBaseAndContext(Expression newBase, Expression context) {
406         return newBase;
407     }
408
409     /**
410      * INTERNAL:
411      * The expression builder represent the entire object, just return it.
412      */

413     public Object JavaDoc valueFromObject(Object JavaDoc object, AbstractSession session, AbstractRecord translationRow, InMemoryQueryIndirectionPolicy valueHolderPolicy, boolean isObjectUnregistered) {
414         return object;
415     }
416
417     /**
418      * INTERNAL:
419      * If the additional Join Criteria for the class this builder represents has
420      * been added to the statement this method will return true;
421      */

422     public boolean wasAdditionJoinCriteriaUsed(){
423         return this.wasAdditionJoinCriteriaUsed;
424     }
425     
426     /**
427      * INTERNAL:
428      * Returns true if TopLink set the query class as appoased to the customer. This
429      * is important in determining if this Expression should be treated as a parallel
430      * expression during normalization
431      */

432     public boolean wasQueryClassSetInternally(){
433         return this.wasQueryClassSetInternally;
434     }
435     
436     /**
437      * INTERNAL:
438      * For debug printing purposes.
439      */

440     public void writeDescriptionOn(BufferedWriter writer) throws IOException {
441         String JavaDoc className;
442         if (getQueryClass() == null) {
443             className = "QUERY OBJECT";
444         } else {
445             className = getQueryClass().getName();
446         }
447         writer.write(className + tableAliasesDescription());
448     }
449 }
450
Popular Tags