All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jetbrick.web.mvc.router.RestfulMatcher Maven / Gradle / Ivy

There is a newer version: 2.1.1
Show newest version
/**
 * Copyright 2013-2014 Guoqiang Chen, Shanghai, China. All rights reserved.
 *
 * Email: [email protected]
 * URL: http://subchen.github.io/
 *
 * 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 jetbrick.web.mvc.router;

import java.util.*;
import jetbrick.collections.SoftHashMap;
import jetbrick.collections.multimap.MultiValueHashMap;
import jetbrick.collections.multimap.MultiValueMap;
import jetbrick.lang.StringUtils;
import jetbrick.web.mvc.RouteInfo;
import jetbrick.web.mvc.action.ActionInfo;
import jetbrick.web.mvc.action.PathVariables;

/*
 * 

分组匹配算法

*
    *
  1. 按照 HttpMethod 分组
  2. *
  3. 按照静态/动态 URL 分组(cache)
  4. *
  5. 动态 URL 先按照 path 长度分组,再按照 group 分组
  6. *
*/ final class RestfulMatcher { private static final int MAX_PATH_PARTS = 20; private Map staticUrls = new HashMap(128); private Map cachedUrls = new SoftHashMap(256); private OneByOneMatcher[] matchers = new OneByOneMatcher[MAX_PATH_PARTS]; // 按照长度分组 public void register(ActionInfo action, String url) { if (url.indexOf('{') == -1) { staticUrls.put(url, new RouteInfo(action)); } else { String[] urlSegments = StringUtils.split(url.substring(1), '/'); if (urlSegments.length >= MAX_PATH_PARTS) { throw new IllegalStateException("exceed max url parts: " + url); } OneByOneMatcher matcher = matchers[urlSegments.length]; if (matcher == null) { matcher = new OneByOneMatcher(); matchers[urlSegments.length] = matcher; } matcher.register(action, urlSegments); } } public RouteInfo lookup(String url) { // 1. 查询静态路由 RouteInfo info = staticUrls.get(url); if (info != null) return info; // 2. 查询动态路由缓存 info = cachedUrls.get(url); if (info != null) { return info; } // 3. 开始执行动态路由匹配 (分组匹配) String[] urlSegments = StringUtils.split(url.substring(1), '/'); if (urlSegments.length >= MAX_PATH_PARTS) { throw new IllegalStateException("exceed max url parts: " + url); } OneByOneMatcher matcher = matchers[urlSegments.length]; if (matcher != null) { info = matcher.lookup(urlSegments); } // 4. 加入缓存 if (info == null) { info = RouteInfo.NOT_FOUND; } cachedUrls.put(url, info); // 5. 返回 return info; } // 动态路由匹配(逐个匹配) static final class OneByOneMatcher { private final MultiValueMap groups = new MultiValueHashMap(256); private final List ungroupList = new ArrayList(32); // 添加路由信息(按照 URL 前缀分组) public void register(ActionInfo action, String[] urlSegments) { String group = urlSegments[0]; if (group.indexOf('{') == -1) { groups.put(group, action); } else { ungroupList.add(action); } } public RouteInfo lookup(String[] urlSegments) { // 1. 先 new 出一个存放 URL PathVariables 的对象 PathVariables pathVariables = new PathVariables(); // 2. 分组查询 String group = urlSegments[0]; List actions = groups.getList(group); if (actions != null) { RouteInfo info = doLookup(actions, urlSegments, pathVariables); if (info != null) { return info; } } // 3. 查找未分组的内容 return doLookup(ungroupList, urlSegments, pathVariables); } private RouteInfo doLookup(List actions, String[] urlSegments, PathVariables pathVariables) { for (ActionInfo action : actions) { if (action.match(urlSegments, pathVariables)) { return new RouteInfo(action, pathVariables); } } return null; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy