KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectstyle > cayenne > access > util > ResultDescriptor


1 /* ====================================================================
2  *
3  * The ObjectStyle Group Software License, version 1.1
4  * ObjectStyle Group - http://objectstyle.org/
5  *
6  * Copyright (c) 2002-2005, Andrei (Andrus) Adamchik and individual authors
7  * of the software. All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * 1. Redistributions of source code must retain the above copyright
14  * notice, this list of conditions and the following disclaimer.
15  *
16  * 2. Redistributions in binary form must reproduce the above copyright
17  * notice, this list of conditions and the following disclaimer in
18  * the documentation and/or other materials provided with the
19  * distribution.
20  *
21  * 3. The end-user documentation included with the redistribution, if any,
22  * must include the following acknowlegement:
23  * "This product includes software developed by independent contributors
24  * and hosted on ObjectStyle Group web site (http://objectstyle.org/)."
25  * Alternately, this acknowlegement may appear in the software itself,
26  * if and wherever such third-party acknowlegements normally appear.
27  *
28  * 4. The names "ObjectStyle Group" and "Cayenne" must not be used to endorse
29  * or promote products derived from this software without prior written
30  * permission. For written permission, email
31  * "andrus at objectstyle dot org".
32  *
33  * 5. Products derived from this software may not be called "ObjectStyle"
34  * or "Cayenne", nor may "ObjectStyle" or "Cayenne" appear in their
35  * names without prior written permission.
36  *
37  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
38  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
39  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
40  * DISCLAIMED. IN NO EVENT SHALL THE OBJECTSTYLE GROUP OR
41  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
42  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
43  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
44  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
45  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
46  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
47  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48  * SUCH DAMAGE.
49  * ====================================================================
50  *
51  * This software consists of voluntary contributions made by many
52  * individuals and hosted on ObjectStyle Group web site. For more
53  * information on the ObjectStyle Group, please see
54  * <http://objectstyle.org/>.
55  */

56 package org.objectstyle.cayenne.access.util;
57
58 import java.sql.ResultSet JavaDoc;
59 import java.sql.ResultSetMetaData JavaDoc;
60 import java.sql.SQLException JavaDoc;
61 import java.util.ArrayList JavaDoc;
62 import java.util.Collection JavaDoc;
63 import java.util.Iterator JavaDoc;
64 import java.util.List JavaDoc;
65
66 import org.objectstyle.cayenne.CayenneRuntimeException;
67 import org.objectstyle.cayenne.access.jdbc.ColumnDescriptor;
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.DbEntity;
73 import org.objectstyle.cayenne.map.ObjAttribute;
74 import org.objectstyle.cayenne.map.ObjEntity;
75 import org.objectstyle.cayenne.map.Procedure;
76 import org.objectstyle.cayenne.map.ProcedureParameter;
77
78 /**
79  * Contains information about the ResultSet used to process fetched rows. ResultDescriptor
80  * is initialized by calling various "add*" methods, after that it must be indexed by
81  * calling "index".
82  *
83  * @author Andrei Adamchik
84  * @deprecated Since 1.2 replaced with RowDescriptor that provides clean and
85  * straightforward creation options instead of ResultDescriptor's obscure ways
86  * to index Cayenne attributes data.
87  */

