Пример #1
0
  private static MultivaluedMap<ParameterType, Parameter> getParametersInfo(
      Method m, Object[] params, OperationResourceInfo ori) {
    MultivaluedMap<ParameterType, Parameter> map = new MetadataMap<ParameterType, Parameter>();

    List<Parameter> parameters = ori.getParameters();
    if (parameters.size() == 0) {
      return map;
    }
    int requestBodyParam = 0;
    int multipartParam = 0;
    for (Parameter p : parameters) {
      if (isIgnorableParameter(m, p)) {
        continue;
      }
      if (p.getType() == ParameterType.REQUEST_BODY) {
        requestBodyParam++;
        if (getMultipart(ori, p.getIndex()) != null) {
          multipartParam++;
        }
      }
      map.add(p.getType(), p);
    }

    if (map.containsKey(ParameterType.REQUEST_BODY)) {
      if (requestBodyParam > 1 && requestBodyParam != multipartParam) {
        reportInvalidResourceMethod(ori.getMethodToInvoke(), "SINGLE_BODY_ONLY");
      }
      if (map.containsKey(ParameterType.FORM)) {
        reportInvalidResourceMethod(ori.getMethodToInvoke(), "ONLY_FORM_ALLOWED");
      }
    }
    return map;
  }
Пример #2
0
  /* (non-Javadoc)
   * @see org.apache.cxf.interceptor.Interceptor#handleMessage(org.apache.cxf.message.Message)
   */
  public void handleMessage(Message message) {
    try {
      if (message != null) {

        List<Object> params = message.getContent(List.class); // parameter instances
        if (params.get(0) instanceof HasXsl) {

          OperationResourceInfo ori = message.getExchange().get(OperationResourceInfo.class);
          JAXBElementProvider provider =
              (JAXBElementProvider)
                  ProviderFactory.getInstance(message)
                      .createMessageBodyWriter(
                          ori.getMethodToInvoke().getReturnType(),
                          ori.getMethodToInvoke().getGenericReturnType(),
                          ori.getMethodToInvoke().getAnnotations(),
                          MediaType.APPLICATION_XML_TYPE,
                          message);
          Map<String, Object> properties = new HashMap<String, Object>();

          HasXsl hasXsl = (HasXsl) params.get(0);
          // System.out.println("Stylesheet params " + hasXsl.getClass() + " " + hasXsl.getXsl());
          if (hasXsl == null || hasXsl.getXsl().equalsIgnoreCase(Constants.NO_XSL)) {
            properties.put(XML_HEADERS, "<!-- no stylesheet -->");
          } else {
            properties.put(
                XML_HEADERS,
                "<?xml-stylesheet type='application/xml' href='" + hasXsl.getXsl() + "'?>");
          }
          provider.setMarshallerProperties(properties);
        }
      }
    } catch (Throwable x) {
      throw new WebApplicationException(Response.status(Status.BAD_REQUEST).build());
    }
  }
Пример #3
0
 private static OperationResourceInfo createOperationInfo(
     Method m, Method annotatedMethod, ClassResourceInfo cri, Path path, String httpMethod) {
   OperationResourceInfo ori = new OperationResourceInfo(m, annotatedMethod, cri);
   URITemplate t = URITemplate.createTemplate(path);
   ori.setURITemplate(t);
   ori.setHttpMethod(httpMethod);
   return ori;
 }
Пример #4
0
 private static int getBodyIndex(
     MultivaluedMap<ParameterType, Parameter> map, OperationResourceInfo ori) {
   List<Parameter> list = map.get(ParameterType.REQUEST_BODY);
   int index = list == null || list.size() > 1 ? -1 : list.get(0).getIndex();
   if (ori.isSubResourceLocator() && index != -1) {
     reportInvalidResourceMethod(ori.getMethodToInvoke(), "NO_BODY_IN_SUBRESOURCE");
   }
   return index;
 }
