final <R extends Route> R add(R route) throws MalformedRouteException { if (route == null) { throw new NullPointerException("No null route accepted"); } if (((Route) route).parent != null) { throw new IllegalArgumentException("No route with an existing parent can be accepted"); } // LinkedList<Param> ancestorParams = new LinkedList<Param>(); findAncestorOrSelfParams(ancestorParams); LinkedList<Param> descendantParams = new LinkedList<Param>(); for (Param param : ancestorParams) { ((Route) route).findDescendantOrSelfParams(param.name, descendantParams); if (descendantParams.size() > 0) { throw new MalformedRouteException("Duplicate parameter " + param.name); } } // if (route instanceof PatternRoute || route instanceof SegmentRoute) { children = Tools.appendTo(children, route); terminal = false; ((Route) route).parent = this; } else { throw new IllegalArgumentException("Only accept segment or pattern routes"); } // return route; }
private Param findParam(QualifiedName name) { Param param = getParam(name); if (param == null && parent != null) { param = parent.findParam(name); } return param; }
final Route append(RouteDescriptor descriptor) throws MalformedRouteException { Route route = append(descriptor.getPathParams(), descriptor.getPath()); // for (RouteParamDescriptor routeParamDesc : descriptor.getRouteParams()) { route.add(RouteParam.create(routeParamDesc)); } // for (RequestParamDescriptor requestParamDesc : descriptor.getRequestParams()) { route.add(RequestParam.create(requestParamDesc, router)); } // for (RouteDescriptor childDescriptor : descriptor.getChildren()) { route.append(childDescriptor); } // return route; }
/** * Append a path, creates the necessary routes and returns the last route added. * * @param pathParamDescriptors the path param descriptors * @param path the path to append * @return the last route added */ private Route append(Map<QualifiedName, PathParamDescriptor> pathParamDescriptors, String path) throws MalformedRouteException { if (path.length() == 0 || path.charAt(0) != '/') { throw new MalformedRouteException(); } // int pos = path.length(); int level = 0; List<Integer> start = new ArrayList<Integer>(); List<Integer> end = new ArrayList<Integer>(); for (int i = 1; i < path.length(); i++) { char c = path.charAt(i); if (c == '{') { if (level++ == 0) { start.add(i); } } else if (c == '}') { if (--level == 0) { end.add(i); } } else if (c == '/') { if (level == 0) { pos = i; break; } } } // Route next; if (start.isEmpty()) { String segment = path.substring(1, pos); SegmentRoute route = new SegmentRoute(router, segment); add(route); next = route; } else { if (start.size() == end.size()) { PatternBuilder builder = new PatternBuilder(); builder.expr("^").expr('/'); List<String> chunks = new ArrayList<String>(); List<PathParam> parameterPatterns = new ArrayList<PathParam>(); // int previous = 1; for (int i = 0; i < start.size(); i++) { builder.litteral(path, previous, start.get(i)); chunks.add(path.substring(previous, start.get(i))); String parameterName = path.substring(start.get(i) + 1, end.get(i)); // QualifiedName parameterQName = QualifiedName.parse(parameterName); // Now get path param metadata PathParamDescriptor parameterDescriptor = pathParamDescriptors.get(parameterQName); // PathParam param; if (parameterDescriptor != null) { param = PathParam.create(parameterDescriptor, router); } else { param = PathParam.create(parameterQName, router); } // Append routing regex to the route regex surrounded by a non capturing regex // to isolate routingRegex like a|b or a(.)b builder.expr("(?:").expr(param.routingRegex).expr(")"); // Add the path param with the rendering regex parameterPatterns.add(param); previous = end.get(i) + 1; } // builder.litteral(path, previous, pos); // We want to satisfy one of the following conditions // - the next char after the matched expression is '/' // - the expression matched until the end // - the match expression is the '/' expression builder.expr("(?:(?<=^/)|(?=/)|$)"); // chunks.add(path.substring(previous, pos)); PatternRoute route = new PatternRoute(router, router.compile(builder.build()), parameterPatterns, chunks); // Wire add(route); // next = route; } else { throw new UnsupportedOperationException("Report error"); } } // if (pos < path.length()) { return next.append(pathParamDescriptors, path.substring(pos)); } else { return next; } }
private RouteMatch _find(RenderContext context) { // Match first the static parameteters for (RouteParam param : routeParamArray) { RenderContext.Parameter entry = context.getParameter(param.name); if (entry != null && !entry.isMatched() && param.value.equals(entry.getValue())) { entry.remove(entry.getValue()); } else { return null; } } // Match any request parameter for (RequestParam requestParamDef : requestParamArray) { RenderContext.Parameter entry = context.getParameter(requestParamDef.name); boolean matched = false; if (entry != null && !entry.isMatched()) { if (requestParamDef.matchPattern == null || context.matcher(requestParamDef.matchPattern).matches(entry.getValue())) { matched = true; } } if (matched) { entry.remove(entry.getValue()); } else { switch (requestParamDef.controlMode) { case OPTIONAL: // Do nothing break; case REQUIRED: return null; default: throw new AssertionError(); } } } // Match any pattern parameter if (this instanceof PatternRoute) { PatternRoute prt = (PatternRoute) this; for (int i = 0; i < prt.params.length; i++) { PathParam param = prt.params[i]; RenderContext.Parameter s = context.getParameter(param.name); String matched = null; if (s != null && !s.isMatched()) { switch (param.encodingMode) { case FORM: case PRESERVE_PATH: for (int j = 0; j < param.matchingRegex.length; j++) { Regex renderingRegex = param.matchingRegex[j]; if (context.matcher(renderingRegex).matches(s.getValue())) { matched = param.templatePrefixes[j] + s.getValue() + param.templateSuffixes[j]; break; } } break; default: throw new AssertionError(); } } if (matched != null) { s.remove(matched); } else { return null; } } } // if (context.isEmpty() && terminal) { Map<QualifiedName, String> matches = Collections.emptyMap(); for (QualifiedName name : context.getNames()) { RenderContext.Parameter parameter = context.getParameter(name); if (matches.isEmpty()) { matches = new HashMap<QualifiedName, String>(); } String match = parameter.getMatch(); matches.put(name, match); } return new RouteMatch(context, this, matches); } // for (Route route : children) { RouteMatch a = route.find(context); if (a != null) { return a; } } // return null; }
private void findAncestorOrSelfParams(List<Param> params) { findParams(params); if (parent != null) { parent.findAncestorOrSelfParams(params); } }