{"action":"closed","issue":{"url":"https://api.github.com/repos/elasticsearch/elasticsearch/issues/5191","labels_url":"https://api.github.com/repos/elasticsearch/elasticsearch/issues/5191/labels{/name}","comments_url":"https://api.github.com/repos/elasticsearch/elasticsearch/issues/5191/comments","events_url":"https://api.github.com/repos/elasticsearch/elasticsearch/issues/5191/events","html_url":"https://github.com/elasticsearch/elasticsearch/issues/5191","id":27941965,"number":5191,"title":"Add support for matching mode when attaching REST handlers","user":{"login":"templth","id":558344,"avatar_url":"https://avatars.githubusercontent.com/u/558344?v=3","gravatar_id":"","url":"https://api.github.com/users/templth","html_url":"https://github.com/templth","followers_url":"https://api.github.com/users/templth/followers","following_url":"https://api.github.com/users/templth/following{/other_user}","gists_url":"https://api.github.com/users/templth/gists{/gist_id}","starred_url":"https://api.github.com/users/templth/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/templth/subscriptions","organizations_url":"https://api.github.com/users/templth/orgs","repos_url":"https://api.github.com/users/templth/repos","events_url":"https://api.github.com/users/templth/events{/privacy}","received_events_url":"https://api.github.com/users/templth/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/elasticsearch/elasticsearch/labels/feedback_needed","name":"feedback_needed","color":"d4c5f9"}],"state":"closed","locked":false,"assignee":{"login":"clintongormley","id":56599,"avatar_url":"https://avatars.githubusercontent.com/u/56599?v=3","gravatar_id":"","url":"https://api.github.com/users/clintongormley","html_url":"https://github.com/clintongormley","followers_url":"https://api.github.com/users/clintongormley/followers","following_url":"https://api.github.com/users/clintongormley/following{/other_user}","gists_url":"https://api.github.com/users/clintongormley/gists{/gist_id}","starred_url":"https://api.github.com/users/clintongormley/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/clintongormley/subscriptions","organizations_url":"https://api.github.com/users/clintongormley/orgs","repos_url":"https://api.github.com/users/clintongormley/repos","events_url":"https://api.github.com/users/clintongormley/events{/privacy}","received_events_url":"https://api.github.com/users/clintongormley/received_events","type":"User","site_admin":false},"milestone":null,"comments":14,"created_at":"2014-02-20T07:27:41Z","updated_at":"2015-01-30T09:57:38Z","closed_at":"2015-01-30T09:57:38Z","body":"At the moment, ElasticSearch does a matching mode `equals` when attaching REST handlers using the method `RestController#registerHandler`:\r\n\r\n    \t@Inject\r\n\tpublic MyRestHandler(Settings settings, Client client, RestController controller) {\r\n\t\tsuper(settings, client);\r\n\r\n\t\t// Define REST endpoints\r\n\t\tcontroller.registerHandler(Method.GET, \"(...)\",this);\r\n\r\nIn some cases, it's not suitable since we would want to attach an handle on a subset of URIs. For such cases, the matching mode `starts with` would be more suitable:\r\n\r\n    controller.registerHandler(Method.GET, \"/myuri\",\r\n                       RestMatchingMode.STARTS_WITH, this);\r\n\r\nThis means that all sub URIs (like `/myuri/segment1`, `/myuri/segment2/segment3/segment4`, and so on) would handle by the same class. This would be useful if we want manage URIs in a custom way (URI format, ...) that isn't supported by ElasticSearch. This is typically the case for OData URIs.\r\n\r\nTo implement such feature, we need to add an enumeration to list all support matching modes:\r\n\r\n    public enum RestMatchingMode {\r\n        EQUALS, STARTS_WITH\r\n    }\r\n\r\nWe also need to update the `RestController` to add the corresponding methods:\r\n\r\n    public void registerHandler(RestRequest.Method method,\r\n                                          String path, RestHandler handler) {\r\n        registerHandler(method, path, RestMatchingMode.EQUALS, handler);\r\n    }\r\n\r\n    public void registerHandler(RestRequest.Method method, String path,\r\n                                         RestMatchingMode matchingMode, RestHandler handler) {\r\n        (...)\r\n    }\r\n\r\nAs the matching is handled by the classes `PathTrie` and `TreeNode`, we need to add in it the support of matching mode at both methods insert and retrieve.\r\n\r\n    public synchronized void insert(String[] path, int index,\r\n                         RestMatchingMode matchingMode, T value) {\r\n       (...)\r\n       TrieNode<T> node = children.get(key);\r\n       if (node == null) {\r\n            if (index == (path.length - 1)) {\r\n                node = new TrieNode<T>(token, value, this, wildcard, matchingMode);\r\n            } else {\r\n                node = new TrieNode<T>(token, null, this, wildcard, RestMatchingMode.EQUALS);\r\n            }\r\n            children = newMapBuilder(children).put(key, node).immutableMap();\r\n        (...)\r\n    }\r\n\r\n    public T retrieve(String[] path, int index, Map<String, String> params) {\r\n        (...)\r\n        if (index == (path.length - 1)) {\r\n            return node.value;\r\n        }\r\n\r\n        // In the case of starts with matching, return the value\r\n        if (RestMatchingMode.STARTS_WITH.equals(node.getMatchingMode())) {\r\n            return node.value;\r\n        }\r\n        (...)\r\n\r\nMoreover we simply need to add the property matchingMode in the class TreeNode\r\n\r\n    public class TrieNode<T> {\r\n        (...)\r\n        private RestMatchingMode matchingMode; \r\n        (...)\r\n\r\n        public TrieNode(String key, T value, TrieNode parent, String wildcard,\r\n                                   RestMatchingMode matchingMode) {\r\n            this.key = key;\r\n            this.wildcard = wildcard;\r\n            this.isWildcard = (key.equals(wildcard));\r\n            this.parent = parent;\r\n            this.value = value;\r\n            this.children = ImmutableMap.of();\r\n            this.matchingMode = matchingMode;\r\n            (...)\r\n        }\r\n        (...)\r\n    }\r\n\r\n\r\n"}}