001: /**
002: * JOnAS: Java(TM) Open Application Server
003: * Copyright (C) 1999-2004 Bull S.A.
004: * Contact: jonas-team@objectweb.org
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation; either
009: * version 2.1 of the License, or any later version.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: * You should have received a copy of the GNU Lesser General Public
017: * License along with this library; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
019: * USA
020: *
021: * --------------------------------------------------------------------------
022: * $Id: EjbqlVariableVisitor.java 6140 2005-01-22 01:42:53Z rhs $
023: * --------------------------------------------------------------------------
024: */package org.objectweb.jonas_ejb.lib;
025:
026: import java.util.HashMap;
027: import java.util.HashSet;
028: import java.util.Iterator;
029: import java.util.Map;
030: import java.util.Stack;
031:
032: import org.objectweb.jonas_ejb.container.TraceEjb;
033: import org.objectweb.jonas_ejb.deployment.api.DeploymentDescEjb2;
034: import org.objectweb.jonas_ejb.deployment.ejbql.ASTAbstractSchemaName;
035: import org.objectweb.jonas_ejb.deployment.ejbql.ASTCollectionMemberDeclaration;
036: import org.objectweb.jonas_ejb.deployment.ejbql.ASTCollectionValuedPathExpression;
037: import org.objectweb.jonas_ejb.deployment.ejbql.ASTEJBQL;
038: import org.objectweb.jonas_ejb.deployment.ejbql.ASTFromClause;
039: import org.objectweb.jonas_ejb.deployment.ejbql.ASTIdentifier;
040: import org.objectweb.jonas_ejb.deployment.ejbql.ASTPath;
041: import org.objectweb.jonas_ejb.deployment.ejbql.ASTRangeVariableDeclaration;
042: import org.objectweb.jonas_ejb.deployment.ejbql.ParseException;
043: import org.objectweb.jonas_ejb.deployment.ejbql.SimpleNode;
044: import org.objectweb.jonas_ejb.deployment.ejbql.ASTSelectClause;
045: import org.objectweb.jonas_ejb.deployment.ejbql.ASTSelectExpression;
046: import org.objectweb.jonas_ejb.deployment.ejbql.ASTAggregateSelectExpression;
047: import org.objectweb.jonas_ejb.deployment.ejbql.ASTIdentificationVariable;
048: import org.objectweb.jonas_ejb.deployment.ejbql.ASTCmpPathExpression;
049: import org.objectweb.jonas_ejb.deployment.ejbql.ASTSingleValuedCmrPathExpression;
050: import org.objectweb.jonas_ejb.deployment.ejbql.ASTSingleValuedPathExpression;
051: import org.objectweb.jonas_ejb.deployment.ejbql.ASTWhereClause;
052: import org.objectweb.jonas_ejb.deployment.ejbql.ASTConditionalExpression;
053: import org.objectweb.jonas_ejb.deployment.ejbql.ASTConditionalTerm;
054: import org.objectweb.jonas_ejb.deployment.ejbql.ASTConditionalFactor;
055: import org.objectweb.jonas_ejb.deployment.ejbql.ASTBetweenExpression;
056: import org.objectweb.jonas_ejb.deployment.ejbql.ASTInExpression;
057: import org.objectweb.jonas_ejb.deployment.ejbql.ASTLikeExpression;
058: import org.objectweb.jonas_ejb.deployment.ejbql.ASTNullComparisonExpression;
059: import org.objectweb.jonas_ejb.deployment.ejbql.ASTEmptyCollectionComparisonExpression;
060: import org.objectweb.jonas_ejb.deployment.ejbql.ASTCollectionMemberExpression;
061: import org.objectweb.jonas_ejb.deployment.ejbql.ASTComparisonExpression;
062: import org.objectweb.jonas_ejb.deployment.ejbql.ASTArithmeticExpression;
063: import org.objectweb.jonas_ejb.deployment.ejbql.ASTArithmeticTerm;
064: import org.objectweb.jonas_ejb.deployment.ejbql.ASTArithmeticFactor;
065: import org.objectweb.jonas_ejb.deployment.ejbql.ASTStringExpression;
066: import org.objectweb.jonas_ejb.deployment.ejbql.ASTDatetimeExpression;
067: import org.objectweb.jonas_ejb.deployment.ejbql.ASTBooleanExpression;
068: import org.objectweb.jonas_ejb.deployment.ejbql.ASTEntityBeanExpression;
069: import org.objectweb.jonas_ejb.deployment.ejbql.ASTFunctionsReturningStrings;
070: import org.objectweb.jonas_ejb.deployment.ejbql.ASTFunctionsReturningNumerics;
071: import org.objectweb.jonas_ejb.deployment.ejbql.ASTOrderByClause;
072: import org.objectweb.jonas_ejb.deployment.ejbql.ASTOrderByItem;
073: import org.objectweb.jorm.metainfo.api.Class;
074: import org.objectweb.jorm.metainfo.api.Manager;
075: import org.objectweb.medor.api.Field;
076: import org.objectweb.medor.api.MedorException;
077: import org.objectweb.medor.query.api.QueryTree;
078: import org.objectweb.medor.query.api.QueryTreeField;
079: import org.objectweb.medor.query.jorm.lib.ClassExtent;
080: import org.objectweb.medor.query.jorm.lib.PNameField;
081: import org.objectweb.medor.query.jorm.lib.QueryBuilder;
082: import org.objectweb.medor.query.lib.QueryTreePrinter;
083: import org.objectweb.medor.filter.lib.BasicFieldOperand;
084: import org.objectweb.util.monolog.api.BasicLevel;
085:
086: /**
087: * Implementation of a visitor that creates a map of pairs [name,QueryTreeField]
088: * for all defined identifiers of the query.
089: * @author Christophe Ney [cney@batisseurs.com] Initial developper
090: * @author Helene Joanin:
091: * <ul>
092: * <li>In the visit of the SELECT clause, do not forget to add the id
093: * in the ids structure if its not present. Indeed, the definition of
094: * this id is done in the FROM clause which is visited later. This is
095: * needed for ejbSelect query which allows path_expression in the SELECT
096: * clause.</li>
097: * <li>Use of the NavigatorNodeFactory.getIn() for IN in the FROM part
098: * instead of NavigatorNodeFactory.getNavigatorNode()</li>
099: * <li>Some modifications needed to take into account CollectionValuedPathExpression
100: * for the member of and is empty operators.</li>
101: * <li>For the MemberOf implementation, do not more build an unique
102: * QueryTree, but a Map of pairs [name,QueryTreeField]</li>
103: * <li>Add the ORDER BY clause.</li>
104: * <li>Take into account the new interface of NavigatorNodeFactory.</li>
105: * <li>IS EMPTY / IS NOT EMPTY</li>
106: * <li>Take into account the EJBQL version 2.1 syntax.</li>
107: * </ul>
108: */
109: public class EjbqlVariableVisitor extends EjbqlAbstractVisitor {
110:
111: /**
112: * The JORM Manager
113: */
114: private Manager manager;
115:
116: /**
117: * The Deployment Descriptors information
118: */
119: private DeploymentDescEjb2 dd;
120:
121: /**
122: * ids structure for all the defined identifiers of the query,.
123: */
124: private HashMap ids = new HashMap();
125:
126: /**
127: * field for each defined identifiers of the query.
128: */
129: private HashMap fields = new HashMap();
130:
131: private QueryBuilder qb = new QueryBuilder();
132:
133: /**
134: * track which paths are collections
135: */
136: private HashSet collections = new HashSet();
137:
138: /**
139: * constructor
140: * @param ejbql root of the lexical tree
141: * @param dd Deployment Descriptor
142: * @param qb query builder used to navigate paths
143: * @throws Exception when error parsing
144: */
145:
146: public EjbqlVariableVisitor(ASTEJBQL ejbql, DeploymentDescEjb2 dd,
147: QueryBuilder qb) throws Exception {
148: this .dd = dd;
149: this .qb = qb;
150: manager = dd.getJormManager();
151:
152: // parse the ejbql and build the ids structure
153: visit(ejbql);
154:
155: for (Iterator it = ids.keySet().iterator(); it.hasNext();) {
156: String id = (String) it.next();
157: IdValue idv = (IdValue) ids.get(id);
158: fields.put(id + "." + Field.PNAMENAME, qb
159: .project(define(id)));
160: for (int i = 0; i < idv.getDeclaredPathLength(); i++) {
161: String path = idv.getMergedPath(i);
162: if (!collections.contains(path)) {
163: fields.put(path, qb.project(define(path)));
164: }
165: }
166: }
167: }
168:
169: private QueryTreeField define(String id) throws ParseException,
170: MedorException {
171: String[] path = splitPath(id);
172:
173: if (!qb.contains(path[0])) {
174: IdValue idv = (IdValue) ids.get(path[0]);
175: String[] name = idv.getName();
176:
177: PNameField pnf;
178: if (name.length == 1) {
179: pnf = extent(name[0], path[0]);
180: } else {
181: pnf = (PNameField) define(mergePath(name));
182: }
183: qb.define(path[0], pnf);
184: }
185:
186: return qb.navigate(path);
187: }
188:
189: private PNameField extent(String schema, String alias)
190: throws ParseException, MedorException {
191: if (schema == null) {
192: throw new NullPointerException("schema");
193: }
194: String cn = dd.asn2BeanDesc(schema).getJormClassName();
195: Class theClass = manager.getClass(cn);
196: if (theClass == null) {
197: throw new ParseException(
198: "Abstract schema name \""
199: + schema
200: + "\" has not been declared in the jorm meta information");
201: }
202: ClassExtent ext = new ClassExtent(theClass, alias,
203: Field.PNAMENAME, false);
204: return (PNameField) ext.getField(ext.getPNameFieldName());
205: }
206:
207: /**
208: * get the Map that was built from visiting the lexical query tree This map
209: * allows to get the org.objectweb.medor.api.Field from its name (ident or
210: * path).
211: * @return the Fields map
212: */
213: public Map getFields() {
214: return fields;
215: }
216:
217: /**
218: * Trace the given ids structure
219: * @param idsM identifiocators Map
220: */
221: public void traceIds(HashMap idsM) {
222: if (TraceEjb.isDebugQuery()) {
223: TraceEjb.query.log(BasicLevel.DEBUG,
224: "Begin of IDS structure:");
225: // trace the ids structure
226: for (Iterator i = idsM.keySet().iterator(); i.hasNext();) {
227: String id = (String) i.next();
228: IdValue idv = (IdValue) idsM.get(id);
229: TraceEjb.query.log(BasicLevel.DEBUG, "ids[" + id + "]="
230: + idv);
231: if (idv.getQueryTree() != null) {
232: QueryTreePrinter.printQueryTree(idv.getQueryTree(),
233: TraceEjb.query, BasicLevel.DEBUG);
234: }
235: }
236: TraceEjb.query.log(BasicLevel.DEBUG,
237: "End of IDS structure:");
238: }
239: }
240:
241: /**
242: * visit child nodes
243: * @param node the node to visit
244: * @param data the current stack
245: * @return the stack
246: */
247: public Object visit(ASTFromClause node, Object data) {
248: return visit((SimpleNode) node, data);
249: }
250:
251: /**
252: * visit child nodes
253: * @param node the node to visit
254: * @param data the current stack
255: * @return the stack
256: */
257: public Object visit(ASTCollectionMemberDeclaration node, Object data) {
258: return visit((SimpleNode) node, data);
259: }
260:
261: /**
262: * visit child nodes
263: * @param node the node to visit
264: * @param data the current stack
265: * @return the stack
266: */
267: public Object visit(ASTRangeVariableDeclaration node, Object data) {
268: return visit((SimpleNode) node, data);
269: }
270:
271: /**
272: * visit child nodes
273: * @param node the node to visit
274: * @param data the current stack
275: * @return the stack
276: */
277: public Object visit(ASTCollectionValuedPathExpression node,
278: Object data) {
279: return visit((SimpleNode) node, data);
280: }
281:
282: /**
283: * Push the Node to the stack
284: * @param node the node to visit
285: * @param data the current stack
286: * @return the stack
287: */
288: public Object visit(ASTAbstractSchemaName node, Object data) {
289: ((Stack) data).push(node.value);
290: return null;
291: }
292:
293: /**
294: * Store the pair identifier,Node from the Stack in HashMap
295: * @param node the node to visit
296: * @param data the current stack
297: * @return the stack
298: */
299: public Object visit(ASTIdentifier node, Object data) {
300: String id = (String) node.value;
301: String name = (String) ((Stack) data).pop();
302: IdValue iv = (IdValue) ids.get(id);
303: if (iv == null) {
304: iv = new IdValue(name);
305: ids.put(id, iv);
306: } else {
307: iv.setName(splitPath(name));
308: }
309: return null;
310: }
311:
312: /**
313: * Push the Node to the stack
314: * @param node the node to visit
315: * @param data the current stack
316: * @return the stack
317: */
318: public Object visit(ASTPath node, Object data) {
319: ((Stack) data).push(node.value);
320: return null;
321: }
322:
323: /**
324: * Process the variable ie create the IdValue if not already done and add the path
325: * @param path of the variable
326: */
327: private void processVariable(String path) {
328: // Common to select, where and orderby clauses
329: String id = splitPath(path)[0];
330: IdValue iv = (IdValue) ids.get(id);
331: if (iv == null) {
332: iv = new IdValue();
333: ids.put(id, iv);
334: }
335: iv.addPath(path);
336: }
337:
338: // -------------- select ---------------//
339: /**
340: * visit child nodes
341: * @param node the node to visit
342: * @param data the current stack
343: * @return the stack
344: */
345: public Object visit(ASTSelectClause node, Object data) {
346: visit((SimpleNode) node, data);
347: Stack st = (Stack) data;
348: if (!st.empty()) {
349: processVariable((String) st.pop());
350: }
351: return null;
352: }
353:
354: /**
355: * visit child nodes
356: * @param node the node to visit
357: * @param data the current stack
358: * @return the stack
359: */
360: public Object visit(ASTSelectExpression node, Object data) {
361: return visit((SimpleNode) node, data);
362: }
363:
364: /**
365: * visit child nodes
366: * @param node the node to visit
367: * @param data the current stack
368: * @return the stack
369: */
370: public Object visit(ASTAggregateSelectExpression node, Object data) {
371: return visit((SimpleNode) node, data);
372: }
373:
374: /**
375: * visit child nodes
376: * @param node the node to visit
377: * @param data the current stack
378: * @return the stack
379: */
380: public Object visit(ASTIdentificationVariable node, Object data) {
381: return visit((SimpleNode) node, data);
382: }
383:
384: /**
385: * visit child nodes
386: * @param node the node to visit
387: * @param data the current stack
388: * @return the stack
389: */
390: public Object visit(ASTSingleValuedPathExpression node, Object data) {
391: return visit((SimpleNode) node, data);
392: }
393:
394: /**
395: * visit child nodes
396: * @param node the node to visit
397: * @param data the current stack
398: * @return the stack
399: */
400: public Object visit(ASTSingleValuedCmrPathExpression node,
401: Object data) {
402: return visit((SimpleNode) node, data);
403: }
404:
405: /**
406: * visit child nodes
407: * @param node the node to visit
408: * @param data the current stack
409: * @return the stack
410: */
411: public Object visit(ASTCmpPathExpression node, Object data) {
412: return visit((SimpleNode) node, data);
413: }
414:
415: // ----------- Where -----------------//
416: /**
417: * visit child nodes
418: * @param node the node to visit
419: * @param data the current stack
420: * @return the stack
421: */
422: public Object visit(ASTWhereClause node, Object data) {
423: visit((SimpleNode) node, data);
424: Stack st = (Stack) data;
425: while (!st.empty()) {
426: processVariable((String) st.pop());
427: }
428: return null;
429: }
430:
431: /**
432: * visit child nodes
433: * @param node the node to visit
434: * @param data the current stack
435: * @return the stack
436: */
437: public Object visit(ASTConditionalExpression node, Object data) {
438: return visit((SimpleNode) node, data);
439: }
440:
441: /**
442: * visit child nodes
443: * @param node the node to visit
444: * @param data the current stack
445: * @return the stack
446: */
447: public Object visit(ASTConditionalTerm node, Object data) {
448: return visit((SimpleNode) node, data);
449: }
450:
451: /**
452: * Visit child nodes and count the number of the unary operator NOT.
453: * @param node the node to visit
454: * @param data the current stack
455: * @return the stack
456: */
457: public Object visit(ASTConditionalFactor node, Object data) {
458: return visit((SimpleNode) node, data);
459: }
460:
461: /**
462: * visit child nodes
463: * @param node the node to visit
464: * @param data the current stack
465: * @return the stack
466: */
467: public Object visit(ASTBetweenExpression node, Object data) {
468: return visit((SimpleNode) node, data);
469: }
470:
471: /**
472: * visit child nodes
473: * @param node the node to visit
474: * @param data the current stack
475: * @return the stack
476: */
477: public Object visit(ASTInExpression node, Object data) {
478: return visit((SimpleNode) node, data);
479: }
480:
481: /**
482: * visit child nodes
483: * @param node the node to visit
484: * @param data the current stack
485: * @return the stack
486: */
487: public Object visit(ASTLikeExpression node, Object data) {
488: return visit((SimpleNode) node, data);
489: }
490:
491: /**
492: * visit child nodes
493: * @param node the node to visit
494: * @param data the current stack
495: * @return the stack
496: */
497: public Object visit(ASTNullComparisonExpression node, Object data) {
498: return visit((SimpleNode) node, data);
499: }
500:
501: /**
502: * visit child nodes and see if it's IS EMPTY or IS NOT EMPTY
503: * @param node the node to visit
504: * @param data the current stack
505: * @return the stack
506: */
507: public Object visit(ASTEmptyCollectionComparisonExpression node,
508: Object data) {
509: visit((SimpleNode) node, data);
510: Stack st = (Stack) data;
511: String path = (String) st.peek();
512: collections.add(path);
513: return null;
514: }
515:
516: /**
517: * visit child nodes
518: * @param node the node to visit
519: * @param data the current stack
520: * @return the stack
521: */
522: public Object visit(ASTCollectionMemberExpression node, Object data) {
523: visit((SimpleNode) node, data);
524: Stack st = (Stack) data;
525: String path = (String) st.peek();
526: collections.add(path);
527: return null;
528: }
529:
530: /**
531: * visit child nodes
532: * @param node the node to visit
533: * @param data the current stack
534: * @return the stack
535: */
536: public Object visit(ASTComparisonExpression node, Object data) {
537: return visit((SimpleNode) node, data);
538: }
539:
540: /**
541: * visit child nodes
542: * @param node the node to visit
543: * @param data the current stack
544: * @return the stack
545: */
546: public Object visit(ASTArithmeticExpression node, Object data) {
547: return visit((SimpleNode) node, data);
548: }
549:
550: /**
551: * visit child nodes
552: * @param node the node to visit
553: * @param data the current stack
554: * @return the stack
555: */
556: public Object visit(ASTArithmeticTerm node, Object data) {
557: return visit((SimpleNode) node, data);
558: }
559:
560: /**
561: * visit child nodes
562: * @param node the node to visit
563: * @param data the current stack
564: * @return the stack
565: */
566: public Object visit(ASTArithmeticFactor node, Object data) {
567: return visit((SimpleNode) node, data);
568: }
569:
570: /**
571: * visit child nodes
572: * @param node the node to visit
573: * @param data the current stack
574: * @return the stack
575: */
576: public Object visit(ASTStringExpression node, Object data) {
577: return visit((SimpleNode) node, data);
578: }
579:
580: /**
581: * visit child nodes
582: * @param node the node to visit
583: * @param data the current stack
584: * @return the stack
585: */
586: public Object visit(ASTDatetimeExpression node, Object data) {
587: return visit((SimpleNode) node, data);
588: }
589:
590: /**
591: * visit child nodes
592: * @param node the node to visit
593: * @param data the current stack
594: * @return the stack
595: */
596: public Object visit(ASTBooleanExpression node, Object data) {
597: return visit((SimpleNode) node, data);
598: }
599:
600: /**
601: * visit child nodes
602: * @param node the node to visit
603: * @param data the current stack
604: * @return the stack
605: */
606: public Object visit(ASTEntityBeanExpression node, Object data) {
607: return visit((SimpleNode) node, data);
608: }
609:
610: /**
611: * visit child nodes
612: * @param node the node to visit
613: * @param data the current stack
614: * @return the stack
615: */
616: public Object visit(ASTFunctionsReturningStrings node, Object data) {
617: return visit((SimpleNode) node, data);
618: }
619:
620: /**
621: * visit child nodes
622: * @param node the node to visit
623: * @param data the current stack
624: * @return the stack
625: */
626: public Object visit(ASTFunctionsReturningNumerics node, Object data) {
627: return visit((SimpleNode) node, data);
628: }
629:
630: // ----------- Order by -----------------//
631: /**
632: * visit child nodes
633: * @param node the node to visit
634: * @param data the current stack
635: * @return the stack
636: */
637: public Object visit(ASTOrderByClause node, Object data) {
638: visit((SimpleNode) node, data);
639: Stack st = (Stack) data;
640: while (!st.empty()) {
641: processVariable((String) st.pop());
642: }
643: return null;
644: }
645:
646: /**
647: * visit child nodes
648: * @param node the node to visit
649: * @param data the current stack
650: * @return the stack
651: */
652: public Object visit(ASTOrderByItem node, Object data) {
653: return visit((SimpleNode) node, data);
654: }
655:
656: }
|