first commit
This commit is contained in:
@@ -0,0 +1,292 @@
|
||||
/*
|
||||
* 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙,邂逅框架梦]
|
||||
*
|
||||
* 知启蒙WEB容器(zhiqim_httpd)在LGPL3.0协议下开源:https://www.zhiqim.com/gitcan/zhiqim/zhiqim_httpd.htm
|
||||
*
|
||||
* This file is part of [zhiqim_httpd].
|
||||
*
|
||||
* [zhiqim_httpd] is free software: you can redistribute
|
||||
* it and/or modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* [zhiqim_httpd] is distributed in the hope that it will
|
||||
* be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with [zhiqim_httpd].
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.zhiqim.httpd;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.zhiqim.httpd.bio.HttpBioListener;
|
||||
import org.zhiqim.httpd.bio.HttpBioSslListener;
|
||||
import org.zhiqim.httpd.nio.HttpNioListener;
|
||||
import org.zhiqim.httpd.nio.HttpNioSslListener;
|
||||
import org.zhiqim.kernel.Global;
|
||||
import org.zhiqim.kernel.Servicer;
|
||||
import org.zhiqim.kernel.config.Group;
|
||||
import org.zhiqim.kernel.extend.HashSetS;
|
||||
import org.zhiqim.kernel.logging.Log;
|
||||
import org.zhiqim.kernel.logging.LogFactory;
|
||||
import org.zhiqim.kernel.util.Arrays;
|
||||
import org.zhiqim.kernel.util.Asserts;
|
||||
import org.zhiqim.kernel.util.Classes;
|
||||
import org.zhiqim.kernel.util.Validates;
|
||||
|
||||
/**
|
||||
* HTTP多例服务,负责启动和关闭: <br><br>
|
||||
* 1、初始化AIO/BIO/NIO监听服务<br>
|
||||
* 2、加载和配置上下文环境 <br>
|
||||
*
|
||||
* @version v1.0.0 @author zouzhigang 2014-3-21 新建与整理
|
||||
*/
|
||||
public class HttpServer extends Servicer implements HttpdConstants
|
||||
{
|
||||
private static final Log log = LogFactory.getLog(HttpServer.class);
|
||||
|
||||
private boolean isRunning; //是否运行
|
||||
private HttpListener listener; //HTTP监听器
|
||||
private final List<HttpContext> contextList; //HTTP上下文环境表
|
||||
|
||||
/*********************************************************************************/
|
||||
//配置创建HTTP服务
|
||||
/*********************************************************************************/
|
||||
|
||||
public HttpServer()
|
||||
{
|
||||
this.contextList = new ArrayList<>();
|
||||
}
|
||||
|
||||
public boolean isRunning()
|
||||
{
|
||||
return isRunning;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean create() throws Exception
|
||||
{
|
||||
//1.诊断参数
|
||||
Group group = Global.getGroup(id);
|
||||
Asserts.as(group != null?null:"HTTP服务[%s]未找到整个配置组", id);
|
||||
log.info("初始化[HTTP服务:%s]开始...", id);
|
||||
|
||||
//2、初始化上下文环境
|
||||
String contexts = group.getString(_SERVER_CONTEXT_);
|
||||
Asserts.as(Validates.isNotEmptyBlank(contexts)?null:"HTTP服务["+id+"]未找到[context]配置项");
|
||||
|
||||
//3、初始化监听器
|
||||
String scheme = group.getString(_LISTEN_SCHEME_, _HTTP_);
|
||||
String io = group.getString(_LISTEN_IO_, _BIO_);
|
||||
if (_HTTPS_.equalsIgnoreCase(scheme))
|
||||
{
|
||||
if (_NIO_.equalsIgnoreCase(io))
|
||||
listener = new HttpNioSslListener(this);
|
||||
else
|
||||
listener = new HttpBioSslListener(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_NIO_.equalsIgnoreCase(io))
|
||||
listener = new HttpNioListener(this);
|
||||
else
|
||||
listener = new HttpBioListener(this);
|
||||
}
|
||||
|
||||
listener.setGroup(group);
|
||||
listener.open();
|
||||
|
||||
//4、初始化上下文环境
|
||||
String[] contextArr = Arrays.toStringArray(contexts);
|
||||
for (String contextId : contextArr)
|
||||
{
|
||||
Group cGroup = Global.getGroup(contextId);
|
||||
Asserts.as(cGroup != null?null:"HTTP服务["+id+"]未找到context["+contextId+"]配置项");
|
||||
|
||||
String contextClass = cGroup.getString(_CONTEXT_CLASS_, _HTTP_CONTEXT_CLASS_);
|
||||
Object obj = Classes.newInstance(contextClass);
|
||||
Asserts.as((obj instanceof HttpContext)?null:"HTTP服务["+id+"]context["+contextId+"]的[class]配置项未实现HttpContext接口");
|
||||
|
||||
HttpContext context = (HttpContext)obj;
|
||||
context.setServer(this);
|
||||
if (!context.create(cGroup))
|
||||
return false;
|
||||
|
||||
contextList.add(context);
|
||||
}
|
||||
|
||||
isRunning = true;
|
||||
|
||||
log.info("初始化[HTTP服务:%s]"+this.listener.toString()+"完成!!!%s", id, _BR_);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() throws Exception
|
||||
{
|
||||
isRunning = false;
|
||||
if (listener != null)
|
||||
{
|
||||
listener.close();
|
||||
listener = null;
|
||||
}
|
||||
|
||||
for (HttpContext context : contextList)
|
||||
{
|
||||
if (context.isRunning())
|
||||
context.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************************************/
|
||||
//手动创建服务 设置三个参数 domain & host & encoding 和 设置 listen & context 再setRunning()
|
||||
/***************************************************************************************************/
|
||||
|
||||
public void setRunning()
|
||||
{
|
||||
this.isRunning = true;
|
||||
}
|
||||
|
||||
public void addContext(HttpContext context)
|
||||
{
|
||||
//检查是否有相同的配置
|
||||
context.setServer(this);
|
||||
chkContextDomainPath(context.getContextDomains(), context.getContextPath());
|
||||
|
||||
//通过后放置到列表中
|
||||
contextList.add(context);
|
||||
}
|
||||
|
||||
public void removeContext(HttpContext context)
|
||||
{
|
||||
try
|
||||
{
|
||||
context.destroy();
|
||||
contextList.remove(context);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
log.error("移除上下文环境时异常", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeContext(String contextId)
|
||||
{
|
||||
HttpContext context = getContext(contextId);
|
||||
if (context == null)
|
||||
return;
|
||||
|
||||
removeContext(context);
|
||||
}
|
||||
|
||||
/** 检查域名和路径是否存在相同的配置 */
|
||||
public void chkContextDomainPath(HashSetS domains, String path)
|
||||
{
|
||||
if (domains.isEmpty())
|
||||
{//未配置域名
|
||||
for (HttpContext ctx : contextList)
|
||||
{
|
||||
if (!ctx.getContextDomains().isEmpty())
|
||||
continue;
|
||||
|
||||
if (!ctx.getContextPath().equals(path))
|
||||
continue;
|
||||
|
||||
throw Asserts.exception("存在相同的上下文环境配置[%s]", ctx.getContextPath());
|
||||
}
|
||||
}
|
||||
else
|
||||
{//有配置域名
|
||||
for (HttpContext ctx : contextList)
|
||||
{
|
||||
HashSetS ds = ctx.getContextDomains();
|
||||
if (ds.isEmpty())
|
||||
continue;
|
||||
|
||||
if (!ctx.getContextPath().equals(path))
|
||||
continue;
|
||||
|
||||
for (String d : domains.instance())
|
||||
{
|
||||
if (!ds.contains(d))
|
||||
continue;
|
||||
|
||||
//只要有一个成立则表示有相同
|
||||
throw Asserts.exception("存在相同的上下文环境配置[%s][%s]", d, ctx.getContextPath());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************************/
|
||||
//获取 & 配对 listen, context, scheme, port, domain, host, encoding
|
||||
/*********************************************************************************/
|
||||
|
||||
public HttpListener getListener()
|
||||
{
|
||||
return listener;
|
||||
}
|
||||
|
||||
public List<HttpContext> getContextList()
|
||||
{
|
||||
return contextList;
|
||||
}
|
||||
|
||||
public HttpContext getContext(String contextId)
|
||||
{
|
||||
Asserts.as(contextId != null?null:"上下文环境路径不能为空");
|
||||
|
||||
for (HttpContext context : contextList)
|
||||
{
|
||||
if (contextId.equals(context.getId()))
|
||||
return context;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public HttpContext getContext(String contextDomain, String contextPath)
|
||||
{
|
||||
Asserts.as(contextPath != null?null:"上下文环境路径不能为空");
|
||||
|
||||
if (!Validates.isEmptyBlank(contextDomain))
|
||||
{//1.域名不为空,优先找匹配上的
|
||||
for (HttpContext context : contextList)
|
||||
{
|
||||
HashSetS domains = context.getContextDomains();
|
||||
if (domains.isEmpty())
|
||||
continue;
|
||||
|
||||
if (domains.contains(contextDomain) && contextPath.equals(context.getContextPath()))
|
||||
return context;
|
||||
}
|
||||
}
|
||||
|
||||
//2.再找缺省未配置域名的,只比较上下文环境路径
|
||||
for (HttpContext context : contextList)
|
||||
{
|
||||
if (!context.getContextDomains().isEmpty())
|
||||
continue;
|
||||
|
||||
if (contextPath.equals(context.getContextPath()))
|
||||
return context;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getPort()
|
||||
{
|
||||
return listener.getPort();
|
||||
}
|
||||
|
||||
public String getScheme()
|
||||
{
|
||||
return listener.getScheme();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user