    1   /*
    2    * Copyright 1999-2004 The Apache Software Foundation
    3    *
    4    * Licensed under the Apache License, Version 2.0 (the "License");
    5    * you may not use this file except in compliance with the License.
    6    * You may obtain a copy of the License at
    7    *
    8    *     http://www.apache.org/licenses/LICENSE-2.0
    9    *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  package org.apache.commons.jxpath.functions;
    17
    18  import java.lang.reflect.InvocationTargetException;
    19  import java.lang.reflect.Method;
    20  import java.lang.reflect.Modifier;
    21
    22  import org.apache.commons.jxpath.ExpressionContext;
    23  import org.apache.commons.jxpath.Function;
    24  import org.apache.commons.jxpath.JXPathException;
    25  import org.apache.commons.jxpath.util.TypeUtils;
    26  import org.apache.commons.jxpath.util.ValueUtils;
    27
    28  /***
    29   * An XPath extension function implemented as an individual Java method.
    30   *
    31   * @author Dmitri Plotnikov
    32   * @version $Revision: 1.11 $ $Date: 2004/02/29 14:17:44 $
    33   */
    34  public class MethodFunction implements Function {
    35
    36      private Method method;
    37      private static final Object EMPTY_ARRAY[] = new Object[0];
    38
    39      public MethodFunction(Method method) {
    40          this.method = ValueUtils.getAccessibleMethod(method);
    41      }
    42
    43      public Object invoke(ExpressionContext context, Object[] parameters) {
    44          try {
    45              Object target;
    46              Object[] args;
    47              if (Modifier.isStatic(method.getModifiers())) {
    48                  target = null;
    49                  if (parameters == null) {
    50                      parameters = EMPTY_ARRAY;
    51                  }
    52                  int pi = 0;
    53                  Class types[] = method.getParameterTypes();
    54                  if (types.length >= 1
    55                      && ExpressionContext.class.isAssignableFrom(types[0])) {
    56                      pi = 1;
    57                  }
    58                  args = new Object[parameters.length + pi];
    59                  if (pi == 1) {
    60                      args[0] = context;
    61                  }
    62                  for (int i = 0; i < parameters.length; i++) {
    63                      args[i + pi] =
    64                          TypeUtils.convert(parameters[i], types[i + pi]);
    65                  }
    66              }
    67              else {
    68                  int pi = 0;
    69                  Class types[] = method.getParameterTypes();
    70                  if (types.length >= 1
    71                      && ExpressionContext.class.isAssignableFrom(types[0])) {
    72                      pi = 1;
    73                  }
    74                  target =
    75                      TypeUtils.convert(
    76                          parameters[0],
    77                          method.getDeclaringClass());
    78                  args = new Object[parameters.length - 1 + pi];
    79                  if (pi == 1) {
    80                      args[0] = context;
    81                  }
    82                  for (int i = 1; i < parameters.length; i++) {
    83                      args[pi + i - 1] =
    84                          TypeUtils.convert(parameters[i], types[i + pi - 1]);
    85                  }
    86              }
    87
    88              return method.invoke(target, args);
    89          }
    90          catch (Throwable ex) {
    91              if (ex instanceof InvocationTargetException) {
    92                  ex = ((InvocationTargetException) ex).getTargetException();
    93              }
    94              throw new JXPathException("Cannot invoke " + method, ex);
    95          }
    96      }
    97
    98      public String toString() {
    99          return method.toString();
    100     }
    101 }