Пример #5
0
  private static void getAllTypesForResource(
      ClassResourceInfo resource,
      ResourceTypes types,
      boolean jaxbOnly,
      MessageBodyWriter<?> jaxbWriter) {
    for (OperationResourceInfo ori : resource.getMethodDispatcher().getOperationResourceInfos()) {
      Method method = ori.getMethodToInvoke();
      Class<?> realReturnType = method.getReturnType();
      Class<?> cls = realReturnType;
      if (cls == Response.class) {
        cls = getActualJaxbType(cls, method, false);
      }
      Type type = method.getGenericReturnType();
      if (jaxbOnly) {
        checkJaxbType(
            resource.getServiceClass(),
            cls,
            realReturnType == Response.class ? cls : type,
            types,
            method.getAnnotations(),
            jaxbWriter);
      } else {
        types.getAllTypes().put(cls, type);
      }

      for (Parameter pm : ori.getParameters()) {
        if (pm.getType() == ParameterType.REQUEST_BODY) {
          Class<?> inType = method.getParameterTypes()[pm.getIndex()];
          Type paramType = method.getGenericParameterTypes()[pm.getIndex()];
          if (jaxbOnly) {
            checkJaxbType(
                resource.getServiceClass(),
                inType,
                paramType,
                types,
                method.getParameterAnnotations()[pm.getIndex()],
                jaxbWriter);
          } else {
            types.getAllTypes().put(inType, paramType);
          }
        }
      }
    }

    for (ClassResourceInfo sub : resource.getSubResources()) {
      if (!isRecursiveSubResource(resource, sub)) {
        getAllTypesForResource(sub, types, jaxbOnly, jaxbWriter);
      }
    }
  }
Пример #6
0
  private MultivaluedMap<String, String> setRequestHeaders(
      MultivaluedMap<String, String> headers,
      OperationResourceInfo ori,
      boolean formParams,
      Class<?> bodyClass,
      Class<?> responseClass) {
    if (headers.getFirst(HttpHeaders.CONTENT_TYPE) == null) {
      if (formParams || bodyClass != null && MultivaluedMap.class.isAssignableFrom(bodyClass)) {
        headers.putSingle(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED);
      } else {
        String ctType = null;
        List<MediaType> consumeTypes = ori.getConsumeTypes();
        if (!consumeTypes.isEmpty() && !consumeTypes.get(0).equals(MediaType.WILDCARD_TYPE)) {
          ctType = JAXRSUtils.mediaTypeToString(ori.getConsumeTypes().get(0));
        } else if (bodyClass != null) {
          ctType = MediaType.APPLICATION_XML;
        }
        if (ctType != null) {
          headers.putSingle(HttpHeaders.CONTENT_TYPE, ctType);
        }
      }
    }

    List<MediaType> accepts = getAccept(headers);
    if (accepts == null) {
      boolean produceWildcard =
          ori.getProduceTypes().size() == 0
              || ori.getProduceTypes().get(0).equals(MediaType.WILDCARD_TYPE);
      if (produceWildcard) {
        accepts =
            InjectionUtils.isPrimitive(responseClass)
                ? Collections.singletonList(MediaType.TEXT_PLAIN_TYPE)
                : Collections.singletonList(MediaType.APPLICATION_XML_TYPE);
      } else if (responseClass == Void.class || responseClass == Void.TYPE) {
        accepts = Collections.singletonList(MediaType.WILDCARD_TYPE);
      } else {
        accepts = ori.getProduceTypes();
      }

      for (MediaType mt : accepts) {
        headers.add(HttpHeaders.ACCEPT, JAXRSUtils.mediaTypeToString(mt));
      }
    }

    return headers;
  }
