KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > versant > core > metadata > MetaDataUtils


1
2 /*
3  * Copyright (c) 1998 - 2005 Versant Corporation
4  * All rights reserved. This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License v1.0
6  * which accompanies this distribution, and is available at
7  * http://www.eclipse.org/legal/epl-v10.html
8  *
9  * Contributors:
10  * Versant Corporation - initial API and implementation
11  */

12 package com.versant.core.metadata;
13
14 import java.util.*;
15 import java.lang.reflect.Modifier JavaDoc;
16 import java.lang.reflect.Field JavaDoc;
17 import java.lang.reflect.Method JavaDoc;
18 import java.math.BigDecimal JavaDoc;
19 import java.math.BigInteger JavaDoc;
20 import java.io.IOException JavaDoc;
21 import java.io.DataOutputStream JavaDoc;
22 import java.io.ByteArrayOutputStream JavaDoc;
23 import java.security.MessageDigest JavaDoc;
24 import java.security.DigestOutputStream JavaDoc;
25 import java.security.NoSuchAlgorithmException JavaDoc;
26
27 import com.versant.core.common.BindingSupportImpl;
28
29 /**
30  * This knows how to analyze types to detirmine default persistence
31  * information e.g. persistence-modifier, default-fetch-group and so on.
32  * This is used by the runtime meta data building code and the workbench.
33  *
34  * @see MetaDataBuilder
35  */

