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 6342) +++ C:/Java/castor-4/src/main/java/org/exolab/castor/jdo/engine/JDOClassDescriptor.java (working copy) @@ -44,7 +44,6 @@ */ package org.exolab.castor.jdo.engine; -import java.util.HashMap; import java.util.Map; import java.util.Properties; @@ -52,34 +51,34 @@ 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.FieldDescriptor; import org.exolab.castor.mapping.MappingException; import org.exolab.castor.mapping.loader.ClassDescriptorImpl; import org.exolab.castor.mapping.xml.CacheTypeMapping; +import org.exolab.castor.mapping.xml.ClassMapping; 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; - /** 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 final AccessMode _accessMode; /** The properties defining cache type and parameters. */ private final Properties _cacheParams = new Properties(); @@ -84,15 +83,19 @@ /** 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(); + /** The key generator specified for this class. */ + private KeyGeneratorDescriptor _keyGenDesc; + + /** Associated named queries, keyed by their name. */ + private Map _namedQueries; - public JDOClassDescriptor(final ClassDescriptor clsDesc, - final KeyGeneratorDescriptor keyGenDesc) + //----------------------------------------------------------------------------------- + + public JDOClassDescriptor(final ClassMapping clsMap, final Class javaClass, + final FieldDescriptor[] fields, final FieldDescriptor[] identities, + final ClassDescriptor extend) throws MappingException { - super((ClassDescriptorImpl) clsDesc); + super(clsMap, javaClass, fields, identities, extend); _tableName = getMapping().getMapTo().getTable(); if (_tableName == null) { @@ -107,6 +110,13 @@ throw new IllegalArgumentException("Identity field must be of type JDOFieldDescriptor"); } + for (int i = 0; i < getIdentities().length; i++) { + String[] sqlNames = ((JDOFieldDescriptor) getIdentities()[i]).getSQLName(); + if (sqlNames == null) { + throw new MappingException("mapping.noSqlName", getIdentities()[i].getFieldName(), getJavaClass().getName()); + } + } + if ((getExtends() != null) && !(getExtends() instanceof JDOClassDescriptor)) { throw new IllegalArgumentException( "Extended class does not have a JDO descriptor" ); } @@ -111,17 +121,6 @@ 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; - CacheTypeMapping cacheMapping = getMapping().getCacheTypeMapping(); if (cacheMapping != null) { String capacity = Integer.toString(cacheMapping.getCapacity()); @@ -145,7 +144,15 @@ } _cacheParams.put(Cache.PARAM_NAME, getMapping().getName()); + + if (getMapping().getAccess() == null) { + _accessMode = AccessMode.Shared; + } else { + _accessMode = AccessMode.valueOf(getMapping().getAccess().toString()); + } } + + //----------------------------------------------------------------------------------- /** * Returns the table name to which this object maps. @@ -155,6 +162,10 @@ public String getTableName() { return _tableName; } + + public AccessMode getAccessMode() { + return _accessMode; + } public Properties getCacheParams() { return _cacheParams; @@ -161,40 +172,18 @@ } /** - * 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. + * Set key generator specified for this class. + * + * @param keyGenDesc Key generator descriptor. */ - 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))) { - - field = (JDOFieldDescriptor) _fields[i]; - break; - } - } - - 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]; - } - } - } - - return field; + protected void setKeyGeneratorDescriptor(final KeyGeneratorDescriptor keyGenDesc) { + _keyGenDesc = keyGenDesc; } /** - * Returns the key generator specified for this class. + * Get key generator specified for this class. * - * @return The key generator descriptor + * @return Key generator descriptor. */ public KeyGeneratorDescriptor getKeyGeneratorDescriptor() { return _keyGenDesc; @@ -199,38 +188,66 @@ public KeyGeneratorDescriptor getKeyGeneratorDescriptor() { return _keyGenDesc; } - + /** - * @return The names of columns that the identity consists of. + * Set map of named query strings associated with their names. + * + * @param namedQueries Map of named query strings associated with their names. */ - public String[] getIdentityColumnNames() { - return _idnames; - } - - public String toString() { - return super.toString() + " AS " + _tableName; + protected void setNamedQueries(final Map namedQueries) { + _namedQueries = namedQueries; } /** - * 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 + * Get map of named query strings associated with their names. + * + * @return Map of named query strings associated with their names. */ - public String getNamedQuery(String name) { - String namedQuery = (String) _namedQueries.get(name); - return namedQuery; + public Map getNamedQueries() { + return _namedQueries; } + //----------------------------------------------------------------------------------- + /** - * 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 + * Returns a JDOFieldDescriptor for the field with the name passed. null + * if named field does not exist. + * + * @param name Name of the field to return. + * @return Field if it exists, otherwise null. */ - public void addNamedQuery(final String name, final String namedQuery) throws QueryException { - if (_namedQueries.containsKey(name)) { - throw new QueryException ("Duplicate entry for named query " + name); + public JDOFieldDescriptor getField(String name) { + FieldDescriptor[] fields = getFields(); + for (int i = 0 ; i < fields.length ; ++i) { + FieldDescriptor field = fields[i]; + if ((field instanceof JDOFieldDescriptor) + && (field.getFieldName().equals(name))) { + + return (JDOFieldDescriptor) field; + } } - _namedQueries.put(name, namedQuery); + + 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 null; + } + + //----------------------------------------------------------------------------------- + + /** + * {@inheritDoc} + */ + public String toString() { + return super.toString() + " AS " + _tableName; } + + //----------------------------------------------------------------------------------- } 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 6342) +++ C:/Java/castor-4/src/main/java/org/exolab/castor/jdo/engine/JDOMappingLoader.java (working copy) @@ -49,8 +49,8 @@ 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.mapping.*; +import org.exolab.castor.mapping.loader.ClassDescriptorImpl; import org.exolab.castor.mapping.loader.CollectionHandlers; import org.exolab.castor.mapping.loader.FieldHandlerFriend; import org.exolab.castor.mapping.loader.FieldHandlerImpl; @@ -65,8 +65,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 +76,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 { @@ -84,6 +89,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,59 +122,68 @@ //----------------------------------------------------------------------------------- + /** Used by the constructor for creating key generators. */ + private Map _keyGenDefs; + /** Used by the constructor for creating key generators. */ + private Map _keyGenDescs; - /** - * Used by the constructor for creating key generators. - * See {@link #loadMapping}. - */ - private Hashtable _keyGenDefs = new Hashtable(); + /** 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 KeyGeneratorRegistry _keyGenReg; + /** An association map between class name and a list of query definitions of this + * class. */ + private Map _namedQueryDefs; - /** - * Used by the constructor for creating key generators. - * See {@link #loadMapping}. - */ - private Hashtable _keyGenDescs = new Hashtable(); - - /** - * Used to locally register all loaded queries - * to detect duplicated query names. - * See {@link #createDescriptor(ClassMapping)}. - */ - private Hashtable _namedQueries = new Hashtable(); + /** The JDO PersistenceFactory (aka BaseFactory) is used for adjusting SQL type for + * the given database. */ + private BaseFactory _factory; + + //----------------------------------------------------------------------------------- + public JDOMappingLoader(ClassLoader loader) { + super(loader); + } + + //----------------------------------------------------------------------------------- /** - * The JDO PersistenceFactory (aka BaseFactory) is used for adjusting - * SQL type for the given database. + * {@inheritDoc} */ - private BaseFactory _factory; - + public BindingType getBindingType() { return BindingType.JDO; } + /** - * 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}. + * {@inheritDoc} */ - private KeyGeneratorRegistry _keyGenReg = new KeyGeneratorRegistry(); + public void loadMapping(final MappingRoot mapping, final Object param) + throws MappingException { + if (loadMapping()) { + _factory = (BaseFactory) param; + + loadKeyGenDefinitions(mapping); + loadNamedQueryDefinitions(mapping); + + loadClassMapping(mapping); + + cleanupNamedQueryDefinitions(); + cleanupKeyGenDefinitions(); + } + } + - public JDOMappingLoader(ClassLoader loader) { - super(loader); - } - - public BindingType getBindingType() { return BindingType.JDO; } + + + /** + * {@inheritDoc} + */ protected ClassDescriptor createDescriptor(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. JDO only supports + // JDO class descriptors. if ((clsMap.getMapTo() == null) || (clsMap.getMapTo().getTable() == null)) { return AbstractMappingLoader.NO_DESCRIPTOR; } @@ -172,76 +188,121 @@ return AbstractMappingLoader.NO_DESCRIPTOR; } - // See if we have a compiled descriptor. - clsDesc = null; - if ((clsDesc != null) && (clsDesc instanceof JDOClassDescriptor)) { - return clsDesc; + // Obtain the Java class. + Class javaClass; + try { + javaClass = resolveType(clsMap.getName()); + } catch (ClassNotFoundException ex) { + throw new MappingException("mapping.classNotFound", clsMap.getName()); } - // 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); + // 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()); - // 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()); - } + // If this class depends another class, need to obtain the depended class + ClassDescriptor depend = getDepended(clsMap, javaClass.getName()); + + FieldDescriptor[] identities = null; + + // 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)) { + // 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()); + } - // create a key generator descriptor - keyGenName = clsMap.getKeyGenerator(); - keyGenDesc = null; - if (keyGenName != null) { - String keyGenFactoryName; - KeyGeneratorDef keyGenDef; - Enumeration enumeration; - Properties params; + // Divide fields into identity fields and regular fields + identities = new FieldDescriptor[ids.length]; + fields = divideFieldDescriptors(fields, ids, identities); - // 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()); + 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]; + } + } } } - keyGenDesc = (KeyGeneratorDescriptor) _keyGenDescs.get(keyGenName); - if (keyGenDesc == null) { - keyGenDesc = new KeyGeneratorDescriptor(keyGenName, - keyGenFactoryName, params, _keyGenReg); - _keyGenDescs.put(keyGenName, keyGenDesc); + + // 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()); + } } } - JDOClassDescriptor classDescriptor = new JDOClassDescriptor(clsDesc, keyGenDesc); + if (!Types.isConstructable(javaClass, true)) { + throw new MappingException("mapping.classNotConstructable", javaClass.getName()); + } - // 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()); - } - classDescriptor.addNamedQuery(namedQuery.getName(), namedQuery.getQuery()); - _namedQueries.put(namedQuery.getName(), namedQuery); - } catch (QueryException e) { - throw new MappingException(e); - } + // 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 ((identities == null) || (identities[0] == null)) { + throw new MappingException("mapping.noIdentity", javaClass.getName()); } + + // Create the class descriptor. + JDOClassDescriptor clsDesc = new JDOClassDescriptor( + clsMap, javaClass, fields, identities, extend); - return classDescriptor; + clsDesc.setDepends(depend); + + String keyGenName = clsMap.getKeyGenerator(); + clsDesc.setKeyGeneratorDescriptor(createKeyGenDescriptor(keyGenName)); + clsDesc.setNamedQueries(createNamedQueryDescriptors(clsMap.getName())); + + return clsDesc; } + + + + + + + + + /** * Parse the sql type attribute to build an * array of types, needed to support whitespace inside @@ -531,31 +592,122 @@ return jdoFieldDescriptor; } - protected void loadMappingInternal(final MappingRoot mapping, final Object param) + //----------------------------------------------------------------------------------- + + /** + * Load the key generator definitions and check for duplicate names. + * + * @param mapping + * @throws MappingException + */ + private void loadKeyGenDefinitions(final MappingRoot mapping) 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; + _keyGenDefs = new HashMap(); + + Enumeration enumeration = mapping.enumerateKeyGeneratorDef(); + while (enumeration.hasMoreElements()) { + KeyGeneratorDef keyGenDef = (KeyGeneratorDef) enumeration.nextElement(); + String 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); + } - keyGenDef = (KeyGeneratorDef) enumeration.nextElement(); - name = keyGenDef.getAlias(); - if (name == null) { - name = keyGenDef.getName(); + _keyGenDescs = new HashMap(); + _keyGenReg = new KeyGeneratorRegistry(); + } + + private KeyGeneratorDescriptor createKeyGenDescriptor(final String keyGenName) { + if (keyGenName == null) { return null; } + + String keyGenFactoryName = keyGenName; + Properties params = new Properties(); + + // First search among declared key generators and resolve alias + KeyGeneratorDef keyGenDef = (KeyGeneratorDef) _keyGenDefs.get(keyGenName); + if (keyGenDef != null) { + keyGenFactoryName = keyGenDef.getName(); + Enumeration enumeration = keyGenDef.enumerateParam(); + while (enumeration.hasMoreElements()) { + Param par = (Param) enumeration.nextElement(); + params.put(par.getName(), par.getValue()); } - if ( _keyGenDefs.get( name ) != null ) { - throw new MappingException( Messages.format( "mapping.dupKeyGen", name ) ); + } + + Object keyGenDesc = _keyGenDescs.get(keyGenName); + if (keyGenDesc == null) { + keyGenDesc = new KeyGeneratorDescriptor( + keyGenName, keyGenFactoryName, params, _keyGenReg); + _keyGenDescs.put(keyGenName, keyGenDesc); + } + return (KeyGeneratorDescriptor) keyGenDesc; + } + + private void cleanupKeyGenDefinitions() { + if (_keyGenReg != null) { _keyGenReg.clear(); } + _keyGenReg = null; + if (_keyGenDescs != null) { _keyGenDescs.clear(); } + _keyGenDescs = null; + if (_keyGenDefs != null) { _keyGenDefs.clear(); } + _keyGenDefs = null; + } + + //----------------------------------------------------------------------------------- + + private void loadNamedQueryDefinitions(final MappingRoot mapping) + throws MappingException { + _namedQueryDefs = new HashMap(); + + Set queryNames = new HashSet(); + + Enumeration enumeration = mapping.enumerateClassMapping(); + while (enumeration.hasMoreElements()) { + ClassMapping clsMap = (ClassMapping) enumeration.nextElement(); + + List definitions = new ArrayList(); + + Enumeration namedQueriesEnum = clsMap.enumerateNamedQuery(); + while (namedQueriesEnum.hasMoreElements()) { + NamedQuery namedQuery = (NamedQuery) namedQueriesEnum.nextElement(); + String queryName = namedQuery.getName(); + if (queryNames.contains(queryName)) { + String msg = "Duplicate entry for named query with name " + queryName; + throw new MappingException(msg); + } + queryNames.add(queryName); + + definitions.add(namedQuery); } - _keyGenDefs.put( name, keyGenDef ); + + _namedQueryDefs.put(clsMap.getName(), definitions); } + + queryNames.clear(); + } - super.loadMappingInternal(mapping, null); - - _keyGenDefs = null; - _keyGenDescs = null; - _keyGenReg = null; + /** + * Extract named queries and add them to JDO class descriptor. + * + * @param className + */ + private Map createNamedQueryDescriptors(final String className) { + Map namedQueries = new HashMap(); + + List definitions = (List) _namedQueryDefs.get(className); + for (int i = 0; i < definitions.size(); i++) { + NamedQuery def = (NamedQuery) definitions.get(i); + namedQueries.put(def.getName(), def.getQuery()); + } + + return namedQueries; + } + + private void cleanupNamedQueryDefinitions() { + if (_namedQueryDefs != null) { _namedQueryDefs.clear(); } + _namedQueryDefs = null; } + + //----------------------------------------------------------------------------------- } Index: C:/Java/castor-4/src/main/java/org/exolab/castor/jdo/engine/KeyGeneratorRegistry.java =================================================================== --- C:/Java/castor-4/src/main/java/org/exolab/castor/jdo/engine/KeyGeneratorRegistry.java (revision 6342) +++ C:/Java/castor-4/src/main/java/org/exolab/castor/jdo/engine/KeyGeneratorRegistry.java (working copy) @@ -128,4 +128,6 @@ } return keyGen; } + + public void clear() { _keyGens.clear(); } } 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 6342) +++ 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; /** @@ -140,9 +141,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 6342) +++ 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 6342) +++ 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 6342) +++ 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 6342) +++ 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/AbstractMappingLoader.java =================================================================== --- C:/Java/castor-4/src/main/java/org/exolab/castor/mapping/loader/AbstractMappingLoader.java (revision 6342) +++ C:/Java/castor-4/src/main/java/org/exolab/castor/mapping/loader/AbstractMappingLoader.java (working copy) @@ -86,6 +86,8 @@ * @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); @@ -129,6 +131,8 @@ 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 +142,8 @@ super(loader); } + //-------------------------------------------------------------------------- + /** * {@inheritDoc} */ @@ -146,20 +152,16 @@ } /** - * 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 void loadClassMapping(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 +170,8 @@ List retryList = new ArrayList(); while (enumeration.hasMoreElements()) { ClassMapping clsMap = (ClassMapping) enumeration.nextElement(); - ClassDescriptor clsDesc = null; - try { - clsDesc = createDescriptor(clsMap); + createClassDescriptor(clsMap); } catch (MappingException mx) { // save for later for possible out-of-order mapping files... retryList.add(clsMap); @@ -177,14 +177,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,17 +183,11 @@ // 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())); - } + createClassDescriptor(clsMap); } - for (Iterator i = this.descriptorIterator(); i.hasNext();) { + // iterate over all class descriptors and resolve relations between them + for (Iterator i = descriptorIterator(); i.hasNext();) { ClassDescriptor clsDesc = (ClassDescriptor) i.next(); if (clsDesc != NO_DESCRIPTOR) { resolveRelations(clsDesc); } } @@ -206,18 +192,18 @@ if (clsDesc != NO_DESCRIPTOR) { resolveRelations(clsDesc); } } } - - 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 ); - } + + //-------------------------------------------------------------------------- + + private void createClassDescriptor(final ClassMapping clsMap) + throws MappingException { + 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())); } } @@ -230,93 +216,38 @@ * @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()); - } + protected abstract ClassDescriptor createDescriptor(final ClassMapping clsMap) + throws MappingException; + + + + + + + + /** + * 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 ClassNotFoundException { + return Types.typeFromName(getClassLoader(), typeName); + } - // 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]); + 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 ); } - 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); } /** @@ -330,7 +261,7 @@ * @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 String clsName) throws MappingException { if (clsMap.getExtends() == null) { return null; } @@ -364,7 +295,7 @@ * @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 String clsName) throws MappingException { if (clsMap.getDepends() == null) { return null; } @@ -395,7 +326,7 @@ * @throws MappingException An exception indicating why mapping for the class cannot * be created. */ - private FieldDescriptor[] createFieldDescriptors(final ClassMapping clsMap, + protected final FieldDescriptor[] createFieldDescriptors(final ClassMapping clsMap, final Class javaClass) throws MappingException { FieldMapping[] fldMap = null; @@ -424,7 +355,7 @@ * the exception). * @throws MappingException If at least two fields have the same name. */ - private void checkFieldNames(final FieldDescriptor[] fields, final String clsName) + protected final void checkFieldNames(final FieldDescriptor[] fields, final String clsName) throws MappingException { for (int i = 0; i < fields.length - 1; i++) { String fieldName = fields[i].getFieldName(); @@ -446,7 +377,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 +387,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); @@ -1059,7 +990,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 6342) +++ 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 6342) +++ C:/Java/castor-4/src/main/java/org/exolab/castor/mapping/loader/ClassDescriptorImpl.java (working copy) @@ -42,109 +42,115 @@ * * $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; - - - /** - * The descriptor of the class which this class extends, - * or null if this is a top-level class. - */ - private final ClassDescriptor _extends; + private final ClassMapping _map; - /** - * 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(); + /** The Java class for this descriptor. */ + private final Class _javaClass; - private final ClassDescriptor _depends; + /** The fields described for this class. */ + private final FieldDescriptor[] _fields; - /** - * The field of the identity for this class. - */ - protected final FieldDescriptor[] _identities; + /** The field of the identity for this class. */ + private final FieldDescriptor[] _identities; + /** The descriptor of the class which this class extends, + * or null if this is a top-level class. */ + private final ClassDescriptor _extends; + + /** 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(); - /** - * The access mode specified for this class. - */ - private AccessMode _accessMode; + private ClassDescriptor _depends; + //----------------------------------------------------------------------------------- - /** - * 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 ClassDescriptorImpl(final ClassMapping map, final Class javaClass, + public ClassDescriptorImpl(final ClassMapping clsMap, 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()); + _map = clsMap; + _javaClass = javaClass; + + if (fields == null) { + throw new IllegalArgumentException("Argument 'fields' is null"); + } + _fields = (FieldDescriptor[]) fields.clone(); + + _depends = depend; - if (map.getAccess() == null) { - _accessMode = AccessMode.Shared; + 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).addExtended(this); + } + + if (identities == null) { + if (_extends instanceof ClassDescriptorImpl) { + _identities = ((ClassDescriptorImpl) _extends).getIdentities(); + } else if (_extends.getIdentity() == null) { + _identities = null; + } else { + _identities = new FieldDescriptor[] {_extends.getIdentity()}; + } + } else { + _identities = identities; + } } else { - _accessMode = AccessMode.valueOf(map.getAccess().toString()); + _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); } } - - private ClassDescriptorImpl(final ClassMapping clsMap, final Class javaClass, + + public ClassDescriptorImpl(final ClassMapping clsMap, final Class javaClass, final FieldDescriptor[] fields, final FieldDescriptor[] identities, - final ClassDescriptor extend, final ClassDescriptor depend, - final boolean verifyConstructable) + final ClassDescriptor extend) throws MappingException { - if (verifyConstructable && (!Types.isConstructable(javaClass, true))) { - throw new MappingException("mapping.classNotConstructable", javaClass.getName()); - } - _map = clsMap; _javaClass = javaClass; @@ -153,8 +159,6 @@ } _fields = (FieldDescriptor[]) fields.clone(); - _depends = depend; - if (extend != null) { if (!extend.getJavaClass().isAssignableFrom(javaClass)) { throw new MappingException("mapping.classDoesNotExtend", @@ -163,17 +167,20 @@ _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); + this.getClass().getName().equals("org.exolab.castor.jdo.engine.JDOClassDescriptor")) { + ((ClassDescriptorImpl) _extends).addExtended(this); } - if (_extends instanceof ClassDescriptorImpl) { - _identities = ( identities == null ? ((ClassDescriptorImpl)_extends).getIdentities() : identities ); + if (identities == null) { + if (_extends instanceof ClassDescriptorImpl) { + _identities = ((ClassDescriptorImpl) _extends).getIdentities(); + } else if (_extends.getIdentity() == null) { + _identities = null; + } else { + _identities = new FieldDescriptor[] {_extends.getIdentity()}; + } } else { - // a quick hack to fix a ClassCastException :-( - _identities = ( identities == null ? - (_extends.getIdentity() == null? null : new FieldDescriptor[] { _extends.getIdentity() } ) - : identities ); + _identities = identities; } } else { _extends = null; @@ -200,7 +207,7 @@ } /** - * Constructor used by derived classes. + * Constructor used for AbstractMappingLoader.NO_DESCRIPTOR only. */ protected ClassDescriptorImpl(final Class javaClass) { _map = null; @@ -208,10 +215,9 @@ _extends = null; _fields = null; _identities = null; - _depends = null; - _accessMode = null; + } - } + //----------------------------------------------------------------------------------- public ClassMapping getMapping() { return _map; @@ -217,25 +223,24 @@ return _map; } - public Class getJavaClass() - { + public Class getJavaClass() { return _javaClass; } - - public FieldDescriptor[] getFields() - { + public FieldDescriptor[] getFields() { return _fields; } + public FieldDescriptor[] getIdentities() { + return _identities; + } - public ClassDescriptor getExtends() - { - return _extends; + public FieldDescriptor getIdentity() { + return (_identities == null) ? null : _identities[0]; } - public boolean isExtending() { - return (_extends != null); + public ClassDescriptor getExtends() { + return _extends; } /** @@ -243,16 +248,16 @@ * * @return A collection of class descriptors. */ - public Collection getExtendedBy() { - return _extendedBy; + public Collection getExtended() { + return _extended; } - public boolean isExtended() { - return (_extendedBy.size() > 0); + private void addExtended(ClassDescriptor classDesc) { + _extended.add(classDesc); } - public void addExtendedBy(ClassDescriptor classDesc) { - _extendedBy.add(classDesc); + public void setDepends(final ClassDescriptor depends) { + _depends = depends; } public ClassDescriptor getDepends() { @@ -259,50 +264,16 @@ return _depends; } - public FieldDescriptor getIdentity() { - return _identities == null? null : _identities[0]; - } - - public FieldDescriptor[] getIdentities() { - return _identities; - } - - - public AccessMode getAccessMode() - { - return _accessMode; - } - + //----------------------------------------------------------------------------------- /** - * 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 6342) +++ 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 6342) +++ 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 6342) +++ 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 6342) +++ C:/Java/castor-4/src/main/java/org/exolab/castor/xml/XMLMappingLoader.java (working copy) @@ -1,6 +1,6 @@ /** + * ("Software"), with or without modification, are permitted provided * Redistribution and use of this software and associated documentation - * ("Software"), with or without modification, are permitted provided * that the following conditions are met: * * 1. Redistributions of source code must retain copyright @@ -57,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.ClassDescriptorImpl; import org.exolab.castor.mapping.loader.CollectionHandlers; import org.exolab.castor.mapping.loader.AbstractMappingLoader; import org.exolab.castor.mapping.loader.FieldHandlerImpl; @@ -61,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; @@ -65,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; @@ -93,6 +96,8 @@ * @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. @@ -140,6 +145,8 @@ private NodeType _primitiveNodeType = null; + //----------------------------------------------------------------------------------- + /** * Creates a new XMLMappingLoader */ @@ -145,60 +152,39 @@ */ public XMLMappingLoader(ClassLoader loader) { super(loader); - + LocalConfiguration config = LocalConfiguration.getInstance(); - + _primitiveNodeType = config.getPrimitiveNodeType(); - _naming = config.getXMLNaming(); + _naming = config.getXMLNaming(); + } - } //-- XMLMappingLoader - - + //----------------------------------------------------------------------------------- + /** + * {@inheritDoc} + */ public BindingType getBindingType() { return BindingType.XML; } - private void createResolver() { - _cdResolver = (XMLClassDescriptorResolverImpl) - ClassDescriptorResolverFactory.createClassDescriptorResolver(BindingType.XML); - _cdResolver.setIntrospection(false); - _cdResolver.setLoadPackageMappings(false); - } - - 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; - - 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()) { loadClassMapping(mapping); } } - protected ClassDescriptor createDescriptor( ClassMapping clsMap ) - throws MappingException - { + + + + + /** + * {@inheritDoc} + */ + protected final ClassDescriptor createDescriptor(final ClassMapping clsMap) + throws MappingException { ClassDescriptor clsDesc; - String xmlName; if (clsMap.getAutoComplete()) { if ((clsMap.getMapTo() == null) && @@ -206,25 +192,111 @@ (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; + if (clsDesc != null) { return clsDesc; } + } catch(ResolverException rx) { + + } + } + } + + // 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)) { + if (clsMap.getVerifyConstructable() && (!Types.isConstructable(javaClass, true))) { + throw new MappingException("mapping.classNotConstructable", javaClass.getName()); + } + clsDesc = new ClassDescriptorImpl( + clsMap, javaClass, fields, null, extend, depend); + } else { + // 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()); } - catch(ResolverException rx) {} - + } + + // Create the class descriptor. + if (clsMap.getVerifyConstructable() && (!Types.isConstructable(javaClass, true))) { + throw new MappingException("mapping.classNotConstructable", javaClass.getName()); } + clsDesc = new ClassDescriptorImpl( + clsMap, javaClass, fields, identities, extend, depend); } - // Use super class to create class descriptor. Field descriptors will be - // generated only for supported fields, see createFieldDesc later on. - clsDesc = super.createDescriptor( clsMap ); MapTo mapTo = clsMap.getMapTo(); + String xmlName; if (( mapTo == null) || (mapTo.getXml() == null)) { String clsName = clsDesc.getJavaClass().getName(); int idx = clsName.lastIndexOf('.'); @@ -248,13 +320,10 @@ Class type = xmlClassDesc.getJavaClass(); //-- check compiled descriptors - if (_cdResolver == null) { - createResolver(); - } + if (_cdResolver == null) { createResolver(); } try { referenceDesc = _cdResolver.resolveXML(type); - } - catch(ResolverException rx) { + } catch (ResolverException rx) { throw new MappingException(rx); } @@ -280,7 +349,7 @@ identity = clsMap.getIdentity(0); - FieldDescriptor[] fields = xmlClassDesc.getFields(); + FieldDescriptor[] xmlFields = xmlClassDesc.getFields(); // Attributes XMLFieldDescriptor[] introFields = referenceDesc.getAttributeDescriptors(); @@ -285,7 +354,7 @@ // Attributes XMLFieldDescriptor[] introFields = referenceDesc.getAttributeDescriptors(); for (int i = 0; i