1010import io .jooby .Router ;
1111
1212import java .util .Arrays ;
13- import java .util .Collections ;
1413import java .util .Map ;
1514import java .util .Objects ;
1615import java .util .concurrent .ConcurrentHashMap ;
@@ -31,24 +30,71 @@ class Chi implements RouteTree {
3130
3231 private static final int NODE_SIZE = ntCatchAll + 1 ;
3332
34- static final StaticRoute NO_MATCH = new StaticRoute (Collections .emptyMap ());
35-
3633 static final char ZERO_CHAR = (char ) 0 ;
3734 private MessageEncoder encoder ;
3835
39- static class StaticRoute {
40- private final Map <String , StaticRouterMatch > methods ;
36+ private interface MethodMatcher {
37+ StaticRouterMatch get (String method );
38+
39+ void put (String method , StaticRouterMatch route );
40+
41+ boolean matches (String method );
42+ }
43+
44+ private static class SingleMethodMatcher implements MethodMatcher {
45+ private String method ;
46+ private StaticRouterMatch route ;
47+
48+ @ Override public void put (String method , StaticRouterMatch route ) {
49+ this .method = method ;
50+ this .route = route ;
51+ }
52+
53+ @ Override public StaticRouterMatch get (String method ) {
54+ return this .method .equals (method ) ? route : null ;
55+ }
56+
57+ @ Override public boolean matches (String method ) {
58+ return this .method .equals (method );
59+ }
60+
61+ public void clear () {
62+ this .method = null ;
63+ this .route = null ;
64+ }
65+ }
66+
67+ private static class MultipleMethodMatcher implements MethodMatcher {
68+ private Map <String , StaticRouterMatch > methods = new ConcurrentHashMap <>();
4169
42- public StaticRoute (Map <String , StaticRouterMatch > methods ) {
43- this .methods = methods ;
70+ public MultipleMethodMatcher (SingleMethodMatcher matcher ) {
71+ methods .put (matcher .method , matcher .route );
72+ matcher .clear ();
4473 }
4574
46- public StaticRoute ( ) {
47- this ( newMap ( Router . METHODS . size ()) );
75+ @ Override public StaticRouterMatch get ( String method ) {
76+ return methods . get ( method );
4877 }
4978
79+ @ Override public void put (String method , StaticRouterMatch route ) {
80+ methods .put (method , route );
81+ }
82+
83+ @ Override public boolean matches (String method ) {
84+ return this .methods .containsKey (method );
85+ }
86+ }
87+
88+ static class StaticRoute {
89+ private MethodMatcher matcher ;
90+
5091 public void put (String method , Route route ) {
51- methods .put (method , new StaticRouterMatch (route ));
92+ if (matcher == null ) {
93+ matcher = new SingleMethodMatcher ();
94+ } else if (matcher instanceof SingleMethodMatcher ) {
95+ matcher = new MultipleMethodMatcher ((SingleMethodMatcher ) matcher );
96+ }
97+ matcher .put (method , new StaticRouterMatch (route ));
5298 }
5399 }
54100
@@ -555,7 +601,7 @@ Segment patNextSegment(String pattern) {
555601 int ws = pattern .indexOf ('*' );
556602
557603 if (ps < 0 && ws < 0 ) {
558- return new Segment (ntStatic , EMPTY_STRING , ( char ) 0 , 0 ,
604+ return new Segment (ntStatic , EMPTY_STRING , ZERO_CHAR , 0 ,
559605 pattern .length ()); // we return the entire thing
560606 }
561607
@@ -623,7 +669,7 @@ Segment patNextSegment(String pattern) {
623669 // EDIT: should we panic if there is stuff after the * ???
624670 // We allow naming a wildcard: *path
625671 //String key = ws == pattern.length() - 1 ? "*" : pattern.substring(ws + 1).toString();
626- return new Segment (ntCatchAll , EMPTY_STRING , ( char ) 0 , ws , pattern .length ());
672+ return new Segment (ntCatchAll , EMPTY_STRING , ZERO_CHAR , ws , pattern .length ());
627673 }
628674
629675 public void destroy () {
@@ -650,11 +696,7 @@ public void destroy() {
650696 private final Node root = new Node ();
651697
652698 /** Not need to use a concurrent map, due we don't allow to add routes after application started. */
653- private final Map <Object , StaticRoute > staticPaths = newMap (16 );
654-
655- static <K , V > Map <K , V > newMap (int size ) {
656- return new ConcurrentHashMap <>(size );
657- }
699+ private final Map <Object , StaticRoute > staticPaths = new ConcurrentHashMap <>();
658700
659701 public void insert (String method , String pattern , Route route ) {
660702 String baseCatchAll = baseCatchAll (pattern );
@@ -691,24 +733,27 @@ public void destroy() {
691733 }
692734
693735 public boolean exists (String method , String path ) {
694- if (!staticPaths .getOrDefault (path , NO_MATCH ).methods .containsKey (method )) {
695- return root .findRoute (new RouterMatch (), method , path ) != null ;
696- }
697- return true ;
736+ return find (method , path ) != null ;
698737 }
699738
700739 @ Override public Router .Match find (String method , String path ) {
701- StaticRouterMatch match = staticPaths .getOrDefault (path , NO_MATCH ).methods .get (method );
702- if (match == null ) {
703- // use radix tree
704- RouterMatch result = new RouterMatch ();
705- Route route = root .findRoute (result , method , path );
706- if (route == null ) {
707- return result .missing (method , path , encoder );
708- }
709- return result .found (route );
740+ StaticRoute staticRoute = staticPaths .get (path );
741+ if (staticRoute == null ) {
742+ return findInternal (method , path );
743+ } else {
744+ StaticRouterMatch match = staticRoute .matcher .get (method );
745+ return match == null ? findInternal (method , path ) : match ;
746+ }
747+ }
748+
749+ private Router .Match findInternal (String method , String path ) {
750+ // use radix tree
751+ RouterMatch result = new RouterMatch ();
752+ Route route = root .findRoute (result , method , path );
753+ if (route == null ) {
754+ return result .missing (method , path , encoder );
710755 }
711- return match ;
756+ return result . found ( route ) ;
712757 }
713758
714759 public void setEncoder (MessageEncoder encoder ) {
0 commit comments