Skip to content
This repository was archived by the owner on Mar 3, 2026. It is now read-only.

Commit b7905f0

Browse files
committed
Hide implementation of route pattern and matcher
1 parent 18652b8 commit b7905f0

17 files changed

Lines changed: 253 additions & 397 deletions

File tree

jooby-core/src/main/java/jooby/Filter.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@
22

33
public interface Filter {
44

5-
void handle(Request request, Response response, RouteChain chain) throws Exception;
5+
void handle(Request request, Response response, Route.Chain chain) throws Exception;
66

77
}

jooby-core/src/main/java/jooby/Jooby.java

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414

1515
import jooby.internal.AssetRoute;
1616
import jooby.internal.FallbackBodyConverter;
17-
import jooby.internal.RouteDefinitionImpl;
1817
import jooby.internal.guice.TypeConverters;
1918
import jooby.internal.jetty.Jetty;
2019
import jooby.internal.mvc.Routes;
@@ -325,7 +324,7 @@ public RouteDefinition use(final Filter filter) {
325324
}
326325

327326
public RouteDefinition use(final String path, final Filter filter) {
328-
return route(new RouteDefinitionImpl("*", path, filter));
327+
return route(RouteDefinition.newRoute("*", path, filter));
329328
}
330329

331330
/**
@@ -344,11 +343,11 @@ public RouteDefinition use(final String path, final Filter filter) {
344343
* @return A new route definition.
345344
*/
346345
public RouteDefinition get(final String path, final Router route) {
347-
return route(new RouteDefinitionImpl("GET", path, route));
346+
return route(RouteDefinition.newRoute("GET", path, route));
348347
}
349348

350349
public RouteDefinition get(final String path, final Filter filter) {
351-
return route(new RouteDefinitionImpl("GET", path, filter));
350+
return route(RouteDefinition.newRoute("GET", path, filter));
352351
}
353352

354353
/**
@@ -367,11 +366,11 @@ public RouteDefinition get(final String path, final Filter filter) {
367366
* @return A new route definition.
368367
*/
369368
public RouteDefinition post(final String path, final Router route) {
370-
return route(new RouteDefinitionImpl("POST", path, route));
369+
return route(RouteDefinition.newRoute("POST", path, route));
371370
}
372371

373372
public RouteDefinition post(final String path, final Filter filter) {
374-
return route(new RouteDefinitionImpl("POST", path, filter));
373+
return route(RouteDefinition.newRoute("POST", path, filter));
375374
}
376375

377376
/**
@@ -390,11 +389,11 @@ public RouteDefinition post(final String path, final Filter filter) {
390389
* @return A new route definition.
391390
*/
392391
public RouteDefinition put(final String path, final Router route) {
393-
return route(new RouteDefinitionImpl("PUT", path, route));
392+
return route(RouteDefinition.newRoute("PUT", path, route));
394393
}
395394

396395
public RouteDefinition put(final String path, final Filter filter) {
397-
return route(new RouteDefinitionImpl("PUT", path, filter));
396+
return route(RouteDefinition.newRoute("PUT", path, filter));
398397
}
399398

400399
/**
@@ -413,11 +412,11 @@ public RouteDefinition put(final String path, final Filter filter) {
413412
* @return A new route definition.
414413
*/
415414
public RouteDefinition delete(final String path, final Router router) {
416-
return route(new RouteDefinitionImpl("DELETE", path, router));
415+
return route(RouteDefinition.newRoute("DELETE", path, router));
417416
}
418417

419418
public RouteDefinition delete(final String path, final Filter filter) {
420-
return route(new RouteDefinitionImpl("DELETE", path, filter));
419+
return route(RouteDefinition.newRoute("DELETE", path, filter));
421420
}
422421

