/* * Copyright (c) 2013-2015 Josef Hardi <josef.hardi@gmail.com> * * Licensed 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 com.obidea.semantika.queryanswer.parser; import java.net.URI; import java.util.ArrayList; import java.util.List; import org.openrdf.model.Value; import org.openrdf.query.algebra.Add; import org.openrdf.query.algebra.And; import org.openrdf.query.algebra.ArbitraryLengthPath; import org.openrdf.query.algebra.Avg; import org.openrdf.query.algebra.BNodeGenerator; import org.openrdf.query.algebra.BindingSetAssignment; import org.openrdf.query.algebra.Bound; import org.openrdf.query.algebra.Clear; import org.openrdf.query.algebra.Coalesce; import org.openrdf.query.algebra.Compare; import org.openrdf.query.algebra.Compare.CompareOp; import org.openrdf.query.algebra.CompareAll; import org.openrdf.query.algebra.CompareAny; import org.openrdf.query.algebra.Copy; import org.openrdf.query.algebra.Count; import org.openrdf.query.algebra.Create; import org.openrdf.query.algebra.Datatype; import org.openrdf.query.algebra.DeleteData; import org.openrdf.query.algebra.DescribeOperator; import org.openrdf.query.algebra.Difference; import org.openrdf.query.algebra.Distinct; import org.openrdf.query.algebra.EmptySet; import org.openrdf.query.algebra.Exists; import org.openrdf.query.algebra.Extension; import org.openrdf.query.algebra.ExtensionElem; import org.openrdf.query.algebra.Filter; import org.openrdf.query.algebra.FunctionCall; import org.openrdf.query.algebra.Group; import org.openrdf.query.algebra.GroupConcat; import org.openrdf.query.algebra.GroupElem; import org.openrdf.query.algebra.IRIFunction; import org.openrdf.query.algebra.If; import org.openrdf.query.algebra.In; import org.openrdf.query.algebra.InsertData; import org.openrdf.query.algebra.Intersection; import org.openrdf.query.algebra.IsBNode; import org.openrdf.query.algebra.IsLiteral; import org.openrdf.query.algebra.IsNumeric; import org.openrdf.query.algebra.IsResource; import org.openrdf.query.algebra.IsURI; import org.openrdf.query.algebra.Label; import org.openrdf.query.algebra.Lang; import org.openrdf.query.algebra.LangMatches; import org.openrdf.query.algebra.LeftJoin; import org.openrdf.query.algebra.Like; import org.openrdf.query.algebra.ListMemberOperator; import org.openrdf.query.algebra.Load; import org.openrdf.query.algebra.LocalName; import org.openrdf.query.algebra.MathExpr; import org.openrdf.query.algebra.MathExpr.MathOp; import org.openrdf.query.algebra.Max; import org.openrdf.query.algebra.Min; import org.openrdf.query.algebra.Modify; import org.openrdf.query.algebra.Move; import org.openrdf.query.algebra.MultiProjection; import org.openrdf.query.algebra.Namespace; import org.openrdf.query.algebra.Not; import org.openrdf.query.algebra.Or; import org.openrdf.query.algebra.Order; import org.openrdf.query.algebra.OrderElem; import org.openrdf.query.algebra.Projection; import org.openrdf.query.algebra.ProjectionElem; import org.openrdf.query.algebra.ProjectionElemList; import org.openrdf.query.algebra.QueryModelNode; import org.openrdf.query.algebra.QueryModelVisitor; import org.openrdf.query.algebra.QueryRoot; import org.openrdf.query.algebra.Reduced; import org.openrdf.query.algebra.Regex; import org.openrdf.query.algebra.SameTerm; import org.openrdf.query.algebra.Sample; import org.openrdf.query.algebra.Service; import org.openrdf.query.algebra.SingletonSet; import org.openrdf.query.algebra.Slice; import org.openrdf.query.algebra.StatementPattern; import org.openrdf.query.algebra.Str; import org.openrdf.query.algebra.Sum; import org.openrdf.query.algebra.TupleExpr; import org.openrdf.query.algebra.Union; import org.openrdf.query.algebra.ValueConstant; import org.openrdf.query.algebra.ValueExpr; import org.openrdf.query.algebra.Var; import org.openrdf.query.algebra.ZeroLengthPath; import com.obidea.semantika.datatype.DataType; import com.obidea.semantika.expression.ExpressionObjectFactory; import com.obidea.semantika.expression.base.ExpressionConstant; import com.obidea.semantika.expression.base.IAtom; import com.obidea.semantika.expression.base.IFunction; import com.obidea.semantika.expression.base.ILiteral; import com.obidea.semantika.expression.base.IQueryExt; import com.obidea.semantika.expression.base.ITerm; import com.obidea.semantika.expression.base.IUriReference; import com.obidea.semantika.expression.base.IVariable; import com.obidea.semantika.expression.base.Join; import com.obidea.semantika.expression.base.QueryExt; import com.obidea.semantika.expression.base.TermUtils; import com.obidea.semantika.mapping.base.TripleAtom; import com.obidea.semantika.util.Serializer; public class SparqlQueryHandler implements QueryModelVisitor<SparqlParserException> { private static ExpressionObjectFactory sExpressionFactory = ExpressionObjectFactory.getInstance(); private IQueryExt mQueryExt; private ITerm mTerm; private List<IVariable> mVarList; private IAtom mQueryExpression; public SparqlQueryHandler() { mQueryExt = createEmptyQuery(); } public IQueryExt getSparql() { mQueryExt.addAtom(getQueryBody()); return mQueryExt; } protected IQueryExt createEmptyQuery() { return new QueryExt(); } protected IVariable getVariable() { return TermUtils.asVariable(getTerm()); } protected ILiteral getLiteral() { return TermUtils.asLiteral(getTerm()); } protected IUriReference getUriReference() { return TermUtils.asUriReference(getTerm()); } protected IFunction getFunction() { return TermUtils.asFunction(getTerm()); } protected ITerm getTerm() { return TermUtils.copy(mTerm); } protected IAtom getQueryBody() { return (IAtom) Serializer.copy(mQueryExpression); } protected List<IVariable> getVariableList() { return mVarList; } @Override public void meet(QueryRoot arg0) throws SparqlParserException { // NO-OP } @Override public void meet(Add arg0) throws SparqlParserException { throw new UnsupportedSparqlExpressionException("SPARQL update string: ADD"); //$NON-NLS-1$ } @Override public void meet(And arg0) throws SparqlParserException { arg0.getLeftArg().visit(this); ITerm termLeft = getTerm(); arg0.getRightArg().visit(this); ITerm termRight = getTerm(); mTerm = sExpressionFactory.formAnd(termLeft, termRight); } @Override public void meet(ArbitraryLengthPath arg0) throws SparqlParserException { // NO-OP } @Override public void meet(Avg arg0) throws SparqlParserException { throw new UnsupportedSparqlExpressionException("Aggregate algebra: AVG"); //$NON-NLS-1$ } @Override public void meet(BindingSetAssignment arg0) throws SparqlParserException { // NO-OP } @Override public void meet(BNodeGenerator arg0) throws SparqlParserException { throw new UnsupportedSparqlExpressionException("Built-in call: BNODE"); //$NON-NLS-1$ } @Override public void meet(Bound arg0) throws SparqlParserException { arg0.getArg().visit(this); ITerm arg = getTerm(); mTerm = sExpressionFactory.formIsNotNull(arg); } @Override public void meet(Clear arg0) throws SparqlParserException { throw new UnsupportedSparqlExpressionException("SPARQL update string: CLEAR"); //$NON-NLS-1$ } @Override public void meet(Coalesce arg0) throws SparqlParserException { throw new UnsupportedSparqlExpressionException("Built-in call: COALESCE"); //$NON-NLS-1$ } @Override public void meet(Compare arg0) throws SparqlParserException { arg0.getLeftArg().visit(this); ITerm termLeft = getTerm(); arg0.getRightArg().visit(this); ITerm termRight = getTerm(); CompareOp op = arg0.getOperator(); switch (op) { case EQ: mTerm = sExpressionFactory.formEq(termLeft, termRight); break; case NE: mTerm = sExpressionFactory.formNeq(termLeft, termRight); break; case GT: mTerm = sExpressionFactory.formGt(termLeft, termRight); break; case GE: mTerm = sExpressionFactory.formGte(termLeft, termRight); break; case LT: mTerm = sExpressionFactory.formLt(termLeft, termRight); break; case LE: mTerm = sExpressionFactory.formLte(termLeft, termRight); break; } } @Override public void meet(CompareAll arg0) throws SparqlParserException { throw new UnsupportedSparqlExpressionException("Sub-query comparator: Compare All"); //$NON-NLS-1$ } @Override public void meet(CompareAny arg0) throws SparqlParserException { throw new UnsupportedSparqlExpressionException("Sub-query comparator: Compare Any"); //$NON-NLS-1$ } @Override public void meet(DescribeOperator arg0) throws SparqlParserException { throw new UnsupportedSparqlExpressionException("DESCRIBE"); //$NON-NLS-1$ } @Override public void meet(Copy arg0) throws SparqlParserException { throw new UnsupportedSparqlExpressionException("SPARQL update string: COPY"); //$NON-NLS-1$ } @Override public void meet(Count arg0) throws SparqlParserException { throw new UnsupportedSparqlExpressionException("Aggregate algebra: COUNT"); //$NON-NLS-1$ } @Override public void meet(Create arg0) throws SparqlParserException { throw new UnsupportedSparqlExpressionException("SPARQL update string: CREATE"); //$NON-NLS-1$ } @Override public void meet(Datatype arg0) throws SparqlParserException { throw new UnsupportedSparqlExpressionException("Built-in call: DATATYPE"); //$NON-NLS-1$ } @Override public void meet(DeleteData arg0) throws SparqlParserException { throw new UnsupportedSparqlExpressionException("SPARQL update string: DELETE DATA"); //$NON-NLS-1$ } @Override public void meet(Difference arg0) throws SparqlParserException { throw new UnsupportedSparqlExpressionException("MINUS"); //$NON-NLS-1$ } @Override public void meet(Distinct arg0) throws SparqlParserException { mQueryExt.setDistinct(true); arg0.visitChildren(this); } @Override public void meet(EmptySet arg0) throws SparqlParserException { // NO-OP } @Override public void meet(Exists arg0) throws SparqlParserException { throw new UnsupportedSparqlExpressionException("Built-in call: EXISTS"); //$NON-NLS-1$ } @Override public void meet(Extension arg0) throws SparqlParserException { List<String> unknownVariables = new ArrayList<String>(); for (ExtensionElem el : arg0.getElements()) { unknownVariables.add(el.getName()); } throw new SparqlParserException("Unknown projection variables: " + unknownVariables); //$NON-NLS-1$ } @Override public void meet(ExtensionElem arg0) throws SparqlParserException { // NO-OP } @Override public void meet(Filter arg0) throws SparqlParserException { TupleExpr expr = arg0.getArg(); if (expr != null) { expr.visit(this); } arg0.getCondition().visit(this); mQueryExt.setFilter(getFunction()); } @Override public void meet(FunctionCall arg0) throws SparqlParserException { throw new UnsupportedSparqlExpressionException("External function call"); //$NON-NLS-1$ } @Override public void meet(Group arg0) throws SparqlParserException { throw new UnsupportedSparqlExpressionException("GROUP BY"); //$NON-NLS-1$ } @Override public void meet(GroupConcat arg0) throws SparqlParserException { throw new UnsupportedSparqlExpressionException("Aggregate Algebra: GroupConcat"); //$NON-NLS-1$ } @Override public void meet(GroupElem arg0) throws SparqlParserException { // NO-OP } @Override public void meet(If arg0) throws SparqlParserException { throw new UnsupportedSparqlExpressionException("Built-in call: IF"); //$NON-NLS-1$ } @Override public void meet(In arg0) throws SparqlParserException { throw new UnsupportedSparqlExpressionException("Sub-query comparator: IN"); //$NON-NLS-1$ } @Override public void meet(InsertData arg0) throws SparqlParserException { throw new UnsupportedSparqlExpressionException("SPARQL update string: INSERT DATA"); //$NON-NLS-1$ } @Override public void meet(Intersection arg0) throws SparqlParserException { throw new UnsupportedSparqlExpressionException("INTERSECT"); //$NON-NLS-1$ } @Override public void meet(IRIFunction arg0) throws SparqlParserException { throw new UnsupportedSparqlExpressionException("Built-in call: IRI"); //$NON-NLS-1$ } @Override public void meet(IsBNode arg0) throws SparqlParserException { throw new UnsupportedSparqlExpressionException("Built-in call: IsBLANK"); //$NON-NLS-1$ } @Override public void meet(IsLiteral arg0) throws SparqlParserException { throw new UnsupportedSparqlExpressionException("Built-in call: IsLITERAL"); //$NON-NLS-1$ } @Override public void meet(IsNumeric arg0) throws SparqlParserException { throw new UnsupportedSparqlExpressionException("Built-in call: IsNUMERIC"); //$NON-NLS-1$ } @Override public void meet(IsResource arg0) throws SparqlParserException { throw new UnsupportedSparqlExpressionException("IsResource"); //$NON-NLS-1$ } @Override public void meet(IsURI arg0) throws SparqlParserException { throw new UnsupportedSparqlExpressionException("Built-in call: IsURI"); //$NON-NLS-1$ } @Override public void meet(org.openrdf.query.algebra.Join arg0) throws SparqlParserException { Join joinExpression = new Join(); joinExpression.setInnerJoin(true); arg0.getLeftArg().visit(this); joinExpression.setLeftExpression(getQueryBody()); arg0.getRightArg().visit(this); joinExpression.setRightExpression(getQueryBody()); mQueryExpression = joinExpression; } @Override public void meet(Label arg0) throws SparqlParserException { // NO-OP } @Override public void meet(Lang arg0) throws SparqlParserException { arg0.getArg().visit(this); ITerm arg = getTerm(); mTerm = sExpressionFactory.formLang(arg); } @Override public void meet(LangMatches arg0) throws SparqlParserException { throw new UnsupportedSparqlExpressionException("Built-in call: LANGMATCHES"); //$NON-NLS-1$ } @Override public void meet(LeftJoin arg0) throws SparqlParserException { Join joinExpression = new Join(); joinExpression.setLeftJoin(true); arg0.getLeftArg().visit(this); joinExpression.setLeftExpression(getQueryBody()); arg0.getRightArg().visit(this); joinExpression.setRightExpression(getQueryBody()); if (arg0.hasCondition()) { arg0.getCondition().visit(this); joinExpression.setFilter(TermUtils.asFunction(getTerm())); } mQueryExpression = joinExpression; } @Override public void meet(Like arg0) throws SparqlParserException { throw new UnsupportedSparqlExpressionException("LIKE"); //$NON-NLS-1$ } @Override public void meet(Load arg0) throws SparqlParserException { throw new UnsupportedSparqlExpressionException("SPARQL update string: LOAD"); //$NON-NLS-1$ } @Override public void meet(LocalName arg0) throws SparqlParserException { // NO-OP } @Override public void meet(MathExpr arg0) throws SparqlParserException { arg0.getLeftArg().visit(this); ITerm leftTerm = getTerm(); arg0.getRightArg().visit(this); ITerm rightTerm = getTerm(); MathOp op = arg0.getOperator(); switch (op) { case PLUS: mTerm = sExpressionFactory.formAddition(leftTerm, rightTerm); break; case MINUS: mTerm = sExpressionFactory.formSubtraction(leftTerm, rightTerm); break; case MULTIPLY: mTerm = sExpressionFactory.formMultiplication(leftTerm, rightTerm); break; case DIVIDE: mTerm = sExpressionFactory.formDivision(leftTerm, rightTerm); break; } } @Override public void meet(Max arg0) throws SparqlParserException { throw new UnsupportedSparqlExpressionException("MAX"); //$NON-NLS-1$ } @Override public void meet(Min arg0) throws SparqlParserException { throw new UnsupportedSparqlExpressionException("MIN"); //$NON-NLS-1$ } @Override public void meet(Modify arg0) throws SparqlParserException { throw new UnsupportedSparqlExpressionException("SPARQL update string: MODIFY"); //$NON-NLS-1$ } @Override public void meet(Move arg0) throws SparqlParserException { throw new UnsupportedSparqlExpressionException("SPARQL update string: MOVE"); //$NON-NLS-1$ } @Override public void meet(MultiProjection arg0) throws SparqlParserException { // NO-OP } @Override public void meet(Namespace arg0) throws SparqlParserException { // NO-OP } @Override public void meet(Not arg0) throws SparqlParserException { arg0.getArg().visit(this); ITerm term = getTerm(); if (term instanceof IFunction) { IFunction function = TermUtils.asFunction(term); String functionName = function.getName(); if (functionName.equals(ExpressionConstant.IS_NOT_NULL)) { mTerm = sExpressionFactory.formIsNull(function.getParameter(0)); } else if (functionName.equals(ExpressionConstant.IS_NULL)) { mTerm = sExpressionFactory.formIsNotNull(function.getParameter(0)); } } else { mTerm = sExpressionFactory.formNot(term); } } @Override public void meet(Or arg0) throws SparqlParserException { arg0.getLeftArg().visit(this); ITerm termLeft = getTerm(); arg0.getRightArg().visit(this); ITerm termRight = getTerm(); mTerm = sExpressionFactory.formOr(termLeft, termRight); } @Override public void meet(Order arg0) throws SparqlParserException { throw new UnsupportedSparqlExpressionException("Query modifier: ORDER BY"); //$NON-NLS-1$ } @Override public void meet(OrderElem arg0) throws SparqlParserException { // NO-OP } @Override public void meet(Projection arg0) throws SparqlParserException { arg0.visitChildren(this); for (IVariable var : getVariableList()) { mQueryExt.addDistTerm(var); } } @Override public void meet(ProjectionElem arg0) throws SparqlParserException { mTerm = sExpressionFactory.getVariable(arg0.getSourceName()); } @Override public void meet(ProjectionElemList arg0) throws SparqlParserException { mVarList = new ArrayList<IVariable>(); for (ProjectionElem el : arg0.getElements()) { el.visit(this); mVarList.add(getVariable()); } } @Override public void meet(Reduced arg0) throws SparqlParserException { throw new UnsupportedSparqlExpressionException("Query modifier: REDUCED"); //$NON-NLS-1$ } @Override public void meet(Regex arg0) throws SparqlParserException { arg0.getArg().visit(this); ITerm textArg = getTerm(); arg0.getPatternArg().visit(this); ITerm patternArg = getTerm(); ITerm flagArg = TermUtils.makeTypedLiteral("i", DataType.STRING); //$NON-NLS-1$ // default flag ValueExpr flagExpr = arg0.getFlagsArg(); if (flagExpr != null) { flagExpr.visit(this); flagArg = getTerm(); } mTerm = sExpressionFactory.formRegex(textArg, patternArg, flagArg); } @Override public void meet(SameTerm arg0) throws SparqlParserException { arg0.getLeftArg().visit(this); ITerm termLeft = getTerm(); arg0.getRightArg().visit(this); ITerm termRight = getTerm(); mTerm = sExpressionFactory.formEq(termLeft, termRight); } @Override public void meet(Sample arg0) throws SparqlParserException { throw new UnsupportedSparqlExpressionException("Aggregate algebra: SAMPLE"); //$NON-NLS-1$ } @Override public void meet(Service arg0) throws SparqlParserException { throw new UnsupportedSparqlExpressionException("SERVICE"); //$NON-NLS-1$ } @Override public void meet(SingletonSet arg0) throws SparqlParserException { // NO-OP } @Override public void meet(Slice arg0) throws SparqlParserException { /* * Basically this method does nothing. It just passes the next TupleExpr * to the next handler. Query modifiers have been handled when constructing * the SelectQuery object initially. */ arg0.getArg().visit(this); } @Override public void meet(StatementPattern arg0) throws SparqlParserException { arg0.getSubjectVar().visit(this); ITerm subject = getTerm(); arg0.getPredicateVar().visit(this); ITerm predicate = getTerm(); arg0.getObjectVar().visit(this); ITerm object = getTerm(); mQueryExpression = new TripleAtom(subject, predicate, object); } @Override public void meet(Str arg0) throws SparqlParserException { arg0.getArg().visit(this); ITerm term = getTerm(); mTerm = sExpressionFactory.formStr(term); } @Override public void meet(Sum arg0) throws SparqlParserException { throw new UnsupportedSparqlExpressionException("Aggregate Algebra: SUM"); //$NON-NLS-1$ } @Override public void meet(Union arg0) throws SparqlParserException { throw new UnsupportedSparqlExpressionException("UNION"); //$NON-NLS-1$ } @Override public void meet(ValueConstant arg0) throws SparqlParserException { Value value = arg0.getValue(); visitValue(value); } @Override public void meet(ListMemberOperator arg0) throws SparqlParserException { // NO-OP } @Override public void meet(Var arg0) throws SparqlParserException { Value value = arg0.getValue(); if (value != null) { visitValue(value); } else { mTerm = sExpressionFactory.getVariable(arg0.getName()); } } @Override public void meet(ZeroLengthPath arg0) throws SparqlParserException { // NO-OP } @Override public void meetOther(QueryModelNode arg0) throws SparqlParserException { arg0.visit(this); } protected void visitValue(Value value) throws SparqlParserException { if (value instanceof org.openrdf.model.Literal) { org.openrdf.model.Literal literal = (org.openrdf.model.Literal) value; String lexicalValue = literal.getLabel(); org.openrdf.model.URI dt = literal.getDatatype(); if (dt == null) { /* * The returned datatype is null for query matching literal with string * type, e.g., * SELECT ?v WHERE { ?v ?p "cat" } */ mTerm = sExpressionFactory.getLiteral(lexicalValue); } else { mTerm = sExpressionFactory.getLiteral(lexicalValue, dt.stringValue()); } } else if (value instanceof org.openrdf.model.URI) { org.openrdf.model.URI uri = (org.openrdf.model.URI) value; URI uriRef = URI.create(uri.toString()); mTerm = sExpressionFactory.getUriReference(uriRef); } else { throw new SparqlParserException("Unknown value constant class: " + value.getClass()); //$NON-NLS-1$ } } }