View Javadoc

    1   /*
    2    *  Licensed to the Apache Software Foundation (ASF) under one
    3    *  or more contributor license agreements.  See the NOTICE file
    4    *  distributed with this work for additional information
    5    *  regarding copyright ownership.  The ASF licenses this file
    6    *  to you under the Apache License, Version 2.0 (the
    7    *  "License"); you may not use this file except in compliance
    8    *  with the License.  You may obtain a copy of the License at
    9    *
    10   *    http://www.apache.org/licenses/LICENSE-2.0
    11   *
    12   *  Unless required by applicable law or agreed to in writing,
    13   *  software distributed under the License is distributed on an
    14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    15   *  KIND, either express or implied.  See the License for the
    16   *  specific language governing permissions and limitations
    17   *  under the License.
    18   *
    19   */
    20  package org.apache.mina.statemachine.transition;
    21
    22  import java.lang.reflect.InvocationTargetException;
    23  import java.lang.reflect.Method;
    24  import java.util.Arrays;
    25
    26  import org.apache.mina.statemachine.context.StateContext;
    27  import org.slf4j.Logger;
    28  import org.slf4j.LoggerFactory;
    29  import org.apache.mina.statemachine.State;
    30
    31  /**
    32   * {@link SelfTransition} which invokes a {@link Method}. The {@link Method} can
    33   * have zero or any number of StateContext and State regarding order
    34   * <p>
    35   * Normally you wouldn't create instances of this class directly but rather use the
    36   * {@link SelfTransition} annotation to define the methods which should be used as
    37   * transitions in your state machine and then let {@link StateMachineFactory} create a
    38   * {@link StateMachine} for you.
    39   * </p>
    40   *
    41   * @author <a href="http://mina.apache.org">Apache MINA Project</a>
    42   */
    43  public class MethodSelfTransition extends AbstractSelfTransition {
    44      private static final Logger LOGGER = LoggerFactory.getLogger(MethodTransition.class);
    45
    46      private Method method;
    47
    48      private final Object target;
    49
    50      private static final Object[] EMPTY_ARGUMENTS = new Object[0];
    51
    52      public MethodSelfTransition(Method method, Object target) {
    53          super();
    54          this.method = method;
    55          this.target = target;
    56      }
    57
    58      /**
    59       * Creates a new instance
    60       *
    61       * @param method the target method.
    62       * @param target the target object.
    63       */
    64      public MethodSelfTransition(String methodName, Object target) {
    65
    66          this.target = target;
    67
    68          Method[] candidates = target.getClass().getMethods();
    69          Method result = null;
    70          for (int i = 0; i < candidates.length; i++) {
    71              if (candidates[i].getName().equals(methodName)) {
    72                  if (result != null) {
    73                      throw new AmbiguousMethodException(methodName);
    74                  }
    75                  result = candidates[i];
    76              }
    77          }
    78
    79          if (result == null) {
    80              throw new NoSuchMethodException(methodName);
    81          }
    82
    83          this.method = result;
    84
    85      }
    86
    87      /**
    88       * Returns the target {@link Method}.
    89       *
    90       * @return the method.
    91       */
    92      public Method getMethod() {
    93          return method;
    94      }
    95
    96      public boolean doExecute(StateContext stateContext, State state) {
    97          Class<?>[] types = method.getParameterTypes();
    98
    99          if (types.length == 0) {
    100             invokeMethod(EMPTY_ARGUMENTS);
    101             return true;
    102         }
    103
    104         if (types.length > 2) {
    105             return false;
    106         }
    107
    108         Object[] args = new Object[types.length];
    109
    110         int i = 0;
    111         if (types[i].isAssignableFrom(StateContext.class)) {
    112             args[i++] = stateContext;
    113         }
    114         if (i < types.length && types[i].isAssignableFrom(State.class)) {
    115             args[i++] = state;
    116         }
    117
    118         invokeMethod(args);
    119
    120         return true;
    121     }
    122
    123     private void invokeMethod(Object[] arguments) {
    124         try {
    125             if (LOGGER.isDebugEnabled()) {
    126                 LOGGER.debug("Executing method " + method + " with arguments " + Arrays.asList(arguments));
    127             }
    128             method.invoke(target, arguments);
    129         } catch (InvocationTargetException ite) {
    130             if (ite.getCause() instanceof RuntimeException) {
    131                 throw (RuntimeException) ite.getCause();
    132             }
    133             throw new MethodInvocationException(method, ite);
    134         } catch (IllegalAccessException iae) {
    135             throw new MethodInvocationException(method, iae);
    136         }
    137     }
    138
    139 }