function findRoute($requestUri, &$routeParameters, $httpRequestMethod, $serverKey)
{
    $routeMethod = null;
    $configuration = RESTConfigurationLoader::loadConfiguration($serverKey);
    $methods = $configuration->getMethods();
    for ($i = 0; $i < count($methods); $i++) {
        if ($methods[$i]->getHttp() != $httpRequestMethod) {
            unset($methods[$i]);
        }
    }
    $requestUri = Explode("?", substr($requestUri, 1));
    $requestUriParts = Explode("/", $requestUri[0]);
    $likelyMethods = array();
    $excludedMethods = array();
    // Backward loop
    for ($i = count($requestUriParts) - 1; $i >= 0; $i--) {
        // Find if there's a path like that, otherwise check for placeholders
        foreach ($methods as $method) {
            $methodName = $method->getName();
            if (in_array($methodName, $excludedMethods)) {
                continue;
            }
            $route = $method->getRoute();
            if (!empty($route)) {
                $routeParts = Explode("/", substr($route, 1));
                if (count($routeParts) <= count($requestUriParts)) {
                    $backwardIndex = count($routeParts) - (count($requestUriParts) - $i);
                    if ($backwardIndex >= 0) {
                        if ($routeParts[$backwardIndex] == $requestUriParts[$i]) {
                            if (!ArrayUtils::existKey($methodName, $likelyMethods)) {
                                $likelyMethods[$methodName] = array();
                            }
                        } else {
                            if (RouteUtils::isRoutePlaceholder($routeParts[$backwardIndex])) {
                                $foundParameters;
                                $placeHolder = RouteUtils::getRoutePlaceholder($routeParts[$backwardIndex]);
                                if (!ArrayUtils::existKey($methodName, $likelyMethods)) {
                                    $foundParameters = array();
                                } else {
                                    $foundParameters = $likelyMethods[$methodName];
                                }
                                $foundParameters[$placeHolder] = $requestUriParts[$i];
                                $likelyMethods[$methodName] = $foundParameters;
                            } else {
                                array_push($excludedMethods, $methodName);
                                unset($likelyMethods[$methodName]);
                            }
                        }
                    }
                }
            }
        }
    }
    if (count($likelyMethods) > 1) {
        // Get the route with the highest matches
        $maxRouteSize = 0;
        foreach ($likelyMethods as $key => $value) {
            $route = RESTConfigurationLoader::getMethod($key, $serverKey)->getRoute();
            $routeSize = count(Explode("/", substr($route, 1)));
            if ($routeSize > $maxRouteSize) {
                $maxRouteSize = $routeSize;
            }
        }
        foreach ($likelyMethods as $key => $value) {
            $route = RESTConfigurationLoader::getMethod($key, $serverKey)->getRoute();
            $routeSize = count(Explode("/", substr($route, 1)));
            if ($routeSize < $maxRouteSize) {
                unset($likelyMethods[$key]);
            }
        }
    }
    if (count($likelyMethods) > 1) {
        $ambiguousMethods = "";
        foreach ($likelyMethods as $key => $value) {
            $ambiguousMethods .= "\"" . $key . "\", ";
        }
        $ambiguousMethods = substr($ambiguousMethods, 0, strlen($ambiguousMethods) - 2);
        throw new MashapeException(sprintf(EXCEPTION_AMBIGUOUS_ROUTE, $ambiguousMethods), EXCEPTION_SYSTEM_ERROR_CODE);
    }
    // Get the first item (just one or none item can exist)
    foreach ($likelyMethods as $key => $value) {
        $routeMethod = RESTConfigurationLoader::getMethod($key, $serverKey);
        $routeParameters = array_merge($routeParameters, $value);
        break;
    }
    return $routeMethod;
}
function serializeParameters($method, $instance)
{
    $reflectedClass = new ReflectionClass(get_class($instance));
    $reflectedMethod = $reflectedClass->getMethod($method->getName());
    $reflectedParameters = $reflectedMethod->getParameters();
    $result = "\t\t<parameters>\n";
    for ($i = 0; $i < count($reflectedParameters); $i++) {
        $param = $reflectedParameters[$i];
        $result .= "\t\t\t<parameter optional=\"" . ($param->isDefaultValueAvailable() ? "true" : "false") . "\">" . $param->name . "</parameter>\n";
    }
    $result .= "\t\t</parameters>\n";
    // Check route parameters
    $route = $method->getRoute();
    if (!empty($route)) {
        $routeParts = Explode("/", substr($route, 1));
        foreach ($routeParts as $routePart) {
            if (RouteUtils::isRoutePlaceholder($routePart)) {
                $placeHolder = RouteUtils::getRoutePlaceholder($routePart);
                $exist = false;
                for ($i = 0; $i < count($reflectedParameters); $i++) {
                    $param = $reflectedParameters[$i];
                    if ($placeHolder == $param->name) {
                        if ($param->isDefaultValueAvailable()) {
                            throw new MashapeException(sprintf(EXCEPTION_METHOD_OPTIONAL_ROUTE_PARAM, $param->name, $method->getName()), EXCEPTION_XML_CODE);
                        }
                        $exist = true;
                        break;
                    }
                }
                if ($exist == false) {
                    throw new MashapeException(sprintf(EXCEPTION_METHOD_INVALID_ROUTE_PARAM, $placeHolder), EXCEPTION_XML_CODE);
                }
            }
        }
    }
    return $result;
}