Пример #7
0
    protected void doWriteBody(
        Message outMessage, Object body, Type bodyType, Annotation[] customAnns, OutputStream os)
        throws Fault {

      OperationResourceInfo ori = outMessage.getContent(OperationResourceInfo.class);
      if (ori == null) {
        return;
      }

      Method method = ori.getMethodToInvoke();
      int bodyIndex = (Integer) outMessage.get("BODY_INDEX");

      Annotation[] anns =
          customAnns != null
              ? customAnns
              : getMethodAnnotations(ori.getAnnotatedMethod(), bodyIndex);
      try {
        if (bodyIndex != -1) {
          Class<?> paramClass = method.getParameterTypes()[bodyIndex];
          Class<?> bodyClass =
              paramClass.isAssignableFrom(body.getClass()) ? paramClass : body.getClass();
          Type genericType = method.getGenericParameterTypes()[bodyIndex];
          if (bodyType != null) {
            genericType = bodyType;
          }
          genericType =
              InjectionUtils.processGenericTypeIfNeeded(
                  ori.getClassResourceInfo().getServiceClass(), bodyClass, genericType);
          bodyClass = InjectionUtils.updateParamClassToTypeIfNeeded(bodyClass, genericType);
          writeBody(body, outMessage, bodyClass, genericType, anns, os);
        } else {
          Type paramType = body.getClass();
          if (bodyType != null) {
            paramType = bodyType;
          }
          writeBody(body, outMessage, body.getClass(), paramType, anns, os);
        }
      } catch (Exception ex) {
        throw new Fault(ex);
      }
    }
Пример #8
0
 public List<String> getMatchedURIs(boolean decode) {
   if (stack != null) {
     List<String> objects = new ArrayList<String>();
     List<String> uris = new LinkedList<String>();
     String sum = "";
     for (MethodInvocationInfo invocation : stack) {
       OperationResourceInfo ori = invocation.getMethodInfo();
       URITemplate[] paths = {ori.getClassResourceInfo().getURITemplate(), ori.getURITemplate()};
       for (URITemplate t : paths) {
         if (t != null) {
           String v = t.getValue();
           sum += "/" + (decode ? HttpUtils.pathDecode(v) : v);
         }
       }
       UriBuilder ub = UriBuilder.fromPath(sum);
       objects.addAll(invocation.getTemplateValues());
       uris.add(0, ub.build(objects.toArray()).normalize().getPath());
     }
     return uris;
   }
   LOG.fine("No resource stack information, returning empty list");
   return Collections.emptyList();
 }
