Source Code Cross Referenced for ObjectExpression.java in  » Database-ORM » JPOX » org » jpox » store » expression » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Database ORM » JPOX » org.jpox.store.expression 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /**********************************************************************
002:        Copyright (c) 2003 Erik Bengtson and others. All rights reserved.
003:        Licensed under the Apache License, Version 2.0 (the "License");
004:        you may not use this file except in compliance with the License.
005:        You may obtain a copy of the License at
006:
007:            http://www.apache.org/licenses/LICENSE-2.0
008:
009:        Unless required by applicable law or agreed to in writing, software
010:        distributed under the License is distributed on an "AS IS" BASIS,
011:        WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012:        See the License for the specific language governing permissions and
013:        limitations under the License.
014:         
015:
016:        Contributors:
017:        2003 Andy Jefferson - coding standards
018:        2005 Andy Jefferson - added handling for joins to related fields
019:        2005 Andy Jefferson - added fix for use of "this" to avoid LEFT OUTER JOIN
020:            ...
021:         **********************************************************************/package org.jpox.store.expression;
022:
023:        import java.util.Iterator;
024:
025:        import org.jpox.ClassLoaderResolver;
026:        import org.jpox.api.ApiAdapter;
027:        import org.jpox.exceptions.JPOXUserException;
028:        import org.jpox.jdo.exceptions.ClassNotPersistenceCapableException;
029:        import org.jpox.metadata.AbstractClassMetaData;
030:        import org.jpox.metadata.AbstractMemberMetaData;
031:        import org.jpox.metadata.DiscriminatorMetaData;
032:        import org.jpox.metadata.DiscriminatorStrategy;
033:        import org.jpox.metadata.InheritanceStrategy;
034:        import org.jpox.store.DatastoreClass;
035:        import org.jpox.store.DatastoreContainerObject;
036:        import org.jpox.store.DatastoreIdentifier;
037:        import org.jpox.store.IdentifierFactory;
038:        import org.jpox.store.mapping.BigDecimalMapping;
039:        import org.jpox.store.mapping.BigIntegerMapping;
040:        import org.jpox.store.mapping.BooleanMapping;
041:        import org.jpox.store.mapping.ByteMapping;
042:        import org.jpox.store.mapping.CharacterMapping;
043:        import org.jpox.store.mapping.DiscriminatorMapping;
044:        import org.jpox.store.mapping.DoubleMapping;
045:        import org.jpox.store.mapping.EmbeddedMapping;
046:        import org.jpox.store.mapping.EmbeddedPCMapping;
047:        import org.jpox.store.mapping.FloatMapping;
048:        import org.jpox.store.mapping.ObjectIdClassMapping;
049:        import org.jpox.store.mapping.IntegerMapping;
050:        import org.jpox.store.mapping.JavaTypeMapping;
051:        import org.jpox.store.mapping.LongMapping;
052:        import org.jpox.store.mapping.PersistenceCapableMapping;
053:        import org.jpox.store.mapping.ReferenceMapping;
054:        import org.jpox.store.mapping.ShortMapping;
055:        import org.jpox.store.mapping.SqlDateMapping;
056:        import org.jpox.store.mapping.SqlTimeMapping;
057:        import org.jpox.store.mapping.SqlTimestampMapping;
058:        import org.jpox.store.mapping.StringMapping;
059:        import org.jpox.util.JPOXLogger;
060:
061:        /**
062:         * Representation of an Object expression in a Query.
063:         * Let's take an example :-
064:         * <PRE>
065:         * We have classes A and B, and A contains a reference to B "b".
066:         * If we do a JDOQL query for class A of "b.someField == value" then
067:         * "b" is interpreted first and an ObjectExpression is created to represent
068:         * that object (of type B).
069:         * </PRE>
070:         * The expression has an associated TableExpression, and a list of
071:         * expressions which represent the datastore columns identifying the
072:         * object (the PK fields/columns).
073:         *
074:         * @version $Revision: 1.59 $
075:         **/
076:        public class ObjectExpression extends ScalarExpression {
077:            protected ScalarExpression conditionExpr;
078:            private Class castType;
079:
080:            /** Name of the field that this object represents. Null typically means that this is the candidate object. */
081:            private String fieldName;
082:
083:            /** Type of the field that this object represents. */
084:            private String fieldType;
085:
086:            /** Flag for whether we are using a related table and so dont need to join again in field access. */
087:            // TODO This is always true!!!! Why ?????????
088:            private boolean usingRelatedTable = true;
089:
090:            protected ObjectExpression(QueryExpression qs) {
091:                super (qs);
092:            }
093:
094:            /**
095:             * Constructor for an object expression, using the mapping of the field, and the expression for the table.
096:             * @param qs The Query Statement
097:             * @param mapping The mapping for the field whose object we are expressing
098:             * @param te The expression for the table of the object.
099:             */
100:            public ObjectExpression(QueryExpression qs,
101:                    JavaTypeMapping mapping, LogicSetExpression te) {
102:                super (qs, mapping, te);
103:            }
104:
105:            /**
106:             * Constructor for an object expression, using the mapping of the field (which has no datastore columns),
107:             * the expression for its table, the mapping for a field in another table to join to, and the expression
108:             * for the other table. This is for use in 2 situations :-
109:             * <UL>
110:             * <LI>a 1-1 bidirectional single-FK relation where one side has its FK stored in the other object,
111:             * so we need to left outer join to get that field.</LI>
112:             * <LI>a 1-N bidirectional join table relation where the element side has to navigate via the
113:             * join table to get to the owner object.</LI>
114:             * </UL>
115:             * @param qs The Query Statement
116:             * @param mapping The mapping for the field whose object we are expressing
117:             * @param te The expression for the table of the object
118:             * @param refMapping The mapping of the field in another table that we join to
119:             * @param teTarget The expression for the other table that we are joining to.
120:             * @param selectMapping The mapping that we should select in the other table
121:             */
122:            public ObjectExpression(QueryExpression qs,
123:                    JavaTypeMapping mapping, LogicSetExpression te,
124:                    JavaTypeMapping refMapping, LogicSetExpression teTarget,
125:                    JavaTypeMapping selectMapping) {
126:                this (qs);
127:
128:                // Join from the ID field of this table to the related field of the related table
129:                ScalarExpression sourceExpr = mapping.getDatastoreContainer()
130:                        .getIDMapping().newScalarExpression(qs, te);
131:                ScalarExpression targetExpr = refMapping.newScalarExpression(
132:                        qs, teTarget);
133:                qs.leftOuterJoin(sourceExpr, targetExpr, teTarget, true, true);
134:
135:                this .mapping = selectMapping;
136:                this .te = teTarget;
137:                for (int i = 0; i < this .mapping.getNumberOfDatastoreFields(); i++) {
138:                    expressionList.addExpression(new DatastoreFieldExpression(
139:                            qs, this .mapping.getDataStoreMapping(i)
140:                                    .getDatastoreField(), teTarget));
141:                }
142:                st.append(expressionList.toString());
143:                usingRelatedTable = true;
144:            }
145:
146:            /**
147:             * Construct an object expression conditioned to a boolean expression
148:             * If this expression is an operand of an operation with result type Boolean has the following semantic
149:             * 
150:             * if (conditionExpr == null )
151:             *    return (otherExpression op expr);
152:             * else
153:             *    return (otherExpression op expr) & conditionExpr;
154:             * 
155:             * @param qs the QueryExpression
156:             * @param expr the expression
157:             * @param conditionExpr the conditional boolean expression
158:             * @param te the TableExpression
159:             */
160:            public ObjectExpression(QueryExpression qs, ScalarExpression expr,
161:                    ScalarExpression conditionExpr, LogicSetExpression te) {
162:                super (qs);
163:
164:                this .te = te;
165:                this .mapping = expr.mapping;
166:                this .st.append(expr.st.toString());
167:                this .expressionList = expr.expressionList;
168:                this .conditionExpr = conditionExpr;
169:            }
170:
171:            /**
172:             * Method to change the expression to use only the first datastore field.
173:             * This is used where we want to use the expression in an aggregate and
174:             * only can use one datastore field. Package permission to prevent external access.
175:             */
176:            void useFirstDatastoreFieldOnly() {
177:                if (mapping.getNumberOfDatastoreFields() <= 1) {
178:                    // Do nothing
179:                    return;
180:                }
181:
182:                // Replace the expressionList and SQL as if starting from scratch
183:                expressionList = new ExpressionList();
184:                expressionList
185:                        .addExpression(new DatastoreFieldExpression(qs, mapping
186:                                .getDataStoreMapping(0).getDatastoreField(), te));
187:                st.clearStatement();
188:                st.append(expressionList.toString());
189:            }
190:
191:            /**
192:             * Convenience method for the case where the mapping being used is a PersistenceCapableMapping
193:             * and where we want to represent the identity instead of the object represented by that
194:             * mapping. This changes the mapping to use the id.
195:             */
196:            public void useIdentityFormOfPCMapping() {
197:                if (mapping instanceof  PersistenceCapableMapping) {
198:                    mapping = new ObjectIdClassMapping(
199:                            (PersistenceCapableMapping) mapping);
200:                }
201:            }
202:
203:            /**
204:             * Convenience method to add an outer join suffix.
205:             * Particularly for use with Oracle (8) which uses syntax like table1.col1 = table2.col2 (+),
206:             * @param suffix The suffix
207:             */
208:            public void addOuterJoinSuffix(String suffix) {
209:                if (suffix != null) {
210:                    st.append(suffix);
211:                }
212:            }
213:
214:            /**
215:             * Cast operator. Called when the query contains "(type)obj" where "obj" is this object.
216:             * @param castType The type we cast this object to
217:             * @return Scalar expression representing the cast object.
218:             */
219:            public ScalarExpression cast(Class castType) {
220:                ObjectExpression objectCast;
221:                LogicSetExpression te = qs.getTableExpression(this .qs
222:                        .getStoreManager()
223:                        .getDatastoreClass(castType.getName(),
224:                                qs.getClassLoaderResolver()).getIdentifier());
225:                DatastoreClass dc = this .qs.getStoreManager()
226:                        .getDatastoreClass(castType.getName(),
227:                                qs.getClassLoaderResolver());
228:                if (te == null) {
229:                    IdentifierFactory idFactory = qs.getStoreManager()
230:                            .getIdentifierFactory();
231:                    String jtIdentifier = this .te.getAlias().getIdentifier();
232:                    if (castType != null
233:                            && !castType.getName().equals(mapping.getType())) {
234:                        String castTypeName = castType.getName();
235:                        jtIdentifier = idFactory.newIdentifier(
236:                                this .te.getAlias(),
237:                                castTypeName.substring(castTypeName
238:                                        .lastIndexOf('.') + 1)).getIdentifier();
239:                    }
240:
241:                    DatastoreIdentifier jtRangeVar = idFactory.newIdentifier(
242:                            IdentifierFactory.TABLE, jtIdentifier);
243:                    LogicSetExpression jtTblExpr = qs
244:                            .getTableExpression(jtRangeVar);
245:
246:                    if (jtTblExpr == null) {
247:                        jtTblExpr = qs.newTableExpression(dc, jtRangeVar);
248:                    }
249:                    te = jtTblExpr;
250:                    qs.leftOuterJoin(this , dc.getIDMapping()
251:                            .newScalarExpression(qs, jtTblExpr), jtTblExpr,
252:                            true, true);
253:                }
254:                objectCast = new ObjectExpression(qs, dc.getIDMapping(), te);
255:                objectCast.conditionExpr = this .conditionExpr;
256:                return objectCast;
257:            }
258:
259:            /**
260:             * Equals operator. Called when the query contains "obj == value" where "obj" is this object.
261:             * @param expr The expression we compare with (the right-hand-side in the query)
262:             * @return Boolean expression representing the comparison.
263:             */
264:            public BooleanExpression eq(ScalarExpression expr) {
265:                BooleanExpression bExpr = null;
266:                if (expr instanceof  NullLiteral) {
267:                    for (int i = 0; i < this .expressionList.size(); i++) {
268:                        if (bExpr == null) {
269:                            bExpr = expr.eq(this .expressionList
270:                                    .getExpression(i));
271:                        } else {
272:                            bExpr = bExpr.and(expr.eq(this .expressionList
273:                                    .getExpression(i)));
274:                        }
275:                    }
276:                } else if (literalIsValidForSimpleComparison(expr)) {
277:                    if (this .expressionList.size() > 1) {
278:                        // More than 1 value to compare with a literal!
279:                        bExpr = super .eq(expr);
280:                    } else {
281:                        // Just do a direct comparison with the basic literals
282:                        bExpr = new BooleanExpression(this , OP_EQ, expr);
283:                    }
284:                } else if (expr instanceof  ObjectLiteral) {
285:                    bExpr = expr.eq(this );
286:                } else if (expr instanceof  ObjectExpression) {
287:                    for (int i = 0; i < this .expressionList.size(); i++) {
288:                        ScalarExpression source = this .expressionList
289:                                .getExpression(i);
290:                        ScalarExpression target = expr.expressionList
291:                                .getExpression(i);
292:                        if (bExpr == null) {
293:                            bExpr = source.eq(target);
294:                        } else {
295:                            bExpr = bExpr.and(source.eq(target));
296:                        }
297:                    }
298:                } else if (expr instanceof  UnboundVariable) {
299:                    if (((UnboundVariable) expr).getVariableType() == null) {
300:                        // Set the variable type to this objects type
301:                        ((UnboundVariable) expr).setVariableType(qs
302:                                .getClassLoaderResolver().classForName(
303:                                        fieldType));
304:                    }
305:                    bExpr = expr.eq(this );
306:                } else if (expr instanceof  BooleanBitColumnExpression) {
307:                    bExpr = null;
308:                } else {
309:                    bExpr = super .eq(expr);
310:                }
311:
312:                if (conditionExpr != null) {
313:                    return new BooleanExpression(conditionExpr, OP_AND, bExpr);
314:                }
315:
316:                return bExpr;
317:            }
318:
319:            /**
320:             * Not equals operator. Called when the query contains "obj != value" where "obj" is this object.
321:             * @param expr The expression we compare with (the right-hand-side in the query)
322:             * @return Boolean expression representing the comparison.
323:             */
324:            public BooleanExpression noteq(ScalarExpression expr) {
325:                BooleanExpression bExpr = null;
326:                if (expr instanceof  NullLiteral) {
327:                    for (int i = 0; i < this .expressionList.size(); i++) {
328:                        if (bExpr == null) {
329:                            bExpr = expr.eq(this .expressionList
330:                                    .getExpression(i));
331:                        } else {
332:                            bExpr = bExpr.and(expr.eq(this .expressionList
333:                                    .getExpression(i)));
334:                        }
335:                    }
336:                    bExpr = new BooleanExpression(OP_NOT, bExpr
337:                            .encloseWithInParentheses());
338:                } else if (literalIsValidForSimpleComparison(expr)) {
339:                    if (this .expressionList.size() > 1) {
340:                        // More than 1 value to compare with a literal!
341:                        bExpr = super .noteq(expr);
342:                    } else {
343:                        // Just do a direct comparison with the basic literals
344:                        bExpr = new BooleanExpression(this , OP_NOTEQ, expr);
345:                    }
346:                } else if (expr instanceof  ObjectLiteral) {
347:                    bExpr = expr.noteq(this );
348:                } else if (expr instanceof  ObjectExpression) {
349:                    for (int i = 0; i < this .expressionList.size(); i++) {
350:                        ScalarExpression source = this .expressionList
351:                                .getExpression(i);
352:                        ScalarExpression target = expr.expressionList
353:                                .getExpression(i);
354:                        if (bExpr == null) {
355:                            bExpr = source.eq(target);
356:                        } else {
357:                            bExpr = bExpr.and(source.eq(target));
358:                        }
359:                    }
360:                    bExpr = new BooleanExpression(OP_NOT, bExpr
361:                            .encloseWithInParentheses());
362:                } else if (expr instanceof  UnboundVariable) {
363:                    if (((UnboundVariable) expr).getVariableType() == null) {
364:                        // Set the variable type to this objects type
365:                        ((UnboundVariable) expr).setVariableType(qs
366:                                .getClassLoaderResolver().classForName(
367:                                        fieldType));
368:                    }
369:                    bExpr = expr.noteq(this );
370:                } else if (expr instanceof  BooleanBitColumnExpression) {
371:                    if (conditionExpr != null) {
372:                        bExpr = new BooleanExpression(ScalarExpression.OP_NOT,
373:                                conditionExpr);
374:                    }
375:                } else {
376:                    bExpr = super .noteq(expr);
377:                }
378:
379:                if (conditionExpr != null) {
380:                    return new BooleanExpression(conditionExpr, OP_AND, bExpr);
381:                }
382:
383:                return bExpr;
384:            }
385:
386:            /**
387:             * Convenience method to return if this object is valid for simple comparison
388:             * with the passed expression. Performs a type comparison of the object and the expression
389:             * for compatibility. The expression must be a literal of a suitable type for simple
390:             * comparison (e.g where this object is a String, and the literal is a StringLiteral).
391:             * @param expr The expression
392:             * @return Whether a simple comparison is valid
393:             */
394:            private boolean literalIsValidForSimpleComparison(
395:                    ScalarExpression expr) {
396:                // Our mapping is a single field type and is of the same basic type as the expression
397:                if ((expr instanceof  BooleanLiteral && (mapping instanceof  BooleanMapping))
398:                        || (expr instanceof  ByteLiteral && (mapping instanceof  ByteMapping))
399:                        || (expr instanceof  CharacterLiteral && (mapping instanceof  CharacterMapping))
400:                        || (expr instanceof  FloatingPointLiteral && (mapping instanceof  FloatMapping
401:                                || mapping instanceof  DoubleMapping || mapping instanceof  BigDecimalMapping))
402:                        || (expr instanceof  IntegerLiteral
403:                                && (mapping instanceof  IntegerMapping
404:                                        || mapping instanceof  LongMapping || mapping instanceof  BigIntegerMapping) || mapping instanceof  ShortMapping)
405:                        || (expr instanceof  SqlDateLiteral && (mapping instanceof  SqlDateMapping))
406:                        || (expr instanceof  SqlTimeLiteral && (mapping instanceof  SqlTimeMapping))
407:                        || (expr instanceof  SqlTimestampLiteral && (mapping instanceof  SqlTimestampMapping))
408:                        || (expr instanceof  StringLiteral && (mapping instanceof  StringMapping || mapping instanceof  CharacterMapping))) {
409:                    return true;
410:                }
411:
412:                return false;
413:            }
414:
415:            public BooleanExpression in(ScalarExpression expr) {
416:                return new BooleanExpression(this , OP_IN, expr);
417:            }
418:
419:            /**
420:             * Access a field in the object that this expression represents.
421:             * If the field is contained in a different table then will use the "innerJoin" input parameter
422:             * and make a join to the required table. If the field is a 1-1 relation and the current table holds the FK
423:             * then no join will be made.
424:             * @param subfieldName the field to be accessed in this object
425:             * @param innerJoin whether to inner join
426:             * @return The field expression representing the required field of this object
427:             */
428:            public ScalarExpression accessField(String subfieldName,
429:                    boolean innerJoin) {
430:                DatastoreContainerObject table;
431:                ClassLoaderResolver clr = qs.getClassLoaderResolver();
432:                try {
433:                    if (mapping instanceof  EmbeddedMapping) {
434:                        // Any embedded fields can go straight to the main table if embedded there
435:                        table = mapping.getDatastoreContainer();
436:                        if (te.getMainTable().equals(table)) {
437:                            // Provide the full field name so we can allow for nested embeddings
438:                            return te.newFieldExpression(fieldName + "."
439:                                    + subfieldName);
440:                        }
441:                    } else if (mapping instanceof  PersistenceCapableMapping
442:                            || mapping instanceof  ReferenceMapping) {
443:                        AbstractClassMetaData otherCmd = qs.getStoreManager()
444:                                .getMetaDataManager().getMetaDataForClass(
445:                                        mapping.getType(), clr);
446:                        if (otherCmd.getInheritanceMetaData()
447:                                .getStrategyValue() == InheritanceStrategy.SUBCLASS_TABLE) {
448:                            // Field is a PC class that uses "subclass-table" inheritance strategy (and so has multiple possible tables to join to)
449:                            AbstractClassMetaData[] cmds = qs.getStoreManager()
450:                                    .getClassesManagingTableForClass(otherCmd,
451:                                            clr);
452:                            if (cmds != null) {
453:                                // Join to the first table
454:                                // TODO Allow for all possible tables. Can we do an OR of the tables ? How ?
455:                                if (cmds.length > 1) {
456:                                    JPOXLogger.QUERY.warn(LOCALISER.msg(
457:                                            "037006", mapping
458:                                                    .getFieldMetaData()
459:                                                    .getFullFieldName(),
460:                                            cmds[0].getFullClassName()));
461:                                }
462:                                table = qs.getStoreManager().getDatastoreClass(
463:                                        cmds[0].getFullClassName(), clr);
464:                            } else {
465:                                // No subclasses with tables to join to, so throw a user error
466:                                throw new JPOXUserException(LOCALISER.msg(
467:                                        "037005", mapping.getFieldMetaData()
468:                                                .getFullFieldName()));
469:                            }
470:                        } else {
471:                            // Class of the field will have its own table
472:                            table = qs.getStoreManager().getDatastoreClass(
473:                                    mapping.getType(), clr);
474:                            ApiAdapter api = qs.getStoreManager()
475:                                    .getApiAdapter();
476:
477:                            if (fieldName != null && subfieldName != null) {
478:                                AbstractMemberMetaData subfieldMetaData = otherCmd
479:                                        .getMetaDataForMember(subfieldName);
480:                                if (subfieldMetaData != null
481:                                        && subfieldMetaData.isPrimaryKey()
482:                                        && !api.isPersistable(subfieldMetaData
483:                                                .getType())) {
484:                                    // Selecting a non-PC field in the other class that is part of its PK mapping (so we have a column here for it)
485:                                    // Avoids the extra join to the other table
486:                                    JavaTypeMapping[] subMappings = ((PersistenceCapableMapping) mapping)
487:                                            .getJavaTypeMapping();
488:                                    if (subMappings.length == 1) {
489:                                        // TODO Cater for a field of a composite PK being selected
490:                                        return subMappings[0]
491:                                                .newScalarExpression(qs, te);
492:                                    }
493:                                }
494:                            }
495:                        }
496:                    } else {
497:                        table = qs.getStoreManager().getDatastoreClass(
498:                                mapping.getType(), clr);
499:                    }
500:                } catch (ClassNotPersistenceCapableException cnpce) {
501:                    return te.newFieldExpression(subfieldName);
502:                }
503:
504:                if (fieldType != null && !fieldType.equals(mapping.getType())) {
505:                    // The field relation is to a table that allows multiple types to be stored (and has a discriminator)
506:                    // and the type we want is not the base type, so we need to restrict the values of the discriminator.
507:                    DiscriminatorMetaData dismd = table
508:                            .getDiscriminatorMetaData();
509:                    DiscriminatorMapping discriminatorMapping = (DiscriminatorMapping) table
510:                            .getDiscriminatorMapping(false);
511:                    if (dismd != null
512:                            && dismd.getStrategy() != DiscriminatorStrategy.NONE) {
513:                        // Start with the required class
514:                        BooleanExpression discrExpr = booleanConditionForClassInDiscriminator(
515:                                qs, fieldType, dismd, discriminatorMapping, te);
516:
517:                        // Add "or" condition for any of its possible subclasses (if any)
518:                        Iterator subclassIter = qs.getStoreManager()
519:                                .getSubClassesForClass(fieldType, true, clr)
520:                                .iterator();
521:                        while (subclassIter.hasNext()) {
522:                            String subCandidateType = (String) subclassIter
523:                                    .next();
524:                            discrExpr
525:                                    .ior(booleanConditionForClassInDiscriminator(
526:                                            qs, subCandidateType, dismd,
527:                                            discriminatorMapping, te));
528:                        }
529:
530:                        discrExpr.encloseWithInParentheses();
531:
532:                        // Add the discriminator restrictions as an "and" condition to the Query Statement
533:                        qs.andCondition(discrExpr);
534:                    }
535:                }
536:
537:                if (te.getMainTable().equals(table) && usingRelatedTable
538:                        && fieldName == null) {
539:                    //TODO fieldname==null, QUESTION is it "<candidateAlias>" namespace? debug and see
540:                    // We are already in the same table (left outer join in the constructor) and it isn't a self reference so just return 
541:                    // the field expression. This can happen when we have a 1-1 bidir single FK and to generate the ObjectExpression we
542:                    // had to join across to the related field
543:                    return te.newFieldExpression(subfieldName);
544:                }
545:
546:                // jt... = "joined table"
547:                String jtIdentifier = te.getAlias().getIdentifier();
548:                if (fieldName != null) {
549:                    jtIdentifier += '.' + fieldName;
550:                }
551:                if (!subfieldName.equals("this")) // TODO Use qs.getCandidateAlias()
552:                {
553:                    jtIdentifier += '.' + subfieldName;
554:                }
555:
556:                if (castType != null
557:                        && !castType.getName().equals(mapping.getType())) {
558:                    String castTypeName = castType.getName();
559:                    jtIdentifier += '.' + castTypeName.substring(castTypeName
560:                            .lastIndexOf('.') + 1);
561:                }
562:
563:                DatastoreIdentifier jtRangeVar = qs.getStoreManager()
564:                        .getIdentifierFactory().newIdentifier(
565:                                IdentifierFactory.TABLE, jtIdentifier);
566:                LogicSetExpression jtTblExpr = qs
567:                        .getTableExpression(jtRangeVar);
568:                if (jtTblExpr == null) {
569:                    // We can't join further (this subfield is not an object with a table expression)
570:                    if (te.getAlias().getIdentifier().equalsIgnoreCase("this")
571:                            && // TODO Use qs.getCandidateAlias()
572:                            table == qs.getMainTableExpression().getMainTable()
573:                            && fieldName == null) {
574:                        // Query contains "this.field" so just provide the associated field expression for that field
575:                        return qs.getMainTableExpression().newFieldExpression(
576:                                subfieldName);
577:                    }
578:
579:                    jtTblExpr = qs.newTableExpression(table, jtRangeVar);
580:
581:                    ScalarExpression jtExpr = table.getIDMapping()
582:                            .newScalarExpression(qs, jtTblExpr);
583:                    ScalarExpression expr = mapping.newScalarExpression(qs, te);
584:                    if (mapping.isNullable()) {
585:                        if (innerJoin) {
586:                            qs.innerJoin(jtExpr, expr, jtTblExpr, true, true);
587:                        } else {
588:                            qs.leftOuterJoin(jtExpr, expr, jtTblExpr, true,
589:                                    true);
590:                        }
591:                    } else {
592:                        qs.innerJoin(jtExpr, expr, jtTblExpr, true, true);
593:                    }
594:                }
595:
596:                if (mapping instanceof  EmbeddedPCMapping) {
597:                    return jtTblExpr.newFieldExpression(fieldName + "."
598:                            + subfieldName);
599:                } else {
600:                    return jtTblExpr.newFieldExpression(subfieldName);
601:                }
602:            }
603:
604:            /**
605:             * Method to return a constraint for restricting the field to just instances of a particular class.
606:             * @param expr Expression for the class that we want instances of (a ClassExpression).
607:             * @return The expression for the instanceof clause
608:             */
609:            public BooleanExpression instanceOf(ScalarExpression expr) {
610:                if (expr instanceof  ClassExpression) {
611:                    ClassLoaderResolver clr = qs.getClassLoaderResolver();
612:                    Class instanceof Class = ((ClassExpression) expr).getCls();
613:                    Class fieldClass = clr.classForName(mapping.getType());
614:                    if (!fieldClass.isAssignableFrom(instanceof Class)
615:                            && !instanceof Class.isAssignableFrom(fieldClass)) {
616:                        // Field type and instanceof type are totally incompatible, so just return false
617:                        return new BooleanLiteral(qs, mapping, true)
618:                                .eq(new BooleanLiteral(qs, mapping, false));
619:                    }
620:
621:                    DatastoreContainerObject table;
622:                    try {
623:                        if (mapping instanceof  EmbeddedMapping) {
624:                            // Field is embedded in this table
625:                            // TODO Enable instanceof on non-PC fields (currently just return "true")
626:                            return new BooleanLiteral(qs, mapping, true)
627:                                    .eq(new BooleanLiteral(qs, mapping, true));
628:                        } else if (mapping instanceof  PersistenceCapableMapping
629:                                || mapping instanceof  ReferenceMapping) {
630:                            // Field has its own table, so join to it
631:                            AbstractClassMetaData fieldCmd = qs
632:                                    .getStoreManager()
633:                                    .getMetaDataManager()
634:                                    .getMetaDataForClass(mapping.getType(), clr);
635:                            if (fieldCmd.getInheritanceMetaData()
636:                                    .getStrategyValue() == InheritanceStrategy.SUBCLASS_TABLE) {
637:                                // Field is a PC class that uses "subclass-table" inheritance strategy (and so has multiple possible tables to join to)
638:                                AbstractClassMetaData[] cmds = qs
639:                                        .getStoreManager()
640:                                        .getClassesManagingTableForClass(
641:                                                fieldCmd, clr);
642:                                if (cmds != null) {
643:                                    // Join to the first table
644:                                    // TODO Allow for all possible tables. Can we do an OR of the tables ? How ?
645:                                    if (cmds.length > 1) {
646:                                        JPOXLogger.QUERY.warn(LOCALISER.msg(
647:                                                "037006", mapping
648:                                                        .getFieldMetaData()
649:                                                        .getFullFieldName(),
650:                                                cmds[0].getFullClassName()));
651:                                    }
652:                                    table = qs.getStoreManager()
653:                                            .getDatastoreClass(
654:                                                    cmds[0].getFullClassName(),
655:                                                    clr);
656:                                } else {
657:                                    // No subclasses with tables to join to, so throw a user error
658:                                    throw new JPOXUserException(LOCALISER.msg(
659:                                            "037005", mapping
660:                                                    .getFieldMetaData()
661:                                                    .getFullFieldName()));
662:                                }
663:                            } else {
664:                                // Class of the field will have its own table
665:                                table = qs.getStoreManager().getDatastoreClass(
666:                                        mapping.getType(), clr);
667:                            }
668:                        } else {
669:                            table = qs.getStoreManager().getDatastoreClass(
670:                                    mapping.getType(), clr);
671:                        }
672:                    } catch (ClassNotPersistenceCapableException cnpce) {
673:                        // Field is not PersistenceCapable
674:                        // TODO Enable instanceof on non-PC fields (currently just return "true")
675:                        return new BooleanLiteral(qs, mapping, true)
676:                                .eq(new BooleanLiteral(qs, mapping, true));
677:                    }
678:
679:                    // Check if the table of the field has a discriminator
680:                    IdentifierFactory idFactory = qs.getStoreManager()
681:                            .getIdentifierFactory();
682:                    DiscriminatorMetaData dismd = table
683:                            .getDiscriminatorMetaData();
684:                    DiscriminatorMapping discriminatorMapping = (DiscriminatorMapping) table
685:                            .getDiscriminatorMapping(false);
686:                    if (discriminatorMapping != null) {
687:                        // Has a discriminator so do a join to the table of the field and apply a constraint on its discriminator
688:                        LogicSetExpression fieldTblExpr = null;
689:                        if (fieldName == null) {
690:                            // Using THIS so use default table expression
691:                            fieldTblExpr = qs.getMainTableExpression();
692:                        } else {
693:                            // Using field, so our real table will have an identifier of "THIS_{fieldName}" via INNER JOIN
694:                            String fieldIdentifier = te.getAlias()
695:                                    .getIdentifier();
696:                            fieldIdentifier += '.' + fieldName;
697:                            DatastoreIdentifier fieldRangeVar = idFactory
698:                                    .newIdentifier(IdentifierFactory.TABLE,
699:                                            fieldIdentifier);
700:                            fieldTblExpr = qs.getTableExpression(fieldRangeVar);
701:                            if (fieldTblExpr == null) {
702:                                fieldTblExpr = qs.newTableExpression(table,
703:                                        fieldRangeVar);
704:                            }
705:                            ScalarExpression fieldExpr = table.getIDMapping()
706:                                    .newScalarExpression(qs, fieldTblExpr);
707:                            expr = mapping.newScalarExpression(qs, te);
708:                            qs.innerJoin(fieldExpr, expr, fieldTblExpr, true,
709:                                    true);
710:                        }
711:
712:                        // Return a constraint on the discriminator for this table to get the right instances
713:                        // This allows all discriminator values for the instanceof class and all of its subclasses
714:                        // DISCRIM = 'baseVal' OR DISCRIM = 'sub1Val' OR DISCRIM = 'sub2Val' ... etc
715:                        BooleanExpression discrExpr = booleanConditionForClassInDiscriminator(
716:                                qs, instanceof Class.getName(), dismd,
717:                                discriminatorMapping, fieldTblExpr);
718:                        Iterator subclassIter = qs.getStoreManager()
719:                                .getSubClassesForClass(
720:                                        instanceof Class.getName(), true, clr)
721:                                .iterator();
722:                        while (subclassIter.hasNext()) {
723:                            String subCandidateType = (String) subclassIter
724:                                    .next();
725:                            discrExpr
726:                                    .ior(booleanConditionForClassInDiscriminator(
727:                                            qs, subCandidateType, dismd,
728:                                            discriminatorMapping, fieldTblExpr));
729:                        }
730:                        discrExpr.encloseWithInParentheses();
731:
732:                        return discrExpr;
733:                    } else {
734:                        // No discriminator so maybe union, or just a SELECT
735:                        // Need to join to the instanceof class (where appropriate)
736:                        // TODO RDBMS-71 Only join on the UNION select that it is applicable to
737:                        if (table instanceof  DatastoreClass) {
738:                            DatastoreClass ct = (DatastoreClass) table;
739:                            if (ct.managesClass(instanceof Class.getName())) {
740:                                // This type is managed in this table so must be an instance
741:                                return new BooleanLiteral(qs, mapping, true)
742:                                        .eq(new BooleanLiteral(qs, mapping,
743:                                                true));
744:                            } else {
745:                                // The instanceof type is not managed here
746:                                DatastoreClass instanceof Table = qs
747:                                        .getStoreManager().getDatastoreClass(
748:                                                instanceof Class.getName(), clr);
749:                                String fieldIdentifier = te.getAlias()
750:                                        .getIdentifier();
751:                                if (fieldName == null) {
752:                                    // Using THIS, so our real table will have an identifier of "THIS_INST"
753:                                    fieldIdentifier += ".INST";
754:                                } else {
755:                                    // Using field, so our real table will have an identifier of "THIS_{fieldName}"
756:                                    fieldIdentifier += '.' + fieldName;
757:                                }
758:                                DatastoreIdentifier fieldRangeVar = idFactory
759:                                        .newIdentifier(IdentifierFactory.TABLE,
760:                                                fieldIdentifier);
761:                                LogicSetExpression fieldTblExpr = qs
762:                                        .newTableExpression(instanceof Table,
763:                                                fieldRangeVar);
764:                                ScalarExpression fieldExpr = table
765:                                        .getIDMapping().newScalarExpression(qs,
766:                                                te);
767:                                if (fieldName == null) {
768:                                    expr = instanceof Table.getIDMapping()
769:                                            .newScalarExpression(qs,
770:                                                    fieldTblExpr);
771:                                } else {
772:                                    expr = mapping.newScalarExpression(qs,
773:                                            fieldTblExpr);
774:                                }
775:                                qs.innerJoin(fieldExpr, expr, fieldTblExpr,
776:                                        true, true);
777:                                return new BooleanLiteral(qs, mapping, true)
778:                                        .eq(new BooleanLiteral(qs, mapping,
779:                                                true));
780:                            }
781:                        } else {
782:                            // Assumed to be in the right class
783:                            return new BooleanLiteral(qs, mapping, true)
784:                                    .eq(new BooleanLiteral(qs, mapping, true));
785:                        }
786:                    }
787:                } else {
788:                    // Invalid to use "XX instanceof YY" where YY is not a class.
789:                    throw new JPOXUserException(LOCALISER.msg("037007", expr
790:                            .getClass().getName()));
791:                }
792:            }
793:
794:            /**
795:             * Set the field which this expression was created from.
796:             * @param fieldName The fieldName to set.
797:             * @param fieldType The fieldType to set
798:             */
799:            public void setFieldDefinition(String fieldName, String fieldType) {
800:                this .fieldName = fieldName;
801:                this .fieldType = fieldType;
802:            }
803:
804:            /**
805:             * Convenience method to generate a BooleanExpression for a value of the
806:             * discriminator for the provided table expression.
807:             * @param stmt The Query Statement to be updated
808:             * @param className The possible class name
809:             * @param dismd MetaData for the discriminator
810:             * @param discriminatorMapping Mapping for the discriminator
811:             * @param tableExpr Table Expression
812:             * @return BooleanExpression for this discriminator value
813:             */
814:            private BooleanExpression booleanConditionForClassInDiscriminator(
815:                    QueryExpression stmt, String className,
816:                    DiscriminatorMetaData dismd,
817:                    JavaTypeMapping discriminatorMapping,
818:                    LogicSetExpression tableExpr) {
819:                // Default to the "class-name" discriminator strategy
820:                String discriminatorValue = className;
821:                if (dismd.getStrategy() == DiscriminatorStrategy.VALUE_MAP) {
822:                    // Get the MetaData for the target class since that holds the "value"
823:                    AbstractClassMetaData targetCmd = stmt.getStoreManager()
824:                            .getMetaDataManager().getMetaDataForClass(
825:                                    className, stmt.getClassLoaderResolver());
826:                    discriminatorValue = targetCmd.getInheritanceMetaData()
827:                            .getDiscriminatorMetaData().getValue();
828:                }
829:                ScalarExpression discrExpr = discriminatorMapping
830:                        .newScalarExpression(stmt, tableExpr);
831:                ScalarExpression discrVal = discriminatorMapping.newLiteral(
832:                        stmt, discriminatorValue);
833:                return discrExpr.eq(discrVal);
834:            }
835:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.