Source Code Cross Referenced for ComposedQuery.java in  » Web-Framework » makumba » org » makumba » list » engine » 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 » Web Framework » makumba » org.makumba.list.engine 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        ///////////////////////////////
002:        //  Makumba, Makumba tag library
003:        //  Copyright (C) 2000-2003  http://www.makumba.org
004:        //
005:        //  This library is free software; you can redistribute it and/or
006:        //  modify it under the terms of the GNU Lesser General Public
007:        //  License as published by the Free Software Foundation; either
008:        //  version 2.1 of the License, or (at your option) any later version.
009:        //
010:        //  This library is distributed in the hope that it will be useful,
011:        //  but WITHOUT ANY WARRANTY; without even the implied warranty of
012:        //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013:        //  Lesser General Public License for more details.
014:        //
015:        //  You should have received a copy of the GNU Lesser General Public
016:        //  License along with this library; if not, write to the Free Software
017:        //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
018:        //
019:        //  -------------
020:        //  $Id: ComposedQuery.java 2150 2007-11-22 17:16:18Z cristian_bogdan $
021:        //  $Name$
022:        /////////////////////////////////////
023:
024:        package org.makumba.list.engine;
025:
026:        import java.util.Enumeration;
027:        import java.util.HashMap;
028:        import java.util.Hashtable;
029:        import java.util.Iterator;
030:        import java.util.Map;
031:        import java.util.StringTokenizer;
032:        import java.util.Vector;
033:
034:        import org.makumba.DataDefinition;
035:        import org.makumba.FieldDefinition;
036:        import org.makumba.InvalidFieldTypeException;
037:        import org.makumba.LogicException;
038:        import org.makumba.commons.ArgumentReplacer;
039:        import org.makumba.list.tags.QueryTag;
040:        import org.makumba.providers.QueryProvider;
041:
042:        /**
043:         * An OQL query composed from various elements found in script pages. It can be enriched when a new element is found. It
044:         * has a prepared Qyuery correspondent in a makumba database It may be based on a super query.
045:         * 
046:         * @author Cristian Bogdan
047:         * @version $Id: ComposedQuery.java 2150 2007-11-22 17:16:18Z cristian_bogdan $
048:         */
049:        public class ComposedQuery {
050:
051:            /**
052:             * Interface for an Evaluator which can evaluate expressions
053:             * 
054:             * @author Cristian Bogdan
055:             */
056:            public static interface Evaluator {
057:
058:                /**
059:                 * Evaluates the expression
060:                 * 
061:                 * @param s
062:                 *            the expression to evaluate
063:                 * @return The transformed expression after evaluation
064:                 */
065:                String evaluate(String s);
066:            }
067:
068:            public QueryProvider qep = null;
069:
070:            /**
071:             * Default constructor
072:             * 
073:             * @param sections
074:             * @param usesHQL
075:             */
076:            public ComposedQuery(String[] sections, String queryLanguage) {
077:                this .sections = sections;
078:                this .derivedSections = sections;
079:                this .qep = QueryProvider.makeQueryAnalzyer(queryLanguage);
080:            }
081:
082:            /** The subqueries of this query */
083:            Vector<ComposedSubquery> subqueries = new Vector<ComposedSubquery>();
084:
085:            /** The projections made in this query */
086:            Vector<Object> projections = new Vector<Object>();
087:
088:            /** The expression associated to each projection */
089:            Hashtable<String, Integer> projectionExpr = new Hashtable<String, Integer>();
090:
091:            /** Standard index for the FROM query section */
092:            public static final int FROM = 0;
093:
094:            /** Standard index for the WHERE query section */
095:            public static final int WHERE = 1;
096:
097:            /** Standard index for the GROUPBY query section */
098:            public static final int GROUPBY = 2;
099:
100:            /** Standard index for the ORDERBY query section */
101:            public static final int ORDERBY = 3;
102:
103:            /** Standard index for the VARFROM query section */
104:            public static final int VARFROM = 4;
105:
106:            /** Section texts, encoded with the standard indexes */
107:            String[] sections;
108:
109:            /** Derived section texts, made from the sections of this query and the sections of its superqueries */
110:            String[] derivedSections;
111:
112:            String typeAnalyzerOQL;
113:
114:            String fromAnalyzerOQL;
115:
116:            /**
117:             * The keyset defining the primary key for this query. Normally the primary key is made of the keys declared in
118:             * FROM, in this query and all the parent queries. Keys are kept as integers (indexes)
119:             */
120:            Vector<Integer> keyset;
121:
122:            /** The keyset of all the parent queries */
123:            Vector previousKeyset;
124:
125:            /** The labels of the keyset */
126:            Vector<String> keysetLabels;
127:
128:            /** A Vector containing and empty vector. Used for empty keysets */
129:            static Vector empty;
130:            static {
131:                empty = new Vector();
132:                empty.addElement(new Vector());
133:            }
134:
135:            /**
136:             * Gets the type of the result
137:             * 
138:             * @return The DataDefinition corresponding to the type of the result
139:             */
140:            public DataDefinition getResultType() {
141:                if (typeAnalyzerOQL == null) {
142:                    return null;
143:                } else {
144:                    return qep.getQueryAnalysis(typeAnalyzerOQL)
145:                            .getProjectionType();
146:                }
147:            }
148:
149:            /**
150:             * Gets the type of a given label
151:             * 
152:             * @param s
153:             *            the name of the label
154:             * @return A DataDefinition corresponding to the type of the label
155:             */
156:            public DataDefinition getLabelType(String s) {
157:                if (typeAnalyzerOQL == null) {
158:                    return null;
159:                } else {
160:                    return qep.getQueryAnalysis(typeAnalyzerOQL)
161:                            .getLabelType(s);
162:                }
163:            }
164:
165:            /**
166:             * Initializes the object. This is a template method
167:             */
168:            public void init() {
169:                initKeysets();
170:                fromAnalyzerOQL = "SELECT 1 ";
171:                if (getFromSection() != null)
172:                    fromAnalyzerOQL += "FROM " + getFromSection();
173:            }
174:
175:            /**
176:             * Gets the FROM section
177:             * 
178:             * @return A String containing the FROM section of the query
179:             */
180:            public String getFromSection() {
181:                return derivedSections[FROM];
182:            }
183:
184:            /**
185:             * Initializes the keysets. previousKeyset is "empty"
186:             */
187:            protected void initKeysets() {
188:                previousKeyset = empty;
189:                keyset = new Vector<Integer>();
190:                keysetLabels = new Vector<String>();
191:            }
192:
193:            /**
194:             * Adds a subquery to this query. Makes it aware that it has subqueries at all. Makes it be able to announce its
195:             * subqueries about changes (this will be needed when unique=true will be possible)
196:             * 
197:             * @param q
198:             *            the subquery
199:             */
200:            protected void addSubquery(ComposedSubquery q) {
201:                if (subqueries.size() == 0)
202:                    prependFromToKeyset();
203:                subqueries.addElement(q);
204:            }
205:
206:            /**
207:             * Adds all keys from the FROM section to the keyset, and their labels to the keyLabels. They are all added as
208:             * projections (this has to change)
209:             */
210:            protected void prependFromToKeyset() {
211:                projectionExpr.clear();
212:                Enumeration e = ((Vector) projections.clone()).elements();
213:                projections.removeAllElements();
214:
215:                // add the previous keyset
216:                for (int i = 0; i < keyset.size(); i++)
217:                    checkProjectionInteger((String) e.nextElement());
218:
219:                for (StringTokenizer st = new StringTokenizer(
220:                        sections[FROM] == null ? "" : sections[FROM], ","); st
221:                        .hasMoreTokens();) {
222:                    String label = st.nextToken().trim();
223:                    int j = label.lastIndexOf(" ");
224:                    if (j == -1)
225:                        throw new RuntimeException("invalid FROM");
226:                    label = label.substring(j + 1).trim();
227:
228:                    label = qep.getPrimaryKeyNotation(label);
229:
230:                    keysetLabels.addElement(label);
231:
232:                    keyset.addElement(addProjection(label));
233:                }
234:
235:                while (e.hasMoreElements())
236:                    checkProjectionInteger((String) e.nextElement());
237:            }
238:
239:            /**
240:             * Gets a given projection
241:             * 
242:             * @param n
243:             *            the index of the projection
244:             * @return A String containing the projection
245:             */
246:            public String getProjectionAt(int n) {
247:                return (String) projections.elementAt(n);
248:            }
249:
250:            /**
251:             * Adds a projection with the given expression
252:             * 
253:             * @param expr
254:             *            the expression to add
255:             * @return The index at which the expression was added
256:             */
257:            Integer addProjection(String expr) {
258:                Integer index = new Integer(projections.size());
259:                projections.addElement(expr);
260:                projectionExpr.put(expr, index);
261:                return index;
262:            }
263:
264:            /**
265:             * Checks if a projection exists, and if not, adds it.
266:             * 
267:             * @param expr
268:             *            the expression to add
269:             * @return The index of the added projection
270:             */
271:            public Integer checkProjectionInteger(String expr) {
272:                Integer index = (Integer) projectionExpr.get(expr);
273:                if (index == null) {
274:                    addProjection(expr);
275:                    // FIXME: if DISTINCT is true, need to recompute the keyset and notify the subqueries to recompute their
276:                    // previous keyset
277:                    return null;
278:                }
279:                return index;
280:            }
281:
282:            /**
283:             * Checks if a projection exists, and if not, adds it.
284:             * 
285:             * @param expr
286:             *            the expression to add
287:             * @return The column name of the projection
288:             */
289:            String checkProjection(String expr) {
290:                Integer i = checkProjectionInteger(expr);
291:                if (i == null)
292:                    return null;
293:                return columnName(i);
294:            }
295:
296:            /**
297:             * Gets the name of a column indicated by index
298:             * 
299:             * @param n
300:             *            the index of the column
301:             * @return A String containing the name of the column, of the kind "colN"
302:             */
303:            public static String columnName(Integer n) {
304:                return "col" + (n.intValue() + 1);
305:            }
306:
307:            /**
308:             * Checks the orderBy or groupBy expressions to see if they are already selected, if not adds a projection. Only
309:             * group by and order by labels.
310:             * 
311:             * @param str
312:             *            an orderBy or groupBy expression
313:             * @return The checked expression, transformed according to the projections
314:             */
315:            String checkExpr(String str) {
316:                if (!qep.selectGroupOrOrderAsLabels())
317:                    return str;
318:                if (str == null)
319:                    return null;
320:                if (str.trim().length() == 0)
321:                    return null;
322:                // if(projections.size()==1)
323:                // new Throwable().printStackTrace();
324:
325:                StringBuffer ret = new StringBuffer();
326:                String sep = "";
327:                for (StringTokenizer st = new StringTokenizer(str, ","); st
328:                        .hasMoreTokens();) {
329:                    ret.append(sep);
330:                    sep = ",";
331:                    String s = st.nextToken().trim();
332:                    String rest = "";
333:                    int i = s.indexOf(" ");
334:                    if (i != -1) {
335:                        rest = s.substring(i);
336:                        s = s.substring(0, i);
337:                    }
338:                    // if the projection doesnt exist, this returns null, but it adds a new projection
339:                    String p = checkProjection(s);
340:                    if (p == null)
341:                        // and the second time this doesn#t return null, but the projection name
342:                        p = checkProjection(s);
343:                    ret.append(p).append(rest);
344:                }
345:                return ret.toString();
346:            }
347:
348:            /**
349:             * Computes the query from its sections
350:             * 
351:             * @param derivedSections
352:             *            the sections of this query
353:             * @param typeAnalysisOnly
354:             *            indicates whether this is only a type analysis
355:             * @return The computed OQL query
356:             */
357:            protected String computeQuery(String derivedSections[],
358:                    boolean typeAnalysisOnly) {
359:                String groups = null;
360:                String orders = null;
361:                if (!typeAnalysisOnly) {
362:                    groups = checkExpr((String) derivedSections[GROUPBY]);
363:                    orders = checkExpr((String) derivedSections[ORDERBY]);
364:                }
365:
366:                StringBuffer sb = new StringBuffer();
367:                sb.append("SELECT ");
368:                String sep = "";
369:
370:                int i = 0;
371:
372:                for (Enumeration e = projections.elements(); e
373:                        .hasMoreElements();) {
374:                    sb.append(sep);
375:                    sep = ",";
376:                    sb.append(e.nextElement()).append(" AS ").append(
377:                            columnName(new Integer(i++)));
378:                }
379:                Object o;
380:
381:                if ((o = derivedSections[FROM]) != null) {
382:                    sb.append(" FROM ");
383:                    sb.append(o);
384:
385:                    // there can be no VARFROM without FROM
386:                    // VARFROM is not part of type analysis
387:                    // (i.e. projections don't know about it)
388:                    if (!typeAnalysisOnly && derivedSections.length == 5
389:                            && derivedSections[VARFROM] != null
390:                            && derivedSections[VARFROM].trim().length() > 0)
391:                        sb.append(",").append(derivedSections[VARFROM]);
392:                }
393:                if (!typeAnalysisOnly) {
394:                    if ((o = derivedSections[WHERE]) != null
395:                            && derivedSections[WHERE].trim().length() > 0) {
396:                        sb.append(" WHERE ");
397:                        sb.append(o);
398:                    }
399:                    if (groups != null) {
400:                        sb.append(" GROUP BY ");
401:                        sb.append(groups);
402:                    }
403:                    if (orders != null) {
404:                        sb.append(" ORDER BY ");
405:                        sb.append(orders);
406:                    }
407:                }
408:                String ret = sb.toString();
409:                if (!typeAnalysisOnly)
410:                    return ret;
411:
412:                // replace names with numbers
413:                ArgumentReplacer ar = new ArgumentReplacer(ret);
414:                Map<String, Object> d = new HashMap<String, Object>();
415:                int j = 1;
416:                for (Iterator<String> e = ar.getArgumentNames(); e.hasNext();)
417:                    d.put(e.next(), "$" + (j++));
418:                return ar.replaceValues(d);
419:            }
420:
421:            // ------------
422:            /**
423:             * Executes the contained query in the given database
424:             * 
425:             * @param qep
426:             *            the database where the query should be ran
427:             * @param args
428:             *            the arguments we may need during the execution
429:             * @param v
430:             *            the evaluator evaluating the expressions
431:             * @param offset
432:             *            at which iteration this query should start
433:             * @param limit
434:             *            how many times should this query be ran
435:             * @throws LogicException
436:             */
437:            public Grouper execute(QueryProvider qep, Map args, Evaluator v,
438:                    int offset, int limit) throws LogicException {
439:                analyze();
440:                String[] vars = new String[5];
441:                vars[0] = getFromSection();
442:                for (int i = 1; i < 5; i++)
443:                    vars[i] = derivedSections[i] == null ? null : v
444:                            .evaluate(derivedSections[i]);
445:
446:                return new Grouper(previousKeyset, qep.execute(
447:                        computeQuery(vars, false), args, offset, limit)
448:                        .elements());
449:            }
450:
451:            public synchronized void analyze() {
452:                if (projections.isEmpty())
453:                    prependFromToKeyset();
454:                if (typeAnalyzerOQL == null)
455:                    typeAnalyzerOQL = computeQuery(derivedSections, true);
456:            }
457:
458:            /**
459:             * Checks if an expression is valid, nullable or set
460:             * 
461:             * @param expr
462:             *            the expression
463:             * @return The path to the null pointer (if the object is nullable), <code>null</code> otherwise
464:             */
465:            public Object checkExprSetOrNullable(String expr) {
466:                if (expr.toLowerCase().indexOf(" from ") != -1)
467:                    // subqueries do not need separate queries
468:                    return null;
469:                int n = 0;
470:                int m = 0;
471:                while (true) {
472:                    // FIXME: this is a not that good algorithm for finding label.field1.fiel2.field3
473:                    while (n < expr.length() && !isMakId(expr.charAt(n)))
474:                        n++;
475:
476:                    if (n == expr.length())
477:                        return null;
478:                    m = n;
479:                    while (n < expr.length() && isMakId(expr.charAt(n)))
480:                        n++;
481:                    Object nl = checkLabelSetOrNullable(expr.substring(m, n));
482:                    if (nl != null)
483:                        return nl;
484:                    if (n == expr.length())
485:                        return null;
486:                }
487:            }
488:
489:            /**
490:             * Checks if a character can be part of a makumba identifier
491:             * 
492:             * @param c
493:             *            the character to check
494:             * @return <code>true</code> if the character can be part of a makumba identifier, <code>false</code> otherwise
495:             */
496:            static boolean isMakId(char c) {
497:                return Character.isJavaIdentifierPart(c) || c == '.';
498:            }
499:
500:            /**
501:             * Checks if an id is nullable, and if so, return the path to the null pointer
502:             * 
503:             * @param referenceSequence
504:             *            a sequence like field1.field2.field3
505:             * @return The path to the null pointer (if the object is nullable), <code>null</code> otherwise
506:             */
507:            public Object checkLabelSetOrNullable(String referenceSequence) {
508:                int dot = referenceSequence.indexOf(".");
509:                if (dot == -1)
510:                    return null;
511:                String substring = referenceSequence.substring(0, dot);
512:                try { // if the "label" is actually a real number as 3.0
513:                    Integer.parseInt(substring);
514:                    return null; // if so, just return
515:                } catch (NumberFormatException e) {
516:                }
517:                DataDefinition dd = qep.getQueryAnalysis(fromAnalyzerOQL)
518:                        .getLabelType(substring);
519:                if (dd == null)
520:                    throw new org.makumba.InvalidValueException(
521:                            "no such label " + substring);
522:                while (true) {
523:                    int dot1 = referenceSequence.indexOf(".", dot + 1);
524:                    if (dot1 == -1) {
525:                        String fn = referenceSequence.substring(dot + 1);
526:                        FieldDefinition fd = dd.getFieldDefinition(fn);
527:                        if (fd == null
528:                                && (fd = qep.getAlternativeField(dd, fn)) == null)
529:                            throw new org.makumba.NoSuchFieldException(dd, fn);
530:
531:                        if (fd.getType().equals("set"))
532:                            return fd;
533:                        return null;
534:                    }
535:                    FieldDefinition fd = dd
536:                            .getFieldDefinition(referenceSequence.substring(
537:                                    dot + 1, dot1));
538:                    if (fd == null)
539:                        throw new org.makumba.NoSuchFieldException(dd,
540:                                referenceSequence.substring(dot + 1, dot1));
541:                    if (!fd.getType().startsWith("ptr"))
542:                        throw new InvalidFieldTypeException(fd, "pointer");
543:                    if (!fd.isNotNull())
544:                        return referenceSequence.substring(0, dot1);
545:                    dd = fd.getPointedType();
546:                    dot = dot1;
547:                }
548:            }
549:
550:            /**
551:             * allows to directly set a projection. Used for totalCount in
552:             * {@link QueryTag#doAnalyzedStartTag(org.makumba.analyser.PageCache)} to compose a query with 'count(*)' as the
553:             * only projection.
554:             */
555:            public void addProjection(Object o) {
556:                projections.add(o);
557:            }
558:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.