Пример #9
0
  private void serializeMessage(
      ServerProviderFactory providerFactory,
      Message message,
      Response theResponse,
      OperationResourceInfo ori,
      boolean firstTry) {

    ResponseImpl response = (ResponseImpl) JAXRSUtils.copyResponseIfNeeded(theResponse);

    final Exchange exchange = message.getExchange();

    boolean headResponse =
        response.getStatus() == 200
            && firstTry
            && ori != null
            && HttpMethod.HEAD.equals(ori.getHttpMethod());
    Object entity = response.getActualEntity();
    if (headResponse && entity != null) {
      LOG.info(new org.apache.cxf.common.i18n.Message("HEAD_WITHOUT_ENTITY", BUNDLE).toString());
      entity = null;
    }

    Method invoked =
        ori == null
            ? null
            : ori.getAnnotatedMethod() != null ? ori.getAnnotatedMethod() : ori.getMethodToInvoke();

    Annotation[] annotations = null;
    Annotation[] staticAnns = ori != null ? ori.getOutAnnotations() : new Annotation[] {};
    Annotation[] responseAnns = response.getEntityAnnotations();
    if (responseAnns != null) {
      annotations = new Annotation[staticAnns.length + responseAnns.length];
      System.arraycopy(staticAnns, 0, annotations, 0, staticAnns.length);
      System.arraycopy(responseAnns, 0, annotations, staticAnns.length, responseAnns.length);
    } else {
      annotations = staticAnns;
    }

    response.setStatus(getActualStatus(response.getStatus(), entity));
    response.setEntity(entity, annotations);

    // Prepare the headers
    MultivaluedMap<String, Object> responseHeaders =
        prepareResponseHeaders(message, response, entity, firstTry);

    // Run the filters
    try {
      JAXRSUtils.runContainerResponseFilters(providerFactory, response, message, ori, invoked);
    } catch (Throwable ex) {
      handleWriteException(providerFactory, message, ex, firstTry);
      return;
    }

    // Write the entity
    entity = InjectionUtils.getEntity(response.getActualEntity());
    setResponseStatus(message, getActualStatus(response.getStatus(), entity));
    if (entity == null) {
      if (!headResponse) {
        responseHeaders.putSingle(HttpHeaders.CONTENT_LENGTH, "0");
        if (MessageUtils.getContextualBoolean(
            message, "remove.content.type.for.empty.response", false)) {
          responseHeaders.remove(HttpHeaders.CONTENT_TYPE);
          message.remove(Message.CONTENT_TYPE);
        }
      }
      HttpUtils.convertHeaderValuesToString(responseHeaders, true);
      return;
    }

    Object ignoreWritersProp = exchange.get(JAXRSUtils.IGNORE_MESSAGE_WRITERS);
    boolean ignoreWriters =
        ignoreWritersProp == null ? false : Boolean.valueOf(ignoreWritersProp.toString());
    if (ignoreWriters) {
      writeResponseToStream(message.getContent(OutputStream.class), entity);
      return;
    }

    MediaType responseMediaType =
        getResponseMediaType(responseHeaders.getFirst(HttpHeaders.CONTENT_TYPE));

    Class<?> serviceCls = invoked != null ? ori.getClassResourceInfo().getServiceClass() : null;
    Class<?> targetType = InjectionUtils.getRawResponseClass(entity);
    Type genericType =
        InjectionUtils.getGenericResponseType(
            invoked, serviceCls, response.getActualEntity(), targetType, exchange);
    targetType = InjectionUtils.updateParamClassToTypeIfNeeded(targetType, genericType);
    annotations = response.getEntityAnnotations();

    List<WriterInterceptor> writers =
        providerFactory.createMessageBodyWriterInterceptor(
            targetType,
            genericType,
            annotations,
            responseMediaType,
            message,
            ori == null ? null : ori.getNameBindings());

    OutputStream outOriginal = message.getContent(OutputStream.class);
    if (writers == null || writers.isEmpty()) {
      writeResponseErrorMessage(
          message, outOriginal, "NO_MSG_WRITER", targetType, responseMediaType);
      return;
    }
    try {
      boolean checkWriters = false;
      if (responseMediaType.isWildcardSubtype()) {
        Produces pM =
            AnnotationUtils.getMethodAnnotation(
                ori == null ? null : ori.getAnnotatedMethod(), Produces.class);
        Produces pC = AnnotationUtils.getClassAnnotation(serviceCls, Produces.class);
        checkWriters = pM == null && pC == null;
      }
      responseMediaType = checkFinalContentType(responseMediaType, writers, checkWriters);
    } catch (Throwable ex) {
      handleWriteException(providerFactory, message, ex, firstTry);
      return;
    }
    String finalResponseContentType = JAXRSUtils.mediaTypeToString(responseMediaType);
    if (LOG.isLoggable(Level.FINE)) {
      LOG.fine("Response content type is: " + finalResponseContentType);
    }
    responseHeaders.putSingle(HttpHeaders.CONTENT_TYPE, finalResponseContentType);
    message.put(Message.CONTENT_TYPE, finalResponseContentType);

    boolean enabled = checkBufferingMode(message, writers, firstTry);
    try {

      try {
        JAXRSUtils.writeMessageBody(
            writers,
            entity,
            targetType,
            genericType,
            annotations,
            responseMediaType,
            responseHeaders,
            message);

        if (isResponseRedirected(message)) {
          return;
        }
        checkCachedStream(message, outOriginal, enabled);
      } finally {
        if (enabled) {
          OutputStream os = message.getContent(OutputStream.class);
          if (os != outOriginal && os instanceof CachedOutputStream) {
            os.close();
          }
          message.setContent(OutputStream.class, outOriginal);
          message.put(XMLStreamWriter.class.getName(), null);
        }
      }

    } catch (Throwable ex) {
      logWriteError(firstTry, targetType, responseMediaType);
      handleWriteException(providerFactory, message, ex, firstTry);
    }
  }
