Package org.cruxframework.crux.core.server.rest.core.registry

Source Code of org.cruxframework.crux.core.server.rest.core.registry.PathParamSegment$Group

/*
* Copyright 2011 cruxframework.org
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.cruxframework.crux.core.server.rest.core.registry;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.cruxframework.crux.core.server.rest.core.dispatch.ResourceMethod;
import org.cruxframework.crux.core.server.rest.spi.BadRequestException;
import org.cruxframework.crux.core.server.rest.spi.HttpRequest;
import org.cruxframework.crux.core.server.rest.spi.NotFoundException;
import org.cruxframework.crux.core.server.rest.spi.UriInfo;
import org.cruxframework.crux.core.server.rest.util.Encode;
import org.cruxframework.crux.core.server.rest.util.PathHelper;

/**
*
* @author Thiago da Rosa de Bustamante
*
*/
public class PathParamSegment extends Segment implements Comparable<PathParamSegment>
{
  protected String pathExpression;
  protected String regex;
  protected Pattern pattern;
  protected List<Group> groups = new ArrayList<Group>();
  protected int literalCharacters;
  protected int numCapturingGroups;
  protected int numNonDefaultGroups;

  private static class Group
  {
    int group;
    String name;

    private Group(int group, String name)
    {
      this.group = group;
      this.name = name;
    }
  }

  public int compareTo(PathParamSegment pathParamSegment)
  {
    // as per spec sort first by literal characters, then numCapturing
    // groups, then num non-default groups

    if (literalCharacters > pathParamSegment.literalCharacters)
      return -1;
    if (literalCharacters < pathParamSegment.literalCharacters)
      return 1;

    if (numCapturingGroups > pathParamSegment.numCapturingGroups)
      return -1;
    if (numCapturingGroups < pathParamSegment.numCapturingGroups)
      return 1;

    if (numNonDefaultGroups > pathParamSegment.numNonDefaultGroups)
      return -1;
    if (numNonDefaultGroups < pathParamSegment.numNonDefaultGroups)
      return 1;

    return 0;
  }

  // [^?] is in expression to ignore non-capturing group
  public static final Pattern GROUP = Pattern.compile("[^\\\\]\\([^?]");

  /**
   * Find the number of groups in the regular expression don't count escaped
   * '('
   *
   * @param regex
   * @return
   */
  private static int groupCount(String regex)
  {
    regex = " " + regex; // add a space because GROUP regex trans to match a
               // non-preceding slash.
    // if the grouping characters in the range block ignore them.
    int idxOpen = regex.indexOf('[');
    if (idxOpen != -1)
    {
      int idxClose = regex.indexOf(']', idxOpen);
      if (idxClose != -1)
      {
        regex = regex.substring(0, idxOpen) + regex.substring(idxClose + 1);
      }
    }
    Matcher matcher = GROUP.matcher(regex);
    int groupCount = 0;
    while (matcher.find())
      groupCount++;
    return groupCount;
  }

  public PathParamSegment(String segment)
  {
    this.pathExpression = segment;
    String replacedCurlySegment = PathHelper.replaceEnclosedCurlyBraces(segment);
    literalCharacters = PathHelper.URI_PARAM_PATTERN.matcher(replacedCurlySegment).replaceAll("").length();

    String[] split = PathHelper.URI_PARAM_PATTERN.split(replacedCurlySegment);
    Matcher withPathParam = PathHelper.URI_PARAM_PATTERN.matcher(replacedCurlySegment);
    int i = 0;
    StringBuffer buffer = new StringBuffer();
    if (i < split.length)
      buffer.append(Pattern.quote(split[i++]));
    int groupNumber = 1;

    while (withPathParam.find())
    {
      String name = withPathParam.group(1);
      buffer.append("(");
      if (withPathParam.group(3) == null)
      {
        buffer.append("[^/]+");
        groups.add(new Group(groupNumber++, name));
      }
      else
      {
        String expr = withPathParam.group(3);
        expr = PathHelper.recoverEnclosedCurlyBraces(expr);
        buffer.append(expr);
        numNonDefaultGroups++;
        groups.add(new Group(groupNumber++, name));
        groupNumber += groupCount(expr);
      }
      buffer.append(")");
      if (i < split.length)
        buffer.append(Pattern.quote(split[i++]));
    }
    regex = buffer.toString();
    pattern = Pattern.compile(regex);
    numCapturingGroups = groups.size();
  }

  public String getRegex()
  {
    return regex;
  }

  public String getPathExpression()
  {
    return pathExpression;
  }

  protected void populatePathParams(HttpRequest request, Matcher matcher, String path)
  {
    UriInfo uriInfo = (UriInfo) request.getUri();
    for (Group group : groups)
    {
      String value = matcher.group(group.group);
      uriInfo.addEncodedPathParameter(group.name, value);
      int index = matcher.start(group.group);

      int start = 0;
      if (path.charAt(0) == '/')
        start++;
      int segmentIndex = 0;

      if (start < path.length())
      {
        int count = 0;
        for (int i = start; i < index && i < path.length(); i++)
        {
          if (path.charAt(i) == '/')
            count++;
        }
        segmentIndex = count;
      }

      int numSegments = 1;
      for (int i = 0; i < value.length(); i++)
      {
        if (value.charAt(i) == '/')
          numSegments++;
      }

      if (segmentIndex + numSegments > request.getUri().getPathSegments().size())
      {

        throw new BadRequestException("Number of matched segments greater than actual", "Can not invoke requested service");
      }
      PathSegment[] encodedSegments = new PathSegment[numSegments];
      PathSegment[] decodedSegments = new PathSegment[numSegments];
      for (int i = 0; i < numSegments; i++)
      {
        decodedSegments[i] = request.getUri().getPathSegments().get(segmentIndex + i);
        encodedSegments[i] = request.getUri().getPathSegments(false).get(segmentIndex + i);
      }
      uriInfo.getEncodedPathParameterPathSegments().add(group.name, encodedSegments);
      uriInfo.getPathParameterPathSegments().add(group.name, decodedSegments);
    }
  }

  public ResourceMethod matchPattern(HttpRequest request, String path, int start)
  {
    UriInfo uriInfo = (UriInfo) request.getUri();
    Matcher matcher = pattern.matcher(path);
    matcher.region(start, path.length());

    if (matcher.matches())
    {
      // we consumed entire path string
      ResourceMethod invoker = match(request.getHttpMethod(), request);
      if (invoker == null)
      {
        throw new NotFoundException("Could not find resource for relative : " + path + " of full path: " + request.getUri().getRequestUri());
      }
      uriInfo.pushMatchedURI(path, Encode.decode(path));
      populatePathParams(request, matcher, path);
      return invoker;
    }
    throw new NotFoundException("Could not find resource for relative : " + path + " of full path: " + request.getUri().getRequestUri());
  }

  public static int pathSegmentIndex(String string, int start, int stop)
  {
    if (start >= string.length())
      return 0;
    int count = 0;
    for (int i = start; i < stop && i < string.length(); i++)
    {
      if (string.charAt(i) == '/')
        count++;
    }
    return count;
  }

}
TOP

Related Classes of org.cruxframework.crux.core.server.rest.core.registry.PathParamSegment$Group

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.