com.logicbus.backend.server.http.MessageRouterServletHandler Maven / Gradle / Ivy
package com.logicbus.backend.server.http;
import java.io.IOException;
import java.io.InputStream;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.alogic.matcher.CommonMatcher;
import com.alogic.matcher.MatcherFactory;
import com.anysoft.util.*;
import com.anysoft.util.resource.ResourceFactory;
import com.anysoft.webloader.HttpClientTool;
import com.google.re2j.Matcher;
import com.google.re2j.Pattern;
import com.logicbus.backend.IpAndServiceAccessController;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.anysoft.webloader.ServletConfigProperties;
import com.anysoft.webloader.ServletHandler;
import com.logicbus.backend.AccessController;
import com.logicbus.backend.DefaultNormalizer;
import com.logicbus.backend.Normalizer;
import com.logicbus.backend.server.MessageRouter;
import com.logicbus.models.catalog.Path;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
/**
* 基于anyWebLoader的ServletHandler
*
* @author duanyy
*
* @version 1.0.5 [20140412 duanyy]
* - 修改消息传递模型。
*
* @version 1.0.7 [20140418 duanyy]
* - 增加全局序列号功能,从Http头的GlobalSerial变量获取前端传入的全局序列号
*
* @version 1.2.1 [20140614 duanyy]
* - 支持跨域服务调用
*
* @version 1.2.6 [20140807 duanyy]
* - ServantPool和ServantFactory插件化
*
* @version 1.2.7.2 [20140910 duanyy]
* - Normalizer降级为Servlet级别对象
*
* @version 1.3.0.1 [20141031 duanyy]
* - 解决问题:框架截获了post方式的body数据,导致post过来的form数据无法获取
*
* @version 1.4.0 [20141117 duanyy]
* - 将MessageDoc和Context进行合并整合
*
* @version 1.6.1.2 [20141118 duanyy]
* - 支持HttpContext的数据截取,通过Servlet的变量intercept.mode来控制
*
* @version 1.6.3.28 [20150708 duanyy]
* - 允许设置为缓存模式
*
* @version 1.6.4.8 [20151013 duanyy]
* - CORS成了可选配置
*
* @version 1.6.5.6 [20160523 duanyy]
* - 在MessageRouter中提前写出报文
*
* @version 1.6.7.9 [20170201 duanyy]
* - 采用SLF4j日志框架输出日志
*
* @version 1.6.8.6 [20170410 duanyy]
* - 增加Options方法的实现
*
* @version 1.6.9.8 [20170821 duanyy]
* - 优化代码
*
* @version 1.6.11.12 [20170123 duanyy]
* - http响应的缓存属性改成由服务来个性化控制
*
* @version 1.6.12.8 [20181121 duanyy]
* - 关闭缺省的cors支持
*
* @version 1.6.12.11 [20181206 duanyy]
* - 可配置是否支持options方法
*
* @version 1.6.13.30 [20210106 duanyy]
* - CORS支持改为定向域名支持
*
* @version 1.6.13.31 [20210108 duanyy]
* - 支持对Origin中域名的解析
*
* @version 1.6.14.6 [20210415 duanyy]
* - 可通过配置文件进行配置
*/
public class MessageRouterServletHandler implements ServletHandler,XMLConfigurable, Configurable {
/**
* 访问控制器
*/
protected AccessController ac = null;
/**
* 路径标准化
*/
protected Normalizer normalizer = null;
/**
* 是否开启拦截模式
*/
protected boolean interceptMode = false;
/**
* a logger of log4j
*/
protected static Logger LOG = LoggerFactory.getLogger(MessageRouterServletHandler.class);
protected static final String DEFAULT = "java:///com/logicbus/backend/servant.entry.xml#" + MessageRouterServletHandler.class.getName();
/**
* 是否已经获取服务器信息
*/
protected static boolean getServerInfo = false;
/**
* 编码
*/
protected static String encoding = "utf-8";
protected String methodAllow = "GET,PUT,POST";
protected boolean corsSupport = false;
protected boolean optionSupport = true;
protected CommonMatcher corsMatcher = null;
protected HttpClientTool clientTool = null;
/**
* 用来提取Origin中域名的正则表达式
*/
protected static Pattern pattern = Pattern.compile("(\\w+):\\/\\/([^/:]+)(?::(\\d*))?([^#\\?]*)");
@Override
public void init(ServletConfig servletConfig) throws ServletException {
ServletConfigProperties props = new ServletConfigProperties(servletConfig);
String master = PropertiesConstants.getString(props, "servant.entry.master", DEFAULT);
String secondary = PropertiesConstants.getString(props, "servant.entry.secondary", DEFAULT);
ResourceFactory rf = Settings.getResourceFactory();
InputStream in = null;
try {
in = rf.load(master, secondary, null);
Document doc = XmlTools.loadFromInputStream(in);
if (doc != null){
configure(doc.getDocumentElement(), props);
}
}catch (Exception ex){
LOG.error("Can not init servant entry with file : " + master);
}finally{
IOTools.close(in);
}
}
@Override
public void configure(Properties props) {
encoding = PropertiesConstants.getString(props,"http.encoding", encoding);
corsSupport = PropertiesConstants.getBoolean(props, "http.cors", corsSupport);
optionSupport = PropertiesConstants.getBoolean(props, "http.option", optionSupport);
methodAllow = PropertiesConstants.getString(props, "http.method.allow", methodAllow);
interceptMode = PropertiesConstants.getBoolean(props, "intercept.mode", interceptMode);
corsMatcher = MatcherFactory.getMatcher(PropertiesConstants.getString(props,"http.cors.matcher","(wildcard)*"),props);
if (normalizer == null) {
String normalizerClass = PropertiesConstants.getString(props, "normalizer", DefaultNormalizer.class.getName());
LOG.info("Normalizer is initializing,module:" + normalizerClass);
try {
Normalizer.TheFactory ncf = new Normalizer.TheFactory(
Settings.getClassLoader());
normalizer = ncf.newInstance(normalizerClass, props);
} catch (Throwable t) {
normalizer = new DefaultNormalizer(props);
LOG.error("Failed to initialize Normalizer.Using default:"
+ DefaultNormalizer.class.getName());
}
}
clientTool = Settings.getToolkit(HttpClientTool.class);
if (ac == null) {
ac = (AccessController) Settings.get("accessController");
}
}
@Override
public void configure(Element e, Properties p) {
XmlElementProperties props = new XmlElementProperties(e,p);
Element elem = XmlTools.getFirstElementByPath(e,"normalizer");
if (elem != null){
try {
Normalizer.TheFactory ncf = new Normalizer.TheFactory(Settings.getClassLoader());
normalizer = ncf.newInstance(elem,props,"module",DefaultNormalizer.class.getName());
} catch (Throwable t) {
LOG.error("Failed to initialize Normalizer:" + XmlTools.node2String(elem));
LOG.error(ExceptionUtils.getStackTrace(t));
}
}
elem = XmlTools.getFirstElementByPath(e,"ac");
if (elem != null){
AccessController.TheFactory f = new AccessController.TheFactory();
try {
ac = f.newInstance(elem,props,"module", IpAndServiceAccessController.class.getName());
} catch (Throwable t) {
LOG.error("Failed to create access controller:" + XmlTools.node2String(elem));
LOG.error(ExceptionUtils.getStackTrace(t));
}
}
configure(props);
}
@Override
public void doService(HttpServletRequest request,
HttpServletResponse response, String method)
throws ServletException, IOException {
if (!getServerInfo){
Settings settings = Settings.get();
settings.SetValue("server.host", request.getLocalAddr());
settings.SetValue("server.port", String.valueOf(request.getLocalPort()));
LOG.info("Get server info:" + settings.GetValue("server.host", "") + ":" + settings.GetValue("server.port",""));
getServerInfo = true;
}
// 1.2.1 duanyy
// to support CORS
if (corsSupport){
String origin = request.getHeader("Origin");
if (StringUtils.isNotEmpty(origin) && corsMatcher != null){
Matcher matcher = pattern.matcher(origin);
String domain = origin;
if (matcher.find()){
domain = matcher.group(2);
}
if (corsMatcher.isMatch(domain)) {
clientTool.setResponseHeader(response,"Access-Control-Allow-Origin", origin);
clientTool.setResponseHeader(response,"Access-Control-Allow-Credentials", "true");
}
}
}
if (method.equals("options")){
if (optionSupport){
clientTool.setResponseHeader(response,"Allow", methodAllow);
}else{
clientTool.sendError(response,HttpServletResponse.SC_NOT_FOUND,"core.e1000:Method options is not supported now.");
}
}else{
HttpContext ctx = new HttpContext(request,response,encoding,interceptMode);
MessageRouter.action(normalizer,request,ctx,ac);
}
}
@Override
public void destroy() {
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy