/**
  * @param method
  * @param urlPattern
  * @return the first route matching <code>method</code> and <code>pattern</code>.
  */
 protected ERXRoute routeForMethodAndPattern(ERXRoute.Method method, String urlPattern) {
   for (ERXRoute route : _routes) {
     if (route.method().equals(method) && route.routePattern().pattern().equals(urlPattern)) {
       return route;
     }
   }
   return null;
 }
 /**
  * Returns the routes for the given controller class.
  *
  * @param routeController the controller class
  * @return the routes for the given controller class
  */
 public NSArray<ERXRoute> routesForControllerClass(
     Class<? extends ERXRouteController> routeController) {
   NSMutableArray<ERXRoute> routes = new NSMutableArray<ERXRoute>();
   for (ERXRoute route : _routes) {
     if (route.controller() == routeController) {
       routes.add(route);
     }
   }
   return routes;
 }
  /**
   * Returns the route that matches the request method and path, storing metadata about the route in
   * the given userInfo dictionary.
   *
   * @param method the request method
   * @param path the request path
   * @param userInfo a mutable userInfo
   * @return the matching route (or null if one is not found)
   */
  public ERXRoute routeForMethodAndPath(
      String method, String path, NSMutableDictionary<String, Object> userInfo) {
    if (!path.startsWith("/")) {
      path = "/" + path;
    }

    int dotIndex = path.lastIndexOf('.');
    String requestedType = null;
    if (dotIndex >= 0 && path.indexOf('/', dotIndex + 1) == -1) {
      String type = path.substring(dotIndex + 1);
      if (_parseUnknownExtensions || ERXRestFormat.hasFormatNamed(type)) {
        if (type.length() > 0) {
          requestedType = type;
          userInfo.setObjectForKey(type, ERXRouteRequestHandler.ExtensionKey);
        }
        path = path.substring(0, dotIndex);
      }
    }

    ERXRoute.Method routeMethod =
        ERXRoute.Method.valueOf(ERXStringUtilities.capitalize(method.toLowerCase()));
    ERXRoute matchingRoute = null;
    NSDictionary<ERXRoute.Key, String> keys = null;
    for (ERXRoute route : _routes) {
      keys = route.keys(path, routeMethod);
      if (keys != null) {
        matchingRoute = route;
        break;
      }
    }

    if (matchingRoute != null) {
      if (requestedType != null) {
        userInfo.setObjectForKey(requestedType, ERXRouteRequestHandler.TypeKey);
      }
      userInfo.setObjectForKey(path, ERXRouteRequestHandler.PathKey);
      userInfo.setObjectForKey(matchingRoute, ERXRouteRequestHandler.RouteKey);
      userInfo.setObjectForKey(keys, ERXRouteRequestHandler.KeysKey);
    }

    return matchingRoute;
  }
 /**
  * Checks for an existing route that matches the {@link er.rest.routes.ERXRoute.Method} and {@link
  * er.rest.routes.ERXRoute#routePattern()} of <code>route</code> and yet has a different
  * controller or action mapping.
  *
  * @param route
  */
 protected void verifyRoute(ERXRoute route) {
   ERXRoute duplicateRoute =
       routeForMethodAndPattern(route.method(), route.routePattern().pattern());
   if (duplicateRoute != null) {
     boolean isDifferentController =
         ObjectUtils.notEqual(duplicateRoute.controller(), route.controller());
     boolean isDifferentAction = ObjectUtils.notEqual(duplicateRoute.action(), route.action());
     if (isDifferentController || isDifferentAction) {
       // We have a problem whereby two routes with same url pattern and http method map to
       // different direct actions
       StringBuilder message = new StringBuilder();
       message.append("The route <");
       message.append(route);
       message.append("> conflicts with existing route <");
       message.append(duplicateRoute);
       message.append(">.");
       if (isDifferentController) {
         message.append(" The controller class <");
         message.append(route.controller());
         message.append("> is different to <");
         message.append(duplicateRoute.controller());
         message.append(">.");
       }
       if (isDifferentAction) {
         message.append(" The action <");
         message.append(route.action());
         message.append("> is different to <");
         message.append(duplicateRoute.action());
         message.append(">.");
       }
       throw new IllegalStateException(message.toString());
     }
   }
 }
 /**
  * Clears any caches that may exist on ERXRoutes (probably only useful to JRebel, to clear the
  * route parameter method cache).
  */
 public void _clearCaches() {
   for (ERXRoute route : _routes) {
     route._clearCaches();
   }
 }