001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.juneau.rest.common.utils;
018
019import static org.apache.juneau.commons.utils.Shorts.*;
020
021import java.lang.reflect.*;
022
023/**
024 * HTTP utilities.
025 *
026 */
027@SuppressWarnings({
028   "java:S3776" // detectHttpMethod and detectHttpPath branch over the do/get/put/... name-prefix conventions
029})
030public class HttpUtils {
031
032   /**
033    * Prevents instantiation.
034    */
035   private HttpUtils() {}
036
037   private static final String[] LC_METHODS = { "get", "put", "post", "delete", "options", "head", "connect", "trace", "patch" };
038   private static final String[] UC_METHODS = { "GET", "PUT", "POST", "DELETE", "OPTIONS", "HEAD", "CONNECT", "TRACE", "PATCH" };
039
040   /**
041    * Given a method name, infers the REST method name.
042    *
043    * @param m The Java method. Must not be <jk>null</jk>.
044    * @param detectMethod Whether we should auto-detect the HTTP method name from the Java method name.
045    * @param def The default HTTP method if not detected. Can be <jk>null</jk>.
046    * @return The REST method name, or <c>def</c> (which can be <jk>null</jk>) if not detected.
047    */
048   public static String detectHttpMethod(Method m, boolean detectMethod, String def) {
049      String n = m.getName();
050      if (detectMethod) {
051         if (n.startsWith("do") && n.length() > 2) {
052            String n2 = ucr(n.substring(2));
053            for (var t : UC_METHODS)
054               if (eq(n2, t))
055                  return n2;
056         }
057         for (var t : LC_METHODS)
058            if (n.startsWith(t) && (n.length() == t.length() || Character.isUpperCase(n.charAt(t.length()))))
059               return ucr(t);
060      }
061      return def;
062   }
063
064   /**
065    * Given a Java method, infers the REST path.
066    *
067    * @param m The Java method. Must not be <jk>null</jk>.
068    * @param method The HTTP method name if it's known. Can be <jk>null</jk>, in which case the path is inferred from Java method naming conventions.
069    * @return The REST path. Never <jk>null</jk> (falls back to <c>'/' + methodName</c> when no convention matches).
070    */
071   public static String detectHttpPath(Method m, String method) {
072      String n = m.getName();
073      if (method == null) {
074         if (n.startsWith("do") && n.length() > 2) {
075            String n2 = ucr(n.substring(2));
076            for (var t : UC_METHODS)
077               if (eq(n2, t))
078                  return "/";
079         }
080         for (var t : LC_METHODS) {
081            if (n.startsWith(t) && (n.length() == t.length() || Character.isUpperCase(n.charAt(t.length())))) {
082               return '/' + java.beans.Introspector.decapitalize(n.substring(t.length()));
083            }
084         }
085      } else {
086         if (eqic(n, method) || eqa(n, "do", "_"))
087            return "/";
088         if (n.startsWith(method) && (n.length() == method.length() || Character.isUpperCase(n.charAt(method.length())))) {
089            return '/' + java.beans.Introspector.decapitalize(n.substring(method.length()));
090         }
091      }
092      return '/' + n;
093   }
094}