Example #1
0
 public Map<QualifiedName, String> next() {
   if (!hasNext()) {
     throw new NoSuchElementException();
   }
   Map<QualifiedName, String> parameters = next.getParameters();
   next = null;
   return parameters;
 }
Example #2
0
  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;
  }