/**
   * * Invokes one of the resource methods annotated with {@link MethodMapping}.
   *
   * @param mappedMethod mapping info of the method.
   * @param attributes Attributes object for the current request.
   * @return the value returned by the invoked method
   */
  private Object invokeMappedMethod(MethodMappingInfo mappedMethod, Attributes attributes) {

    Method method = mappedMethod.getMethod();
    List parametersValues = new ArrayList();

    // Attributes objects
    PageParameters pageParameters = attributes.getParameters();
    WebResponse response = (WebResponse) attributes.getResponse();
    HttpMethod httpMethod = HttpUtils.getHttpMethod((WebRequest) RequestCycle.get().getRequest());

    LinkedHashMap<String, String> pathParameters =
        mappedMethod.populatePathParameters(pageParameters);
    Iterator<String> pathParamsIterator = pathParameters.values().iterator();
    Class<?>[] parameterTypes = method.getParameterTypes();

    for (int i = 0; i < parameterTypes.length; i++) {
      Object paramValue = null;
      MethodParameter methodParameter = new MethodParameter(parameterTypes[i], mappedMethod, i);
      Annotation annotation = ReflectionUtils.getAnnotationParam(i, method);
      // retrieve parameter value
      if (annotation != null)
        paramValue =
            extractParameterValue(methodParameter, pathParameters, annotation, pageParameters);
      else paramValue = extractParameterFromUrl(methodParameter, pathParamsIterator);
      // try to use the default value
      if (paramValue == null && !methodParameter.getDeaultValue().isEmpty())
        paramValue =
            toObject(methodParameter.getParameterClass(), methodParameter.getDeaultValue());

      if (paramValue == null && methodParameter.isRequired()) {
        response.sendError(
            400,
            "No suitable method found for URL '"
                + extractUrlFromRequest()
                + "' and HTTP method "
                + httpMethod);
        return null;
      }

      parametersValues.add(paramValue);
    }

    try {
      return method.invoke(this, parametersValues.toArray());
    } catch (Exception e) {
      response.sendError(500, "General server error.");
      throw new RuntimeException("Error invoking method '" + method.getName() + "'", e);
    }
  }
  /**
   * * Handles a REST request invoking one of the methods annotated with {@link MethodMapping}. If
   * the annotated method returns a value, this latter is automatically serialized to a given string
   * format (like JSON, XML, etc...) and written to the web response.<br>
   * If no method is found to serve the current request, a 400 HTTP code is returned to the client.
   * Similarly, a 401 HTTP code is return if the user doesn't own one of the roles required to
   * execute an annotated method (See {@link AuthorizeInvocation}).
   */
  @Override
  public final void respond(Attributes attributes) {
    PageParameters pageParameters = attributes.getParameters();
    WebResponse response = (WebResponse) attributes.getResponse();
    HttpMethod httpMethod = HttpUtils.getHttpMethod((WebRequest) RequestCycle.get().getRequest());
    int indexedParamCount = pageParameters.getIndexedCount();

    // mapped method are stored concatenating the number of the segments of
    // their URL and their HTTP method (see annotation MethodMapping)
    List<MethodMappingInfo> mappedMethodsCandidates =
        mappedMethods.get(indexedParamCount + "_" + httpMethod.getMethod());

    MethodMappingInfo mappedMethod =
        selectMostSuitedMethod(mappedMethodsCandidates, pageParameters);

    if (mappedMethod != null) {
      if (!hasAny(mappedMethod.getRoles())) {
        response.sendError(401, "User is not allowed to invoke method on server.");
        return;
      }

      onBeforeMethodInvoked(mappedMethod, attributes);
      Object result = invokeMappedMethod(mappedMethod, attributes);
      onAfterMethodInvoked(mappedMethod, attributes, result);

      // if the invoked method returns a value, it is written to response
      if (result != null) {
        serializeObjectToResponse(response, result, mappedMethod.getMimeOutputFormat());
      }
    } else {
      response.sendError(
          400,
          "No suitable method found for URL '"
              + extractUrlFromRequest()
              + "' and HTTP method "
              + httpMethod);
    }
  }