1. /*
  2. * Copyright 2002-2004 the original author or authors.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package org.springframework.orm.ibatis;
  17. import java.io.IOException;
  18. import java.io.InputStream;
  19. import java.io.InputStreamReader;
  20. import java.util.Properties;
  21. import javax.sql.DataSource;
  22. import com.ibatis.sqlmap.client.SqlMapClient;
  23. import com.ibatis.sqlmap.client.SqlMapClientBuilder;
  24. import com.ibatis.sqlmap.engine.impl.ExtendedSqlMapClient;
  25. import com.ibatis.sqlmap.engine.transaction.TransactionManager;
  26. import com.ibatis.sqlmap.engine.transaction.external.ExternalTransactionConfig;
  27. import org.springframework.beans.factory.FactoryBean;
  28. import org.springframework.beans.factory.InitializingBean;
  29. import org.springframework.core.io.Resource;
  30. /**
  31. * FactoryBean that creates an iBATIS Database Layer SqlMapClient as singleton
  32. * in the current bean factory, possibly for use with SqlMapClientTemplate.
  33. *
  34. * <p>Allows to specify a DataSource at the SqlMapClient level. This is
  35. * preferable to per-DAO DataSource references, as it allows for lazy loading
  36. * and avoids repeated DataSource references.
  37. *
  38. * <p>NOTE: The SqlMapClient/SqlMapSession API is the API of iBATIS SQL Maps 2.
  39. * With SQL Maps 1.x, the SqlMap/MappedStatement API has to be used.
  40. *
  41. * @author Juergen Hoeller
  42. * @since 24.02.2004
  43. * @see #setConfigLocation
  44. * @see #setDataSource
  45. * @see SqlMapClientTemplate#setSqlMapClient
  46. * @see SqlMapClientTemplate#setDataSource
  47. */
  48. public class SqlMapClientFactoryBean implements FactoryBean, InitializingBean {
  49. private Resource configLocation;
  50. private Properties sqlMapClientProperties;
  51. private DataSource dataSource;
  52. private SqlMapClient sqlMapClient;
  53. /**
  54. * Set the location of the iBATIS SqlMapClient config file as class path resource.
  55. * A typical value is "WEB-INF/sql-map-config.xml".
  56. */
  57. public void setConfigLocation(Resource configLocation) {
  58. this.configLocation = configLocation;
  59. }
  60. /**
  61. * Set optional properties to be passed into the SqlMapClientBuilder.
  62. * @see com.ibatis.sqlmap.client.SqlMapClientBuilder#buildSqlMapClient(java.io.Reader, java.util.Properties)
  63. */
  64. public void setSqlMapClientProperties(Properties sqlMapClientProperties) {
  65. this.sqlMapClientProperties = sqlMapClientProperties;
  66. }
  67. /**
  68. * Set the DataSource to be used by the SqlMapClient. If specified, this
  69. * will override corresponding settings in the SqlMapClient properties.
  70. * <p>Specifying a DataSource for the SqlMapClient rather than for each
  71. * individual DAO allows for lazy loading, for example when using
  72. * PaginatedList results.
  73. * <p>With a DataSource passed in here, you don't need to specify one
  74. * for each DAO. Passing the SqlMapClient to the DAOs is enough, as it
  75. * already carries a DataSource. Thus, it's recommended to specify the
  76. * DataSource at this central location only.
  77. * <p>Thanks to Brandon Goodin from the iBATIS team for the hint on
  78. * how to make this work with Spring's integration strategy!
  79. * @see com.ibatis.sqlmap.client.SqlMapClient#getDataSource
  80. * @see SqlMapClientTemplate#setDataSource
  81. * @see SqlMapClientTemplate#queryForPaginatedList
  82. */
  83. public void setDataSource(DataSource dataSource) {
  84. this.dataSource = dataSource;
  85. }
  86. public void afterPropertiesSet() throws IOException {
  87. if (this.configLocation == null) {
  88. throw new IllegalArgumentException("configLocation is required");
  89. }
  90. // build the SqlMapClient
  91. InputStream is = this.configLocation.getInputStream();
  92. this.sqlMapClient = (this.sqlMapClientProperties != null) ?
  93. SqlMapClientBuilder.buildSqlMapClient(new InputStreamReader(is), this.sqlMapClientProperties) :
  94. SqlMapClientBuilder.buildSqlMapClient(new InputStreamReader(is));
  95. // tell the SqlMapClient to use the given DataSource, if any
  96. if (this.dataSource != null) {
  97. if (!(this.sqlMapClient instanceof ExtendedSqlMapClient)) {
  98. throw new IllegalArgumentException("Cannot set DataSource for SqlMapClient " +
  99. "if not of type ExtendedSqlMapClient");
  100. }
  101. ExtendedSqlMapClient extendedClient = (ExtendedSqlMapClient) this.sqlMapClient;
  102. ExternalTransactionConfig transactionConfig = new ExternalTransactionConfig();
  103. transactionConfig.setDataSource(this.dataSource);
  104. transactionConfig.setMaximumConcurrentTransactions(extendedClient.getDelegate().getMaxTransactions());
  105. extendedClient.getDelegate().setTxManager(new TransactionManager(transactionConfig));
  106. }
  107. }
  108. public Object getObject() {
  109. return this.sqlMapClient;
  110. }
  111. public Class getObjectType() {
  112. return (this.sqlMapClient != null ? this.sqlMapClient.getClass() : SqlMapClient.class);
  113. }
  114. public boolean isSingleton() {
  115. return true;
  116. }
  117. }