001: /*
002: * The contents of this file are subject to the Sapient Public License
003: * Version 1.0 (the "License"); you may not use this file except in compliance
004: * with the License. You may obtain a copy of the License at
005: * http://carbon.sf.net/License.html.
006: *
007: * Software distributed under the License is distributed on an "AS IS" basis,
008: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
009: * the specific language governing rights and limitations under the License.
010: *
011: * The Original Code is The Carbon Component Framework.
012: *
013: * The Initial Developer of the Original Code is Sapient Corporation
014: *
015: * Copyright (C) 2003 Sapient Corporation. All Rights Reserved.
016: */
017:
018: package org.sape.carbon.services.sqldataloader.total;
019:
020: import org.apache.commons.logging.Log;
021: import org.apache.commons.logging.LogFactory;
022:
023: import java.lang.reflect.Constructor;
024: import java.lang.reflect.InvocationTargetException;
025: import java.sql.Connection;
026: import java.sql.PreparedStatement;
027: import java.sql.ResultSet;
028: import java.sql.SQLException;
029: import java.util.Comparator;
030: import java.util.Iterator;
031: import java.util.Map;
032: import java.util.Set;
033:
034: import org.sape.carbon.core.component.ComponentConfiguration;
035: import org.sape.carbon.core.component.lifecycle.Configurable;
036: import org.sape.carbon.core.config.InvalidConfigurationException;
037: import org.sape.carbon.core.util.reflection.BeanUtil;
038: import org.sape.carbon.services.cache.CacheLoadException;
039: import org.sape.carbon.services.cache.total.ConfigurableMapTypeCacheDataLoader;
040:
041: /**
042: * <p>Class provides a generic lookup class to users with a mechanism to cache
043: * data retreived from a table. The object containing the data, query
044: * retreiving the data and the key for the cache are all configurable
045: * propertied read from the component configuration file.
046: * </p>
047: *
048: * <p> It reads the data from database using the configured query and loads
049: * it into Javabean objects which are then stored in cache. </p>
050: * @see SqlBeanDataLoaderConfiguration
051: *
052: * Copyright 2003 Sapient
053: * @since carbon 2.1
054: * @author Akash Tayal, May 2003
055: * @version $Revision: 1.1 $($Author: ghinkl $ / $Date: 2003/09/30 02:08:19 $)
056: */
057: public class SqlBeanDataLoader implements
058: ConfigurableMapTypeCacheDataLoader, Configurable {
059:
060: /** The handle to Apache-commons logger */
061: private Log log = LogFactory.getLog(this .getClass());
062:
063: /** Reference to configuration document */
064: protected SqlBeanDataLoaderConfiguration config = null;
065:
066: /**
067: * Configure the component. This is preceded and followed by the suspend
068: * and resume operations if they are available on the component.
069: *
070: * @param configuration A GenericTotalCacheDataLoaderConfiguration
071: */
072: public void configure(ComponentConfiguration configuration) {
073: this .config = (SqlBeanDataLoaderConfiguration) configuration;
074: }
075:
076: /**
077: * <p>Creates and executes the PreparedStatement to retrieve data from
078: * database. This method abstracts out the creation and execution of SQL
079: * statement. </p>
080: * <p> You can extend this class and provide implementation for this
081: * method in case you want to retrieve data using callable statement.
082: * </p>
083: *
084: * @param connection Connection to the database
085: * @return ResultSet of retrieved data
086: * @throws CacheLoadException in case there is some error in loading
087: * the data
088: */
089: protected ResultSet retrieveResult(Connection connection)
090: throws SQLException {
091:
092: PreparedStatement preparedStatement = connection
093: .prepareStatement(config.getDataLoadQuery());
094: ResultSet resultSet = preparedStatement.executeQuery();
095: return resultSet;
096: }
097:
098: /**
099: * <p>Loads the cache with data elements.
100: * Executes the configured SQL query and loads the data into
101: * configured bean. </p>
102: *
103: * <p>Reads the configuration to retrieve a map of db columns and bean
104: * attributes. Reads the value for each column from database and populates
105: * it into the mapping bean attributes. </p>
106: *
107: * @return Map of cached data
108: * @throws CacheLoadException in case there is some error in loading
109: * the data
110: */
111: public Map loadAllData() throws CacheLoadException {
112: Connection connection = null;
113: String beanAttributeName = null;
114: try {
115:
116: // Obtaining the connection
117: connection = (config.getConnectionFactory())
118: .getConnection();
119:
120: // Retrieving the result from database
121: ResultSet resultSet = retrieveResult(connection);
122:
123: // Creating the map based on implmentation provided
124: Map returnMap = getMapInstance();
125:
126: // Reading the mapping of db column name to bean attribute
127: Set attributeSet = (config.getBeanAttribute()).entrySet();
128:
129: while (resultSet.next()) {
130: Object key = resultSet.getObject(config.getKeyColumn());
131: Object bean;
132: try {
133: bean = (config.getBeanClass()).newInstance();
134: } catch (IllegalAccessException iae) {
135: throw new InvalidConfigurationException(this
136: .getClass(), this .config
137: .getConfigurationName(), "BeanClass",
138: "Could not create instance of lookup bean",
139: iae);
140: } catch (InstantiationException ie) {
141: throw new InvalidConfigurationException(this
142: .getClass(), this .config
143: .getConfigurationName(), "BeanClass",
144: "Could not create instance of lookup bean",
145: ie);
146: }
147: // Reading each column name from map and retrieving value
148: // from the row of result set.
149: Iterator attributeIterator = attributeSet.iterator();
150:
151: while (attributeIterator.hasNext()) {
152: Map.Entry attribute = (Map.Entry) attributeIterator
153: .next();
154: String columnName = (String) attribute.getKey();
155: beanAttributeName = (String) attribute.getValue();
156: log.info("BEAN DATA LOADER COLUMN NAME IS "
157: + columnName);
158: log.info("BEAN DATA LOADER ATTRIBUTE NAME IS "
159: + beanAttributeName);
160: log.info("DATA TYPE OF COLUMN IS "
161: + resultSet.getObject(columnName)
162: .getClass());
163: BeanUtil.setObjectAttribute(bean,
164: beanAttributeName, resultSet
165: .getObject(columnName));
166: }
167: returnMap.put(key, bean);
168: }
169: return returnMap;
170: } catch (IllegalArgumentException iarge) {
171: throw new InvalidConfigurationException(this .getClass(),
172: this .config.getConfigurationName(),
173: "BeanAttribute", "Bean attribute type for "
174: + beanAttributeName
175: + " and db column type do not match", iarge);
176: } catch (IllegalAccessException iae) {
177: throw new InvalidConfigurationException(this .getClass(),
178: this .config.getConfigurationName(),
179: "BeanAttribute", "Could not set attribute "
180: + beanAttributeName + " in bean class", iae);
181: } catch (NoSuchMethodException nsme) {
182: throw new InvalidConfigurationException(this .getClass(),
183: this .config.getConfigurationName(),
184: "BeanAttribute", "Could not set attribute "
185: + beanAttributeName + " in bean class",
186: nsme);
187: } catch (InvocationTargetException ite) {
188: throw new InvalidConfigurationException(this .getClass(),
189: this .config.getConfigurationName(),
190: "BeanAttribute", "Could not set attribute "
191: + beanAttributeName + " in bean class", ite);
192: } catch (SQLException sqle) {
193: throw new CacheLoadException(getClass(),
194: "Could not load Cache from database", sqle);
195: } finally {
196: if (connection != null) {
197: try {
198: connection.close();
199: } catch (SQLException sqle) {
200: // eating the exception
201: }
202: }
203: }
204: }
205:
206: /**
207: * <p>Returns an instance of configured map implementation.
208: * This method just returns a new and blank instance.
209: * In case comparator is defined for the map, the appropriate
210: * constructor of the map implementation is used to create the
211: * new instance. </p>
212: * <p> Please note that the new map instance is not synchronized in
213: * this method. As required the synchronization takes place in the
214: * <code>WritableCache</code> </p>
215: *
216: * @return Map instance
217: */
218: public Map getMapInstance() {
219:
220: Map returnMap;
221: // if comparator implementation to be used is specified
222: if (this .config.getComparator() != null) {
223: Class[] constructorParameters = new Class[] { Comparator.class };
224: Object[] constructorArguments;
225: try {
226: constructorArguments = new Object[] { (config
227: .getComparator()).newInstance() };
228: } catch (IllegalAccessException iae) {
229: throw new InvalidConfigurationException(
230: this .getClass(), this .config
231: .getConfigurationName(), "Comparator",
232: "Could not instantiate comparator instance",
233: iae);
234: } catch (InstantiationException ie) {
235: throw new InvalidConfigurationException(
236: this .getClass(), this .config
237: .getConfigurationName(), "Comparator",
238: "Could not instantiate comparator instance", ie);
239: }
240: try {
241: Constructor constr = (config.getMapType())
242: .getConstructor(constructorParameters);
243: returnMap = (Map) constr
244: .newInstance(constructorArguments);
245: } catch (IllegalAccessException iae) {
246: throw new InvalidConfigurationException(
247: this .getClass(), this .config
248: .getConfigurationName(), "MapType",
249: "Could not instantiate map instance", iae);
250: } catch (NoSuchMethodException nsme) {
251: throw new InvalidConfigurationException(
252: this .getClass(), this .config
253: .getConfigurationName(), "MapType",
254: "Could not instantiate map instance", nsme);
255: } catch (InstantiationException ie) {
256: throw new InvalidConfigurationException(
257: this .getClass(), this .config
258: .getConfigurationName(), "MapType",
259: "Could not instantiate map instance", ie);
260: } catch (InvocationTargetException ite) {
261: throw new InvalidConfigurationException(
262: this .getClass(), this .config
263: .getConfigurationName(), "MapType",
264: "Could not instantiate map instance", ite);
265: }
266: } else {
267: // No Comparator implementation was specified
268: try {
269: if (log.isTraceEnabled()) {
270: log
271: .trace("No Comparator implementation was provided. "
272: + "Creating map instance without comparator of type "
273: + config.getMapType().getName());
274: }
275: returnMap = (Map) (config.getMapType()).newInstance();
276: } catch (IllegalAccessException iae) {
277: throw new InvalidConfigurationException(
278: this .getClass(), this .config
279: .getConfigurationName(), "MapType",
280: "Could not instantiate map instance", iae);
281: } catch (InstantiationException ie) {
282: throw new InvalidConfigurationException(
283: this .getClass(), this .config
284: .getConfigurationName(), "MapType",
285: "Could not instantiate map instance", ie);
286: }
287: }
288: return returnMap;
289: }
290:
291: }
|