Source Code Cross Referenced for WhereResolver.java in  » Database-ORM » beankeeper » hu » netmind » persistence » parser » 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 » beankeeper » hu.netmind.persistence.parser 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /**
002:         * Copyright (C) 2006 NetMind Consulting Bt.
003:         *
004:         * This library is free software; you can redistribute it and/or
005:         * modify it under the terms of the GNU Lesser General Public
006:         * License as published by the Free Software Foundation; either
007:         * version 3 of the License, or (at your option) any later version.
008:         *
009:         * This library is distributed in the hope that it will be useful,
010:         * but WITHOUT ANY WARRANTY; without even the implied warranty of
011:         * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
012:         * Lesser General Public License for more details.
013:         *
014:         * You should have received a copy of the GNU Lesser General Public
015:         * License along with this library; if not, write to the Free Software
016:         * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
017:         */package hu.netmind.persistence.parser;
018:
019:        import hu.netmind.persistence.*;
020:        import java.util.*;
021:        import org.apache.log4j.Logger;
022:
023:        /**
024:         * The parser resolver. Handles resolving objects and attributes
025:         * to table names and such. This class also handles the symbol table.
026:         * @author Brautigam Robert
027:         * @version Revision: $Revision$
028:         */
029:        public class WhereResolver implements  Resolver {
030:            private static Logger logger = Logger
031:                    .getLogger(WhereResolver.class);
032:
033:            private StoreContext context;
034:            private HashMap symbolTable;
035:            private Vector allTableTerms;
036:            private Vector allLeftTableTerms;
037:            // Main class stuff only used by 'find', when selecting single class
038:            private TableTerm mainTerm;
039:            private ClassInfo mainClassInfo;
040:            private ClassSpecifier mainClassSpecifier;
041:
042:            public WhereResolver(StoreContext context) {
043:                this .context = context;
044:                allLeftTableTerms = new Vector();
045:                symbolTable = new HashMap();
046:                mainTerm = null;
047:                mainClassInfo = null;
048:            }
049:
050:            /**
051:             * Resolve main table name.
052:             */
053:            public TableTerm resolve(ClassSpecifier specifier, boolean selected) {
054:                String alias = specifier.getAlias() != null ? specifier
055:                        .getAlias() : specifier.getClassName();
056:                // Insert symbol table entry
057:                SymbolTableEntry entry = (SymbolTableEntry) symbolTable
058:                        .get(alias);
059:                TableTerm tableTerm = null;
060:                if (entry == null) {
061:                    // Determine class for specifier
062:                    ClassInfo classInfo = context.getClassTracker()
063:                            .getMatchingClassInfo(specifier.getClassName());
064:                    if (classInfo == null)
065:                        throw new ParserException(ParserException.SYMBOL_ERROR,
066:                                "could not find class for table name: "
067:                                        + specifier.getClassName());
068:                    // Entry was null, create
069:                    entry = new SymbolTableEntry();
070:                    entry.alias = specifier.getAlias();
071:                    entry.tableName = classInfo.getTableName(classInfo
072:                            .getSourceEntry());
073:                    entry.automatic = false;
074:                    entry.expression = null;
075:                    entry.selected = true;
076:                    entry.classInfo = classInfo;
077:                    symbolTable.put(alias, entry);
078:                    if (specifier.getAlias() == null) {
079:                        // Insert default table name symbol too, for later left table
080:                        // term fixing, which will use the full table name
081:                        symbolTable.put(entry.tableName, entry);
082:                    }
083:                    logger.debug("adding table to symbol table: "
084:                            + entry.tableName + "(" + alias + ")");
085:                    // Construct table term
086:                    tableTerm = new TableTerm(classInfo.getTableName(classInfo
087:                            .getSourceEntry()), specifier.getAlias());
088:                    // Remember main table
089:                    if (selected) {
090:                        logger.debug("table entry " + entry.tableName + "("
091:                                + alias + ") is selected, adding left tables.");
092:                        // Remember
093:                        mainClassSpecifier = specifier;
094:                        mainClassInfo = classInfo;
095:                        mainTerm = tableTerm; // Main term is the selected class/table
096:                        // Fix entry to contain all relevant classes
097:                        fixLeftTableTerms(entry);
098:                        tableTerm.setLeftTableTerms(entry.leftTerms);
099:                    }
100:                } else {
101:                    // Construct table term
102:                    tableTerm = new TableTerm(entry.tableName, entry.alias);
103:                }
104:                // Return with table term
105:                logger.debug("translated: " + specifier + " -> " + tableTerm);
106:                return tableTerm;
107:            }
108:
109:            private ReferenceTerm getReferenceTerm(SymbolTableEntry entry) {
110:                switch (entry.type) {
111:                case SymbolTableEntry.TYPE_HANDLED:
112:                    return new ReferenceTerm(entry.tableName, entry.alias,
113:                            entry.referenceColumn);
114:                case SymbolTableEntry.TYPE_OBJECT:
115:                    return new ReferenceTerm(entry.tableName, entry.alias,
116:                            "persistence_id");
117:                default:
118:                    return null;
119:                }
120:            }
121:
122:            /**
123:             * Resolver attribute chain.
124:             */
125:            public ReferenceTerm resolve(ClassSpecifier specifier,
126:                    List attributeSpecifiers, boolean selected) {
127:                // Resolve class specifier
128:                // This is not as easy as it sounds: if there are no attribute
129:                // specifiers and there is no alias given, it may mean that
130:                // this identifier represents an attribute to selected main class
131:                // (if there is one).
132:                if (((attributeSpecifiers == null) || (attributeSpecifiers
133:                        .size() == 0))
134:                        && (specifier.getAlias() == null)
135:                        && (mainClassInfo != null)) {
136:                    String attributeName = specifier.getClassName();
137:                    if (mainClassInfo.getAttributeType(attributeName) != null) {
138:                        // Simulate a normal entry
139:                        specifier = mainClassSpecifier;
140:                        attributeSpecifiers = new Vector();
141:                        attributeSpecifiers.add(new AttributeSpecifier(
142:                                attributeName, null, null));
143:                    }
144:                }
145:                // Now go through names, the root name does already exist,
146:                // because that is the class. All other names are 
147:                // combined with attributes (book.title). This also should
148:                // be inserted into symbol table, if it is a class.
149:                resolve(specifier, selected); // Resolve class
150:                StringBuffer alias = new StringBuffer(
151:                        specifier.getAlias() == null ? specifier.getClassName()
152:                                : specifier.getAlias());
153:                SymbolTableEntry previousEntry = (SymbolTableEntry) symbolTable
154:                        .get(alias.toString());
155:                ClassInfo previousInfo = previousEntry.classInfo;
156:                AttributeSpecifier primitiveAttributeSpecifier = null;
157:                for (int i = 0; (attributeSpecifiers != null)
158:                        && (i < attributeSpecifiers.size()); i++) {
159:                    AttributeSpecifier spec = (AttributeSpecifier) attributeSpecifiers
160:                            .get(i);
161:                    String attributeName = spec.getIdentifier();
162:                    Class attributeClass = previousInfo
163:                            .getAttributeType(attributeName);
164:                    if (attributeClass == null)
165:                        throw new ParserException(ParserException.ABORT,
166:                                "can not resolve the identifier '"
167:                                        + attributeName + "' on '"
168:                                        + alias.toString() + "', classinfo: "
169:                                        + previousInfo);
170:                    alias.append("." + attributeName);
171:                    logger.debug("processing attribute: " + alias);
172:                    int attributeType = context.getClassTracker().getType(
173:                            attributeClass);
174:                    // Handle additional array specifier.
175:                    if ((spec.getKeyname() != null)
176:                            && (attributeType != ClassTracker.TYPE_HANDLED))
177:                        throw new ParserException(ParserException.ABORT,
178:                                "additional array specifier found, but type is not 'handled': "
179:                                        + alias);
180:                    if (attributeType == ClassTracker.TYPE_HANDLED) {
181:                        logger
182:                                .debug("attribute '"
183:                                        + alias
184:                                        + "' found to be a handled type, letting the handler in.");
185:                        // If the array specifier is given, add to alias
186:                        if (spec.getKeyname() != null)
187:                            alias.append("['" + spec.getKeyname() + "']");
188:                        // Calculate the symbol table entry for this part
189:                        SymbolTableEntry entry = (SymbolTableEntry) symbolTable
190:                                .get(alias.toString());
191:                        if (entry == null) {
192:                            entry = context.getTypeHandlerTracker().getHandler(
193:                                    attributeClass).getSymbolEntry(spec,
194:                                    previousEntry, previousInfo,
195:                                    getReferenceTerm(previousEntry));
196:                            if (entry.alias != null) {
197:                                // Entry wants to be in the symbol table
198:                                symbolTable.put(entry.alias, entry);
199:                            } else {
200:                                // Entry does no want into the symbol table,
201:                                // so create an extremal symbol.
202:                                int num = 0;
203:                                while (symbolTable.containsKey(alias.toString()
204:                                        + "-notused" + num))
205:                                    num++;
206:                                symbolTable.put(alias.toString() + "-notused"
207:                                        + num, entry);
208:                            }
209:                        }
210:                        previousEntry = entry;
211:                        // If this is not the last specifier, then calculate the
212:                        // class info for the next specifier.
213:                        if (i + 1 < attributeSpecifiers.size())
214:                            previousInfo = context.getTypeHandlerTracker()
215:                                    .getHandler(attributeClass).getSymbolInfo(
216:                                            entry, spec);
217:                    }
218:                    // Reserved type
219:                    if (attributeType == ClassTracker.TYPE_RESERVED)
220:                        throw new ParserException(ParserException.ABORT,
221:                                "attribute type is reserved, can not handle it: "
222:                                        + alias.toString());
223:                    // Attribute is an object
224:                    if (attributeType == ClassTracker.TYPE_OBJECT) {
225:                        logger.debug("attribute '" + alias
226:                                + "' found to be an object.");
227:                        ClassInfo containerInfo = previousInfo;
228:                        if (spec.getClassName() != null)
229:                            previousInfo = context.getClassTracker()
230:                                    .getMatchingClassInfo(spec.getClassName());
231:                        else
232:                            previousInfo = context
233:                                    .getClassTracker()
234:                                    .getClassInfo(
235:                                            previousInfo
236:                                                    .getAttributeType(attributeName),
237:                                            null);
238:                        // Get entry
239:                        SymbolTableEntry entry = (SymbolTableEntry) symbolTable
240:                                .get(alias.toString());
241:                        if (entry == null) {
242:                            // Create entry
243:                            entry = new SymbolTableEntry();
244:                            entry.alias = null;
245:                            entry.tableName = previousInfo
246:                                    .getTableName(previousInfo.getSourceEntry());
247:                            entry.automatic = true;
248:                            entry.type = SymbolTableEntry.TYPE_OBJECT;
249:                            entry.classInfo = previousInfo;
250:                            symbolTable.put(alias.toString(), entry);
251:                            // Create expression
252:                            Expression expr = new Expression();
253:                            // Determine whether the entry's tableName is correct, or if
254:                            // a superclass's table is required for attribute
255:                            TableTerm previousTerm = new TableTerm(
256:                                    previousEntry.tableName,
257:                                    previousEntry.alias);
258:                            ClassEntry super ClassEntry = containerInfo
259:                                    .getAttributeClassEntry(attributeName);
260:                            if (logger.isDebugEnabled())
261:                                logger.debug("selecting object attribute "
262:                                        + attributeName
263:                                        + ", class: "
264:                                        + previousEntry.classInfo
265:                                                .getSourceEntry()
266:                                        + ", superclass: " + super ClassEntry);
267:                            if (!previousEntry.classInfo.getSourceEntry()
268:                                    .equals(super ClassEntry)) {
269:                                // Class holding the attribute differs from entry's class.
270:                                // Note: if a superclass is in charge, there should be no
271:                                // dynamic name.
272:                                ClassInfo super Info = context.getClassTracker()
273:                                        .getClassInfo(super ClassEntry);
274:                                String super TableName = super Info
275:                                        .getTableName(super ClassEntry);
276:                                previousTerm = new TableTerm(super TableName,
277:                                        null);
278:                                if (logger.isDebugEnabled())
279:                                    logger
280:                                            .debug("determining whether to allocate supertable: "
281:                                                    + super TableName
282:                                                    + ", tables allocated: "
283:                                                    + previousEntry.allocatedSuperTables);
284:                                if (!previousEntry.allocatedSuperTables
285:                                        .contains(super TableName)) {
286:                                    logger.debug("allocating superclass: "
287:                                            + super ClassEntry);
288:                                    // This superclass was not yet allocated
289:                                    ReferenceTerm connectLeftTerm = new ReferenceTerm(
290:                                            previousEntry.tableName,
291:                                            previousEntry.alias,
292:                                            "persistence_id");
293:                                    previousEntry.termList.add(connectLeftTerm);
294:                                    expr.add(connectLeftTerm);
295:                                    expr.add("=");
296:                                    ReferenceTerm connectRightTerm = new ReferenceTerm(
297:                                            previousTerm, "persistence_id");
298:                                    previousEntry.termList
299:                                            .add(connectRightTerm);
300:                                    expr.add(connectRightTerm);
301:                                    expr.add("and");
302:                                    // Add to list
303:                                    previousEntry.allocatedSuperTables
304:                                            .add(super TableName);
305:                                }
306:                            }
307:                            // Rest of expression
308:                            ReferenceTerm leftTerm = new ReferenceTerm(
309:                                    previousTerm, attributeName);
310:                            previousEntry.termList.add(leftTerm);
311:                            expr.add(leftTerm);
312:                            expr.add("=");
313:                            ReferenceTerm refTerm = getReferenceTerm(entry);
314:                            expr.add(refTerm);
315:                            entry.termList.add(refTerm);
316:                            entry.expression = expr;
317:                        }
318:                        previousEntry = entry;
319:                    }
320:                    // Attribute is primitive type
321:                    if (attributeType == ClassTracker.TYPE_PRIMITIVE) {
322:                        logger.debug("attribute '" + alias
323:                                + "' found to be a primitive attribute.");
324:                        // A primitive type should be the last in the list
325:                        if (i + 1 < attributeSpecifiers.size())
326:                            throw new ParserException(ParserException.ABORT,
327:                                    "A primitive type encountered, but not the last in list: "
328:                                            + alias.toString());
329:                        // Mark primitive type
330:                        primitiveAttributeSpecifier = spec;
331:                    }
332:                }
333:                // If we're here, that means, attribute list has ended.
334:                // Either in a primitive type attribute or in object. 
335:                SymbolTableEntry entry = (SymbolTableEntry) symbolTable
336:                        .get(alias.toString());
337:                if (entry == null) {
338:                    // This means we are in an attribute, so get previous entry
339:                    entry = previousEntry;
340:                }
341:                // Construct and return term
342:                ReferenceTerm result = null;
343:                if (primitiveAttributeSpecifier != null) {
344:                    // Attribute specified, this means, we must check whether
345:                    // this attribute is part of the class in entry or in superclass.
346:                    TableTerm tableTerm = new TableTerm(entry.tableName,
347:                            entry.alias, entry.leftTerms);
348:                    ClassEntry super ClassEntry = entry.classInfo
349:                            .getAttributeClassEntry(primitiveAttributeSpecifier
350:                                    .getIdentifier());
351:                    if (logger.isDebugEnabled())
352:                        logger.debug("selecting primitive attribute "
353:                                + primitiveAttributeSpecifier.getIdentifier()
354:                                + ", class: "
355:                                + entry.classInfo.getSourceEntry()
356:                                + ", superclass: " + super ClassEntry);
357:                    if (!entry.classInfo.getSourceEntry().equals(
358:                            super ClassEntry)) {
359:                        // Class holding the attribute differs from entry's class
360:                        ClassInfo super Info = context.getClassTracker()
361:                                .getClassInfo(super ClassEntry);
362:                        String super TableName = super Info
363:                                .getTableName(super ClassEntry);
364:                        tableTerm = new TableTerm(super TableName, null);
365:                        if (!entry.allocatedSuperTables
366:                                .contains(super TableName)) {
367:                            logger
368:                                    .debug("primitive attribute is a related class' attribute, and not yet allocated.");
369:                            Expression expr = entry.expression;
370:                            if (expr == null) {
371:                                expr = new Expression();
372:                                entry.expression = expr;
373:                            }
374:                            if (expr.size() > 0)
375:                                expr.add("and");
376:                            // This superclass was not yet allocated
377:                            ReferenceTerm connectLeftTerm = new ReferenceTerm(
378:                                    entry.tableName, entry.alias,
379:                                    "persistence_id");
380:                            entry.termList.add(connectLeftTerm);
381:                            expr.add(connectLeftTerm);
382:                            expr.add("=");
383:                            ReferenceTerm connectRightTerm = new ReferenceTerm(
384:                                    tableTerm, "persistence_id");
385:                            entry.termList.add(connectRightTerm);
386:                            expr.add(connectRightTerm);
387:                            // Add to list
388:                            entry.allocatedSuperTables.add(super TableName);
389:                        }
390:                    }
391:                    // Construct result
392:                    String attributeName = primitiveAttributeSpecifier
393:                            .getIdentifier();
394:                    boolean id = false;
395:                    if ("persistenceid".equalsIgnoreCase(attributeName)) {
396:                        attributeName = "persistence_id";
397:                        id = true;
398:                    }
399:                    result = new ReferenceTerm(tableTerm, attributeName);
400:                    if (id) // Mark specifically for id reference
401:                        result.setId();
402:                } else {
403:                    // Term did not end in attribute specification, so leave
404:                    // persistence id, which is available in all tables
405:                    result = getReferenceTerm(entry);
406:                }
407:                entry.termList.add(result);
408:                return result; // Return term
409:            }
410:
411:            /**
412:             * Fix a primitive expression. Called from parser!
413:             * The problem is expressions like this: find holder where holder.attr = 'Ni'.
414:             * If the holder.attr is an object type, and not declared 'primitive', then
415:             * the parser can not know it is meant to be primitive only when it
416:             * comes to the right term which is primitive. So in this case, we
417:             * must alter the expression to include the primitive type's table.
418:             */
419:            public void fixPrimitiveExpression(Expression expr) {
420:                // Fix is only necessary if
421:                // - left term is a reference term
422:                // - left term does not point to a primitive type
423:                // - right term is a constant term
424:                // - right term is a primitive type (and not id)
425:                Object rawLeftTerm = expr.get(0);
426:                Object rawRightTerm = expr.get(2);
427:                if (!(rawLeftTerm instanceof  ReferenceTerm))
428:                    return;
429:                if (!(rawRightTerm instanceof  ConstantTerm))
430:                    return;
431:                ReferenceTerm leftTerm = (ReferenceTerm) rawLeftTerm;
432:                ConstantTerm rightTerm = (ConstantTerm) rawRightTerm;
433:                if (context.getClassTracker().getType(
434:                        rightTerm.getValue().getClass()) != ClassTracker.TYPE_PRIMITIVE)
435:                    return; // Not primitive
436:                if (rightTerm.isId() || leftTerm.isId())
437:                    return; // Is an Id expression specifically
438:                ClassInfo leftInfo = context.getClassTracker()
439:                        .getTableClassInfo(leftTerm.getTableName());
440:                if ((leftInfo != null)
441:                        && (context.getClassTracker().getType(
442:                                leftInfo.getAttributeType(leftTerm
443:                                        .getColumnName())) == ClassTracker.TYPE_PRIMITIVE))
444:                    return; // Attribute is primitive
445:                if (logger.isDebugEnabled())
446:                    logger.debug("fixing primitive expression: " + expr);
447:                // Now insert expression referencing the primitive type's table
448:                // Note: We must insert a symbol table entry for the primitive type's
449:                // table, but it's not a real symbol, it should have an extremal
450:                // name.
451:                ClassInfo primitiveInfo = context.getClassTracker()
452:                        .getClassInfo(rightTerm.getValue().getClass(),
453:                                rightTerm.getValue());
454:                String primitiveTableName = primitiveInfo
455:                        .getTableName(primitiveInfo.getSourceEntry());
456:                TableTerm primitiveTableTerm = new TableTerm(
457:                        primitiveTableName, null);
458:                SymbolTableEntry entry = new SymbolTableEntry();
459:                entry.alias = null;
460:                entry.tableName = primitiveTableName;
461:                entry.automatic = true;
462:                entry.type = SymbolTableEntry.TYPE_OBJECT;
463:                symbolTable.put("primitive" + symbolTable.size(), entry);
464:                // Create contact expression to primitive table
465:                Expression contactExpr = new Expression();
466:                contactExpr.add(leftTerm);
467:                contactExpr.add("=");
468:                ReferenceTerm contactTerm = new ReferenceTerm(
469:                        primitiveTableTerm, "persistence_id");
470:                contactExpr.add(contactTerm);
471:                entry.termList.add(contactTerm);
472:                entry.expression = contactExpr;
473:                // Alter original expression
474:                ReferenceTerm valueTerm = new ReferenceTerm(primitiveTableTerm,
475:                        "value");
476:                entry.termList.add(valueTerm);
477:                expr.set(0, valueTerm); // Replace original left term
478:            }
479:
480:            private boolean fixContainsNegated(Expression expr,
481:                    boolean isNegated) {
482:                if (expr == null)
483:                    return false;
484:                boolean originalNegated = isNegated;
485:                isNegated = false;
486:                for (int i = 0; i < expr.size(); i++) {
487:                    Object obj = expr.get(i);
488:                    if (obj instanceof  String) {
489:                        if ("contains".equalsIgnoreCase((String) obj)) {
490:                            if (isNegated ^ originalNegated)
491:                                return true;
492:                            expr.set(i, "="); // Replace with '=' sign
493:                        } else
494:                            isNegated = "not".equalsIgnoreCase((String) obj);
495:                    }
496:                    if ((obj instanceof  Expression)
497:                            && (fixContainsNegated((Expression) obj, isNegated
498:                                    ^ originalNegated)))
499:                        return true;
500:                }
501:                return false;
502:            }
503:
504:            /**
505:             * Fix unaliased generated table term.
506:             */
507:            private Expression fixAutomaticTerms(Expression expr) {
508:                // First, generate all temporary names
509:                allTableTerms = new Vector(); // Fill all table terms vector
510:                Expression plusExpression = new Expression();
511:                String namePrefix = "t_";
512:                int tempNameIndex = 1;
513:                // Entries will be filtered through a set, because a single
514:                // entry could be present in the map multiple times (for example
515:                // a main table is available as an alias, and as a table name entry)
516:                Iterator iterator = new HashSet(symbolTable.values())
517:                        .iterator();
518:                while (iterator.hasNext()) {
519:                    SymbolTableEntry entry = (SymbolTableEntry) iterator.next();
520:                    // Generate index for class and all superclasses!
521:                    HashMap tableNameAliases = new HashMap();
522:                    Vector tableNames = new Vector(entry.allocatedSuperTables);
523:                    if (entry.automatic)
524:                        tableNames.add(entry.tableName);
525:                    else
526:                        allTableTerms.add(new TableTerm(entry.tableName,
527:                                entry.alias));
528:                    for (int i = 0; i < tableNames.size(); i++) {
529:                        while (symbolTable.get(namePrefix + tempNameIndex) != null)
530:                            tempNameIndex++;
531:                        tableNameAliases.put(tableNames.get(i), namePrefix
532:                                + tempNameIndex);
533:                        allTableTerms.add(new TableTerm((String) tableNames
534:                                .get(i), namePrefix + tempNameIndex));
535:                        tempNameIndex++;
536:                    }
537:                    // Walk through referred terms and fill in the gaps
538:                    for (int i = 0; i < entry.termList.size(); i++) {
539:                        TableTerm term = (TableTerm) entry.termList.get(i);
540:                        String newAlias = (String) tableNameAliases.get(term
541:                                .getTableName());
542:                        if (newAlias != null)
543:                            term.setAlias(newAlias);
544:                    }
545:                    // Remember it's expression
546:                    if (entry.expression != null) {
547:                        if (logger.isDebugEnabled())
548:                            logger.debug("entry '" + entry.alias
549:                                    + "' has connector expression: "
550:                                    + entry.expression);
551:                        if (plusExpression.size() > 0)
552:                            plusExpression.add("and");
553:                        plusExpression.addAll(entry.expression);
554:                    }
555:                }
556:                // Now create final expression
557:                Expression result = expr;
558:                if (plusExpression.size() != 0) {
559:                    if (result.size() != 0) {
560:                        result = new Expression();
561:                        result.add(plusExpression);
562:                        result.add("and");
563:                        result.add(expr);
564:                    } else {
565:                        result = plusExpression;
566:                    }
567:                }
568:                // Return
569:                return result;
570:            }
571:
572:            /**
573:             * All all left table terms to term.
574:             */
575:            private void fixLeftTableTerms(ClassInfo info, TableTerm term,
576:                    List leftTerms) {
577:                // Calculate left table terms
578:                Set relatedClassEntries = new HashSet(context.getClassTracker()
579:                        .getRelatedClassEntries(info.getSourceEntry()));
580:                for (int i = 0; i < leftTerms.size(); i++) {
581:                    // Go through left term, if this is a left term to the info, then
582:                    // insert it to this term's left terms
583:                    TableTerm leftTerm = (TableTerm) leftTerms.get(i);
584:                    ClassEntry leftEntry = context.getClassTracker()
585:                            .getTableClassInfo(leftTerm.getTableName())
586:                            .getSourceEntry();
587:                    if (relatedClassEntries.contains(leftEntry))
588:                        term.getLeftTableTerms().add(leftTerm);
589:                }
590:            }
591:
592:            /**
593:             * Get the left table terms, which will contained in the select.
594:             */
595:            private void fixLeftTableTerms(SymbolTableEntry mainEntry) {
596:                // Calculate left table terms
597:                List relatedClassEntries = context.getClassTracker()
598:                        .getRelatedClassEntries(
599:                                mainEntry.classInfo.getSourceEntry());
600:                if (logger.isDebugEnabled())
601:                    logger.debug("found related classes: "
602:                            + relatedClassEntries + ", to class info: "
603:                            + mainEntry.classInfo);
604:                for (int i = 0; i < relatedClassEntries.size(); i++) {
605:                    ClassEntry relatedClassEntry = (ClassEntry) relatedClassEntries
606:                            .get(i);
607:                    ClassInfo relatedClassInfo = context.getClassTracker()
608:                            .getClassInfo(relatedClassEntry);
609:                    if (logger.isDebugEnabled())
610:                        logger.debug("found left joined class: "
611:                                + relatedClassEntry + ", class info: "
612:                                + relatedClassInfo);
613:                    if (relatedClassInfo == null)
614:                        throw new ParserException(ParserException.ABORT,
615:                                "object class not found for loading: '"
616:                                        + relatedClassEntry + "'");
617:                    // Create the term and add to mainterm
618:                    TableTerm leftTerm = new TableTerm(relatedClassInfo
619:                            .getTableName(relatedClassEntry), null);
620:                    if (logger.isDebugEnabled())
621:                        logger.debug("adding left term to: "
622:                                + mainEntry.tableName + "(" + mainEntry.alias
623:                                + "), left term: " + leftTerm);
624:                    allLeftTableTerms.add(leftTerm);
625:                    mainEntry.termList.add(leftTerm);
626:                    mainEntry.leftTerms.add(leftTerm);
627:                    mainEntry.allocatedSuperTables.add(leftTerm.getTableName());
628:                }
629:            }
630:
631:            /**
632:             * Add date constraint expressions.
633:             */
634:            private Expression fixDateConstraints(List localAllTableTerms,
635:                    List localAllLeftTableTerms, Expression expr,
636:                    TimeControl timeControl) {
637:                Expression dateExpression = new Expression();
638:                // Generate date constraints for all tables
639:                for (int i = 0; i < localAllTableTerms.size(); i++) {
640:                    TableTerm term = (TableTerm) localAllTableTerms.get(i);
641:                    // Add to date constraints
642:                    if (dateExpression.size() != 0)
643:                        dateExpression.add("and");
644:                    if (localAllLeftTableTerms.contains(term)) {
645:                        // Left table
646:                        timeControl.applyToLeftTable(dateExpression, term);
647:                    } else {
648:                        // Not a left table, so no null values possible
649:                        timeControl.apply(dateExpression, term);
650:                    }
651:                }
652:                // Return
653:                Expression result = expr;
654:                if (dateExpression.size() != 0) {
655:                    if ((result != null) && (result.size() != 0)) {
656:                        result = new Expression();
657:                        result.add(dateExpression);
658:                        result.add("and");
659:                        result.add(expr);
660:                    } else {
661:                        result = dateExpression;
662:                    }
663:                }
664:                // Return
665:                return result;
666:            }
667:
668:            private boolean validViewSelectTables(QueryStatement stmt) {
669:                if (stmt.getMode() == QueryStatement.MODE_FIND)
670:                    return true; // Valid, because it is in find mode
671:                // Check whether all selected terms are storable
672:                for (int i = 0; i < stmt.getSelectTerms().size(); i++) {
673:                    TableTerm term = (TableTerm) stmt.getSelectTerms().get(i);
674:                    ClassEntry entry = context.getClassTracker()
675:                            .getTableClassInfo(term.getTableName())
676:                            .getSourceEntry();
677:                    if (!entry.isStorable())
678:                        return false;
679:                }
680:                return true;
681:            }
682:
683:            private void fixNonstorableTerms(List selectTerms, Expression expr) {
684:                // Go through all terms, and those which are not storable and
685:                // not selected need to be substituted with ids table.
686:                if (expr == null)
687:                    return;
688:                for (int i = 0; i < expr.size(); i++) {
689:                    Object value = expr.get(i);
690:                    if (value instanceof  Expression) {
691:                        fixNonstorableTerms(selectTerms, (Expression) value);
692:                    } else if (value instanceof  TableTerm) {
693:                        // Found a table term
694:                        TableTerm term = (TableTerm) value;
695:                        ClassInfo info = context.getClassTracker()
696:                                .getTableClassInfo(term.getTableName());
697:                        if (info == null)
698:                            continue; // No worries, most likely an internal table
699:                        ClassEntry entry = info.getSourceEntry();
700:                        if ((!selectTerms.contains(term))
701:                                && (!entry.isStorable())) {
702:                            // A non-storable entry's term found which is not selected,
703:                            // so substitute
704:                            allTableTerms.remove(term); // Remove from time control
705:                            term.setTableName("persistence_object_ids"); // Alter to ids
706:                        }
707:                    }
708:                }
709:            }
710:
711:            private void fixOrderBys(QueryStatement stmt) {
712:                if (stmt.getOrderByList() == null)
713:                    stmt.setOrderByList(new Vector());
714:                if (stmt.getMode() == QueryStatement.MODE_FIND) {
715:                    // Find mode: add default order by on persistence_id
716:                    TableTerm mainTerm = (TableTerm) stmt.getSelectTerms().get(
717:                            0);
718:                    OrderBy orderBy = new OrderBy(new ReferenceTerm(mainTerm,
719:                            "persistence_id"), OrderBy.ASCENDING);
720:                    if (!stmt.getOrderByList().contains(orderBy))
721:                        stmt.getOrderByList().add(orderBy);
722:                } else {
723:                    // View mode: add all view attributes as order bys, so
724:                    // listing becomes unambigous.
725:                    for (int i = 0; i < stmt.getSelectTerms().size(); i++) {
726:                        ReferenceTerm term = (ReferenceTerm) stmt
727:                                .getSelectTerms().get(i);
728:                        OrderBy orderBy = new OrderBy(term, OrderBy.ASCENDING);
729:                        if (!stmt.getOrderByList().contains(orderBy))
730:                            stmt.getOrderByList().add(orderBy);
731:                    }
732:                }
733:            }
734:
735:            /**
736:             * Generate the final statements.
737:             */
738:            public QueryStatementList generate(QueryStatement stmt) {
739:                Expression expr = stmt.getQueryExpression();
740:                if (expr == null)
741:                    expr = new Expression();
742:                if (logger.isDebugEnabled()) {
743:                    logger.debug("symbol table before finalizing: "
744:                            + symbolTable);
745:                    logger.debug("expression before finalizing: " + expr);
746:                }
747:                // Add default order bys
748:                fixOrderBys(stmt);
749:                // Check whether 'contains' operator is negated (this is not allowed)
750:                // if it does not, then substitute with '=' sign.
751:                if (fixContainsNegated(expr, false))
752:                    throw new ParserException(
753:                            ParserException.ABORT,
754:                            "'contains' operator is negated, this may not mean what you think it means, so it's disallowed.");
755:                // If this is a view select, check whether all selected terms
756:                // are storable.
757:                if (!validViewSelectTables(stmt))
758:                    throw new ParserException(
759:                            ParserException.ABORT,
760:                            "view selects can not contain non-storable terms (ie. interface types and abstract objects as selected terms).");
761:                // Generate left table terms for selected tables
762:                stmt.setAllLeftTableTerms(allLeftTableTerms);
763:                // Generate aliases and connector expressions
764:                stmt.setQueryExpression(fixAutomaticTerms(expr));
765:                // Fix all non-storable terms that are used in the expression but
766:                // not selected.
767:                fixNonstorableTerms(stmt.getSelectTerms(), stmt
768:                        .getQueryExpression());
769:                // Now generate all the root queries for this query.
770:                // View selects can not contain non-storable terms, and find
771:                // selects can only contain 1 main term, so get the roots for
772:                // this main term, and iterate over it's roots.
773:                QueryStatementList stmts = new QueryStatementList();
774:                TableTerm selectTerm = (TableTerm) stmt.getSelectTerms().get(0);
775:                ClassEntry selectEntry = context.getClassTracker()
776:                        .getTableClassInfo(selectTerm.getTableName())
777:                        .getSourceEntry();
778:                List roots = context.getClassTracker()
779:                        .getStorableRootClassEntries(selectEntry);
780:                // Prepare local lists, these will be used later
781:                Vector localAllTableTermsCore = new Vector(allTableTerms);
782:                Vector localAllLeftTableTermsCore = new Vector(
783:                        allLeftTableTerms);
784:                localAllTableTermsCore.remove(selectTerm);
785:                localAllTableTermsCore
786:                        .removeAll(selectTerm.getLeftTableTerms());
787:                localAllLeftTableTermsCore.removeAll(selectTerm
788:                        .getLeftTableTerms());
789:                if (logger.isDebugEnabled())
790:                    logger.debug("determined roots for " + selectEntry + ": "
791:                            + roots);
792:                // Now generate the statements themselves
793:                for (int r = 0; r < roots.size(); r++) {
794:                    // Clone statement
795:                    QueryStatement subStmt = stmt.deepCopy();
796:                    Vector localAllTableTerms = new Vector(
797:                            localAllTableTermsCore);
798:                    Vector localAllLeftTableTerms = new Vector(
799:                            localAllLeftTableTermsCore);
800:                    // The counter determines with which root to replace select term with
801:                    ClassEntry rootEntry = (ClassEntry) roots.get(r);
802:                    if (logger.isDebugEnabled())
803:                        logger.debug("entry " + selectEntry
804:                                + " is to be replaced with root entry: "
805:                                + rootEntry);
806:                    ClassInfo rootInfo = context.getClassTracker()
807:                            .getClassInfo(rootEntry);
808:                    TableTerm rootTerm = selectTerm.deepCopy();
809:                    rootTerm.setTableName(rootInfo.getTableName(rootEntry));
810:                    rootTerm.getLeftTableTerms().clear();
811:                    fixLeftTableTerms(rootInfo, rootTerm, selectTerm
812:                            .getLeftTableTerms()); // Add left table terms
813:                    if (logger.isDebugEnabled())
814:                        logger.debug("entry " + selectEntry + " (" + selectTerm
815:                                + ") is replaced with root entry: " + rootEntry
816:                                + " (" + rootTerm + ")");
817:                    // Do replace operation in statement. This will replace
818:                    // the term everywhere.
819:                    subStmt.replace(selectTerm, rootTerm);
820:                    // All tables to the local all tables list for later date fix
821:                    localAllTableTerms.add(rootTerm);
822:                    localAllTableTerms.addAll(rootTerm.getLeftTableTerms());
823:                    localAllLeftTableTerms.addAll(rootTerm.getLeftTableTerms());
824:                    subStmt.setAllLeftTableTerms(localAllLeftTableTerms);
825:                    // Generate static representation (it is important, that this is
826:                    // before date constraints are added
827:                    subStmt.setStaticRepresentation(subStmt.getMode()
828:                            + " "
829:                            + subStmt.getSelectTerms().toString()
830:                            + " "
831:                            + (subStmt.getQueryExpression() != null ? subStmt
832:                                    .getQueryExpression().toString() : "")
833:                            + (subStmt.getOrderByList() != null ? subStmt
834:                                    .getOrderByList().toString() : ""));
835:                    // Generate date constraints
836:                    subStmt.setQueryExpression(fixDateConstraints(
837:                            localAllTableTerms, localAllLeftTableTerms, subStmt
838:                                    .getQueryExpression(), subStmt
839:                                    .getTimeControl()));
840:                    // Debug
841:                    if (logger.isDebugEnabled())
842:                        logger.debug("generated statement, selected: "
843:                                + subStmt.getSelectTerms() + ", expression: "
844:                                + subStmt.getQueryExpression() + ", order by: "
845:                                + subStmt.getOrderByList());
846:                    // Insert complete query into result query list
847:                    stmts.add(subStmt);
848:                }
849:                // Now generate the all ids statement. This is a statement which provides
850:                // all ids of all selected objects in one statement.
851:                if (stmts.size() == 1) {
852:                    // Only one statement, so the ids are provided by that
853:                    stmts.setAllIdsStatement((QueryStatement) stmts.get(0));
854:                } else {
855:                    // Multiple statements. This is only possible in 'find' mode, so
856:                    // there is a single term, which needs to be substituted with the
857:                    // 'ids' table. This is possible, since the table in question is
858:                    // non-storable, that means it has got no attributes.
859:                    QueryStatement subStmt = stmt.deepCopy();
860:                    if (logger.isDebugEnabled())
861:                        logger.debug("entry " + selectEntry
862:                                + " is to be replaced with ids table.");
863:                    TableTerm rootTerm = new TableTerm(
864:                            "persistence_object_ids", selectTerm.getAlias());
865:                    // Do replace operation in statement. This will replace
866:                    // the term everywhere.
867:                    subStmt.replace(selectTerm, rootTerm);
868:                    // We do not want date constraints on ids table, so the core
869:                    // table lists are ok.
870:                    subStmt.setAllLeftTableTerms(localAllLeftTableTermsCore);
871:                    // Generate static representation (it is important, that this is
872:                    // before date constraints are added
873:                    subStmt.setStaticRepresentation(subStmt.getMode()
874:                            + " "
875:                            + subStmt.getSelectTerms().toString()
876:                            + " "
877:                            + (subStmt.getQueryExpression() != null ? subStmt
878:                                    .getQueryExpression().toString() : "")
879:                            + (subStmt.getOrderByList() != null ? subStmt
880:                                    .getOrderByList().toString() : ""));
881:                    // Generate date constraints
882:                    subStmt.setQueryExpression(fixDateConstraints(
883:                            localAllTableTermsCore, localAllLeftTableTermsCore,
884:                            subStmt.getQueryExpression(), subStmt
885:                                    .getTimeControl()));
886:                    // Debug
887:                    if (logger.isDebugEnabled())
888:                        logger
889:                                .debug("generated 'all ids' statement, selected: "
890:                                        + subStmt.getSelectTerms()
891:                                        + ", expression: "
892:                                        + subStmt.getQueryExpression()
893:                                        + ", order by: "
894:                                        + subStmt.getOrderByList());
895:                    // Set all ids select term 
896:                    stmts.setAllIdsStatement(subStmt);
897:                }
898:                return stmts;
899:            }
900:
901:            public static class SymbolTableEntry {
902:                public static final int TYPE_HANDLED = 1;
903:                public static final int TYPE_OBJECT = 3;
904:                public static final int TYPE_PRIMITIVE = 4;
905:
906:                public String alias; // Alias of table entry
907:                public String tableName; // The table name
908:                public String referenceColumn;
909:                // Used by handled types, definies the
910:                // reference column, if sub-specified.
911:                public boolean selected; // Whether this entry will be selected
912:                public List termList; // List of terms in which it could not
913:                // be resolved yet
914:                public List leftTerms; // Left table terms for entry.
915:                public List allocatedSuperTables;
916:                // The list of tables of superclasses
917:                // already allocated (used)
918:                public ClassInfo classInfo;// Class info if symbol is a table
919:                public boolean automatic; // Whether symbol should be automatically
920:                // generated
921:                public Expression expression;
922:                // The expression this entry generated
923:                public int type = TYPE_OBJECT;
924:
925:                public SymbolTableEntry() {
926:                    termList = new LinkedList();
927:                    allocatedSuperTables = new LinkedList();
928:                    leftTerms = new LinkedList();
929:                }
930:
931:                public String toString() {
932:                    return "[Symbol entry: " + tableName + " (" + alias + "), "
933:                            + type + ":" + automatic + "]";
934:                }
935:            }
936:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.