KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > jdo > api > persistence > model > Model


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  * Model.java
26  *
27  * Created on March 9, 2000, 6:19 PM
28  */

29
30 package com.sun.jdo.api.persistence.model;
31
32 import java.io.*;
33 import java.util.*;
34 import java.lang.reflect.Modifier JavaDoc;
35
36 import org.netbeans.modules.dbschema.migration.archiver.XMLInputStream;
37 import org.netbeans.modules.dbschema.migration.archiver.XMLOutputStream;
38
39 import org.netbeans.modules.dbschema.SchemaElement;
40 import com.sun.jdo.api.persistence.model.util.LogHelperModel;
41 import com.sun.jdo.api.persistence.model.util.ModelValidator;
42 import com.sun.jdo.api.persistence.model.jdo.*;
43 import com.sun.jdo.api.persistence.model.jdo.impl.*;
44 import com.sun.jdo.api.persistence.model.mapping.MappingClassElement;
45 import com.sun.jdo.api.persistence.model.mapping.MappingFieldElement;
46 import com.sun.jdo.api.persistence.model.mapping.impl.MappingClassElementImpl;
47 import com.sun.jdo.spi.persistence.utility.*;
48 import com.sun.jdo.spi.persistence.utility.logging.Logger;
49
50 /* TODO:
51     1. think about moving illegal lists of static info out to a properties file
52     2. think about throwing an exception or setting the declaring class/table
53     on add member in both models (jdo and mapping).
54     3. add an extra level (bridge pattern) for java elements (generic, member,
55     class, field) so can use those instead of names
56     4. javadoc: @exception vs. @throws
57     5. review javadoc, try generating with -link to java.sun.com for Integer
58     calls
59     6. Move various ARGS constants to a better place, like an extra class.
60
61  */

62
63 /**
64  *
65  * @author raccah
66  * @version %I%
67  */