Пример #10
0
  @Override
  public void handleMessage(Message message) throws Fault {

    if (checkETagSkipList(
        message.get(Message.PATH_INFO).toString(),
        message.get(Message.HTTP_REQUEST_METHOD).toString())) {
      log.info("Skipping ETagInInterceptor for URI : " + message.get(Message.PATH_INFO).toString());
      return;
    }

    OperationResourceInfo operationResource =
        message.getExchange().get(OperationResourceInfo.class);
    Map<String, List<String>> headers = CastUtils.cast((Map) message.get(Message.PROTOCOL_HEADERS));
    List<Object> arguments = MessageContentsList.getContentsList(message);
    try {
      Class aClass =
          Class.forName(operationResource.getMethodToInvoke().getDeclaringClass().getName());
      Method aClassMethod =
          aClass.getMethod(
              operationResource.getMethodToInvoke().getName() + RestApiConstants.GET_LAST_UPDATED,
              operationResource.getMethodToInvoke().getParameterTypes());
      Object o = aClass.newInstance();
      String lastUpdatedTime = String.valueOf(aClassMethod.invoke(o, arguments.toArray()));
      if (message.get(Message.HTTP_REQUEST_METHOD).equals(RestApiConstants.GET)) {
        if (!Objects.equals(lastUpdatedTime, "null")) {
          String eTag = ETagGenerator.getETag(lastUpdatedTime);
          if (headers.containsKey(HttpHeaders.IF_NONE_MATCH)) {
            String headerValue = headers.get(HttpHeaders.IF_NONE_MATCH).get(0);
            if (Objects.equals(eTag, headerValue)) {
              Response response = Response.notModified(eTag).build();
              message.getExchange().put(Response.class, response);
              return;
            }
          }
          message.getExchange().put(RestApiConstants.ETAG, eTag);
        }
      }
      /*
      If the request method is a PUT or a DELETE and the If-Match header is given then the ETag value for the
      resource and the header value will be compared and if they do not match then the flow will be terminated
      with 412 PRECONDITION FAILED
       */
      if (((RestApiConstants.PUT.equals(message.get(Message.HTTP_REQUEST_METHOD))
              || RestApiConstants.DELETE.equals(message.get(Message.HTTP_REQUEST_METHOD))))
          && headers.containsKey(HttpHeaders.IF_MATCH)) {
        String ifMatchHeaderValue;
        ifMatchHeaderValue = String.valueOf(headers.get(HttpHeaders.IF_MATCH).get(0));
        if (!Objects.equals(lastUpdatedTime, "null")) {
          String eTag = ETagGenerator.getETag(lastUpdatedTime);
          if (!Objects.equals(ifMatchHeaderValue, eTag)) {
            Response response = Response.status(Response.Status.PRECONDITION_FAILED).build();
            message.getExchange().put(Response.class, response);
          }
        }
      }
    } catch (ClassNotFoundException
        | NoSuchMethodException
        | IllegalAccessException
        | InvocationTargetException
        | InstantiationException e) {
      if (log.isDebugEnabled()) {
        log.debug(
            " Error while retrieving the ETag Resource timestamps due to " + e.getMessage(), e);
      }
    }
  }