88 public class ResultDescriptor {
89
90     // indexed data
91
protected String JavaDoc[] names;
92     protected int[] jdbcTypes;
93     protected ExtendedType[] converters;
94     protected int[] idIndexes;
95     protected int[] outParamIndexes;
96
97     // unindexed data
98
protected List JavaDoc dbAttributes = new ArrayList JavaDoc();
99     protected List JavaDoc javaTypes = new ArrayList JavaDoc();
100     protected ExtendedTypeMap typesMapping;
101     protected ObjEntity rootEntity;
102     protected boolean indexedIds;
103
104     /**
105      * Creates and returns a ResultDescritor based on ResultSet metadata.
106      */

107     public static ResultDescriptor createDescriptor(
108             ResultSet JavaDoc resultSet,
109             ExtendedTypeMap typeConverters) {
110         ResultDescriptor descriptor = new ResultDescriptor(typeConverters);
111         try {
112             ResultSetMetaData JavaDoc md = resultSet.getMetaData();
113             int len = md.getColumnCount();
114             if (len == 0) {
115                 throw new CayenneRuntimeException("No columns in ResultSet.");
116             }
117
118             for (int i = 0; i < len; i++) {
119
120                 // figure out column name
121
int pos = i + 1;
122                 String JavaDoc name = md.getColumnLabel(pos);
123                 int sqlType = md.getColumnType(pos);
124                 int precision = md.getScale(pos);
125                 int length = md.getColumnDisplaySize(pos);
126                 if (name == null || name.length() == 0) {
127                     name = md.getColumnName(i + 1);
128
129                     if (name == null || name.length() == 0) {
130                         name = "column_" + (i + 1);
131                     }
132                 }
133
134                 DbAttribute desc = new DbAttribute();
135                 desc.setName(name);
136                 desc.setType(md.getColumnType(i + 1));
137
138                 descriptor.addDbAttribute(desc);
139                 descriptor.addJavaType(TypesMapping.getJavaBySqlType(
140                         sqlType,
141                         length,
142                         precision));
143             }
144         }
145         catch (SQLException JavaDoc sqex) {
146             throw new CayenneRuntimeException("Error reading metadata.", sqex);
147         }
148
149         descriptor.index();
150         return descriptor;
151     }
152
153     /**
154      * Creates and returns a ResultDescriptor for an array of ColumnDescriptors.
155      *
156      * @since 1.1
157      */

158     public static ResultDescriptor createDescriptor(
159             ColumnDescriptor[] columns,
160             ExtendedTypeMap typeConverters) {
161
162         ResultDescriptor descriptor = new ResultDescriptor(typeConverters);
163
164         int len = columns.length;
165         descriptor.names = new String JavaDoc[len];
166         descriptor.jdbcTypes = new int[len];
167         descriptor.converters = new ExtendedType[len];
168         int idWidth = 0;
169
170         for (int i = 0; i < len; i++) {
171             descriptor.names[i] = columns[i].getName();
172             descriptor.jdbcTypes[i] = columns[i].getJdbcType();
173             descriptor.converters[i] = typeConverters.getRegisteredType(columns[i]
174                     .getJavaClass());
175             if (columns[i].isPrimaryKey()) {
176                 idWidth++;
177             }
178         }
179
180         return descriptor;
181     }
182
183     /**
184      * Creates and returns a ResultDescriptor for the stored procedure parameters.
185      */

186     public static ResultDescriptor createDescriptor(
187             Procedure procedure,
188             ExtendedTypeMap typeConverters) {
189         ResultDescriptor descriptor = new ResultDescriptor(typeConverters);
190         Iterator JavaDoc it = procedure.getCallParameters().iterator();
191         while (it.hasNext()) {
192             descriptor.addDbAttribute(new ProcedureParameterWrapper(
193                     (ProcedureParameter) it.next()));
194         }
195
196         descriptor.index();
197         return descriptor;
198     }
199
200     public ResultDescriptor(ExtendedTypeMap typesMapping) {
201         this(typesMapping, null);
202     }
203
204     public ResultDescriptor(ExtendedTypeMap typesMapping, ObjEntity rootEntity) {
205         this.typesMapping = typesMapping;
206         this.rootEntity = rootEntity;
207     }
208
209     public void addColumns(Collection JavaDoc dbAttributes) {
210         this.dbAttributes.addAll(dbAttributes);
211     }
212
213     public void addDbAttribute(DbAttribute attr) {
214         this.dbAttributes.add(attr);
215     }
216
217     public void addJavaTypes(Collection JavaDoc javaTypes) {
218         this.javaTypes.addAll(javaTypes);
219     }
220
221     public void addJavaType(String JavaDoc javaType) {
222         this.javaTypes.add(javaType);
223     }
224
225     /**
226      * Reindexes primary key based on DbEntity.
227      *
228      * @since 1.1
229      */

230     protected void indexIds(DbEntity entity) {
231         // TODO: maybe check if the entity has changed,
232
// and reindex again... since now we assume that once indexing
233
// is done, the entity is always the same...
234

235         if (!indexedIds) {
236             synchronized (this) {
237                 if (!indexedIds) {
238                     idIndexes = new int[0];
239
240                     if (entity == null) {
241                         return;
242                     }
243
244                     indexedIds = true;
245
246                     int resultWidth = names.length;
247                     int[] tmp = new int[resultWidth];
248                     int j = 0;
249                     for (int i = 0; i < resultWidth; i++) {
250                         DbAttribute attribute = (DbAttribute) entity
251                                 .getAttribute(names[i]);
252                         if (attribute != null && attribute.isPrimaryKey()) {
253                             tmp[j++] = i;
254                         }
255                     }
256
257                     if (j > 0) {
258                         this.idIndexes = new int[j];
259                         System.arraycopy(tmp, 0, idIndexes, 0, j);
260                     }
261
262                 }
263             }
264         }
265     }
266
267     public void index() {
268
269         // assert validity
270
if (javaTypes.size() > 0 && javaTypes.size() != dbAttributes.size()) {
271             throw new IllegalArgumentException JavaDoc(
272                     "DbAttributes and Java type arrays must have the same size.");
273         }
274
275         // init various things
276
int resultWidth = dbAttributes.size();
277         int outWidth = 0;
278         this.names = new String JavaDoc[resultWidth];
279         this.jdbcTypes = new int[resultWidth];
280         for (int i = 0; i < resultWidth; i++) {
281             DbAttribute attr = (DbAttribute) dbAttributes.get(i);
282
283             // set type
284
jdbcTypes[i] = attr.getType();
285
286             // check if this is a stored procedure OUT parameter
287
if (attr instanceof ProcedureParameterWrapper) {
288                 if (((ProcedureParameterWrapper) attr).getParameter().isOutParam()) {
289                     outWidth++;
290                 }
291             }
292
293             // figure out name
294
String JavaDoc name = null;
295             if (rootEntity != null) {
296                 ObjAttribute objAttr = rootEntity.getAttributeForDbAttribute(attr);
297                 if (objAttr != null) {
298                     name = objAttr.getDbAttributePath();
299                 }
300             }
301
302             if (name == null) {
303                 name = attr.getName();
304             }
305
306             names[i] = name;
307         }
308
309         if (outWidth == 0) {
310             this.outParamIndexes = new int[0];
311         }
312         else {
313             this.outParamIndexes = new int[outWidth];
314             for (int i = 0, j = 0; i < resultWidth; i++) {
315                 DbAttribute attr = (DbAttribute) dbAttributes.get(i);
316                 jdbcTypes[i] = attr.getType();
317
318                 if (attr instanceof ProcedureParameterWrapper) {
319                     if (((ProcedureParameterWrapper) attr).getParameter().isOutParam()) {
320                         outParamIndexes[j++] = i;
321                     }
322                 }
323             }
324         }
325
326         // initialize type converters, must do after everything else,
327
// since this may depend on some of the indexed data
328
if (javaTypes.size() > 0) {
329             initConvertersFromJavaTypes();
330         }
331         else if (rootEntity != null) {
332             initConvertersFromMapping();
333         }
334         else {
335             initDefaultConverters();
336         }
337     }
338
339     protected void initConvertersFromJavaTypes() {
340         int resultWidth = dbAttributes.size();
341         this.converters = new ExtendedType[resultWidth];
342
343         for (int i = 0; i < resultWidth; i++) {
344             converters[i] = typesMapping.getRegisteredType((String JavaDoc) javaTypes.get(i));
345         }
346     }
347
348     protected void initDefaultConverters() {
349         int resultWidth = dbAttributes.size();
350         this.converters = new ExtendedType[resultWidth];
351
352         for (int i = 0; i < resultWidth; i++) {
353             String JavaDoc javaType = TypesMapping.getJavaBySqlType(jdbcTypes[i]);
354             converters[i] = typesMapping.getRegisteredType(javaType);
355         }
356     }
357
358     protected void initConvertersFromMapping() {
359
360         // assert that we have all the data
361
if (dbAttributes.size() == 0) {
362             throw new IllegalArgumentException JavaDoc("DbAttributes list is empty.");
363         }
364
365         if (rootEntity == null) {
366             throw new IllegalArgumentException JavaDoc("Root ObjEntity is null.");
367         }
368
369         int resultWidth = dbAttributes.size();
370         this.converters = new ExtendedType[resultWidth];
371
372         for (int i = 0; i < resultWidth; i++) {
373             String JavaDoc javaType = null;
374             DbAttribute attr = (DbAttribute) dbAttributes.get(i);
375             ObjAttribute objAttr = rootEntity.getAttributeForDbAttribute(attr);
376
377             // TODO: [See CAY-207 for details] This setup doesn't allow to correctly
378
// determine the Java class of an attribute if it is defined in a sub-entity
379
// of the query root entity... Hence all inherited attributes will be fetched
380
// as generic types, ignoring any possible custom type.
381
if (objAttr != null) {
382                 javaType = objAttr.getType();
383             }
384             else {
385                 javaType = TypesMapping.getJavaBySqlType(attr.getType());
386             }
387
388             converters[i] = typesMapping.getRegisteredType(javaType);
389         }
390     }
391
392     public ExtendedType[] getConverters() {
393         return converters;
394     }
395
396     /**
397      * @since 1.1
398      */

399     public int[] getIdIndexes(DbEntity entity) {
400         indexIds(entity);
401         return idIndexes;
402     }
403
404     public int[] getJdbcTypes() {
405         return jdbcTypes;
406     }
407
408     public String JavaDoc[] getNames() {
409         return names;
410     }
411
412     /**
413      * Returns a count of columns in the result.
414      */

415     public int getResultWidth() {
416         return dbAttributes.size();
417     }
418
419     public int[] getOutParamIndexes() {
420         return outParamIndexes;
421     }
422
423     // [UGLY HACK AHEAD] wrapper to make a ProcedureParameter
424
// look like a DbAttribute. A better implementation would
425
// probably be a common interface for both.
426
static class ProcedureParameterWrapper extends DbAttribute {
427
428         ProcedureParameter parameter;
429
430         ProcedureParameterWrapper(ProcedureParameter parameter) {
431             this.parameter = parameter;
432         }
433
434         public int getMaxLength() {
435             return parameter.getMaxLength();
436         }
437
438         public int getPrecision() {
439             return parameter.getPrecision();
440         }
441
442         public int getType() {
443             return parameter.getType();
444         }
445
446         public String JavaDoc getName() {
447             return parameter.getName();
448         }
449
450         public Object JavaDoc getParent() {
451             return parameter.getParent();
452         }
453
454         public ProcedureParameter getParameter() {
455             return parameter;
456         }
457
458     }
459 }
Popular Tags