org.apache.jena.sdb.exprmatch.ExprMatcher Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jena-sdb Show documentation
Show all versions of jena-sdb Show documentation
SDB is a persistence layer for use with Apache Jena that uses an SQL database to store triples/quads.
/*
* 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.jena.sdb.exprmatch;
import java.util.List;
import org.apache.jena.sparql.core.Var ;
import org.apache.jena.sparql.expr.* ;
import org.apache.jena.sparql.util.ExprUtils ;
/** Matches an expression template to a query expression.
*/
public class ExprMatcher
{
/* ActionMap : what to do when a variable is encountered in the pattern
* CalloutMap : what to do when a (fixed) function is discovered in the pattern
* ResultMap : Association of var name to expression needed for a match.
* Actually, just a string -> expression map
*/
/** Match an expression against a pattern. If the pattern has variables
* in it, these are checked, by name, in the MapAction and the registered action
* invoked to determine whether the variable matches; if the pattern has a named
* function, the MapCallout is used to find a registered operation.
* Return a map of results, recording the bindings of variables
*/
public static MapResult match(Expr expression,
Expr pattern,
MapAction mapAction,
MapCallout mapCallout,
MapResult mapResult)
{
MatchVisitor m = new MatchVisitor(expression, mapAction, mapCallout, mapResult) ;
try {
pattern.visit(m) ;
} catch (NoExprMatch ex)
{
return null ;
}
return mapResult ;
}
public static MapResult match(Expr expression,
Expr pattern,
MapAction mapAction,
MapCallout mapCallout)
{
return match(expression, pattern, mapAction, mapCallout, new MapResult()) ;
}
public static MapResult match(Expr expression, Expr pattern, MapAction mapAction)
{ return match(expression, pattern, mapAction, null, new MapResult()) ; }
public static MapResult match(String expression, String pattern, MapAction mapAction)
{
return match(ExprUtils.parse(expression),
ExprUtils.parse(pattern),
mapAction) ;
}
// Visit/walk the pattern
static class MatchVisitor extends ExprVisitorFunction implements ExprVisitor
{
private Expr target ;
private MapAction aMap ;
private MapResult rMap ;
private MapCallout cMap ;
// Default action is to accept anything - i.e. pattern variables are any expression
static ActionMatch defaultAction = new ActionMatchBind() ;
MatchVisitor(Expr target, MapAction aMap, MapCallout cMap, MapResult rMap)
{
this.aMap = aMap ;
this.rMap = rMap ;
this.cMap = cMap ;
this.target = target ;
}
/* ExprFunction in the pattern:
* 1/ If in the call out map, do that : return
* 2/ Check that the thing to be matched is a function as well
* and has the same function label (internal name or IRI).
* 3/ Check same number of arguments
* 4/ For each argument, match that as well.
*/
@Override
public void visitExprFunction(ExprFunction patExpr)
{
String uri = patExpr.getFunctionIRI() ;
if ( uri != null && cMap != null && cMap.containsKey(uri) )
{
List args = patExpr.getArgs() ;
if( ! cMap.get(uri).match(uri, args, rMap) )
throw new NoExprMatch("Function callout rejected match") ;
return ;
}
if ( ! target.isFunction() )
throw new NoExprMatch("Not an ExprFunction: "+target) ;
ExprFunction funcTarget = target.getFunction() ;
if ( ! patExpr.getFunctionSymbol().equals(funcTarget.getFunctionSymbol()) )
throw new NoExprMatch("Different function symbols: "+patExpr.getFunctionSymbol().getSymbol()+" // "+funcTarget.getFunctionSymbol().getSymbol()) ;
if ( patExpr.numArgs() != funcTarget.numArgs() )
throw new NoExprMatch("Different arity: "+patExpr.numArgs()+"/"+funcTarget.numArgs()) ;
// Either both null (some built-in) or both the same IRI
if ( ! ( patExpr.getFunctionIRI() == null && funcTarget.getFunctionIRI() == null ) )
if ( ! patExpr.getFunctionIRI().equals(funcTarget.getFunctionIRI()) )
throw new NoExprMatch("Different functions: "+patExpr.getFunctionIRI()+" "+funcTarget.getFunctionIRI()) ;
for ( int i = 1 ; i <= funcTarget.numArgs() ; i++ )
{
// Recurse, breaking up the target.
Expr p = patExpr.getArg(i) ;
Expr e = funcTarget.getArg(i) ;
MatchVisitor m = new MatchVisitor(e, aMap, cMap, rMap) ;
p.visit(m) ;
}
}
/* NodeValue in the pattern
* The target must have the same.
*/
@Override
public void visit(NodeValue nv)
{
if ( ! target.isConstant() )
throw new NoExprMatch("Not a NodeValue") ;
if ( ! nv.equals(target.getConstant()) )
throw new NoExprMatch("Different value: "+nv+" & "+target.getConstant()) ;
}
@Override
public void visit(ExprNone none)
{
throw new NoExprMatch("ExprNone") ;
}
/*
* Variable is the pattern
* 1/ If in the action map, do the action
* 2/ Invoke default action.
*/
@Override
public void visit(ExprVar patternVar)
{
Var vn = patternVar.asVar() ;
ActionMatch a = aMap.get(vn) ;
if ( a == null )
a = defaultAction ;
if ( a.match(vn, target, rMap) )
return ;
throw new NoExprMatch("Action for "+patternVar+ "+failed") ;
}
@Override
public void visit(ExprFunctionOp funcOp)
{ throw new NoExprMatch("ExprFunctionOp") ; }
@Override
public void visit(ExprAggregator eAgg)
{ throw new NoExprMatch("ExprAggregate") ; }
}
}