OK, I looked at this more, and have the code changed locally, but have
not committed it yet for a few reasons:
1) It's a bigger change than I expected (including a change to
sql-map-config-2.dtd)
2) We have a release coming soon and I do not want to break it.
3) I have not tested it yet
So, if you want to try it out, the only code change is in
SqlMapConfigParser.java (attached), but as I said, it is not tested,
and will require that you also change your sqlmap config dtd (changed
version also attached).
I guess this also gives everyone an opportunity to chime in on this
change before it goes in.
Thoughts anyone?
Larry
On 11/24/06, Larry Meadors <[EMAIL PROTECTED]> wrote:
OK, think I found this, but since today is a holiday, and we have FOUR
INCHES OF FRESH SNOW, I need to take my kids sledding (or they need to
take me sledding?).
At any rate, I won't get to it until this evening.
Priorities. :-)
Larry
On 11/24/06, Larry Meadors <[EMAIL PROTECTED]> wrote:
> Guillaume is correct. The settings element is not pre-processed like
> other elements are.
>
> ..although I am not sure why. I'll look at that and see if I can fix it.
>
> Larry
>
>
> On 11/24/06, Guillaume Carré <[EMAIL PROTECTED]> wrote:
> > 2006/11/24, Tom Stroobants <[EMAIL PROTECTED]>:
> > >
> > > Hi All,
> > >
> > > We have an application that runs on different servers ...
> > > On one server we want to overrule to IBATIS caching like this:
> > >
> > > <?xml version="1.0" encoding="UTF-8"?>
> > > <!DOCTYPE sqlMapConfig PUBLIC "-//iBATIS.com//DTD SQL Map Config
> > > 2.0//EN" "http://www.ibatis.com/dtd/sql-map-config-2.dtd">
> > >
> > > <sqlMapConfig>
> > > <properties resource="ibatis.properties"/>
> > > <settings cacheModelsEnabled="${ibatis.cacheModelsEnabled}"/>
> > >
> > > ...
> > >
> > > </sqlMapConfig>
> > >
> > > We also have an ibatis.properties file which contains the key
> > > ibatis.cacheModelsEnabled = true
> > >
> > > But this doesn't seem to work ...
> > >
> > > Any advice ?
> >
> > Hello,
> >
> > there is no way to overrule caching, with ${} properties, or with the API.
> >
> > I posted almost the same question here 2 weeks ago.
> > http://www.mail-archive.com/[email protected]/msg06763.html
> > --
> > Guillaume Carré
> >
>
package com.ibatis.sqlmap.engine.builder.xml;
import com.ibatis.common.resources.Resources;
import com.ibatis.common.xml.Nodelet;
import com.ibatis.common.xml.NodeletParser;
import com.ibatis.common.xml.NodeletUtils;
import com.ibatis.common.beans.ClassInfo;
import com.ibatis.sqlmap.client.SqlMapClient;
import com.ibatis.sqlmap.client.SqlMapException;
import com.ibatis.sqlmap.client.extensions.TypeHandlerCallback;
import com.ibatis.sqlmap.engine.accessplan.AccessPlanFactory;
import com.ibatis.sqlmap.engine.cache.CacheModel;
import com.ibatis.sqlmap.engine.cache.fifo.FifoCacheController;
import com.ibatis.sqlmap.engine.cache.lru.LruCacheController;
import com.ibatis.sqlmap.engine.cache.memory.MemoryCacheController;
import com.ibatis.sqlmap.engine.datasource.DataSourceFactory;
import com.ibatis.sqlmap.engine.datasource.DbcpDataSourceFactory;
import com.ibatis.sqlmap.engine.datasource.JndiDataSourceFactory;
import com.ibatis.sqlmap.engine.datasource.SimpleDataSourceFactory;
import com.ibatis.sqlmap.engine.impl.SqlMapClientImpl;
import com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate;
import com.ibatis.sqlmap.engine.mapping.result.ResultObjectFactory;
import com.ibatis.sqlmap.engine.mapping.statement.MappedStatement;
import com.ibatis.sqlmap.engine.transaction.TransactionConfig;
import com.ibatis.sqlmap.engine.transaction.TransactionManager;
import com.ibatis.sqlmap.engine.transaction.external.ExternalTransactionConfig;
import com.ibatis.sqlmap.engine.transaction.jdbc.JdbcTransactionConfig;
import com.ibatis.sqlmap.engine.transaction.jta.JtaTransactionConfig;
import com.ibatis.sqlmap.engine.type.*;
import org.w3c.dom.Node;
import java.io.Reader;
import java.util.Iterator;
import java.util.Properties;
public class SqlMapConfigParser extends BaseParser {
protected final NodeletParser parser = new NodeletParser();
public SqlMapConfigParser() {
this(null, null);
}
public SqlMapConfigParser(XmlConverter sqlMapConfigConv, XmlConverter sqlMapConv) {
super(new Variables());
parser.setValidation(true);
parser.setEntityResolver(new SqlMapClasspathEntityResolver());
vars.sqlMapConfigConv = sqlMapConfigConv;
vars.sqlMapConv = sqlMapConv;
vars.delegate = new SqlMapExecutorDelegate();
vars.typeHandlerFactory = vars.delegate.getTypeHandlerFactory();
vars.client = new SqlMapClientImpl(vars.delegate);
registerDefaultTypeAliases();
addSqlMapConfigNodelets();
addGlobalPropNodelets();
addSettingsNodelets();
addTypeAliasNodelets();
addTypeHandlerNodelets();
addTransactionManagerNodelets();
addSqlMapNodelets();
addResultObjectFactoryNodelets();
}
public SqlMapClient parse(Reader reader, Properties props) {
vars.properties = props;
return parse(reader);
}
public SqlMapClient parse(Reader reader) {
try {
if (vars.sqlMapConfigConv != null) {
reader = vars.sqlMapConfigConv.convertXml(reader);
}
parser.parse(reader);
return vars.client;
} 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 {
Iterator cacheNames = vars.client.getDelegate().getCacheModelNames();
while (cacheNames.hasNext()) {
String cacheName = (String) cacheNames.next();
CacheModel cacheModel = vars.client.getDelegate().getCacheModel(cacheName);
Iterator statementNames = cacheModel.getFlushTriggerStatementNames();
while (statementNames.hasNext()) {
String statementName = (String) statementNames.next();
MappedStatement statement = vars.client.getDelegate().getMappedStatement(statementName);
if (statement != null) {
statement.addExecuteListener(cacheModel);
} else {
throw new RuntimeException("Could not find statement named '" + statementName + "' for use as a flush trigger for the cache model named '" + cacheName + "'.");
}
}
}
}
});
}
private void addGlobalPropNodelets() {
parser.addNodelet("/sqlMapConfig/properties", new Nodelet() {
public void process(Node node) throws Exception {
vars.errorCtx.setActivity("loading global properties");
Properties attributes = NodeletUtils.parseAttributes(node,vars.properties);
String resource = attributes.getProperty("resource");
String url = attributes.getProperty("url");
try {
Properties props;
if (resource != null) {
vars.errorCtx.setResource(resource);
props = Resources.getResourceAsProperties(resource);
} else if (url != null) {
vars.errorCtx.setResource(url);
props = Resources.getUrlAsProperties(url);
} else {
throw new RuntimeException("The " + "properties" + " element requires either a resource or a url attribute.");
}
if (vars.properties == null) {
vars.properties = props;
} else {
props.putAll(vars.properties);
vars.properties = props;
}
} catch (Exception e) {
throw new RuntimeException("Error loading properties. Cause: " + e);
}
}
});
}
private void addSettingsNodelets() {
parser.addNodelet("/sqlMapConfig/settings", new Nodelet() {
public void process(Node node) throws Exception {
vars.errorCtx.setActivity("loading settings properties");
Properties attributes = NodeletUtils.parseAttributes(node, vars.properties);
String classInfoCacheEnabledAttr = NodeletUtils.parsePropertyTokens(attributes.getProperty("classInfoCacheEnabled"), vars.properties);
boolean classInfoCacheEnabled = (classInfoCacheEnabledAttr == null || "true".equals(classInfoCacheEnabledAttr));
ClassInfo.setCacheEnabled(classInfoCacheEnabled);
String lazyLoadingEnabledAttr = NodeletUtils.parsePropertyTokens(attributes.getProperty("lazyLoadingEnabled"), vars.properties);
boolean lazyLoadingEnabled = (lazyLoadingEnabledAttr == null || "true".equals(lazyLoadingEnabledAttr));
vars.client.getDelegate().setLazyLoadingEnabled(lazyLoadingEnabled);
String statementCachingEnabledAttr = NodeletUtils.parsePropertyTokens(attributes.getProperty("statementCachingEnabled"), vars.properties);
boolean statementCachingEnabled = (statementCachingEnabledAttr == null || "true".equals(statementCachingEnabledAttr));
vars.client.getDelegate().setStatementCacheEnabled(statementCachingEnabled);
String cacheModelsEnabledAttr = NodeletUtils.parsePropertyTokens(attributes.getProperty("cacheModelsEnabled"), vars.properties);
boolean cacheModelsEnabled = (cacheModelsEnabledAttr == null || "true".equals(cacheModelsEnabledAttr));
vars.client.getDelegate().setCacheModelsEnabled(cacheModelsEnabled);
String enhancementEnabledAttr = NodeletUtils.parsePropertyTokens(attributes.getProperty("enhancementEnabled"), vars.properties);
boolean enhancementEnabled = (enhancementEnabledAttr == null || "true".equals(enhancementEnabledAttr));
try {
enhancementEnabled = enhancementEnabled && Resources.classForName("net.sf.cglib.proxy.InvocationHandler") != null;
} catch (ClassNotFoundException e) {
enhancementEnabled = false;
}
vars.client.getDelegate().setEnhancementEnabled(enhancementEnabled);
String useStatementNamespacesAttr = NodeletUtils.parsePropertyTokens(attributes.getProperty("useStatementNamespaces"), vars.properties);
vars.useStatementNamespaces = ("true".equals(useStatementNamespacesAttr));
String maxTransactions = NodeletUtils.parsePropertyTokens(attributes.getProperty("maxTransactions"), vars.properties);
if (maxTransactions != null && Integer.parseInt(maxTransactions) > 0) {
vars.client.getDelegate().setMaxTransactions(Integer.parseInt(maxTransactions));
}
String maxRequests = NodeletUtils.parsePropertyTokens(attributes.getProperty("maxRequests"), vars.properties);
if (maxRequests != null && Integer.parseInt(maxRequests) > 0) {
vars.client.getDelegate().setMaxRequests(Integer.parseInt(maxRequests));
}
String maxSessions = NodeletUtils.parsePropertyTokens(attributes.getProperty("maxSessions"), vars.properties);
if (maxSessions != null && Integer.parseInt(maxSessions) > 0) {
vars.client.getDelegate().setMaxSessions(Integer.parseInt(maxSessions));
}
AccessPlanFactory.setBytecodeEnhancementEnabled(vars.client.getDelegate().isEnhancementEnabled());
String defaultStatementTimeout = NodeletUtils.parsePropertyTokens(attributes.getProperty("defaultStatementTimeout"), vars.properties);
if (defaultStatementTimeout != null) {
try {
vars.defaultStatementTimeout = Integer.valueOf(defaultStatementTimeout);
} catch (NumberFormatException e) {
throw new SqlMapException("Specified defaultStatementTimeout is not a valid integer");
}
}
}
});
}
private void addTypeAliasNodelets() {
parser.addNodelet("/sqlMapConfig/typeAlias", new Nodelet() {
public void process(Node node) throws Exception {
Properties prop = NodeletUtils.parseAttributes(node, vars.properties);
String alias = prop.getProperty("alias");
String type = prop.getProperty("type");
vars.typeHandlerFactory.putTypeAlias(alias, type);
}
});
}
private void addTypeHandlerNodelets() {
parser.addNodelet("/sqlMapConfig/typeHandler", new Nodelet() {
public void process(Node node) throws Exception {
vars.errorCtx.setActivity("building a building custom type handler");
try {
TypeHandlerFactory typeHandlerFactory = vars.client.getDelegate().getTypeHandlerFactory();
Properties prop = NodeletUtils.parseAttributes(node, vars.properties);
String jdbcType = prop.getProperty("jdbcType");
String javaType = prop.getProperty("javaType");
String callback = prop.getProperty("callback");
callback = typeHandlerFactory.resolveAlias(callback);
javaType = typeHandlerFactory.resolveAlias(javaType);
vars.errorCtx.setMoreInfo("Check the callback attribute '" + callback + "' (must be a classname).");
TypeHandler typeHandler;
Object impl = Resources.classForName(callback).newInstance();
if (impl instanceof TypeHandlerCallback) {
typeHandler = new CustomTypeHandler((TypeHandlerCallback) impl);
} else if (impl instanceof TypeHandler) {
typeHandler = (TypeHandler) impl;
} else {
throw new RuntimeException ("The class '' is not a valid implementation of TypeHandler or TypeHandlerCallback");
}
vars.errorCtx.setMoreInfo("Check the javaType attribute '" + javaType + "' (must be a classname) or the jdbcType '" + jdbcType + "' (must be a JDBC type name).");
if (jdbcType != null && jdbcType.length() > 0) {
typeHandlerFactory.register(Resources.classForName(javaType), jdbcType, typeHandler);
} else {
typeHandlerFactory.register(Resources.classForName(javaType), typeHandler);
}
} catch (Exception e) {
throw new SqlMapException("Error registering occurred. Cause: " + e, e);
}
vars.errorCtx.setMoreInfo(null);
vars.errorCtx.setObjectId(null);
}
});
}
private void addTransactionManagerNodelets() {
parser.addNodelet("/sqlMapConfig/transactionManager/end()", new Nodelet() {
public void process(Node node) throws Exception {
vars.errorCtx.setActivity("configuring the transaction manager");
Properties attributes = NodeletUtils.parseAttributes(node, vars.properties);
String type = attributes.getProperty("type");
type = vars.typeHandlerFactory.resolveAlias(type);
TransactionManager txManager;
try {
vars.errorCtx.setMoreInfo("Check the transaction manager type or class.");
TransactionConfig config = (TransactionConfig) Resources.instantiate(type);
config.setDataSource(vars.dataSource);
config.setMaximumConcurrentTransactions(vars.client.getDelegate().getMaxTransactions());
vars.errorCtx.setMoreInfo("Check the transactio nmanager properties or configuration.");
config.initialize(vars.txProps);
vars.errorCtx.setMoreInfo(null);
txManager = new TransactionManager(config);
txManager.setForceCommit("true".equals(attributes.getProperty("commitRequired")));
} catch (Exception e) {
if (e instanceof SqlMapException) {
throw (SqlMapException) e;
} else {
throw new SqlMapException("Error initializing TransactionManager. Could not instantiate TransactionConfig. Cause: " + e, e);
}
}
vars.client.getDelegate().setTxManager(txManager);
}
});
parser.addNodelet("/sqlMapConfig/transactionManager/property", new Nodelet() {
public void process(Node node) throws Exception {
Properties attributes = NodeletUtils.parseAttributes(node, vars.properties);
String name = attributes.getProperty("name");
String value = NodeletUtils.parsePropertyTokens(attributes.getProperty("value"), vars.properties);
vars.txProps.setProperty(name, value);
}
});
parser.addNodelet("/sqlMapConfig/transactionManager/dataSource", new Nodelet() {
public void process(Node node) throws Exception {
vars.dsProps = new Properties();
}
});
parser.addNodelet("/sqlMapConfig/transactionManager/dataSource/end()", new Nodelet() {
public void process(Node node) throws Exception {
vars.errorCtx.setActivity("configuring the data source");
Properties attributes = NodeletUtils.parseAttributes(node, vars.properties);
String type = attributes.getProperty("type");
type = vars.typeHandlerFactory.resolveAlias(type);
try {
vars.errorCtx.setMoreInfo("Check the data source type or class.");
DataSourceFactory dsFactory = (DataSourceFactory) Resources.instantiate(type);
vars.errorCtx.setMoreInfo("Check the data source properties or configuration.");
dsFactory.initialize(vars.dsProps);
vars.dataSource = dsFactory.getDataSource();
vars.errorCtx.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);
}
}
}
});
parser.addNodelet("/sqlMapConfig/transactionManager/dataSource/property", new Nodelet() {
public void process(Node node) throws Exception {
Properties attributes = NodeletUtils.parseAttributes(node, vars.properties);
String name = attributes.getProperty("name");
String value = NodeletUtils.parsePropertyTokens(attributes.getProperty("value"), vars.properties);
vars.dsProps.setProperty(name, value);
}
});
}
protected void addSqlMapNodelets() {
parser.addNodelet("/sqlMapConfig/sqlMap", new Nodelet() {
public void process(Node node) throws Exception {
vars.errorCtx.setActivity("loading the SQL Map resource");
Properties attributes = NodeletUtils.parseAttributes(node, vars.properties);
String resource = attributes.getProperty("resource");
String url = attributes.getProperty("url");
Reader reader;
if (resource != null) {
vars.errorCtx.setResource(resource);
reader = Resources.getResourceAsReader(resource);
} else if (url != null) {
vars.errorCtx.setResource(url);
reader = Resources.getUrlAsReader(url);
} else {
throw new SqlMapException("The <sqlMap> element requires either a resource or a url attribute.");
}
if (vars.sqlMapConv != null) {
reader = vars.sqlMapConv.convertXml(reader);
}
new SqlMapParser(vars).parse(reader);
}
});
}
private void addResultObjectFactoryNodelets() {
parser.addNodelet("/sqlMapConfig/resultObjectFactory", new Nodelet() {
public void process(Node node) throws Exception {
vars.errorCtx.setActivity("configuring the Result Object Factory");
Properties attributes = NodeletUtils.parseAttributes(node, vars.properties);
String type = attributes.getProperty("type");
ResultObjectFactory rof;
try {
rof = (ResultObjectFactory) Resources.instantiate(type);
vars.delegate.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, vars.properties);
String name = attributes.getProperty("name");
String value = NodeletUtils.parsePropertyTokens(attributes.getProperty("value"), vars.properties);
vars.delegate.getResultObjectFactory().setProperty(name, value);
}
});
}
private void registerDefaultTypeAliases() {
// TRANSACTION ALIASES
vars.typeHandlerFactory.putTypeAlias("JDBC", JdbcTransactionConfig.class.getName());
vars.typeHandlerFactory.putTypeAlias("JTA", JtaTransactionConfig.class.getName());
vars.typeHandlerFactory.putTypeAlias("EXTERNAL", ExternalTransactionConfig.class.getName());
// DATA SOURCE ALIASES
vars.typeHandlerFactory.putTypeAlias("SIMPLE", SimpleDataSourceFactory.class.getName());
vars.typeHandlerFactory.putTypeAlias("DBCP", DbcpDataSourceFactory.class.getName());
vars.typeHandlerFactory.putTypeAlias("JNDI", JndiDataSourceFactory.class.getName());
// CACHE ALIASES
vars.typeHandlerFactory.putTypeAlias("FIFO", FifoCacheController.class.getName());
vars.typeHandlerFactory.putTypeAlias("LRU", LruCacheController.class.getName());
vars.typeHandlerFactory.putTypeAlias("MEMORY", MemoryCacheController.class.getName());
// use a string for OSCache to avoid unnecessary loading of properties upon init
vars.typeHandlerFactory.putTypeAlias("OSCACHE", "com.ibatis.sqlmap.engine.cache.oscache.OSCacheController");
// TYPE ALIASEs
vars.typeHandlerFactory.putTypeAlias("dom", DomTypeMarker.class.getName());
vars.typeHandlerFactory.putTypeAlias("domCollection", DomCollectionTypeMarker.class.getName());
vars.typeHandlerFactory.putTypeAlias("xml", XmlTypeMarker.class.getName());
vars.typeHandlerFactory.putTypeAlias("xmlCollection", XmlCollectionTypeMarker.class.getName());
}
}
<?xml version="1.0" encoding="UTF-8" ?>
<!--
Copyright 2004 Clinton Begin
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!ELEMENT sqlMapConfig (properties?, settings?, resultObjectFactory?, typeAlias*, typeHandler*, transactionManager?, sqlMap+)+>
<!ATTLIST sqlMapConfig
xmlns:fo CDATA #IMPLIED
>
<!ELEMENT properties EMPTY>
<!ATTLIST properties
resource CDATA #IMPLIED
url CDATA #IMPLIED
>
<!ELEMENT settings EMPTY>
<!ATTLIST settings
classInfoCacheEnabled #IMPLIED
lazyLoadingEnabled #IMPLIED
statementCachingEnabled #IMPLIED
cacheModelsEnabled #IMPLIED
enhancementEnabled #IMPLIED
errorTracingEnabled #IMPLIED
useStatementNamespaces #IMPLIED
maxSessions CDATA #IMPLIED
maxTransactions CDATA #IMPLIED
maxRequests CDATA #IMPLIED
defaultStatementTimeout CDATA #IMPLIED
>
<!ELEMENT transactionManager (property*,dataSource)>
<!ATTLIST transactionManager
type CDATA #REQUIRED
commitRequired (true | false) #IMPLIED
>
<!ELEMENT dataSource (property*)>
<!ATTLIST dataSource
type CDATA #REQUIRED
>
<!ELEMENT property EMPTY>
<!ATTLIST property
name CDATA #REQUIRED
value CDATA #REQUIRED
>
<!ELEMENT sqlMap EMPTY>
<!ATTLIST sqlMap
resource CDATA #IMPLIED
url CDATA #IMPLIED
>
<!ELEMENT typeAlias EMPTY>
<!ATTLIST typeAlias
alias CDATA #REQUIRED
type CDATA #REQUIRED
>
<!ELEMENT typeHandler EMPTY>
<!ATTLIST typeHandler
javaType CDATA #REQUIRED
jdbcType CDATA #IMPLIED
callback CDATA #REQUIRED
>
<!ELEMENT resultObjectFactory (property*)>
<!ATTLIST resultObjectFactory
type CDATA #REQUIRED
>