KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > jdo > spi > persistence > support > sqlstore > model > LocalFieldDesc


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 /*
25  * LocalFieldDesc.java
26  *
27  * Created on March 3, 2000
28  *
29  */

30
31 package com.sun.jdo.spi.persistence.support.sqlstore.model;
32
33 import org.netbeans.modules.dbschema.ColumnElement;
34 import com.sun.jdo.spi.persistence.utility.FieldTypeEnumeration;
35 import com.sun.jdo.spi.persistence.utility.logging.Logger;
36 import com.sun.jdo.spi.persistence.support.sqlstore.StateManager;
37
38 import java.util.ArrayList JavaDoc;
39 import java.util.Iterator JavaDoc;
40 import java.lang.reflect.Field JavaDoc;
41 import java.sql.Types JavaDoc;
42 import java.math.BigInteger JavaDoc;
43 import java.math.BigDecimal JavaDoc;
44
45
46 /**
47  *
48  */

49 public class LocalFieldDesc extends FieldDesc {
50
51     /** Array of ColumnElement. */
52     final ArrayList JavaDoc columnDescs;
53
54     /** Stores this special mapping information. */
55     private Boolean JavaDoc primitiveMappedToNullableColumn;
56
57     /** SQL Column type for primary column. */
58     private final int primaryColumnType;
59
60     LocalFieldDesc(ClassDesc config, ArrayList JavaDoc columnDescs) {
61         super(config);
62         this.columnDescs = columnDescs;
63
64         //Initialize primary column's type.
65
primaryColumnType = getPrimaryColumn().getType();
66
67         sqlProperties |= FieldDesc.PROP_RECORD_ON_UPDATE;
68     }
69
70     public boolean isPrimitiveMappedToNullableColumn() {
71         if (primitiveMappedToNullableColumn == null) {
72             boolean rc = getType().isPrimitive();
73
74             for (Iterator JavaDoc iter = columnDescs.iterator(); iter.hasNext() && rc; ) {
75                 ColumnElement c = (ColumnElement) iter.next();
76                 rc = c.isNullable();
77             }
78             primitiveMappedToNullableColumn = new Boolean JavaDoc(rc);
79         }
80
81         return primitiveMappedToNullableColumn.booleanValue();
82     }
83
84     /**
85      * Determines if this field is mapped to a LOB column type. It is assumed that
86      * lob fields are mapped to only one columns and UI and model verifications enforce it.
87      * @return <code>true</code> if field is mapped to LOB column type. <code>false</code>
88      * otherwise.
89      */

90     public boolean isMappedToLob() {
91         return
92             primaryColumnType == Types.BLOB ||
93
94             //primaryColumnType == Types.BINARY ||
95
//primaryColumnType == Types.VARBINARY ||
96
//primaryColumnType == Types.LONGVARBINARY ||
97

98             isCharLobType(primaryColumnType) ||
99             // If none of above, check if the field is mapped to byte[].
100
// We should treat any field mapped to byte[] as mapped to a LOB.
101
getEnumType() == FieldTypeEnumeration.ARRAY_BYTE_PRIMITIVE;
102     }
103
104     /**
105      * Determines if <code>sqltype</code> passed to this method is to be considered a character
106      * LOB type.
107      * @return <code>true</code> if field is mapped to character LOB column type. <code>false</code>
108      * otherwise.
109      */

110     public static boolean isCharLobType(int sqlType) {
111         //Resolve : Need to check for all supported datbases all possible LOB types
112
return
113             sqlType == Types.LONGVARCHAR ||
114             sqlType == Types.CLOB;
115     }
116
117     /**
118      * Determines if the <code>sqlType</code> passed to this method corresponds to
119      * a fixed char type.
120      *
121      * @param sqlType The input sqlType.
122      * @return <code>true</code> if field is mapped to Types.CHAR
123      * <code>false</code> otherwise.
124      */

125     public static boolean isFixedCharType(int sqlType) {
126         return sqlType == Types.CHAR;
127     }
128
129     /**
130      * Gets the <code>ColumnElement</code> for the primary column of this field.
131      * @return The <code>ColumnElement</code> for the primary column of this field.
132      */

133     public ColumnElement getPrimaryColumn() {
134         return ((ColumnElement) columnDescs.get(0));
135     }
136
137     /**
138      * Returns an iterator on the mapped column elements.
139      * @return An iterator on the mapped column elements.
140      */

141     public Iterator JavaDoc getColumnElements() {
142         return columnDescs.iterator();
143     }
144
145     /**
146      * Returns true if this field is a version field.
147      */

148     public boolean isVersion() {
149         return ((sqlProperties & FieldDesc.PROP_VERSION_FIELD) > 0);
150     }
151
152     /**
153      * Increments this field in the instance managed by state manager
154      * <code>sm</code> by one.
155      *
156      * @param sm State manager to be modified.
157      */

158     public void incrementValue(StateManager sm) {
159         assert isVersion();
160
161         Long JavaDoc val = (Long JavaDoc) getValue(sm);
162         long value = (val != null) ? val.longValue() : 0;
163
164         setValue(sm, new Long JavaDoc(++value));
165     }
166
167     //
168
// ------------ Initialisation methods ------------
169
//
170

171     /**
172      * Calls the superclass method and disables concurrency checking
173      * for certain field types.
174      */

175     protected void setupDesc(Field JavaDoc f) {
176         super.setupDesc(f);
177
178         // Disables concurrency check for fields mapped to LOB columns.
179
if (isMappedToLob() ) {
180             sqlProperties = sqlProperties & ~PROP_IN_CONCURRENCY_CHECK;
181         }
182
183         // Disables the concurrency check for scaled numeric fields.
184
switch (getEnumType()) {
185             case FieldTypeEnumeration.FLOAT_PRIMITIVE:
186             case FieldTypeEnumeration.FLOAT:
187             case FieldTypeEnumeration.DOUBLE_PRIMITIVE:
188             case FieldTypeEnumeration.DOUBLE:
189             case FieldTypeEnumeration.BIGDECIMAL:
190                 sqlProperties &= ~PROP_IN_CONCURRENCY_CHECK;
191         }
192     }
193
194     /**
195      * This array specifies the precedence of Java types that are mapped
196      * to non-nullable database types without scale.
197      * The primitive type long has the highest precedence and the type
198      * Float has the lowest.
199      */

200     private static final Class JavaDoc[] nonNullableNonScaledTypes =
201             {
202                 Long.TYPE, Integer.TYPE, Short.TYPE, Byte.TYPE, Double.TYPE,
203                 Float.TYPE, BigInteger JavaDoc.class, BigDecimal JavaDoc.class, Long JavaDoc.class,
204                 Integer JavaDoc.class, Short JavaDoc.class, Byte JavaDoc.class, Double JavaDoc.class, Float JavaDoc.class
205             };
206
207     /**
208      * This array specifies the precedence of Java types that are mapped
209      * to nullable SQL types without scale.
210      * The type BigDecimal has the highest precedence and the primitive
211      * type float has the lowest.
212      */

213     private static final Class JavaDoc[] nullableNonScaledTypes =
214             {
215                 BigInteger JavaDoc.class, BigDecimal JavaDoc.class, Long JavaDoc.class, Integer JavaDoc.class, Short JavaDoc.class,
216                 Byte JavaDoc.class, Double JavaDoc.class, Float JavaDoc.class, Long.TYPE, Integer.TYPE,
217                 Short.TYPE, Byte.TYPE, Double.TYPE, Float.TYPE
218             };
219
220     /**
221      * This array specifies the precedence of Java types that are mapped
222      * to non-nullable SQL types with scale.
223      * The primitive type double has the highest precedence and the primitive
224      * type byte has the lowest.
225      */

226     private static final Class JavaDoc[] nonNullableScaledTypes =
227             {
228                 Double.TYPE, Float.TYPE, Long.TYPE, Integer.TYPE, Short.TYPE,
229                 Byte.TYPE, BigDecimal JavaDoc.class, Double JavaDoc.class, BigInteger JavaDoc.class,
230                 Long JavaDoc.class, Integer JavaDoc.class, Short JavaDoc.class, Byte JavaDoc.class
231             };
232
233     /**
234      * This array specifies the precedence of Java types that are mapped
235      * to non-nullable SQL types without scale.
236      * The primitive type BigDecimal has the highest precedence and the primitive
237      * type float has the lowest.
238      */

239     private static final Class JavaDoc[] nullableScaledTypes =
240             {
241                 BigDecimal JavaDoc.class, Double JavaDoc.class, Float JavaDoc.class, BigInteger JavaDoc.class,
242                 Long JavaDoc.class, Integer JavaDoc.class, Short JavaDoc.class, Byte JavaDoc.class, Double.TYPE,
243                 Float.TYPE, Long.TYPE, Integer.TYPE, Short.TYPE, Byte.TYPE
244             };
245
246     /**
247      * This method looks up the type precedence given a typePrecedence array.
248      * @param type the class type whose precedence we want to look up
249      * @param typePrecedence an array of types. Possible values are:
250      * @see #nonNullableNonScaledTypes
251      * @see #nullableNonScaledTypes
252      * @see #nonNullableScaledTypes
253      * @see #nullableScaledTypes
254      * @return an integer value indicating the precedence
255      */

256     private static int lookupTypePrecedence(Class JavaDoc type, Class JavaDoc typePrecedence[]) {
257         for (int i = 0; i < typePrecedence.length; i++) {
258             if (type == typePrecedence[i]) {
259                 return i;
260             }
261         }
262
263         return Integer.MAX_VALUE;
264     }
265
266     /**
267      * This method computes the type precedence for the given field f.
268      * @return an integer value indicating the precedence. 0 indicates
269      * highest precedence and Integer.MAX_VALUE indicates lowest.
270      */

271     private int computeTypePrecedence() {
272         ColumnElement c = (ColumnElement) columnDescs.get(0);
273         int sqlType = c.getType();
274         Class JavaDoc type = getType();
275         boolean isNullable = c.isNullable();
276         int precedence = Integer.MAX_VALUE;
277
278         switch (sqlType) {
279             case Types.TINYINT:
280             case Types.SMALLINT:
281             case Types.INTEGER:
282             case Types.BIGINT:
283                 if (isNullable) {
284                     precedence = lookupTypePrecedence(type, nullableNonScaledTypes);
285                 } else {
286                     precedence = lookupTypePrecedence(type, nonNullableNonScaledTypes);
287                 }
288                 break;
289             case Types.REAL:
290             case Types.FLOAT:
291             case Types.DOUBLE:
292                 if (isNullable) {
293                     precedence = lookupTypePrecedence(type, nullableScaledTypes);
294                 } else {
295                     precedence = lookupTypePrecedence(type, nonNullableScaledTypes);
296                 }
297                 break;
298             case Types.NUMERIC:
299             case Types.DECIMAL:
300                 int scale = -1;
301                 if ((scale = c.getScale().intValue()) == 0) {
302                     // non scaled type
303
if (isNullable) {
304                         precedence = lookupTypePrecedence(type, nullableNonScaledTypes);
305                     } else {
306                         precedence = lookupTypePrecedence(type, nonNullableNonScaledTypes);
307                     }
308                 } else if (scale > 0) {
309                     // scaled type
310
if (isNullable) {
311                         precedence = lookupTypePrecedence(type, nullableScaledTypes);
312                     } else {
313                         precedence = lookupTypePrecedence(type, nonNullableScaledTypes);
314                     }
315                 }
316                 break;
317             case Types.CHAR:
318             case Types.VARCHAR:
319             case Types.LONGVARCHAR:
320                 if (type == String JavaDoc.class) {
321                     precedence = 0;
322                 }
323                 break;
324             case Types.DATE:
325             case Types.TIMESTAMP:
326                 if (java.util.Date JavaDoc.class.isAssignableFrom(type)) {
327                     precedence = 0;
328                 }
329                 break;
330             case Types.BIT:
331                 if (type == Boolean JavaDoc.class) {
332                     if (isNullable) {
333                         precedence = 0;
334                     } else {
335                         precedence = 1;
336                     }
337                 } else if (type == Boolean.TYPE) {
338                     if (isNullable) {
339                         precedence = 1;
340                     } else {
341                         precedence = 0;
342                     }
343                 }
344                 break;
345         }
346
347         return precedence;
348     }
349
350     void computeTrackedPrimitiveFields() {
351         for (int i = 0; i < classDesc.fields.size(); i++) {
352             FieldDesc tf = (FieldDesc) classDesc.fields.get(i);
353
354             if ((tf instanceof LocalFieldDesc) && (this != tf) && (compareColumns(this, tf) == true)) {
355                 addTrackedField(tf);
356             }
357         }
358     }
359
360     /**
361      * Compute the primary tracked field.
362      */

363     void computePrimaryTrackedPrimitiveField() {
364         ArrayList JavaDoc trackedFields = null;
365
366         // We need to skip fields that are read-only.
367
if (((trackedFields = getTrackedFields()) == null) ||
368                 (sqlProperties & (FieldDesc.PROP_PRIMARY_TRACKED_FIELD |
369                 FieldDesc.PROP_SECONDARY_TRACKED_FIELD |
370                 FieldDesc.PROP_READ_ONLY)) > 0) {
371             return;
372         }
373
374         // We don't know which field is the primary field yet, so we set this field
375
// to be secondary. Once we know that this field is primary, we can unset it.
376
sqlProperties |= FieldDesc.PROP_SECONDARY_TRACKED_FIELD;
377
378         FieldDesc primaryTrackedField = null;
379         int currentPrecedence = Integer.MAX_VALUE;
380         int precedence = 0;
381
382         if ((precedence = computeTypePrecedence()) < currentPrecedence) {
383             primaryTrackedField = this;
384             currentPrecedence = precedence;
385         }
386
387         for (int j = 0; j < trackedFields.size(); j++) {
388             FieldDesc tf = (FieldDesc) trackedFields.get(j);
389
390             // We don't need to assign primary or secondary status for ForeignFieldDesc
391
// because we don't write it to the disk.
392
if (tf instanceof ForeignFieldDesc) {
393                 continue;
394             }
395
396             // We don't know which field is the primary field yet, so we set this field
397
// to be secondary. Once we know the which field is primary, we can unset it.
398
tf.sqlProperties |= FieldDesc.PROP_SECONDARY_TRACKED_FIELD;
399
400             if ((precedence = ((LocalFieldDesc) tf).computeTypePrecedence()) < currentPrecedence) {
401                 primaryTrackedField = tf;
402                 currentPrecedence = precedence;
403             }
404         }
405
406         // If we didn't find any candidate for the primary tracked field,
407
// we pick f as the one.
408
if (primaryTrackedField == null) {
409             primaryTrackedField = this;
410         }
411
412         if (logger.isLoggable(Logger.FINEST)) {
413             logger.finest("sqlstore.model.classdesc.primarytrackedfield", primaryTrackedField.getName()); // NOI18N
414
}
415
416         primaryTrackedField.sqlProperties |= FieldDesc.PROP_PRIMARY_TRACKED_FIELD;
417         primaryTrackedField.sqlProperties &= ~FieldDesc.PROP_SECONDARY_TRACKED_FIELD;
418     }
419
420     void computeTrackedRelationshipFields() {
421
422         if (((sqlProperties & FieldDesc.PROP_REF_INTEGRITY_UPDATES) == 0) &&
423                 ((sqlProperties & FieldDesc.PROP_PRIMARY_KEY_FIELD) == 0)) {
424             return;
425         }
426
427         for (int k = 0; k < classDesc.foreignFields.size(); k++) {
428             ForeignFieldDesc tf = (ForeignFieldDesc) classDesc.foreignFields.get(k);
429
430             if (compareColumns(this, tf) == true) {
431                 // In the case where the relationship has cardinality LWB and UPB
432
// both equal to 1, it is possible for the relationship field to
433
// be mapped to same column as the primary key field. We will
434
// allow this relationship field to be tracked by the primary key field.
435
if (((sqlProperties & FieldDesc.PROP_PRIMARY_KEY_FIELD) > 0) &&
436                         ((tf.cardinalityUPB > 1) || (tf.cardinalityLWB == 0))) {
437                     continue;
438                 }
439
440                 // If f does not track other primitive fields, we need to
441
// make it the primary tracked field because it was skipped
442
// in computeTrackedPrimitiveFields().
443
if (getTrackedFields() == null) {
444                     sqlProperties |= FieldDesc.PROP_PRIMARY_TRACKED_FIELD;
445                 }
446
447                 addTrackedField(tf);
448
449                 // Mark f to indicate that it is tracking a relationship field.
450
sqlProperties |= FieldDesc.PROP_TRACK_RELATIONSHIP_FIELD;
451             }
452         }
453     }
454
455     void cleanupTrackedFields() {
456         ArrayList JavaDoc trackedFields = getTrackedFields();
457
458         if (trackedFields != null) {
459             for (int j = 1; ; j++) {
460                 int index = trackedFields.size() - j;
461
462                 if (index < 0) {
463                     break;
464                 }
465
466                 FieldDesc tf = (FieldDesc) trackedFields.get(index);
467
468                 if (tf instanceof LocalFieldDesc) {
469                     break;
470                 }
471
472                 ArrayList JavaDoc foreignTrackedFields = tf.getTrackedFields();
473
474                 if (foreignTrackedFields != null) {
475                     trackedFields.removeAll(foreignTrackedFields);
476                 }
477             }
478         }
479     }
480
481 }
482
Popular Tags