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

org.xson.web.xml.XMLPluginBuilder Maven / Gradle / Ivy

Go to download

xco-web is an easy to use control layer framework, is part of the SOA system, using xml language to describe the controller.

The newest version!
package org.xson.web.xml;

import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.log4j.Logger;
import org.xson.web.Container;
import org.xson.web.RequestContext;
import org.xson.web.XcoWebException;
import org.xson.web.cache.vo.CacheUseVo;
import org.xson.web.cache.vo.CacheVo;
import org.xson.web.util.StringUtils;
import org.xson.web.xml.InterceptVo.InterceptType;

public class XMLPluginBuilder {

	private Logger			logger			= Logger.getLogger(XMLPluginBuilder.class);
	private XPathParser		parser			= null;
	private XmlNodeWrapper	root			= null;
	private BuilderContext	bc				= null;

	// 引用标志
	private String			refMark			= "@";
	private String			urlSeparator	= "/";
	private String			leftBrackets	= "{";
	private String			rightBrackets	= "}";

	public XMLPluginBuilder(InputStream inputStream, BuilderContext bc) {
		this.bc = bc;
		this.parser = new XPathParser(inputStream);
		this.root = this.parser.evalNode("/web-controller");
	}

	public void parseBeanNode() {
		try {
			buildBeanNode(this.root.evalNodes("bean"));
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	public void parseInterceptNode() {
		try {
			buildInterceptNode(this.root.evalNodes("assembly"), InterceptType.ASSEMBLY);
			buildInterceptNode(this.root.evalNodes("before"), InterceptType.BEFORE);
			buildInterceptNode(this.root.evalNodes("after"), InterceptType.AFTER);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	public void parseControllerNode() {
		try {
			buildControllerNode(this.root.evalNodes("c"));
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	private void buildBeanNode(List contexts) throws Exception {
		// 
		for (XmlNodeWrapper context : contexts) {
			String id = StringUtils.trim(context.getStringAttribute("id"));
			String clazz = StringUtils.trim(context.getStringAttribute("class"));
			if (this.bc.getBeanIdMap().containsKey(id)) {
				throw new RuntimeException("Duplicate Bean: " + id);
			}
			Object obj = this.bc.getBeanClassMap().get(clazz);
			if (null == obj) {
				obj = Class.forName(clazz).newInstance();
				this.bc.getBeanClassMap().put(clazz, obj);
			}
			this.bc.getBeanIdMap().put(id, obj);
			logger.info("Add  :" + clazz);
		}
	}

	private void buildInterceptNode(List contexts, InterceptType type) throws Exception {
		for (XmlNodeWrapper context : contexts) {

			String call = StringUtils.trim(context.getStringAttribute("call"));
			String _order = StringUtils.trim(context.getStringAttribute("order"));

			if (InterceptType.ASSEMBLY == type) {
				if (this.bc.getBeforeMap().containsKey(call)) {
					throw new RuntimeException("Duplicate Assembly: " + call);
				}
			} else if (InterceptType.BEFORE == type) {
				if (this.bc.getBeforeMap().containsKey(call)) {
					throw new RuntimeException("Duplicate Before: " + call);
				}
			} else {
				if (this.bc.getAfterMap().containsKey(call)) {
					throw new RuntimeException("Duplicate After: " + call);
				}
			}

			MethodObject mo = getMethodObject(call);

			int order = Container.getInstance().getOrder();
			if (null != _order) {
				order = Integer.parseInt(_order);
			}

			List includeList = new ArrayList();
			List excludeList = new ArrayList();

			// 
			List includeNodes = context.evalNodes("include");
			for (XmlNodeWrapper include : includeNodes) {
				String body = StringUtils.trim(include.getStringBody());
				if (null != body) {
					includeList.add(body);
				}
			}
			if (includeList.size() == 0) {
				includeList = null;
			}

			// 
			List excludeNodes = context.evalNodes("exclude");
			for (XmlNodeWrapper exclude : excludeNodes) {
				String body = StringUtils.trim(exclude.getStringBody());
				if (null != body) {
					excludeList.add(body);
				}
			}
			if (excludeList.size() == 0) {
				excludeList = null;
			}

			if (null == includeList && null == excludeList) {
				throw new RuntimeException("Intercept missing : " + call);
			}

			InterceptVo baVo = new InterceptVo(mo, order, includeList, excludeList);

			if (InterceptType.ASSEMBLY == type) {
				this.bc.getAssemblyList().add(baVo);
				this.bc.getAssemblyMap().put(call, call);
			} else if (InterceptType.BEFORE == type) {
				this.bc.getBeforeList().add(baVo);
				this.bc.getBeforeMap().put(call, call);
			} else {
				this.bc.getAfterList().add(baVo);
				this.bc.getAfterMap().put(call, call);
			}

		}
	}

	private void buildControllerNode(List contexts) throws Exception {
		for (XmlNodeWrapper context : contexts) {
			// 基于安全考虑, 不能支持*,
			String url = StringUtils.trim(context.getStringAttribute("url"));
			if (this.bc.getControllerMap().containsKey(url)) {
				throw new RuntimeException("Duplicate URL: " + url);
			}
			String transfer = StringUtils.trim(context.getStringAttribute("transfer"));
			if (null != transfer) {
				transfer = parseTransfer(transfer, url);
			}
			String validate = StringUtils.trim(context.getStringAttribute("validate"));
			if (null != validate) {
				validate = parseValidate(validate, url);
			}

			String exec = StringUtils.trim(context.getStringAttribute("exec"));
			MethodObject execMethod = null;
			if (null != exec) {
				execMethod = getMethodObject(exec);
			}

			if (null == transfer && null == execMethod) {
				throw new RuntimeException("transfer and exec can not be empty, url: " + url);
			}

			// 权限
			String permission = StringUtils.trim(context.getStringAttribute("permission"));

			// 缓存
			String _cacheUse = StringUtils.trim(context.getStringAttribute("cache"));
			CacheUseVo cacheUse = null;
			if (null != _cacheUse && _cacheUse.length() > 0) {
				cacheUse = parseCacheUse(_cacheUse, url);
			}

			// 私有的assembly
			List assemblyList = new ArrayList();
			List assemblyNodes = context.evalNodes("assembly");
			for (XmlNodeWrapper node : assemblyNodes) {
				String call = StringUtils.trim(node.getStringAttribute("call"));
				String _order = StringUtils.trim(node.getStringAttribute("order"));
				MethodObject mo = getMethodObject(call);
				int order = Container.getInstance().getOrder();
				if (null != _order) {
					order = Integer.parseInt(_order);
				}
				InterceptVo baVo = new InterceptVo(mo, order);
				assemblyList.add(baVo);
			}

			// 私有的before
			List beforeList = new ArrayList();
			List beforeNodes = context.evalNodes("before");
			for (XmlNodeWrapper node : beforeNodes) {
				String call = StringUtils.trim(node.getStringAttribute("call"));
				String _order = StringUtils.trim(node.getStringAttribute("order"));
				MethodObject mo = getMethodObject(call);
				int order = Container.getInstance().getOrder();
				if (null != _order) {
					order = Integer.parseInt(_order);
				}
				InterceptVo baVo = new InterceptVo(mo, order);
				beforeList.add(baVo);
			}

			// 私有的after
			List afterList = new ArrayList();
			List afterNodes = context.evalNodes("after");
			for (XmlNodeWrapper node : afterNodes) {
				String call = StringUtils.trim(node.getStringAttribute("call"));
				String _order = StringUtils.trim(node.getStringAttribute("order"));
				MethodObject mo = getMethodObject(call);
				int order = Container.getInstance().getOrder();
				if (null != _order) {
					order = Integer.parseInt(_order);
				}
				InterceptVo baVo = new InterceptVo(mo, order);
				afterList.add(baVo);
			}

			ControllerVo cVo = new ControllerVo(url, transfer, validate, execMethod, getInterceptList(url, assemblyList, InterceptType.ASSEMBLY),
					getInterceptList(url, beforeList, InterceptType.BEFORE), getInterceptList(url, afterList, InterceptType.AFTER), permission,
					cacheUse);

			this.bc.getControllerMap().put(cVo.getUrl(), cVo);
			logger.info("Add  :" + cVo.getUrl());
		}
	}

	private MethodObject getMethodObject(String str) throws Exception {
		MethodObject mo = null;
		// a.b
		// if (str.startsWith(refMark)) {
		if (str.startsWith(leftBrackets)) {
			String[] array = str.split("\\.");
			if (array.length != 2) {
				throw new RuntimeException("Invalid bean reference: " + str);
			}
			// String beanId = array[0].substring(1);
			String beanId = array[0].substring(1, array[0].length() - 1);
			String methodName = array[1];

			Object bean = this.bc.getBeanIdMap().get(beanId);
			if (null == bean) {
				throw new RuntimeException("Reference bean does not exist: " + beanId);
			}
			String moKey = bean.getClass().getName() + "." + methodName;
			mo = this.bc.getMoMap().get(moKey);
			if (null == mo) {
				Method method = bean.getClass().getMethod(methodName, RequestContext.class);
				// 如果方法不存在或者参数类型不匹配,这里会抛出异常
				method.setAccessible(true);
				mo = new MethodObject(method, bean);
				this.bc.getMoMap().put(moKey, mo);
			}
		} else {
			mo = this.bc.getMoMap().get(str);
			if (null != mo) {
				return mo;
			}
			int pos = str.lastIndexOf(".");
			String className = str.substring(1, pos);
			String methodName = str.substring(pos + 1, str.length());

			Object instance = this.bc.getBeanClassMap().get(className);
			Class clazz = null;
			if (null == instance) {
				clazz = Class.forName(className);
				instance = clazz.newInstance();
				this.bc.getBeanClassMap().put(className, instance);
			} else {
				clazz = instance.getClass();
			}
			Method method = clazz.getMethod(methodName, RequestContext.class);
			// 如果方法不存在或者参数类型不匹配,这里会抛出异常
			method.setAccessible(true);
			mo = new MethodObject(method, instance);
			this.bc.getMoMap().put(str, mo);
		}
		return mo;
	}

	/**
	 * URL合并
	 */
	private String urlMerge(String domain, String path) {
		if (domain.endsWith(urlSeparator) && path.startsWith(urlSeparator)) {
			return domain + path.substring(1);
		} else if (domain.endsWith(urlSeparator) || path.startsWith(urlSeparator)) {
			return domain + path;
		} else {
			return domain + urlSeparator + path;
		}
	}

	private String parseTransfer(String transfer, String url) {
		// 第一种情况: {xxx}/@
		String regex = "\\{.*\\}/@";
		Pattern pattern = Pattern.compile(regex);
		Matcher matcher = pattern.matcher(transfer);
		if (matcher.matches()) {
			int pos = transfer.indexOf(rightBrackets);
			String domainRef = transfer.substring(1, pos);
			String domain = this.bc.getDomainMap().get(domainRef);
			if (null == domain) {
				// TODO: 完善
				throw new RuntimeException("域名引用错误: " + transfer);
			}
			return urlMerge(domain, url);
		}
		// 第二种情况: {xxx}/axx/bxx
		if (transfer.startsWith(leftBrackets)) {
			int pos = transfer.indexOf(rightBrackets);
			String domainRef = transfer.substring(1, pos);
			String domain = this.bc.getDomainMap().get(domainRef);
			if (null == domain) {
				// TODO: 完善
				throw new RuntimeException("域名引用错误: " + transfer);
			}
			String path = transfer.substring(pos + 1);
			return urlMerge(domain, path);
		}
		// 第三种情况: 完全手写
		return transfer;
	}

	private String parseValidate(String validate, String url) {
		if (refMark.equals(validate)) {
			String validateKey = url;
			if (validateKey.startsWith(urlSeparator)) {
				validateKey = validateKey.substring(1);
			}
			// if (validateKey.endsWith(urlSeparator)) {
			//
			// }
			return validateKey;
		}
		return validate;
	}

	private List getInterceptList(String url, List list, InterceptType type) {
		List result = null;
		List matchList = new ArrayList();
		// 全局的
		List globalList = null;

		if (InterceptType.ASSEMBLY == type) {
			globalList = this.bc.getAssemblyList();
		} else if (InterceptType.BEFORE == type) {
			globalList = this.bc.getBeforeList();
		} else {
			globalList = this.bc.getAfterList();
		}

		for (InterceptVo baVo : globalList) {
			if (baVo.match(url)) {
				matchList.add(baVo);
			}
		}
		if (list.size() > 0) {
			matchList.addAll(list);
		}

		if (matchList.size() > 0) {
			Collections.sort(matchList);// sort
			result = new ArrayList();
			for (InterceptVo baVo : matchList) {
				result.add(baVo.getMo());
			}
		}

		return result;
	}

	/**
	 * 解析: ID:xxx; key:xxx; time:1000; ignore:a,b
* 最短cache="@" * */ private CacheUseVo parseCacheUse(String cacheUse, String url) { CacheUseVo cacheUseVo = null; String[] array = cacheUse.split(";"); if (array.length > 0) { if (array.length == 1 && (-1 == array[0].indexOf("key:"))) { // 特殊情况 CacheVo cacheVo = this.bc.getDefaultCacheVo(); if (null == cacheVo) { throw new XcoWebException("未匹配的cache.id: " + cacheUse); } return new CacheUseVo(cacheVo, cacheUse, null, null, url); } Map map = new HashMap(); for (int i = 0; i < array.length; i++) { String[] item = array[i].split(":"); map.put(item[0].trim().toUpperCase(), item[1].trim()); } CacheVo cacheVo = null; if (map.containsKey("id".toUpperCase())) { cacheVo = this.bc.getCacheVoMap().get(map.get("id".toUpperCase())); } else { cacheVo = this.bc.getDefaultCacheVo(); } if (null == cacheVo) { throw new XcoWebException("未匹配的cache.id: " + cacheUse); } String key = map.get("key".toUpperCase()); if (null == key) { throw new XcoWebException("不存在的cache.key: " + cacheUse); } // TODO: 可用expire代替 Integer time = null; if (map.containsKey("time".toUpperCase())) { time = Integer.parseInt(map.get("time".toUpperCase())); } String[] ignore = null; // if (map.containsKey("ignore".toUpperCase())) { // ignore = map.get("ignore".toUpperCase()).split(","); // } cacheUseVo = new CacheUseVo(cacheVo, key, time, ignore, url); } return cacheUseVo; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy