Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/objectstyle/cayenne/access/util/ResultDescriptor.java


1   /* ====================================================================
2    *
3    * The ObjectStyle Group Software License, Version 1.0
4    *
5    * Copyright (c) 2002-2003 The ObjectStyle Group
6    * and individual authors of the software.  All rights reserved.
7    *
8    * Redistribution and use in source and binary forms, with or without
9    * modification, are permitted provided that the following conditions
10   * are met:
11   *
12   * 1. Redistributions of source code must retain the above copyright
13   *    notice, this list of conditions and the following disclaimer.
14   *
15   * 2. Redistributions in binary form must reproduce the above copyright
16   *    notice, this list of conditions and the following disclaimer in
17   *    the documentation and/or other materials provided with the
18   *    distribution.
19   *
20   * 3. The end-user documentation included with the redistribution, if
21   *    any, must include the following acknowlegement:
22   *       "This product includes software developed by the
23   *        ObjectStyle Group (http://objectstyle.org/)."
24   *    Alternately, this acknowlegement may appear in the software itself,
25   *    if and wherever such third-party acknowlegements normally appear.
26   *
27   * 4. The names "ObjectStyle Group" and "Cayenne"
28   *    must not be used to endorse or promote products derived
29   *    from this software without prior written permission. For written
30   *    permission, please contact andrus@objectstyle.org.
31   *
32   * 5. Products derived from this software may not be called "ObjectStyle"
33   *    nor may "ObjectStyle" appear in their names without prior written
34   *    permission of the ObjectStyle Group.
35   *
36   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39   * DISCLAIMED.  IN NO EVENT SHALL THE OBJECTSTYLE GROUP OR
40   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
43   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
44   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
45   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
46   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47   * SUCH DAMAGE.
48   * ====================================================================
49   *
50   * This software consists of voluntary contributions made by many
51   * individuals on behalf of the ObjectStyle Group.  For more
52   * information on the ObjectStyle Group, please see
53   * <http://objectstyle.org/>.
54   *
55   */
56  package org.objectstyle.cayenne.access.util;
57  
58  import java.sql.ResultSet;
59  import java.sql.ResultSetMetaData;
60  import java.sql.SQLException;
61  import java.util.ArrayList;
62  import java.util.Collection;
63  import java.util.Iterator;
64  import java.util.List;
65  
66  import org.apache.log4j.Logger;
67  import org.objectstyle.cayenne.CayenneRuntimeException;
68  import org.objectstyle.cayenne.access.types.ExtendedType;
69  import org.objectstyle.cayenne.access.types.ExtendedTypeMap;
70  import org.objectstyle.cayenne.dba.TypesMapping;
71  import org.objectstyle.cayenne.map.DbAttribute;
72  import org.objectstyle.cayenne.map.ObjAttribute;
73  import org.objectstyle.cayenne.map.ObjEntity;
74  import org.objectstyle.cayenne.map.Procedure;
75  import org.objectstyle.cayenne.map.ProcedureParameter;
76  
77  /**
78   * Contains information about the ResultSet used to process fetched rows. 
79   * ResultDescriptor is initialized by calling various "add*" methods, after that
80   * it must be indexed by calling "index".
81   * 
82   * @author Andrei Adamchik
83   */
84  public class ResultDescriptor {
85      private static Logger logObj = Logger.getLogger(ResultDescriptor.class);
86  
87      private static final int[] emptyInt = new int[0];
88  
89      // indexed data
90      protected String[] names;
91      protected int[] jdbcTypes;
92      protected ExtendedType[] converters;
93      protected int[] idIndexes;
94      protected int[] outParamIndexes;
95  
96      // unindexed data
97      protected List dbAttributes = new ArrayList();
98      protected List javaTypes = new ArrayList();
99      protected ExtendedTypeMap typesMapping;
100     protected ObjEntity rootEntity;
101 
102     /**
103      * Creates and returns a ResultDescritor based on ResultSet metadata.
104      */
105     public static ResultDescriptor createDescriptor(
106         ResultSet resultSet,
107         ExtendedTypeMap typeConverters) {
108         ResultDescriptor descriptor = new ResultDescriptor(typeConverters);
109         try {
110             ResultSetMetaData md = resultSet.getMetaData();
111             int len = md.getColumnCount();
112             if (len == 0) {
113                 throw new CayenneRuntimeException("No columns in ResultSet.");
114             }
115 
116             for (int i = 0; i < len; i++) {
117 
118                 // figure out column name
119                 int pos = i + 1;
120                 String name = md.getColumnLabel(pos);
121                 int sqlType = md.getColumnType(pos);
122                 int precision = md.getScale(pos);
123                 int length = md.getColumnDisplaySize(pos);
124                 if (name == null || name.length() == 0) {
125                     name = md.getColumnName(i + 1);
126 
127                     if (name == null || name.length() == 0) {
128                         name = "column_" + (i + 1);
129                     }
130                 }
131 
132                 DbAttribute desc = new DbAttribute();
133                 desc.setName(name);
134                 desc.setType(md.getColumnType(i + 1));
135                 
136                 descriptor.addDbAttribute(desc);
137                 descriptor.addJavaType(TypesMapping.getJavaBySqlType(sqlType, length, precision));
138             }
139         } catch (SQLException sqex) {
140             throw new CayenneRuntimeException("Error reading metadata.", sqex);
141         }
142 
143         descriptor.index();
144         return descriptor;
145     }
146 
147     /**
148      * Creates and returns a ResultDescriptor for the stored procedure parameters. 
149      */
150     public static ResultDescriptor createDescriptor(
151         Procedure procedure,
152         ExtendedTypeMap typeConverters) {
153         ResultDescriptor descriptor = new ResultDescriptor(typeConverters);
154         Iterator it = procedure.getCallParameters().iterator();
155         while (it.hasNext()) {
156             descriptor.addDbAttribute(new ProcedureParameterWrapper((ProcedureParameter) it.next()));
157         }
158 
159         descriptor.index();
160         return descriptor;
161     }
162 
163     public ResultDescriptor(ExtendedTypeMap typesMapping) {
164         this(typesMapping, null);
165     }
166 
167     public ResultDescriptor(
168         ExtendedTypeMap typesMapping,
169         ObjEntity rootEntity) {
170         this.typesMapping = typesMapping;
171         this.rootEntity = rootEntity;
172     }
173 
174     public void addColumns(Collection dbAttributes) {
175         this.dbAttributes.addAll(dbAttributes);
176     }
177 
178     public void addDbAttribute(DbAttribute attr) {
179         this.dbAttributes.add(attr);
180     }
181 
182     public void addJavaTypes(Collection javaTypes) {
183         this.javaTypes.addAll(javaTypes);
184     }
185 
186     public void addJavaType(String javaType) {
187         this.javaTypes.add(javaType);
188     }
189 
190     public void index() {
191 
192         // assert validity
193         if (javaTypes.size() > 0 && javaTypes.size() != dbAttributes.size()) {
194             throw new IllegalArgumentException("DbAttributes and Java type arrays must have the same size.");
195         }
196 
197         // init various things
198         int resultWidth = dbAttributes.size();
199         int idWidth = 0;
200         int outWidth = 0;
201         this.names = new String[resultWidth];
202         this.jdbcTypes = new int[resultWidth];
203         for (int i = 0; i < resultWidth; i++) {
204             DbAttribute attr = (DbAttribute) dbAttributes.get(i);
205 
206             // set type
207             jdbcTypes[i] = attr.getType();
208 
209             // check if this is an ID
210             if (attr.isPrimaryKey()) {
211                 idWidth++;
212             }
213 
214             // check if this is a stored procedure OUT parameter
215             if (attr instanceof ProcedureParameterWrapper) {
216                 if (((ProcedureParameterWrapper) attr).getParameter().isOutParam()) {
217                     outWidth++;
218                 }
219             }
220 
221             // figure out name
222             String name = null;
223             if (rootEntity != null) {
224                 ObjAttribute objAttr =
225                     rootEntity.getAttributeForDbAttribute(attr);
226                 if (objAttr != null) {
227                     name = objAttr.getDbAttributePath();
228                 }
229             }
230 
231             if (name == null) {
232                 name = attr.getName();
233             }
234 
235             names[i] = name;
236         }
237 
238         if (idWidth == 0) {
239             this.idIndexes = emptyInt;
240         } else {
241             this.idIndexes = new int[idWidth];
242             for (int i = 0, j = 0; i < resultWidth; i++) {
243                 DbAttribute attr = (DbAttribute) dbAttributes.get(i);
244                 jdbcTypes[i] = attr.getType();
245 
246                 if (attr.isPrimaryKey()) {
247                     idIndexes[j++] = i;
248                 }
249             }
250         }
251 
252         if (outWidth == 0) {
253             this.outParamIndexes = emptyInt;
254         } else {
255             this.outParamIndexes = new int[outWidth];
256             for (int i = 0, j = 0; i < resultWidth; i++) {
257                 DbAttribute attr = (DbAttribute) dbAttributes.get(i);
258                 jdbcTypes[i] = attr.getType();
259 
260                 if (attr instanceof ProcedureParameterWrapper) {
261                     if (((ProcedureParameterWrapper) attr).getParameter().isOutParam()) {
262                         outParamIndexes[j++] = i;
263                     }
264                 }
265             }
266         }
267 
268         // initialize type converters, must do after everything else,
269         // since this may depend on some of the indexed data
270         if (javaTypes.size() > 0) {
271             initConvertersFromJavaTypes();
272         } else if (rootEntity != null) {
273             initConvertersFromMapping();
274         } else {
275             initDefaultConverters();
276         }
277     }
278 
279     protected void initConvertersFromJavaTypes() {
280         int resultWidth = dbAttributes.size();
281         this.converters = new ExtendedType[resultWidth];
282 
283         for (int i = 0; i < resultWidth; i++) {
284             converters[i] =
285                 typesMapping.getRegisteredType((String) javaTypes.get(i));
286         }
287     }
288 
289     protected void initDefaultConverters() {
290         int resultWidth = dbAttributes.size();
291         this.converters = new ExtendedType[resultWidth];
292 
293         for (int i = 0; i < resultWidth; i++) {
294             String javaType = TypesMapping.getJavaBySqlType(jdbcTypes[i]);
295             converters[i] = typesMapping.getRegisteredType(javaType);
296         }
297     }
298 
299     protected void initConvertersFromMapping() {
300 
301         // assert that we have all the data
302         if (dbAttributes.size() == 0) {
303             throw new IllegalArgumentException("DbAttributes list is empty.");
304         }
305 
306         if (rootEntity == null) {
307             throw new IllegalArgumentException("Root ObjEntity is null.");
308         }
309 
310         int resultWidth = dbAttributes.size();
311         this.converters = new ExtendedType[resultWidth];
312 
313         for (int i = 0; i < resultWidth; i++) {
314             String javaType = null;
315             DbAttribute attr = (DbAttribute) dbAttributes.get(i);
316             ObjAttribute objAttr = rootEntity.getAttributeForDbAttribute(attr);
317             if (objAttr != null) {
318                 javaType = objAttr.getType();
319             } else {
320                 javaType = TypesMapping.getJavaBySqlType(attr.getType());
321             }
322 
323             converters[i] = typesMapping.getRegisteredType(javaType);
324         }
325     }
326 
327     public ExtendedType[] getConverters() {
328         return converters;
329     }
330 
331     public int[] getIdIndexes() {
332         return idIndexes;
333     }
334 
335     public int[] getJdbcTypes() {
336         return jdbcTypes;
337     }
338 
339     public String[] getNames() {
340         return names;
341     }
342 
343     /**
344      * Returns a count of columns in the result.
345      */
346     public int getResultWidth() {
347         return dbAttributes.size();
348     }
349 
350     public int[] getOutParamIndexes() {
351         return outParamIndexes;
352     }
353     
354     // [UGLY HACK AHEAD] wrapper to make a ProcedureParameter
355     // look like a DbAttribute. A better implementation would
356     // probably be a common interface for both.
357     static class ProcedureParameterWrapper extends DbAttribute {
358         ProcedureParameter parameter;
359         
360         ProcedureParameterWrapper(ProcedureParameter parameter) {
361             this.parameter = parameter;
362         }
363         
364         public int getMaxLength() {
365             return parameter.getMaxLength();
366         }
367 
368         public int getPrecision() {
369             return parameter.getPrecision();
370         }
371 
372         public int getType() {
373             return parameter.getType();
374         }
375 
376         public String getName() {
377             return parameter.getName();
378         }
379 
380         public Object getParent() {
381             return parameter.getParent();
382         }
383         
384         public ProcedureParameter getParameter() {
385             return parameter;
386         }
387 
388     }
389 }