Ejemplo n.º 1
0
  /**
   * 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;
    }
  }