Index: C:/Java/castor-4/src/doc/release-notes.xml =================================================================== --- C:/Java/castor-4/src/doc/release-notes.xml (revision 6773) +++ C:/Java/castor-4/src/doc/release-notes.xml (working copy) @@ -65,7 +65,7 @@

If you are using the Castor code generator to generate code - from schemas that use xsd:import, whether or not code + from schemas that use xsd:import, whether or not code was generated from the imported schemas was controlled by a combination of switches. Now it is controlled only by the "-generateImportedSchemas" option of SourceGeneratorMain, the @@ -76,6 +76,26 @@ + + + Refactored creation of ClassDescriptors through MappingLoader. + + + Ralf Joachim + ralf.joachim@syscon-world.de + + + Ralf Joachim + ralf.joachim@syscon-world.de + + + Ralf Joachim + ralf.joachim@syscon-world.de + + Enh. + All + 20070127 + Fixed problem with not closed file handles for '.castor.cdr' during Index: C:/Java/castor-4/src/etc/CHANGELOG =================================================================== --- C:/Java/castor-4/src/etc/CHANGELOG (revision 6773) +++ C:/Java/castor-4/src/etc/CHANGELOG (working copy) @@ -1,6 +1,11 @@ SVN ------------------------------- +All: Resolved issue CASTOR-1644 using contribution from Ralf Joachim [Ralf.joachim@syscon-world.de] + Refactored creation of ClassDescriptors through MappingLoader. + Details: http://jira.codehaus.org/browse/CASTOR-1644 + (Ralf - 20070127) + Gen: Resolved issue CASTOR-1854 using contribution from Werner Guttmann [werner.guttmann@gmx.net] Fixed problem with not closed file handles for '.castor.cdr' during code generation. Details: http://jira.codehaus.org/browse/CASTOR-1854 Index: C:/Java/castor-4/src/main/java/org/exolab/castor/jdo/engine/JDOClassDescriptor.java =================================================================== --- C:/Java/castor-4/src/main/java/org/exolab/castor/jdo/engine/JDOClassDescriptor.java (revision 6773) +++ C:/Java/castor-4/src/main/java/org/exolab/castor/jdo/engine/JDOClassDescriptor.java (working copy) @@ -48,38 +48,29 @@ import java.util.Map; import java.util.Properties; -import org.castor.cache.Cache; -import org.castor.cache.simple.CountLimited; -import org.castor.cache.simple.TimeLimited; -import org.castor.util.Messages; -import org.exolab.castor.jdo.OQLQuery; -import org.exolab.castor.jdo.QueryException; -import org.exolab.castor.jdo.TimeStampable; +import org.exolab.castor.mapping.AccessMode; import org.exolab.castor.mapping.ClassDescriptor; -import org.exolab.castor.mapping.MappingException; +import org.exolab.castor.mapping.FieldDescriptor; import org.exolab.castor.mapping.loader.ClassDescriptorImpl; -import org.exolab.castor.mapping.xml.CacheTypeMapping; -import org.exolab.castor.mapping.xml.Param; /** - * JDO class descriptors. Extends {@link ClassDescriptor} to include the - * table name and other SQL-related information. All fields are of - * type {@link JDOFieldDescriptor}, identity field is not included in the - * returned field list, and contained fields are flattened out for - * efficiency (thus all fields are directly accessible). + * JDO class descriptors. Extends {@link ClassDescriptor} to include the table name and + * other SQL-related information. All fields are of type {@link JDOFieldDescriptor}, + * identity field is not included in the returned field list, and contained fields are + * flattened out for efficiency (thus all fields are directly accessible). * - * @author Assaf Arkin + * @author Assaf Arkin + * @author Ralf Joachim * @version $Revision$ $Date: 2006-04-10 16:39:24 -0600 (Mon, 10 Apr 2006) $ */ public class JDOClassDescriptor extends ClassDescriptorImpl { + //----------------------------------------------------------------------------------- + /** The name of the SQL table. */ - private final String _tableName; + private String _tableName; - /** The names of columns that the identity consists of. */ - private final String[] _idnames; - - /** The key generator specified for this class. */ - private final KeyGeneratorDescriptor _keyGenDesc; + /** The access mode specified for this class. */ + private AccessMode _accessMode = AccessMode.Shared; /** The properties defining cache type and parameters. */ private final Properties _cacheParams = new Properties(); @@ -84,69 +75,24 @@ /** The properties defining cache type and parameters. */ private final Properties _cacheParams = new Properties(); - /** - * Associated named queries, keyed by their name - */ - private Map _namedQueries = new HashMap(); + /** Associated named queries, keyed by their name. */ + private final Map _namedQueries = new HashMap(); - public JDOClassDescriptor(final ClassDescriptor clsDesc, - final KeyGeneratorDescriptor keyGenDesc) - throws MappingException { - super((ClassDescriptorImpl) clsDesc); - - _tableName = getMapping().getMapTo().getTable(); - if (_tableName == null) { - throw new IllegalArgumentException("Argument 'tableName' is null"); - } - - if (getIdentity() == null) { - throw new MappingException("mapping.noIdentity", getJavaClass().getName()); - } - - if (!(getIdentity() instanceof JDOFieldDescriptor)) { - throw new IllegalArgumentException("Identity field must be of type JDOFieldDescriptor"); - } - - if ((getExtends() != null) && !(getExtends() instanceof JDOClassDescriptor)) { - throw new IllegalArgumentException( "Extended class does not have a JDO descriptor" ); - } - - _idnames = new String[_identities.length]; - for (int i = 0; i < _idnames.length; i++) { - String[] sqlNames = ((JDOFieldDescriptor) _identities[i]).getSQLName(); - if (sqlNames == null) { - throw new MappingException("mapping.noSqlName", _identities[i].getFieldName(), getJavaClass().getName()); - } - _idnames[i] = sqlNames[0]; - } - - _keyGenDesc = keyGenDesc; + /** The key generator specified for this class. */ + private KeyGeneratorDescriptor _keyGenDesc; - CacheTypeMapping cacheMapping = getMapping().getCacheTypeMapping(); - if (cacheMapping != null) { - String capacity = Long.toString(cacheMapping.getCapacity()); - _cacheParams.put(CountLimited.PARAM_CAPACITY, capacity); - _cacheParams.put(TimeLimited.PARAM_TTL, capacity); - - Param[] params = cacheMapping.getParam(); - for (int i = 0; i < params.length; i++) { - _cacheParams.put(params[i].getName(), params[i].getValue()); - } + //----------------------------------------------------------------------------------- - String debug = new Boolean(cacheMapping.getDebug()).toString(); - _cacheParams.put(Cache.PARAM_DEBUG, debug); - - String type = cacheMapping.getType(); - if ((TimeStampable.class.isAssignableFrom(getJavaClass())) - && (type != null) && (type.equalsIgnoreCase("none"))) { - throw new MappingException(Messages.format("persist.wrongCacheTypeSpecified", getMapping().getName())); - } - _cacheParams.put(Cache.PARAM_TYPE, type); - } - - _cacheParams.put(Cache.PARAM_NAME, getMapping().getName()); + public JDOClassDescriptor() { + super(); } + + //----------------------------------------------------------------------------------- + protected void setTableName(final String tableName) { + _tableName = tableName; + } + /** * Returns the table name to which this object maps. * @@ -155,6 +101,18 @@ public String getTableName() { return _tableName; } + + protected void setAccessMode(final AccessMode accessMode) { + _accessMode = accessMode; + } + + public AccessMode getAccessMode() { + return _accessMode; + } + + protected void addCacheParam(final String key, final String value) { + _cacheParams.put(key, value); + } public Properties getCacheParams() { return _cacheParams; @@ -160,77 +118,78 @@ return _cacheParams; } + protected void addNamedQuery(final String name, final String query) { + _namedQueries.put(name, query); + } + + /** + * Get map of named query strings associated with their names. + * + * @return Map of named query strings associated with their names. + */ + public Map getNamedQueries() { + return _namedQueries; + } + + /** + * Set key generator specified for this class. + * + * @param keyGenDesc Key generator descriptor. + */ + protected void setKeyGeneratorDescriptor(final KeyGeneratorDescriptor keyGenDesc) { + _keyGenDesc = keyGenDesc; + } + + /** + * Get key generator specified for this class. + * + * @return Key generator descriptor. + */ + public KeyGeneratorDescriptor getKeyGeneratorDescriptor() { + return _keyGenDesc; + } + + //----------------------------------------------------------------------------------- + /** - * Returns a JDOFieldDescriptor for the field with the name passed. Null + * Returns a JDOFieldDescriptor for the field with the name passed. null * if named field does not exist. * - * @param name The name of the field to return - * @return The field if it exists, otherwise null. + * @param name Name of the field to return. + * @return Field if it exists, otherwise null. */ public JDOFieldDescriptor getField(String name) { - JDOFieldDescriptor field = null; - for (int i = 0 ; i < _fields.length ; ++i) { - if ((_fields[i] instanceof JDOFieldDescriptor) - && (_fields[i].getFieldName().equals(name))) { + FieldDescriptor[] fields = getFields(); + for (int i = 0 ; i < fields.length ; ++i) { + FieldDescriptor field = fields[i]; + if ((field instanceof JDOFieldDescriptor) + && (field.getFieldName().equals(name))) { - field = (JDOFieldDescriptor) _fields[i]; - break; + return (JDOFieldDescriptor) field; } } - if (field == null) { - for (int i = 0 ; i < _identities.length ; ++i) { - if ((_identities[i] instanceof JDOFieldDescriptor) - && (_identities[i].getFieldName().equals(name))) { - - field = (JDOFieldDescriptor) _identities[i]; - } + FieldDescriptor[] identities = getIdentities(); + for (int i = 0 ; i < identities.length ; ++i) { + FieldDescriptor field = identities[i]; + if ((field instanceof JDOFieldDescriptor) + && (field.getFieldName().equals(name))) { + + return (JDOFieldDescriptor) field; } } - return field; + return null; } - /** - * Returns the key generator specified for this class. - * - * @return The key generator descriptor - */ - public KeyGeneratorDescriptor getKeyGeneratorDescriptor() { - return _keyGenDesc; - } + //----------------------------------------------------------------------------------- /** - * @return The names of columns that the identity consists of. + * {@inheritDoc} */ - public String[] getIdentityColumnNames() { - return _idnames; - } - public String toString() { - return super.toString() + " AS " + _tableName; + return getJavaClass().getName() + " AS " + _tableName; } - /** - * Returns the OQL statement from a named query instance associated with the given name - * @param name Name of the named query - * @return the OQL statement from a named query instance associated with the given name - */ - public String getNamedQuery(String name) { - String namedQuery = (String) _namedQueries.get(name); - return namedQuery; - } - - /** - * Adds a new named query for the given name for future usage (through Database.getNamedQuery()). - * @param name Name of the named query. - * @param namedQuery Named query to be associated with the given name - * @throws QueryException If there's already a named query for the given name - */ - public void addNamedQuery(final String name, final String namedQuery) throws QueryException { - if (_namedQueries.containsKey(name)) { - throw new QueryException ("Duplicate entry for named query " + name); - } - _namedQueries.put(name, namedQuery); - } + //----------------------------------------------------------------------------------- } Index: C:/Java/castor-4/src/main/java/org/exolab/castor/jdo/engine/JDOMappingLoader.java =================================================================== --- C:/Java/castor-4/src/main/java/org/exolab/castor/jdo/engine/JDOMappingLoader.java (revision 6773) +++ C:/Java/castor-4/src/main/java/org/exolab/castor/jdo/engine/JDOMappingLoader.java (working copy) @@ -44,6 +44,11 @@ */ package org.exolab.castor.jdo.engine; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.castor.cache.Cache; +import org.castor.cache.simple.CountLimited; +import org.castor.cache.simple.TimeLimited; import org.castor.jdo.engine.SQLTypeInfos; import org.castor.jdo.engine.SQLTypeConverters; import org.castor.jdo.engine.SQLTypeConverters.Convertor; @@ -49,9 +54,11 @@ import org.castor.jdo.engine.SQLTypeConverters.Convertor; import org.castor.mapping.BindingType; import org.castor.util.Messages; -import org.exolab.castor.jdo.QueryException; +import org.exolab.castor.jdo.TimeStampable; import org.exolab.castor.mapping.*; +import org.exolab.castor.mapping.loader.AbstractFieldDescriptor; import org.exolab.castor.mapping.loader.CollectionHandlers; +import org.exolab.castor.mapping.loader.FieldDescriptorImpl; import org.exolab.castor.mapping.loader.FieldHandlerFriend; import org.exolab.castor.mapping.loader.FieldHandlerImpl; import org.exolab.castor.mapping.loader.AbstractMappingLoader; @@ -65,8 +72,12 @@ import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Enumeration; -import java.util.Hashtable; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; import java.util.Properties; +import java.util.Set; /** * A JDO implementation of mapping helper. Creates JDO class descriptors @@ -72,7 +83,8 @@ * A JDO implementation of mapping helper. Creates JDO class descriptors * from the mapping file. * - * @author Assaf Arkin + * @author Assaf Arkin + * @author Ralf Joachim * @version $Revision$ $Date: 2006-04-13 07:37:49 -0600 (Thu, 13 Apr 2006) $ */ public final class JDOMappingLoader extends AbstractMappingLoader { @@ -78,6 +90,10 @@ public final class JDOMappingLoader extends AbstractMappingLoader { //----------------------------------------------------------------------------------- + /** The Jakarta Commons + * Logging instance used for all logging. */ + private static final Log LOG = LogFactory.getLog(JDOMappingLoader.class); + /** Separators between type name and parameter, e.g. "char[01]". */ private static final char LEFT_PARAM_SEPARATOR = '['; @@ -84,6 +100,8 @@ /** Separators after parameter, e.g. "char[01]". */ private static final char RIGHT_PARAM_SEPARATOR = ']'; + //----------------------------------------------------------------------------------- + /** * Extracts parameter for type convertor from the SQL type definition of the * form "SQL_TYPE_NAME[PARAMETER]". If the type is not parameterized, returns @@ -115,109 +133,301 @@ //----------------------------------------------------------------------------------- + /** Map of key generator descriptors associated by their name. */ + private final Map _keyGenDescs = new HashMap(); + /** Used by the constructor for creating key generators. Each database must have a + * proprietary KeyGeneratorRegistry instance, otherwise it is impossible to + * implement stateful key generator algorithms like HIGH-LOW correctly. */ + private final KeyGeneratorRegistry _keyGenReg = new KeyGeneratorRegistry(); - /** - * Used by the constructor for creating key generators. - * See {@link #loadMapping}. - */ - private Hashtable _keyGenDefs = new Hashtable(); + /** Set of names of all named queries to identify duplicate names. */ + private final Set _queryNames = new HashSet(); + + /** The JDO PersistenceFactory (aka BaseFactory) is used for adjusting SQL type for + * the given database. */ + private BaseFactory _factory; + //----------------------------------------------------------------------------------- - /** - * Used by the constructor for creating key generators. - * See {@link #loadMapping}. - */ - private Hashtable _keyGenDescs = new Hashtable(); + public JDOMappingLoader(ClassLoader loader) { + super(loader); + } + //----------------------------------------------------------------------------------- + /** - * Used to locally register all loaded queries - * to detect duplicated query names. - * See {@link #createDescriptor(ClassMapping)}. - */ - private Hashtable _namedQueries = new Hashtable(); + * {@inheritDoc} + */ + public BindingType getBindingType() { return BindingType.JDO; } + //----------------------------------------------------------------------------------- /** - * The JDO PersistenceFactory (aka BaseFactory) is used for adjusting - * SQL type for the given database. + * {@inheritDoc} */ - private BaseFactory _factory; - + public void loadMapping(final MappingRoot mapping, final Object param) + throws MappingException { + if (loadMapping()) { + _factory = (BaseFactory) param; + + createKeyGenDescriptors(mapping); + createClassDescriptors(mapping); + } + } + /** - * Used by the constructor for creating key generators. - * Each database must have a proprietary KeyGeneratorRegistry instance - * Otherwise it is impossible to implement correctly stateful - * key generator algorithms like HIGH-LOW. - * See {@link #loadMapping}. + * Load key generator definitions, check for duplicate definitions and convert them + * to key generator descriptors. + * + * @param mapping Mapping to load key generator defintions from. + * @throws MappingException If mapping contains more then one key generator + * definition with same name. */ - private KeyGeneratorRegistry _keyGenReg = new KeyGeneratorRegistry(); - - - public JDOMappingLoader(ClassLoader loader) { - super(loader); + private void createKeyGenDescriptors(final MappingRoot mapping) + throws MappingException { + Enumeration enumeration = mapping.enumerateKeyGeneratorDef(); + while (enumeration.hasMoreElements()) { + KeyGeneratorDef def = (KeyGeneratorDef) enumeration.nextElement(); + + String name = def.getAlias(); + if (name == null) { name = def.getName(); } + + KeyGeneratorDescriptor desc = (KeyGeneratorDescriptor) _keyGenDescs.get(name); + if (desc != null) { + throw new MappingException(Messages.format("mapping.dupKeyGen", name)); + } + + Properties params = new Properties(); + + Enumeration enumerateParam = def.enumerateParam(); + while (enumerateParam.hasMoreElements()) { + Param par = (Param) enumerateParam.nextElement(); + params.put(par.getName(), par.getValue()); + } + + desc = new KeyGeneratorDescriptor( + name, def.getName(), params, _keyGenReg); + + _keyGenDescs.put(name, desc); + } } - public BindingType getBindingType() { return BindingType.JDO; } + //----------------------------------------------------------------------------------- - protected ClassDescriptor createDescriptor(final ClassMapping clsMap) + protected final ClassDescriptor createClassDescriptor(final ClassMapping clsMap) throws MappingException { - ClassDescriptor clsDesc; - String keyGenName; - KeyGeneratorDescriptor keyGenDesc; - - // If no SQL information for class, ignore it. JDO only - // supports JDO class descriptors. + // If there is no SQL information for class, ignore it. if ((clsMap.getMapTo() == null) || (clsMap.getMapTo().getTable() == null)) { - return AbstractMappingLoader.NO_DESCRIPTOR; + LOG.info(Messages.format("mapping.ignoringMapping", clsMap.getName())); + return null; } - // See if we have a compiled descriptor. - clsDesc = null; - if ((clsDesc != null) && (clsDesc instanceof JDOClassDescriptor)) { - return clsDesc; + // Create the class descriptor. + JDOClassDescriptor clsDesc = new JDOClassDescriptor(); + + // Set reference to class mapping on class descriptor. + clsDesc.setMapping(clsMap); + + // Obtain the Java class. + Class javaClass = resolveType(clsMap.getName()); + if (!Types.isConstructable(javaClass, true)) { + throw new MappingException( + "mapping.classNotConstructable", javaClass.getName()); + } + clsDesc.setJavaClass(javaClass); + + // If this class extends another class, we need to obtain the extended + // class and make sure this class indeed extends it. + ClassDescriptor extDesc = getExtended(clsMap, javaClass); + if (extDesc != null) { + if (!(extDesc instanceof JDOClassDescriptor)) { + throw new IllegalArgumentException( + "Extended class does not have a JDO descriptor"); + } + + ((JDOClassDescriptor) extDesc).addExtended(clsDesc); } + clsDesc.setExtends(extDesc); + + // If this class depends on another class, obtain the depended class. + clsDesc.setDepends(getDepended(clsMap, javaClass)); + + // Create all field descriptors. + AbstractFieldDescriptor[] allFields = createFieldDescriptors(clsMap, javaClass); - // Use super class to create class descriptor. Field descriptors will be - // generated only for supported fields, see createFieldDesc later on. - // This class may only extend a JDO class, otherwise no mapping will be - // found for the parent. - clsDesc = super.createDescriptor(clsMap); + // Make sure there are no two fields with the same name. + checkFieldNameDuplicates(allFields, javaClass); - // JDO descriptor must include an identity field, the identity field - // is either a field, or a container field containing only JDO fields. - // If the identity field is not a JDO field, it will be cleaned later - // on (we need the descriptor for relations mapping). - if (clsDesc.getIdentity() == null) { - throw new MappingException("mapping.noIdentity", clsDesc.getJavaClass().getName()); + // Set class descriptor containing the field + for (int i = 0; i < allFields.length; i++) { + allFields[i].setContainingClassDescriptor(clsDesc); } + + // Identify identity and normal fields. Note that order must be preserved. + List fieldList = new ArrayList(allFields.length); + List idList = new ArrayList(); + if (extDesc == null) { + // Sort fields into 2 lists based on identity definition of field. + for (int i = 0; i < allFields.length; i++) { + if (!allFields[i].isIdentity()) { + fieldList.add(allFields[i]); + } else { + idList.add(allFields[i]); + } + } + + if (idList.size() == 0) { + // Found no identities based on identity definition of field. + // Try to find identities based on identity definition on class. + String[] idNames = clsMap.getIdentity(); + if ((idNames == null) || (idNames.length == 0)) { + // There are also no identity definitions on class. + throw new MappingException("mapping.noIdentity", javaClass.getName()); + } + + FieldDescriptor identity; + for (int i = 0; i < idNames.length; i++) { + identity = findIdentityByName(fieldList, idNames[i], javaClass); + if (identity != null) { + idList.add(identity); + } else { + throw new MappingException("mapping.identityMissing", + idNames[i], javaClass.getName()); + } + } + } + } else { + // Add all fields of extending class to field list. + for (int i = 0; i < allFields.length; i++) { fieldList.add(allFields[i]); } + + // Add all identities of extended class to identity list. + FieldDescriptor[] extIds = ((JDOClassDescriptor) extDesc).getIdentities(); + for (int i = 0; i < extIds.length; i++) { idList.add(extIds[i]); } + + // Search redefined identities in extending class. + FieldDescriptor identity; + for (int i = 0; i < idList.size(); i++) { + String idName = ((FieldDescriptor) idList.get(i)).getFieldName(); + identity = findIdentityByName(fieldList, idName, javaClass); + if (identity != null) { idList.set(i, identity); } + } + } + + // Set identities on class descriptor. + FieldDescriptor[] ids = new FieldDescriptor[idList.size()]; + clsDesc.setIdentities((FieldDescriptor[]) idList.toArray(ids)); - // create a key generator descriptor - keyGenName = clsMap.getKeyGenerator(); - keyGenDesc = null; - if (keyGenName != null) { - String keyGenFactoryName; - KeyGeneratorDef keyGenDef; - Enumeration enumeration; - Properties params; + // Set fields on class descriptor. + FieldDescriptor[] fields = new FieldDescriptor[fieldList.size()]; + clsDesc.setFields((FieldDescriptor[]) fieldList.toArray(fields)); + + clsDesc.setTableName(clsMap.getMapTo().getTable()); + + extractAndSetAccessMode(clsDesc, clsMap); + extractAndAddCacheParams(clsDesc, clsMap, javaClass); + extractAndAddNamedQueries(clsDesc, clsMap); + extractAndSetKeyGeneratorDescriptor(clsDesc, clsMap); + + return clsDesc; + } + + /** + * Extract access mode from class mapping and set it at JDO class descriptor. + * + * @param clsDesc JDO class descriptor to set the access mode on. + * @param clsMap Class mapping to extract the access mode from. + */ + private void extractAndSetAccessMode(final JDOClassDescriptor clsDesc, + final ClassMapping clsMap) { + if (clsMap.getAccess() != null) { + clsDesc.setAccessMode(AccessMode.valueOf(clsMap.getAccess().toString())); + } + } + + /** + * Extract cache parameters from class mapping and add them to JDO class descriptor. + * + * @param clsDesc JDO class descriptor to add the cache parameters to. + * @param clsMap Class mapping to extract the cache parameters from. + * @param javaClass Class the cache parameters are defined for. + * @throws MappingException If cache type none has been specified for + * a class that implements TimeStampable interface. + */ + private void extractAndAddCacheParams(final JDOClassDescriptor clsDesc, + final ClassMapping clsMap, final Class javaClass) + throws MappingException { + clsDesc.addCacheParam(Cache.PARAM_NAME, clsMap.getName()); - // first search among declared key generators - // and resolve alias - keyGenDef = (KeyGeneratorDef) _keyGenDefs.get(keyGenName); - params = new Properties(); - keyGenFactoryName = keyGenName; - if (keyGenDef != null) { - keyGenFactoryName = keyGenDef.getName(); - enumeration = keyGenDef.enumerateParam(); - while (enumeration.hasMoreElements()) { - Param par = (Param) enumeration.nextElement(); - params.put(par.getName(), par.getValue()); + CacheTypeMapping cacheMapping = clsMap.getCacheTypeMapping(); + if (cacheMapping != null) { + String type = cacheMapping.getType(); + if ("none".equalsIgnoreCase(type)) { + if (TimeStampable.class.isAssignableFrom(javaClass)) { + throw new MappingException(Messages.format( + "persist.wrongCacheTypeSpecified", clsMap.getName())); } } + clsDesc.addCacheParam(Cache.PARAM_TYPE, type); + + Param[] params = cacheMapping.getParam(); + for (int i = 0; i < params.length; i++) { + clsDesc.addCacheParam(params[i].getName(), params[i].getValue()); + } + + String debug = new Boolean(cacheMapping.getDebug()).toString(); + clsDesc.addCacheParam(Cache.PARAM_DEBUG, debug); + + String capacity = Long.toString(cacheMapping.getCapacity()); + clsDesc.addCacheParam(CountLimited.PARAM_CAPACITY, capacity); + clsDesc.addCacheParam(TimeLimited.PARAM_TTL, capacity); + } + } + + /** + * Extract named queries from class mapping and add them to JDO class descriptor. + * + * @param clsDesc JDO class descriptor to add the named queries to. + * @param clsMap Class mapping to extract the named queries from. + * @throws MappingException On duplicate query names. + */ + private void extractAndAddNamedQueries(final JDOClassDescriptor clsDesc, + final ClassMapping clsMap) + throws MappingException { + Enumeration namedQueriesEnum = clsMap.enumerateNamedQuery(); + while (namedQueriesEnum.hasMoreElements()) { + NamedQuery query = (NamedQuery) namedQueriesEnum.nextElement(); + String queryName = query.getName(); + if (_queryNames.contains(queryName)) { + throw new MappingException( + "Duplicate entry for named query with name " + queryName); + } + _queryNames.add(queryName); + + clsDesc.addNamedQuery(queryName, query.getQuery()); + } + } + + /** + * Extract name of key generator to use from class mapping. Search for an already + * existing key generator descriptor, e.g. those generated from the key generator + * definitions in mapping. If no descriptor can be found a new one is created and + * added to the map of class descriptors. Set the key generator descriptor at the + * class descriptor. + * + * @param clsDesc JDO class descriptor to set the key generator descriptor at. + * @param clsMap Class mapping name of key generator. + */ + private void extractAndSetKeyGeneratorDescriptor(final JDOClassDescriptor clsDesc, + final ClassMapping clsMap) { + KeyGeneratorDescriptor keyGenDesc = null; + + String keyGenName = clsMap.getKeyGenerator(); + if (keyGenName != null) { keyGenDesc = (KeyGeneratorDescriptor) _keyGenDescs.get(keyGenName); if (keyGenDesc == null) { - keyGenDesc = new KeyGeneratorDescriptor(keyGenName, - keyGenFactoryName, params, _keyGenReg); + keyGenDesc = new KeyGeneratorDescriptor( + keyGenName, keyGenName, new Properties(), _keyGenReg); _keyGenDescs.put(keyGenName, keyGenDesc); } } @@ -222,26 +432,46 @@ } } - JDOClassDescriptor classDescriptor = new JDOClassDescriptor(clsDesc, keyGenDesc); - - // extract named queries and add to (JDO) class descriptor - Enumeration namedQueriesEnum = clsMap.enumerateNamedQuery(); - while (namedQueriesEnum.hasMoreElements()) { - NamedQuery namedQuery = (NamedQuery) namedQueriesEnum.nextElement(); - try { - if(_namedQueries.contains(namedQuery.getName())) { - throw new MappingException("Duplicate entry for named query with name " + namedQuery.getName()); + clsDesc.setKeyGeneratorDescriptor(keyGenDesc); + } + + protected final FieldDescriptor findIdentityByName( + final List fldList, final String idName, final Class javaClass) + throws MappingException { + for (int i = 0; i < fldList.size(); i++) { + FieldDescriptor field = (FieldDescriptor) fldList.get(i); + if (idName.equals(field.getFieldName())) { + if (!(field instanceof JDOFieldDescriptor)) { + throw new IllegalStateException( + "Identity field must be of type JDOFieldDescriptor"); + } + + String[] sqlName = ((JDOFieldDescriptor) field).getSQLName(); + if (sqlName == null) { + throw new MappingException("mapping.noSqlName", + field.getFieldName(), javaClass.getName()); } - classDescriptor.addNamedQuery(namedQuery.getName(), namedQuery.getQuery()); - _namedQueries.put(namedQuery.getName(), namedQuery); - } catch (QueryException e) { - throw new MappingException(e); + + fldList.remove(i); + return field; } } - - return classDescriptor; + return null; + } + + protected final void resolveRelations(final ClassDescriptor clsDesc) { + FieldDescriptor[] fields = clsDesc.getFields(); + for (int i = 0 ; i < fields.length ; ++i) { + FieldDescriptor field = fields[i]; + ClassDescriptor desc = getDescriptor(field.getFieldType().getName()); + if ((desc != null) && (field instanceof FieldDescriptorImpl)) { + ((FieldDescriptorImpl) field).setClassDescriptor(desc); + } + } } + //----------------------------------------------------------------------------------- + /** * Parse the sql type attribute to build an * array of types, needed to support whitespace inside @@ -367,7 +597,7 @@ } - protected FieldDescriptor createFieldDesc( Class javaClass, FieldMapping fieldMap ) + protected AbstractFieldDescriptor createFieldDesc( Class javaClass, FieldMapping fieldMap ) throws MappingException { // If not an SQL field, return a stock field descriptor. @@ -380,11 +610,7 @@ // field/accessor. Class fieldType = null; if ( fieldMap.getType() != null ) { - try { - fieldType = resolveType( fieldMap.getType() ); - } catch ( ClassNotFoundException except ) { - throw new MappingException( "mapping.classNotFound", fieldMap.getType() ); - } + fieldType = resolveType( fieldMap.getType() ); } // If the field is declared as a collection, grab the collection type as @@ -417,13 +643,7 @@ //-- check for user supplied FieldHandler if (fieldMap.getHandler() != null) { - Class handlerClass = null; - try { - handlerClass = resolveType( fieldMap.getHandler() ); - } - catch (ClassNotFoundException except) { - throw new MappingException( "mapping.classNotFound", fieldMap.getHandler() ); - } + Class handlerClass = resolveType(fieldMap.getHandler()); if (!FieldHandler.class.isAssignableFrom(handlerClass)) { String err = "The class '" + fieldMap.getHandler() + @@ -531,31 +751,5 @@ return jdoFieldDescriptor; } - protected void loadMappingInternal(final MappingRoot mapping, final Object param) - throws MappingException { - Enumeration enumeration; - _factory = (BaseFactory) param; - // Load the key generator definitions and check for duplicate names - enumeration = mapping.enumerateKeyGeneratorDef(); - while ( enumeration.hasMoreElements() ) { - KeyGeneratorDef keyGenDef; - String name; - - keyGenDef = (KeyGeneratorDef) enumeration.nextElement(); - name = keyGenDef.getAlias(); - if (name == null) { - name = keyGenDef.getName(); - } - if ( _keyGenDefs.get( name ) != null ) { - throw new MappingException( Messages.format( "mapping.dupKeyGen", name ) ); - } - _keyGenDefs.put( name, keyGenDef ); - } - - super.loadMappingInternal(mapping, null); - - _keyGenDefs = null; - _keyGenDescs = null; - _keyGenReg = null; - } + //----------------------------------------------------------------------------------- } Index: C:/Java/castor-4/src/main/java/org/exolab/castor/jdo/engine/SQLHelper.java =================================================================== --- C:/Java/castor-4/src/main/java/org/exolab/castor/jdo/engine/SQLHelper.java (revision 6773) +++ C:/Java/castor-4/src/main/java/org/exolab/castor/jdo/engine/SQLHelper.java (working copy) @@ -27,6 +27,7 @@ import org.apache.commons.logging.LogFactory; import org.castor.jdo.engine.SQLTypeInfos; import org.exolab.castor.mapping.FieldDescriptor; +import org.exolab.castor.mapping.MappingException; import org.exolab.castor.persist.spi.Identity; /** @@ -142,9 +143,19 @@ for (Iterator iter = extendingClassDescriptors.iterator(); iter.hasNext(); ) { classDescriptor = (JDOClassDescriptor) iter.next(); classDescriptorsToAdd.add (classDescriptor); - addExtendingClassDescriptors(classDescriptorsToAdd, classDescriptor.getExtendedBy()); + addExtendingClassDescriptors(classDescriptorsToAdd, classDescriptor.getExtended()); } } + + public static String[] getIdentitySQLNames(final JDOClassDescriptor desc) { + FieldDescriptor[] identities = desc.getIdentities(); + String[] sqlNames = new String[identities.length]; + for (int i = 0; i < identities.length; i++) { + sqlNames[i] = ((JDOFieldDescriptor) identities[i]).getSQLName()[0]; + } + + return sqlNames; + } private SQLHelper() { } } Index: C:/Java/castor-4/src/main/java/org/exolab/castor/jdo/engine/SQLQuery.java =================================================================== --- C:/Java/castor-4/src/main/java/org/exolab/castor/jdo/engine/SQLQuery.java (revision 6773) +++ C:/Java/castor-4/src/main/java/org/exolab/castor/jdo/engine/SQLQuery.java (working copy) @@ -461,8 +461,8 @@ // "multi field" each fetchRaw is called, we might reuse them. int originalFieldNumber = _requestedEngine.getInfo().length; - if (_requestedEngine.getDescriptor().isExtended()) { - Collection extendingClassDescriptors = _requestedEngine.getDescriptor().getExtendedBy(); + Collection extendingClassDescriptors = _requestedEngine.getDescriptor().getExtended(); + if (extendingClassDescriptors.size() > 0) { int numberOfExtendLevels = SQLHelper.numberOfExtendingClassDescriptors(_requestedEngine.getDescriptor()); JDOClassDescriptor leafDescriptor = null; Object[] returnValues = null; Index: C:/Java/castor-4/src/main/java/org/exolab/castor/jdo/engine/SQLStatementLoad.java =================================================================== --- C:/Java/castor-4/src/main/java/org/exolab/castor/jdo/engine/SQLStatementLoad.java (revision 6773) +++ C:/Java/castor-4/src/main/java/org/exolab/castor/jdo/engine/SQLStatementLoad.java (working copy) @@ -80,7 +80,7 @@ // obtain the number of ClassDescriptor that extend this one. _numberOfExtendLevels = SQLHelper.numberOfExtendingClassDescriptors(engine.getDescriptor()); - _extendingClassDescriptors = engine.getDescriptor().getExtendedBy(); + _extendingClassDescriptors = engine.getDescriptor().getExtended(); buildStatement(); } @@ -97,8 +97,10 @@ JDOClassDescriptor baseDesc; while (curDesc.getExtends() != null) { baseDesc = (JDOClassDescriptor) curDesc.getExtends(); - expr.addInnerJoin(curDesc.getTableName(), curDesc.getIdentityColumnNames(), - baseDesc.getTableName(), baseDesc.getIdentityColumnNames()); + String[] curDescIdNames = SQLHelper.getIdentitySQLNames(curDesc); + String[] baseDescIdNames = SQLHelper.getIdentitySQLNames(baseDesc); + expr.addInnerJoin(curDesc.getTableName(), curDescIdNames, + baseDesc.getTableName(), baseDescIdNames); joinTables.add(baseDesc.getTableName()); curDesc = baseDesc; } @@ -118,7 +120,7 @@ // add id fields for root table if first field points to a separate table if ((i == 0) && field.isJoined()) { - String[] identities = _engine.getDescriptor().getIdentityColumnNames(); + String[] identities = SQLHelper.getIdentitySQLNames(_engine.getDescriptor()); for (int j = 0; j < identities.length; j++) { expr.addColumn(curDesc.getTableName(), identities[j]); } @@ -130,7 +132,7 @@ if (!alias.equals(aliasOld) && !field.isJoined()) { JDOClassDescriptor classDescriptor = (JDOClassDescriptor) field.getFieldDescriptor().getContainingClassDescriptor(); - String[] identities = classDescriptor.getIdentityColumnNames(); + String[] identities = SQLHelper.getIdentitySQLNames(classDescriptor); for (int j = 0; j < identities.length; j++) { boolean isTableNameAlreadyAdded = identitiesUsedForTable.containsKey(classDescriptor.getTableName()); if (!isTableNameAlreadyAdded) { @@ -167,7 +169,7 @@ // 'join' all the extending tables List classDescriptorsToAdd = new LinkedList(); JDOClassDescriptor classDescriptor = null; - SQLHelper.addExtendingClassDescriptors(classDescriptorsToAdd, _engine.getDescriptor().getExtendedBy()); + SQLHelper.addExtendingClassDescriptors(classDescriptorsToAdd, _engine.getDescriptor().getExtended()); if (classDescriptorsToAdd.size() > 0) { for (Iterator iter = classDescriptorsToAdd.iterator(); iter.hasNext(); ) { @@ -179,8 +181,10 @@ + classDescriptor.getTableName()); } - expr.addOuterJoin(_mapTo, _engine.getDescriptor().getIdentityColumnNames(), - classDescriptor.getTableName(), classDescriptor.getIdentityColumnNames()); + String[] engDescIdNames = SQLHelper.getIdentitySQLNames(_engine.getDescriptor()); + String[] clsDescIdNames = SQLHelper.getIdentitySQLNames(classDescriptor); + expr.addOuterJoin(_mapTo, engDescIdNames, + classDescriptor.getTableName(), clsDescIdNames); Persistence persistenceEngine; try { Index: C:/Java/castor-4/src/main/java/org/exolab/castor/jdo/oql/ParseTreeWalker.java =================================================================== --- C:/Java/castor-4/src/main/java/org/exolab/castor/jdo/oql/ParseTreeWalker.java (revision 6773) +++ C:/Java/castor-4/src/main/java/org/exolab/castor/jdo/oql/ParseTreeWalker.java (working copy) @@ -26,6 +26,7 @@ import org.exolab.castor.jdo.engine.JDOClassDescriptor; import org.exolab.castor.jdo.engine.JDOFieldDescriptor; import org.exolab.castor.jdo.engine.SQLEngine; +import org.exolab.castor.jdo.engine.SQLHelper; import org.exolab.castor.mapping.loader.Types; import org.exolab.castor.persist.LockEngine; import org.exolab.castor.persist.spi.QueryExpression; @@ -370,9 +371,11 @@ tableAlias2 = buildTableAlias(tableAlias2, path, tableIndex); } expr.addTable(cd.getTableName(), tableAlias2); + String[] clsDescIdNames = SQLHelper.getIdentitySQLNames(clsDesc); + String[] cdIdNames = SQLHelper.getIdentitySQLNames(cd); expr.addInnerJoin( - clsDesc.getTableName(), clsDesc.getIdentityColumnNames(), tableAlias1, - cd.getTableName(), cd.getIdentityColumnNames(), tableAlias2); + clsDesc.getTableName(), clsDescIdNames, tableAlias1, + cd.getTableName(), cdIdNames, tableAlias2); } return retVal; } Index: C:/Java/castor-4/src/main/java/org/exolab/castor/mapping/ClassDescriptor.java =================================================================== --- C:/Java/castor-4/src/main/java/org/exolab/castor/mapping/ClassDescriptor.java (revision 6773) +++ C:/Java/castor-4/src/main/java/org/exolab/castor/mapping/ClassDescriptor.java (working copy) @@ -42,11 +42,8 @@ * * $Id$ */ - - package org.exolab.castor.mapping; - /** * Describes the properties of a class and its fields. Implementations * will extend this inteface to provide additional properties. @@ -55,10 +52,7 @@ * @version $Revision$ $Date: 2003-03-03 00:05:44 -0700 (Mon, 03 Mar 2003) $ * @see FieldDescriptor */ -public interface ClassDescriptor -{ - - +public interface ClassDescriptor { /** * Returns the Java class represented by this descriptor. * @@ -66,7 +60,6 @@ */ public Class getJavaClass(); - /** * Returns a list of fields represented by this descriptor. * @@ -74,7 +67,6 @@ */ public FieldDescriptor[] getFields(); - /** * Returns the class descriptor of the class extended by this class. * @@ -82,7 +74,6 @@ */ public ClassDescriptor getExtends(); - /** * Returns the identity field, null if this class has no identity. * @@ -89,16 +80,6 @@ * @return The identity field */ public FieldDescriptor getIdentity(); - - - /** - * Returns the access mode specified for this class. - * - * @return The access mode - */ - public AccessMode getAccessMode(); - - } Index: C:/Java/castor-4/src/main/java/org/exolab/castor/mapping/loader/AbstractFieldDescriptor.java =================================================================== --- C:/Java/castor-4/src/main/java/org/exolab/castor/mapping/loader/AbstractFieldDescriptor.java (revision 6773) +++ C:/Java/castor-4/src/main/java/org/exolab/castor/mapping/loader/AbstractFieldDescriptor.java (working copy) @@ -33,6 +33,9 @@ /** True if the object described by this descriptor is multivalued. */ private boolean _multivalued; + + /** True if the field is part of the identity of the class. */ + private boolean _identity; //-------------------------------------------------------------------------- @@ -190,6 +193,24 @@ public final boolean isMultivalued() { return _multivalued; } + + /** + * Set wether the described field is part of the identity of the class it belongs to. + * + * @param identity true if field is part of the classes identity. + */ + public final void setIdentity(final boolean identity) { + _identity = identity; + } + + /** + * Is the described field is part of the identity of the class it belongs to? + * + * @return true if field is part of the classes identity. + */ + public final boolean isIdentity() { + return _identity; + } //-------------------------------------------------------------------------- } Index: C:/Java/castor-4/src/main/java/org/exolab/castor/mapping/loader/AbstractMappingLoader.java =================================================================== --- C:/Java/castor-4/src/main/java/org/exolab/castor/mapping/loader/AbstractMappingLoader.java (revision 6773) +++ C:/Java/castor-4/src/main/java/org/exolab/castor/mapping/loader/AbstractMappingLoader.java (working copy) @@ -58,9 +58,6 @@ import java.util.List; import java.util.Enumeration; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.castor.util.Messages; import org.exolab.castor.mapping.ClassDescriptor; import org.exolab.castor.mapping.CollectionHandler; import org.exolab.castor.mapping.ExtendedFieldHandler; @@ -86,9 +83,7 @@ * @version $Revision$ $Date: 2006-04-10 16:39:24 -0600 (Mon, 10 Apr 2006) $ */ public abstract class AbstractMappingLoader extends AbstractMappingLoader2 { - /** The Jakarta Commons - * Logging instance used for all logging. */ - private static final Log LOG = LogFactory.getLog(AbstractMappingLoader.class); + //-------------------------------------------------------------------------- /** The prefix for the "add" method. */ private static final String ADD_METHOD_PREFIX = "add"; @@ -127,7 +122,7 @@ /** Factory method name for type-safe enumerations. */ protected static final String VALUE_OF = "valueOf"; - protected static final ClassDescriptor NO_DESCRIPTOR = new ClassDescriptorImpl(Class.class); + //-------------------------------------------------------------------------- /** * Constructs a new mapping helper. This constructor is used by a derived class. @@ -138,6 +133,8 @@ super(loader); } + //-------------------------------------------------------------------------- + /** * {@inheritDoc} */ @@ -145,21 +142,19 @@ return "CastorXmlMapping"; } + //-------------------------------------------------------------------------- + /** - * Returns the Java class for the named type. The type name can be one of the - * accepted short names (e.g. integer) or the full Java class name (e.g. - * java.lang.Integer). If the short name is used, the primitive type might - * be returned. + * Loads the mapping from the specified mapping object if not loaded previously. + * + * @param mapping The mapping information. + * @param param Arbitrary parameter that can be used by subclasses. + * @throws MappingException The mapping file is invalid. */ - protected final Class resolveType(final String typeName) - throws ClassNotFoundException { - return Types.typeFromName(getClassLoader(), typeName); - } + public abstract void loadMapping(final MappingRoot mapping, final Object param) + throws MappingException; - /** - * {@inheritDoc} - */ - protected void loadMappingInternal(final MappingRoot mapping, final Object param) + protected final void createClassDescriptors(final MappingRoot mapping) throws MappingException { // Load the mapping for all the classes. This is always returned // in the same order as it appeared in the mapping file. @@ -168,10 +163,9 @@ List retryList = new ArrayList(); while (enumeration.hasMoreElements()) { ClassMapping clsMap = (ClassMapping) enumeration.nextElement(); - ClassDescriptor clsDesc = null; - try { - clsDesc = createDescriptor(clsMap); + ClassDescriptor clsDesc = createClassDescriptor(clsMap); + if (clsDesc != null) { addDescriptor(clsDesc); } } catch (MappingException mx) { // save for later for possible out-of-order mapping files... retryList.add(clsMap); @@ -177,14 +171,6 @@ retryList.add(clsMap); continue; } - - if (clsDesc != NO_DESCRIPTOR) { - addDescriptor(clsDesc); - } else { - // If the return value is NoDescriptor then the derived - // class was not successful in constructing a descriptor. - LOG.info(Messages.format("mapping.ignoringMapping", clsMap.getName())); - } } // handle possible retries, for now we only loop once on the retries, but we @@ -191,134 +177,19 @@ // should change this to keep looping until we have no more success rate. for (Iterator i = retryList.iterator(); i.hasNext();) { ClassMapping clsMap = (ClassMapping) i.next(); - ClassDescriptor clsDesc = createDescriptor(clsMap); - if (clsDesc != NO_DESCRIPTOR) { - addDescriptor(clsDesc); - } else { - // If the return value is NoDescriptor then the derived - // class was not successful in constructing a descriptor. - LOG.info(Messages.format("mapping.ignoringMapping", clsMap.getName())); - } + ClassDescriptor clsDesc = createClassDescriptor(clsMap); + if (clsDesc != null) { addDescriptor(clsDesc); } } - for (Iterator i = this.descriptorIterator(); i.hasNext();) { - ClassDescriptor clsDesc = (ClassDescriptor) i.next(); - if (clsDesc != NO_DESCRIPTOR) { resolveRelations(clsDesc); } + // iterate over all class descriptors and resolve relations between them + for (Iterator i = descriptorIterator(); i.hasNext();) { + resolveRelations((ClassDescriptor) i.next()); } } - - protected void resolveRelations(final ClassDescriptor clsDesc) { - FieldDescriptor[] fields = clsDesc.getFields(); - for ( int i = 0 ; i < fields.length ; ++i ) { - FieldDescriptor field = fields[i]; - ClassDescriptor desc = getDescriptor(field.getFieldType().getName()); - if (desc == NO_DESCRIPTOR) { - // XXX Error message should come here - continue; - } else if ((desc != null) && (field instanceof FieldDescriptorImpl)) { - ( (FieldDescriptorImpl) field ).setClassDescriptor( desc ); - } - } - } - - /** - * Creates a new descriptor. The class mapping information is used to create a new - * stock {@link ClassDescriptor}. Implementations may extend this class to create a - * more suitable descriptor. - * - * @param clsMap The class mapping information. - * @throws MappingException An exception indicating why mapping for the class cannot - * be created. - */ - protected ClassDescriptor createDescriptor(final ClassMapping clsMap) - throws MappingException { - // Obtain the Java class. - Class javaClass; - try { - javaClass = resolveType(clsMap.getName()); - } catch (ClassNotFoundException ex) { - throw new MappingException("mapping.classNotFound", clsMap.getName()); - } - - // If this class extends another class, we need to obtain the extended - // class and make sure this class indeed extends it. - ClassDescriptor extend = getExtended(clsMap, javaClass.getName()); - - // If this class depends another class, need to obtain the depended class - ClassDescriptor depend = getDepended(clsMap, javaClass.getName()); - - // Get field descriptors first. Note: order must be preserved for fields, but not - // for relations or container fields. Add all the container fields in there. - FieldDescriptor[] fields = createFieldDescriptors(clsMap, javaClass); - - // Make sure there are no two fields with the same name. - checkFieldNames(fields, javaClass.getName()); - - ClassMapping origin = getOrigin(clsMap); - String[] ids = getIdentityColumnNames(origin.getIdentity(), origin); - - if ((ids == null) || (ids.length == 0)) { - return new ClassDescriptorImpl( - clsMap, javaClass, fields, null, extend, depend); - } - - // Check that an XML mapping file does not declare more identity attributes for a - // given class than there are field elements defined for that class. - // (Patch submitted by Gabriel Richard Pack ) - if ((origin == clsMap) && (ids.length > fields.length)) { - StringBuffer badIdentities = new StringBuffer(); - for (int index = 0; index < ids.length; index++) { - if (index != 0) { badIdentities.append(" or "); } - badIdentities.append(ids[index]); - } - throw new MappingException( - "mapping.identityMissing", badIdentities, javaClass.getName()); - } - - // Divide fields into identity fields and regular fields - FieldDescriptor[] identities = new FieldDescriptor[ids.length]; - fields = divideFieldDescriptors(fields, ids, identities); - - if (extend != null) { - // We allow identity fields to be re-defined in the extends class mapping to - // override some properties of the field, for example, . - if (extend instanceof ClassDescriptorImpl) { - ClassDescriptorImpl extendImpl = (ClassDescriptorImpl) extend; - for (int i = 0; i < identities.length; i++) { - if (identities[i] == null) { - identities[i] = extendImpl.getIdentities()[i]; - } - } - } else { - // We leave things in the old way for the XML side - if (identities[0] == null) { - if (extend.getIdentity() != null) { - identities = new FieldDescriptor[] {extend.getIdentity()}; - } else { - identities = new FieldDescriptor[0]; - } - } - } - } - - // A general test of identities - if ((ids != null) && (ids.length > 0)) { - if ((identities == null) || (identities.length <= 0 )) { - StringBuffer badIdentities = new StringBuffer(); - for (int i = 0; i < ids.length; i++) { - if (i != 0) { badIdentities.append("/"); } - badIdentities.append(ids[i]); - } - throw new MappingException( - "mapping.identityMissing", badIdentities, javaClass.getName()); - } - } - - // Create the class descriptor. - return new ClassDescriptorImpl( - clsMap, javaClass, fields, identities, extend, depend); - } - + + protected abstract ClassDescriptor createClassDescriptor(final ClassMapping clsMap) + throws MappingException; + /** * Gets the ClassDescriptor the given classMapping extends. * @@ -330,27 +201,26 @@ * @throws MappingException If the given ClassMapping extends another ClassMapping but * its descriptor could not be found. */ - private ClassDescriptor getExtended(final ClassMapping clsMap, final String clsName) + protected final ClassDescriptor getExtended( + final ClassMapping clsMap, final Class javaClass) throws MappingException { if (clsMap.getExtends() == null) { return null; } - try { - ClassMapping mapping = (ClassMapping) clsMap.getExtends(); - Class type = resolveType(mapping.getName()); - ClassDescriptor result = getDescriptor(type.getName()); - - if (result == null) { - throw new MappingException("mapping.extendsMissing", mapping, clsName); - } + ClassMapping mapping = (ClassMapping) clsMap.getExtends(); + Class type = resolveType(mapping.getName()); + ClassDescriptor result = getDescriptor(type.getName()); - if (result == NO_DESCRIPTOR) { - throw new MappingException("mapping.extendsNoMapping", mapping, clsName); - } + if (result == null) { + throw new MappingException( + "mapping.extendsMissing", mapping, javaClass.getName()); + } - return result; - } catch (ClassNotFoundException ex) { - throw new MappingException(ex); + if (!result.getJavaClass().isAssignableFrom(javaClass)) { + throw new MappingException("mapping.classDoesNotExtend", + javaClass.getName(), result.getJavaClass().getName()); } + + return result; } /** @@ -364,23 +234,67 @@ * @throws MappingException If the given ClassMapping depends on another ClassMapping * but its descriptor could not be found. */ - private ClassDescriptor getDepended(final ClassMapping clsMap, final String clsName) + protected final ClassDescriptor getDepended( + final ClassMapping clsMap, final Class javaClass) throws MappingException { if (clsMap.getDepends() == null) { return null; } - try { - ClassMapping mapping = (ClassMapping) clsMap.getDepends(); - Class type = resolveType(mapping.getName()); - ClassDescriptor result = getDescriptor(type.getName()); + ClassMapping mapping = (ClassMapping) clsMap.getDepends(); + Class type = resolveType(mapping.getName()); + ClassDescriptor result = getDescriptor(type.getName()); + + if (result == null) { + throw new MappingException( + "Depends not found: " + mapping + " " + javaClass.getName()); + } - if ((result == null) || (result == NO_DESCRIPTOR)) { - String msg = "Depends not found: " + mapping + " " + clsName; - throw new MappingException(msg); + return result; + } + + /** + * Checks all given fields for name equality and throws a MappingException if at + * least two fields have the same name. + * + * @param fields The fields to be checked. + * @param cls Class that is checked (this is used for generating the exception). + * @throws MappingException If at least two fields have the same name. + */ + protected final void checkFieldNameDuplicates( + final FieldDescriptor[] fields, final Class cls) + throws MappingException { + for (int i = 0; i < fields.length - 1; i++) { + String fieldName = fields[i].getFieldName(); + for (int j = i + 1; j < fields.length; j++) { + if (fieldName.equals(fields[j].getFieldName())) { + throw new MappingException("The field " + fieldName + + " appears twice in the descriptor for " + cls.getName()); + } } + } + } + + protected abstract void resolveRelations(final ClassDescriptor clsDesc); - return result; - } catch (ClassNotFoundException e) { - throw new MappingException(e); + //-------------------------------------------------------------------------- + + + + + + + + /** + * Returns the Java class for the named type. The type name can be one of the + * accepted short names (e.g. integer) or the full Java class name (e.g. + * java.lang.Integer). If the short name is used, the primitive type might + * be returned. + */ + protected final Class resolveType(final String typeName) + throws MappingException { + try { + return Types.typeFromName(getClassLoader(), typeName); + } catch (ClassNotFoundException ex) { + throw new MappingException("mapping.classNotFound", typeName); } } @@ -395,7 +309,7 @@ * @throws MappingException An exception indicating why mapping for the class cannot * be created. */ - private FieldDescriptor[] createFieldDescriptors(final ClassMapping clsMap, + protected final AbstractFieldDescriptor[] createFieldDescriptors(final ClassMapping clsMap, final Class javaClass) throws MappingException { FieldMapping[] fldMap = null; @@ -404,12 +318,15 @@ } if ((fldMap == null) || (fldMap.length == 0)) { - return new FieldDescriptor[0]; + return new AbstractFieldDescriptor[0]; } - FieldDescriptor[] fields = new FieldDescriptor[fldMap.length]; + AbstractFieldDescriptor[] fields = new AbstractFieldDescriptor[fldMap.length]; for (int i = 0; i < fldMap.length; i++) { fields[i] = createFieldDesc(javaClass, fldMap[i]); + + // set identity flag + fields[i].setIdentity(fldMap[i].getIdentity()); } return fields; @@ -416,29 +333,6 @@ } /** - * Checks all given fields for name equality and throws a MappingException if at least - * two fields have the same name. - * - * @param fields The fields to be checked. - * @param clsName The name of the class that is checked (this is used for generating - * the exception). - * @throws MappingException If at least two fields have the same name. - */ - private void checkFieldNames(final FieldDescriptor[] fields, final String clsName) - throws MappingException { - for (int i = 0; i < fields.length - 1; i++) { - String fieldName = fields[i].getFieldName(); - - for (int j = i + 1; j < fields.length; j++) { - if (fieldName.equals(fields[j].getFieldName())) { - throw new MappingException("The field " + fieldName - + " appears twice in the descriptor for " + clsName); - } - } - } - } - - /** * Gets the top-most (i.e. without any further 'extends') extends of the given * classMapping. * @@ -446,7 +340,7 @@ * @return The top-most extends of the given ClassMapping or the ClassMapping itself * if it does not extend any other ClassMapping. */ - private ClassMapping getOrigin(final ClassMapping clsMap) { + protected final ClassMapping getOrigin(final ClassMapping clsMap) { ClassMapping result = clsMap; while (result.getExtends() != null) { @@ -456,7 +350,7 @@ return result; } - private FieldDescriptor[] divideFieldDescriptors(final FieldDescriptor[] fields, + protected final FieldDescriptor[] divideFieldDescriptors(final FieldDescriptor[] fields, final String[] ids, final FieldDescriptor[] identities) { List fieldList = new ArrayList(fields.length); @@ -492,7 +386,7 @@ * @return The index of the id column name that matches the given field's name or * -1 if no such id column name exists. */ - private int getIdColumnIndex(FieldDescriptor field, String[] ids) { + protected int getIdColumnIndex(FieldDescriptor field, String[] ids) { for (int i = 0; i < ids.length; i++) { if (field.getFieldName().equals(ids[i])) { return i; @@ -512,7 +406,7 @@ * @throws MappingException The field or its accessor methods are not * found, not accessible, not of the specified type, etc. */ - protected FieldDescriptor createFieldDesc(final Class javaClass, + protected AbstractFieldDescriptor createFieldDesc(final Class javaClass, final FieldMapping fieldMap) throws MappingException { String fieldName = fieldMap.getName(); @@ -519,11 +413,7 @@ // If the field type is supplied, grab it and use it to locate the field/accessor. Class fieldType = null; if (fieldMap.getType() != null) { - try { - fieldType = resolveType(fieldMap.getType()); - } catch (ClassNotFoundException ex) { - throw new MappingException("mapping.classNotFound", fieldMap.getType()); - } + fieldType = resolveType(fieldMap.getType()); } // If the field is declared as a collection, grab the collection type as @@ -543,12 +433,7 @@ // Check for user supplied FieldHandler if (fieldMap.getHandler() != null) { Class handlerClass = null; - try { - handlerClass = resolveType(fieldMap.getHandler()); - } catch (ClassNotFoundException ex) { - throw new MappingException( - "mapping.classNotFound", fieldMap.getHandler()); - } + handlerClass = resolveType(fieldMap.getHandler()); if (!FieldHandler.class.isAssignableFrom(handlerClass)) { String err = "The class '" + fieldMap.getHandler() + "' must implement " @@ -1059,7 +944,7 @@ * @throws MappingException The method is not accessible or is not of the * specified type. */ - protected static final Method findAccessor(final Class javaClass, + public static final Method findAccessor(final Class javaClass, final String methodName, Class fieldType, final boolean getMethod) throws MappingException { try { Index: C:/Java/castor-4/src/main/java/org/exolab/castor/mapping/loader/AbstractMappingLoader2.java =================================================================== --- C:/Java/castor-4/src/main/java/org/exolab/castor/mapping/loader/AbstractMappingLoader2.java (revision 6773) +++ C:/Java/castor-4/src/main/java/org/exolab/castor/mapping/loader/AbstractMappingLoader2.java (working copy) @@ -9,7 +9,6 @@ import org.exolab.castor.mapping.ClassDescriptor; import org.exolab.castor.mapping.MappingException; import org.exolab.castor.mapping.MappingLoader; -import org.exolab.castor.mapping.xml.MappingRoot; public abstract class AbstractMappingLoader2 implements MappingLoader { //-------------------------------------------------------------------------- @@ -126,32 +125,18 @@ //-------------------------------------------------------------------------- /** - * Loads the mapping from the specified mapping object if not loaded previously. - * - * @param mapping The mapping information. - * @param param Arbitrary parameter that can be used by subclasses. - * @throws MappingException The mapping file is invalid. + * Return if mapping should be loaded with this MappingLoader instance or if another + * mapping have been loaded previously. If no mapping have been loaded previously + * then prevent any other mapping to be loaded later on. + * + * @return true if mapping should be loaded, false + * otherwise. */ - public final void loadMapping(final MappingRoot mapping, final Object param) - throws MappingException { - if (!_loaded) { - _loaded = true; - - loadMappingInternal(mapping, param); - } + protected final boolean loadMapping() { + if (_loaded) { return false; } + _loaded = true; + return true; } - /** - * Loads the mapping from the specified mapping object. Calls {@link #createDescriptor} to - * create each descriptor and {@link #addDescriptor} to store it. Also loads all the included - * mapping files. - * - * @param mapping The mapping information. - * @param param Arbitrary parameter that can be used by subclasses. - * @throws MappingException The mapping file is invalid. - */ - protected abstract void loadMappingInternal(MappingRoot mapping, Object param) - throws MappingException; - //-------------------------------------------------------------------------- } Index: C:/Java/castor-4/src/main/java/org/exolab/castor/mapping/loader/ClassDescriptorImpl.java =================================================================== --- C:/Java/castor-4/src/main/java/org/exolab/castor/mapping/loader/ClassDescriptorImpl.java (revision 6773) +++ C:/Java/castor-4/src/main/java/org/exolab/castor/mapping/loader/ClassDescriptorImpl.java (working copy) @@ -42,200 +42,75 @@ * * $Id$ */ - - package org.exolab.castor.mapping.loader; - import java.util.Collection; import java.util.LinkedList; -import org.exolab.castor.mapping.ValidityException; import org.exolab.castor.mapping.ClassDescriptor; import org.exolab.castor.mapping.FieldDescriptor; -import org.exolab.castor.mapping.MappingException; -import org.exolab.castor.mapping.AccessMode; import org.exolab.castor.mapping.xml.ClassMapping; - /** - * A basic class descriptor implementation. Engines will extend this - * class to provide additional functionality. - * + * A basic class descriptor implementation. Engines will extend this class to provide + * additional functionality. * - * @author Assaf Arkin + * @author Assaf Arkin + * @author Ralf Joachim * @version $Revision$ $Date: 2006-01-07 15:48:31 -0700 (Sat, 07 Jan 2006) $ */ public class ClassDescriptorImpl implements ClassDescriptor { - private final ClassMapping _map; - /** - * The Java class for this descriptor. - */ - private final Class _javaClass; + //----------------------------------------------------------------------------------- - /** - * The fields described for this class. - */ - protected final FieldDescriptor[] _fields; - + private ClassMapping _mapping; + + /** The Java class for this descriptor. */ + private Class _javaClass; - /** - * The descriptor of the class which this class extends, - * or null if this is a top-level class. - */ - private final ClassDescriptor _extends; + /** The descriptor of the class which this class extends, + * or null if this is a top-level class. */ + private ClassDescriptor _extends; - /** - * A collection of class descriptors that extend this class, or - * an empty collection if this is a leaf class. - */ - private final Collection _extendedBy = new LinkedList(); + /** A collection of class descriptors that extend this class, or + * an empty collection if this is a leaf class. */ + private final Collection _extended = new LinkedList(); - private final ClassDescriptor _depends; + private ClassDescriptor _depends; - /** - * The field of the identity for this class. - */ - protected final FieldDescriptor[] _identities; - + /** The fields described for this class. */ + private FieldDescriptor[] _fields; - /** - * The access mode specified for this class. - */ - private AccessMode _accessMode; + /** The field of the identity for this class. */ + private FieldDescriptor[] _identities; + //----------------------------------------------------------------------------------- - /** - * Constructs a new descriptor for the specified class. When describing - * inheritence, the descriptor of the parent class should be used and only - * the fields added in this object must be supplied here. - * - * @throws MappingException The extended descriptor does not match - * a parent class of this type - */ - - public ClassDescriptorImpl(final ClassDescriptorImpl clsDesc) - throws MappingException { - this(clsDesc.getMapping(), clsDesc.getJavaClass(), clsDesc.getFields(), - clsDesc.getIdentities(), clsDesc.getExtends(), clsDesc.getDepends(), true); - - _accessMode = clsDesc.getAccessMode(); + public void setMapping(final ClassMapping mapping) { + _mapping = mapping; } - public ClassDescriptorImpl(final ClassMapping map, final Class javaClass, - final FieldDescriptor[] fields, final FieldDescriptor[] identities, - final ClassDescriptor extend, final ClassDescriptor depend) - throws MappingException { - this(map, javaClass, fields, identities, extend, depend, - map.getVerifyConstructable()); - - if (map.getAccess() == null) { - _accessMode = AccessMode.Shared; - } else { - _accessMode = AccessMode.valueOf(map.getAccess().toString()); - } + public ClassMapping getMapping() { + return _mapping; } - private ClassDescriptorImpl(final ClassMapping clsMap, final Class javaClass, - final FieldDescriptor[] fields, final FieldDescriptor[] identities, - final ClassDescriptor extend, final ClassDescriptor depend, - final boolean verifyConstructable) - throws MappingException { - if (verifyConstructable && (!Types.isConstructable(javaClass, true))) { - throw new MappingException("mapping.classNotConstructable", javaClass.getName()); - } - - _map = clsMap; - _javaClass = javaClass; - - if (fields == null) { - throw new IllegalArgumentException("Argument 'fields' is null"); - } - _fields = (FieldDescriptor[]) fields.clone(); - - _depends = depend; - - if (extend != null) { - if (!extend.getJavaClass().isAssignableFrom(javaClass)) { - throw new MappingException("mapping.classDoesNotExtend", - javaClass.getName(), extend.getJavaClass().getName()); - } - _extends = extend; - - if (_extends.getClass().getName().equals("org.exolab.castor.jdo.engine.JDOClassDescriptor") && - this.getClass().getName().equals("org.exolab.castor.jdo.engine.JDOClassDescriptor")) { - ((ClassDescriptorImpl) _extends).addExtendedBy(this); - } - - if (_extends instanceof ClassDescriptorImpl) { - _identities = ( identities == null ? ((ClassDescriptorImpl)_extends).getIdentities() : identities ); - } else { - // a quick hack to fix a ClassCastException :-( - _identities = ( identities == null ? - (_extends.getIdentity() == null? null : new FieldDescriptor[] { _extends.getIdentity() } ) - : identities ); - } - } else { - _extends = null; - _identities = identities; - } - - // fritz: propagate containing class to fields - // oleg: don't alter the identity's info if the identity was taken - // from the ancestor class. - // So complicated condition is needed since for JDO fields first a pure - // ClassDescriptorImpl is created, and then JDOClassDescriptorImpl for - // the same class - if ((_identities != null) && (_identities.length > 0) && (_identities[0] != null) - && ((_identities[0].getContainingClassDescriptor() == null) - || (_identities[0].getContainingClassDescriptor().getJavaClass() == _javaClass))) { - for (int i = 0; i < _identities.length; i++) { - _identities[i].setContainingClassDescriptor(this); - } - } - - for (int i = 0; i < _fields.length; i++) { - _fields[i].setContainingClassDescriptor(this); - } - } - - /** - * Constructor used by derived classes. - */ - protected ClassDescriptorImpl(final Class javaClass) { - _map = null; + public void setJavaClass(final Class javaClass) { _javaClass = javaClass; - _extends = null; - _fields = null; - _identities = null; - _depends = null; - _accessMode = null; - - } - - public ClassMapping getMapping() { - return _map; } - public Class getJavaClass() - { + public Class getJavaClass() { return _javaClass; } - - - public FieldDescriptor[] getFields() - { - return _fields; + + public void setExtends(final ClassDescriptor extend) { + _extends = extend; } - - - public ClassDescriptor getExtends() - { + + public ClassDescriptor getExtends() { return _extends; } - public boolean isExtending() { - return (_extends != null); + public void addExtended(final ClassDescriptor classDesc) { + _extended.add(classDesc); } /** @@ -243,16 +118,12 @@ * * @return A collection of class descriptors. */ - public Collection getExtendedBy() { - return _extendedBy; - } - - public boolean isExtended() { - return (_extendedBy.size() > 0); + public Collection getExtended() { + return _extended; } - public void addExtendedBy(ClassDescriptor classDesc) { - _extendedBy.add(classDesc); + public void setDepends(final ClassDescriptor depends) { + _depends = depends; } public ClassDescriptor getDepends() { @@ -259,8 +130,16 @@ return _depends; } - public FieldDescriptor getIdentity() { - return _identities == null? null : _identities[0]; + public void setFields(final FieldDescriptor[] fields) { + _fields = fields; + } + + public FieldDescriptor[] getFields() { + return _fields; + } + + public void setIdentities(final FieldDescriptor[] identities) { + _identities = identities; } public FieldDescriptor[] getIdentities() { @@ -267,42 +146,20 @@ return _identities; } - - public AccessMode getAccessMode() - { - return _accessMode; + public FieldDescriptor getIdentity() { + return (_identities == null) ? null : _identities[0]; } - + + //----------------------------------------------------------------------------------- /** - * Checks the object validity. Returns successfully if the object - * can be stored, is valid, etc, throws an exception otherwise. - * - * @param object The object - * @throws ValidityException The object is invalid, a required is - * null, or any other validity violation - * @throws IllegalStateException The Java object has changed and - * is no longer supported by this handler, or the handler - * is not compatiable with the Java object + * {@inheritDoc} */ - public void checkValidity( Object object ) - throws ValidityException, IllegalStateException - { - // Object cannot be saved if one of the required fields is null - for ( int i = 0 ; i < _fields.length ; ++i ) { - if ( _fields[ i ].isRequired() && _fields[ i ].getHandler().getValue( object ) == null ) - throw new ValidityException( "mapping.requiredField", - object.getClass().getName(), _fields[ i ].getFieldName() ); - } - } - - - public String toString() - { + public String toString() { return _javaClass.getName(); } - + //----------------------------------------------------------------------------------- } Index: C:/Java/castor-4/src/main/java/org/exolab/castor/persist/ClassMolder.java =================================================================== --- C:/Java/castor-4/src/main/java/org/exolab/castor/persist/ClassMolder.java (revision 6773) +++ C:/Java/castor-4/src/main/java/org/exolab/castor/persist/ClassMolder.java (working copy) @@ -1458,7 +1458,7 @@ * @return The actual (OQL) statement */ public String getNamedQuery(String name) { - return ((JDOClassDescriptor) _clsDesc).getNamedQuery(name); + return (String) ((JDOClassDescriptor) _clsDesc).getNamedQueries().get(name); } } Index: C:/Java/castor-4/src/main/java/org/exolab/castor/tools/MappingToolMappingLoader.java =================================================================== --- C:/Java/castor-4/src/main/java/org/exolab/castor/tools/MappingToolMappingLoader.java (revision 6773) +++ C:/Java/castor-4/src/main/java/org/exolab/castor/tools/MappingToolMappingLoader.java (working copy) @@ -46,7 +46,6 @@ import java.lang.reflect.Array; -import org.castor.mapping.BindingType; import org.exolab.castor.mapping.loader.AbstractMappingLoader; import org.exolab.castor.xml.JavaNaming; @@ -53,7 +52,7 @@ /** * Extend mapping loader to give us access to the findAccessor method. */ -public final class MappingToolMappingLoader extends AbstractMappingLoader { +public final class MappingToolMappingLoader { private static final String GET = "get"; private static final String SET = "set"; private static final String ADD = "add"; @@ -58,10 +57,6 @@ private static final String SET = "set"; private static final String ADD = "add"; - MappingToolMappingLoader() { super(null); } - - public BindingType getBindingType() { return null; } - /** * Returns true if the get method returns an array. * This method is used for greater compatability with @@ -69,7 +64,7 @@ * * @return if get method returns an array. **/ - boolean returnsArray(final Class clazz, final String fieldName, final Class type) { + public static boolean returnsArray(final Class clazz, final String fieldName, final Class type) { try { Class array = null; if (type.isArray()) { @@ -81,7 +76,7 @@ String prefix = JavaNaming.toJavaClassName(fieldName); String method = GET + prefix; boolean isGet = true; - if (findAccessor(clazz, method, array, isGet) != null) { + if (AbstractMappingLoader.findAccessor(clazz, method, array, isGet) != null) { return true; } } catch(Exception ex) { @@ -90,7 +85,7 @@ return false; } - boolean canFindAccessors(final Class clazz, final String fieldName, final Class type) { + public static boolean canFindAccessors(final Class clazz, final String fieldName, final Class type) { try { //-- getMethod String prefix = JavaNaming.toJavaClassName(fieldName); @@ -96,7 +91,7 @@ String prefix = JavaNaming.toJavaClassName(fieldName); String method = GET + prefix; boolean isGet = true; - if (findAccessor(clazz, method, type, isGet) != null) { + if (AbstractMappingLoader.findAccessor(clazz, method, type, isGet) != null) { return true; } @@ -103,11 +98,11 @@ //-- setMethod and/or addMethod isGet = false; method = SET + prefix; - if (findAccessor(clazz, method, type, isGet) != null) { + if (AbstractMappingLoader.findAccessor(clazz, method, type, isGet) != null) { return true; } method = ADD + prefix; - if (findAccessor(clazz, method, type, isGet) != null) { + if (AbstractMappingLoader.findAccessor(clazz, method, type, isGet) != null) { return true; } } catch(Exception ex) { Index: C:/Java/castor-4/src/main/java/org/exolab/castor/xml/MarshalFramework.java =================================================================== --- C:/Java/castor-4/src/main/java/org/exolab/castor/xml/MarshalFramework.java (revision 6773) +++ C:/Java/castor-4/src/main/java/org/exolab/castor/xml/MarshalFramework.java (working copy) @@ -627,18 +627,5 @@ public FieldDescriptor getIdentity() { return _classDesc.getIdentity(); } //-- getIdentity - - - /** - * Returns the access mode specified for this class. - * - * @return The access mode - */ - public AccessMode getAccessMode() { - return _classDesc.getAccessMode(); - } //-- getAccessMode - } //-- InternalXMLClassDescriptor - - } //-- MarshalFramework Index: C:/Java/castor-4/src/main/java/org/exolab/castor/xml/XMLMappingLoader.java =================================================================== --- C:/Java/castor-4/src/main/java/org/exolab/castor/xml/XMLMappingLoader.java (revision 6773) +++ C:/Java/castor-4/src/main/java/org/exolab/castor/xml/XMLMappingLoader.java (working copy) @@ -50,7 +50,6 @@ package org.exolab.castor.xml; import org.castor.mapping.BindingType; -import org.castor.util.Messages; import org.exolab.castor.mapping.ClassDescriptor; import org.exolab.castor.mapping.FieldDescriptor; import org.exolab.castor.mapping.FieldHandler; @@ -58,6 +57,7 @@ import org.exolab.castor.mapping.MappingException; import org.exolab.castor.mapping.TypeConvertor; import org.exolab.castor.mapping.CollectionHandler; +import org.exolab.castor.mapping.loader.AbstractFieldDescriptor; import org.exolab.castor.mapping.loader.CollectionHandlers; import org.exolab.castor.mapping.loader.AbstractMappingLoader; import org.exolab.castor.mapping.loader.FieldHandlerImpl; @@ -62,6 +62,7 @@ import org.exolab.castor.mapping.loader.AbstractMappingLoader; import org.exolab.castor.mapping.loader.FieldHandlerImpl; import org.exolab.castor.mapping.loader.TypeInfo; +import org.exolab.castor.mapping.loader.Types; import org.exolab.castor.mapping.xml.ClassMapping; import org.exolab.castor.mapping.xml.FieldMapping; import org.exolab.castor.mapping.xml.BindXml; @@ -66,6 +67,7 @@ import org.exolab.castor.mapping.xml.FieldMapping; import org.exolab.castor.mapping.xml.BindXml; import org.exolab.castor.mapping.xml.MapTo; +import org.exolab.castor.mapping.xml.MappingRoot; import org.exolab.castor.mapping.xml.Property; import org.exolab.castor.mapping.xml.types.BindXmlAutoNamingType; import org.exolab.castor.mapping.xml.types.FieldMappingCollectionType; @@ -85,6 +87,8 @@ import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.List; /** * An XML implementation of mapping helper. Creates XML class @@ -95,52 +99,37 @@ * @version $Revision$ $Date: 2006-02-23 01:37:50 -0700 (Thu, 23 Feb 2006) $ */ public final class XMLMappingLoader extends AbstractMappingLoader { - /** - * The default xml prefix used on certain - * attributes such as xml:lang, xml:base, etc. - */ - private static final String XML_PREFIX = "xml:"; + //----------------------------------------------------------------------------------- - - /** - * Empty array of class types used for reflection - **/ + /** The default xml prefix used on certain attributes such as xml:lang, xml:base, + * etc. */ + private static final String XML_PREFIX = "xml:"; + + /** Empty array of class types used for reflection. */ private static final Class[] EMPTY_ARGS = new Class[0]; - /** - * The NCName Schema type - **/ + /** The NCName Schema type. */ private static final String NCNAME = "NCName"; - /** - * The string argument for the valueOf method, used - * for introspection. - **/ + /** The string argument for the valueOf method, used for introspection. */ private static final Class[] STRING_ARG = { String.class }; - /** - * Factory method name for type-safe enumerations. This - * is primarily for allowing users to map classes that - * were created by Castor's SourceGenerator. - **/ + /** Factory method name for type-safe enumerations. This is primarily for allowing + * users to map classes that were created by Castor's SourceGenerator. */ private static final String VALUE_OF = "valueOf"; + //----------------------------------------------------------------------------------- - /** - * A reference to the internal ClassDescriptorResolver - */ + /** A reference to the internal ClassDescriptorResolver. */ private XMLClassDescriptorResolverImpl _cdResolver; - /** - * naming conventions - */ - private XMLNaming _naming = null; + /** The default NodeType for primitives. */ + private NodeType _primitiveNodeType = null; - /** - * The default NodeType for primitives - */ - private NodeType _primitiveNodeType = null; + /** Naming conventions. */ + private XMLNaming _naming = null; + //----------------------------------------------------------------------------------- /** * Creates a new XMLMappingLoader @@ -149,59 +138,31 @@ super(loader); LocalConfiguration config = LocalConfiguration.getInstance(); - _primitiveNodeType = config.getPrimitiveNodeType(); - _naming = config.getXMLNaming(); - - } //-- XMLMappingLoader - - - - public BindingType getBindingType() { return BindingType.XML; } - - private void createResolver() { - _cdResolver = (XMLClassDescriptorResolverImpl) - ClassDescriptorResolverFactory.createClassDescriptorResolver(BindingType.XML); - _cdResolver.setIntrospection(false); - _cdResolver.setLoadPackageMappings(false); + _naming = config.getXMLNaming(); } - protected void resolveRelations(ClassDescriptor clsDesc) { - FieldDescriptor[] fields; + //----------------------------------------------------------------------------------- - fields = clsDesc.getFields(); - for ( int i = 0 ; i < fields.length ; ++i ) { - if (fields[i].getClassDescriptor() != null) continue; - ClassDescriptor relDesc; + /** + * {@inheritDoc} + */ + public BindingType getBindingType() { return BindingType.XML; } - Class fieldType = fields[i].getFieldType(); - if (fieldType != null) { - relDesc = getDescriptor(fieldType.getName()); - if ( relDesc == NO_DESCRIPTOR ) { - // XXX Error message should come here - } - else if ( relDesc != null && - relDesc instanceof XMLClassDescriptor && - fields[ i ] instanceof XMLFieldDescriptorImpl ) - { - ( (XMLFieldDescriptorImpl) fields[ i ] ).setClassDescriptor( (XMLClassDescriptor) relDesc ); + //----------------------------------------------------------------------------------- - //-- removed kvisco 20010814 - // ( (XMLFieldDescriptorImpl) fields[ i ] ).setNodeType( NodeType.Element ); - } - } - } - if ( clsDesc instanceof XMLClassDescriptorImpl ) - ( (XMLClassDescriptorImpl) clsDesc ).sortDescriptors(); + /** + * {@inheritDoc} + */ + public void loadMapping(final MappingRoot mapping, final Object param) + throws MappingException { + if (loadMapping()) { createClassDescriptors(mapping); } } - - protected ClassDescriptor createDescriptor( ClassMapping clsMap ) - throws MappingException - { - ClassDescriptor clsDesc; - String xmlName; - + //----------------------------------------------------------------------------------- + + protected final ClassDescriptor createClassDescriptor(final ClassMapping clsMap) + throws MappingException { if (clsMap.getAutoComplete()) { if ((clsMap.getMapTo() == null) && ((clsMap.getClassChoice() == null) || @@ -208,55 +169,124 @@ (clsMap.getClassChoice().getFieldMappingCount() == 0)) && (clsMap.getIdentityCount() == 0)) { - //-- if we make it here we simply try - //-- to load a compiled mapping - if (_cdResolver == null) { - createResolver(); - } + // If we make it here we simply try to load a compiled mapping + if (_cdResolver == null) { createResolver(); } try { - clsDesc = _cdResolver.resolve(clsMap.getName()); - if (clsDesc != null) - return clsDesc; + ClassDescriptor clsDesc = _cdResolver.resolve(clsMap.getName()); + if (clsDesc != null) { return clsDesc; } + } catch(ResolverException rx) { + } - catch(ResolverException rx) {} - + } + } + + // Create the class descriptor. + XMLClassDescriptorAdapter xmlClassDesc = new XMLClassDescriptorAdapter(); + + // Obtain the Java class. + Class javaClass = resolveType(clsMap.getName()); + if (clsMap.getVerifyConstructable()) { + if (!Types.isConstructable(javaClass, true)) { + throw new MappingException( + "mapping.classNotConstructable", javaClass.getName()); } } + xmlClassDesc.setJavaClass(javaClass); - // Use super class to create class descriptor. Field descriptors will be - // generated only for supported fields, see createFieldDesc later on. - clsDesc = super.createDescriptor( clsMap ); + // Obtain XML name. + String xmlName; MapTo mapTo = clsMap.getMapTo(); - if (( mapTo == null) || (mapTo.getXml() == null)) { - String clsName = clsDesc.getJavaClass().getName(); + if ((mapTo != null) && (mapTo.getXml() != null)) { + xmlName = mapTo.getXml(); + } else { + String clsName = javaClass.getName(); int idx = clsName.lastIndexOf('.'); - if (idx >= 0) { - clsName = clsName.substring(idx+1); - } - xmlName = _naming.toXMLName( clsName ); + if (idx >= 0) { clsName = clsName.substring(idx + 1); } + xmlName = _naming.toXMLName(clsName); } - else { - xmlName = clsMap.getMapTo().getXml(); + xmlClassDesc.setXMLName(xmlName); - } + // If this class extends another class, we need to obtain the extended + // class and make sure this class indeed extends it. + ClassDescriptor extDesc = getExtended(clsMap, javaClass); + xmlClassDesc.setExtends((XMLClassDescriptor) extDesc); + + // Create all field descriptors. + AbstractFieldDescriptor[] allFields = createFieldDescriptors(clsMap, javaClass); - XMLClassDescriptorImpl xmlClassDesc - = new XMLClassDescriptorAdapter( clsDesc, xmlName, _primitiveNodeType ); - + // Make sure there are no two fields with the same name. + checkFieldNameDuplicates(allFields, javaClass); + + // Identify identity and normal fields. Note that order must be preserved. + List fieldList = new ArrayList(allFields.length); + List idList = new ArrayList(); + if (extDesc == null) { + // Sort fields into 2 lists based on identity definition of field. + for (int i = 0; i < allFields.length; i++) { + if (!allFields[i].isIdentity()) { + fieldList.add(allFields[i]); + } else { + idList.add(allFields[i]); + } + } + + if (idList.size() == 0) { + // Found no identities based on identity definition of field. + // Try to find identities based on identity definition on class. + String[] idNames = clsMap.getIdentity(); + + FieldDescriptor identity; + for (int i = 0; i < idNames.length; i++) { + identity = findIdentityByName(fieldList, idNames[i], javaClass); + if (identity != null) { + idList.add(identity); + } else { + throw new MappingException("mapping.identityMissing", + idNames[i], javaClass.getName()); + } + } + } + } else { + // Add all fields of extending class to field list. + for (int i = 0; i < allFields.length; i++) { fieldList.add(allFields[i]); } + + // Add identity of extended class to identity list. + if (extDesc.getIdentity() != null) { idList.add(extDesc.getIdentity()); } + + // Search redefined identities in extending class. + FieldDescriptor identity; + for (int i = 0; i < idList.size(); i++) { + String idname = ((FieldDescriptor) idList.get(i)).getFieldName(); + identity = findIdentityByName(fieldList, idname, javaClass); + if (identity != null) { idList.set(i, identity); } + } + } + + FieldDescriptor xmlId = null; + if (idList.size() != 0) { xmlId = (FieldDescriptor) idList.get(0); } + + for (int i = 0; i < allFields.length; i++) { + FieldDescriptor fieldDesc = allFields[i]; + if (fieldDesc != null) { + if (fieldDesc == xmlId) { + xmlClassDesc.setIdentity((XMLFieldDescriptorImpl) fieldDesc); + } else { + xmlClassDesc.addFieldDescriptor((XMLFieldDescriptorImpl) fieldDesc); + } + } + } + if (clsMap.getAutoComplete()) { XMLClassDescriptor referenceDesc = null; - + Class type = xmlClassDesc.getJavaClass(); - - //-- check compiled descriptors - if (_cdResolver == null) { - createResolver(); - } + + //-- check compiled descriptors + if (_cdResolver == null) { createResolver(); } try { referenceDesc = _cdResolver.resolveXML(type); - } - catch(ResolverException rx) { + } catch (ResolverException rx) { throw new MappingException(rx); } @@ -281,8 +311,8 @@ if (clsMap.getIdentityCount() > 0) identity = clsMap.getIdentity(0); - - FieldDescriptor[] fields = xmlClassDesc.getFields(); + + FieldDescriptor[] xmlFields2 = xmlClassDesc.getFields(); // Attributes XMLFieldDescriptor[] introFields = referenceDesc.getAttributeDescriptors(); @@ -287,7 +317,7 @@ // Attributes XMLFieldDescriptor[] introFields = referenceDesc.getAttributeDescriptors(); for (int i = 0; ifieldName is in fields */ @@ -345,7 +417,7 @@ } //-- method: isMatchFieldName - protected FieldDescriptor createFieldDesc( Class javaClass, FieldMapping fieldMap ) + protected AbstractFieldDescriptor createFieldDesc( Class javaClass, FieldMapping fieldMap ) throws MappingException { @@ -490,8 +562,8 @@ //-- has class descriptor for type specified if (xml.getClassMapping() != null) { - ClassDescriptor cd = createDescriptor(xml.getClassMapping()); - xmlDesc.setClassDescriptor((XMLClassDescriptor)cd); + ClassDescriptor cd = createClassDescriptor(xml.getClassMapping()); + xmlDesc.setClassDescriptor(cd); } //-- has location path? Index: C:/Java/castor-4/src/main/java/org/exolab/castor/xml/util/XMLClassDescriptorAdapter.java =================================================================== --- C:/Java/castor-4/src/main/java/org/exolab/castor/xml/util/XMLClassDescriptorAdapter.java (revision 6773) +++ C:/Java/castor-4/src/main/java/org/exolab/castor/xml/util/XMLClassDescriptorAdapter.java (working copy) @@ -46,6 +46,7 @@ import org.exolab.castor.mapping.ClassDescriptor; import org.exolab.castor.mapping.FieldDescriptor; +import org.exolab.castor.mapping.MappingException; import org.exolab.castor.mapping.loader.ClassDescriptorImpl; import org.exolab.castor.util.LocalConfiguration; import org.exolab.castor.xml.NodeType; @@ -61,6 +62,9 @@ * @version $Revision$ $Date: 2005-12-13 14:58:48 -0700 (Tue, 13 Dec 2005) $ */ public class XMLClassDescriptorAdapter extends XMLClassDescriptorImpl { + public XMLClassDescriptorAdapter() { + super(); + } /** * Creates a new XMLClassDescriptorAdapter using the given ClassDescriptor. @@ -82,7 +86,7 @@ */ public XMLClassDescriptorAdapter(final ClassDescriptor classDesc, String xmlName, NodeType primitiveNodeType) - throws org.exolab.castor.mapping.MappingException { + throws MappingException { super(); if (classDesc == null) { @@ -104,7 +108,7 @@ if (xmlName == null) { if (classDesc instanceof XMLClassDescriptor) { - xmlName = ((XMLClassDescriptor)classDesc).getXMLName(); + xmlName = ((XMLClassDescriptor) classDesc).getXMLName(); } else { XMLNaming naming = XMLNaming.getInstance(); String name = classDesc.getJavaClass().getName(); @@ -111,7 +115,7 @@ //-- strip package int idx = name.lastIndexOf('.'); if (idx >= 0) { - name = name.substring(idx+1); + name = name.substring(idx + 1); } xmlName = naming.toXMLName(name); } @@ -117,7 +121,7 @@ } } setXMLName(xmlName); - } //-- XMLClassDescriptorAdapter + } /** * Copies the fieldDescriptors of the given XMLClassDesctiptor into this @@ -125,9 +129,8 @@ * * @param classDesc the XMLClassDescriptor to process */ - private void process(final ClassDescriptor classDesc, final NodeType primitiveNodeType) - throws org.exolab.castor.mapping.MappingException { - + private void process(ClassDescriptor classDesc, NodeType primitiveNodeType) + throws MappingException { if (classDesc instanceof XMLClassDescriptor) { //-- hopefully this won't happen, but we can't prevent it. process((XMLClassDescriptor)classDesc); @@ -223,7 +226,7 @@ primitiveNodeType)); } } - } //-- process + } /** * Copies the fieldDescriptors of the given XMLClassDesctiptor into this @@ -231,8 +234,7 @@ * * @param classDesc the XMLClassDescriptor to process */ - private void process(final XMLClassDescriptor classDesc) - throws org.exolab.castor.mapping.MappingException { + private void process(XMLClassDescriptor classDesc) { FieldDescriptor identity = classDesc.getIdentity(); FieldDescriptor[] fields = classDesc.getFields(); for (int i = 0; i < fields.length; i++) { @@ -249,7 +251,6 @@ setIdentity((XMLFieldDescriptor)identity); } setXMLName(classDesc.getXMLName()); - setExtendsWithoutFlatten((XMLClassDescriptor)classDesc.getExtends()); - } //-- process - -} //-- XMLClassDescriptorAdapter + setExtendsWithoutFlatten((XMLClassDescriptor) classDesc.getExtends()); + } +} Index: C:/Java/castor-4/src/main/java/org/exolab/castor/xml/util/XMLClassDescriptorImpl.java =================================================================== --- C:/Java/castor-4/src/main/java/org/exolab/castor/xml/util/XMLClassDescriptorImpl.java (revision 6773) +++ C:/Java/castor-4/src/main/java/org/exolab/castor/xml/util/XMLClassDescriptorImpl.java (working copy) @@ -1205,7 +1205,7 @@ * * @param type the Class type being described */ - protected void setJavaClass(Class type) { + public void setJavaClass(Class type) { this._class = type; } //-- setJavaClass