/*
* 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.sparql.function.user;
import java.util.List;
import java.util.Map;
import org.apache.jena.sparql.core.Var ;
import org.apache.jena.sparql.expr.* ;
import org.apache.jena.sparql.sse.builders.ExprBuildException ;
/**
* An expression transformer that will expand user defined function expressions
* so they do not explicitly rely on other user defined functions.
* <p>
* See {@link UserDefinedFunctionFactory#getPreserveDependencies()} for discussion of what this means in practise
* </p>
*/
public class ExprTransformExpand extends ExprTransformCopy {
private Map<String, UserDefinedFunctionDefinition> definitions;
/**
* Creates a new transformer
* @param defs User defined function definitions
*/
public ExprTransformExpand(Map<String, UserDefinedFunctionDefinition> defs) {
if (defs == null) throw new IllegalArgumentException("defs cannot be null");
this.definitions = defs;
}
@Override
public Expr transform(ExprFunctionN func, ExprList args) {
ExprFunction f = func.getFunction();
if (this.shouldExpand(f)) {
UserDefinedFunctionDefinition def = this.definitions.get(f.getFunction().getFunctionIRI());
UserDefinedFunction uFunc = (UserDefinedFunction) def.newFunctionInstance();
//Need to watch out for the case where the arguments supplied to the invoked
//function are in a different order to the arguments supplied to the defined
//function
//Thus we will build the list of arguments used to expand the inner function
//manually
List<Var> defArgs = def.getArgList();
ExprList subArgs = new ExprList();
for (int i = 0; i < args.size(); i++) {
Expr arg = args.get(i);
String var = arg.getVarName();
if (var == null) {
//Non-variable args may be passed as-is
subArgs.add(arg);
} else {
//Variable args must be checked to ensure they are within the number of
//arguments of the invoked function
//We then use the arg as-is to substitute
if (i > defArgs.size()) throw new ExprBuildException("Unable to expand function dependency, the function <" + def.getUri() + "> is called but uses an argument ?" + var + " which is not an argument to the outer function");
subArgs.add(arg);
}
}
//Expand the function
uFunc.build(def.getUri(), subArgs);
return uFunc.getActualExpr();
} else {
return super.transform(func, args);
}
}
private boolean shouldExpand(ExprFunction func) {
return this.definitions.containsKey(func.getFunctionIRI());
}
}