Пример #11
0
  private Object doChainedInvocation(
      URI uri,
      MultivaluedMap<String, String> headers,
      OperationResourceInfo ori,
      Object body,
      int bodyIndex,
      Exchange exchange,
      Map<String, Object> invocationContext)
      throws Throwable {
    Bus configuredBus = getConfiguration().getBus();
    Bus origBus = BusFactory.getAndSetThreadDefaultBus(configuredBus);
    ClassLoaderHolder origLoader = null;
    try {
      ClassLoader loader = configuredBus.getExtension(ClassLoader.class);
      if (loader != null) {
        origLoader = ClassLoaderUtils.setThreadContextClassloader(loader);
      }
      Message outMessage =
          createMessage(body, ori.getHttpMethod(), headers, uri, exchange, invocationContext, true);
      if (bodyIndex != -1) {
        outMessage.put(Type.class, ori.getMethodToInvoke().getGenericParameterTypes()[bodyIndex]);
      }
      outMessage.getExchange().setOneWay(ori.isOneway());
      setSupportOnewayResponseProperty(outMessage);
      outMessage.setContent(OperationResourceInfo.class, ori);
      setPlainOperationNameProperty(outMessage, ori.getMethodToInvoke().getName());
      outMessage.getExchange().put(Method.class, ori.getMethodToInvoke());

      outMessage.put(
          Annotation.class.getName(), getMethodAnnotations(ori.getAnnotatedMethod(), bodyIndex));

      if (body != null) {
        outMessage.put("BODY_INDEX", bodyIndex);
      }
      outMessage.getInterceptorChain().add(bodyWriter);

      Map<String, Object> reqContext = getRequestContext(outMessage);
      reqContext.put(OperationResourceInfo.class.getName(), ori);
      reqContext.put("BODY_INDEX", bodyIndex);

      // execute chain
      doRunInterceptorChain(outMessage);

      Object[] results = preProcessResult(outMessage);
      if (results != null && results.length == 1) {
        return results[0];
      }

      try {
        return handleResponse(outMessage, ori.getClassResourceInfo().getServiceClass());
      } finally {
        completeExchange(outMessage.getExchange(), true);
      }
    } finally {
      if (origLoader != null) {
        origLoader.reset();
      }
      if (origBus != configuredBus) {
        BusFactory.setThreadDefaultBus(origBus);
      }
    }
  }
Пример #12
0
 private static Multipart getMultipart(OperationResourceInfo ori, int index) {
   Method aMethod = ori.getAnnotatedMethod();
   return aMethod != null
       ? AnnotationUtils.getAnnotation(aMethod.getParameterAnnotations()[index], Multipart.class)
       : null;
 }
Пример #13
0
  private List<Object> getPathParamValues(
      Method m,
      Object[] params,
      MultivaluedMap<ParameterType, Parameter> map,
      List<Parameter> beanParams,
      OperationResourceInfo ori,
      int bodyIndex) {
    List<Object> list = new LinkedList<Object>();

    List<String> methodVars = ori.getURITemplate().getVariables();
    List<Parameter> paramsList = getParameters(map, ParameterType.PATH);
    Map<String, BeanPair> beanParamValues = new HashMap<String, BeanPair>(beanParams.size());
    for (Parameter p : beanParams) {
      beanParamValues.putAll(getValuesFromBeanParam(params[p.getIndex()], PathParam.class));
    }
    if (!beanParamValues.isEmpty() && !methodVars.containsAll(beanParamValues.keySet())) {
      List<String> classVars = ori.getClassResourceInfo().getURITemplate().getVariables();
      for (String classVar : classVars) {
        BeanPair pair = beanParamValues.get(classVar);
        if (pair != null) {
          Object paramValue = convertParamValue(pair.getValue(), pair.getAnns());
          if (isRoot) {
            valuesMap.put(classVar, paramValue);
          } else {
            list.add(paramValue);
          }
        }
      }
    }
    if (isRoot) {
      list.addAll(valuesMap.values());
    }

    Map<String, Parameter> paramsMap = new LinkedHashMap<String, Parameter>();
    for (Parameter p : paramsList) {
      if (p.getName().length() == 0) {
        MultivaluedMap<String, Object> values =
            InjectionUtils.extractValuesFromBean(params[p.getIndex()], "");
        for (String var : methodVars) {
          list.addAll(values.get(var));
        }
      } else {
        paramsMap.put(p.getName(), p);
      }
    }

    Object requestBody = bodyIndex == -1 ? null : params[bodyIndex];
    for (String varName : methodVars) {
      Parameter p = paramsMap.remove(varName);
      if (p != null) {
        list.add(convertParamValue(params[p.getIndex()], getParamAnnotations(m, p)));
      } else if (beanParamValues.containsKey(varName)) {
        BeanPair pair = beanParamValues.get(varName);
        list.add(convertParamValue(pair.getValue(), pair.getAnns()));
      } else if (requestBody != null) {
        try {
          Method getter =
              requestBody
                  .getClass()
                  .getMethod("get" + StringUtils.capitalize(varName), new Class<?>[] {});
          list.add(getter.invoke(requestBody, new Object[] {}));
        } catch (Exception ex) {
          // continue
        }
      }
    }

    for (Parameter p : paramsMap.values()) {
      if (valuesMap.containsKey(p.getName())) {
        int index = 0;
        for (Iterator<String> it = valuesMap.keySet().iterator(); it.hasNext(); index++) {
          if (it.next().equals(p.getName()) && index < list.size()) {
            list.remove(index);
            list.add(index, convertParamValue(params[p.getIndex()], null));
            break;
          }
        }
      }
    }

    return list;
  }