68 public abstract class Model
69 {
70     /** Default instance of the model for use at runtime. */
71     public static final Model RUNTIME;
72
73     /** Default instance of the model used by the enhancer. */
74     public static final Model ENHANCER;
75
76     /** Standard set of arguments for comparison with equals method.
77      */

78     public static final String JavaDoc[] EQUALS_ARGS = {"java.lang.Object"}; //NOI18N
79

80     /** Standard set of empty arguments (for comparison with hashCode method
81      * and no-arg constructor).
82      */

83     public static final String JavaDoc[] NO_ARGS = new String JavaDoc[0];
84
85     /** Standard set of arguments for comparison with readObject method.
86      */

87     public static final String JavaDoc[] READ_OBJECT_ARGS = {"java.io.ObjectInputStream"}; //NOI18N
88

89     /** Standard set of arguments for comparison with writeObject method.
90      */

91     public static final String JavaDoc[] WRITE_OBJECT_ARGS = {"java.io.ObjectOutputStream"}; //NOI18N
92

93     /** Map of mapping class elements which have been loaded. Keys are fully
94      * qualified class names.
95      */

96     private final Map _classes = new WeakValueHashMap();
97
98     /** Set of fully qualified names of classes known to be
99      * non persistence-capable.
100      */

101     private final Set _nonPCClasses = new WeakHashSet();
102
103     /** List of illegal package name prefixes for superclasses of
104      * persistence capable classes.
105      */

106     private static List _illegalPrefixes;
107
108     /** List of illegal class names for superclasses of persistence capable
109      * classes.
110      */

111     private static List _illegalClasses;
112
113     /** List of class names for second class objects. */
114     private static List _scoClasses;
115
116     /** List of class names for mutable second class objects. */
117     private static List _mutableScoClasses;
118
119     /** List of class names for collections. */
120     private static List _collectionClasses;
121
122     /** I18N message base */
123     public static final String JavaDoc messageBase =
124         "com.sun.jdo.api.persistence.model.Bundle"; // NOI18N
125

126     /** I18N message handler */
127     private static final ResourceBundle _messages = I18NHelper.loadBundle(
128         Model.class);
129
130     static
131     {
132         String JavaDoc prefixes[] =
133             {"java.awt", "java.applet", "javax.swing", "javax.ejb"};// NOI18N
134
String JavaDoc classes[] = {"java.lang.Throwable"}; // NOI18N
135
String JavaDoc collectionClasses[] = { "java.util.Collection", // NOI18N
136
"java.util.AbstractCollection", // NOI18N
137
//"java.util.List", "java.util.AbstractList", // NOI18N
138
"java.util.Set", "java.util.AbstractSet", // NOI18N
139
//"java.util.ArrayList", "java.util.Vector", // NOI18N
140
"java.util.HashSet", // NOI18N
141
//"com.sun.jdo.spi.persistence.support.sqlstore.sco.ArrayList", // NOI18N
142
//"com.sun.jdo.spi.persistence.support.sqlstore.sco.Vector", // NOI18N
143
"com.sun.jdo.spi.persistence.support.sqlstore.sco.HashSet"}; // NOI18N
144
String JavaDoc mutableScoClasses[] = {"java.util.Date", // NOI18N
145
"com.sun.jdo.spi.persistence.support.sqlstore.sco.Date", "java.sql.Date",// NOI18N
146
"com.sun.jdo.spi.persistence.support.sqlstore.sco.SqlDate", // NOI18N
147
"java.sql.Time", "com.sun.jdo.spi.persistence.support.sqlstore.sco.SqlTime", // NOI18N
148
"java.sql.Timestamp", // NOI18N
149
"com.sun.jdo.spi.persistence.support.sqlstore.sco.SqlTimestamp"}; // NOI18N
150
String JavaDoc scoClasses[] = {"java.lang.String", // NOI18N
151
"java.lang.Character", "java.lang.Boolean", // NOI18N
152
"java.lang.Long", "java.lang.Number", "java.lang.Byte", // NOI18N
153
"java.lang.Short", "java.lang.Integer", "java.lang.Float", // NOI18N
154
"java.lang.Double", "java.math.BigDecimal", // NOI18N
155
"java.math.BigInteger"}; // NOI18N
156

157         _illegalPrefixes = Arrays.asList(prefixes);
158         _illegalClasses = Arrays.asList(classes);
159         _collectionClasses = Arrays.asList(collectionClasses);
160         _mutableScoClasses = new ArrayList(Arrays.asList(mutableScoClasses));
161         _mutableScoClasses.addAll(_collectionClasses);
162         _scoClasses = new ArrayList(Arrays.asList(scoClasses));
163         _scoClasses.addAll(_mutableScoClasses);
164
165         // always load the runtime model
166
RUNTIME = NewModel(null, "com.sun.jdo.api.persistence.model.RuntimeModel"); //NOI18N
167
// always load the enhancer model
168
ENHANCER = NewModel(null, "com.sun.jdo.api.persistence.model.EnhancerModel"); //NOI18N
169
}
170
171         /** Create a new Model of the requested type. If the class definition
172          * exists in the class path of the environment, then this method will
173          * create a new instance of the Model.
174          * @param modelName the fully qualified name of the class to be
175          * instantiated.
176          * @param testName the fully qualified name of the class to be tested
177          * as a precondition to loading.
178          * @return a new instance of the requested class (which implements
179          * Model).
180          */

181         static protected Model NewModel (String JavaDoc testName, String JavaDoc modelName) {
182             Class JavaDoc DynamicClass = null;
183             Model model = null;
184             try {
185                 if (testName != null)
186                     // try this class as a precondition to the real class to load
187
Class.forName (testName);
188                 DynamicClass = Class.forName (modelName);
189                 if (DynamicClass != null)
190                     model = (Model) DynamicClass.newInstance();
191             }
192             catch (Exception JavaDoc e) {
193                 // this is expected in the environment
194
}
195             return model;
196         }
197     /** @return I18N message handler for this element
198      */

199     protected static final ResourceBundle getMessages ()
200     {
201         return _messages;
202     }
203
204     /** Returns the input stream with the supplied resource name found with
205      * the supplied class name.
206      * @param className the fully qualified name of the class which will be
207      * used as a base to find the resource
208      * @param classLoader the class loader used to find mapping information
209      * @param resourceName the name of the resource to be found
210      * @return the input stream for the specified resource, <code>null</code>
211      * if an error occurs or none exists
212      */

213     abstract protected BufferedInputStream getInputStreamForResource (
214         String JavaDoc className, ClassLoader JavaDoc classLoader, String JavaDoc resourceName);
215
216     /** Determines if the specified className represents an interface type.
217      * @param className the fully qualified name of the class to be checked
218      * @return <code>true</code> if this class name represents an interface;
219      * <code>false</code> otherwise.
220      */

221     abstract public boolean isInterface (String JavaDoc className);
222
223     /** Determines if the specified className has a persistent superclass.
224      * @param className the fully qualified name of the class to be checked
225      * @return <code>true</code> if this class name represents a class which
226      * has a persistent superclass (anywhere in the inheritance chain);
227      * <code>false</code> otherwise.
228      */

229     public boolean hasPersistentSuperclass (String JavaDoc className)
230     {
231         while ((className = getSuperclass(className)) != null)
232         {
233             if (isPersistent(className))
234                 return true;
235         }
236
237         return false;
238     }
239
240     /** Returns the name of the second to top (top excluding java.lang.Object)
241      * superclass for the given class name.
242      * @param className the fully qualified name of the class to be checked
243      * @return the top non-Object superclass for className,
244      * <code>className</code> if an error occurs or none exists
245      */

246     abstract protected String JavaDoc findPenultimateSuperclass (String JavaDoc className);
247
248     /** Returns the name of the superclass for the given class name.
249      * @param className the fully qualified name of the class to be checked
250      * @return thesuperclass for className, <code>null</code> if an error
251      * occurs or none exists
252      */

253     abstract protected String JavaDoc getSuperclass (String JavaDoc className);
254
255     /** Returns a PersistenceClassElement created from the specified class name.
256      * Since our implementation of the mapping model class includes the
257      * persistence class, this method finds the persistence class by extracting
258      * it from the mapping class for the supplied name.
259      * @param className the fully qualified name of the persistence capable
260      * class to be returned
261      * @return the PersistenceClassElement for className,
262      * <code>null</code> if an error occurs or none exists
263      * @see #getMappingClass
264      */

265     public PersistenceClassElement getPersistenceClass (String JavaDoc className)
266     {
267         return getPersistenceClass(className, null);
268     }
269
270     /** Returns a PersistenceClassElement created from the specified class name.
271      * Since our implementation of the mapping model class includes the
272      * persistence class, this method finds the persistence class by extracting
273      * it from the mapping class for the supplied name.
274      * @param className the fully qualified name of the persistence capable
275      * class to be returned
276      * @param classLoader the class loader used to find mapping information
277      * @return the PersistenceClassElement for className,
278      * <code>null</code> if an error occurs or none exists
279      * @see #getMappingClass
280      */

281     public PersistenceClassElement getPersistenceClass (String JavaDoc className,
282         ClassLoader JavaDoc classLoader)
283     {
284         return getPersistenceClass(getMappingClass(className, classLoader));
285     }
286
287     /** Returns a PersistenceClassElement created from the mapping class.
288      * @param mappingClass the mapping class element to which the persistence
289      * class is associated
290      * @return the PersistenceClassElement for mappingClass,
291      * <code>null</code> if an error occurs or none exists
292      * @see #getMappingClass
293      */

294     protected PersistenceClassElement getPersistenceClass (
295         MappingClassElement mappingClass)
296     {
297         return ((mappingClass == null) ? null :
298             ((MappingClassElementImpl)mappingClass).getPersistenceElement());
299     }
300
301     /** Returns the MappingClassElement created for the specified class name.
302      * This method looks up the class in the internal cache. If not present
303      * it loads the corresponding xml file containing the mapping information.
304      * @param className the fully qualified name of the mapping class
305      * @return the MappingClassElement for class,
306      * <code>null</code> if an error occurs or none exists
307      */

308     public MappingClassElement getMappingClass (String JavaDoc className)
309     {
310         return getMappingClass(className, null);
311     }
312
313     /** Returns the MappingClassElement created for the specified class name.
314      * This method looks up the class in the internal cache. If not present
315      * it loads the corresponding xml file containing the mapping information.
316      * @param className the fully qualified name of the mapping class
317      * @param classLoader the class loader used to find mapping information
318      * @return the MappingClassElement for className,
319      * <code>null</code> if an error occurs or none exists
320      * @see MappingClassElementImpl#forName
321      */

322     public MappingClassElement getMappingClass (String JavaDoc className,
323        ClassLoader JavaDoc classLoader)
324     {
325         // This method synchronizes the access of the _classes cache,
326
// rather than using a synchronized map. This is for optimization only.
327
// Otherwise two parallel calls would read the mapping file twice,
328
// create two MCE instances and the second MCE instance would replace
329
// the first in the cache.
330
// Any other access of _classes potentially needs to be synchronized
331
// using the same variable _classes (e.g. updateKeyForClass).
332
synchronized (this._classes)
333         {
334             MappingClassElement mappingClass =
335                 (MappingClassElement)_classes.get(className);
336
337             if (mappingClass == null)
338             {
339                 // check whether the class is known to be non PC
340
if (_nonPCClasses.contains(className))
341                     return null;
342
343                 try
344                 {
345                     InputStream stream = getInputStreamForResource(className,
346                         classLoader, getResourceNameWithExtension(className));
347
348                     if (stream != null)
349                     {
350                         // if the file is empty, the archiver prints an
351
// exception, so protect against that case and
352
// return null without updating either cache
353
if (stream.available() > 0)
354                         {
355                             XMLInputStream xmlInput = new XMLInputStream(stream,
356                                 getClass().getClassLoader());
357
358                             mappingClass =
359                                 (MappingClassElement)xmlInput.readObject();
360                             xmlInput.close();
361
362                             // postUnarchive performs version number checking
363
// and possible format conversions
364
mappingClass.postUnarchive();
365
366                             // can't call updateKeyForClass here there are cases
367
// when the mapping class name doesn't match the
368
// classname (such as copy/paste, move etc.)
369
_classes.put(className, mappingClass);
370
371                             // update the modified flags for the mapping and
372
// persistence classes since the xml archiver uses
373
// all the set methods
374
mappingClass.setModified(false);
375                             getPersistenceClass(mappingClass).
376                                 setModified(false);
377                         }
378                     }
379                     else
380                     {
381                         // stream is null, mapping file does not exist =>
382
// class is not PC, so store the class name in the
383
// set of classes known to be non PC
384
_nonPCClasses.add(className);
385                     }
386                 }
387                 catch (ModelException e)
388                 {
389                     // MBO: print reason to logger
390
LogHelperModel.getLogger().log(Logger.WARNING,
391                         e.getMessage());
392                     return null;
393                 }
394                 catch (Exception JavaDoc e)
395                 {
396                     // MBO: print reason to logger
397
LogHelperModel.getLogger().log(Logger.WARNING,
398                         I18NHelper.getMessage(getMessages(),
399                         "file.cannot_read", className, e.toString())); //NOI18N
400
} // will return null
401
}
402
403             return mappingClass;
404         }
405     }
406
407     /** Returns an unmodifiable copy of the MappingClassElement cache.
408      * @return unmodifiable MappingClassElement cache
409      */

410     public Map getMappingCache ()
411     {
412         return Collections.unmodifiableMap(_classes);
413     }
414
415     /** Returns an unmodifiable copy of the ClassLoader cache.
416      * This implementation returns null, but subclasses (such as RuntimeModel)
417      * can override this method if they support a class loader cache.
418      * @return unmodifiable ClassLoader cache
419      */

420     public Map getClassLoaderCache ()
421     {
422         return null;
423     }
424
425     /** Removes the classes cached with the specified class loader from all
426      * caches.
427      * This implementation does nothing, but subclasses (such as RuntimeModel)
428      * can override this method if they support a class loader cache.
429      * @param classLoader used to determine the classes to be removed
430      */

431     public void removeResourcesFromCaches (ClassLoader JavaDoc classLoader)
432     {
433         // Do nothing in the top-level model.
434
}
435     
436     /** Removes the specified classes from all caches. The specified
437      * collection includes the fully qualified class names of the classes
438      * to be removed. The method removes each class from the cache of
439      * MappingClassElements and the set of classes known to be non
440      * PC. Furthermore it removes the SchemaElement associated with this
441      * class from the SchemaElement cache. The next call getMappingClass
442      * will determine the status of the classes.
443      * @param classNames a collection of fully qualified class names
444      */

445     protected void removeResourcesFromCaches (Collection classNames)
446     {
447         if (classNames == null)
448             return;
449
450         synchronized (this._classes)
451         {
452             for (Iterator i = classNames.iterator(); i.hasNext();)
453             {
454                 String JavaDoc className = (String JavaDoc)i.next();
455                 MappingClassElement mapping =
456                     (MappingClassElement)_classes.get(className);
457
458                 // If the cache has a MappingClassElement with the specified
459
// className, get its databaseRoot and remove the corresonding
460
// SchemaElement from the SchemaElement cache.
461
if (mapping != null)
462                     SchemaElement.removeFromCache(mapping.getDatabaseRoot());
463                 
464                 // remove the corresponding MappingClassElement from cache
465
_classes.remove(className);
466                 
467                 // remove the class from the set of classes known to be non PC
468
_nonPCClasses.remove(className);
469             }
470         }
471     }
472
473     /** Removes the class with the supplied name from the cache of
474      * classes known to be non PC.
475      * The next call getMappingClass will determine the status of the class.
476      * @param className the fully qualified name of the class
477      */

478     public void removeFromCache (String JavaDoc className)
479     {
480         synchronized (this._classes)
481         {
482             // remove the class from the set of classes known to be non PC
483
_nonPCClasses.remove(className);
484         }
485     }
486
487     /** Stores the supplied MappingClassElement to an xml file, creating the
488      * file if necessary. The caller is responsible for updating the cache
489      * by calling updateKeyForClass, if necessary.
490      * @param mappingClass the mapping class to be saved
491      * @exception IOException if there is some error saving the class
492      * @see #createFile
493      */

494     public void storeMappingClass (MappingClassElement mappingClass)
495         throws IOException
496     {
497         if (mappingClass != null)
498         {
499             String JavaDoc className = mappingClass.getName();
500             OutputStream stream = ((className == null) ? null :
501                 createFile(className, getFileName(className),
502                 MappingClassElement.MAPPING_EXTENSION));
503
504             storeMappingClass(mappingClass, stream);
505         }
506     }
507
508     /** Stores the supplied MappingClassElement to an xml file in the
509      * specified output stream. The caller is responsible for updating
510      * the cache by calling updateKeyForClass, if necessary.
511      * @param mappingClass the mapping class to be saved
512      * @param stream the output stream
513      * @exception IOException if there is some error saving the class
514      * @see #createFile
515      */

516     public void storeMappingClass (MappingClassElement mappingClass,
517         OutputStream stream) throws IOException
518     {
519         if (mappingClass != null)
520         {
521             String JavaDoc className = mappingClass.getName();
522
523             if (stream != null)
524             {
525                 XMLOutputStream xmlOutput = new XMLOutputStream(stream);
526
527                 try
528                 {
529                     mappingClass.preArchive(); // call pre archive hook
530
xmlOutput.writeObject(mappingClass);
531
532                     // update modified flags for the mapping and persistence
533
// classes after save
534
mappingClass.setModified(false);
535                     getPersistenceClass(mappingClass).setModified(false);
536                 }
537                 catch (ModelException e)
538                 {
539                     // MBO: print reason to logger
540
LogHelperModel.getLogger().log(Logger.WARNING,
541                         e.getMessage());
542                 }
543                 finally
544                 {
545                     if (xmlOutput != null)
546                         xmlOutput.close();
547
548                     unlockFile(stream, className);
549                 }
550                 return;
551             }
552
553             throw new IOException(I18NHelper.getMessage(getMessages(),
554                 "file.cannot_save", className)); // NOI18N
555
}
556     }
557
558     public void unlockFile (OutputStream stream, String JavaDoc className)
559         throws IOException
560     {
561         unlockFile(className);
562
563         if (stream != null)
564             stream.close();
565     }
566
567     // overridden in DevelopmentModel
568
public void lockFile (String JavaDoc className) throws IOException {}
569
570     // overridden in DevelopmentModel
571
public void unlockFile (String JavaDoc className) {}
572
573     /** Stores the MappingClassElement for the specified class name to an xml
574      * file, creating the file if necessary. The MappingClassElement must be
575      * present in the HashMap of classes known by the Model in order to stored.
576      * @param className the fully qualified name of the mapping class
577      * @exception IOException if there is some error saving the class
578      * @see #storeMappingClass
579      */

580     public void storeMappingClass (String JavaDoc className) throws IOException
581     {
582         MappingClassElement mappingClass = null;
583
584         synchronized (this._classes)
585         {
586             mappingClass = (MappingClassElement)_classes.get(className);
587         }
588         storeMappingClass(mappingClass);
589     }
590
591     /** Updates the key in the cache for the supplied MappingClassElement.
592      * @param mappingClass the mapping class to be put in the cache
593      * (the new name is extracted from this element). The corresponding
594      * handling of the files is automatically handled by the data object.
595      * (use <code>null</code> to remove the old key but not replace it)
596      * @param oldName the fully qualified name of the old key for the mapping
597      * class (use <code>null</code> to add the new key but not replace it)
598      */

599     public void updateKeyForClass (MappingClassElement mappingClass,
600         String JavaDoc oldName)
601     {
602         // need to synchronize _classes access here
603
// (for details see getMappingClass)
604
synchronized (this._classes)
605         {
606             // remove the old key from the cache
607
if (oldName != null)
608                 _classes.remove(oldName);
609
610             // store the class under the new key in the cache
611
if (mappingClass != null)
612             {
613                 String JavaDoc className = mappingClass.getName();
614
615                 _classes.put(className, mappingClass);
616
617                 // ensure that the name of the mappingClass does not occur
618
// in the list of classes known to be non PC
619
_nonPCClasses.remove(className);
620             }
621         }
622     }
623
624     /** Determines if the specified className represents a persistence capable
625      * class. A class is persistence capable only if it is directly marked as
626      * such -- not by inheritance.
627      * @param className the fully qualified name of the class to be checked
628      * @return <code>true</code> if this class name represents a persistence
629      * capable class; <code>false</code> otherwise.
630      */

631     public boolean isPersistent (String JavaDoc className)
632     {
633         return isPersistent(className, (ClassLoader JavaDoc)null);
634     }
635
636
637     /** Determines if the specified className represents a persistence capable
638      * class. A class is persistence capable only if it is directly marked as
639      * such -- not by inheritance.
640      * @param className the fully qualified name of the class to be checked
641      * @param classLoader the class loader used to find mapping information
642      * @return <code>true</code> if this class name represents a persistence
643      * capable class; <code>false</code> otherwise.
644      */

645     public boolean isPersistent (String JavaDoc className, ClassLoader JavaDoc classLoader)
646     {
647         return (getPersistenceClass(className, classLoader) != null);
648     }
649
650     /** Determines if the specified className represents a legal candidate for
651      * becoming a persistence capable class. A class may not become
652      * persistence capable if it is declared as static or abstract, an
653      * interface, a subclass of another persistence capable class
654      * (either direct or indirect), an exception subclass, or a subclass
655      * of ejb, swing, awt, or applet classes.
656      * @param className the fully qualified name of the class to be checked
657      * @return <code>true</code> if this class name represents a legal
658      * candidate for becoming a persistence capable class;
659      * <code>false</code> otherwise.
660      * @see #getModifiersForClass
661      * @see #isInterface
662      * @see #findPenultimateSuperclass
663      */

664     public boolean isPersistenceCapableAllowed (String JavaDoc className)
665     {
666         int modifier = getModifiersForClass(className);
667
668         if (!Modifier.isStatic(modifier) && !Modifier.isAbstract(modifier) &&
669             !isInterface(className) && !hasPersistentSuperclass(className))
670         {
671             String JavaDoc highestSuperclassName = findPenultimateSuperclass(className);
672             Iterator iterator = _illegalPrefixes.iterator();
673
674             while (iterator.hasNext())
675             {
676                 String JavaDoc nextPrefix = iterator.next().toString();
677
678                 if (highestSuperclassName.startsWith(nextPrefix))
679                     return false;
680             }
681
682             iterator = _illegalClasses.iterator();
683             while (iterator.hasNext())
684             {
685                 String JavaDoc nextClass = iterator.next().toString();
686
687                 if (highestSuperclassName.equals(nextClass))
688                     return false;
689             }
690
691             return true;
692         }
693
694         return false;
695     }
696
697     /** Computes the mapping file resource name (with extension) for the
698      * supplied class name by converting the package name to a resource name.
699      * @param className the fully qualified name of the class
700      * @return the mapping file resource name (with extension) for the supplied
701      * class name
702      * @see MappingClassElement#MAPPING_EXTENSION
703      */

704     protected String JavaDoc getResourceNameWithExtension (String JavaDoc className)
705     {
706         return getResourceName(className) + "." + // NOI18N
707
MappingClassElement.MAPPING_EXTENSION;
708     }
709
710     /** Computes the base resource name (without extension) for the supplied
711      * class name by converting the package name to a resource name.
712      * @param className the fully qualified name of the class
713      * @return the base resource name (without extension) for the supplied
714      * class name
715      */

716     protected String JavaDoc getResourceName (String JavaDoc className)
717     {
718         return ((className != null) ?
719             className.replace('.', '/') : null);
720     }
721
722     /** Computes the mapping file name (with extension) for the supplied
723      * class name by converting the package name to a path name.
724      * @param className the fully qualified name of the class
725      * @return the mapping file name (with extension) for the supplied
726      * class name
727      * @see #getFileName
728      * @see MappingClassElement#MAPPING_EXTENSION
729      */

730     protected String JavaDoc getFileNameWithExtension (String JavaDoc className)
731     {
732         return getFileName(className) + "." + // NOI18N
733
MappingClassElement.MAPPING_EXTENSION;
734     }
735
736     /** Computes the base file name (without extension) for the supplied
737      * class name by converting the package name to a path name.
738      * @param className the fully qualified name of the class
739      * @return the base file name (without extension) for the supplied
740      * class name
741      */

742     protected String JavaDoc getFileName (String JavaDoc className)
743     {
744         return ((className != null) ?
745             className.replace('.', File.separatorChar) : null);
746     }
747
748     /** Converts the class with the supplied name to or from persistence
749      * capable depending on the flag.
750      * @param className the fully qualified name of the class
751      * @param flag if <code>true</code>, convert this class to be
752      * persistence capable, if <code>false</code>, convert this class
753      * to be non-persistence capable
754      * @exception IOException if there is some error converting the class
755      */

756     public void convertToPersistenceCapable (String JavaDoc className,
757         boolean flag) throws IOException
758     {
759         boolean classIsPersistent = isPersistent(className);
760         Exception JavaDoc conversionException = null;
761
762         if (flag && !classIsPersistent &&
763             isPersistenceCapableAllowed(className))
764         {
765             try
766             {
767                 // this calls updateKeyForClass which updates
768
// the mapping cache and the set of classes known to be non PC
769
createSkeletonMappingClass(className);
770             }
771             catch (Exception JavaDoc e)
772             {
773                 // need to unconvert whatever partial conversion succeeded
774
conversionException = e;
775             }
776         }
777
778         if ((!flag && classIsPersistent) || (conversionException != null))
779         {
780             try
781             {
782                 // delete the mapping file
783
deleteFile(className, getFileNameWithExtension(className));
784
785                 synchronized (this._classes)
786                 {
787                     // remove the corresponding MappingClassElement from cache
788
_classes.remove(className);
789                     
790                     // put the class in the set of classes known to be non PC
791
_nonPCClasses.add(className);
792                 }
793             }
794             catch (Exception JavaDoc e) // rethrow if not a problem during unconvert
795
{
796                 if (conversionException == null)
797                     conversionException = e;
798             }
799         }
800
801         if (conversionException != null) // rethrow the exception
802
{
803             if (conversionException instanceof RuntimeException JavaDoc)
804                 throw (RuntimeException JavaDoc)conversionException;
805             else if (conversionException instanceof IOException)
806                 throw (IOException)conversionException;
807         }
808     }
809
810     /** Converts the class with the supplied name to persistence-capable,
811      * then convert its default fields and save it to the xml file.
812      * @param className the fully qualified name of the class
813      * @exception IOException if there is some error storing the class
814      */

815     public void convertToPersistenceCapable (String JavaDoc className)
816         throws IOException
817     {
818         convertToPersistenceCapable(className, true);
819         convertDefaultFields(className);
820         storeMappingClass(className);
821     }
822
823     /** Creates a PersistenceClassElement with the specified name, then wraps
824      * it in a mapping class and stores it in the hash map of classes.
825      * This is the first phase of converting a class to be persistence-capable.
826      * @param className the fully qualified name of the class
827      * @see #convertDefaultFields
828      * @see #updateKeyForClass
829      */

830     private void createSkeletonMappingClass (String JavaDoc className)
831     {
832         PersistenceClassElement element = new PersistenceClassElement(
833             new PersistenceClassElementImpl(className));
834
835         updateKeyForClass(new MappingClassElementImpl(element), null);
836     }
837
838     /** Adds the default allowable persistent fields to the persistent class
839      * with the specified name. This is the second phase of converting
840      * a class to be persistence-capable.
841      * @param className the fully qualified name of the class
842      * @see #createSkeletonMappingClass
843      * @see #convertFields
844      */

845     public void convertDefaultFields (String JavaDoc className)
846     {
847         convertFields(className, getFields(className));
848     }
849
850     /** Adds the allowable persistent fields from the supplied list
851      * to the persistent class with the specified name.
852      * @param className the fully qualified name of the class
853      * @param fields a list of (short) field names
854      * @see #convertDefaultFields
855      */

856     public void convertFields (String JavaDoc className, List fields)
857     {
858         PersistenceClassElement element = getPersistenceClass(className);
859
860         if (element != null)
861         {
862             Iterator iterator = fields.iterator();
863
864             // iterate the list of fields and create corresponding
865
// PersistenceFieldElements (& RelationshipElements)
866
while (iterator.hasNext())
867             {
868                 String JavaDoc fieldName = (String JavaDoc)iterator.next();
869
870                 if (isPersistentAllowed(className, fieldName) &&
871                     shouldBePersistent(className, fieldName))
872                 {
873                     addFieldElement(element, fieldName);
874                 }
875             }
876
877             /* comment out -- not supporting concurrency groups for beta
878             // add everything to one concurrency group by default
879             PersistenceFieldElement[] persistentFields = element.getFields();
880             if ((persistentFields != null) && (persistentFields.length > 0))
881             {
882                 String defaultGroupName = I18NHelper.getMessage(getMessages(),
883                     "jdo.concurrency_group.default");
884                 ConcurrencyGroupElement group = new ConcurrencyGroupElement(
885                     new ConcurrencyGroupElementImpl(defaultGroupName), element);
886
887                 try
888                 {
889                     group.addFields(persistentFields);
890                     element.addConcurrencyGroup(group);
891                 }
892                 catch (ModelException e)
893                 {} // just don't add this group
894             }*/

895         }
896     }
897
898     /** Adds a PersistenceFieldElement for the specified field to the
899      * supplied PersistenceClassElement, creating a RelationshipElement if
900      * necessary.
901      * @param element the persistence class element to be used
902      * @param fieldName the name of the field to be added
903      */

904     public boolean addFieldElement (PersistenceClassElement element,
905         String JavaDoc fieldName)
906     {
907         String JavaDoc fieldType = getFieldType(element.getName(), fieldName);
908         boolean isCollection = isCollection(fieldType);
909
910         try
911         {
912             // check if should be relationship here
913
if (isPersistent(fieldType) || isCollection)
914             {
915                 RelationshipElement relationship = new RelationshipElement(
916                     new RelationshipElementImpl(fieldName), element);
917
918                 if (isCollection)
919                 {
920                     relationship.setCollectionClass(
921                         getDefaultCollectionClass(fieldType));
922                 }
923                 else // set upper bound = 1 (jdo model should really do this)
924
relationship.setUpperBound(1);
925
926                 element.addField(relationship);
927             }
928             else
929             {
930                 element.addField(new PersistenceFieldElement(new
931                     PersistenceFieldElementImpl(fieldName), element));
932             }
933
934             return true;
935         }
936         catch (ModelException e)
937         {} // will return false
938

939         return false;
940     }
941
942     /** Removes the specified PersistenceFieldElement from its declaring
943      * class. This method is added so that there is a common way to do this
944      * which checks if the argument is a relationship element with an inverse
945      * (in which case the inverse should first be cleared). This should
946      * really be handled by the jdo model directly, but the removeField method
947      * doesn't have access to the Model which is necessary for setting
948      * (or clearing) inverse relationships.
949      * @param element the persistence field element to be removed
950      * @exception ModelException if there is some error removing the field
951      */

952     public void removeFieldElement (PersistenceFieldElement element)
953         throws ModelException
954     {
955         if (element != null)
956         {
957             if (element instanceof RelationshipElement)
958             {
959                 ((RelationshipElement)element).setInverseRelationship(null,
960                     this);
961             }
962
963             element.getDeclaringClass().removeField(element);
964         }
965     }
966
967     /** Gets the name of the related class for a relationship element.
968      * This method is added so that there is a common way to do this. It
969      * checks if the argument is a collection relationship element (in which
970      * case the element class should be returned) or not (in which case the
971      * type should be returned). This should really be handled by the jdo
972      * model directly, but it doesn't have access to the Model which is
973      * necessary for finding the field type and whether it is a collection or
974      * not.
975      * @param element the relationship element to be examined
976      * @return the name of the related class
977      */

978     public String JavaDoc getRelatedClass (RelationshipElement element)
979     {
980         if (element != null)
981         {
982             String JavaDoc fieldType = getFieldType(
983                 element.getDeclaringClass().getName(), element.getName());
984             String JavaDoc relatedClass = (isCollection(fieldType) ?
985                 element.getElementClass() : fieldType);
986
987             return (StringHelper.isEmpty(relatedClass) ? null :
988                 relatedClass.trim());
989         }
990
991         return null;
992     }
993
994     /** Computes the list of names of the possible collection classes for the
995      * specified class.
996      * @param className the fully qualified name of the class to be checked
997      * @return an array of supported collection classes for the
998      * specified class name.
999      * @see #getFieldType
1000     * @see #getDefaultCollectionClass
1001     */

1002    public ArrayList getSupportedCollectionClasses (String JavaDoc className)
1003    {
1004        String JavaDoc supportedSet = "java.util.HashSet"; // NOI18N
1005
// String supportedList = "java.util.ArrayList"; // NOI18N
1006
// String supportedVector = "java.util.Vector"; // NOI18N
1007
ArrayList returnList = new ArrayList();
1008
1009        // for dogwood, only support sets
1010
returnList.add(supportedSet);
1011    /* if (className.indexOf("Collection") != -1) // NOI18N
1012        {
1013            returnList.add(supportedSet);
1014            returnList.add(supportedList);
1015            returnList.add(supportedVector);
1016        }
1017        else if (className.indexOf("List") != -1) // NOI18N
1018            returnList.add(supportedList);
1019        else if (className.indexOf("Set") != -1) // NOI18N
1020            returnList.add(supportedSet);
1021        else if (supportedVector.equals(className))
1022            returnList.add(supportedVector);
1023    */

1024        return returnList;
1025    }
1026
1027    /** Returns the default collection class for the specified class. If
1028     * the specified class is an unspecified Collection type, the return
1029     * will be HashSet.
1030     * @param className the fully qualified name of the class to be checked
1031     * @return the name of the default supported collection class for the
1032     * specified class name.
1033     * @see #getFieldType
1034     * @see #getSupportedCollectionClasses
1035     */

1036    public String JavaDoc getDefaultCollectionClass (String JavaDoc className)
1037    {
1038        String JavaDoc collectionClass = "java.util.HashSet"; // NOI18N
1039

1040        // for dogwood, only support sets
1041
/* if (className.indexOf("List") != -1) // NOI18N
1042            collectionClass = "java.util.ArrayList"; // NOI18N
1043        else if ("java.util.Vector".equals(className)) // NOI18N
1044            collectionClass = className;
1045    */

1046        return collectionClass;
1047    }
1048
1049    /** Creates a file with the given base file name and extension
1050     * parallel to the supplied class (if it does not yet exist).
1051     * @param className the fully qualified name of the class
1052     * @param baseFileName the name of the base file
1053     * @param extension the file extension
1054     * @return the output stream for the specified resource, <code>null</code>
1055     * if an error occurs or none exists
1056     * @exception IOException if there is some error creating the file
1057     */

1058    abstract protected BufferedOutputStream createFile (String JavaDoc className,
1059        String JavaDoc baseFileName, String JavaDoc extension) throws IOException;
1060
1061    /** Deletes the file with the given file name which is parallel
1062     * to the supplied class.
1063     * @param className the fully qualified name of the class
1064     * @param fileName the name of the file
1065     * @exception IOException if there is some error deleting the file
1066     */

1067    abstract protected void deleteFile (String JavaDoc className, String JavaDoc fileName)
1068        throws IOException;
1069
1070    /** Returns a list of names of all the declared field elements in the
1071     * class with the specified name.
1072     * @param className the fully qualified name of the class to be checked
1073     * @return the names of the field elements for the specified class
1074     */

1075    abstract public List getFields (String JavaDoc className);
1076
1077    /** Returns a list of names of all the field elements in the
1078     * class with the specified name. This list includes the inherited
1079     * fields.
1080     * @param className the fully qualified name of the class to be checked
1081     * @return the names of the field elements for the specified class
1082     */

1083    public List getAllFields (String JavaDoc className)
1084    {
1085        List returnList = new ArrayList();
1086        
1087        while (className != null)
1088        {
1089            returnList.addAll(getFields(className));
1090            className = getSuperclass(className);
1091        }
1092
1093        return returnList;
1094    }
1095
1096    /** Returns the class element with the specified className.
1097     * @param className the fully qualified name of the class to be checked
1098     * @return the class element for the specified className
1099     */

1100    public Object JavaDoc getClass (String JavaDoc className)
1101    {
1102        return getClass(className, null);
1103    }
1104
1105    /** Returns the class element with the specified className.
1106     * @param className the fully qualified name of the class to be checked
1107     * @param classLoader the class loader used to find mapping information
1108     * @return the class element for the specified className
1109     */

1110    abstract public Object JavaDoc getClass (String JavaDoc className, ClassLoader JavaDoc classLoader);
1111
1112    /** Determines if a class with the specified className exists.
1113     * @param className the fully qualified name of the class to be checked
1114     * @return <code>true</code> if this class name represents a valid
1115     * class; <code>false</code> otherwise.
1116     */

1117    public boolean hasClass (String JavaDoc className)
1118    {
1119        return hasClass(className, null);
1120    }
1121
1122    /** Determines if a class with the specified className exists.
1123     * @param className the fully qualified name of the class to be checked
1124     * @param classLoader the class loader used to find mapping information
1125     * @return <code>true</code> if this class name represents a valid
1126     * class; <code>false</code> otherwise.
1127     */

1128    public boolean hasClass (String JavaDoc className, ClassLoader JavaDoc classLoader)
1129    {
1130        return (getClass(className, classLoader) != null);
1131    }
1132
1133    /** Determines if the specified class implements the specified interface.
1134     * Note, class element is a model specific class representation as returned
1135     * by a getClass call executed on the same model instance.
1136     * @param classElement the class element to be checked
1137     * @param interfaceName the fully qualified name of the interface to
1138     * be checked
1139     * @return <code>true</code> if the class implements the interface;
1140     * <code>false</code> otherwise.
1141     * @see #getClass
1142     */

1143    abstract public boolean implementsInterface (Object JavaDoc classElement,
1144        String JavaDoc interfaceName);
1145
1146    /** Determines if the class with the specified name declares a constructor.
1147     * @param className the name of the class to be checked
1148     * @return <code>true</code> if the class declares a constructor;
1149     * <code>false</code> otherwise.
1150     * @see #getClass
1151     */

1152    abstract public boolean hasConstructor (String JavaDoc className);
1153
1154    /** Returns the constructor element for the specified argument types
1155     * in the class with the specified name. Types are specified as type
1156     * names for primitive type such as int, float or as fully qualified
1157     * class names.
1158     * @param className the name of the class which contains the constructor
1159     * to be checked
1160     * @param argTypeNames the fully qualified names of the argument types
1161     * @return the constructor element
1162     * @see #getClass
1163     */

1164    abstract public Object JavaDoc getConstructor (String JavaDoc className,
1165        String JavaDoc[] argTypeNames);
1166
1167    /** Returns the method element for the specified method name and argument
1168     * types in the class with the specified name. Types are specified as
1169     * type names for primitive type such as int, float or as fully qualified
1170     * class names.
1171     * @param className the name of the class which contains the method
1172     * to be checked
1173     * @param methodName the name of the method to be checked
1174     * @param argTypeNames the fully qualified names of the argument types
1175     * @return the method element
1176     * @see #getClass
1177     */

1178    abstract public Object JavaDoc getMethod (String JavaDoc className, String JavaDoc methodName,
1179        String JavaDoc[] argTypeNames);
1180
1181    /** Returns the inherited method element for the specified method
1182     * name and argument types in the class with the specified name.
1183     * Types are specified as type names for primitive type such as
1184     * int, float or as fully qualified class names. Note that the class
1185     * with the specified className is not checked for this method, only
1186     * superclasses are checked.
1187     * @param className the name of the class which contains the method
1188     * to be checked
1189     * @param methodName the name of the method to be checked
1190     * @param argTypeNames the fully qualified names of the argument types
1191     * @return the method element
1192     * @see #getClass
1193     */

1194    public Object JavaDoc getInheritedMethod (String JavaDoc className, String JavaDoc methodName,
1195        String JavaDoc[] argTypeNames)
1196    {
1197        String JavaDoc superClass = getSuperclass(className);
1198        Object JavaDoc method = null;
1199
1200        while ((superClass != null) && ((method =
1201            getMethod(superClass, methodName, argTypeNames)) == null))
1202        {
1203            superClass = getSuperclass(superClass);
1204        }
1205
1206        return method;
1207    }
1208
1209    /** Returns the string representation of type of the specified element.
1210     * If element denotes a field, it returns the type of the field.
1211     * If element denotes a method, it returns the return type of the method.
1212     * Note, element is either a field element as returned by getField, or a
1213     * method element as returned by getMethod executed on the same model
1214     * instance.
1215     * @param element the element to be checked
1216     * @return the string representation of the type of the element
1217     * @see #getField
1218     * @see #getMethod
1219     */

1220    abstract public String JavaDoc getType (Object JavaDoc element);
1221
1222    /** Returns the field element for the specified fieldName in the class
1223     * with the specified className.
1224     * @param className the fully qualified name of the class which contains
1225     * the field to be checked
1226     * @param fieldName the name of the field to be checked
1227     * @return the field element for the specified fieldName
1228     */

1229    abstract public Object JavaDoc getField (String JavaDoc className, String JavaDoc fieldName);
1230
1231    /** Returns the inherited field element for the specified fieldName in
1232     * the class with the specified className. Note that the class
1233     * with the specified className is not checked for this field, only
1234     * superclasses are checked.
1235     * @param className the fully qualified name of the class which contains
1236     * a superclass with the field to be checked
1237     * @param fieldName the name of the field to be checked
1238     * @return the field element for the specified fieldName
1239     */

1240    public Object JavaDoc getInheritedField (String JavaDoc className, String JavaDoc fieldName)
1241    {
1242        String JavaDoc superClass = getSuperclass(className);
1243        Object JavaDoc field = null;
1244
1245        while ((superClass != null) &&
1246            ((field = getField(superClass, fieldName)) == null))
1247        {
1248            superClass = getSuperclass(superClass);
1249        }
1250
1251        return field;
1252    }
1253
1254    /** Determines if a field with the specified fieldName exists in the class
1255     * with the specified className.
1256     * @param className the fully qualified name of the class which contains
1257     * the field to be checked
1258     * @param fieldName the name of the field to be checked
1259     * @return <code>true</code> if this field name represents a valid
1260     * field; <code>false</code> otherwise.
1261     */

1262    public boolean hasField (String JavaDoc className, String JavaDoc fieldName)
1263    {
1264        return (getField(className, fieldName) != null);
1265    }
1266
1267    /** Returns the field type for the specified fieldName in the class
1268     * with the specified className.
1269     * @param className the fully qualified name of the class which contains
1270     * the field to be checked
1271     * @param fieldName the name of the field to be checked
1272     * @return the field type for the specified fieldName
1273     */

1274    public String JavaDoc getFieldType (String JavaDoc className, String JavaDoc fieldName)
1275    {
1276        return getType(getField(className, fieldName));
1277    }
1278
1279    /** Determines if the specified field element has a serializable type.
1280     * A type is serializable if it is a primitive type, a class that
1281     * implements java.io.Serializable or an interface that inherits from
1282     * java.io.Serializable.
1283     * Note, the field element is a model specific field representation as
1284     * returned by a getField call executed on the same model instance.
1285     * @param fieldElement the field element to be checked
1286     * @return <code>true</code> if the field element has a serializable type;
1287     * <code>false</code> otherwise.
1288     * @see #getField
1289     */

1290    abstract public boolean isSerializable (Object JavaDoc fieldElement);
1291
1292    /** Determines if a field with the specified fieldName in the class
1293     * with the specified className has a primitive type.
1294     * @param className the fully qualified name of the class which contains
1295     * the field to be checked
1296     * @param fieldName the name of the field to be checked
1297     * @return <code>true</code> if this field name represents a primitive
1298     * field; <code>false</code> otherwise.
1299     * @see #getFieldType
1300     */

1301    public boolean isPrimitive (String JavaDoc className, String JavaDoc fieldName)
1302    {
1303        return isPrimitive(getFieldType(className, fieldName));
1304    }
1305
1306    /** Determines if the specified className represents a primitive type.
1307     * @param className the fully qualified name of the class or type to be
1308     * checked
1309     * @return <code>true</code> if this class represents a primitive;
1310     * <code>false</code> otherwise.
1311     * @see #getFieldType
1312     */

1313    protected boolean isPrimitive (String JavaDoc className)
1314    {
1315        return ((className != null) &&
1316            JavaTypeHelper.getPrimitiveClass(className) != null);
1317    }
1318
1319    /** Determines if a field with the specified fieldName in the class
1320     * with the specified className is an array.
1321     * @param className the fully qualified name of the class which contains
1322     * the field to be checked
1323     * @param fieldName the name of the field to be checked
1324     * @return <code>true</code> if this field name represents a java array
1325     * field; <code>false</code> otherwise.
1326     * @see #getFieldType
1327     */

1328    abstract public boolean isArray (String JavaDoc className, String JavaDoc fieldName);
1329
1330    /** Determines if a field with the specified fieldName in the class
1331     * with the specified className is a byte array.
1332     * @param className the fully qualified name of the class which contains
1333     * the field to be checked
1334     * @param fieldName the name of the field to be checked
1335     * @return <code>true</code> if this field name represents a byte array
1336     * field; <code>false</code> otherwise.
1337     * @see #getFieldType
1338     */

1339    public boolean isByteArray (String JavaDoc className, String JavaDoc fieldName)
1340    {
1341        return isByteArray(getFieldType(className, fieldName));
1342    }
1343
1344    /** Determines if the specified className represents a byte array.
1345     * @param className the fully qualified name of the class or type to be
1346     * checked
1347     * @return <code>true</code> if this class represents a byte array;
1348     * <code>false</code> otherwise.
1349     */

1350    protected boolean isByteArray (String JavaDoc className)
1351    {
1352        return ("byte[]".equals(className)); // NOI18N
1353
}
1354
1355    /** Determines if the class name represents a collection.
1356     * @param className the fully qualified name of the class to be checked
1357     * @return <code>true</code> if this class represents a collection;
1358     * <code>false</code> otherwise.
1359     * @see #getFieldType
1360     */

1361    public boolean isCollection (String JavaDoc className)
1362    {
1363        return _collectionClasses.contains(className);
1364    }
1365
1366    /** Determines if the specified className represents a second class object.
1367     * For this release, the class name is checked against a list of supported
1368     * second class objects since user-defined second class objects are not
1369     * supported.
1370     * @param className the fully qualified name of the class to be checked
1371     * @return <code>true</code> if this class represents a second class
1372     * object; <code>false</code> otherwise.
1373     * @see #isMutableSecondClassObject
1374     * @see #isCollection
1375     * @see #getFieldType
1376     */

1377    public boolean isSecondClassObject (String JavaDoc className)
1378    {
1379        return _scoClasses.contains(className);
1380    }
1381
1382    /** Determines if the specified className represents a mutable second class
1383     * object. For this release, the class name is checked against a list of
1384     * supported mutable second class objects since user-defined second class
1385     * objects are not supported.
1386     * @param className the fully qualified name of the class to be checked
1387     * @return <code>true</code> if this class represents a mutable second
1388     * class object; <code>false</code> otherwise.
1389     * @see #isSecondClassObject
1390     * @see #isCollection
1391     * @see #getFieldType
1392     */

1393    public boolean isMutableSecondClassObject (String JavaDoc className)
1394    {
1395        return _mutableScoClasses.contains(className);
1396    }
1397
1398    /** Returns the string representation of declaring class of
1399     * the specified member element. Note, the member element is
1400     * either a class element as returned by getClass, a field element
1401     * as returned by getField, a constructor element as returned by
1402     * getConstructor, or a method element as returned by getMethod
1403     * executed on the same model instance.
1404     * @param memberElement the member element to be checked
1405     * @return the string representation of the declaring class of
1406     * the specified memberElement
1407     * @see #getClass
1408     * @see #getField
1409     * @see #getConstructor
1410     * @see #getMethod
1411     */

1412    abstract public String JavaDoc getDeclaringClass (Object JavaDoc memberElement);
1413
1414    /** Returns the modifier mask for the specified member element.
1415     * Note, the member element is either a class element as returned by
1416     * getClass, a field element as returned by getField, a constructor element
1417     * as returned by getConstructor, or a method element as returned by
1418     * getMethod executed on the same model instance.
1419     * @param memberElement the member element to be checked
1420     * @return the modifier mask for the specified memberElement
1421     * @see java.lang.reflect.Modifier
1422     * @see #getClass
1423     * @see #getField
1424     * @see #getConstructor
1425     * @see #getMethod
1426     */

1427    abstract public int getModifiers (Object JavaDoc memberElement);
1428
1429    /** Returns the modifier mask for the specified className.
1430     * @param className the fully qualified name of the class to be checked
1431     * @return the modifier mask for the specified class
1432     * @see java.lang.reflect.Modifier
1433     */

1434    public int getModifiersForClass (String JavaDoc className)
1435    {
1436        return getModifiers(getClass(className));
1437    }
1438
1439    /** Returns the modifier mask for the specified fieldName in the class
1440     * with the specified className.
1441     * @param className the fully qualified name of the class which contains
1442     * the field to be checked
1443     * @param fieldName the name of the field to be checked
1444     * @return the modifier mask for the specified field
1445     * @see java.lang.reflect.Modifier
1446     */

1447    protected int getModifiers (String JavaDoc className, String JavaDoc fieldName)
1448    {
1449        return getModifiers(getField(className, fieldName));
1450    }
1451
1452    /** Returns <code>true</code> if the specified field can be made
1453     * persistent, <code>false</code> otherwise. This computation is based
1454     * on the modifier and type of the field. Fields which are non-final
1455     * and non-static and are primitive, persistence capable, or second
1456     * class objects and not arrays return <code>true</code>.
1457     * @param className the fully qualified name of the class which contains
1458     * the field to be checked
1459     * @param fieldName the name of the field to be checked
1460     * @return whether the specified field can be made persistent
1461     * @see #getModifiers(String,String)
1462     * @see #isPrimitive
1463     * @see #isArray
1464     * @see #isPersistent
1465     * @see #isSecondClassObject
1466     * @see #shouldBePersistent
1467     */

1468    public boolean isPersistentAllowed (String JavaDoc className, String JavaDoc fieldName)
1469    {
1470        return isPersistentAllowed(className, null, fieldName);
1471    }
1472    
1473    /** Returns <code>true</code> if the specified field can be made
1474     * persistent, <code>false</code> otherwise. This computation is based
1475     * on the modifier and type of the field. Fields which are non-final
1476     * and non-static and are primitive, persistence capable, byte arrays, or
1477     * second class objects and not arrays return <code>true</code>.
1478     * @param className the fully qualified name of the class which contains
1479     * the field to be checked
1480     * @param classLoader the class loader used to find mapping information
1481     * @param fieldName the name of the field to be checked
1482     * @return whether the specified field can be made persistent
1483     * @see #getModifiers(String,String)
1484     * @see #getFieldType
1485     * @see #isPersistentTypeAllowed
1486     * @see #shouldBePersistent
1487     */

1488    public boolean isPersistentAllowed (String JavaDoc className,
1489       ClassLoader JavaDoc classLoader, String JavaDoc fieldName)
1490    {
1491        int modifier = getModifiers(className, fieldName);
1492
1493        if (!Modifier.isStatic(modifier) && !Modifier.isFinal(modifier))
1494        {
1495            return isPersistentTypeAllowed(
1496                getFieldType(className, fieldName), classLoader);
1497        }
1498
1499        return false;
1500    }
1501
1502    /** Returns <code>true</code> if the a field of the specified class or
1503     * type can be made persistent, <code>false</code> otherwise. Fields
1504     * which are primitive, persistence capable, byte arrays, or second
1505     * class objects and not arrays return <code>true</code>.
1506     * @param className the fully qualified name of the class or type to be
1507     * checked
1508     * @param classLoader the class loader used to find mapping information
1509     * @return <code>true</code> if this class represents a type which
1510     * can be made persistent; <code>false</code> otherwise.
1511     * @see #isPrimitive
1512     * @see #isByteArray
1513     * @see #isPersistent
1514     * @see #isSecondClassObject
1515     */

1516    protected boolean isPersistentTypeAllowed (String JavaDoc className,
1517        ClassLoader JavaDoc classLoader)
1518    {
1519        return (isPrimitive(className) || isSecondClassObject(className) ||
1520            isByteArray(className) || isPersistent(className, classLoader));
1521    }
1522
1523    /** Returns <code>true</code> if the specified field should be made
1524     * persistent (i.e. does it make sense), <code>false</code> otherwise.
1525     * This computation is based solely on the modifier: those which are not
1526     * volatile return <code>true</code>.
1527     * @param className the fully qualified name of the class which contains
1528     * the field to be checked
1529     * @param fieldName the name of the field to be checked
1530     * @return whether the specified field should be made persistent
1531     * see #getModifiers(String,String)
1532     */

1533    public boolean shouldBePersistent (String JavaDoc className, String JavaDoc fieldName)
1534    {
1535        return !Modifier.isVolatile(getModifiers(className, fieldName));
1536    }
1537
1538    /** Returns the PersistenceFieldElement with the supplied fieldName found
1539     * in the supplied className.
1540     * @param className the fully qualified name of the class which contains
1541     * the field to be checked
1542     * @param fieldName the name of the field to be checked
1543     * @return the PersistenceFieldElement for the specified field,
1544     * <code>null</code> if an error occurs or none exists
1545     */

1546    public PersistenceFieldElement getPersistenceField (String JavaDoc className,
1547        String JavaDoc fieldName)
1548    {
1549        return (hasField(className, fieldName) ?
1550            getPersistenceFieldInternal(className, fieldName) : null);
1551    }
1552
1553    /** Returns the PersistenceFieldElement with the supplied fieldName found
1554     * in the supplied className.
1555     * @param className the fully qualified name of the class which contains
1556     * the field to be checked
1557     * @param fieldName the name of the field to be checked
1558     * @return the PersistenceFieldElement for the specified field,
1559     * <code>null</code> if an error occurs or none exists
1560     */

1561    protected PersistenceFieldElement getPersistenceFieldInternal
1562        (String JavaDoc className, String JavaDoc fieldName)
1563    {
1564        PersistenceClassElement classElement = getPersistenceClass(className);
1565
1566        return ((classElement != null) ?
1567            classElement.getField(fieldName) : null);
1568    }
1569
1570    /** Determines if the specified className and fieldName pair represent a
1571     * persistent field.
1572     * @param className the fully qualified name of the class which contains
1573     * the field to be checked
1574     * @param fieldName the name of the field to be checked
1575     * @return <code>true</code> if this field name represents a persistent
1576     * field; <code>false</code> otherwise.
1577     */

1578    public boolean isPersistent (String JavaDoc className, String JavaDoc fieldName)
1579    {
1580        PersistenceFieldElement fieldElement =
1581            getPersistenceField(className, fieldName);
1582
1583        if (fieldElement != null)
1584        {
1585            return (PersistenceFieldElement.PERSISTENT ==
1586                fieldElement.getPersistenceType());
1587        }
1588
1589        return false;
1590    }
1591
1592    /** Determines if the specified className and fieldName pair represent a
1593     * key field.
1594     * @param className the fully qualified name of the class which contains
1595     * the field to be checked
1596     * @param fieldName the name of the field to be checked
1597     * @return <code>true</code> if this field name represents a key field;
1598     * <code>false</code> otherwise.
1599     */

1600    public boolean isKey (String JavaDoc className, String JavaDoc fieldName)
1601    {
1602        if (hasField(className, fieldName))
1603        {
1604            PersistenceClassElement classElement =
1605                getPersistenceClass(className);
1606
1607            if (classElement != null)
1608            {
1609                String JavaDoc keyClass = classElement.getKeyClass();
1610
1611                if (keyClass != null)
1612                    return hasField(keyClass, fieldName);
1613            }
1614        }
1615
1616        return false;
1617    }
1618
1619    /** Determines if the specified className and fieldName pair represent a
1620     * field which has a type which is valid for key fields. Valid key
1621     * field types include non-collection SCOs (wrappers, Date, Time, etc.)
1622     * and primitives.
1623     * @param className the fully qualified name of the class which contains
1624     * the field to be checked
1625     * @param fieldName the name of the field to be checked
1626     * @return <code>true</code> if this field name represents a field
1627     * with a valid type for a key field; <code>false</code> otherwise.
1628     */

1629    public boolean isValidKeyType (String JavaDoc className, String JavaDoc fieldName)
1630    {
1631        String JavaDoc fieldType = getFieldType(className, fieldName);
1632
1633        if (fieldType == null)
1634            fieldType = getType(getInheritedField(className, fieldName));
1635
1636        return (isPrimitive(fieldType) ||
1637            (isSecondClassObject(fieldType) && !isCollection(fieldType)));
1638    }
1639
1640    /** Determines if the specified className and fieldName pair represent a
1641     * field which is part of the default fetch group.
1642     * @param className the fully qualified name of the class which contains
1643     * the field to be checked
1644     * @param fieldName the name of the field to be checked
1645     * @return <code>true</code> if this field name represents a field in
1646     * the default fetch group; <code>false</code> otherwise.
1647     */

1648    public boolean isDefaultFetchGroup (String JavaDoc className, String JavaDoc fieldName)
1649    {
1650        MappingClassElement mappingClass = getMappingClass(className);
1651
1652        try
1653        {
1654            return (MappingFieldElement.GROUP_DEFAULT ==
1655                mappingClass.getField(fieldName).getFetchGroup());
1656        }
1657        catch (Exception JavaDoc e)
1658        {} // will return false
1659

1660        return false;
1661    }
1662
1663    /** Parses the combination of java (or class) information and mapping/jdo
1664     * information by running through a subset of the full validation check
1665     * and aborting (and returning <code>false</code> at the first error or
1666     * warning.
1667     * @param className the fully qualified name of the class to be checked
1668     * @return <code>true</code> if no errors or warnings occur,
1669     * <code>false</code> otherwise.
1670     */

1671    public boolean parse (String JavaDoc className)
1672    {
1673        return new ModelValidator(this, className, getMessages()).parseCheck();
1674    }
1675
1676    /** Validates the combination of java (or class) information and mapping/jdo
1677     * information by running through the full validation check and returning
1678     * a collection of ModelValidationExceptions containing any errors or
1679     * warnings encountered.
1680     * @param className the fully qualified name of the class to be checked
1681     * @param bundle the overridden resource bundle file - specify
1682     * <code>null</code> if the default one should be used
1683     * @return a collection of ModelValidationExceptions containing any
1684     * errors or warnings encountered. If no errors or warnings were
1685     * encountered, the collection will be empty, not <code>null</code>.
1686     */

1687    public Collection validate (String JavaDoc className, ResourceBundle bundle)
1688    {
1689        return validate(className, null, bundle);
1690    }
1691
1692    /** Validates the combination of java (or class) information and mapping/jdo
1693     * information by running through the full validation check and returning
1694     * a collection of ModelValidationExceptions containing any errors or
1695     * warnings encountered.
1696     * @param className the fully qualified name of the class to be checked
1697     * @param classLoader the class loader used to find mapping information
1698     * @param bundle the overridden resource bundle file - specify
1699     * <code>null</code> if the default one should be used
1700     * @return a collection of ModelValidationExceptions containing any
1701     * errors or warnings encountered. If no errors or warnings were
1702     * encountered, the collection will be empty, not <code>null</code>.
1703     */

1704    public Collection validate (String JavaDoc className, ClassLoader JavaDoc classLoader,
1705        ResourceBundle bundle)
1706    {
1707        return new ModelValidator(this, className, classLoader,
1708            ((bundle == null) ? getMessages() : bundle)).fullValidationCheck();
1709    }
1710
1711}
1712
1713
Popular Tags