public class SqlMapConfigParser {
//初始化 NodeletParser
protected final NodeletParser parser = new NodeletParser();
//初始化XmlParserState
private XmlParserState state = new XmlParserState();
private boolean usingStreams = false;
public SqlMapConfigParser() {
parser.setValidation(true);
parser.setEntityResolver(new SqlMapClasspathEntityResolver());
//解析sqlMapConfig
addSqlMapConfigNodelets();
//解析全局属性
addGlobalPropNodelets();
//解析环境参数
addSettingsNodelets();
//解析别名配置
addTypeAliasNodelets();
//解析类型处理器
addTypeHandlerNodelets();
//解析事务
addTransactionManagerNodelets();
//解析sqlMap
addSqlMapNodelets();
//解析结果对象工厂配置
addResultObjectFactoryNodelets();
}
public SqlMapClient parse(Reader reader, Properties props) {
if (props != null) state.setGlobalProps(props);
return parse(reader);
}
public SqlMapClient parse(Reader reader) {
try {
usingStreams = false;
parser.parse(reader);
return state.getConfig().getClient();
} catch (Exception e) {
throw new RuntimeException("Error occurred. Cause: " + e, e);
}
}
public SqlMapClient parse(InputStream inputStream, Properties props) {
if (props != null) state.setGlobalProps(props);
return parse(inputStream);
}
public SqlMapClient parse(InputStream inputStream) {
try {
usingStreams = true;
parser.parse(inputStream);
return state.getConfig().getClient();
} catch (Exception e) {
throw new RuntimeException("Error occurred. Cause: " + e, e);
}
}
private void addSqlMapConfigNodelets() {
parser.addNodelet("/sqlMapConfig/end()", new Nodelet() {
public void process(Node node) throws Exception {
state.getConfig().finalizeSqlMapConfig();
}
});
}
//解析sqlmap的属性配置
private void addGlobalPropNodelets() {
parser.addNodelet("/sqlMapConfig/properties", new Nodelet() {
public void process(Node node) throws Exception {
Properties attributes = NodeletUtils.parseAttributes(node, state.getGlobalProps());
String resource = attributes.getProperty("resource");
String url = attributes.getProperty("url");
state.setGlobalProperties(resource, url);
}
});
}
//解析sqlMapConfig setting节点数据
private void addSettingsNodelets() {
parser.addNodelet("/sqlMapConfig/settings", new Nodelet() {
public void process(Node node) throws Exception {
Properties attributes = NodeletUtils.parseAttributes(node, state.getGlobalProps());
//获取SqlMapConfiguration对象
SqlMapConfiguration config = state.getConfig();
//获取classInfoCacheEnabled属性值
String classInfoCacheEnabledAttr = attributes.getProperty("classInfoCacheEnabled");
//如果没有配置该属性,或将该属性设置为true则将sqlMapConfiguration的值设置为true
boolean classInfoCacheEnabled = (classInfoCacheEnabledAttr == null || "true".equals(classInfoCacheEnabledAttr));
config.setClassInfoCacheEnabled(classInfoCacheEnabled);
// 获取lazyLoadingEnabled属性值,是否启用懒加载
String lazyLoadingEnabledAttr = attributes.getProperty("lazyLoadingEnabled");
//默认是开启lazyLoadingEnabled
boolean lazyLoadingEnabled = (lazyLoadingEnabledAttr == null || "true".equals(lazyLoadingEnabledAttr));
config.setLazyLoadingEnabled(lazyLoadingEnabled);
//获取statementCachingEnabled属性值,是否开启statement的缓存
String statementCachingEnabledAttr = attributes.getProperty("statementCachingEnabled");
//默认是开启的
boolean statementCachingEnabled = (statementCachingEnabledAttr == null || "true".equals(statementCachingEnabledAttr));
config.setStatementCachingEnabled(statementCachingEnabled);
//获取cachedModelsEnabled的属性值,默认是true,该值是表示是否开启SqlMapClient上的缓存机制
String cacheModelsEnabledAttr = attributes.getProperty("cacheModelsEnabled");
boolean cacheModelsEnabled = (cacheModelsEnabledAttr == null || "true".equals(cacheModelsEnabledAttr));
config.setCacheModelsEnabled(cacheModelsEnabled);
// 获取enhancementEnabled的属性值,默认是true,该值表示是否针对POJO开启字节码增强机制,减少reflet的性能开销
String enhancementEnabledAttr = attributes.getProperty("enhancementEnabled");
boolean enhancementEnabled = (enhancementEnabledAttr == null || "true".equals(enhancementEnabledAttr));
config.setEnhancementEnabled(enhancementEnabled);
//获取useColumnLabel的属性值,默认是true
String useColumnLabelAttr = attributes.getProperty("useColumnLabel");
boolean useColumnLabel = (useColumnLabelAttr == null || "true".equals(useColumnLabelAttr));
config.setUseColumnLabel(useColumnLabel);
//获取forceMultipleResultSetSupport的属性值,默认值是false
String forceMultipleResultSetSupportAttr = attributes.getProperty("forceMultipleResultSetSupport");
boolean forceMultipleResultSetSupport = "true".equals(forceMultipleResultSetSupportAttr);
config.setForceMultipleResultSetSupport(forceMultipleResultSetSupport);
//获取defaultSatementTimeout的属性值,默认值是null;JDBC连接的超时时间,默认是无时间限制
String defaultTimeoutAttr = attributes.getProperty("defaultStatementTimeout");
Integer defaultTimeout = defaultTimeoutAttr == null ? null : Integer.valueOf(defaultTimeoutAttr);
config.setDefaultStatementTimeout(defaultTimeout);
//获取useStatementNamespaces的属性值,默认值是false:是否使用命名空间
String useStatementNamespacesAttr = attributes.getProperty("useStatementNamespaces");
boolean useStatementNamespaces = "true".equals(useStatementNamespacesAttr);
state.setUseStatementNamespaces(useStatementNamespaces);
}
});
}
private void addTypeAliasNodelets() {
parser.addNodelet("/sqlMapConfig/typeAlias", new Nodelet() {
public void process(Node node) throws Exception {
Properties prop = NodeletUtils.parseAttributes(node, state.getGlobalProps());
String alias = prop.getProperty("alias");
String type = prop.getProperty("type");
state.getConfig().getTypeHandlerFactory().putTypeAlias(alias, type);
}
});
}
// 解析SqlMapConfig中typeHandler节点配置
private void addTypeHandlerNodelets() {
parser.addNodelet("/sqlMapConfig/typeHandler", new Nodelet() {
public void process(Node node) throws Exception {
Properties prop = NodeletUtils.parseAttributes(node, state.getGlobalProps());
//获取jdbcType,javaType,callback的属性值
String jdbcType = prop.getProperty("jdbcType");
String javaType = prop.getProperty("javaType");
String callback = prop.getProperty("callback");
//根据javaType,callback作为别名去TypeHandlerFactory获取映射值,如果不是别名则返回原始值
javaType = state.getConfig().getTypeHandlerFactory().resolveAlias(javaType);
callback = state.getConfig().getTypeHandlerFactory().resolveAlias(callback);
//在SqlMapConfiguration实例中设置TypeHandler
state.getConfig().newTypeHandler(Resources.classForName(javaType), jdbcType, Resources.instantiate(callback));
}
});
}
// 解析SqlMapConfig中transactionManager节点下的属性配置
private void addTransactionManagerNodelets() {
parser.addNodelet("/sqlMapConfig/transactionManager/property", new Nodelet() {
public void process(Node node) throws Exception {
Properties attributes = NodeletUtils.parseAttributes(node, state.getGlobalProps());
String name = attributes.getProperty("name");
String value = NodeletUtils.parsePropertyTokens(attributes.getProperty("value"), state.getGlobalProps());
state.getTxProps().setProperty(name, value);
}
});
parser.addNodelet("/sqlMapConfig/transactionManager/end()", new Nodelet() {
public void process(Node node) throws Exception {
Properties attributes = NodeletUtils.parseAttributes(node, state.getGlobalProps());
String type = attributes.getProperty("type");
boolean commitRequired = "true".equals(attributes.getProperty("commitRequired"));
state.getConfig().getErrorContext().setActivity("configuring the transaction manager");
type = state.getConfig().getTypeHandlerFactory().resolveAlias(type);
TransactionManager txManager;
try {
state.getConfig().getErrorContext().setMoreInfo("Check the transaction manager type or class.");
TransactionConfig config = (TransactionConfig) Resources.instantiate(type);
config.setDataSource(state.getDataSource());
state.getConfig().getErrorContext().setMoreInfo("Check the transactio nmanager properties or configuration.");
config.setProperties(state.getTxProps());
config.setForceCommit(commitRequired);
config.setDataSource(state.getDataSource());
state.getConfig().getErrorContext().setMoreInfo(null);
txManager = new TransactionManager(config);
} catch (Exception e) {
if (e instanceof SqlMapException) {
throw (SqlMapException) e;
} else {
throw new SqlMapException("Error initializing TransactionManager. Could not instantiate TransactionConfig. Cause: " + e, e);
}
}
state.getConfig().setTransactionManager(txManager);
}
});
//解析dataSource属性
parser.addNodelet("/sqlMapConfig/transactionManager/dataSource/property", new Nodelet() {
public void process(Node node) throws Exception {
Properties attributes = NodeletUtils.parseAttributes(node, state.getGlobalProps());
String name = attributes.getProperty("name");
String value = NodeletUtils.parsePropertyTokens(attributes.getProperty("value"), state.getGlobalProps());
state.getDsProps().setProperty(name, value);
}
});
parser.addNodelet("/sqlMapConfig/transactionManager/dataSource/end()", new Nodelet() {
public void process(Node node) throws Exception {
state.getConfig().getErrorContext().setActivity("configuring the data source");
Properties attributes = NodeletUtils.parseAttributes(node, state.getGlobalProps());
String type = attributes.getProperty("type");
Properties props = state.getDsProps();
type = state.getConfig().getTypeHandlerFactory().resolveAlias(type);
try {
state.getConfig().getErrorContext().setMoreInfo("Check the data source type or class.");
DataSourceFactory dsFactory = (DataSourceFactory) Resources.instantiate(type);
state.getConfig().getErrorContext().setMoreInfo("Check the data source properties or configuration.");
dsFactory.initialize(props);
state.setDataSource(dsFactory.getDataSource());
state.getConfig().getErrorContext().setMoreInfo(null);
} catch (Exception e) {
if (e instanceof SqlMapException) {
throw (SqlMapException) e;
} else {
throw new SqlMapException("Error initializing DataSource. Could not instantiate DataSourceFactory. Cause: " + e, e);
}
}
}
});
}
protected void addSqlMapNodelets() {
//解析sqlMap
parser.addNodelet("/sqlMapConfig/sqlMap", new Nodelet() {
public void process(Node node) throws Exception {
state.getConfig().getErrorContext().setActivity("loading the SQL Map resource");
Properties attributes = NodeletUtils.parseAttributes(node, state.getGlobalProps());
String resource = attributes.getProperty("resource");
String url = attributes.getProperty("url");
if (usingStreams) {
InputStream inputStream = null;
if (resource != null) {
state.getConfig().getErrorContext().setResource(resource);
inputStream = Resources.getResourceAsStream(resource);
} else if (url != null) {
state.getConfig().getErrorContext().setResource(url);
inputStream = Resources.getUrlAsStream(url);
} else {
throw new SqlMapException("The <sqlMap> element requires either a resource or a url attribute.");
}
//使用SQLMapParser解析sqlMap
new SqlMapParser(state).parse(inputStream);
} else {
Reader reader = null;
if (resource != null) {
state.getConfig().getErrorContext().setResource(resource);
reader = Resources.getResourceAsReader(resource);
} else if (url != null) {
state.getConfig().getErrorContext().setResource(url);
reader = Resources.getUrlAsReader(url);
} else {
throw new SqlMapException("The <sqlMap> element requires either a resource or a url attribute.");
}
new SqlMapParser(state).parse(reader);
}
}
});
}
//解析resultObjectFactory
private void addResultObjectFactoryNodelets() {
parser.addNodelet("/sqlMapConfig/resultObjectFactory", new Nodelet() {
public void process(Node node) throws Exception {
Properties attributes = NodeletUtils.parseAttributes(node, state.getGlobalProps());
String type = attributes.getProperty("type");
state.getConfig().getErrorContext().setActivity("configuring the Result Object Factory");
ResultObjectFactory rof;
try {
rof = (ResultObjectFactory) Resources.instantiate(type);
state.getConfig().setResultObjectFactory(rof);
} catch (Exception e) {
throw new SqlMapException("Error instantiating resultObjectFactory: " + type, e);
}
}
});
parser.addNodelet("/sqlMapConfig/resultObjectFactory/property", new Nodelet() {
public void process(Node node) throws Exception {
Properties attributes = NodeletUtils.parseAttributes(node, state.getGlobalProps());
String name = attributes.getProperty("name");
String value = NodeletUtils.parsePropertyTokens(attributes.getProperty("value"), state.getGlobalProps());
state.getConfig().getDelegate().getResultObjectFactory().setProperty(name, value);
}
});
}
}