    001/*
    002 * Licensed to the Apache Software Foundation (ASF) under one or more
    003 * contributor license agreements.  See the NOTICE file distributed with
    004 * this work for additional information regarding copyright ownership.
    005 * The ASF licenses this file to You under the Apache License, Version 2.0
    006 * (the "License"); you may not use this file except in compliance with
    007 * the License.  You may obtain a copy of the License at
    008 *
    009 *     http://www.apache.org/licenses/LICENSE-2.0
    010 *
    011 * Unless required by applicable law or agreed to in writing, software
    012 * distributed under the License is distributed on an "AS IS" BASIS,
    013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014 * See the License for the specific language governing permissions and
    015 * limitations under the License.
    016 */
    017
    018package org.apache.commons.jxpath.ri.compiler;
    019
    020import java.util.Arrays;
    021
    022import org.apache.commons.jxpath.Function;
    023import org.apache.commons.jxpath.JXPathFunctionNotFoundException;
    024import org.apache.commons.jxpath.NodeSet;
    025import org.apache.commons.jxpath.ri.EvalContext;
    026import org.apache.commons.jxpath.ri.QName;
    027import org.apache.commons.jxpath.ri.axes.NodeSetContext;
    028
    029/**
    030 * Represents an element of the parse tree representing an extension function call.
    031 */
    032public class ExtensionFunction extends Operation {
    033
    034    private final QName functionName;
    035
    036    /**
    037     * Constructs a new ExtensionFunction.
    038     *
    039     * @param functionName name of the function
    040     * @param args         Expression[] of function args
    041     */
    042    public ExtensionFunction(final QName functionName, final Expression[] args) {
    043        super(args);
    044        this.functionName = functionName;
    045    }
    046
    047    @Override
    048    public Object compute(final EvalContext context) {
    049        return computeValue(context);
    050    }
    051
    052    /**
    053     * An extension function gets the current context, therefore it MAY be context dependent.
    054     *
    055     * @return true
    056     */
    057    @Override
    058    public boolean computeContextDependent() {
    059        return true;
    060    }
    061
    062    @Override
    063    public Object computeValue(final EvalContext context) {
    064        Object[] parameters = null;
    065        if (args != null) {
    066            parameters = new Object[args.length];
    067            for (int i = 0; i < args.length; i++) {
    068                parameters[i] = convert(args[i].compute(context));
    069            }
    070        }
    071        final Function function = context.getRootContext().getFunction(functionName, parameters);
    072        if (function == null) {
    073            throw new JXPathFunctionNotFoundException("No such function: " + functionName + Arrays.asList(parameters));
    074        }
    075        final Object result = function.invoke(context, parameters);
    076        return result instanceof NodeSet ? new NodeSetContext(context, (NodeSet) result) : result;
    077    }
    078
    079    /**
    080     * Convert any incoming context to a value.
    081     *
    082     * @param object Object to convert
    083     * @return context value or {@code object} unscathed.
    084     */
    085    private Object convert(final Object object) {
    086        return object instanceof EvalContext ? ((EvalContext) object).getValue() : object;
    087    }
    088
    089    /**
    090     * Gets the function name
    091     *
    092     * @return QName
    093     */
    094    public QName getFunctionName() {
    095        return functionName;
    096    }
    097
    098    @Override
    099    public String toString() {
    100        final StringBuilder buffer = new StringBuilder();
    101        buffer.append(functionName);
    102        buffer.append('(');
    103        final Expression[] args = getArguments();
    104        if (args != null) {
    105            for (int i = 0; i < args.length; i++) {
    106                if (i > 0) {
    107                    buffer.append(", ");
    108                }
    109                buffer.append(args[i]);
    110            }
    111        }
    112        buffer.append(')');
    113        return buffer.toString();
    114    }
    115}