1818 */
1919package org .elasticsearch .test .rest .yaml .restspec ;
2020
21- import org .apache .http .client .methods .HttpPost ;
22- import org .apache .http .client .methods .HttpPut ;
21+ import org .elasticsearch .common .collect .Tuple ;
2322
2423import java .util .ArrayList ;
24+ import java .util .Collection ;
25+ import java .util .Comparator ;
2526import java .util .HashMap ;
27+ import java .util .LinkedHashSet ;
2628import java .util .List ;
2729import java .util .Locale ;
2830import java .util .Map ;
31+ import java .util .Objects ;
32+ import java .util .PriorityQueue ;
2933import java .util .Set ;
3034
3135/**
@@ -35,9 +39,7 @@ public class ClientYamlSuiteRestApi {
3539
3640 private final String location ;
3741 private final String name ;
38- private List <String > methods = new ArrayList <>();
39- private List <String > paths = new ArrayList <>();
40- private Map <String , Boolean > pathParts = new HashMap <>();
42+ private Set <Path > paths = new LinkedHashSet <>();
4143 private Map <String , Boolean > params = new HashMap <>();
4244 private Body body = Body .NOT_SUPPORTED ;
4345 private Stability stability = Stability .UNKNOWN ;
@@ -64,60 +66,17 @@ public String getLocation() {
6466 return location ;
6567 }
6668
67- public List <String > getMethods () {
68- return methods ;
69- }
70-
71- /**
72- * Returns the supported http methods given the rest parameters provided
73- */
74- public List <String > getSupportedMethods (Set <String > restParams ) {
75- //we try to avoid hardcoded mappings but the index api is the exception
76- if ("index" .equals (name ) || "create" .equals (name )) {
77- List <String > indexMethods = new ArrayList <>();
78- for (String method : methods ) {
79- if (restParams .contains ("id" )) {
80- //PUT when the id is provided
81- if (HttpPut .METHOD_NAME .equals (method )) {
82- indexMethods .add (method );
83- }
84- } else {
85- //POST without id
86- if (HttpPost .METHOD_NAME .equals (method )) {
87- indexMethods .add (method );
88- }
89- }
90- }
91- return indexMethods ;
69+ void addPath (String path , String [] methods , Set <String > parts ) {
70+ boolean add = this .paths .add (new Path (path , methods , parts ));
71+ if (add == false ) {
72+ throw new IllegalArgumentException ("Found duplicate path [" + path + "]" );
9273 }
93-
94- return methods ;
95- }
96-
97- void addMethod (String method ) {
98- this .methods .add (method );
9974 }
10075
101- public List < String > getPaths () {
76+ public Collection < Path > getPaths () {
10277 return paths ;
10378 }
10479
105- void addPath (String path ) {
106- this .paths .add (path );
107- }
108-
109- /**
110- * Gets all path parts supported by the api. For every path part defines if it
111- * is required or optional.
112- */
113- public Map <String , Boolean > getPathParts () {
114- return pathParts ;
115- }
116-
117- void addPathPart (String pathPart , boolean required ) {
118- this .pathParts .put (pathPart , required );
119- }
120-
12180 /**
12281 * Gets all parameters supported by the api. For every parameter defines if it
12382 * is required or optional.
@@ -153,46 +112,86 @@ public void setStability(String stability) {
153112 public Stability getStability () { return this .stability ; }
154113
155114 /**
156- * Finds the best matching rest path given the current parameters and replaces
157- * placeholders with their corresponding values received as arguments
115+ * Returns the best matching paths based on the provided parameters, which may include either path parts or query_string parameters.
116+ * The best path is the one that has exactly the same number of placeholders to replace
117+ * (e.g. /{index}/{type}/{id} when the path params are exactly index, type and id).
118+ * It returns a list instead of a single path as there are cases where there is more than one best matching path:
119+ * - /{index}/_alias/{name}, /{index}/_aliases/{name}
120+ * - /{index}/{type}/_mapping, /{index}/{type}/_mappings, /{index}/_mappings/{type}, /{index}/_mapping/{type}
158121 */
159- public ClientYamlSuiteRestPath [] getFinalPaths (Map <String , String > pathParams ) {
160- List <ClientYamlSuiteRestPath > matchingRestPaths = findMatchingRestPaths (pathParams .keySet ());
161- if (matchingRestPaths == null || matchingRestPaths .isEmpty ()) {
162- throw new IllegalArgumentException ("unable to find matching rest path for api [" + name + "] and path params " + pathParams );
122+ public List <ClientYamlSuiteRestApi .Path > getBestMatchingPaths (Set <String > params ) {
123+ PriorityQueue <Tuple <Integer , Path >> queue = new PriorityQueue <>(Comparator .comparing (Tuple ::v1 , (a , b ) -> Integer .compare (b , a )));
124+ for (ClientYamlSuiteRestApi .Path path : paths ) {
125+ int matches = 0 ;
126+ for (String actualParameter : params ) {
127+ if (path .getParts ().contains (actualParameter )) {
128+ matches ++;
129+ }
130+ }
131+ if (matches == path .parts .size ()) {
132+ queue .add (Tuple .tuple (matches , path ));
133+ }
163134 }
164-
165- ClientYamlSuiteRestPath [] restPaths = new ClientYamlSuiteRestPath [matchingRestPaths .size ()];
166- for (int i = 0 ; i < matchingRestPaths .size (); i ++) {
167- ClientYamlSuiteRestPath restPath = matchingRestPaths .get (i );
168- restPaths [i ] = restPath .replacePlaceholders (pathParams );
135+ if (queue .isEmpty ()) {
136+ throw new IllegalStateException ("Unable to find a matching path for api [" + name + "]" + params );
169137 }
170- return restPaths ;
138+ List <Path > paths = new ArrayList <>();
139+ Tuple <Integer , Path > poll = queue .poll ();
140+ int maxMatches = poll .v1 ();
141+ do {
142+ paths .add (poll .v2 ());
143+ poll = queue .poll ();
144+ } while (poll != null && poll .v1 () == maxMatches );
145+
146+ return paths ;
171147 }
172148
173- /**
174- * Finds the matching rest paths out of the available ones with the current api (based on REST spec).
175- *
176- * The best path is the one that has exactly the same number of placeholders to replace
177- * (e.g. /{index}/{type}/{id} when the path params are exactly index, type and id).
178- */
179- private List <ClientYamlSuiteRestPath > findMatchingRestPaths (Set <String > restParams ) {
149+ public static class Path {
150+ private final String path ;
151+ private final String [] methods ;
152+ private final Set <String > parts ;
180153
181- List <ClientYamlSuiteRestPath > matchingRestPaths = new ArrayList <>();
182- ClientYamlSuiteRestPath [] restPaths = buildRestPaths ();
183- for (ClientYamlSuiteRestPath restPath : restPaths ) {
184- if (restPath .matches (restParams )) {
185- matchingRestPaths .add (restPath );
154+ private Path (String path , String [] methods , Set <String > parts ) {
155+ this .path = Objects .requireNonNull (path , "path must not be null" );
156+ this .methods = Objects .requireNonNull (methods , "methods must not be null" );
157+ if (methods .length == 0 ) {
158+ throw new IllegalArgumentException ("methods is empty, at least one method is required" );
159+ }
160+ this .parts = Objects .requireNonNull (parts , "parts must not be null" );
161+ for (String part : parts ) {
162+ if (path .contains ("{" + part + "}" ) == false ) {
163+ throw new IllegalArgumentException ("part [" + part + "] not contained in path [" + path + "]" );
164+ }
186165 }
187166 }
188- return matchingRestPaths ;
189- }
190167
191- private ClientYamlSuiteRestPath [] buildRestPaths () {
192- ClientYamlSuiteRestPath [] restPaths = new ClientYamlSuiteRestPath [paths .size ()];
193- for (int i = 0 ; i < restPaths .length ; i ++) {
194- restPaths [i ] = new ClientYamlSuiteRestPath (paths .get (i ));
168+ public String getPath () {
169+ return path ;
170+ }
171+
172+ public String [] getMethods () {
173+ return methods ;
174+ }
175+
176+ public Set <String > getParts () {
177+ return parts ;
178+ }
179+
180+ @ Override
181+ public boolean equals (Object o ) {
182+ if (this == o ) {
183+ return true ;
184+ }
185+ if (o == null || getClass () != o .getClass ()) {
186+ return false ;
187+ }
188+ Path path = (Path ) o ;
189+ return this .path .equals (path .path );
190+ }
191+
192+ @ Override
193+ public int hashCode () {
194+ return Objects .hash (path );
195195 }
196- return restPaths ;
197196 }
198197}
0 commit comments