001: /**
002: * Copyright (C) 2001-2004 France Telecom R&D
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 2 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 org.objectweb.speedo.generation.jorm.rdb;
018:
019: import org.objectweb.speedo.query.jdo.parser.SpeedoQLVisitor;
020: import org.objectweb.speedo.query.jdo.parser.SimpleNode;
021: import org.objectweb.speedo.query.jdo.parser.ASTSpeedoPrimary;
022: import org.objectweb.speedo.query.jdo.parser.ASTSpeedoQL;
023: import org.objectweb.speedo.query.jdo.parser.ASTPrimary;
024: import org.objectweb.speedo.query.jdo.parser.ASTRelationalExpression;
025: import org.objectweb.speedo.query.jdo.parser.ASTAdditiveExpression;
026: import org.objectweb.speedo.query.jdo.parser.ASTUnaryExpression;
027: import org.objectweb.speedo.query.jdo.parser.ASTCastExpression;
028: import org.objectweb.speedo.query.jdo.parser.ASTArgumentList;
029: import org.objectweb.speedo.query.jdo.parser.ASTLiteral;
030: import org.objectweb.speedo.query.jdo.parser.ASTType;
031: import org.objectweb.speedo.query.jdo.parser.ASTQualifiedName;
032: import org.objectweb.speedo.query.jdo.parser.SpeedoQLConstants;
033: import org.objectweb.speedo.query.jdo.parser.SpeedoQL;
034: import org.objectweb.speedo.query.jdo.parser.ParseException;
035: import org.objectweb.speedo.api.SpeedoException;
036: import org.objectweb.speedo.metadata.SpeedoClass;
037: import org.objectweb.medor.expression.api.Expression;
038: import org.objectweb.medor.expression.api.Operator;
039: import org.objectweb.medor.expression.api.Operand;
040: import org.objectweb.medor.expression.lib.ConditionalOr;
041: import org.objectweb.medor.expression.lib.ConditionalAnd;
042: import org.objectweb.medor.expression.lib.Or;
043: import org.objectweb.medor.expression.lib.And;
044: import org.objectweb.medor.expression.lib.Equal;
045: import org.objectweb.medor.expression.lib.NotEqual;
046: import org.objectweb.medor.expression.lib.Lower;
047: import org.objectweb.medor.expression.lib.Greater;
048: import org.objectweb.medor.expression.lib.GreaterEqual;
049: import org.objectweb.medor.expression.lib.LowerEqual;
050: import org.objectweb.medor.expression.lib.Plus;
051: import org.objectweb.medor.expression.lib.Minus;
052: import org.objectweb.medor.expression.lib.Mult;
053: import org.objectweb.medor.expression.lib.DivideBy;
054: import org.objectweb.medor.expression.lib.UMinus;
055: import org.objectweb.medor.expression.lib.Bitwize;
056: import org.objectweb.medor.expression.lib.Not;
057: import org.objectweb.medor.expression.lib.BasicOperand;
058: import org.objectweb.util.monolog.api.BasicLevel;
059: import org.objectweb.util.monolog.api.Logger;
060: import org.objectweb.jorm.mapper.rdb.metainfo.RdbFilter;
061: import org.objectweb.jorm.type.api.PTypeSpace;
062:
063: import java.util.Stack;
064: import java.io.CharArrayReader;
065:
066: /**
067: * It manages the filter dedicated to the filtered inheritance mapping.
068: *
069: * @author S.Chassande-Barrioz
070: */
071: public class FilterManager {
072:
073: private Logger logger;
074: private boolean debug = false;
075: private FilterParser parser = new FilterParser();
076:
077: public FilterManager(Logger logger) {
078: this .logger = logger;
079: }
080:
081: public FilterParser getParser() {
082: return parser;
083: }
084:
085: public void assignFilter(String filter, RdbFilter rdbFilter,
086: SpeedoClass sc, String projectName, String mapperName)
087: throws SpeedoException {
088: debug = logger != null && logger.isLoggable(BasicLevel.DEBUG);
089: Expression medorExpression = parser.parse(filter);
090: if (!isJormPredicate(medorExpression)) {
091: throw new SpeedoException(
092: "The specified filter is not supported, \n\tclass"
093: + sc.getFQName() + "\n\tfilter=" + filter);
094: }
095: rdbFilter.setExpression(medorExpression);
096: }
097:
098: public class FilterParser implements SpeedoQLVisitor {
099: private Expression expression;
100: private String tab = "";
101:
102: public synchronized Expression parse(String filter)
103: throws SpeedoException {
104: try {
105: visit(new SpeedoQL(new CharArrayReader(filter
106: .toCharArray())).SpeedoQL());
107: return expression;
108: } catch (ParseException e) {
109: throw new SpeedoException(
110: "Impossible to parse the filter and to create AST",
111: e);
112: } catch (SpeedoException e) {
113: throw e;
114: } catch (Exception e) {
115: throw new SpeedoException(
116: "Impossible to parse the filter", e);
117: }
118: }
119:
120: // IMPLEMENTATION OF THE SpeedoQLVisitor INTERFACE //
121: //-------------------------------------------------//
122:
123: public Object visit(ASTPrimary node, Object data) {
124: visit((SimpleNode) node, data);
125: return null;
126: }
127:
128: public Object visit(ASTSpeedoPrimary node, Object data) {
129: visit((SimpleNode) node, data);
130: Stack stack = (Stack) data;
131: expression = (Expression) stack.pop();
132: return null;
133: }
134:
135: public Object visit(ASTRelationalExpression node, Object data) {
136: logger.log(BasicLevel.DEBUG, tab
137: + "Visit RelationalExpression: " + node);
138: tab += '\t';
139: visit((SimpleNode) node, data);
140: tab = tab.substring(1);
141: Stack stack = (Stack) data;
142: if (stack.size() > 0) {
143: if (debug) {
144: logger.log(BasicLevel.DEBUG,
145: "manage relational expression: "
146: + "(children: "
147: + node.jjtGetNumChildren()
148: + ", stack: " + stack.size()
149: + ", peek:" + stack.peek() + ")");
150: }
151: for (int i = 0; (i < (node.jjtGetNumChildren() - 1) && stack
152: .size() > 0); i++) {
153: int op = ((Integer) node.ops.get(node
154: .jjtGetNumChildren()
155: - 2 - i)).intValue();
156: if (usedInRelationalExpresssion(op)) {
157: Object child2 = stack.pop();
158: Object child1 = stack.pop();
159: if (debug) {
160: logger.log(BasicLevel.DEBUG, "pop child1: "
161: + child1);
162: logger.log(BasicLevel.DEBUG, "pop child2: "
163: + child2);
164: }
165: Expression ret = null;
166: switch (op) {
167: case SpeedoQLConstants.OR:
168: ret = new ConditionalOr(
169: (Expression) child1,
170: (Expression) child2);
171: break;
172: case SpeedoQLConstants.AND:
173: ret = new ConditionalAnd(
174: (Expression) child1,
175: (Expression) child2);
176: break;
177: case SpeedoQLConstants.BITWISEOR:
178: ret = new Or((Expression) child1,
179: (Expression) child2);
180: break;
181: case SpeedoQLConstants.BITWISEXOR:
182: ret = null;
183: break;
184: case SpeedoQLConstants.BITWISEAND:
185: ret = new And((Expression) child1,
186: (Expression) child2);
187: break;
188: case SpeedoQLConstants.EQ:
189: ret = new Equal((Expression) child1,
190: (Expression) child2);
191: break;
192: case SpeedoQLConstants.NEQ:
193: ret = new NotEqual((Expression) child1,
194: (Expression) child2);
195: break;
196: case SpeedoQLConstants.LT:
197: ret = new Lower((Expression) child1,
198: (Expression) child2);
199: break;
200: case SpeedoQLConstants.GT:
201: ret = new Greater((Expression) child1,
202: (Expression) child2);
203: break;
204: case SpeedoQLConstants.GTE:
205: ret = new GreaterEqual((Expression) child1,
206: (Expression) child2);
207: break;
208: case SpeedoQLConstants.LTE:
209: ret = new LowerEqual((Expression) child1,
210: (Expression) child2);
211: break;
212: }
213: if (debug) {
214: logger.log(BasicLevel.DEBUG, "push(" + ret
215: + ")");
216: }
217: stack.push(ret);
218: }
219: }
220: }
221: if (debug) {
222: logger.log(BasicLevel.DEBUG, "children:"
223: + node.jjtGetNumChildren() + " / stack: "
224: + stack.size());
225: logger.log(BasicLevel.DEBUG, tab
226: + "End of Visit RelationalExpression: " + node);
227: }
228: return null;
229: }
230:
231: public Object visit(ASTAdditiveExpression node, Object data) {
232: logger.log(BasicLevel.DEBUG, tab
233: + "Visit AdditiveExpression: " + node);
234: tab += '\t';
235: visit((SimpleNode) node, data);
236: tab = tab.substring(1);
237: Stack stack = (Stack) data;
238: if (stack.size() > 0) {
239: Expression ret = (Expression) stack.pop();
240: for (int i = 0; i < node.jjtGetNumChildren() - 1; i++) {
241: logger.log(BasicLevel.DEBUG,
242: "Visit AdditiveExpression... children...["
243: + i + "]");
244:
245: switch (((Integer) node.ops.get(node
246: .jjtGetNumChildren()
247: - 2 - i)).intValue()) {
248:
249: case SpeedoQLConstants.PLUS:
250: ret = new Plus((Expression) stack.pop(), ret);
251: break;
252: case SpeedoQLConstants.MINUS:
253: ret = new Minus((Expression) stack.pop(), ret);
254: break;
255: case SpeedoQLConstants.MULT:
256: ret = new Mult((Expression) stack.pop(), ret);
257: break;
258: case SpeedoQLConstants.DIV:
259: ret = new DivideBy((Expression) stack.pop(),
260: ret);
261: break;
262: default:
263:
264: }
265: }
266: ((Stack) data).push(ret);
267: }
268: logger.log(BasicLevel.DEBUG, tab
269: + "End of Visit AdditiveExpression: " + node);
270: return null;
271: }
272:
273: public Object visit(ASTUnaryExpression node, Object data) {
274: logger.log(BasicLevel.DEBUG, tab + "Visit UnaryExpression"
275: + node);
276: tab += '\t';
277: visit((SimpleNode) node, data);
278: tab = tab.substring(1);
279: Stack stack = (Stack) data;
280: if (stack.size() > 0) {
281: Object o = stack.pop();
282: if (node.ops.size() > 0) {
283: switch (((Integer) node.ops.get(0)).intValue()) {
284: case SpeedoQLConstants.MINUS:
285: o = new UMinus((Expression) o);
286: break;
287: case SpeedoQLConstants.BITWISECOMPL:
288: o = new Bitwize((Expression) o);
289: break;
290: case SpeedoQLConstants.NOT:
291: logger.log(BasicLevel.DEBUG, "NOT(" + o + "): "
292: + node);
293: o = new Not((Expression) o);
294: break;
295: }
296: }
297: ((Stack) data).push(o);
298: }
299: logger.log(BasicLevel.DEBUG, tab
300: + "End of Visit UnaryExpression: " + node);
301: return null;
302: }
303:
304: public Object visit(ASTCastExpression node, Object data) {
305: return null;
306: }
307:
308: public Object visit(ASTArgumentList node, Object data) {
309: return null;
310: }
311:
312: public Object visit(ASTLiteral node, Object data) {
313: if (node.value instanceof Integer) {
314: ((Stack) data).push(new BasicOperand(
315: ((Integer) node.value).intValue()));
316: } else if (node.value instanceof Float) {
317: ((Stack) data).push(new BasicOperand(
318: ((Float) node.value).floatValue()));
319: } else if (node.value instanceof Character) {
320: ((Stack) data).push(new BasicOperand(
321: ((Character) node.value).charValue()));
322: } else if (node.value instanceof String) {
323: String s = (String) (node.value);
324: s = s.substring(1, s.length() - 1);
325: ((Stack) data).push(new BasicOperand(s));
326: } else if (node.value instanceof Boolean) {
327: ((Stack) data).push(new BasicOperand(
328: ((Boolean) node.value).booleanValue()));
329: }
330: return null;
331: }
332:
333: public Object visit(ASTType node, Object data) {
334: logger.log(BasicLevel.DEBUG, "Visit Type: " + node);
335: return null;
336: }
337:
338: public Object visit(ASTQualifiedName node, Object data) {
339: ((Stack) data).push(new BasicOperand((String) node.value));
340: return null;
341: }
342:
343: /**
344: * Visit method to call from constructor.
345: * Child node visitors get a <code>java.util.Stack</code> as data parameter.
346: * @throws java.lang.Exception any nested exception thrown from other visit method
347: */
348: public Object visit(SimpleNode node) throws Exception {
349: return visit(node, new Stack());
350: }
351:
352: /**
353: * Generic visit method that traverses all child nodes
354: */
355: public Object visit(SimpleNode node, Object data) {
356: return node.childrenAccept(this , data);
357: }
358:
359: public Object visit(ASTSpeedoQL node, Object data) {
360: return null;
361: }
362:
363: private boolean usedInRelationalExpresssion(int op) {
364: switch (op) {
365: case SpeedoQLConstants.OR:
366: case SpeedoQLConstants.AND:
367: case SpeedoQLConstants.BITWISEOR:
368: case SpeedoQLConstants.BITWISEXOR:
369: case SpeedoQLConstants.BITWISEAND:
370: case SpeedoQLConstants.EQ:
371: case SpeedoQLConstants.NEQ:
372: case SpeedoQLConstants.LT:
373: case SpeedoQLConstants.GT:
374: case SpeedoQLConstants.GTE:
375: case SpeedoQLConstants.LTE:
376: logger.log(BasicLevel.DEBUG, "node useful");
377: return true;
378: default:
379: logger.log(BasicLevel.DEBUG, "node useless");
380: return false;
381: }
382: }
383:
384: }
385:
386: // OTHER METHODS //
387: //---------------//
388:
389: /**
390: * Calculates if an expression can be used as Jorm predicate as inheritance
391: * filter.
392: * @param e is the medor Expression to analyze.
393: * @return true if the expression is compatible.
394: */
395: private boolean isJormPredicate(Expression e) {
396: return isSimpleOperator(e)
397: || (e instanceof ConditionalAnd
398: && isJormPredicate(((Operator) e)
399: .getExpression(0)) && isJormPredicate(((Operator) e)
400: .getExpression(1)));
401: }
402:
403: private boolean isSimpleOperator(Expression e) {
404: boolean res = e instanceof Equal || e instanceof Greater
405: || e instanceof GreaterEqual || e instanceof Lower
406: || e instanceof LowerEqual;
407: if (res == false) {
408: return false;
409: }
410: Operator op = (Operator) e;
411:
412: if (!(op.getExpression(0) instanceof Operand && op
413: .getExpression(1) instanceof Operand)) {
414: return false;
415: }
416: Operand o0 = (Operand) op.getExpression(0);
417: Operand o1 = (Operand) op.getExpression(1);
418: if (o0.getType().getTypeCode() == PTypeSpace.STRING
419: .getTypeCode()) {
420: return true;
421: } else if (o1.getType().getTypeCode() == PTypeSpace.STRING
422: .getTypeCode()) {
423: //reverse the order: column name at left
424: op.setExpression(0, o1);
425: op.setExpression(1, o0);
426: return true;
427: } else {
428: return false;
429: }
430: }
431: }
|