Пример #14
0
  /**
   * Updates the current state if Client method is invoked, otherwise does the remote invocation or
   * returns a new proxy if subresource method is invoked. Can throw an expected exception if
   * ResponseExceptionMapper is registered
   */
  public Object invoke(Object o, Method m, Object[] params) throws Throwable {

    Class<?> declaringClass = m.getDeclaringClass();
    if (Client.class == declaringClass
        || InvocationHandlerAware.class == declaringClass
        || Object.class == declaringClass) {
      return m.invoke(this, params);
    }
    resetResponse();
    OperationResourceInfo ori = cri.getMethodDispatcher().getOperationResourceInfo(m);
    if (ori == null) {
      reportInvalidResourceMethod(m, "INVALID_RESOURCE_METHOD");
    }

    MultivaluedMap<ParameterType, Parameter> types = getParametersInfo(m, params, ori);
    List<Parameter> beanParamsList = getParameters(types, ParameterType.BEAN);

    int bodyIndex = getBodyIndex(types, ori);

    List<Object> pathParams = getPathParamValues(m, params, types, beanParamsList, ori, bodyIndex);

    UriBuilder builder = getCurrentBuilder().clone();
    if (isRoot) {
      addNonEmptyPath(builder, ori.getClassResourceInfo().getURITemplate().getValue());
    }
    addNonEmptyPath(builder, ori.getURITemplate().getValue());

    handleMatrixes(m, params, types, beanParamsList, builder);
    handleQueries(m, params, types, beanParamsList, builder);

    URI uri = builder.buildFromEncoded(pathParams.toArray()).normalize();

    MultivaluedMap<String, String> headers = getHeaders();
    MultivaluedMap<String, String> paramHeaders = new MetadataMap<String, String>();
    handleHeaders(m, params, paramHeaders, beanParamsList, types);
    handleCookies(m, params, paramHeaders, beanParamsList, types);

    if (ori.isSubResourceLocator()) {
      ClassResourceInfo subCri = cri.getSubResource(m.getReturnType(), m.getReturnType());
      if (subCri == null) {
        reportInvalidResourceMethod(m, "INVALID_SUBRESOURCE");
      }

      MultivaluedMap<String, String> subHeaders = paramHeaders;
      if (inheritHeaders) {
        subHeaders.putAll(headers);
      }

      ClientState newState =
          getState()
              .newState(
                  uri, subHeaders, getTemplateParametersMap(ori.getURITemplate(), pathParams));
      ClientProxyImpl proxyImpl =
          new ClientProxyImpl(newState, proxyLoader, subCri, false, inheritHeaders);
      proxyImpl.setConfiguration(getConfiguration());
      return JAXRSClientFactory.createProxy(m.getReturnType(), proxyLoader, proxyImpl);
    }
    headers.putAll(paramHeaders);

    getState().setTemplates(getTemplateParametersMap(ori.getURITemplate(), pathParams));

    Object body = null;
    if (bodyIndex != -1) {
      body = params[bodyIndex];
      if (body == null) {
        bodyIndex = -1;
      }
    } else if (types.containsKey(ParameterType.FORM)) {
      body = handleForm(m, params, types, beanParamsList);
    } else if (types.containsKey(ParameterType.REQUEST_BODY)) {
      body = handleMultipart(types, ori, params);
    }

    setRequestHeaders(
        headers,
        ori,
        types.containsKey(ParameterType.FORM),
        body == null ? null : body.getClass(),
        m.getReturnType());

    return doChainedInvocation(uri, headers, ori, body, bodyIndex, null, null);
  }