View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.jxpath.ri.compiler;
19  
20  import java.util.Arrays;
21  
22  import org.apache.commons.jxpath.Function;
23  import org.apache.commons.jxpath.JXPathFunctionNotFoundException;
24  import org.apache.commons.jxpath.NodeSet;
25  import org.apache.commons.jxpath.ri.EvalContext;
26  import org.apache.commons.jxpath.ri.QName;
27  import org.apache.commons.jxpath.ri.axes.NodeSetContext;
28  
29  /**
30   * Represents an element of the parse tree representing an extension function call.
31   */
32  public class ExtensionFunction extends Operation {
33  
34      private final QName functionName;
35  
36      /**
37       * Constructs a new ExtensionFunction.
38       *
39       * @param functionName name of the function
40       * @param args         Expression[] of function args
41       */
42      public ExtensionFunction(final QName functionName, final Expression[] args) {
43          super(args);
44          this.functionName = functionName;
45      }
46  
47      @Override
48      public Object compute(final EvalContext context) {
49          return computeValue(context);
50      }
51  
52      /**
53       * An extension function gets the current context, therefore it MAY be context dependent.
54       *
55       * @return true
56       */
57      @Override
58      public boolean computeContextDependent() {
59          return true;
60      }
61  
62      @Override
63      public Object computeValue(final EvalContext context) {
64          Object[] parameters = null;
65          if (args != null) {
66              parameters = new Object[args.length];
67              for (int i = 0; i < args.length; i++) {
68                  parameters[i] = convert(args[i].compute(context));
69              }
70          }
71          final Function function = context.getRootContext().getFunction(functionName, parameters);
72          if (function == null) {
73              throw new JXPathFunctionNotFoundException("No such function: " + functionName + Arrays.asList(parameters));
74          }
75          final Object result = function.invoke(context, parameters);
76          return result instanceof NodeSet ? new NodeSetContext(context, (NodeSet) result) : result;
77      }
78  
79      /**
80       * Convert any incoming context to a value.
81       *
82       * @param object Object to convert
83       * @return context value or {@code object} unscathed.
84       */
85      private Object convert(final Object object) {
86          return object instanceof EvalContext ? ((EvalContext) object).getValue() : object;
87      }
88  
89      /**
90       * Gets the function name
91       *
92       * @return QName
93       */
94      public QName getFunctionName() {
95          return functionName;
96      }
97  
98      @Override
99      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 }