/*
* Copyright 2009 DuraSpace.
*
* 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 org.mulgara.query.functions;
import java.util.List;
import javax.xml.xpath.XPathFunction;
import javax.xml.xpath.XPathFunctionException;
import org.jrdf.graph.Literal;
import org.mulgara.query.QueryException;
import org.mulgara.query.filter.value.SimpleLiteral;
/**
* General class for providing management information for XPath function implementations.
*
* @created Oct 5, 2009
* @author Paula Gearon
* @copyright © 2009 <a href="http://www.duraspace.org/">DuraSpace</a>
*/
public abstract class MulgaraFunction implements XPathFunction {
/**
* Evaluate the method represented by this class, using the supplied arguments.
* @see javax.xml.xpath.XPathFunction#evaluate(java.util.List)
*/
@SuppressWarnings("rawtypes")
public Object evaluate(List args) throws XPathFunctionException {
checkArgs(getArity(), args);
try {
return eval(args);
} catch (ClassCastException e) {
throw new XPathFunctionException("Incorrect parameter types passed to function: " + e.getMessage());
}
}
/**
* Test that the correct number of arguments were provided to the function call.
* @param expected The expected number of arguments.
* @param args The list of arguments.
* @throws XPathFunctionException Thrown if the argument list is the wrong length.
*/
protected void checkArgs(int expected, List<?> args) throws XPathFunctionException {
if (expected >= 0 && args.size() != expected) {
throw new XPathFunctionException("Incorrect number of parameters. Should be " + expected + ", but was: " + args.size());
}
}
/**
* Returns the number of arguments required to use this function. Default is 1.
* @return The number of arguments for this function.
*/
protected int getArity() { return 1; }
/**
* The name of this function, followed by its arity.
* If not overridden then this will be the function class's name, starting with a lower-case letter.
* @return The name/arity of this function.
*/
public String getName() {
StringBuilder name = new StringBuilder(getClass().getSimpleName());
char c = name.charAt(0);
if (Character.isUpperCase(c)) {
name.setCharAt(0, Character.toLowerCase(c));
}
for (int i = 1; i < name.length(); i++) {
c = name.charAt(0);
if (Character.isUpperCase(c)) name.replace(i, i + 1, "-" + Character.toLowerCase(c));
}
name.append("/");
int arity = getArity();
if (arity >= 0) name.append(getArity());
else name.append("*");
return name.toString();
}
/**
* Evaluates the operation of the function. The argument list will be the correct length.
* @param args The arguments for the function.
* @return The return value of the function.
* @throws XPathFunctionException If there was an error executing the function.
*/
protected abstract Object eval(List<?> args) throws XPathFunctionException;
/**
* Convert a singleton value into its effective boolean value (EBV).
* @param o The singleton to test.
* @return The EBV of the value.
* @throws XPathFunctionException If a complex evaluation throws an exception.
*/
protected static final boolean toBool(Object o) throws XPathFunctionException {
if (o == null) return false;
if (o instanceof String) return ((String)o).length() != 0;
if (o instanceof Number) return ((Number)o).doubleValue() != 0 && ((Number)o).doubleValue() != Double.NaN;
if (o instanceof Boolean) return ((Boolean)o).booleanValue();
try {
if (o instanceof Literal) return new SimpleLiteral(((Literal)o).getLexicalForm(), ((Literal)o).getLanguage()).test(null);
} catch (NullPointerException e) {
throw new XPathFunctionException("Conversion of data to a simple literal requires a context: " + e.getMessage());
} catch (QueryException e) {
throw new XPathFunctionException("Unable to convert data to a simple literal: " + e.getMessage());
}
throw new XPathFunctionException("Type error: " + o + " [" + o.getClass() + "]");
}
}