/* * 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 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 net.paoding.rose.web.impl.mapping; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import net.paoding.rose.util.PrinteHelper; import net.paoding.rose.web.annotation.ReqMethod; import net.paoding.rose.web.impl.module.ControllerRef; import net.paoding.rose.web.impl.module.MethodRef; import net.paoding.rose.web.impl.module.Module; import net.paoding.rose.web.impl.thread.ActionEngine; import net.paoding.rose.web.impl.thread.ControllerEngine; import net.paoding.rose.web.impl.thread.Engine; import net.paoding.rose.web.impl.thread.LinkedEngine; import net.paoding.rose.web.impl.thread.ModuleEngine; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * * @author 王志亮 [qieqie.wang@gmail.com] * */ public class TreeBuilder { protected static final Log logger = LogFactory.getLog(TreeBuilder.class); /* * 构造一个树,树的结点是地址-资源映射,每个结点都能回答是否匹配一个字符串,每个匹配的节点都知道如何执行对该资源的操作. * 构造树的过程: * 识别组件==>求得他的资源定义==>判断是否已经创建了==>未创建的创建一个树结点==>已创建的找出这个结点 * ==>在这个资源增加相应的操作以及逻辑==>若是新建的结点把它加到树中,同时满足遍历、匹配顺序要求 */ public void create(MappingNode tree, List<Module> modules) { addRoot(tree, modules); check(tree, tree, ""); } private void addRoot(MappingNode rootNode, List<Module> modules) { for (Module module : modules) { addModule(rootNode, module); } } private void addModule(final MappingNode rootNode, Module module) { List<Mapping> terms = MappingFactory.parse(module.getMappingPath()); LinkedEngine rootEngine = rootNode.getMiddleEngines().getEngines(ReqMethod.GET)[0]; MappingNode parent = rootNode; for (Mapping mapping : terms) { if (mapping.getDefinition().length() == 0) { continue; } MappingNode temp = parent.getChild(mapping.getDefinition()); if (temp == null) { temp = new MappingNode(mapping); parent.linkAsChild(temp); } parent = temp; } LinkedEngine moduleEngine = new LinkedEngine(rootEngine, new ModuleEngine(module), parent); parent.getMiddleEngines().addEngine(ReqMethod.ALL, moduleEngine); // controllers List<ControllerRef> controllers = module.getControllers(); for (ControllerRef controller : controllers) { addController(module, parent, moduleEngine, controller); } } private void addController(Module module, MappingNode moduleNode, LinkedEngine moduleEngine, ControllerRef controller) { // Engine engine = new ControllerEngine(module, controller); Set<String> mappingPaths = new HashSet<String>(Arrays.asList(controller.getMappingPaths())); for (String mappingPath : mappingPaths) { List<Mapping> mappings = MappingFactory.parse(mappingPath); // MappingNode target = moduleNode; for (Mapping mapping : mappings) { if (mapping.getDefinition().length() == 0) { continue; } MappingNode temp = target.getChild(mapping.getDefinition()); if (temp == null) { temp = new MappingNode(mapping); target.linkAsChild(temp); } target = temp; } LinkedEngine controllerEngine = new LinkedEngine(moduleEngine, engine, target); target.getMiddleEngines().addEngine(ReqMethod.ALL, controllerEngine); // // actions MethodRef[] actions = controller.getActions(); for (MethodRef action : actions) { addAction(module, controller, action, target, controllerEngine); } } } private void addAction(Module module, ControllerRef controller, MethodRef action, MappingNode controllerNode, LinkedEngine controllerEngine) { Map<String, Set<ReqMethod>> mappingPaths = action.getMappings(); if (mappingPaths.size() == 0) { return; } Engine actionEngine = new ActionEngine(module, controller.getControllerClass(),// controller.getControllerObject(), action.getMethod()); for (String mappingPath : mappingPaths.keySet()) { List<Mapping> mappings = MappingFactory.parse(mappingPath); MappingNode target = controllerNode; for (Mapping mapping : mappings) { if (mapping.getDefinition().length() == 0) { continue; } MappingNode temp = target.getChild(mapping.getDefinition()); if (temp == null) { temp = new MappingNode(mapping); target.linkAsChild(temp); } target = temp; } // for (ReqMethod method : mappingPaths.get(mappingPath)) { LinkedEngine linkedActionEngine = new LinkedEngine(// controllerEngine, actionEngine, target); target.getLeafEngines().addEngine(method, linkedActionEngine); } } } /** * 检查整个树的状况,尽可能报告可能存在的问题 * * @param tree * @param parent * @param prefix */ private void check(MappingNode tree, MappingNode parent, String prefix) { MappingNode child = parent.getLeftMostChild(); MappingNode sibling = null; while (child != null) { if (sibling != null) { if (child.compareTo(sibling) == 0) { logger.error("mapping conflicts: '" + child.getMapping().getDefinition() + "' conflicts with '" + sibling.getMapping().getDefinition() + "' in '" + prefix + "'; here is the mapping tree, " + "you can find the conflict in it:\n" + PrinteHelper.list(tree)); throw new IllegalArgumentException("mapping conflicts: '" + child.getMapping().getDefinition() + "' conflicts with '" + sibling.getMapping().getDefinition() + "' in '" + prefix + "'"); } } check(tree, child, prefix + child.getMapping().getDefinition()); sibling = child; child = child.getSibling(); } } }