View Javadoc

1   /*
2    * Copyright 2001-2004 The Apache Software Foundation.
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  
17  package org.apache.commons.beanutils;
18  
19  import java.io.Serializable;
20  import java.sql.ResultSet;
21  import java.sql.ResultSetMetaData;
22  import java.sql.SQLException;
23  import java.util.ArrayList;
24  import java.util.HashMap;
25  import java.util.Map;
26  
27  /**
28   * <p>Provides common logic for JDBC implementations of {@link DynaClass}.</p>
29   *
30   * @author   Craig R. McClanahan
31   * @author   George Franciscus
32   * @version $Revision: 1.4 $ $Date: 2004/02/28 13:18:33 $
33   */
34  
35  abstract class JDBCDynaClass implements DynaClass, Serializable {
36  
37      // ----------------------------------------------------- Instance Variables
38  
39      /**
40       * <p>Flag defining whether column names should be lower cased when
41       * converted to property names.</p>
42       */
43      protected boolean lowerCase = true;
44  
45      /**
46       * <p>The set of dynamic properties that are part of this
47       * {@link DynaClass}.</p>
48       */
49      protected DynaProperty properties[] = null;
50  
51      /**
52       * <p>The set of dynamic properties that are part of this
53       * {@link DynaClass}, keyed by the property name.  Individual descriptor
54       * instances will be the same instances as those in the
55       * <code>properties</code> list.</p>
56       */
57      protected Map propertiesMap = new HashMap();
58  
59      // ------------------------------------------------------ DynaClass Methods
60  
61      /**
62       * <p>Return the name of this DynaClass (analogous to the
63       * <code>getName()</code> method of <code>java.lang.Class</code), which
64       * allows the same <code>DynaClass</code> implementation class to support
65       * different dynamic classes, with different sets of properties.</p>
66       */
67      public String getName() {
68  
69          return (this.getClass().getName());
70  
71      }
72  
73      /**
74       * <p>Return a property descriptor for the specified property, if it
75       * exists; otherwise, return <code>null</code>.</p>
76       *
77       * @param name Name of the dynamic property for which a descriptor
78       *  is requested
79       *
80       * @exception IllegalArgumentException if no property name is specified
81       */
82      public DynaProperty getDynaProperty(String name) {
83  
84          if (name == null) {
85              throw new IllegalArgumentException("No property name specified");
86          }
87          return ((DynaProperty) propertiesMap.get(name));
88  
89      }
90  
91      /**
92       * <p>Return an array of <code>ProperyDescriptors</code> for the properties
93       * currently defined in this DynaClass.  If no properties are defined, a
94       * zero-length array will be returned.</p>
95       */
96      public DynaProperty[] getDynaProperties() {
97  
98          return (properties);
99  
100     }
101 
102     /**
103      * <p>Instantiate and return a new DynaBean instance, associated
104      * with this DynaClass.  <strong>NOTE</strong> - This operation is not
105      * supported, and throws an exception.</p>
106      *
107      * @exception IllegalAccessException if the Class or the appropriate
108      *  constructor is not accessible
109      * @exception InstantiationException if this Class represents an abstract
110      *  class, an array class, a primitive type, or void; or if instantiation
111      *  fails for some other reason
112      */
113     public DynaBean newInstance()
114             throws IllegalAccessException, InstantiationException {
115 
116         throw new UnsupportedOperationException("newInstance() not supported");
117 
118     }
119 
120     /**
121      * <p>Loads and returns the <code>Class</code> of the given name.
122      * By default, a load from the thread context class loader is attempted.
123      * If there is no such class loader, the class loader used to load this
124      * class will be utilized.</p>
125      *
126      * @exception SQLException if an exception was thrown trying to load
127      *  the specified class
128      */
129     protected Class loadClass(String className) throws SQLException {
130 
131         try {
132             ClassLoader cl = Thread.currentThread().getContextClassLoader();
133             if (cl == null) {
134                     cl = this.getClass().getClassLoader();
135             }
136             return (cl.loadClass(className));
137         } catch (Exception e) {
138             throw new SQLException(
139                     "Cannot load column class '" + className + "': " + e);
140         }
141 
142     }
143 
144     /**
145      * <p>Factory method to create a new DynaProperty for the given index
146      * into the result set metadata.</p>
147      * 
148      * @param metadata is the result set metadata
149      * @param i is the column index in the metadata
150      * @return the newly created DynaProperty instance
151      */
152     protected DynaProperty createDynaProperty(
153                                     ResultSetMetaData metadata,
154                                     int i)
155                                     throws SQLException {
156 
157         String name = null;
158         if (lowerCase) {
159             name = metadata.getColumnName(i).toLowerCase();
160         } else {
161             name = metadata.getColumnName(i);
162         }
163         String className = null;
164         try {
165             className = metadata.getColumnClassName(i);
166         } catch (SQLException e) {
167             // this is a patch for HsqlDb to ignore exceptions
168             // thrown by its metadata implementation
169         }
170 
171         // Default to Object type if no class name could be retrieved
172         // from the metadata
173         Class clazz = Object.class;
174         if (className != null) {
175             clazz = loadClass(className);
176         }
177         return new DynaProperty(name, clazz);
178 
179     }
180 
181     /**
182      * <p>Introspect the metadata associated with our result set, and populate
183      * the <code>properties</code> and <code>propertiesMap</code> instance
184      * variables.</p>
185      *
186      * @param resultSet The <code>resultSet</code> whose metadata is to
187      *  be introspected
188      *
189      * @exception SQLException if an error is encountered processing the
190      *  result set metadata
191      */
192     protected void introspect(ResultSet resultSet) throws SQLException {
193 
194         // Accumulate an ordered list of DynaProperties
195         ArrayList list = new ArrayList();
196         ResultSetMetaData metadata = resultSet.getMetaData();
197         int n = metadata.getColumnCount();
198         for (int i = 1; i <= n; i++) { // JDBC is one-relative!
199             DynaProperty dynaProperty = createDynaProperty(metadata, i);
200             if (dynaProperty != null) {
201                     list.add(dynaProperty);
202             }
203         }
204 
205         // Convert this list into the internal data structures we need
206         properties =
207             (DynaProperty[]) list.toArray(new DynaProperty[list.size()]);
208         for (int i = 0; i < properties.length; i++) {
209             propertiesMap.put(properties[i].getName(), properties[i]);
210         }
211 
212     }
213 
214 }