public Map<QualifiedName, String> next() { if (!hasNext()) { throw new NoSuchElementException(); } Map<QualifiedName, String> parameters = next.getParameters(); next = null; return parameters; }
private static RouteFrame route(RouteFrame root, Map<String, String[]> requestParams) { RouteFrame current = root; // if (root.status == RouteFrame.Status.MATCHED) { if (root.parent != null) { current = root.parent; } else { return null; } } else if (root.status != RouteFrame.Status.BEGIN) { throw new AssertionError("Unexpected status " + root.status); } // while (true) { if (current.status == RouteFrame.Status.BEGIN) { boolean matched = true; // We enter a frame for (RequestParam requestParamDef : current.route.requestParamArray) { String value = null; String[] values = requestParams.get(requestParamDef.matchName); if (values != null && values.length > 0 && values[0] != null) { value = values[0]; } if (value == null) { switch (requestParamDef.controlMode) { case OPTIONAL: // Do nothing break; case REQUIRED: matched = false; break; } } else if (!requestParamDef.matchValue(value)) { matched = false; break; } switch (requestParamDef.valueMapping) { case CANONICAL: break; case NEVER_EMPTY: if (value != null && value.length() == 0) { value = null; } break; case NEVER_NULL: if (value == null) { value = ""; } break; } if (value != null) { if (current.matches == null) { current.matches = new HashMap<QualifiedName, String>(); } current.matches.put(requestParamDef.name, value); } } // if (matched) { // We enter next state current.status = RouteFrame.Status.MATCHED_PARAMS; } else { current.status = RouteFrame.Status.END; } } else if (current.status == RouteFrame.Status.MATCHED_PARAMS) { RouteFrame.Status next; // Anything that does not begin with '/' returns null if (current.path.length() > 0 && current.path.charAt(0) == '/') { // The '/' means the current controller if any, otherwise it may be processed by the // pattern matching if (current.path.length() == 1 && current.route.terminal) { next = RouteFrame.Status.MATCHED; } else { next = RouteFrame.Status.PROCESS_CHILDREN; } } else { next = RouteFrame.Status.END; } // current.status = next; } else if (current.status == RouteFrame.Status.PROCESS_CHILDREN) { if (current.childIndex < current.route.children.length) { Route child = current.route.children[current.childIndex++]; // The next frame RouteFrame next; // if (child instanceof SegmentRoute) { SegmentRoute segmentRoute = (SegmentRoute) child; // if (segmentRoute.name.length() == 0) { // Delegate the process to the next route next = new RouteFrame(current, segmentRoute, current.path); } else { // Find the next '/' for determining the segment and next path // JULIEN : this can be computed multiple times int pos = current.path.indexOf('/', 1); if (pos == -1) { pos = current.path.length(); } String segment = current.path.getValue().substring(1, pos); // Determine next path if (segmentRoute.name.equals(segment)) { // Lazy create next segment path // JULIEN : this can be computed multiple times Path nextSegmentPath; if (pos == current.path.length()) { // todo make a constant nextSegmentPath = Path.SLASH; } else { nextSegmentPath = current.path.subPath(pos); } // Delegate the process to the next route next = new RouteFrame(current, segmentRoute, nextSegmentPath); } else { next = null; } } } else if (child instanceof PatternRoute) { PatternRoute patternRoute = (PatternRoute) child; // Regex.Match[] matches = patternRoute.pattern.matcher().find(current.path.getValue()); // We match if (matches.length > 0) { // Build next controller context int nextPos = matches[0].getEnd(); Path nextPath; if (current.path.length() == nextPos) { nextPath = Path.SLASH; } else { if (nextPos > 0 && current.path.charAt(nextPos - 1) == '/') { nextPos--; } // nextPath = current.path.subPath(nextPos); } // Delegate to next patternRoute next = new RouteFrame(current, patternRoute, nextPath); // JULIEN : this can be done lazily // Append parameters int index = 1; for (int i = 0; i < patternRoute.params.length; i++) { PathParam param = patternRoute.params[i]; for (int j = 0; j < param.matchingRegex.length; j++) { Regex.Match match = matches[index + j]; if (match.getEnd() != -1) { String value; if (param.encodingMode == EncodingMode.FORM) { StringBuilder sb = new StringBuilder(); for (int from = match.getStart(); from < match.getEnd(); from++) { char c = current.path.charAt(from); if (c == child.router.separatorEscape && current.path.getRawLength(from) == 1) { c = '/'; } sb.append(c); } value = sb.toString(); } else { value = match.getValue(); } if (next.matches == null) { next.matches = new HashMap<QualifiedName, String>(); } next.matches.put(param.name, value); break; } else { // It can be the match of a particular disjunction // or an optional parameter } } index += param.matchingRegex.length; } } else { next = null; } } else { throw new AssertionError(); } // if (next != null) { current = next; } } else { current.status = RouteFrame.Status.END; } } else if (current.status == RouteFrame.Status.MATCHED) { // We found a solution break; } else if (current.status == RouteFrame.Status.END) { if (current.parent != null) { current = current.parent; } else { // The end of the search break; } } else { throw new AssertionError(); } } // return current; }