001: /*
002: * $Header: /export/home/cvsroot/MyPersonalizerRepository/MyPersonalizer/Subsystems/Kernel/Sources/es/udc/mypersonalizer/kernel/model/query/parser/XPathTranslatorVisitor.java,v 1.1.1.1 2004/03/25 12:08:37 fbellas Exp $
003: * $Revision: 1.1.1.1 $
004: * $Date: 2004/03/25 12:08:37 $
005: *
006: * =============================================================================
007: *
008: * Copyright (c) 2003, The MyPersonalizer Development Group
009: * (http://www.tic.udc.es/~fbellas/mypersonalizer/index.html) at
010: * University Of A Coruņa
011: * All rights reserved.
012: *
013: * Redistribution and use in source and binary forms, with or without
014: * modification, are permitted provided that the following conditions are met:
015: *
016: * - Redistributions of source code must retain the above copyright notice,
017: * this list of conditions and the following disclaimer.
018: *
019: * - Redistributions in binary form must reproduce the above copyright notice,
020: * this list of conditions and the following disclaimer in the documentation
021: * and/or other materials provided with the distribution.
022: *
023: * - Neither the name of the University Of A Coruņa nor the names of its
024: * contributors may be used to endorse or promote products derived from
025: * this software without specific prior written permission.
026: *
027: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
028: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
029: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
030: * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
031: * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
032: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
033: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
034: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
035: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
036: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
037: * POSSIBILITY OF SUCH DAMAGE.
038: *
039: */
040: package es.udc.mypersonalizer.kernel.model.query.parser;
041:
042: import java.util.ArrayList;
043: import java.util.HashMap;
044: import java.util.Iterator;
045: import java.util.List;
046: import java.util.Map;
047:
048: import org.jaxen.expr.AdditiveExpr;
049: import org.jaxen.expr.AllNodeStep;
050: import org.jaxen.expr.CommentNodeStep;
051: import org.jaxen.expr.EqualityExpr;
052: import org.jaxen.expr.Expr;
053: import org.jaxen.expr.FilterExpr;
054: import org.jaxen.expr.FunctionCallExpr;
055: import org.jaxen.expr.LiteralExpr;
056: import org.jaxen.expr.LocationPath;
057: import org.jaxen.expr.LogicalExpr;
058: import org.jaxen.expr.MultiplicativeExpr;
059: import org.jaxen.expr.NameStep;
060: import org.jaxen.expr.NumberExpr;
061: import org.jaxen.expr.PathExpr;
062: import org.jaxen.expr.Predicate;
063: import org.jaxen.expr.ProcessingInstructionNodeStep;
064: import org.jaxen.expr.RelationalExpr;
065: import org.jaxen.expr.TextNodeStep;
066: import org.jaxen.expr.UnaryExpr;
067: import org.jaxen.expr.UnionExpr;
068: import org.jaxen.expr.VariableReferenceExpr;
069: import org.jaxen.expr.Visitor;
070:
071: import es.udc.mypersonalizer.kernel.model.metainfo.MetaProperty;
072: import es.udc.mypersonalizer.kernel.model.query.ast.Step;
073: import es.udc.mypersonalizer.kernel.model.query.ast.exceptions.WrongArgumentsException;
074: import es.udc.mypersonalizer.kernel.model.query.ast.expr.BooleanExpression;
075: import es.udc.mypersonalizer.kernel.model.query.ast.expr.ContainsFunctionExpression;
076: import es.udc.mypersonalizer.kernel.model.query.ast.expr.EqualityExpression;
077: import es.udc.mypersonalizer.kernel.model.query.ast.expr.EqualsExpression;
078: import es.udc.mypersonalizer.kernel.model.query.ast.expr.Expression;
079: import es.udc.mypersonalizer.kernel.model.query.ast.expr.FunctionExpression;
080: import es.udc.mypersonalizer.kernel.model.query.ast.expr.GreaterOrEqualExpression;
081: import es.udc.mypersonalizer.kernel.model.query.ast.expr.GreaterThanExpression;
082: import es.udc.mypersonalizer.kernel.model.query.ast.expr.LesserOrEqualExpression;
083: import es.udc.mypersonalizer.kernel.model.query.ast.expr.LesserThanExpression;
084: import es.udc.mypersonalizer.kernel.model.query.ast.expr.LiteralNumericExpression;
085: import es.udc.mypersonalizer.kernel.model.query.ast.expr.LiteralStringExpression;
086: import es.udc.mypersonalizer.kernel.model.query.ast.expr.LogicalAndExpression;
087: import es.udc.mypersonalizer.kernel.model.query.ast.expr.LogicalExpression;
088: import es.udc.mypersonalizer.kernel.model.query.ast.expr.LogicalOrExpression;
089: import es.udc.mypersonalizer.kernel.model.query.ast.expr.NotEqualsExpression;
090: import es.udc.mypersonalizer.kernel.model.query.ast.expr.RelationalExpression;
091: import es.udc.mypersonalizer.kernel.model.query.ast.expr.StartsWithFunctionExpression;
092: import es.udc.mypersonalizer.kernel.model.query.ast.expr.StepExpression;
093: import es.udc.mypersonalizer.kernel.model.query.executor.MetaPropertyResolver;
094:
095: /**
096: * Visitor which translates an XPath expression to a list of query steps.
097: *
098: * @author Abel Muinho
099: * @since 1.0
100: */
101: public class XPathTranslatorVisitor implements Visitor {
102: /** Class objects for each supported logical expression. */
103: private static final Map LOGICAL_EXPRESSIONS_BY_OPERATOR;
104:
105: /** Class objects for each supported function. */
106: private static final Map FUNCTIONS_BY_NAME;
107:
108: /** Class objects for each supported equality operator. */
109: private static final Map EQUALITY_EXPRESSIONS_BY_OPERATOR;
110:
111: /** Class objects for each supported relational operator. */
112: private static final Map RELATIONAL_EXPRESSIONS_BY_OPERATOR;
113:
114: /** Resolver for metaProperties. */
115: private MetaPropertyResolver resolver = new MetaPropertyResolver();
116:
117: /** The Jaxen visitor interface does not allow returning values, so
118: * we must keep them in a variable as a side-effect of the visits.
119: */
120: private Object visitResult = null;
121:
122: static {
123: LOGICAL_EXPRESSIONS_BY_OPERATOR = new HashMap(2);
124: LOGICAL_EXPRESSIONS_BY_OPERATOR.put("and",
125: LogicalAndExpression.class);
126: LOGICAL_EXPRESSIONS_BY_OPERATOR.put("or",
127: LogicalOrExpression.class);
128:
129: FUNCTIONS_BY_NAME = new HashMap(2);
130: FUNCTIONS_BY_NAME.put("contains",
131: ContainsFunctionExpression.class);
132: FUNCTIONS_BY_NAME.put("starts-with",
133: StartsWithFunctionExpression.class);
134:
135: EQUALITY_EXPRESSIONS_BY_OPERATOR = new HashMap(2);
136: EQUALITY_EXPRESSIONS_BY_OPERATOR.put("=",
137: EqualsExpression.class);
138: EQUALITY_EXPRESSIONS_BY_OPERATOR.put("!=",
139: NotEqualsExpression.class);
140:
141: RELATIONAL_EXPRESSIONS_BY_OPERATOR = new HashMap(2);
142: RELATIONAL_EXPRESSIONS_BY_OPERATOR.put(">",
143: GreaterThanExpression.class);
144: RELATIONAL_EXPRESSIONS_BY_OPERATOR.put("<",
145: LesserThanExpression.class);
146: RELATIONAL_EXPRESSIONS_BY_OPERATOR.put("<=",
147: LesserOrEqualExpression.class);
148: RELATIONAL_EXPRESSIONS_BY_OPERATOR.put(">=",
149: GreaterOrEqualExpression.class);
150: }
151:
152: /**
153: * Obtains the list of query steps that is the result of the visit.
154: * @return the list of query steps.
155: */
156: public List getResultSteps() {
157: StepExpression resultExpr = (StepExpression) visitResult;
158: return resultExpr.getSteps();
159: }
160:
161: public void visit(PathExpr expr) {
162: throw new XPathVisitorException(
163: "XPath element PathExpr not supported");
164: }
165:
166: public void visit(LocationPath path) {
167: List stepList = new ArrayList();
168: MetaPropertyResolver oldResolver = this .resolver;
169: this .resolver = new MetaPropertyResolver(oldResolver);
170: /* Process the path's steps. */
171: Iterator stepsIt = path.getSteps().iterator();
172: while (stepsIt.hasNext()) {
173: org.jaxen.expr.Step xpathStep = (org.jaxen.expr.Step) stepsIt
174: .next();
175: xpathStep.accept(this );
176: stepList.add(visitResult);
177: }
178: StepExpression result = new StepExpression();
179: result.setSteps(stepList);
180: visitResult = result;
181: this .resolver = oldResolver;
182: }
183:
184: public void visit(LogicalExpr expr) {
185: Class logicalExpressionClass = (Class) LOGICAL_EXPRESSIONS_BY_OPERATOR
186: .get(expr.getOperator());
187: LogicalExpression expression;
188: try {
189: expression = (LogicalExpression) logicalExpressionClass
190: .newInstance();
191: } catch (Exception e) {
192: throw new XPathVisitorException(e);
193: }
194: expr.getLHS().accept(this );
195: expression.setLHS((Expression) visitResult);
196: expr.getRHS().accept(this );
197: expression.setRHS((Expression) visitResult);
198: visitResult = expression;
199: }
200:
201: public void visit(EqualityExpr expr) {
202: Class equalityExpressionClass = (Class) EQUALITY_EXPRESSIONS_BY_OPERATOR
203: .get(expr.getOperator());
204: EqualityExpression expression;
205: try {
206: expression = (EqualityExpression) equalityExpressionClass
207: .newInstance();
208: } catch (Exception e) {
209: throw new XPathVisitorException(e);
210: }
211: expr.getLHS().accept(this );
212: expression.setLHS((Expression) visitResult);
213: expr.getRHS().accept(this );
214: expression.setRHS((Expression) visitResult);
215: visitResult = expression;
216: }
217:
218: public void visit(FilterExpr expr) {
219: throw new XPathVisitorException("XPath element "
220: + "FilterExpr not supported");
221: }
222:
223: public void visit(RelationalExpr expr) {
224: Class relationalExpressionClass = (Class) RELATIONAL_EXPRESSIONS_BY_OPERATOR
225: .get(expr.getOperator());
226: RelationalExpression expression;
227: try {
228: expression = (RelationalExpression) relationalExpressionClass
229: .newInstance();
230: } catch (Exception e) {
231: throw new XPathVisitorException(e);
232: }
233: expr.getLHS().accept(this );
234: expression.setLHS((Expression) visitResult);
235: expr.getRHS().accept(this );
236: expression.setRHS((Expression) visitResult);
237: visitResult = expression;
238: }
239:
240: public void visit(AdditiveExpr expr) {
241: throw new XPathVisitorException("XPath element "
242: + "AdditiveExpr not supported");
243: }
244:
245: public void visit(MultiplicativeExpr expr) {
246: throw new XPathVisitorException("XPath element "
247: + "MultiplicativeExpr not supported");
248: }
249:
250: public void visit(UnaryExpr expr) {
251: throw new XPathVisitorException("XPath element "
252: + "UnaryExpr not supported");
253: }
254:
255: public void visit(UnionExpr expr) {
256: throw new XPathVisitorException("XPath element "
257: + "UnionExpr not supported");
258: }
259:
260: public void visit(NumberExpr expr) {
261: LiteralNumericExpression expression = new LiteralNumericExpression();
262: expression.setValue(expr.getNumber());
263: visitResult = expression;
264: }
265:
266: public void visit(LiteralExpr expr) {
267: LiteralStringExpression expression = new LiteralStringExpression();
268: expression.setValue(expr.getLiteral());
269: visitResult = expression;
270: }
271:
272: public void visit(VariableReferenceExpr expr) {
273: throw new XPathVisitorException("XPath element "
274: + "VariableReferenceExpr not supported");
275: }
276:
277: public void visit(FunctionCallExpr expr) {
278: Class functionCallExpressionClass = (Class) FUNCTIONS_BY_NAME
279: .get(expr.getFunctionName());
280: /* Check if we've got a known function. */
281: if (functionCallExpressionClass == null) {
282: throw new XPathVisitorException("Function '"
283: + expr.getFunctionName() + "' not supported");
284: }
285:
286: FunctionExpression expression;
287: try {
288: expression = (FunctionExpression) functionCallExpressionClass
289: .newInstance();
290: } catch (Exception e) {
291: throw new XPathVisitorException(e);
292: }
293: int paramCount = expr.getParameters().size();
294: Expression arguments[] = new Expression[paramCount];
295: for (int i = 0; i < paramCount; i++) {
296: Expr argumentExpr = (Expr) expr.getParameters().get(i);
297: argumentExpr.accept(this );
298: arguments[i] = (Expression) visitResult;
299: }
300: try {
301: expression.setArguments(arguments);
302: } catch (WrongArgumentsException e) {
303: throw new XPathVisitorException(e);
304: }
305: visitResult = expression;
306: }
307:
308: public void visit(NameStep step) {
309: String name = step.getLocalName();
310: MetaProperty metaProperty = resolver.resolve(name);
311: if (metaProperty == null) {
312: throw new XPathVisitorException("The property " + name
313: + " can't be resolved.");
314: }
315: Step queryStep = new Step();
316: queryStep.setMetaProperty(metaProperty);
317: Iterator predicatesIt = step.getPredicates().iterator();
318: while (predicatesIt.hasNext()) {
319: Predicate pred = (Predicate) predicatesIt.next();
320: pred.accept(this );
321: if (queryStep.getExpression() != null) {
322: /* If there already is an expression, combine with an and. */
323: LogicalAndExpression andExpression = new LogicalAndExpression();
324: andExpression.setLHS(queryStep.getExpression());
325: andExpression.setRHS((Expression) visitResult);
326: queryStep.setExpression(andExpression);
327: } else {
328: /* If there is no expression, set it. */
329: if (visitResult instanceof BooleanExpression) {
330: queryStep
331: .setExpression((BooleanExpression) visitResult);
332: } else {
333: throw new XPathVisitorException(
334: "Step expressions must be boolean");
335: }
336: }
337: }
338: visitResult = queryStep;
339: }
340:
341: public void visit(ProcessingInstructionNodeStep step) {
342: throw new XPathVisitorException("XPath element "
343: + "ProcessingInstructionNodeStep not supported");
344: }
345:
346: public void visit(AllNodeStep step) {
347: throw new XPathVisitorException("XPath element AllNodeStep"
348: + " not supported");
349: }
350:
351: public void visit(TextNodeStep step) {
352: throw new XPathVisitorException("XPath element TextNodeStep"
353: + " not supported");
354: }
355:
356: public void visit(CommentNodeStep step) {
357: throw new XPathVisitorException("XPath element CommentNodeStep"
358: + " not supported");
359: }
360:
361: public void visit(Predicate pred) {
362: pred.getExpr().accept(this);
363: }
364:
365: }
|