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    package org.apache.commons.jxpath.ri.compiler;
018    
019    import java.util.Arrays;
020    
021    import org.apache.commons.jxpath.Function;
022    import org.apache.commons.jxpath.JXPathFunctionNotFoundException;
023    import org.apache.commons.jxpath.NodeSet;
024    import org.apache.commons.jxpath.ri.EvalContext;
025    import org.apache.commons.jxpath.ri.QName;
026    import org.apache.commons.jxpath.ri.axes.NodeSetContext;
027    
028    /**
029     * Represents an element of the parse tree representing an extension function
030     * call.
031     *
032     * @author Dmitri Plotnikov
033     * @version $Revision: 652845 $ $Date: 2008-05-02 12:46:46 -0500 (Fri, 02 May 2008) $
034     */
035    public class ExtensionFunction extends Operation {
036    
037        private QName functionName;
038    
039        /**
040         * Create a new ExtensionFunction.
041         * @param functionName name of the function
042         * @param args Expression[] of function args
043         */
044        public ExtensionFunction(QName functionName, Expression[] args) {
045            super(args);
046            this.functionName = functionName;
047        }
048    
049        /**
050         * Get the function name
051         * @return QName
052         */
053        public QName getFunctionName() {
054            return functionName;
055        }
056    
057        /**
058         * An extension function gets the current context, therefore it MAY be
059         * context dependent.
060         * @return true
061         */
062        public boolean computeContextDependent() {
063            return true;
064        }
065    
066        public String toString() {
067            StringBuffer buffer = new StringBuffer();
068            buffer.append(functionName);
069            buffer.append('(');
070            Expression[] args = getArguments();
071            if (args != null) {
072                for (int i = 0; i < args.length; i++) {
073                    if (i > 0) {
074                        buffer.append(", ");
075                    }
076                    buffer.append(args[i]);
077                }
078            }
079            buffer.append(')');
080            return buffer.toString();
081        }
082    
083        public Object compute(EvalContext context) {
084            return computeValue(context);
085        }
086    
087        public Object computeValue(EvalContext context) {
088            Object[] parameters = null;
089            if (args != null) {
090                parameters = new Object[args.length];
091                for (int i = 0; i < args.length; i++) {
092                    parameters[i] = convert(args[i].compute(context));
093                }
094            }
095    
096            Function function =
097                context.getRootContext().getFunction(functionName, parameters);
098            if (function == null) {
099                throw new JXPathFunctionNotFoundException("No such function: "
100                        + functionName + Arrays.asList(parameters));
101            }
102            Object result = function.invoke(context, parameters);
103            return result instanceof NodeSet ? new NodeSetContext(context,
104                    (NodeSet) result) : result;
105        }
106    
107        /**
108         * Convert any incoming context to a value.
109         * @param object Object to convert
110         * @return context value or <code>object</code> unscathed.
111         */
112        private Object convert(Object object) {
113            return object instanceof EvalContext ? ((EvalContext) object).getValue() : object;
114        }
115    }