Skip to content

Commit 0c2379e

Browse files
committed
fix issue: cannot add route contains dynamic part when route with same dynamic part exists already
1 parent 38ffd72 commit 0c2379e

6 files changed

Lines changed: 80 additions & 38 deletions

File tree

src/main/java/act/Act.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import act.handler.builtin.controller.impl.ReflectedHandlerInvoker;
1616
import act.plugin.AppServicePluginManager;
1717
import act.plugin.GenericPluginManager;
18+
import act.plugin.Plugin;
1819
import act.plugin.PluginScanner;
1920
import act.util.*;
2021
import act.view.ViewManager;
@@ -29,6 +30,7 @@
2930
import org.osgl.util.E;
3031

3132
import java.util.List;
33+
import java.util.Map;
3234

3335
/**
3436
* The Act server
@@ -110,6 +112,7 @@ public static Mode valueOfIgnoreCase(String mode) {
110112
private static GenericPluginManager pluginManager;
111113
private static AppServicePluginManager appPluginManager;
112114
private static IdGenerator idGenerator = new IdGenerator();
115+
private static Map<String, Plugin> genericPluginRegistry = C.newMap();
113116

114117
public static List<Class<?>> pluginClasses() {
115118
ClassLoader cl = Act.class.getClassLoader();
@@ -179,6 +182,15 @@ public static AppManager applicationManager() {
179182
return appManager;
180183
}
181184

185+
public static void registerPlugin(Plugin plugin) {
186+
genericPluginRegistry.put(plugin.getClass().getCanonicalName().intern(), plugin);
187+
}
188+
189+
@SuppressWarnings("unchecked")
190+
public static <T extends Plugin> T registeredPlugin(Class<T> type) {
191+
return (T)genericPluginRegistry.get(type.getCanonicalName().intern());
192+
}
193+
182194
public static void startServer() {
183195
start(false, null);
184196
}

src/main/java/act/app/CliContext.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ public void print(String template, Object ... args) {
175175
}
176176

177177
private void print1(String template, Object ... args) {
178-
pw.printf(template, args);
178+
pw.printf(osNative(template), args);
179179
}
180180

181181
private void println0(String template, Object... args) {
@@ -195,7 +195,7 @@ public void println(String template, Object... args) {
195195
}
196196

197197
private void println1(String template, Object... args) {
198-
pw.printf(template, args);
198+
pw.printf(osNative(template), args);
199199
pw.println();
200200
}
201201

@@ -351,4 +351,14 @@ public static CliContext current() {
351351
return _local.get();
352352
}
353353

354+
private static String osNative(String s) {
355+
s = s.replace("\n\r", "\n");
356+
s = s.replace("\r", "\n");
357+
if ("\n".equals($.OS.lineSeparator())) {
358+
return s;
359+
}
360+
s = s.replace("\n", $.OS.lineSeparator());
361+
return s;
362+
}
363+
354364
}

src/main/java/act/db/DbPlugin.java

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,7 @@ public int hashCode() {
2525

2626
@Override
2727
public boolean equals(Object obj) {
28-
if (obj == this) {
29-
return true;
30-
}
31-
if (null == obj) {
32-
return false;
33-
}
34-
return getClass() == obj.getClass();
28+
return obj == this || null != obj && getClass() == obj.getClass();
3529
}
3630

3731
public abstract DbService initDbService(String id, App app, Map<String, Object> conf);

src/main/java/act/route/Router.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -542,8 +542,11 @@ Node addChild(StrBase<?> name) {
542542
}
543543
Node child = new Node(name, this);
544544
if (child.isDynamic()) {
545-
E.unexpectedIf(null != dynamicChild, "Cannot have more than one dynamic node in the route tree: %s", name);
546-
dynamicChild = child;
545+
//E.unexpectedIf(null != dynamicChild, "Cannot have more than one dynamic node in the route tree: %s", name);
546+
if (null == dynamicChild) {
547+
dynamicChild = child;
548+
}
549+
return dynamicChild;
547550
} else {
548551
staticChildren.put(name, child);
549552
}

src/main/java/act/util/AnnotatedTypeFinder.java

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import act.app.AppByteCodeScannerBase;
77
import act.app.AppSourceCodeScanner;
88
import org.osgl.$;
9+
import org.osgl.util.C;
910
import org.osgl.util.E;
1011
import org.osgl.util.FastStr;
1112

@@ -17,16 +18,14 @@
1718
public abstract class AnnotatedTypeFinder extends AppCodeScannerPluginBase {
1819

1920
private $.Func2<App, String, Map<Class<? extends AppByteCodeScanner>, Set<String>>> foundHandler;
20-
private String clsName;
21-
private String pkgName;
2221
private Class<? extends Annotation> annoType;
2322
private boolean noAbstract;
2423
private boolean publicOnly;
24+
private App app;
25+
protected Set<String> foundClasses = C.newSet();
2526

2627
protected AnnotatedTypeFinder(boolean publicOnly, boolean noAbstract, Class<? extends Annotation> annoType, $.Func2<App, String, Map<Class<? extends AppByteCodeScanner>, Set<String>>> foundHandler) {
2728
E.NPE(annoType, foundHandler);
28-
this.clsName = annoType.getSimpleName();
29-
this.pkgName = FastStr.of(annoType.getName()).beforeLast('.').toString();
3029
this.annoType = annoType;
3130
this.foundHandler = foundHandler;
3231
this.noAbstract = noAbstract;
@@ -37,13 +36,22 @@ protected AnnotatedTypeFinder(Class<? extends Annotation> annoType, $.Func2<App,
3736
this(true, true, annoType, foundHandler);
3837
}
3938

39+
protected AnnotatedTypeFinder(Class<? extends Annotation> annoType) {
40+
this(true, true, annoType, null);
41+
}
42+
43+
protected App app() {
44+
return app;
45+
}
46+
4047
@Override
4148
public AppSourceCodeScanner createAppSourceCodeScanner(App app) {
4249
return null;
4350
}
4451

4552
@Override
4653
public AppByteCodeScanner createAppByteCodeScanner(App app) {
54+
this.app = app;
4755
return new ByteCodeSensor();
4856
}
4957

@@ -75,7 +83,9 @@ public ByteCodeVisitor byteCodeVisitor() {
7583
@Override
7684
public void scanFinished(String className) {
7785
if (detector.found()) {
78-
Map<Class<? extends AppByteCodeScanner>, Set<String>> dependencies = foundHandler.apply(app(), className);
86+
foundClasses.add(className);
87+
Map<Class<? extends AppByteCodeScanner>, Set<String>> dependencies =
88+
null == foundHandler ? null : foundHandler.apply(app(), className);
7989
if (null != dependencies && !dependencies.isEmpty()) {
8090
for (Class<? extends AppByteCodeScanner> c : dependencies.keySet()) {
8191
addDependencyClassToScanner(c, dependencies.get(c));

src/test/java/act/route/RouterTest.java

Lines changed: 35 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import static act.route.RouteSource.ACTION_ANNOTATION;
1919
import static act.route.RouteSource.ROUTE_TABLE;
20+
import static org.osgl.http.H.Method.GET;
2021

2122
public class RouterTest extends RouterTestBase {
2223
private RequestHandler staticDirHandler;
@@ -33,21 +34,21 @@ public void prepare() {
3334

3435
@Test
3536
public void testMappingAdded() {
36-
no(router.isMapped(H.Method.GET, "/foo"));
37-
router.addMapping(H.Method.GET, "/foo", "Foo.bar");
38-
yes(router.isMapped(H.Method.GET, "/foo"));
37+
no(router.isMapped(GET, "/foo"));
38+
router.addMapping(GET, "/foo", "Foo.bar");
39+
yes(router.isMapped(GET, "/foo"));
3940
}
4041

4142
@Test
4243
public void searchRoot() {
43-
router.addMapping(H.Method.GET, "/", controller);
44-
router.getInvoker(H.Method.GET, "/", ctx).handle(ctx);
44+
router.addMapping(GET, "/", controller);
45+
router.getInvoker(GET, "/", ctx).handle(ctx);
4546
controllerInvoked();
4647
}
4748

4849
@Test(expected = NotFound.class)
4950
public void searchBadUrl() {
50-
router.getInvoker(H.Method.GET, "/nonexists", ctx);
51+
router.getInvoker(GET, "/nonexists", ctx);
5152
}
5253

5354
@Test
@@ -59,24 +60,24 @@ public void searchStaticUrl() {
5960

6061
@Test
6162
public void searchDynamicUrl() {
62-
router.addMapping(H.Method.GET, "/svc/{<[0-9]{4}>id}", controller);
63-
router.getInvoker(H.Method.GET, "/svc/1234/", ctx).handle(ctx);
63+
router.addMapping(GET, "/svc/{<[0-9]{4}>id}", controller);
64+
router.getInvoker(GET, "/svc/1234/", ctx).handle(ctx);
6465
controllerInvoked();
6566
Mockito.verify(ctx).param("id", "1234");
6667
}
6768

6869
@Test
6970
public void searchPartialUrl() {
70-
router.addMapping(H.Method.GET, "/public", staticDirHandler);
71-
router.getInvoker(H.Method.GET, "/public/foo/bar.txt", ctx).handle(ctx);
71+
router.addMapping(GET, "/public", staticDirHandler);
72+
router.getInvoker(GET, "/public/foo/bar.txt", ctx).handle(ctx);
7273
Mockito.verify(staticDirHandler).handle(ctx);
7374
Mockito.verify(ctx).param(ParamNames.PATH, "/foo/bar.txt");
7475
}
7576

7677
@Test
7778
public void routeWithStaticDir() {
78-
router.addMapping(H.Method.GET, "/public", "file:/public");
79-
RequestHandler handler = router.getInvoker(H.Method.GET, "/public/foo/bar.txt", ctx);
79+
router.addMapping(GET, "/public", "file:/public");
80+
RequestHandler handler = router.getInvoker(GET, "/public/foo/bar.txt", ctx);
8081
yes(handler instanceof StaticFileGetter);
8182
yes(handler.supportPartialPath());
8283
eq(new File(BASE, "/public"), fieldVal(handler, "base"));
@@ -85,8 +86,8 @@ public void routeWithStaticDir() {
8586
@Test
8687
public void overrideExistingRouting() {
8788
routeWithStaticDir();
88-
router.addMapping(H.Method.GET, "/public", "file:/private");
89-
RequestHandler handler = router.getInvoker(H.Method.GET, "/public/foo/bar.txt", ctx);
89+
router.addMapping(GET, "/public", "file:/private");
90+
RequestHandler handler = router.getInvoker(GET, "/public/foo/bar.txt", ctx);
9091
yes(handler instanceof StaticFileGetter);
9192
yes(handler.supportPartialPath());
9293
eq(new File(BASE, "/private"), fieldVal(handler, "base"));
@@ -95,8 +96,8 @@ public void overrideExistingRouting() {
9596
@Test
9697
public void doNotOverrideExistingRouting() {
9798
routeWithStaticDir();
98-
router.addMapping(H.Method.GET, "/public", "file:/private", ACTION_ANNOTATION);
99-
RequestHandler handler = router.getInvoker(H.Method.GET, "/public/foo/bar.txt", ctx);
99+
router.addMapping(GET, "/public", "file:/private", ACTION_ANNOTATION);
100+
RequestHandler handler = router.getInvoker(GET, "/public/foo/bar.txt", ctx);
100101
yes(handler instanceof StaticFileGetter);
101102
yes(handler.supportPartialPath());
102103
eq(new File(BASE, "/public"), fieldVal(handler, "base"));
@@ -111,30 +112,30 @@ public void senseControllerMethodWithControllerPackage() {
111112
Mockito.when(app.config()).thenReturn(appConfig);
112113
router = new Router(controllerLookup, app);
113114

114-
router.addMapping(H.Method.GET, "/foo", "Controller.foo");
115+
router.addMapping(GET, "/foo", "Controller.foo");
115116
yes(router.isActionMethod("foo.controller.Controller", "foo"));
116117

117-
router.addMapping(H.Method.GET, "/bar", "com.newcontroller.Controller.bar");
118+
router.addMapping(GET, "/bar", "com.newcontroller.Controller.bar");
118119
yes(router.isActionMethod("com.newcontroller.Controller", "bar"));
119120
}
120121

121122
@Test
122123
public void senseControllerMethodWithoutControllerPackage() {
123-
router.addMapping(H.Method.GET, "/foo", "Controller.foo");
124+
router.addMapping(GET, "/foo", "Controller.foo");
124125
no(router.isActionMethod("foo.controller.Controller", "foo"));
125126
yes(router.isActionMethod("Controller", "foo"));
126127

127-
router.addMapping(H.Method.GET, "/bar", "com.newcontroller.Controller.bar");
128+
router.addMapping(GET, "/bar", "com.newcontroller.Controller.bar");
128129
yes(router.isActionMethod("com.newcontroller.Controller", "bar"));
129130
}
130131

131132
@Test
132133
public void itShallNotOverwriteRouteMappingWithSameRouteSource() {
133134
for (RouteSource source : RouteSource.values()) {
134135
router = new Router(controllerLookup, app);
135-
router.addMapping(H.Method.GET, "/foo", "Controller.foo", source);
136+
router.addMapping(GET, "/foo", "Controller.foo", source);
136137
try {
137-
router.addMapping(H.Method.GET, "/foo", "Foo.bar", source);
138+
router.addMapping(GET, "/foo", "Foo.bar", source);
138139
if (source != ROUTE_TABLE) {
139140
fail("expected DuplicateRouteMappingException");
140141
}
@@ -144,4 +145,16 @@ public void itShallNotOverwriteRouteMappingWithSameRouteSource() {
144145
}
145146
}
146147

148+
@Test
149+
public void testAddingTwoRoutesWithSameDynamicPart() {
150+
router.addMapping(GET, "/foo/{id}", "Controller.foo");
151+
router.addMapping(GET, "/foo/{id}/bar", "Foo.bar");
152+
}
153+
154+
@Test(expected = DuplicateRouteMappingException.class)
155+
public void itShallNotAllowAddingHandlersToSameRouteEndingWithDynamicPart() {
156+
router.addMapping(GET, "/foo/{id}", "Controller.foo", RouteSource.ACTION_ANNOTATION);
157+
router.addMapping(GET, "/foo/{id}", "Foo.bar", RouteSource.ACTION_ANNOTATION);
158+
}
159+
147160
}

0 commit comments

Comments
 (0)