/*
* Copyright 2007-2009 the original author or authors.
*
* 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 i 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 net.paoding.rose.web.impl.mapping;
import java.util.ArrayList;
import net.paoding.rose.web.RequestPath;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* {@link MappingNode}代表匹配树的一个结点,树的结点能够包含一个或多个被称为资源的 {@link EngineGroup} 对象
*
* @author 王志亮 [qieqie.wang@gmail.com]
*
*/
public class MappingNode implements Comparable<MappingNode> {
protected static final Log logger = LogFactory.getLog(MappingNode.class);
/** 所使用的映射 */
private final Mapping mapping;
/** 最左子结点 */
private MappingNode leftMostChild;
/** 右兄弟结点 */
private MappingNode sibling;
/** 子节点是变量参数映射的数目 */
private int ammountOfRegexChildren = -1;
/** 叶子引擎: 只有含有叶子引擎的结点才能处理对应地址的请求 */
private final EngineGroup leafEngines = new EngineGroupImpl();
/** 中间引擎: */
private final EngineGroup middleEngines = new EngineGroupImpl();
/**
*
* @param mapping
*/
public MappingNode(Mapping mapping) {
this.mapping = mapping;
this.mapping.setMappingNode(this);
}
public Mapping getMapping() {
return mapping;
}
public String getMappingPath() {
return this.mapping.getDefinition();
}
public MappingNode getLeftMostChild() {
return leftMostChild;
}
public MappingNode getSibling() {
return sibling;
}
public final boolean isLeaf() {
return leftMostChild == null;
}
public void linkAsChild(final MappingNode child) {
if (this.leftMostChild == null) {
this.leftMostChild = child;
} else {
MappingNode prev = null;
MappingNode position = this.leftMostChild;
while (true) {
if (position == null) {
prev.sibling = child;
break;
}
int c = child.getMapping().compareTo(position.getMapping());
if (c < 0) {
child.sibling = position;
if (prev == null) {
this.leftMostChild = child;
} else {
prev.sibling = child;
}
break;
} else {
prev = position;
position = position.sibling;
}
}
}
}
public MappingNode getChild(String mapping) {
MappingNode sibling = this.leftMostChild;
while (sibling != null) {
if (sibling.getMapping().getDefinition().equals(mapping)) {
return sibling;
} else {
sibling = sibling.sibling;
}
}
return null;
}
public EngineGroup getLeafEngines() {
return leafEngines;
}
public EngineGroup getMiddleEngines() {
return middleEngines;
}
public ArrayList<MatchResult> match(RequestPath requestPath) {
// 用来储存并返回的匹配结果集合
ArrayList<MatchResult> matchResults = new ArrayList<MatchResult>(16);
final boolean debugEnabled = logger.isDebugEnabled();
// 当前判断结点
MappingNode curNode = this;
// 给当前判断结点判断的path
String remaining = requestPath.getRosePath();
// 最后一次匹配结果
MatchResult last = null;
// 开始匹配,直至成功或失败
while (true) {
// 当前结点的匹配结果result: 如果能够匹配path成功,一定会返回一个非空的result
// 一旦result非空,这个请求只能在这个结点中处理了,不可能再由其它结点处理,
// 即,如果因为某些原因本结点无法处理此请求,可以直接得出结论:这个请求不能被处理了
last = curNode.getMapping().match(remaining);
if (last != null && /*只对常量匹配的作判断*/last.getParameterName() == null) {
// mapping是 /abc/efg,requestUri是 /abc123的不应该进入/abc分支,reset last为null
if (curNode.ammountOfRegexChildren < 0) {
// 这个if块里面的代码不用考虑同步,因此在并发下可能有若干、少数次的重复计算,不过对结果、性能没影响
curNode.ammountOfRegexChildren = countRegexChildren(curNode);
}
if (curNode.ammountOfRegexChildren == 0) {
if (remaining.length() > last.getValue().length()
&& remaining.charAt(last.getValue().length()) != '/') {
last = null;
}
}
}
// 当前结点打不赢
if (last == null) {
// 兄弟,你上!
if (curNode.sibling == null) {
if (debugEnabled) {
logger.debug("['" + requestPath.getRosePath() + "'] not matched");
}
return null;
}
curNode = curNode.sibling;
continue;
}
if (debugEnabled) {
logger.debug("['" + requestPath.getRosePath() + "'] matched(" //
+ (matchResults.size() + 1) + "): '" + last + "'");
}
// add to results for return
matchResults.add(last);
remaining = remaining.substring(last.getValue().length());
//
if (remaining.length() == 0) {
if (debugEnabled) {
logger.debug("['" + requestPath.getRosePath() + "'] matched over.");
}
return matchResults;
}
//
if (curNode.leftMostChild == null) {
if (debugEnabled) {
logger.debug("['" + requestPath.getRosePath() + "'] not matched");
}
return null;
}
curNode = curNode.leftMostChild;
}
}
private int countRegexChildren(MappingNode curNode) {
int ammountOfRegexChildren = 0;
MappingNode child = curNode.leftMostChild;
while (child != null) {
if (child.getMapping().getParameterName() != null) {
ammountOfRegexChildren++;
}
child = child.sibling;
}
return ammountOfRegexChildren;
}
@Override
public int compareTo(MappingNode target) {
return this.getMapping().compareTo(target.getMapping());
}
/**
*
*/
public void destroy() {
this.leafEngines.destroy();
MappingNode c = leftMostChild;
while (c != null) {
c.destroy();
c = c.sibling;
}
this.middleEngines.destroy();
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof MappingNode)) {
return false;
}
MappingNode target = (MappingNode) obj;
return this.compareTo(target) == 0;
}
@Override
public int hashCode() {
return getMapping().hashCode();
}
@Override
public String toString() {
return getMappingPath();
}
}