423422
/**
@@ -614,7 +613,7 @@ public void configure(final Binder binder) {
614613
// Routes
615614
routes.forEach(candidate -> {
616615
if (candidate instanceof RouteDefinition) {
617-
definitions.addBinding().toInstance((RouteDefinitionImpl) candidate);
616+
definitions.addBinding().toInstance((RouteDefinition) candidate);
618617
} else {
619618
Class<?> routeClass = (Class<?>) candidate;
620619
Routes.routes(mode, routeClass)

jooby-core/src/main/java/jooby/Route.java

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,46 @@
55

66
import com.google.common.annotations.Beta;
77

8+
/**
9+
* <h1>Path Patterns</h1>
10+
* <p>
11+
* Jooby supports Ant-style path patterns:
12+
* </p>
13+
* <p>
14+
* Some examples:
15+
* </p>
16+
* <ul>
17+
* <li>{@code com/t?st.html} - matches {@code com/test.html} but also {@code com/tast.jsp} or
18+
* {@code com/txst.html}</li>
19+
* <li>{@code com/*.html} - matches all {@code .html} files in the {@code com} directory</li>
20+
* <li><code>com/{@literal **}/test.html</code> - matches all {@code test.html} files underneath the
21+
* {@code com} path</li>
22+
* </ul>
23+
*
24+
* <h1>Variable Path Patterns</h1>
25+
* <p>
26+
* Jooby supports path parameters too:
27+
* </p>
28+
* <p>
29+
* Some examples:
30+
* </p>
31+
* <ul>
32+
* <li><code> /user/{id}</code> - /user/* and give you access to the <code>id</code> var.</li>
33+
* <li><code> /user/:id</code> - /user/* and give you access to the <code>id</code> var.</li>
34+
* <li><code> /user/{id:\\d+}</code> - /user/[digits] and give you access to the numeric
35+
* <code>id</code> var.</li>
36+
* </ul>
37+
*
38+
* @author edgar
39+
* @sine 0.1.0
40+
*/
841
@Beta
942
public interface Route {
1043

44+
interface Chain {
45+
void next(Request request, Response response) throws Exception;
46+
}
47+
1148
String path();
1249

1350
String verb();

jooby-core/src/main/java/jooby/RouteChain.java

Lines changed: 0 additions & 7 deletions
This file was deleted.

jooby-core/src/main/java/jooby/RouteDefinition.java

Lines changed: 134 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,22 @@
11
package jooby;
22

3+
import static java.util.Objects.requireNonNull;
4+
5+
import java.util.Arrays;
6+
import java.util.Collections;
37
import java.util.List;
8+
import java.util.Optional;
9+
import java.util.concurrent.atomic.AtomicInteger;
410

511
import javax.annotation.Nonnull;
612

7-
import jooby.internal.RouteDefinitionImpl;
13+
import jooby.internal.RouteImpl;
14+
import jooby.internal.RouteMatcher;
15+
import jooby.internal.RoutePattern;
816

917
import com.google.common.annotations.Beta;
18+
import com.google.common.collect.ImmutableList;
19+
import com.google.common.collect.Lists;
1020

1121
/**
1222
* DSL for customize routes.
@@ -62,85 +72,184 @@
6272
* @since 0.1.0
6373
*/
6474
@Beta
65-
public interface RouteDefinition {
75+
public class RouteDefinition {
6676

67-
public class Builder {
77+
private static final List<MediaType> ALL = ImmutableList.of(MediaType.all);
78+
private static final AtomicInteger INDEX = new AtomicInteger(-1);
6879

69-
public static RouteDefinition newRoute(final String verb, final String path,
70-
final Router router) {
71-
return new RouteDefinitionImpl(verb, path, router);
72-
}
80+
private final int index = INDEX.incrementAndGet();
7381

74-
public static RouteDefinition newRoute(final String verb, final String path,
75-
final Filter filter) {
76-
return new RouteDefinitionImpl(verb, path, filter);
77-
}
82+
private String name = "route" + index;
7883

79-
}
84+
/**
85+
* A route pattern.
86+
*/
87+
private RoutePattern compiledPattern;
8088

8189
/**
82-
* @return A route pattern.
90+
* The target route.
8391
*/
84-
RoutePattern path();
92+
private Filter filter;
93+
94+
/**
95+
* Defines the media types that the methods of a resource class or can accept. Default is:
96+
* {@literal *}/{@literal *}.
97+
*/
98+
private List<MediaType> consumes = ALL;
99+
100+
/**
101+
* Defines the media types that the methods of a resource class or can produces. Default is:
102+
* {@literal *}/{@literal *}.
103+
*/
104+
private List<MediaType> produces = ALL;
105+
private String verb;
106+
107+
private String pattern;
108+
109+
/**
110+
* Creates a new {@link RouteDefinitionImpl}.
111+
*
112+
* @param verb A HTTP verb.
113+
* @param pattern
114+
* @param filter
115+
*/
116+
private RouteDefinition(final String verb, final String pattern, final Filter filter) {
117+
requireNonNull(verb, "A HTTP verb is required.");
118+
requireNonNull(pattern, "A route path is required.");
119+
requireNonNull(filter, "A filter is required.");
120+
121+
this.verb = verb;
122+
this.pattern = pattern;
123+
this.compiledPattern = new RoutePattern(verb, pattern);
124+
this.filter = filter;
125+
}
126+
127+
public String pattern() {
128+
return pattern;
129+
}
130+
131+
public Optional<Route> matches(final String verb, final String path, final MediaType contentType,
132+
final List<MediaType> accept) {
133+
RouteMatcher matcher = compiledPattern.matcher(verb.toUpperCase() + path);
134+
if (matcher.matches()) {
135+
List<MediaType> result = MediaType.matcher(accept).filter(this.produces);
136+
if (canConsume(contentType) && result.size() > 0) {
137+
// keep accept when */*
138+
List<MediaType> produces = result.size() == 1 && result.get(0).name().equals("*/*")
139+
? accept : this.produces;
140+
return Optional.of(asRoute(matcher, produces));
141+
}
142+
}
143+
return Optional.empty();
144+
}
85145

86-
int index();
146+
private Route asRoute(final RouteMatcher matcher, final List<MediaType> produces) {
147+
return new RouteImpl(filter, verb, matcher.path(), pattern, name, index, matcher.vars(), consumes,
148+
produces);
149+
}
87150

88-
String name();
151+
public String verb() {
152+
return verb;
153+
}
89154

90-
RouteDefinition name(String name);
155+
public int index() {
156+
return index;
157+
}
158+
159+
public String name() {
160+
return name;
161+
}
162+
163+
public RouteDefinition name(final String name) {
164+
this.name = requireNonNull(name, "A route's name is required.");
165+
return this;
166+
}
91167

92168
/**
93169
* @param candidate A media type to test.
94170
* @return True, if the route can consume the given media type.
95171
*/
96-
boolean canConsume(@Nonnull MediaType candidate);
172+
public boolean canConsume(@Nonnull final MediaType candidate) {
173+
return MediaType.matcher(Arrays.asList(candidate)).matches(consumes);
174+
}
97175

98176
/**
99177
* @param candidates A media types to test.
100178
* @return True, if the route can produces the given media type.
101179
*/
102-
boolean canProduce(List<MediaType> candidates);
180+
public boolean canProduce(final List<MediaType> candidates) {
181+
return MediaType.matcher(candidates).matches(produces);
182+
}
103183

104184
/**
105185
* Set the media types the route can consume.
106186
*
107187
* @param consumes The media types to test for.
108188
* @return This route definition.
109189
*/
110-
RouteDefinition consumes(MediaType... consumes);
190+
public RouteDefinition consumes(final MediaType... consumes) {
191+
return consumes(Arrays.asList(consumes));
192+
}
111193

112194
/**
113195
* Set the media types the route can consume.
114196
*
115197
* @param consumes The media types to test for.
116198
* @return This route definition.
117199
*/
118-
RouteDefinition consumes(Iterable<MediaType> consumes);
200+
public RouteDefinition consumes(final Iterable<MediaType> consumes) {
201+
this.consumes = Lists.newArrayList(consumes);
202+
Collections.sort(this.consumes);
203+
return this;
204+
}
119205

120206
/**
121207
* Set the media types the route can produces.
122208
*
123209
* @param produces The media types to test for.
124210
* @return This route definition.
125211
*/
126-
RouteDefinition produces(MediaType... produces);
212+
public RouteDefinition produces(final MediaType... produces) {
213+
return produces(Arrays.asList(produces));
214+
}
127215

128216
/**
129217
* Set the media types the route can produces.
130218
*
131219
* @param produces The media types to test for.
132220
* @return This route definition.
133221
*/
134-
RouteDefinition produces(Iterable<MediaType> produces);
222+
public RouteDefinition produces(final Iterable<MediaType> produces) {
223+
this.produces = Lists.newArrayList(produces);
224+
Collections.sort(this.produces);
225+
return this;
226+
}
135227

136228
/**
137229
* @return All the types this route can consumes.
138230
*/
139-
List<MediaType> consumes();
231+
public List<MediaType> consumes() {
232+
return ImmutableList.copyOf(this.consumes);
233+
}
140234

141235
/**
142236
* @return All the types this route can produces.
143237
*/
144-
List<MediaType> produces();
238+
public List<MediaType> produces() {
239+
return ImmutableList.copyOf(this.produces);
240+
}
241+
242+
public static RouteDefinition newRoute(final String verb, final String path,
243+
final Router router) {
244+
return new RouteDefinition(verb, path, (req, res, chain) -> {
245+
router.handle(req, res);
246+
chain.next(req, res);
247+
});
248+
}
249+
250+
public static RouteDefinition newRoute(final String verb, final String path,
251+
final Filter filter) {
252+
return new RouteDefinition(verb, path, filter);
253+
}
145254

146255
}

0 commit comments

Comments
 (0)