36 public final class MetaDataUtils {
37
38     /**
39      * Are we running on jdk 1.5 or higher?
40      */

41     private static boolean isJDK_1_5 = false;
42
43     static {
44         try {
45             Class.forName("java.lang.StringBuilder");
46             isJDK_1_5 = true;
47         } catch (Exception JavaDoc e) {
48             // ignore
49
}
50     }
51
52     /**
53      * This is all the class types that are mutable. These must be cloned
54      * if copies is maintained.
55      */

56     private final HashSet MUTABLE_TYPES = new HashSet();
57
58     /**
59      * Fields with any of these modifiers may not be persistent.
60      */

61     private static final int PM_NONE_FIELD_MODS =
62             Modifier.STATIC | Modifier.FINAL;
63
64     /**
65      * Fields with types in this set are persistent by default.
66      */

67     protected final HashSet PM_PERSISTENT_TYPES = new HashSet();
68
69     /**
70      * Field types in this set default to the default fetch group.
71      */

72     protected final HashSet DFG_TYPES = new HashSet();
73
74     /**
75      * Arrays of types in this set are embedded by default.
76      */

77     protected final HashSet EMBEDDED_ARRAY_TYPES = new HashSet();
78
79     protected static Set BASIC_TYPES = new HashSet();
80
81     private Set classIdSet = new HashSet();
82     private MessageDigest JavaDoc messageDigest;
83     private DataOutputStream JavaDoc hashOut;
84
85     protected HashSet storeTypes = new HashSet(17); // of Class
86

87     // types made persistent through externalization
88
protected HashSet externalizedTypes = new HashSet(17); // of String class name
89

90     public MetaDataUtils() {
91         Class JavaDoc[] mTypes = new Class JavaDoc[]{
92             java.util.Date JavaDoc.class,
93
94             java.util.List JavaDoc.class,
95             java.util.ArrayList JavaDoc.class,
96
97             java.util.LinkedList JavaDoc.class,
98             java.util.Vector JavaDoc.class,
99
100             java.util.Collection JavaDoc.class,
101             java.util.Set JavaDoc.class,
102             java.util.HashSet JavaDoc.class,
103             java.util.TreeSet JavaDoc.class,
104             java.util.SortedSet JavaDoc.class,
105             java.util.SortedMap JavaDoc.class,
106
107             java.util.Map JavaDoc.class,
108             java.util.HashMap JavaDoc.class,
109             java.util.TreeMap JavaDoc.class,
110             java.util.Hashtable JavaDoc.class,
111         };
112
113         
114         for (int i = 0; i < mTypes.length; i++) {
115             MUTABLE_TYPES.add(mTypes[i]);
116         }
117         Class JavaDoc[] dfg = new Class JavaDoc[]{
118             Boolean.TYPE, Byte.TYPE, Short.TYPE, Integer.TYPE,
119             Long.TYPE, Character.TYPE, Float.TYPE, Double.TYPE,
120             Boolean JavaDoc.class, Byte JavaDoc.class, Short JavaDoc.class, Integer JavaDoc.class,
121             Long JavaDoc.class, Character JavaDoc.class, Float JavaDoc.class, Double JavaDoc.class,
122             String JavaDoc.class, BigDecimal JavaDoc.class, BigInteger JavaDoc.class, Date.class,
123
124         };
125         Class JavaDoc[] t = new Class JavaDoc[]{
126             Locale.class, ArrayList.class,
127
128             HashMap.class, HashSet.class,
129             Hashtable.class, LinkedList.class, TreeMap.class, TreeSet.class,
130             SortedSet.class, SortedMap.class,
131             Vector.class, Collection.class, Set.class, List.class, Map.class,
132         };
133
134
135         for (int i = dfg.length - 1; i >= 0; i--) {
136             DFG_TYPES.add(dfg[i]);
137             PM_PERSISTENT_TYPES.add(dfg[i]);
138         }
139         for (int i = t.length - 1; i >= 0; i--) {
140             PM_PERSISTENT_TYPES.add(t[i]);
141         }
142         Class JavaDoc[] emb = new Class JavaDoc[]{
143             Boolean.TYPE, Byte.TYPE, Short.TYPE, Integer.TYPE,
144             Long.TYPE, Character.TYPE, Float.TYPE, Double.TYPE,
145             Boolean JavaDoc.class, Byte JavaDoc.class, Short JavaDoc.class, Integer JavaDoc.class,
146             Long JavaDoc.class, Character JavaDoc.class, Float JavaDoc.class, Double JavaDoc.class,
147
148         };
149         for (int i = emb.length - 1; i >= 0; i--) {
150             if (emb[i].isPrimitive()) EMBEDDED_ARRAY_TYPES.add(emb[i]);
151         }
152
153         Class JavaDoc[] basicTypes = new Class JavaDoc[]{
154             Boolean.TYPE, Byte.TYPE, Short.TYPE, Integer.TYPE,
155             Long.TYPE, Character.TYPE, Float.TYPE, Double.TYPE,
156             Boolean JavaDoc.class, Byte JavaDoc.class, Short JavaDoc.class, Integer JavaDoc.class,
157             Long JavaDoc.class, Character JavaDoc.class, Float JavaDoc.class, Double JavaDoc.class,
158             byte[].class, char[].class, Byte JavaDoc[].class, Character JavaDoc[].class,
159             String JavaDoc.class, BigDecimal JavaDoc.class, BigInteger JavaDoc.class, Date.class,
160             Calendar.class, java.sql.Date JavaDoc.class, java.sql.Time JavaDoc.class,
161             java.sql.Timestamp JavaDoc.class,
162         };
163         for (int i = 0; i < basicTypes.length; i++) {
164             BASIC_TYPES.add(basicTypes[i]);
165         }
166
167         ByteArrayOutputStream JavaDoc devnull = new ByteArrayOutputStream JavaDoc(512);
168         try {
169             messageDigest = MessageDigest.getInstance("SHA");
170             DigestOutputStream JavaDoc mdo = new DigestOutputStream JavaDoc(devnull,
171                     messageDigest);
172             hashOut = new DataOutputStream JavaDoc(mdo);
173         } catch (NoSuchAlgorithmException JavaDoc complain) {
174             throw BindingSupportImpl.getInstance().security(
175                     complain.getMessage());
176         }
177     }
178
179     /**
180      * Clear the set of classId's generated so far and any other statefull
181      * information.
182      */

183     public void clear() {
184         classIdSet.clear();
185         storeTypes.clear();
186         externalizedTypes.clear();
187     }
188
189     /**
190      * Is type a mutable type e.g. java.util.Date etc?
191      */

192     public boolean isMutableType(Class JavaDoc type) {
193         return MUTABLE_TYPES.contains(type);
194     }
195
196     /**
197      * Do the modifiers indicate a field can be persistent?
198      */

199     public boolean isPersistentModifiers(int modifiers) {
200         return (modifiers & PM_NONE_FIELD_MODS) == 0;
201     }
202
203     /**
204      * Do the modifiers indicate a field that is persistent by default?
205      */

206     public boolean isDefaultPersistentModifiers(int modifiers) {
207         return isPersistentModifiers(modifiers) &&
208                 !Modifier.isTransient(modifiers);
209     }
210
211     /**
212      * Is a field of type that can be persistent?
213      *
214      * @param type Type to check
215      * @param classMap Map with all persistent classes as keys
216      */

217     public boolean isPersistentType(Class JavaDoc type, Map classMap) {
218         return isDefaultPersistentType(type, classMap)
219                 || type == Object JavaDoc.class || type.isInterface()
220                 || (type.getComponentType() != null);
221     }
222
223     /**
224      * Is a field of a type that can only be persisted through externalization?
225      */

226     public boolean isPersistableOnlyUsingExternalization(Class JavaDoc type, Map classMap) {
227         boolean et = externalizedTypes.contains(type);
228         if (et) externalizedTypes.remove(type);
229         boolean ans = !isPersistentType(type, classMap);
230         if (et) externalizedTypes.add(type);
231         return ans;
232     }
233
234     /**
235      * Is a field of type that should be persistent by default?
236      *
237      * @param type Type to check
238      * @param classMap Map with all persistent classes as keys
239      */

240     public boolean isDefaultPersistentType(Class JavaDoc type,
241             Map classMap) {
242         
243         if (PM_PERSISTENT_TYPES.contains(type) || classMap.containsKey(type)
244                 || isTypeRegistered(type)
245                 || externalizedTypes.contains(type)) {
246             return true;
247         }
248         type = type.getComponentType();
249         if (type == null) return false;
250         return PM_PERSISTENT_TYPES.contains(type) || classMap.containsKey(type)
251                 || isTypeRegistered(type);
252     }
253
254     /**
255      * Can a field of type with modifiers be considered persistent?
256      *
257      * @param type Type to check
258      * @param modifiers Field modifiers
259      * @param classMap Map with all persistent classes as keys
260      */

261     public boolean isPersistentField(Class JavaDoc type, int modifiers,
262             Map classMap) {
263         return isPersistentModifiers(modifiers)
264                 && isPersistentType(type, classMap);
265     }
266
267     /**
268      * Is the field of of those added by the enhancer?
269      */

270     public boolean isEnhancerAddedField(String JavaDoc fieldName) {
271         return
272
273             fieldName.startsWith("jdo");
274     }
275
276     /**
277      * Should f be considered persistent by default?
278      */

279     public boolean isDefaultPersistentField(ClassMetaData.FieldInfo f, Map classMap) {
280         return !isEnhancerAddedField(f.getName())
281                 && isDefaultPersistentModifiers(f.getModifiers())
282                 && isDefaultPersistentType(f.getType(), classMap);
283     }
284
285     /**
286      * Should f be considered persistent by default?
287      */

288     public boolean isDefaultPersistentField(Field JavaDoc f,
289             Map classMap) {
290         return !isEnhancerAddedField(f.getName())
291                 && isDefaultPersistentModifiers(f.getModifiers())
292                 && isDefaultPersistentType(f.getType(), classMap);
293     }
294
295     /**
296      * Can f be persisted?
297      */

298     public boolean isPersistableField(Field JavaDoc f, Map classMap) {
299         return !isEnhancerAddedField(f.getName())
300                 && isPersistentModifiers(f.getModifiers());
301     }
302
303     /**
304      * Should this field be part of the default fetch group by default?
305      */

306     public boolean isDefaultFetchGroupType(Class JavaDoc type) {
307         return DFG_TYPES.contains(type)
308                 || isTypeRegistered(type)
309                 || externalizedTypes.contains(type);
310     }
311
312     /**
313      * Should a field of type be embedded by default?
314      */

315     public boolean isEmbeddedType(Class JavaDoc type) {
316         if (DFG_TYPES.contains(type) || externalizedTypes.contains(type)) {
317             return true;
318         }
319         type = type.getComponentType();
320         return type != null && EMBEDDED_ARRAY_TYPES.contains(type);
321     }
322
323     /**
324      * What category does a field with the supplied attributes belong to?
325      *
326      * @param persistenceModifier Transactional fields are CATEGORY_TRANSACTIONAL
327      * @param type Type of field
328      * @param classMap Map with all persistent classes as keys
329      * @return One of the MDStatics.CATEGORY_xxx constants
330      * @see MDStatics
331      */

332     public int getFieldCategory(int persistenceModifier, Class JavaDoc type,
333             Map classMap) {
334         switch (persistenceModifier) {
335
336             case MDStatics.PERSISTENCE_MODIFIER_PERSISTENT:
337                 if (externalizedTypes.contains(type)) {
338                     return MDStatics.CATEGORY_EXTERNALIZED;
339                 } else if (type.getComponentType() != null) {
340                     return MDStatics.CATEGORY_ARRAY;
341                 } else if (classMap.containsKey(type)) {
342                     if (type.isInterface()) return MDStatics.CATEGORY_POLYREF;
343                     return MDStatics.CATEGORY_REF;
344                 } else if (Collection.class.isAssignableFrom(type)) {
345                     return MDStatics.CATEGORY_COLLECTION;
346
347                 } else if (Map.class.isAssignableFrom(type)) {
348                     return MDStatics.CATEGORY_MAP;
349                 } else if (type.isInterface() || type == Object JavaDoc.class) {
350                     return MDStatics.CATEGORY_POLYREF;
351                 } else if (!Map.class.isAssignableFrom(type)
352                         && !Collection.class.isAssignableFrom(type)
353                         && !isPersistentType(type, classMap)) {
354                     return MDStatics.CATEGORY_EXTERNALIZED;
355                 }
356                 return MDStatics.CATEGORY_SIMPLE;
357
358             case MDStatics.PERSISTENCE_MODIFIER_TRANSACTIONAL:
359                 return MDStatics.CATEGORY_TRANSACTIONAL;
360
361             case MDStatics.PERSISTENCE_MODIFIER_NONE:
362                 return MDStatics.CATEGORY_NONE;
363         }
364         throw BindingSupportImpl.getInstance().internal("Bad persistence-modifier code: " +
365                 persistenceModifier);
366     }
367
368     /**
369      * Generate the classId for the class. This is a positive int computed
370      * from a hash of the class name with duplicates resolved by incrementing
371      * the id.
372      */

373     public int generateClassId(String JavaDoc qname) {
374         int classId = computeClassId(qname);
375         for (;
376              classIdSet.contains(new Integer JavaDoc(classId));
377              classId = (classId + 1) & 0x7FFFFFFF) {
378             ;
379         }
380         classIdSet.add(new Integer JavaDoc(classId));
381         return classId;
382     }
383
384     private int computeClassId(String JavaDoc className) {
385         int hash = 0;
386         try {
387             hashOut.writeUTF(className);
388             /* Compute the hash value for this class name.
389              * Use only the first 64 bits of the hash.
390              */

391             hashOut.flush();
392             byte hasharray[] = messageDigest.digest();
393             int len = hasharray.length;
394             if (len > 8) len = 8;
395             for (int i = 0; i < len; i++) {
396                 hash += (hasharray[i] & 255) << (i * 4);
397             }
398             hash &= 0x7FFFFFFF; // make sure it is always positive
399
} catch (IOException JavaDoc ignore) {
400             /* can't happen, but be deterministic anyway. */
401             hash = -1;
402         }
403         return hash;
404     }
405
406     /**
407      * Register a store specific persistent type.
408      */

409     public void registerStoreType(Class JavaDoc type) {
410         storeTypes.add(type);
411     }
412
413     /**
414      * Has a store specific persistent type been registered?
415      */

416     public boolean isTypeRegistered(Class JavaDoc type) {
417         return storeTypes.contains(type);
418     }
419
420     /**
421      * Get the element type for a Collection if possible using the JDK 1.5
422      * generics API or null if not possible.
423      */

424     public static Class JavaDoc getGenericElementType(Field JavaDoc field) {
425         return getType(field, 0);
426     }
427
428     /**
429      * Get the key type for a Map if possible using the JDK 1.5
430      * generics API or null if not possible.
431      */

432     public static Class JavaDoc getGenericKeyType(Field JavaDoc field) {
433         return getType(field, 0);
434     }
435
436     /**
437      * Get the value type for a Map if possible using the JDK 1.5 generics
438      * API or null if not possible.
439      */

440     public static Class JavaDoc getGenericValueType(Field JavaDoc field) {
441         return getType(field, 1);
442     }
443
444     /**
445      * Get the class type of Collections and Maps with jdk1.5 generics if at all
446      * possible
447      */

448     private static Class JavaDoc getType(Field JavaDoc field, int index) {
449         if (isJDK_1_5) {
450             // do reflection on the jdk1.5 reflection methods
451
Class JavaDoc clazz = null;
452             try {
453                 Method JavaDoc methodGetGenericType = field.getClass().getMethod(
454                         "getGenericType",
455                         new Class JavaDoc[]{});
456                 if (methodGetGenericType == null) return null;
457                 Object JavaDoc type = methodGetGenericType.invoke(field,
458                         new Object JavaDoc[]{});
459                 if (type == null) return null;
460                 Method JavaDoc methodActualTypeArguments = type.getClass().getMethod(
461                         "getActualTypeArguments",
462                         new Class JavaDoc[]{});
463                 if (methodActualTypeArguments == null) return null;
464                 Object JavaDoc typeArray = methodActualTypeArguments.invoke(type,
465                         new Object JavaDoc[]{});
466                 if (typeArray == null) return null;
467                 Object JavaDoc[] types = (Object JavaDoc[])typeArray;
468                 clazz = (Class JavaDoc)types[index];
469             } catch (Exception JavaDoc e) {
470                 /*hide it all*/
471             }
472             return clazz;
473         } else {
474             return null;
475         }
476     }
477
478     /**
479      * Register a type that is persisted using an externalizer.
480      */

481     public void registerExternalizedType(Class JavaDoc t) {
482         externalizedTypes.add(t);
483     }
484
485     /**
486      * If this is a Basic type as defined by ejb3 spec.
487      */

488     public boolean isBasicType(Class JavaDoc t) {
489         return BASIC_TYPES.contains(t);
490     }
491
492
493 }
494
Popular Tags