Zhiqim Markup Language是知启蒙定义的、类似于JavaJavascript语法的语句和表达式,通常和XML/HTML混编在一起形成的一种新的标记语言。 ZML力求简单易用,目前支持常用的十二种标记语句和五十种表达式,在知启蒙技术体系中被用来代替JSP。
ZmlEngine.java20KB
/*
* 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙,邂逅框架梦]
*
* https://zhiqim.org/project/zhiqim_framework/zhiqim_zml.htm
*
* Zhiqim Zml is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
package org.zhiqim.zml;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map.Entry;
import org.zhiqim.kernel.model.maps.HashMapSO;
import org.zhiqim.kernel.model.maps.LinkedMapSV;
import org.zhiqim.kernel.util.Arrays;
import org.zhiqim.kernel.util.Asserts;
import org.zhiqim.zml.loader.ClassZmlLoader;
import org.zhiqim.zml.loader.FileZmlLoader;
import org.zhiqim.zml.statement._Function;
import org.zhiqim.zml.statement._Include;
import org.zhiqim.zml.statement._Var;
/**
* ZhiqimML引擎主程序<br><br>
*
* 1、设置引擎参数,如加载器、编码等<br>
* 2、加载全局函数定义文件。<br>
* 3、设置共享变量。<br>
*
* @version v1.0.0 @author zouzhigang 2014-3-21 新建与整理
*/
public class ZmlEngine extends ZmlPredefinded implements ZmlConstants
{
//ZML引擎基本参数
private ZmlVarNotice notice;
private String encoding;
private int maxIdleTime;
private int maxKeepTime;
private boolean isAscQuery;
private String[] patterns;
//ZML引擎加载器和全局变量
private ZmlLoader loader;
private final LinkedMapSV<ZmlLoader> cLoaderMap;
private final HashMapSO globalMap;
//ZML引擎配置ZML(最后修改时间、函数表和变量表)
private final LinkedHashMap<ConfigKey, Long> fileMap;
private final LinkedHashMap<ConfigKey, LinkedMapSV<_Function>> functionMap;
private final LinkedHashMap<ConfigKey, LinkedMapSV<_Var>> variableMap;
/** 默认ZML引擎构造方法,编码格式默认为UTF-8 */
public ZmlEngine()
{
this(_UTF_8_);
}
/**
* ZML引擎构造方法,传入编码格式
*
* @param encoding ZML通用的编码格式
*/
public ZmlEngine(String encoding)
{
this.encoding = encoding;
this.patterns = ZML_PATTERN_DEFAULT;
this.cLoaderMap = new LinkedMapSV<>();
this.globalMap = new HashMapSO();
this.fileMap = new LinkedHashMap<>();
this.functionMap = new LinkedHashMap<>();
this.variableMap = new LinkedHashMap<>();
}
/**************************************************************************/
//ZML引擎基本参数
/**************************************************************************/
public void setZmlVarNotice(ZmlVarNotice notice)
{
this.notice = notice;
}
public void setAscQuery(boolean isAscQuery)
{
this.isAscQuery = isAscQuery;
}
public void setEncoding(String encoding)
{
this.encoding = encoding;
}
public void setMaxIdleTime(int maxIdleTime)
{
this.maxIdleTime = maxIdleTime;
}
public void setMaxKeepTime(int maxKeepTime)
{
this.maxKeepTime = maxKeepTime;
}
public void setPatterns(String[] patterns)
{
this.patterns = patterns;
}
public void setPatterns(String patterns)
{
this.patterns = Arrays.toStringArray(patterns);
}
public String getEncoding()
{
return encoding;
}
public int getMaxIdleTime()
{
return maxIdleTime;
}
public int getMaxKeepTime()
{
return maxKeepTime;
}
public String[] getPatterns()
{
return patterns;
}
/**************************************************************************/
//ZML引擎加载器和全局变量
/**************************************************************************/
/**
* 设置ZML加载器,如果是默认的类加载器和文件加载器,请使用setClassZmlLoader/setFileZmlLoader方法
*
* @param loader ZML加载器
*/
public void setZmlLoader(ZmlLoader loader)
{
this.loader = loader;
}
/**
* 设置类ZML加载器
*
* @param clazz 给定一个能访问到ZML文件的类,防止跨ClassLoader加载失败
* @param pathPrefix ZML文件路径前缀,格式为/org/zhiqim/example
*/
public void setClassZmlLoader(Class<?> clazz, String pathPrefix)
{
this.loader = new ClassZmlLoader(this, clazz, pathPrefix);
}
/**
* 设置文件夹加载器
*
* @param dir ZML文件根目录,如new File("./resource");
* @throws IOException 检查文件根目录异常
*/
public void setFileZmlLoader(File dir) throws IOException
{
this.loader = new FileZmlLoader(this, dir.getCanonicalPath());
}
/**
* 增加组件ZML加载器
*
* @param clazz 给定一个能访问到ZML文件的类,防止跨ClassLoader加载失败
* @param pathPrefix ZML文件路径前缀,格式为/org/zhiqim/example
*/
public void addComponentZmlLoader(Class<?> clazz, String pathPrefix)
{
this.cLoaderMap.put(pathPrefix, new ClassZmlLoader(this, clazz, pathPrefix));
}
public void addComponentZmlLoader(String componentPath, ZmlLoader loader)
{
this.cLoaderMap.put(componentPath, loader);
}
public ZmlLoader getLoader(ConfigKey ck)
{
return getLoader(ck.configPath, ck.componentPath);
}
public ZmlLoader getLoader(String contextPath, String componentPath)
{
return (componentPath==null)?this.loader:this.cLoaderMap.get(componentPath);
}
/**
* 增加全局变量
*
* @param name 变量名
* @param obj 变量值
*/
public void addGlobalVariable(String name, Object obj)
{
globalMap.put(name, obj);
}
public Object getGlobalVariable(String key)
{
return globalMap.get(key);
}
public HashMapSO getGlobalMap()
{
return globalMap;
}
/**************************************************************************/
//ZML引擎配置ZML(最后修改时间、函数表和变量表)
/**************************************************************************/
/**
* 添加上下文配置ZML
*
* @param configPath 上下文配置ZML路径
*/
public void addConfigZml(String configPath)
{
Asserts.as(this.loader != null?null:"未设置加载器上不支持添加上下文配置ZML");
this.loadConfigZml(new ConfigKey(configPath, null));
}
/**
* 添加组件上下文配置ZML,带组件路径
*
* @param configPath 上下文配置ZML路径
* @param componentPath 组件路径
*/
public void addConfigZml(String configPath, String componentPath)
{
Asserts.as(this.cLoaderMap.containsKey(componentPath)?null:"未设置该组件加载器上不支持添加组件上下文配置ZML");
this.loadConfigZml(new ConfigKey(configPath, componentPath));
}
/** 检查当前配置更新 */
public void chkCurConfigModified()
{
for (Entry<ConfigKey, Long> entry : fileMap.entrySet())
{
if (entry.getKey().componentPath != null)
continue;
try
{
long lastModified = getConfigLastModified(entry.getKey());
if (lastModified != entry.getValue())
loadConfigZml(entry.getKey());
}
catch (Exception e)
{
throw Asserts.exception("加载上下文ZML["+entry.getKey().configPath+"]异常", e);
}
}
}
/** 检查所有配置更新 */
private void chkAllConfigModified()
{
for (Entry<ConfigKey, Long> entry : fileMap.entrySet())
{
try
{
long lastModified = getConfigLastModified(entry.getKey());
if (lastModified != entry.getValue())
loadConfigZml(entry.getKey());
}
catch (Exception e)
{
throw Asserts.exception("加载上下文ZML["+entry.getKey().configPath+"]异常", e);
}
}
}
/** 获取配置ZML最后修改时间 */
private long getConfigLastModified(ConfigKey ck) throws Exception
{
ZmlLoader loader = getLoader(ck);
return loader.getLastModified(ck.configPath);
}
/** 获取配置ZML里的函数表 */
public LinkedMapSV<_Function> getFunctionMap(String contextPath, String componentPath)
{
return functionMap.get(new ConfigKey(contextPath, componentPath));
}
/** 获取配置ZML里的变量表 */
public LinkedMapSV<_Var> getVarMap(String contextPath, String componentPath)
{
return variableMap.get(new ConfigKey(contextPath, componentPath));
}
/** 查找配置ZML中函数语句 */
public _Function getFunction(String name) throws Exception
{
if (loader == null)
throw new Exception("未定义加载器,不支持获取函数调用");
//先检查上下文文件更新标志
chkAllConfigModified();
if (isAscQuery)
{//按顺序查找对应的函数
for (LinkedMapSV<_Function> fMap : functionMap.values())
{
_Function _function = fMap.get(name);
if (_function != null)
return _function;
}
}
else
{//按倒序查找对应的函数
_Function _function = null;
for (LinkedMapSV<_Function> fMap : functionMap.values())
{
if (fMap.containsKey(name))
_function = fMap.get(name);
}
if (_function != null)
return _function;
}
//如果没找到抛异常
throw new Exception("加载上下文ZML失败,不支持获取函数");
}
/** 查找配置ZML中变量语句 */
public _Var getVar(String name)
{
if (loader == null)
return null;
//先检查上下文文件更新标志
chkAllConfigModified();
if (isAscQuery)
{//按顺序查找对应的变量
for (LinkedMapSV<_Var> vMap : variableMap.values())
{
_Var _var = vMap.get(name);
if (_var != null)
return _var;
}
}
else
{//按倒序查找对应的变量
_Var _var = null;
for (LinkedMapSV<_Var> vMap : variableMap.values())
{
if (vMap.containsKey(name))
_var = vMap.get(name);
}
if (_var != null)
return _var;
}
//如果没找到返回null
return null;
}
/**************************************************************************/
//指定路径判断和查找ZML信息 has & get
/**************************************************************************/
/**
* 判断是否存在ZML信息
*
* @param path ZML相对路径
* @return =true表示存在,=false表示不存在
*/
public boolean hasZml(String path)
{
Asserts.as(this.loader != null?null:"未设置加载器上不支持增通过引擎获取ZML");
try
{
//优先本地查找
if (loader.hasZml(path))
return true;
//再到组件中查找
List<ZmlLoader> list = new ArrayList<>(cLoaderMap.values());
for (int i=list.size()-1;i>=0;i--)
{
ZmlLoader ld = list.get(i);
if (ld.hasZml(path))
return true;
}
return false;
}
catch (Exception e)
{
throw Asserts.exception("加载ZML文件["+path+"]异常", e);
}
}
/**
* 判断是否存在ZML信息
*
* @param path ZML相对路径
* @return 存在返回加载器,不存在返回false
*/
public ZmlLoader getZmlLoader(String path)
{
Asserts.as(this.loader != null?null:"未设置加载器上不支持增通过引擎获取ZML");
try
{
//优先本地查找
if (loader.hasZml(path))
return loader;
//再到组件中查找
List<ZmlLoader> list = new ArrayList<>(cLoaderMap.values());
for (int i=list.size()-1;i>=0;i--)
{
ZmlLoader ld = list.get(i);
if (ld.hasZml(path))
return ld;
}
return null;
}
catch (Exception e)
{
throw Asserts.exception("加载ZML文件["+path+"]异常", e);
}
}
/**
* 获取ZML信息
*
* @param path ZML相对路径
* @return ZML信息
* @throws IOException 读取ZML文件时产生的异常
*/
public Zml getZml(String path) throws FileNotFoundException
{
Asserts.as(this.loader != null?null:"未设置加载器上不支持增通过引擎获取ZML");
try
{
//优先本地查找
Zml zml = loader.loadZml(path);
if (zml != null)
return zml;
//再到组件中查找
List<ZmlLoader> list = new ArrayList<>(cLoaderMap.values());
for (int i=list.size()-1;i>=0;i--)
{
ZmlLoader ld = list.get(i);
zml = ld.loadZml(path);
if (zml != null)
return zml;
}
}
catch (Exception e)
{
throw Asserts.exception("加载ZML文件["+path+"]异常", e);
}
throw Asserts.notFound("未找到ZML文件["+path+"]");
}
/**************************************************************************/
//加载配置ZML
/**************************************************************************/
/** 加载配置ZML */
private void loadConfigZml(ConfigKey mk)
{
String configPath = mk.configPath;
String componentPath = mk.componentPath;
//1.1 先加载ZML
Zml zml = null;
try
{
ZmlLoader theLoader = componentPath==null?this.loader:this.cLoaderMap.get(componentPath);
zml = theLoader.loadZml(configPath);
if (zml == null)
return;//未找到不加载
//修改ZML文件的最后修改时间
fileMap.put(mk, zml.getLastModified());
}
catch (Exception e)
{
throw Asserts.exception("加载上下文ZML["+configPath+"]异常", e);
}
//1.2 从ZML中找到函数列表,变量列表和包含列表
List<_Function> funcList = new ArrayList<>();
List<_Var> varList = new ArrayList<>();
List<_Include> includeList = new ArrayList<>();
try
{
StatementParser.parseContextZml(zml, funcList, varList, includeList);
}
catch (Exception e)
{
throw Asserts.exception("加载上下文ZML["+configPath+"]异常", e);
}
//2.1 找到上下文对应的全局函数表
LinkedMapSV<_Function> funcMap = null;
synchronized (functionMap)
{
LinkedMapSV<_Function> fMap = functionMap.get(mk);
if (fMap == null)
{
fMap = new LinkedMapSV<_Function>();
functionMap.put(mk, fMap);
}
funcMap = fMap;
}
//2.2 把ZML中的函数表加入到全局函数表中
synchronized (funcMap)
{
try
{
funcMap.clear();
for (_Function func : funcList)
{
String name = func.getName();
if (funcMap.containsKey(name))//一个上下文文件定义全局函数不允许重复,多文件之间支持,按优先顺序读取
throw Asserts.exception("找到上下文ZML文件["+configPath+"]中全局函数["+name+"]有重复");
funcMap.put(name, func);
}
}
catch (Exception e)
{
throw Asserts.exception("加载上下文ZML["+configPath+"]异常", e);
}
}
//3.1 找到上下文对应的全局变量表
LinkedMapSV<_Var> varMap = null;
synchronized (variableMap)
{
LinkedMapSV<_Var> vMap = variableMap.get(mk);
if (vMap == null)
{
vMap = new LinkedMapSV<_Var>();
variableMap.put(mk, vMap);
}
varMap = vMap;
}
//3.2 把ZML中的变量表并加入到全局变量表中
synchronized (varMap)
{
try
{
varMap.clear();
for (_Var var : varList)
{
String name = var.getVariableName();
if (varMap.containsKey(name))//一个上下文文件定义全局变量不允许重复,多文件之间支持,按优先顺序读取
throw Asserts.exception("找到上下文ZML文件["+configPath+"]中全局变量["+name+"]有重复");
varMap.put(name, var);
}
if (notice != null)
{//变量更新通知
notice.doUpdateVariable(zml, configPath, componentPath, varMap);
}
}
catch (Exception e)
{
throw Asserts.exception("加载上下文ZML["+configPath+"]异常", e);
}
}
//4 递归加载里面包含表的函数和变量
try
{
ZmlVariable variable = new ZmlVariable();
for (_Include include : includeList)
{
String path = include.getIncludePath(variable);
loadConfigZml(new ConfigKey(path, componentPath));
}
}
catch (Exception e)
{
throw Asserts.exception("加载上下文ZML["+configPath+"]异常", e);
}
}
/**************************************************************************/
//ZML引擎配置键(配置路径和组件路径组合成唯一)
/**************************************************************************/
private class ConfigKey
{
private String configPath;
private String componentPath;
public ConfigKey(String contextPath, String componentPath)
{
this.configPath = contextPath;
this.componentPath = componentPath;
}
@Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + ((componentPath == null) ? 0 : componentPath.hashCode());
result = prime * result + ((configPath == null) ? 0 : configPath.hashCode());
return result;
}
@Override
public boolean equals(Object obj)
{
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ConfigKey other = (ConfigKey)obj;
if (componentPath == null)
{
if (other.componentPath != null)
return false;
}
else if (!componentPath.equals(other.componentPath))
return false;
if (configPath == null)
{
if (other.configPath != null)
return false;
}
else if (!configPath.equals(other.configPath))
return false;
return true;
}
}
}

