public static OperationResourceInfo findTargetMethod()

in rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/JAXRSUtils.java [521:675]


    public static OperationResourceInfo findTargetMethod(
        Map<ClassResourceInfo, MultivaluedMap<String, String>> matchedResources,
        Message message,
        String httpMethod,
        MultivaluedMap<String, String> matchedValues,
        String requestContentType,
        List<MediaType> acceptContentTypes,
        boolean throwException,
        boolean recordMatchedUri) {
    //CHECKSTYLE:ON
        final boolean getMethod = HttpMethod.GET.equals(httpMethod);

        MediaType requestType;
        try {
            requestType = toMediaType(requestContentType);
        } catch (IllegalArgumentException ex) {
            throw ExceptionUtils.toNotSupportedException(ex, null);
        }

        SortedMap<OperationResourceInfo, MultivaluedMap<String, String>> candidateList =
            new TreeMap<OperationResourceInfo, MultivaluedMap<String, String>>(
                new OperationResourceInfoComparator(message, httpMethod,
                                                    getMethod, requestType, acceptContentTypes));

        int pathMatched = 0;
        int methodMatched = 0;
        int consumeMatched = 0;
        
        List<OperationResourceInfo> finalPathSubresources = null;
        for (Map.Entry<ClassResourceInfo, MultivaluedMap<String, String>> rEntry : matchedResources.entrySet()) {
            ClassResourceInfo resource = rEntry.getKey();
            MultivaluedMap<String, String> values = rEntry.getValue();

            String path = getCurrentPath(values);
            LOG.fine(() -> new org.apache.cxf.common.i18n.Message("START_OPER_MATCH",
                                                                  BUNDLE,
                                                                  resource.getServiceClass().getName()).toString());

            for (OperationResourceInfo ori : resource.getMethodDispatcher().getOperationResourceInfos()) {
                boolean added = false;

                URITemplate uriTemplate = ori.getURITemplate();
                MultivaluedMap<String, String> map = new MetadataMap<>(values);
                if (uriTemplate != null && uriTemplate.match(path, map)) {
                    String finalGroup = map.getFirst(URITemplate.FINAL_MATCH_GROUP);
                    boolean finalPath = StringUtils.isEmpty(finalGroup) || PATH_SEGMENT_SEP.equals(finalGroup);

                    if (ori.isSubResourceLocator()) {
                        candidateList.put(ori, map);
                        if (finalPath) {
                            if (finalPathSubresources == null) {
                                finalPathSubresources = new LinkedList<>();
                            }
                            finalPathSubresources.add(ori);
                        }
                        added = true;
                    } else if (finalPath) {
                        pathMatched++;
                        if (matchHttpMethod(ori.getHttpMethod(), httpMethod)) {
                            methodMatched++;
                            //CHECKSTYLE:OFF
                            if (getMethod || matchConsumeTypes(requestType, ori)) {
                                consumeMatched++;
                                for (MediaType acceptType : acceptContentTypes) {
                                    if (matchProduceTypes(acceptType, ori)) {
                                        candidateList.put(ori, map);
                                        added = true;
                                        break;
                                    }
                                }
                            }
                            //CHECKSTYLE:ON
                        }
                    }
                }
                LOG.fine(matchMessageLogSupplier(ori, path, httpMethod, requestType, acceptContentTypes, added));
            }
        }
        
        // We may get several matching candidates with different HTTP methods which match subresources
        // and resources. Before excluding subresources, let us make sure we have at least one matching
        // HTTP method candidate.
        boolean isOptions = HttpMethod.OPTIONS.equalsIgnoreCase(httpMethod);
        if (finalPathSubresources != null && (methodMatched > 0 || isOptions)
            && !MessageUtils.getContextualBoolean(message, KEEP_SUBRESOURCE_CANDIDATES, false)) {
            for (OperationResourceInfo key : finalPathSubresources) {
                candidateList.remove(key);
            }
        }
        if (!candidateList.isEmpty()) {
            Map.Entry<OperationResourceInfo, MultivaluedMap<String, String>> firstEntry =
                candidateList.entrySet().iterator().next();
            matchedValues.clear();
            matchedValues.putAll(firstEntry.getValue());
            OperationResourceInfo ori = firstEntry.getKey();
            if (headMethodPossible(ori.getHttpMethod(), httpMethod)) {
                LOG.info(new org.apache.cxf.common.i18n.Message("GET_INSTEAD_OF_HEAD",
                         BUNDLE, ori.getClassResourceInfo().getServiceClass().getName(),
                         ori.getMethodToInvoke().getName()).toString());
            }
            LOG.fine(() -> new org.apache.cxf.common.i18n.Message("OPER_SELECTED",
                               BUNDLE, ori.getMethodToInvoke().getName(),
                               ori.getClassResourceInfo().getServiceClass().getName()).toString());
            if (!ori.isSubResourceLocator()) {
                MediaType responseMediaType = intersectSortMediaTypes(acceptContentTypes,
                                                                      ori.getProduceTypes(),
                                                                      false).get(0);
                message.getExchange().put(Message.CONTENT_TYPE, mediaTypeToString(responseMediaType,
                                                                                  MEDIA_TYPE_Q_PARAM,
                                                                                  MEDIA_TYPE_QS_PARAM));
            }
            if (recordMatchedUri) {
                pushOntoStack(ori, matchedValues, message);
            }
            return ori;
        }

        if (!throwException) {
            return null;
        }

        int status;

        // criteria matched the least number of times will determine the error code;
        // priority : path, method, consumes, produces;
        if (pathMatched == 0) {
            status = 404;
        } else if (methodMatched == 0) {
            status = 405;
        } else if (consumeMatched == 0) {
            status = 415;
        } else {
            // Not a single Produces match
            status = 406;
        }
        Map.Entry<ClassResourceInfo, MultivaluedMap<String, String>> firstCri =
            matchedResources.entrySet().iterator().next();
        String name = firstCri.getKey().isRoot() ? "NO_OP_EXC" : "NO_SUBRESOURCE_METHOD_FOUND";
        org.apache.cxf.common.i18n.Message errorMsg =
            new org.apache.cxf.common.i18n.Message(name,
                                                   BUNDLE,
                                                   message.get(Message.REQUEST_URI),
                                                   getCurrentPath(firstCri.getValue()),
                                                   httpMethod,
                                                   mediaTypeToString(requestType),
                                                   convertTypesToString(acceptContentTypes));
        if (!"OPTIONS".equalsIgnoreCase(httpMethod)) {
            Level logLevel = getExceptionLogLevel(message, ClientErrorException.class);
            LOG.log(logLevel == null ? Level.FINE : logLevel, () -> errorMsg.toString());
        }
        Response response =
            createResponse(getRootResources(message), message, errorMsg.toString(), status, methodMatched == 0);
        throw ExceptionUtils.toHttpException(null, response);

    }