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 }