KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > jdo > spi > persistence > generator > database > JDBCInfo


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the License). You may not use this file except in
5  * compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * https://glassfish.dev.java.net/public/CDDLv1.0.html or
9  * glassfish/bootstrap/legal/CDDLv1.0.txt.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * Header Notice in each file and include the License file
15  * at glassfish/bootstrap/legal/CDDLv1.0.txt.
16  * If applicable, add the following below the CDDL Header,
17  * with the fields enclosed by brackets [] replaced by
18  * you own identifying information:
19  * "Portions Copyrighted [year] [name of copyright owner]"
20  *
21  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
22  */

23
24 package com.sun.jdo.spi.persistence.generator.database;
25
26
27 import com.sun.jdo.spi.persistence.utility.StringHelper;
28
29 import com.sun.jdo.spi.persistence.utility.logging.Logger;
30
31 /**
32  * Represents how a JDBC type (i.e., one defined by java.sql.Types) is
33  * created in the database.
34  */

35 class JDBCInfo {
36
37     //
38
// These constants are used to locate properties indicating values for
39
// the fields in instances of JDBCInfo.
40
//
41
//
42

43     /** Indicator that property designates the type of a mapped SQL type. */
44     private static final String JavaDoc INDICATOR_TYPE =
45         DatabaseGenerationConstants.INDICATOR_JDBC_TYPE;
46
47     /** Indicator that property designates nullability of mapped SQL type. */
48     private static final String JavaDoc INDICATOR_NULLABLE =
49     DatabaseGenerationConstants.INDICATOR_JDBC_NULLABLE;
50
51     /** Indicator that property designates the precision of mapped SQL type. */
52     private static final String JavaDoc INDICATOR_PRECISION =
53         DatabaseGenerationConstants.INDICATOR_JDBC_PRECISION;
54
55     /** Indicator that property designates the scale of mapped SQL type. */
56     private static final String JavaDoc INDICATOR_SCALE =
57     DatabaseGenerationConstants.INDICATOR_JDBC_SCALE;
58
59     /** Indicator that property designates length of a mapped SQL type. */
60     private static final String JavaDoc INDICATOR_LENGTH =
61         DatabaseGenerationConstants.INDICATOR_JDBC_LENGTH;
62
63     /** Indicator that a type does not have a length associated with it. */
64     private static final String JavaDoc NO_LENGTH_INDICATOR = "null";
65
66     /** Flag value which indicates that a JDBCInfo does not have a length. */
67     private static final Integer JavaDoc NO_LENGTH = new Integer JavaDoc(-1);
68
69      /** Logger for warning & error messages */
70     private static final Logger logger =
71             LogHelperDatabaseGenerator.getLogger();
72     
73     /** Value from java.sql.Types. */
74     private int jdbcType;
75     
76     /** True iff a column of this type is nullable; default is false. */
77     private boolean nullable = false;
78     
79     /** Indicates precision of a fixed-point number column; default is null. */
80     private Integer JavaDoc precision = null;
81     
82     /** Indicates scale of a fixed-point number column; default is null. */
83     private Integer JavaDoc scale = null;
84     
85     /** Indicates length of a char, etc. column; default is null. */
86     private Integer JavaDoc length = null;
87
88
89     //
90
// Allow determining if which fields have been assigned values.
91
//
92

93     /** Indicates which fields in this instance have been set. */
94     private byte fieldsWithValues = 0;
95
96     /** Mask to indicate whether or not {@link #jdbcType} has a value. */
97     private static final byte MASK_JDBC_TYPE = 1 << 0;
98
99     /** Mask to indicate whether or not {@link #nullable} has a value. */
100     private static final byte MASK_NULLABLE = 1 << 1;
101
102     /** Mask to indicate whether or not {@link #precision} has a value. */
103     private static final byte MASK_PRECISION = 1 << 2;
104
105     /** Mask to indicate whether or not {@link #scale} has a value. */
106     private static final byte MASK_SCALE = 1 << 3;
107
108     /** Mask to indicate whether or not {@link #length} has a value. */
109     private static final byte MASK_LENGTH = 1 << 4;
110
111     /** Mask to access all field flags at once. */
112     private static final byte MASK_ALL = MASK_JDBC_TYPE | MASK_NULLABLE
113         | MASK_PRECISION | MASK_SCALE | MASK_LENGTH;
114     
115
116     /**
117      * Constructor which initializes all fields.
118      * @param jdbcType See {@link jdbcType}.
119      * @param precision See {@link precision}.
120      * @param scale See {@link scale}.
121      * @param length See {@link length}.
122      * @param nullable See {@link nullable}.
123      */

124     JDBCInfo(int jdbcType, Integer JavaDoc precision, Integer JavaDoc scale,
125             Integer JavaDoc length, boolean nullable) {
126
127         this.jdbcType = jdbcType;
128         this.precision = precision;
129         this.scale = scale;
130         this.length = length;
131         this.nullable = nullable;
132
133         fieldsWithValues = MASK_ALL;
134     }
135
136     /**
137      * Use this constructor in conjunction with multiple setValue to
138      * initialize an instance.
139      */

140     JDBCInfo() { }
141
142     
143     /**
144      * Sets the value of one field of this JDBCInfo.
145      * @param indicator Determines which field is set.
146      * @param value String form of the new value of a field. Must not be
147      * null. Empty String means to reset the field value to its default,
148      * except for jdbcType: That field has no default, so given an empty
149      * String the value of jdbcType is unchanged.
150      * @throws IllegalJDBCTypeException if <code>indicator</code> shows that
151      * we are setting a JDBC Type and <code>value</code> is not
152      * recognized as being a valid member of java.sql.Types.
153      */

154     void setValue(String JavaDoc value, String JavaDoc indicator)
155             throws IllegalJDBCTypeException {
156
157         if (indicator.equals(INDICATOR_TYPE)) {
158             if (!StringHelper.isEmpty(value)) {
159                 Integer JavaDoc type = MappingPolicy.getJdbcType(value);
160                 if (null == type) {
161                     throw new IllegalJDBCTypeException();
162                 }
163                 this.jdbcType = type.intValue();
164                 this.fieldsWithValues |= MASK_JDBC_TYPE;
165             }
166
167         } else if (indicator.equals(INDICATOR_NULLABLE)) {
168             if (StringHelper.isEmpty(value)) {
169                 this.nullable = false; // default
170
} else {
171                 this.nullable = Boolean.valueOf(value).booleanValue();
172             }
173             this.fieldsWithValues |= MASK_NULLABLE;
174
175         } else if (indicator.equals(INDICATOR_PRECISION)) {
176             this.precision = getIntegerValue(value);
177             this.fieldsWithValues |= MASK_PRECISION;
178
179         } else if (indicator.equals(INDICATOR_SCALE)) {
180             this.scale = getIntegerValue(value);
181             this.fieldsWithValues |= MASK_SCALE;
182
183         } else if (indicator.equals(INDICATOR_LENGTH)) {
184             if (value.trim().equals(NO_LENGTH_INDICATOR)) {
185                 this.length = NO_LENGTH;
186             } else {
187                 this.length = getIntegerValue(value);
188             }
189             this.fieldsWithValues |= MASK_LENGTH;
190         }
191     }
192
193     /**
194      * @param s String whose Integer value is sought.
195      * @return the value of s as an Integer, or null if s is empty.
196      */

197     private Integer JavaDoc getIntegerValue(String JavaDoc s) {
198         Integer JavaDoc rc = null;
199         if (!StringHelper.isEmpty(s)) {
200             rc = new Integer JavaDoc(s);
201         }
202         return rc;
203     }
204
205     //
206
// A note about "completeness".
207
// JDBCInfo instances are created one of 2 ways: By loading a .properties
208
// file for a database, or by a user override. In the first case, the
209
// JDBCInfo will have values for all relevant fields, because that is the
210
// way we have created the .properties files. ("relevant" here means
211
// that, e.g., a length value will be present if required for a field
212
// type for which length is relevant such as VARCHAR.)
213
//
214
// In the second case, a user override might provide only one overriden
215
// value, let's say length. So for a particular field name, we may know
216
// only that it should have a length; of course we need more. So before
217
// allowing access to a JDBCInfo that was created for a field, complete()
218
// it with a JDBCInfo that was created for that field's type.
219
//
220
// See MappingPolicy.JDBCInfo().
221
//
222

223     
224     /**
225      * Fill in values for fields based on values in another JDBCInfo
226      * instance. Only those fields for which this instance does not already
227      * have a value are changed.
228      * @param other Another instance of JDBCInfo that has values which are
229      * used to set as-yet-unset values in this instance.
230      */

231     // XXX For precision and scale, this is not entirely correct.
232
// We should check if this.<val> is set. If so, it must not be greater
233
// than other.<val>. In other words, the other instance's value
234
// overrules the value in this instance, because the other value was
235
// provided in the dbvendor-specific .properties file, which users must
236
// not override. If this instance (i.e., the user override's instance)
237
// specifies an invalid override, we should log a warning, warn the user,
238
// and use the other.<val>.
239
void complete(JDBCInfo other) {
240         if (logger.isLoggable(Logger.FINEST)) {
241             logger.finest("Entering JDBCInfo.complete: " // NOI18N
242
+ "\nthis: " + this // NOI18N
243
+ "\nother: " + other); // NOI18N
244
}
245         if (MASK_ALL != fieldsWithValues) {
246             if ((fieldsWithValues & MASK_JDBC_TYPE) == 0) {
247                 this.jdbcType = other.jdbcType;
248             }
249
250             if ((fieldsWithValues & MASK_NULLABLE) == 0) {
251                 this.nullable = other.nullable;
252             }
253             
254             if ((fieldsWithValues & MASK_PRECISION) == 0) {
255                 this.precision = other.precision;
256             }
257
258             if ((fieldsWithValues & MASK_SCALE) == 0) {
259                 this.scale = other.scale;
260             }
261
262             if ((fieldsWithValues & MASK_LENGTH) == 0
263                 || (other.length == NO_LENGTH)
264                 || (other.length.intValue() < this.length.intValue())) {
265                 this.length = other.length;
266             }
267
268             fieldsWithValues = MASK_ALL;
269         }
270         if (logger.isLoggable(Logger.FINEST)) {
271             logger.finest("Leaving JDBCInfo.complete: " // NOI18N
272
+ "\nthis: " + this); // NOI18N
273
}
274     }
275
276     /**
277      * @return <code>true</code> if this instance has been assigned values
278      * for all fields.
279      */

280     boolean isComplete() {
281         return fieldsWithValues == MASK_ALL;
282     }
283
284     /**
285      * Update this JDBCInfo with information from the other JDBCInfo.
286      * @param other The JDBCInfo with values that will overwrite values in
287      * this JDBCInfo.
288      */

289     void override(JDBCInfo other) {
290         if (null != other) {
291             this.jdbcType = other.jdbcType;
292         }
293     }
294
295     /**
296      * @return true iff this instance has a value for jdbcType
297      */

298     public boolean hasJdbcType() {
299         return (fieldsWithValues & MASK_JDBC_TYPE) == 1;
300     }
301
302     /**
303      * @return The JDBC corresponding to this JDBCInfo. See
304      * {@link java.sql.Types}.
305      */

306     public int getJdbcType() {
307         return jdbcType;
308     }
309
310     /**
311      * @return <code>true</code> of columns based on this JDBCInfo should be
312      * nullable.
313      */

314     public boolean getNullable() {
315         return nullable;
316     }
317
318     /**
319      * @return The precision of of columns based on this JDBCInfo.
320      */

321     public Integer JavaDoc getPrecision() {
322         return precision;
323     }
324
325     /**
326      * @return The scale of of columns based on this JDBCInfo.
327      */

328     public Integer JavaDoc getScale() {
329         return scale;
330     }
331
332     /**
333      * @return The length of of columns based on this JDBCInfo, or null if
334      * this JDBCInfo does not need a length (e.g. CLOB on Oracle).
335      */

336     public Integer JavaDoc getLength() {
337         return NO_LENGTH.equals(length) ? null : length;
338     }
339
340     /**
341      * Debugging support.
342      * @return A String with the value of each field.
343      */

344     public String JavaDoc toString() {
345         return "JDBCInfo:" // NOI18N
346
+ " jdbcType=" + jdbcType // NOI18N
347
+ " nullable=" + nullable // NOI18N
348
+ " precision=" + precision // NOI18N
349
+ " scale=" + scale // NOI18N
350
+ " length=" + length // NOI18N
351
+ " fieldsWithValues=0x" + Integer.toHexString(fieldsWithValues); // NOI18N
352
}
353
354     /**
355      * Used to indicate that a given JDBC Type name is not recognized.
356      */

357     static class IllegalJDBCTypeException extends Exception JavaDoc {
358         IllegalJDBCTypeException() { }
359     }
360 }
361
Popular Tags