001: /*
002: * Copyright 2007 The Kuali Foundation
003: *
004: * Licensed under the Educational Community License, Version 1.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.opensource.org/licenses/ecl1.php
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.kuali.rice.database;
017:
018: import java.util.ArrayList;
019: import java.util.List;
020:
021: import javax.naming.NamingException;
022: import javax.sql.DataSource;
023: import javax.transaction.TransactionManager;
024:
025: import org.apache.commons.lang.StringUtils;
026: import org.kuali.rice.config.Config;
027: import org.kuali.rice.config.ConfigurationException;
028: import org.kuali.rice.core.Core;
029: import org.kuali.rice.lifecycle.Lifecycle;
030: import org.springframework.beans.factory.config.AbstractFactoryBean;
031: import org.springframework.jndi.JndiTemplate;
032:
033: /**
034: * A class that can be used to load the primary datasource for a Rice module
035: * from an object in the Config system or from a JNDI url specified by the
036: * Configuration system. By default, it loads these values from the
037: * follwing properties:
038: *
039: * <ul>
040: * <li>{@link Config#DATASOURCE_OBJ}</li>
041: * <li>{@link Config#DATASOURCE_JNDI}</li>
042: * </ul>
043: *
044: * <p>The config properties checked can be overridden by setting the
045: *
046: *
047: * @author Kuali Rice Team (kuali-rice@googlegroups.com)
048: */
049: public class PrimaryDataSourceFactoryBean extends AbstractFactoryBean {
050:
051: private static final String DEFAULT_DATASOURCE_PARAM = Config.DATASOURCE_OBJ;
052: private static final String DEFAULT_DATASOURCE_JNDI_PARAM = Config.DATASOURCE_JNDI;
053:
054: private TransactionManager transactionManager;
055: private JndiTemplate jndiTemplate;
056: private String defaultDataSourceParam = DEFAULT_DATASOURCE_PARAM;
057: private String defaultDataSourceJndiParam = DEFAULT_DATASOURCE_JNDI_PARAM;
058: private List<String> preferredDataSourceParams = new ArrayList<String>();
059: private List<String> preferredDataSourceJndiParams = new ArrayList<String>();
060:
061: public PrimaryDataSourceFactoryBean() {
062: setSingleton(true);
063: }
064:
065: public Class getObjectType() {
066: return DataSource.class;
067: }
068:
069: @Override
070: protected Object createInstance() throws Exception {
071: Config config = Core.getCurrentContextConfig();
072: DataSource dataSource = createDataSource(config);
073: if (dataSource != null) {
074: return dataSource;
075: }
076: if (this .transactionManager == null) {
077: throw new ConfigurationException(
078: "A transactionManager must be specified!");
079: }
080: return createDefaultDataSource(config, this .transactionManager);
081: }
082:
083: protected DataSource createDataSource(Config config)
084: throws Exception {
085: DataSource dataSource = loadPreferredDataSourceFromConfig(config);
086: if (dataSource == null) {
087: Object dataSourceObject = config
088: .getObject(getDefaultDataSourceParam());
089: if (dataSourceObject != null) {
090: validateDataSource(getDefaultDataSourceParam(),
091: dataSourceObject);
092: dataSource = (DataSource) dataSourceObject;
093: } else {
094: dataSource = getDataSourceFromJndi(config,
095: getDefaultDataSourceJndiParam());
096: }
097: }
098: return dataSource;
099: }
100:
101: protected DataSource loadPreferredDataSourceFromConfig(Config config) {
102: for (String dataSourceParam : getPreferredDataSourceParams()) {
103: Object dataSource = config.getObject(dataSourceParam);
104: if (dataSource != null) {
105: validateDataSource(dataSourceParam, dataSource);
106: return (DataSource) dataSource;
107: }
108: }
109: if (this .jndiTemplate == null) {
110: this .jndiTemplate = new JndiTemplate();
111: }
112: for (String dataSourceJndiParam : getPreferredDataSourceJndiParams()) {
113: DataSource dataSource = getDataSourceFromJndi(config,
114: dataSourceJndiParam);
115: if (dataSource != null) {
116: return dataSource;
117: }
118: }
119: return null;
120: }
121:
122: protected void validateDataSource(String paramName,
123: Object dataSourceObject) {
124: if (!(dataSourceObject instanceof DataSource)) {
125: throw new ConfigurationException(
126: "DataSource configured for parameter '"
127: + paramName
128: + "' was not an instance of DataSource. Was instead "
129: + dataSourceObject.getClass().getName());
130: }
131: }
132:
133: protected DataSource getDataSourceFromJndi(Config config,
134: String dataSourceJndiParam) {
135: String jndiName = config.getProperty(dataSourceJndiParam);
136: if (!StringUtils.isBlank(jndiName)) {
137: try {
138: Object dataSource = getJndiTemplate().lookup(jndiName,
139: DataSource.class);
140: if (dataSource != null) {
141: validateDataSource(dataSourceJndiParam, dataSource);
142: return (DataSource) dataSource;
143: }
144: } catch (NamingException e) {
145: throw new ConfigurationException(
146: "Could not locate the DataSource at the given JNDI location: '"
147: + jndiName + "'", e);
148: }
149: }
150: return null;
151: }
152:
153: protected DataSource createDefaultDataSource(Config config,
154: TransactionManager transactionManager) throws Exception {
155: XAPoolDataSource dataSource = new XAPoolDataSource();
156: dataSource.setTransactionManager(transactionManager);
157:
158: dataSource.setDriverClassName(getStringProperty(config,
159: Config.DATASOURCE_DRIVER_NAME));
160: dataSource.setUrl(getStringProperty(config,
161: Config.DATASOURCE_URL));
162: dataSource.setMaxSize(getIntProperty(config,
163: Config.DATASOURCE_POOL_MAXSIZE));
164: dataSource.setMinSize(getIntProperty(config,
165: Config.DATASOURCE_POOL_MINSIZE));
166: dataSource.setMaxWait(getIntProperty(config,
167: Config.DATASOURCE_POOL_MAXWAIT));
168: dataSource.setValidationQuery(getStringProperty(config,
169: Config.DATASOURCE_POOL_VALIDATION_QUERY));
170: dataSource.setUsername(getStringProperty(config,
171: Config.DATASOURCE_USERNAME));
172: dataSource.setPassword(getStringProperty(config,
173: Config.DATASOURCE_PASSWORD));
174:
175: dataSource.afterPropertiesSet();
176:
177: return dataSource;
178: }
179:
180: protected void destroyInstance(Object instance) throws Exception {
181: if (instance instanceof Lifecycle) {
182: ((Lifecycle) instance).stop();
183: }
184: }
185:
186: protected String getStringProperty(Config config,
187: String propertyName) {
188: String data = config.getProperty(propertyName);
189: if (StringUtils.isEmpty(data)) {
190: throw new ConfigurationException(
191: "Could not locate a value for the given property '"
192: + propertyName + "'.");
193: }
194: return data;
195: }
196:
197: protected int getIntProperty(Config config, String propertyName) {
198: String data = getStringProperty(config, propertyName);
199: try {
200: int intData = Integer.parseInt(data);
201: return intData;
202: } catch (NumberFormatException e) {
203: throw new ConfigurationException("The given property '"
204: + propertyName
205: + "' was not a valid integer. Value was '" + data
206: + "'");
207: }
208: }
209:
210: public void setTransactionManager(
211: TransactionManager transactionManager) {
212: this .transactionManager = transactionManager;
213: }
214:
215: public JndiTemplate getJndiTemplate() {
216: return this .jndiTemplate;
217: }
218:
219: public void setJndiTemplate(JndiTemplate jndiTemplate) {
220: this .jndiTemplate = jndiTemplate;
221: }
222:
223: public String getDefaultDataSourceJndiParam() {
224: return defaultDataSourceJndiParam;
225: }
226:
227: public void setDefaultDataSourceJndiParam(
228: String defaultDataSourceJndiParam) {
229: this .defaultDataSourceJndiParam = defaultDataSourceJndiParam;
230: }
231:
232: public String getDefaultDataSourceParam() {
233: return defaultDataSourceParam;
234: }
235:
236: public void setDefaultDataSourceParam(String defaultDataSourceParam) {
237: this .defaultDataSourceParam = defaultDataSourceParam;
238: }
239:
240: public List<String> getPreferredDataSourceJndiParams() {
241: return preferredDataSourceJndiParams;
242: }
243:
244: public void setPreferredDataSourceJndiParams(
245: List<String> preferredDataSourceJndiParams) {
246: this .preferredDataSourceJndiParams = preferredDataSourceJndiParams;
247: }
248:
249: public List<String> getPreferredDataSourceParams() {
250: return preferredDataSourceParams;
251: }
252:
253: public void setPreferredDataSourceParams(
254: List<String> preferredDataSourceParams) {
255: this.preferredDataSourceParams = preferredDataSourceParams;
256: }
257:
258: }
|