1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 package org.apache.hc.core5.http.impl.routing;
29
30 import java.util.Collections;
31 import java.util.List;
32 import java.util.function.BiFunction;
33 import java.util.function.Function;
34 import java.util.regex.Pattern;
35 import java.util.stream.Collectors;
36
37 final class UriPathRouter<P, T> implements Function<String, T> {
38
39 private final BiFunction<String, List<PathRoute<P, T>>, T> pathRouter;
40 private final List<PathRoute<P, T>> routes;
41
42 UriPathRouter(final Function<String, P> compiler,
43 final BiFunction<String, List<PathRoute<P, T>>, T> pathRouter,
44 final List<PathRoute<String, T>> routes) {
45 this.pathRouter = pathRouter;
46 this.routes = Collections.unmodifiableList(routes.stream()
47 .map(e -> new PathRoute<>(compiler.apply(e.pattern), e.handler))
48 .collect(Collectors.toList()));
49
50 }
51
52 @Override
53 public T apply(final String path) {
54 return pathRouter.apply(path, routes);
55 }
56
57 @Override
58 public String toString() {
59 return routes.toString();
60 }
61
62 static <T> UriPathRouter<?, T> bestMatch(final List<PathRoute<String, T>> routes) {
63 return new UriPathRouter<>(e -> e, new BestMatcher<>(), routes);
64 }
65
66 static <T> UriPathRouter<?, T> ordered(final List<PathRoute<String, T>> routes) {
67 return new UriPathRouter<>(e -> e, new OrderedMatcher<>(), routes);
68 }
69
70 static <T> UriPathRouter<?, T> regEx(final List<PathRoute<String, T>> routes) {
71 return new UriPathRouter<>(Pattern::compile, new RegexMatcher<>(), routes);
72 }
73
74 private static final PathPatternMatcher PATH_PATTERN_MATCHER = PathPatternMatcher.INSTANCE;
75
76
77
78
79
80
81
82
83
84
85
86
87 final static class BestMatcher<T> implements BiFunction<String, List<PathRoute<String, T>>, T> {
88
89 @Override
90 public T apply(final String path, final List<PathRoute<String, T>> routes) {
91 PathRoute<String, T> bestMatch = null;
92 for (final PathRoute<String, T> route : routes) {
93 if (route.pattern.equals(path)) {
94 return route.handler;
95 }
96 if (PATH_PATTERN_MATCHER.match(route.pattern, path)) {
97
98 if (bestMatch == null || PATH_PATTERN_MATCHER.isBetter(route.pattern, bestMatch.pattern)) {
99 bestMatch = route;
100 }
101 }
102 }
103 return bestMatch != null ? bestMatch.handler : null;
104 }
105
106 }
107
108
109
110
111
112
113
114
115
116
117
118
119 final static class OrderedMatcher<T> implements BiFunction<String, List<PathRoute<String, T>>, T> {
120
121 @Override
122 public T apply(final String path, final List<PathRoute<String, T>> routes) {
123 for (final PathRoute<String, T> route : routes) {
124 final String pattern = route.pattern;
125 if (path.equals(pattern)) {
126 return route.handler;
127 }
128 if (PATH_PATTERN_MATCHER.match(pattern, path)) {
129 return route.handler;
130 }
131 }
132 return null;
133 }
134 }
135
136
137
138
139 final static class RegexMatcher<T> implements BiFunction<String, List<PathRoute<Pattern, T>>, T> {
140
141 @Override
142 public T apply(final String path, final List<PathRoute<Pattern, T>> routes) {
143 for (final PathRoute<Pattern, T> route : routes) {
144 final Pattern pattern = route.pattern;
145 if (pattern.matcher(path).matches()) {
146 return route.handler;
147 }
148 }
149 return null;
150 }
151
152 }
153
154 }