1 package com.ibatis.sqlmap.engine.builder.xml; 2 3 import com.ibatis.common.resources.Resources; 4 import com.ibatis.common.xml.Nodelet; 5 import com.ibatis.common.xml.NodeletParser; 6 import com.ibatis.common.xml.NodeletUtils; 7 import com.ibatis.common.exception.NestedRuntimeException; 8 import com.ibatis.sqlmap.client.SqlMapClient; 9 import com.ibatis.sqlmap.client.SqlMapException; 10 import com.ibatis.sqlmap.client.extensions.TypeHandlerCallback; 11 import com.ibatis.sqlmap.engine.accessplan.AccessPlanFactory; 12 import com.ibatis.sqlmap.engine.cache.CacheModel; 13 import com.ibatis.sqlmap.engine.cache.fifo.FifoCacheController; 14 import com.ibatis.sqlmap.engine.cache.lru.LruCacheController; 15 import com.ibatis.sqlmap.engine.cache.memory.MemoryCacheController; 16 import com.ibatis.sqlmap.engine.datasource.DataSourceFactory; 17 import com.ibatis.sqlmap.engine.datasource.DbcpDataSourceFactory; 18 import com.ibatis.sqlmap.engine.datasource.JndiDataSourceFactory; 19 import com.ibatis.sqlmap.engine.datasource.SimpleDataSourceFactory; 20 import com.ibatis.sqlmap.engine.impl.SqlMapClientImpl; 21 import com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate; 22 import com.ibatis.sqlmap.engine.mapping.statement.MappedStatement; 23 import com.ibatis.sqlmap.engine.transaction.TransactionConfig; 24 import com.ibatis.sqlmap.engine.transaction.TransactionManager; 25 import com.ibatis.sqlmap.engine.transaction.external.ExternalTransactionConfig; 26 import com.ibatis.sqlmap.engine.transaction.jdbc.JdbcTransactionConfig; 27 import com.ibatis.sqlmap.engine.transaction.jta.JtaTransactionConfig; 28 import com.ibatis.sqlmap.engine.type.*; 29 import org.w3c.dom.Node ; 30 31 import java.io.Reader ; 32 import java.util.Iterator ; 33 import java.util.Properties ; 34 35 public class SqlMapConfigParser extends BaseParser { 36 37 private final NodeletParser parser = new NodeletParser(); 38 39 public SqlMapConfigParser() { 40 this(null, null); 41 } 42 43 public SqlMapConfigParser(XmlConverter sqlMapConfigConv, XmlConverter sqlMapConv) { 44 super(new Variables()); 45 parser.setValidation(true); 46 parser.setEntityResolver(new SqlMapClasspathEntityResolver()); 47 48 vars.sqlMapConfigConv = sqlMapConfigConv; 49 vars.sqlMapConv = sqlMapConv; 50 51 vars.delegate = new SqlMapExecutorDelegate(); 52 vars.typeHandlerFactory = vars.delegate.getTypeHandlerFactory(); 53 vars.client = new SqlMapClientImpl(vars.delegate); 54 55 registerDefaultTypeAliases(); 56 57 addSqlMapConfigNodelets(); 58 addGlobalPropNodelets(); 59 addSettingsNodelets(); 60 addTypeAliasNodelets(); 61 addTypeHandlerNodelets(); 62 addTransactionManagerNodelets(); 63 addSqlMapNodelets(); 64 65 } 66 67 public SqlMapClient parse(Reader reader, Properties props) { 68 vars.properties = props; 69 return parse(reader); 70 } 71 72 public SqlMapClient parse(Reader reader) { 73 try { 74 if (vars.sqlMapConfigConv != null) { 75 reader = vars.sqlMapConfigConv.convertXml(reader); 76 } 77 78 parser.parse(reader); 79 return vars.client; 80 } catch (Exception e) { 81 throw new NestedRuntimeException("Error occurred. Cause: " + e, e); 82 } 83 } 84 85 private void addSqlMapConfigNodelets() { 86 parser.addNodelet("/sqlMapConfig/end()", new Nodelet() { 87 public void process(Node node) throws Exception { 88 Iterator cacheNames = vars.client.getDelegate().getCacheModelNames(); 89 90 while (cacheNames.hasNext()) { 91 String cacheName = (String ) cacheNames.next(); 92 CacheModel cacheModel = vars.client.getDelegate().getCacheModel(cacheName); 93 Iterator statementNames = cacheModel.getFlushTriggerStatementNames(); 94 while (statementNames.hasNext()) { 95 String statementName = (String ) statementNames.next(); 96 MappedStatement statement = vars.client.getDelegate().getMappedStatement(statementName); 97 if (statement != null) { 98 statement.addExecuteListener(cacheModel); 99 } else { 100 throw new NestedRuntimeException("Could not find statement named '" + statementName + "' for use as a flush trigger for the cache model named '" + cacheName + "'."); 101 } 102 } 103 } 104 } 105 }); 106 } 107 108 private void addGlobalPropNodelets() { 109 parser.addNodelet("/sqlMapConfig/properties", new Nodelet() { 110 public void process(Node node) throws Exception { 111 vars.errorCtx.setActivity("loading global properties"); 112 113 Properties attributes = NodeletUtils.parseAttributes(node); 114 String resource = attributes.getProperty("resource"); 115 String url = attributes.getProperty("url"); 116 117 try { 118 Properties props = null; 119 if (resource != null) { 120 vars.errorCtx.setResource(resource); 121 props = Resources.getResourceAsProperties(resource); 122 } else if (url != null) { 123 vars.errorCtx.setResource(url); 124 props = Resources.getUrlAsProperties(url); 125 } else { 126 throw new NestedRuntimeException("The " + "properties" + " element requires either a resource or a url attribute."); 127 } 128 129 if (vars.properties == null) { 130 vars.properties = props; 131 } else { 132 props.putAll(vars.properties); 133 vars.properties = props; 134 } 135 } catch (Exception e) { 136 throw new NestedRuntimeException("Error loading properties. Cause: " + e); 137 } 138 } 139 }); 140 } 141 142 private void addSettingsNodelets() { 143 parser.addNodelet("/sqlMapConfig/settings", new Nodelet() { 144 public void process(Node node) throws Exception { 145 vars.errorCtx.setActivity("loading settings properties"); 146 147 Properties attributes = NodeletUtils.parseAttributes(node, vars.properties); 148 149 String lazyLoadingEnabledAttr = attributes.getProperty("lazyLoadingEnabled"); 150 boolean lazyLoadingEnabled = (lazyLoadingEnabledAttr == null || "true".equals(lazyLoadingEnabledAttr)); 151 vars.client.getDelegate().setLazyLoadingEnabled(lazyLoadingEnabled); 152 153 String cacheModelsEnabledAttr = attributes.getProperty("cacheModelsEnabled"); 154 boolean cacheModelsEnabled = (cacheModelsEnabledAttr == null || "true".equals(cacheModelsEnabledAttr)); 155 vars.client.getDelegate().setCacheModelsEnabled(cacheModelsEnabled); 156 157 String enhancementEnabledAttr = attributes.getProperty("enhancementEnabled"); 158 boolean enhancementEnabled = (enhancementEnabledAttr == null || "true".equals(enhancementEnabledAttr)); 159 try { 160 enhancementEnabled = enhancementEnabled && Class.forName("net.sf.cglib.proxy.InvocationHandler") != null; 161 } catch (ClassNotFoundException e) { 162 enhancementEnabled = false; 163 } 164 vars.client.getDelegate().setEnhancementEnabled(enhancementEnabled); 165 166 String useStatementNamespacesAttr = attributes.getProperty("useStatementNamespaces"); 167 vars.useStatementNamespaces = ("true".equals(useStatementNamespacesAttr)); 168 169 String maxTransactions = attributes.getProperty("maxTransactions"); 170 if (maxTransactions != null && Integer.parseInt(maxTransactions) > 0) { 171 vars.client.getDelegate().setMaxTransactions(Integer.parseInt(maxTransactions)); 172 } 173 174 String maxRequests = attributes.getProperty("maxRequests"); 175 if (maxRequests != null && Integer.parseInt(maxRequests) > 0) { 176 vars.client.getDelegate().setMaxRequests(Integer.parseInt(maxRequests)); 177 } 178 179 String maxSessions = attributes.getProperty("maxSessions"); 180 if (maxSessions != null && Integer.parseInt(maxSessions) > 0) { 181 vars.client.getDelegate().setMaxSessions(Integer.parseInt(maxSessions)); 182 } 183 184 AccessPlanFactory.setBytecodeEnhancementEnabled(vars.client.getDelegate().isEnhancementEnabled()); 185 } 186 }); 187 } 188 189 private void addTypeAliasNodelets() { 190 parser.addNodelet("/sqlMapConfig/typeAlias", new Nodelet() { 191 public void process(Node node) throws Exception { 192 Properties prop = NodeletUtils.parseAttributes(node, vars.properties); 193 String alias = prop.getProperty("alias"); 194 String type = prop.getProperty("type"); 195 vars.typeHandlerFactory.putTypeAlias(alias, type); 196 } 197 }); 198 } 199 200 private void addTypeHandlerNodelets() { 201 parser.addNodelet("/sqlMapConfig/typeHandler", new Nodelet() { 202 public void process(Node node) throws Exception { 203 vars.errorCtx.setActivity("building a building custom type handler"); 204 try { 205 TypeHandlerFactory typeHandlerFactory = vars.client.getDelegate().getTypeHandlerFactory(); 206 207 Properties prop = NodeletUtils.parseAttributes(node, vars.properties); 208 209 String jdbcType = prop.getProperty("jdbcType"); 210 String javaType = prop.getProperty("javaType"); 211 String callback = prop.getProperty("callback"); 212 callback = typeHandlerFactory.resolveAlias(callback); 213 javaType = typeHandlerFactory.resolveAlias(javaType); 214 215 vars.errorCtx.setMoreInfo("Check the callback attribute '" + callback + "' (must be a classname)."); 216 217 TypeHandler typeHandler; 218 Object impl = Resources.classForName(callback).newInstance(); 219 if (impl instanceof TypeHandlerCallback) { 220 typeHandler = new CustomTypeHandler((TypeHandlerCallback) impl); 221 } else if (impl instanceof TypeHandler) { 222 typeHandler = (TypeHandler) impl; 223 } else { 224 throw new NestedRuntimeException ("The class '' is not a valid implementation of TypeHandler or TypeHandlerCallback"); 225 } 226 227 vars.errorCtx.setMoreInfo("Check the javaType attribute '" + javaType + "' (must be a classname) or the jdbcType '" + jdbcType + "' (must be a JDBC type name)."); 228 if (jdbcType != null && jdbcType.length() > 0) { 229 typeHandlerFactory.register(Resources.classForName(javaType), jdbcType, typeHandler); 230 } else { 231 typeHandlerFactory.register(Resources.classForName(javaType), typeHandler); 232 } 233 } catch (Exception e) { 234 throw new SqlMapException("Error registering occurred. Cause: " + e, e); 235 } 236 vars.errorCtx.setMoreInfo(null); 237 vars.errorCtx.setObjectId(null); 238 } 239 }); 240 } 241 242 private void addTransactionManagerNodelets() { 243 parser.addNodelet("/sqlMapConfig/transactionManager/end()", new Nodelet() { 244 public void process(Node node) throws Exception { 245 vars.errorCtx.setActivity("configuring the transaction manager"); 246 247 Properties attributes = NodeletUtils.parseAttributes(node, vars.properties); 248 249 250 String type = attributes.getProperty("type"); 251 type = vars.typeHandlerFactory.resolveAlias(type); 252 253 TransactionManager txManager = null; 254 try { 255 vars.errorCtx.setMoreInfo("Check the transaction manager type or class."); 256 TransactionConfig config = (TransactionConfig) Resources.instantiate(type); 257 config.setDataSource(vars.dataSource); 258 config.setMaximumConcurrentTransactions(vars.client.getDelegate().getMaxTransactions()); 259 vars.errorCtx.setMoreInfo("Check the transactio nmanager properties or configuration."); 260 config.initialize(vars.txProps); 261 vars.errorCtx.setMoreInfo(null); 262 txManager = new TransactionManager(config); 263 txManager.setForceCommit("true".equals(attributes.getProperty("commitRequired"))); 264 } catch (Exception e) { 265 if (e instanceof SqlMapException) { 266 throw (SqlMapException) e; 267 } else { 268 throw new SqlMapException("Error initializing TransactionManager. Could not instantiate TransactionConfig. Cause: " + e, e); 269 } 270 } 271 272 vars.client.getDelegate().setTxManager(txManager); 273 } 274 }); 275 parser.addNodelet("/sqlMapConfig/transactionManager/property", new Nodelet() { 276 public void process(Node node) throws Exception { 277 Properties attributes = NodeletUtils.parseAttributes(node, vars.properties); 278 String name = attributes.getProperty("name"); 279 String value = NodeletUtils.parsePropertyTokens(attributes.getProperty("value"), vars.properties); 280 vars.txProps.setProperty(name, value); 281 } 282 }); 283 parser.addNodelet("/sqlMapConfig/transactionManager/dataSource", new Nodelet() { 284 public void process(Node node) throws Exception { 285 vars.dsProps = new Properties (); 286 } 287 }); 288 parser.addNodelet("/sqlMapConfig/transactionManager/dataSource/end()", new Nodelet() { 289 public void process(Node node) throws Exception { 290 vars.errorCtx.setActivity("configuring the data source"); 291 292 Properties attributes = NodeletUtils.parseAttributes(node); 293 294 String type = attributes.getProperty("type"); 295 type = vars.typeHandlerFactory.resolveAlias(type); 296 297 try { 298 vars.errorCtx.setMoreInfo("Check the data source type or class."); 299 DataSourceFactory dsFactory = (DataSourceFactory) Resources.instantiate(type); 300 vars.errorCtx.setMoreInfo("Check the data source properties or configuration."); 301 dsFactory.initialize(vars.dsProps); 302 vars.dataSource = dsFactory.getDataSource(); 303 vars.errorCtx.setMoreInfo(null); 304 } catch (Exception e) { 305 if (e instanceof SqlMapException) { 306 throw (SqlMapException) e; 307 } else { 308 throw new SqlMapException("Error initializing DataSource. Could not instantiate DataSourceFactory. Cause: " + e, e); 309 } 310 } 311 } 312 }); 313 parser.addNodelet("/sqlMapConfig/transactionManager/dataSource/property", new Nodelet() { 314 public void process(Node node) throws Exception { 315 Properties attributes = NodeletUtils.parseAttributes(node, vars.properties); 316 String name = attributes.getProperty("name"); 317 String value = NodeletUtils.parsePropertyTokens(attributes.getProperty("value"), vars.properties); 318 vars.dsProps.setProperty(name, value); 319 } 320 }); 321 } 322 323 private void addSqlMapNodelets() { 324 parser.addNodelet("/sqlMapConfig/sqlMap", new Nodelet() { 325 public void process(Node node) throws Exception { 326 vars.errorCtx.setActivity("loading the SQL Map resource"); 327 328 Properties attributes = NodeletUtils.parseAttributes(node, vars.properties); 329 330 String resource = attributes.getProperty("resource"); 331 String url = attributes.getProperty("url"); 332 333 Reader reader = null; 334 if (resource != null) { 335 vars.errorCtx.setResource(resource); 336 reader = Resources.getResourceAsReader(resource); 337 } else if (url != null) { 338 vars.errorCtx.setResource(url); 339 reader = Resources.getUrlAsReader(url); 340 } else { 341 throw new SqlMapException("The " + "sqlMap" + " element requires either a resource or a url attribute."); 342 } 343 344 if (vars.sqlMapConv != null) { 345 reader = vars.sqlMapConv.convertXml(reader); 346 } 347 new SqlMapParser(vars).parse(reader); 348 } 349 }); 350 } 351 352 private void registerDefaultTypeAliases() { 353 vars.typeHandlerFactory.putTypeAlias("JDBC", JdbcTransactionConfig.class.getName()); 355 vars.typeHandlerFactory.putTypeAlias("JTA", JtaTransactionConfig.class.getName()); 356 vars.typeHandlerFactory.putTypeAlias("EXTERNAL", ExternalTransactionConfig.class.getName()); 357 358 vars.typeHandlerFactory.putTypeAlias("SIMPLE", SimpleDataSourceFactory.class.getName()); 360 vars.typeHandlerFactory.putTypeAlias("DBCP", DbcpDataSourceFactory.class.getName()); 361 vars.typeHandlerFactory.putTypeAlias("JNDI", JndiDataSourceFactory.class.getName()); 362 363 vars.typeHandlerFactory.putTypeAlias("FIFO", FifoCacheController.class.getName()); 365 vars.typeHandlerFactory.putTypeAlias("LRU", LruCacheController.class.getName()); 366 vars.typeHandlerFactory.putTypeAlias("MEMORY", MemoryCacheController.class.getName()); 367 vars.typeHandlerFactory.putTypeAlias("OSCACHE", "com.ibatis.sqlmap.engine.cache.oscache.OSCacheController"); 369 370 vars.typeHandlerFactory.putTypeAlias("dom", DomTypeMarker.class.getName()); 372 vars.typeHandlerFactory.putTypeAlias("domCollection", DomCollectionTypeMarker.class.getName()); 373 vars.typeHandlerFactory.putTypeAlias("xml", XmlTypeMarker.class.getName()); 374 vars.typeHandlerFactory.putTypeAlias("xmlCollection", XmlCollectionTypeMarker.class.getName()); 375 } 376 377 378 } 379 | Popular Tags |