/* | |
* Licensed to the Apache Software Foundation (ASF) under one | |
* or more contributor license agreements. See the NOTICE file | |
* distributed with this work for additional information | |
* regarding copyright ownership. The ASF licenses this file | |
* to you under the Apache License, Version 2.0 (the | |
* "License"); you may not use this file except in compliance | |
* with the License. You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, | |
* software distributed under the License is distributed on an | |
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
* KIND, either express or implied. See the License for the | |
* specific language governing permissions and limitations | |
* under the License. | |
*/ | |
package org.apache.ode.ql.jcc; | |
import java.util.ArrayList; | |
import java.util.Collection; | |
import org.apache.ode.ql.tree.Builder; | |
import org.apache.ode.ql.tree.nodes.Conjunction; | |
import org.apache.ode.ql.tree.nodes.Disjunction; | |
import org.apache.ode.ql.tree.nodes.Equality; | |
import org.apache.ode.ql.tree.nodes.GE; | |
import org.apache.ode.ql.tree.nodes.Greater; | |
import org.apache.ode.ql.tree.nodes.Identifier; | |
import org.apache.ode.ql.tree.nodes.In; | |
import org.apache.ode.ql.tree.nodes.LE; | |
import org.apache.ode.ql.tree.nodes.Less; | |
import org.apache.ode.ql.tree.nodes.Like; | |
import org.apache.ode.ql.tree.nodes.Limit; | |
import org.apache.ode.ql.tree.nodes.LogicNode; | |
import org.apache.ode.ql.tree.nodes.OrderBy; | |
import org.apache.ode.ql.tree.nodes.OrderByElement; | |
import org.apache.ode.ql.tree.nodes.OrderByType; | |
import org.apache.ode.ql.tree.nodes.Query; | |
import org.apache.ode.ql.tree.nodes.Value; | |
public class TreeBuilder extends Builder<String> { | |
public org.apache.ode.ql.tree.nodes.Node build(String query) { | |
try { | |
org.apache.ode.ql.jcc.ASTStart start = new Parser(query).start(); | |
return build(start); | |
}catch(ParseException ex) { | |
//TODO create common exception which will indicate parsing exception | |
throw new RuntimeException(ex.getMessage(), ex); | |
} | |
} | |
private org.apache.ode.ql.tree.nodes.Node build(Node node) { | |
if(node instanceof ASTAnd) { | |
return createConjunction(node); | |
} | |
if(node instanceof ASTOr) { | |
return createDisjunction(node); | |
} | |
if(node instanceof ASTLess) { | |
return createLess(node); | |
} | |
if(node instanceof ASTGreater) { | |
return createGreater(node); | |
} | |
if(node instanceof ASTLE) { | |
return createLE(node); | |
} | |
if(node instanceof ASTIn) { | |
return createIn(node); | |
} | |
if(node instanceof ASTGE) { | |
return createGE(node); | |
} | |
if(node instanceof ASTEqual) { | |
return createEquality(node); | |
} | |
if(node instanceof ASTLike) { | |
return createLike(node); | |
} | |
if(node instanceof ASTStart) { | |
return createSelection((ASTStart)node); | |
} | |
throw new IllegalArgumentException("Unsupported node type "+node.getClass()); | |
} | |
private Query createSelection(ASTStart node) { | |
Collection<Object> childs = new ArrayList<Object>(node.jjtGetNumChildren()); | |
OrderBy orderBy = null; | |
Limit limit = null; | |
for(int index = 0;index < node.jjtGetNumChildren();index++) { | |
Node childNode = node.jjtGetChild(index); | |
if(childNode instanceof ASTOrderBy) { | |
orderBy = createOrderBy(childNode); | |
} else if(childNode instanceof ASTLimit) { | |
limit = createLimit(childNode); | |
} else { | |
Object child = build(childNode); | |
childs.add(child); | |
} | |
} | |
return new Query(childs, orderBy, limit); | |
} | |
private OrderBy createOrderBy(Node node) { | |
Collection<OrderByElement> orders = new ArrayList<OrderByElement>(node.jjtGetNumChildren()); | |
for(int i = 0;i < node.jjtGetNumChildren();i++) { | |
orders.add(createOrderByElement((ASTOrderByField)node.jjtGetChild(i))); | |
} | |
return new OrderBy(orders); | |
} | |
private OrderByElement createOrderByElement(ASTOrderByField node) { | |
int childsNum = node.jjtGetNumChildren(); | |
OrderByType type; | |
if(childsNum==1) { | |
type = OrderByType.ASC; | |
} if(childsNum==2) { | |
ASTOrderType astType = (ASTOrderType)extractChildNode(node, 1); | |
type = OrderByType.valueOf(astType.getValue().toUpperCase()); | |
} else { | |
//TODO | |
throw new IllegalArgumentException(); | |
} | |
Identifier id = createIdentifier(node, 0); | |
return new OrderByElement(id, type); | |
} | |
private Conjunction createConjunction(Node node) { | |
Collection<LogicNode> childs = extractLogicNodes(node); | |
return new Conjunction(childs); | |
} | |
private Disjunction createDisjunction(Node node) { | |
Collection<LogicNode> childs = extractLogicNodes(node); | |
return new Disjunction(childs); | |
} | |
private LE createLE(Node node) { | |
checkChildsNumber(node, 2); | |
return new LE(createIdentifier(node, 0), createValue(node, 1)); | |
} | |
private In createIn(Node node) { | |
checkChildsNumber(node, 2); | |
Node inValuesNode = extractChildNode(node, 1, ASTInValues.class); | |
Collection<Value> values = new ArrayList<Value>(inValuesNode.jjtGetNumChildren()); | |
for(int index = 0;index < inValuesNode.jjtGetNumChildren();index++) { | |
values.add(createValue(inValuesNode, index)); | |
} | |
return new In(createIdentifier(node, 0), values); | |
} | |
private GE createGE(Node node) { | |
checkChildsNumber(node, 2); | |
return new GE(createIdentifier(node, 0), createValue(node, 1)); | |
} | |
private Less createLess(Node node) { | |
checkChildsNumber(node, 2); | |
return new Less(createIdentifier(node, 0), createValue(node, 1)); | |
} | |
private Greater createGreater(Node node) { | |
checkChildsNumber(node, 2); | |
return new Greater(createIdentifier(node, 0), createValue(node, 1)); | |
} | |
private Equality createEquality(Node node) { | |
checkChildsNumber(node, 2); | |
return new Equality(createIdentifier(node, 0), createValue(node, 1)); | |
} | |
private Like createLike(Node node) { | |
checkChildsNumber(node, 2); | |
return new Like(createIdentifier(node, 0), createValue(node, 1)); | |
} | |
private Value createValue(Node parentNode, int index) { | |
return new Value<String>(extractValue(parentNode, index).value); | |
} | |
private Limit createLimit(Node node) { | |
return new Limit(((ASTLimit)node).getNumber()); | |
} | |
private Identifier createIdentifier(Node parentNode, int index) { | |
Node node = extractChildNode(parentNode, index); | |
if(node instanceof ASTField) { | |
return new org.apache.ode.ql.tree.nodes.Field(((ASTField)node).name); | |
} | |
if(node instanceof ASTProperty) { | |
return new org.apache.ode.ql.tree.nodes.Property(((ASTProperty)node).getName()); | |
} | |
//TODO | |
throw new IllegalArgumentException(""); | |
} | |
private ASTValue extractValue(Node parentNode, int index) { | |
return (ASTValue)extractChildNode(parentNode, index, ASTValue.class); | |
} | |
@SuppressWarnings("unchecked") | |
private Node extractChildNode(Node parentNode, int index, Class expected) { | |
Node node = extractChildNode(parentNode, index); | |
if(!(expected.isAssignableFrom(node.getClass()))) { | |
//TODO | |
throw new IllegalArgumentException(""); | |
} | |
return node; | |
} | |
private Node extractChildNode(Node parentNode, int index) { | |
if(parentNode.jjtGetNumChildren()<=index) { | |
//TODO | |
throw new IllegalArgumentException(""); | |
} | |
return parentNode.jjtGetChild(index); | |
} | |
private Collection<LogicNode> extractLogicNodes(Node parentNode) { | |
Collection<LogicNode> childs = new ArrayList<LogicNode>(parentNode.jjtGetNumChildren()); | |
for(int index = 0;index < parentNode.jjtGetNumChildren();index++) { | |
childs.add((LogicNode)build(parentNode.jjtGetChild(index))); | |
} | |
return childs; | |
} | |
/* | |
private static boolean checkInheritance(Object obj, Class clazz) { | |
return clazz.isAssignableFrom(clazz.getClass()); | |
} | |
*/ | |
private static void checkChildsNumber(Node node, int expected) { | |
int actual = node.jjtGetNumChildren(); | |
if(actual!=expected) { | |
throw new IllegalArgumentException("Expected childs cound("+actual+") differes from expected "+expected); | |
} | |
} | |
} |