001 package com.khubla.pragmatach.framework.router; 002 003 import java.net.URLDecoder; 004 import java.util.LinkedHashMap; 005 import java.util.List; 006 007 import com.khubla.pragmatach.framework.annotation.Route; 008 import com.khubla.pragmatach.framework.annotation.RouteParameter; 009 import com.khubla.pragmatach.framework.api.PragmatachException; 010 import com.khubla.pragmatach.framework.api.Request; 011 import com.khubla.pragmatach.framework.url.RouteSpecificationSegment; 012 import com.khubla.pragmatach.framework.url.URICracker; 013 014 /** 015 * @author tome 016 */ 017 public class RouteFinder { 018 /** 019 * check that the static parts of the route match 020 */ 021 private static boolean staticPartsMatch(PragmatachRoute pragmatachRoute, String[] crackedURI) throws PragmatachException { 022 try { 023 /* 024 * check that the static path parts match 025 */ 026 int j = 0; 027 for (final RouteSpecificationSegment routeSpecificationSegment : pragmatachRoute.getRouteSpecification().getSegments()) { 028 final String staticPathPart = routeSpecificationSegment.getPath(); 029 if (null != staticPathPart) { 030 if (false == (crackedURI[j].compareTo(staticPathPart) == 0)) { 031 return false; 032 } 033 } 034 j++; 035 } 036 return true; 037 } catch (final Exception e) { 038 throw new PragmatachException("Exception in staticPartsMatch", e); 039 } 040 } 041 042 /** 043 * check that the static parts of wildcard route match 044 */ 045 private static boolean staticWildcardPartsMatch(PragmatachRoute pragmatachRoute, String[] crackedURI) throws PragmatachException { 046 try { 047 /* 048 * check that the static path parts match 049 */ 050 final List<RouteSpecificationSegment> routeSpecificationSegments = pragmatachRoute.getRouteSpecification().getSegments(); 051 for (int i = 0; i < (routeSpecificationSegments.size() - 1); i++) { 052 final RouteSpecificationSegment routeSpecificationSegment = routeSpecificationSegments.get(i); 053 final String staticPathPart = routeSpecificationSegment.getPath(); 054 if (null != staticPathPart) { 055 if (false == (crackedURI[i].compareTo(staticPathPart) == 0)) { 056 return false; 057 } 058 } 059 } 060 return true; 061 } catch (final Exception e) { 062 throw new PragmatachException("Exception in staticPartsMatch", e); 063 } 064 } 065 066 /** 067 * the method parameters. key is the id specified in the routespecification, value is the value passed in the uri 068 */ 069 private LinkedHashMap<String, String> parameterMap; 070 /** 071 * the route 072 */ 073 private PragmatachRoute pragmatachRoute; 074 075 /** 076 * get the parameter map that the URI actually means 077 */ 078 private LinkedHashMap<String, String> buildParameterMap(PragmatachRoute pragmatachRoute, String[] crackedURI) throws PragmatachException { 079 try { 080 /* 081 * the ret 082 */ 083 final LinkedHashMap<String, String> ret = new LinkedHashMap<String, String>(); 084 /* 085 * check if wildcard 086 */ 087 if (false == pragmatachRoute.isWildcardRoute()) { 088 /* 089 * walk the route specification 090 */ 091 int i = 0; 092 for (final RouteSpecificationSegment routeSpecificationSegment : pragmatachRoute.getRouteSpecification().getSegments()) { 093 final String id = routeSpecificationSegment.getVariableId(); 094 if ((null != id) && (id.length() > 0)) { 095 /* 096 * URL decode the parameter 097 */ 098 final String decodedParameter = URLDecoder.decode(crackedURI[i], "UTF-8"); 099 /* 100 * set the parameter 101 */ 102 ret.put(id, decodedParameter); 103 } 104 i++; 105 } 106 } else { 107 /* 108 * hacky, but it works 109 */ 110 for (int i = pragmatachRoute.getSegmentCount() - 1; i < crackedURI.length; i++) { 111 ret.put(crackedURI[i], crackedURI[i]); 112 } 113 } 114 return ret; 115 } catch (final Exception e) { 116 throw new PragmatachException("Exception in getParameters", e); 117 } 118 } 119 120 /** 121 * get the appropriate routes to search. These routes are already ordered. 122 */ 123 private List<PragmatachRoute> getMethodRoutes(Route.HttpMethod httpMethod) throws PragmatachException { 124 if (httpMethod == Route.HttpMethod.get) { 125 return PragmatachRoutes.getInstance().getGETRoutes(); 126 } else { 127 return PragmatachRoutes.getInstance().getPOSTRoutes(); 128 } 129 } 130 131 public LinkedHashMap<String, String> getParameterMap() { 132 return parameterMap; 133 } 134 135 public PragmatachRoute getPragmatachRoute() { 136 return pragmatachRoute; 137 } 138 139 /** 140 * Match route. Returns true if a matching route was found. 141 * <p> 142 * 143 * <pre> 144 * There are multiple criteria for matching. 145 * 1 - Every part of the URI must match the name or regex 146 * 2 - Values must be provided for each method signature variable 147 * </pre> 148 * <p> 149 */ 150 public boolean match(Request request) throws PragmatachException { 151 try { 152 /* 153 * crack the URI 154 */ 155 final String[] crackedURI = URICracker.crackURI(request.getResourcePath()); 156 /* 157 * get the routes 158 */ 159 final List<PragmatachRoute> pragmatachRoutes = getMethodRoutes(request.getMethod()); 160 if (null != pragmatachRoutes) { 161 /* 162 * check for matching regexs 163 */ 164 for (final PragmatachRoute pragmatachRoute : pragmatachRoutes) { 165 /* 166 * route is a regex match at each segment 167 */ 168 if (matchesRouteSpecification(pragmatachRoute, crackedURI)) { 169 /* 170 * build parameter map 171 */ 172 parameterMap = buildParameterMap(pragmatachRoute, crackedURI); 173 /* 174 * remember the matched controller 175 */ 176 this.pragmatachRoute = pragmatachRoute; 177 /* 178 * return true to indicate a match 179 */ 180 return true; 181 } 182 } 183 } 184 /* 185 * no match 186 */ 187 return false; 188 } catch (final Exception e) { 189 throw new PragmatachException("Exception in match", e); 190 } 191 } 192 193 /** 194 * check that the number of segments matches and that each segment matches the regex, if there is one 195 */ 196 private boolean matchesRouteSpecification(PragmatachRoute pragmatachRoute, String[] crackedURI) throws PragmatachException { 197 try { 198 if (false == pragmatachRoute.isWildcardRoute()) { 199 /* 200 * there is a uri? 201 */ 202 if (null != crackedURI) { 203 /* 204 * # of segments passed matches the route specification number of segments? 205 */ 206 if (crackedURI.length == pragmatachRoute.getSegmentCount()) { 207 /* 208 * walk the route annotations 209 */ 210 int i = 0; 211 final List<RouteParameter> routeParameters = pragmatachRoute.getBoundRouteParameters(); 212 if ((null != routeParameters) && (routeParameters.size() > 0)) { 213 for (final RouteParameter routeParameter : routeParameters) { 214 /* 215 * check regex 216 */ 217 final String regex = routeParameter.regex(); 218 if ((null != regex) && (regex.length() > 0)) { 219 if (false == crackedURI[i].matches(regex)) { 220 return false; 221 } 222 } 223 i++; 224 } 225 } 226 /* 227 * check that the static path parts match 228 */ 229 if (false == staticPartsMatch(pragmatachRoute, crackedURI)) { 230 return false; 231 } 232 /* 233 * everything matches 234 */ 235 return true; 236 } else { 237 /* 238 * its not a match 239 */ 240 return false; 241 } 242 } else { 243 if ((0 == pragmatachRoute.getParameterCount()) && (0 == pragmatachRoute.getSegmentCount())) { 244 /* 245 * no parameters; its a match if the static parts match 246 */ 247 return staticPartsMatch(pragmatachRoute, crackedURI); 248 } else { 249 /* 250 * the route requires parameters, and none were passed 251 */ 252 return false; 253 } 254 } 255 } else { 256 /* 257 * check that the static path parts match 258 */ 259 if (false == staticWildcardPartsMatch(pragmatachRoute, crackedURI)) { 260 return false; 261 } 262 /* 263 * matches 264 */ 265 return true; 266 } 267 } catch (final Exception e) { 268 throw new PragmatachException("Exception in matchesRouteSpecification", e); 269 } 270 } 271 }