You are viewing a plain text version of this content. The canonical link for it is here.
Posted to ojb-dev@db.apache.org by ar...@apache.org on 2007/05/16 01:10:15 UTC

svn commit: r538372 - in /db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/metadata: ClassDescriptor.java DescriptorRepository.java

Author: arminw
Date: Tue May 15 16:10:14 2007
New Revision: 538372

URL: http://svn.apache.org/viewvc?view=rev&rev=538372
Log:
rename/add new methods for better handling of subclasses and classes mapped to same table, optimize source

Modified:
    db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/metadata/ClassDescriptor.java
    db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/metadata/DescriptorRepository.java

Modified: db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/metadata/ClassDescriptor.java
URL: http://svn.apache.org/viewvc/db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/metadata/ClassDescriptor.java?view=diff&rev=538372&r1=538371&r2=538372
==============================================================================
--- db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/metadata/ClassDescriptor.java (original)
+++ db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/metadata/ClassDescriptor.java Tue May 15 16:10:14 2007
@@ -25,11 +25,11 @@
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Vector;
 
+import org.apache.commons.lang.ArrayUtils;
 import org.apache.commons.lang.builder.ToStringBuilder;
 import org.apache.commons.lang.builder.ToStringStyle;
 import org.apache.ojb.broker.PersistenceBrokerException;
@@ -41,8 +41,9 @@
 import org.apache.ojb.broker.core.ValueContainer;
 import org.apache.ojb.broker.locking.IsolationLevels;
 import org.apache.ojb.broker.metadata.fieldaccess.PersistentField;
-import org.apache.ojb.broker.util.ClassHelper;
 import org.apache.ojb.broker.util.AttributeTokenizer;
+import org.apache.ojb.broker.util.ClassHelper;
+import org.apache.ojb.broker.util.ShortcutMapper;
 import org.apache.ojb.broker.util.configuration.Configuration;
 import org.apache.ojb.broker.util.configuration.Configurator;
 import org.apache.ojb.broker.util.configuration.impl.OjbConfigurator;
@@ -62,8 +63,6 @@
 public final class ClassDescriptor extends DescriptorBase
     implements Serializable, XmlCapable, IsolationLevels
 {
-	private String persistentFieldClassName;
-
     private static final long serialVersionUID = -5212253607374173965L;
 
     public static final String DYNAMIC_STR = "dynamic";
@@ -133,6 +132,7 @@
      * of these must be present for this function to be successful.
      */
     private Class factoryClass;
+    private String persistentFieldClassName;
     private int useIdentityColumn = 0;
     /**
      * Indicate whether or not this class has LOB fields.
@@ -255,17 +255,17 @@
      * the list of classes in the extent of this class. can be empty
      */
     private Vector extentClasses = new Vector();
-    /**
-     * the list of class names in the extent of this class. can be empty
-     */
-    private Vector extentClassNames = new Vector();
     private Map m_fieldDescriptorNameMap = null;
     private Map m_collectionDescriptorNameMap = null;
     private Map m_objectReferenceDescriptorsNameMap = null;
 
     // BRJ: ClassDescriptor referenced by 'super' ObjectReferenceDescriptor
     private ClassDescriptor m_superCld = null;
-    private boolean m_superCldSet = false;
+    /**
+     * Indicate if <tt>true</tt> that at least one autoincrement primary
+     * key field exists.
+     */
+    private Boolean autoincrementPrimaryKey;
 
     //-----------------------------------------------------------------
     //-----------------------------------------------------------------
@@ -295,10 +295,11 @@
     public void setBaseClass(String baseClass)
     {
         this.baseClass = baseClass;
+        this.m_superCld = null;
         // first deregister
-        getRepository().deregisterSuperClassMultipleJoinedTables(this);
+        getRepository().deregisterTablePerSubclassInheritance(this);
         // register classes using mapping of classes to multiple joined tables
-        getRepository().registerSuperClassMultipleJoinedTables(this);
+        getRepository().registerTablePerSubclassInheritance(this);
     }
 
 //    /**
@@ -369,7 +370,7 @@
         {
             m_rowReader =
                 (RowReader) ClassHelper.newInstance(
-                    newReaderClassName,
+                    ShortcutMapper.resolve(newReaderClassName, RowReader.class),
                     ClassDescriptor.class,
                     this);
         }
@@ -614,20 +615,16 @@
      */
     public ClassDescriptor getSuperClassDescriptor()
     {
-        if (!m_superCldSet)
+        if (baseClass != null && m_superCld == null)
         {
-            if(getBaseClass() != null)
+            m_superCld = getRepository().getDescriptorFor(getBaseClass());
+            if(m_superCld.isAbstract() || m_superCld.isInterface())
             {
-                m_superCld = getRepository().getDescriptorFor(getBaseClass());
-                if(m_superCld.isAbstract() || m_superCld.isInterface())
-                {
-                    throw new MetadataException("Super class mapping only work for real class, but declared super class" +
-                            " is an interface or is abstract. Declared class: " + m_superCld.getClassNameOfObject());
-                }
+                throw new MetadataException("Super class mapping only work for real classes, but declared super class "
+                        + baseClass + " is an interface or is abstract and can't be used by class: "
+                        + m_superCld.getClassNameOfObject());
             }
-            m_superCldSet = true;
         }
-
         return m_superCld;
     }
 
@@ -642,88 +639,104 @@
     }
 
     /**
-     * add an Extent class to the current descriptor
-     * @param newExtendClass
+     * Add an <em>extent class</em> to the current class descriptor.
+     *
+     * @param extent name of the class to add.
      */
-    public void addExtentClass(Class newExtendClass)
+    public void addExtentClass(Class extent)
     {
-        extentClasses.add(newExtendClass);
-        this.addExtentClass(newExtendClass.getName());
+        if(!extentClasses.contains(extent))
+        {
+            extentClasses.add(extent);
+            if(m_repository != null) m_repository.addSuperClassForExtent(extent, this);
+        }
     }
 
     /**
-     * add an Extent class to the current descriptor
-     * @param newExtentClassName name of the class to add
+     * Add an <em>extent class</em> to the current class descriptor.
+     *
+     * @param extent name of the class to add.
      */
-    public void addExtentClass(String newExtentClassName)
+    public void addExtentClass(String extent)
     {
-        extentClassNames.add(newExtentClassName);
-        if(m_repository != null) m_repository.addExtent(newExtentClassName, this);
+        try
+        {
+            Class extentClass = ClassHelper.getClass(extent);
+            addExtentClass(extentClass);
+        }
+        catch (ClassNotFoundException e)
+        {
+            throw new MetadataException("Adding of extent fails: Unable to load class [" + extent
+                    + "]. Make sure it is available on the classpath.", e);
+        }
     }
 
-    public void removeExtentClass(String extentClassName)
+    /**
+     * Remove an <em>extent class</em> from the current class descriptor.
+     * @param extent name of the class to remove.
+     */
+    public void removeExtentClass(String extent)
     {
-        extentClassNames.remove(extentClassName);
-        if(m_repository != null) m_repository.removeExtent(extentClassName);
+        try
+        {
+            Class extentClass = ClassHelper.getClass(extent);
+            removeExtentClass(extentClass);
+        }
+        catch (ClassNotFoundException e)
+        {
+            LoggerFactory.getDefaultLogger().error("Remove of extent fails: Unable to find class [" + extent
+                    + "]. Make sure it is available on the classpath.", e);
+        }
     }
 
     /**
-     * return all classes in this extent.
-     * Creation date: (02.02.2001 17:49:11)
-     * @return java.util.Vector
+     * Remove an <em>extent class</em> from the current class descriptor.
+     * @param extent name of the class to remove.
      */
-    public synchronized Vector getExtentClasses()
+    public void removeExtentClass(Class extent)
+    {
+        boolean result = extentClasses.remove(extent);
+        if(result && m_repository != null) m_repository.removeSuperClassForExtent(extent);
+    }
+
+    /**
+     * Return all <em>extent classes</em> in this extent.
+     *
+     * @return The list of classes.
+     */
+    public Vector getExtentClasses()
     {
-        if (extentClassNames.size() != extentClasses.size())
-        {
-            extentClasses.clear();
-            for (Iterator iter = extentClassNames.iterator(); iter.hasNext();)
-            {
-                String classname = (String) iter.next();
-                Class extentClass;
-                try
-                {
-                    extentClass = ClassHelper.getClass(classname);
-                }
-                catch (ClassNotFoundException e)
-                {
-                    throw new MetadataException(
-                        "Unable to load class ["
-                            + classname
-                            + "]. Make sure it is available on the classpath.",
-                        e);
-                }
-                extentClasses.add(extentClass);
-            }
-        }
         return extentClasses;
     }
 
 
     /**
-     * Return the names of all classes in this extent
-     * @return java.util.Vector a Vector containing the fully qualified names
-     * of all classes in this extent
+     * Return the names of all classes in this extent.
+     *
+     * @return a list containing the fully qualified names
+     * of all extent classes provided by this class.
      */
-    public synchronized Vector getExtentClassNames()
+    public Vector getExtentClassNames()
     {
-        return this.extentClassNames;
+        Vector list = new Vector();
+        for(int i = 0; i < extentClasses.size(); i++)
+        {
+            Class result = (Class) extentClasses.get(i);
+            list.add(result.getName());
+        }
+        return list;
     }
 
     /**
-     * Insert the method's description here.
-     * Creation date: (02.02.2001 17:49:11)
-     * @return boolean
+     * Returns <em>true</em> if this class has <em>extent classes</em>.
      */
     public boolean isExtent()
     {
-        return (getExtentClassNames().size() > 0);
+        return !extentClasses.isEmpty();
     }
 
     /**
-     * Insert the method's description here.
-     * Creation date: (26.01.2001 09:20:09)
-     * @return java.lang.Class
+     * Returns the proxy class of this class or <em>null</em> if not set.
      */
     public synchronized Class getProxyClass()
     {
@@ -1053,7 +1066,7 @@
         if (m_PkFieldDescriptors == null)
         {
             // 1. collect all Primary Key fields from Field list
-            Vector vec = new Vector();
+            ArrayList pkList = new ArrayList();
             // 1.a if descriptor describes an interface: take PK fields from an implementors ClassDescriptor
             if (isInterface())
             {
@@ -1071,12 +1084,12 @@
                     FieldDescriptor fd = fields[i];
                     if (fd.isPrimaryKey())
                     {
-                        vec.add(fd);
+                        pkList.add(fd);
                     }
                 }
                 // 2. Sort fields according to their getOrder() Property
-                Collections.sort(vec, FieldDescriptor.getComparator());
-                m_PkFieldDescriptors = (FieldDescriptor[]) vec.toArray(new FieldDescriptor[vec.size()]);
+                Collections.sort(pkList, FieldDescriptor.getComparator());
+                m_PkFieldDescriptors = (FieldDescriptor[]) pkList.toArray(new FieldDescriptor[pkList.size()]);
             }
         }
         return m_PkFieldDescriptors;
@@ -1325,366 +1338,120 @@
         return zeroArgumentConstructor;
     }
 
-    /*
-     * @see XmlCapable#toXML()
+/*
+arminw:
+TODO: this feature doesn't work, so remove this in future
+*/
+    /**
+     * Set name of the super class.
      */
-    public String toXML()
+    public void setSuperClass(String classname)
     {
-        RepositoryTags tags = RepositoryTags.getInstance();
-        String eol = System.getProperty("line.separator");
+        this.superClass = classname;
+    }
 
-        // comment on class
-        StringBuffer result = new StringBuffer(1024);
-        result.append( eol);
-        result.append( "  <!-- Mapping for Class ");
-        result.append( this.getClassNameOfObject());
-        result.append( " -->");
-        result.append( eol );
+    /**
+     * Return the super class or <code>null</code>
+     * if not declared in repository file.
+     */
+    public String getSuperClass()
+    {
+        return superClass;
+    }
 
-        // opening tag and attributes
-        result.append( "  ");
-        result.append( tags.getOpeningTagNonClosingById(CLASS_DESCRIPTOR));
-        result.append( eol );
+    /**
+     * TODO drop this method?
+     */
+    public void setSuperClassFieldRef(int fieldId)
+    {
+        this.superClassFieldRef = fieldId;
+    }
 
-        // class
-        result.append( "    ");
-        result.append( tags.getAttribute(CLASS_NAME, this.getClassNameOfObject()));
-        result.append( eol );
+    /**
+     * TODO drop this method?
+     */
+    public int getSuperClassFieldRef()
+    {
+        return superClassFieldRef;
+    }
 
-        // isolation level is optional
-        if (null != getRepository())
-        {
-            if (getIsolationLevel() != this.getRepository().getDefaultIsolationLevel())
-            {
-                result.append( "    ");
-                result.append( tags.getAttribute(ISOLATION_LEVEL, this.isolationLevelXml()) );
-                result.append( eol );
-            }
-        }
+    /**
+     * Return true, if the described class is
+     * an interface.
+     */
+    public boolean isInterface()
+    {
+        return m_isInterface;
+    }
 
-        Class theProxyClass = null;
-        try
-        {
-            theProxyClass = this.getProxyClass();
-        }
-        catch (Throwable t)
-        {
-            // Ignore this exception, just try to get the Class object of the
-            // proxy class in order to be able to decide, whether the class
-            // is a dynamic proxy or not.
-        }
+    /**
+     * Set <code>true</code> if described class is
+     * a interface.
+     */
+    public void setIsInterface(boolean newIsInterface)
+    {
+        m_isInterface = newIsInterface;
+    }
 
-        // proxy is optional
-        if (theProxyClass != null)
-	    {
-            if (isDynamicProxy())   // tomdz: What about VirtualProxy ?
-            {
-                result.append( "    ");
-                result.append( tags.getAttribute(CLASS_PROXY, DYNAMIC_STR));
-                result.append( eol );
-            }
-            else
-            {
-                result.append( "    ");
-                result.append( tags.getAttribute(CLASS_PROXY, this.getProxyClassName()));
-                result.append( eol );
-            }
-            result.append( "        ");
-            result.append( tags.getAttribute(PROXY_PREFETCHING_LIMIT, "" + this.getProxyPrefetchingLimit()));
-            result.append( eol );
-	    }
+    /**
+     * @return boolean true if the mapped class is abstract
+     */
+    public boolean isAbstract()
+    {
+        return isAbstract;
+    }
 
-        // schema is optional
-        if (this.getSchema() != null)
-        {
-            result.append( "    ");
-            result.append( tags.getAttribute(SCHEMA_NAME, this.getSchema()));
-            result.append( eol );
-        }
+    /**
+     * Returns acceptLocks.
+     * @return boolean
+     */
+    public boolean isAcceptLocks()
+    {
+        return acceptLocks;
+    }
 
-        // table name
-        if (this.getTableName() != null)
-        {
-            result.append("    ");
-            result.append( tags.getAttribute(TABLE_NAME, this.getTableName()));
-            result.append( eol );
-        }
+    /**
+     * Sets acceptLocks.
+     * @param acceptLocks The m_acceptLocks to set
+     */
+    public void setAcceptLocks(boolean acceptLocks)
+    {
+        this.acceptLocks = acceptLocks;
+    }
 
-        // rowreader is optional
-        if (this.getRowReaderClassName() != null)
-        {
-            result.append( "    ");
-            result.append( tags.getAttribute(ROW_READER, this.getRowReaderClassName()));
-            result.append( eol );
-        }
+    /**
+     * Gets the IndexDescriptors used for DDL generation.
+     */
+    public Vector getIndexes()
+    {
+        return indexes;
+    }
 
-        //accept-locks is optional, enabled by default
-        if (!this.acceptLocks)
-        {
-            result.append( "        ");
-            result.append( tags.getAttribute(ACCEPT_LOCKS, "false"));
-            result.append( eol );
-        }
-        // sequence manager attribute not yet implemented
+    /**
+     * Sets the IndexDescriptors used for DDL generation.
+     */
+    public void setIndexes(Vector indexes)
+    {
+        this.indexes = indexes;
+    }
 
-        // initialization method is optional
-        if (this.getInitializationMethod() != null)
-        {
-            result.append( "    ");
-            result.append( tags.getAttribute(INITIALIZATION_METHOD, this.getInitializationMethod().getName()));
-            result.append( eol );
-        }
+    /**
+     * Gets the repository.
+     * @return Returns a DescriptorRepository
+     */
+    public DescriptorRepository getRepository()
+    {
+        return m_repository;
+    }
 
-        // factory class is optional
-        if (this.getFactoryClass() != null)
-        {
-            result.append( "    ");
-            result.append( tags.getAttribute(FACTORY_CLASS, this.getFactoryClass().getName()) );
-            result.append( eol );
-        }
-
-        //	factory method is optional
-        if (this.getFactoryMethod() != null)
-        {
-            result.append( "    ");
-            result.append( tags.getAttribute(FACTORY_METHOD, this.getFactoryMethod().getName()) );
-            result.append( eol );
-        }
-
-        //reference refresh is optional, disabled by default
-        if (isAlwaysRefresh())
-        {
-            result.append( "    ");
-            result.append( tags.getAttribute(REFRESH, "true"));
-            result.append( eol );
-        }
-
-        result.append( "  >");
-        result.append( eol );
-
-        // end of attributes
-
-        // begin of elements
-        if (isInterface())
-        {
-            // extent-class
-            for (int i = 0; i < getExtentClassNames().size(); i++)
-            {
-                result.append( "      ");
-                result.append( tags.getOpeningTagNonClosingById(CLASS_EXTENT));
-                result.append( " " );
-                result.append( tags.getAttribute(CLASS_REF, getExtentClassNames().get(i).toString()) );
-                result.append( " />");
-                result.append( eol );
-            }
-        }
-        else
-        {
-            // class extent is optional
-            if (isExtent())
-            {
-                for (int i = 0; i < getExtentClassNames().size(); i++)
-                {
-                    result.append( "      ");
-                    result.append( tags.getOpeningTagNonClosingById(CLASS_EXTENT));
-                    result.append( " " );
-                    result.append( tags.getAttribute(CLASS_REF, getExtentClassNames().get(i).toString()) );
-                    result.append( " />");
-                    result.append( eol );
-                }
-            }
-
-            // write all FieldDescriptors
-            FieldDescriptor[] fields = getFieldDescriptions();
-            for (int i = 0; i < fields.length; i++)
-            {
-                result.append( fields[i].toXML() );
-            }
-
-            // write optional ReferenceDescriptors
-            Vector refs = getObjectReferenceDescriptors();
-            for (int i = 0; i < refs.size(); i++)
-            {
-                result.append( ((ObjectReferenceDescriptor) refs.get(i)).toXML() );
-            }
-
-            // write optional CollectionDescriptors
-            Vector cols = getCollectionDescriptors();
-            for (int i = 0; i < cols.size(); i++)
-            {
-                result.append( ((CollectionDescriptor) cols.get(i)).toXML() );
-            }
-
-            // write optional IndexDescriptors
-            for (int i = 0; i < indexes.size(); i++)
-            {
-                IndexDescriptor indexDescriptor = (IndexDescriptor) indexes.elementAt(i);
-                result.append( indexDescriptor.toXML() );
-            }
-
-            // Write out the procedures
-            if (this.getInsertProcedure() != null)
-            {
-                result.append( this.getInsertProcedure().toXML() );
-            }
-            if (this.getUpdateProcedure() != null)
-            {
-                result.append( this.getUpdateProcedure().toXML() );
-            }
-            if (this.getDeleteProcedure() != null)
-            {
-                result.append( this.getDeleteProcedure().toXML() );
-            }
-        }
-        result.append( "  ");
-        result.append( tags.getClosingTagById(CLASS_DESCRIPTOR) );
-        return result.toString();
-    }
-
-    private String isolationLevelXml()
-    {
-        switch (this.getIsolationLevel())
-        {
-            case (IL_OPTIMISTIC) :
-                {
-                    return LITERAL_IL_OPTIMISTIC;
-                }
-            case (IL_READ_COMMITTED) :
-                {
-                    return LITERAL_IL_READ_COMMITTED;
-                }
-            case (IL_READ_UNCOMMITTED) :
-                {
-                    return LITERAL_IL_READ_UNCOMMITTED;
-                }
-            case (IL_REPEATABLE_READ) :
-                {
-                    return LITERAL_IL_REPEATABLE_READ;
-                }
-            case (IL_SERIALIZABLE) :
-                {
-                    return LITERAL_IL_SERIALIZABLE;
-                }
-            default :
-                {
-                    return LITERAL_IL_READ_UNCOMMITTED;
-                }
-        }
-    }
-/*
-arminw:
-TODO: this feature doesn't work, so remove this in future
-*/
-    /**
-     * Set name of the super class.
-     */
-    public void setSuperClass(String classname)
-    {
-        this.superClass = classname;
-    }
-
-    /**
-     * Return the super class or <code>null</code>
-     * if not declared in repository file.
-     */
-    public String getSuperClass()
-    {
-        return superClass;
-    }
-
-    /**
-     * TODO drop this method?
-     */
-    public void setSuperClassFieldRef(int fieldId)
-    {
-        this.superClassFieldRef = fieldId;
-    }
-
-    /**
-     * TODO drop this method?
-     */
-    public int getSuperClassFieldRef()
-    {
-        return superClassFieldRef;
-    }
-
-    /**
-     * Return true, if the described class is
-     * an interface.
-     */
-    public boolean isInterface()
-    {
-        return m_isInterface;
-    }
-
-    /**
-     * Set <code>true</code> if described class is
-     * a interface.
-     */
-    public void setIsInterface(boolean newIsInterface)
-    {
-        m_isInterface = newIsInterface;
-    }
-
-    /**
-     * @return boolean true if the mapped class is abstract
-     */
-    public boolean isAbstract()
-    {
-        return isAbstract;
-    }
-
-    /**
-     * Returns acceptLocks.
-     * @return boolean
-     */
-    public boolean isAcceptLocks()
-    {
-        return acceptLocks;
-    }
-
-    /**
-     * Sets acceptLocks.
-     * @param acceptLocks The m_acceptLocks to set
-     */
-    public void setAcceptLocks(boolean acceptLocks)
-    {
-        this.acceptLocks = acceptLocks;
-    }
-
-    /**
-     * Gets the IndexDescriptors used for DDL generation.
-     */
-    public Vector getIndexes()
-    {
-        return indexes;
-    }
-
-    /**
-     * Sets the IndexDescriptors used for DDL generation.
-     */
-    public void setIndexes(Vector indexes)
-    {
-        this.indexes = indexes;
-    }
-
-    /**
-     * Gets the repository.
-     * @return Returns a DescriptorRepository
-     */
-    public DescriptorRepository getRepository()
-    {
-        return m_repository;
-    }
-
-    /**
-     * Sets the repository.
-     * @param repository The repository to set
-     */
-    public void setRepository(DescriptorRepository repository)
-    {
-        m_repository = repository;
-    }
+    /**
+     * Sets the repository.
+     * @param repository The repository to set
+     */
+    public void setRepository(DescriptorRepository repository)
+    {
+        m_repository = repository;
+    }
 
     /**
      * returns the transaction isolation level to be used for this class. Used only in the ODMG server
@@ -1751,27 +1518,9 @@
     }
 
     /**
-     * Return a string representation of this class.
+     * sets the initialization method for this descriptor
      */
-    public String toString()
-    {
-        ToStringBuilder buf = new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE);
-        return buf
-            .append("classNameOfObject", getClassNameOfObject())
-            .append("tableName", getTableName())
-            .append("schema", getSchema())
-            .append("isInterface", isInterface())
-            .append("extendClassNames", getExtentClassNames().toString())
-            //.append("[fieldDescriptions:")
-            .append(getFieldDescriptions())
-            //.append("]")
-            .toString();
-    }
-
-    /**
-     * sets the initialization method for this descriptor
-     */
-    private synchronized void setInitializationMethod(Method newMethod)
+    private synchronized void setInitializationMethod(Method newMethod)
     {
         if (newMethod != null)
         {
@@ -2093,7 +1842,7 @@
      */
     public void setPersistentFieldClassName(String pfClassName)
     {
-		this.persistentFieldClassName = pfClassName;
+        this.persistentFieldClassName = pfClassName;
     }
 
 
@@ -2316,5 +2065,311 @@
     public void setStateDetection(boolean stateDetection)
     {
         this.stateDetection = stateDetection;
+    }
+
+    public boolean hasAutoincrementPrimaryKey()
+    {
+        if(autoincrementPrimaryKey == null)
+        {
+            boolean result = false;
+            FieldDescriptor[] pks;
+            /*
+            if table per subclass inheritance is used we have to lookup
+            the PK fields of the base class to get the correct setting,
+            because in all sub-classes the autoincrement setting is always 'false' 
+            */
+            if(getSuperClassDescriptor() != null)
+            {
+                ClassDescriptor baseClass = getSuperClassDescriptor();
+                while(baseClass.getSuperClassDescriptor() != null)
+                {
+                    baseClass = baseClass.getSuperClassDescriptor();
+                }
+                pks = baseClass.getPkFields();
+            }
+            else
+            {
+                pks = getPkFields();
+            }
+            for(int i = 0; i < pks.length; i++)
+            {
+                FieldDescriptor pk = pks[i];
+                if(pk.isAutoIncrement())
+                {
+                    result = true;
+                    break;
+                }
+            }
+            autoincrementPrimaryKey = result ? Boolean.TRUE : Boolean.FALSE;
+        }
+        return autoincrementPrimaryKey.booleanValue();
+    }
+
+    /**
+     * Return a string representation of this class.
+     */
+    public String toString()
+    {
+        ToStringBuilder buf = new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE);
+        return buf
+            .append("classNameOfObject", getClassNameOfObject())
+            .append("tableName", getTableName())
+            .append("schema", getSchema())
+            .append("baseClass", baseClass)
+            .append("proxyClass", proxyClassName)
+            .append("factoryClass", factoryClass)
+            .append("factoryMethod", factoryMethodName)
+            .append("extendClassNames", getExtentClassNames().toString())
+            //.append("[fieldDescriptions:")
+            .append("#fields==>", ArrayUtils.toString(getFieldDescriptor(false)))
+            //.append("]")
+            .toString();
+    }
+
+    /*
+     * @see XmlCapable#toXML()
+     */
+    public String toXML()
+    {
+        RepositoryTags tags = RepositoryTags.getInstance();
+        String eol = System.getProperty("line.separator");
+
+        // comment on class
+        StringBuffer result = new StringBuffer(1024);
+        result.append( eol);
+        result.append( "  <!-- Mapping for Class ");
+        result.append( this.getClassNameOfObject());
+        result.append( " -->");
+        result.append( eol );
+
+        // opening tag and attributes
+        result.append( "  ");
+        result.append( tags.getOpeningTagNonClosingById(CLASS_DESCRIPTOR));
+        result.append( eol );
+
+        // class
+        result.append( "    ");
+        result.append( tags.getAttribute(CLASS_NAME, this.getClassNameOfObject()));
+        result.append( eol );
+
+        // isolation level is optional
+        if (null != getRepository())
+        {
+            if (getIsolationLevel() != this.getRepository().getDefaultIsolationLevel())
+            {
+                result.append( "    ");
+                result.append( tags.getAttribute(ISOLATION_LEVEL, this.isolationLevelXml()) );
+                result.append( eol );
+            }
+        }
+
+        Class theProxyClass = null;
+        try
+        {
+            theProxyClass = this.getProxyClass();
+        }
+        catch (Throwable t)
+        {
+            // Ignore this exception, just try to get the Class object of the
+            // proxy class in order to be able to decide, whether the class
+            // is a dynamic proxy or not.
+        }
+
+        // proxy is optional
+        if (theProxyClass != null)
+	    {
+            if (isDynamicProxy())   // tomdz: What about VirtualProxy ?
+            {
+                result.append( "    ");
+                result.append( tags.getAttribute(CLASS_PROXY, DYNAMIC_STR));
+                result.append( eol );
+            }
+            else
+            {
+                result.append( "    ");
+                result.append( tags.getAttribute(CLASS_PROXY, this.getProxyClassName()));
+                result.append( eol );
+            }
+            result.append( "        ");
+            result.append( tags.getAttribute(PROXY_PREFETCHING_LIMIT, "" + this.getProxyPrefetchingLimit()));
+            result.append( eol );
+	    }
+
+        // schema is optional
+        if (this.getSchema() != null)
+        {
+            result.append( "    ");
+            result.append( tags.getAttribute(SCHEMA_NAME, this.getSchema()));
+            result.append( eol );
+        }
+
+        // table name
+        if (this.getTableName() != null)
+        {
+            result.append("    ");
+            result.append( tags.getAttribute(TABLE_NAME, this.getTableName()));
+            result.append( eol );
+        }
+
+        // rowreader is optional
+        if (this.getRowReaderClassName() != null)
+        {
+            result.append( "    ");
+            result.append( tags.getAttribute(ROW_READER, this.getRowReaderClassName()));
+            result.append( eol );
+        }
+
+        //accept-locks is optional, enabled by default
+        if (!this.acceptLocks)
+        {
+            result.append( "        ");
+            result.append( tags.getAttribute(ACCEPT_LOCKS, "false"));
+            result.append( eol );
+        }
+        // sequence manager attribute not yet implemented
+
+        // initialization method is optional
+        if (this.getInitializationMethod() != null)
+        {
+            result.append( "    ");
+            result.append( tags.getAttribute(INITIALIZATION_METHOD, this.getInitializationMethod().getName()));
+            result.append( eol );
+        }
+
+        // factory class is optional
+        if (this.getFactoryClass() != null)
+        {
+            result.append( "    ");
+            result.append( tags.getAttribute(FACTORY_CLASS, this.getFactoryClass().getName()) );
+            result.append( eol );
+        }
+
+        //	factory method is optional
+        if (this.getFactoryMethod() != null)
+        {
+            result.append( "    ");
+            result.append( tags.getAttribute(FACTORY_METHOD, this.getFactoryMethod().getName()) );
+            result.append( eol );
+        }
+
+        //reference refresh is optional, disabled by default
+        if (isAlwaysRefresh())
+        {
+            result.append( "    ");
+            result.append( tags.getAttribute(REFRESH, "true"));
+            result.append( eol );
+        }
+
+        result.append( "  >");
+        result.append( eol );
+
+        // end of attributes
+
+        // begin of elements
+        if (isInterface())
+        {
+            // extent-class
+            for (int i = 0; i < getExtentClassNames().size(); i++)
+            {
+                result.append( "      ");
+                result.append( tags.getOpeningTagNonClosingById(CLASS_EXTENT));
+                result.append( " " );
+                result.append( tags.getAttribute(CLASS_REF, getExtentClassNames().get(i).toString()) );
+                result.append( " />");
+                result.append( eol );
+            }
+        }
+        else
+        {
+            // class extent is optional
+            if (isExtent())
+            {
+                for (int i = 0; i < getExtentClassNames().size(); i++)
+                {
+                    result.append( "      ");
+                    result.append( tags.getOpeningTagNonClosingById(CLASS_EXTENT));
+                    result.append( " " );
+                    result.append( tags.getAttribute(CLASS_REF, getExtentClassNames().get(i).toString()) );
+                    result.append( " />");
+                    result.append( eol );
+                }
+            }
+
+            // write all FieldDescriptors
+            FieldDescriptor[] fields = getFieldDescriptions();
+            for (int i = 0; i < fields.length; i++)
+            {
+                result.append( fields[i].toXML() );
+            }
+
+            // write optional ReferenceDescriptors
+            Vector refs = getObjectReferenceDescriptors();
+            for (int i = 0; i < refs.size(); i++)
+            {
+                result.append( ((ObjectReferenceDescriptor) refs.get(i)).toXML() );
+            }
+
+            // write optional CollectionDescriptors
+            Vector cols = getCollectionDescriptors();
+            for (int i = 0; i < cols.size(); i++)
+            {
+                result.append( ((CollectionDescriptor) cols.get(i)).toXML() );
+            }
+
+            // write optional IndexDescriptors
+            for (int i = 0; i < indexes.size(); i++)
+            {
+                IndexDescriptor indexDescriptor = (IndexDescriptor) indexes.elementAt(i);
+                result.append( indexDescriptor.toXML() );
+            }
+
+            // Write out the procedures
+            if (this.getInsertProcedure() != null)
+            {
+                result.append( this.getInsertProcedure().toXML() );
+            }
+            if (this.getUpdateProcedure() != null)
+            {
+                result.append( this.getUpdateProcedure().toXML() );
+            }
+            if (this.getDeleteProcedure() != null)
+            {
+                result.append( this.getDeleteProcedure().toXML() );
+            }
+        }
+        result.append( "  ");
+        result.append( tags.getClosingTagById(CLASS_DESCRIPTOR) );
+        return result.toString();
+    }
+
+    private String isolationLevelXml()
+    {
+        switch (this.getIsolationLevel())
+        {
+            case (IL_OPTIMISTIC) :
+                {
+                    return LITERAL_IL_OPTIMISTIC;
+                }
+            case (IL_READ_COMMITTED) :
+                {
+                    return LITERAL_IL_READ_COMMITTED;
+                }
+            case (IL_READ_UNCOMMITTED) :
+                {
+                    return LITERAL_IL_READ_UNCOMMITTED;
+                }
+            case (IL_REPEATABLE_READ) :
+                {
+                    return LITERAL_IL_REPEATABLE_READ;
+                }
+            case (IL_SERIALIZABLE) :
+                {
+                    return LITERAL_IL_SERIALIZABLE;
+                }
+            default :
+                {
+                    return LITERAL_IL_READ_UNCOMMITTED;
+                }
+        }
     }
 }

Modified: db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/metadata/DescriptorRepository.java
URL: http://svn.apache.org/viewvc/db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/metadata/DescriptorRepository.java?view=diff&rev=538372&r1=538371&r2=538372
==============================================================================
--- db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/metadata/DescriptorRepository.java (original)
+++ db/ojb/branches/OJB_1_0_RELEASE/src/java/org/apache/ojb/broker/metadata/DescriptorRepository.java Tue May 15 16:10:14 2007
@@ -25,7 +25,6 @@
 import java.util.Map;
 import java.util.Set;
 
-import org.apache.commons.collections.set.ListOrderedSet;
 import org.apache.commons.lang.SystemUtils;
 import org.apache.commons.lang.builder.ToStringBuilder;
 import org.apache.commons.lang.builder.ToStringStyle;
@@ -76,11 +75,12 @@
      * (@see DescriptorRepository#getExtentClass). To speed up the costy
      * evaluation, we use this tiny hash map.
      */
-    private final Map extentTable;
-
-    private Map superClassMultipleJoinedTablesMap;
+    private final Map superClassForExtentMap;
+    private final Map superClassMultipleJoinedTablesMap;
+    private final Map classesToSameTableMap;
 
     private transient Map m_multiMappedTableMap;
+    private transient Map m_subClassesToSameTableMap;
     private transient Map m_topLevelClassTable;
     private transient Map m_firstConcreteClassMap;
     private transient Map m_allConcreteSubClass;
@@ -94,9 +94,10 @@
      */
     public DescriptorRepository() throws PersistenceBrokerException
     {
-        descriptorTable = new HashMap();
-        extentTable = new HashMap();
-        superClassMultipleJoinedTablesMap = new HashMap();
+        descriptorTable = new HashMap(30);
+        superClassForExtentMap = new HashMap(30);
+        superClassMultipleJoinedTablesMap = new HashMap(30);
+        classesToSameTableMap = new HashMap(30);
     }
 
     public static String getVersion()
@@ -105,47 +106,56 @@
     }
 
     /**
+     * Returns a map with all class names as key and the associated
+     * {@link ClassDescriptor} as value.
+     * @return The map used by this class (not cloned!).
+     */
+    public Map getDescriptorTable()
+    {
+        return descriptorTable;
+    }
+
+    private synchronized void changeDescriptorEvent()
+    {
+        m_multiMappedTableMap = null;
+        m_topLevelClassTable = null;
+        m_firstConcreteClassMap = null;
+        m_allConcreteSubClass = null;
+        m_batchConnectionKeyToFKMap = null;
+        m_subClassesToSameTableMap = null;
+    }
+
+    /**
      * Add a pair of extent/classdescriptor to the extentTable to gain speed
-     * while retrieval of extents.
-     * @param classname the name of the extent itself
+     * while retrieval of super class descriptor for a given extent class.
+     *
+     * @param extent the name of the extent itself
      * @param cld the class descriptor, where it belongs to
      */
-    void addExtent(String classname, ClassDescriptor cld)
+    void addSuperClassForExtent(Class extent, ClassDescriptor cld)
     {
-        synchronized (extentTable)
+        synchronized (superClassForExtentMap)
         {
-            extentTable.put(classname, cld);
+            superClassForExtentMap.put(extent, cld);
         }
     }
 
     /**
      * Remove a pair of extent/classdescriptor from the extentTable.
-     * @param classname the name of the extent itself
+     *
+     * @param extent the class of the extent itself.
      */
-    void removeExtent(String classname)
+    void removeSuperClassForExtent(Class extent)
     {
-        synchronized (extentTable)
+        synchronized (superClassForExtentMap)
         {
             // returns the super class for given extent class name
-            ClassDescriptor cld = (ClassDescriptor) extentTable.remove(classname);
-            if(cld != null && m_topLevelClassTable != null)
+            ClassDescriptor cld = (ClassDescriptor) superClassForExtentMap.remove(extent);
+            if(cld != null)
             {
-                Class extClass;
-                try
-                {
-                    extClass = ClassHelper.getClass(classname);
-                }
-                catch (ClassNotFoundException e)
-                {
-                    // Should not happen
-                    throw new MetadataException("Can't instantiate class object for needed extent remove", e);
-                }
                 // remove extent from super class descriptor
-                cld.removeExtentClass(classname);
-                m_topLevelClassTable.remove(extClass);
-                // clear map with first concrete classes, because the removed
-                // extent could be such a first found concrete class
-                m_firstConcreteClassMap = null;
+                cld.removeExtentClass(extent);
+                changeDescriptorEvent();
             }
         }
     }
@@ -169,9 +179,9 @@
         Class retval = (Class) m_topLevelClassTable.get(clazz);
         if (retval == null)
         {
-            synchronized (extentTable)
+            synchronized (superClassForExtentMap)
             {
-                ClassDescriptor cld = (ClassDescriptor) extentTable.get(clazz.getName());
+                ClassDescriptor cld = (ClassDescriptor) superClassForExtentMap.get(clazz);
                 if (cld == null)
                 {
                     // walk the super-references
@@ -219,6 +229,10 @@
     }
 
     /**
+     * Returns all {@link FieldDescriptor} of the specified class and all sub-classes mapped
+     * to the same table as the specified one. This means all fields included in a table-per-hierarchy
+     * inheritance mapping via OJB's extent declaration.
+     *
      * @return all field descriptors for a class that belongs to a set of classes mapped
      * to the same table, otherwise the select queries produced won't contain the necessary
      * information to materialize extents mapped to the same class.
@@ -248,7 +262,6 @@
         then you can lose the stream data."
         */
         List allFieldDescriptors = new ArrayList();
-
         Set visitedColumns = new HashSet();
         ClassDescriptor temp;
         FieldDescriptor[] fields;
@@ -285,47 +298,150 @@
         return retval;
     }
 
-    private List getClassesMappedToSameTable(ClassDescriptor targetCld)
+    private void registerClassesMappedToSameTable(ClassDescriptor cld)
     {
-        /*
-        try to find an extent that contains clazz
-        clone map to avoid synchronization problems, because another thread
-        can do a put(..) operation on descriptor table
-        */
-        Iterator iter = ((HashMap)descriptorTable.clone()).values().iterator();
-        List retval = new ArrayList();
-        /*
-        make sure that target class is at first position
-        this is mandatory, because only this way we can guarantee to extract
-        the correct field-descriptor in method #getAllMappedColumns
-        */
-        retval.add(targetCld);
-        while (iter.hasNext())
+        String tableName = cld.getFullTableName();
+        if(tableName != null)
         {
-            ClassDescriptor cld = (ClassDescriptor) iter.next();
-            if (cld.getFullTableName() != null)
+            List result = (List) classesToSameTableMap.get(cld.getFullTableName());
+            if(result == null)
             {
-                if (cld.getFullTableName().equals(targetCld.getFullTableName())
-                        && !targetCld.getClassOfObject().equals(cld.getClassOfObject()))
-                {
-                    retval.add(cld);
-                }
+                result = new ArrayList();
+                result.add(cld);
+                classesToSameTableMap.put(cld.getFullTableName(), result);
+            }
+            else
+            {
+                result.add(cld);
             }
         }
-        return retval;
     }
 
-    public Map getDescriptorTable()
+    private void deregisterClassesToSameTable(ClassDescriptor cld)
     {
-        return descriptorTable;
+        String tableName = cld.getFullTableName();
+        if(tableName != null)
+        {
+            List result = (List) classesToSameTableMap.get(cld.getFullTableName());
+            if(result != null)
+            {
+                result.remove(cld);
+            }
+        }
+    }
+
+    /**
+     * Returns a list of all {@link ClassDescriptor} mapped to the same table as the
+     * specified class - independent from any inheritance mappings. The specified
+     * descriptor is included in the returned list.
+     *
+     * @param cld The souce class descriptor.
+     * @return A list of classes mapped to the same table. If the specified class isn't
+     * mapped to a table <em>null</em> will be returned. If no other class is mapped to
+     * the same table the list only contains the specified {@link ClassDescriptor}.
+     * @see #getSubClassesMappedToSameTable(ClassDescriptor)
+     * @see #getSubClassesMultipleJoinedTables(ClassDescriptor, boolean)
+     */
+    public List getClassesMappedToSameTable(ClassDescriptor cld)
+    {
+        if(cld.getFullTableName() == null)
+        {
+            return null;
+        }
+        else
+        {
+            List result = (List) classesToSameTableMap.get(cld.getFullTableName());
+            if(result == null || result.isEmpty())
+            {
+                throw new MetadataException("Inconsistent metadata detected, the specified descriptor for class "
+                        + cld.getClassNameOfObject() + " seems not or only partially registered");
+            }
+            return result;
+        }
+    }
+
+// replaced by #getClassesMappedToSameTable
+//    private List getAllMappedToSameTable(ClassDescriptor cld)
+//    {
+//        /*
+//        try to find an extent that contains clazz
+//        clone map to avoid synchronization problems, because another thread
+//        can do a put(..) operation on descriptor table
+//        */
+//        Iterator iter = ((HashMap)descriptorTable.clone()).values().iterator();
+//        List retval = new ArrayList();
+//        /*
+//        make sure that target class is at first position
+//        this is mandatory, because only this way we can guarantee to extract
+//        the correct field-descriptor in method #getAllMappedColumns
+//        */
+//        retval.add(cld);
+//        while (iter.hasNext())
+//        {
+//            ClassDescriptor tmpCld = (ClassDescriptor) iter.next();
+//            if (tmpCld.getFullTableName() != null)
+//            {
+//                if (tmpCld.getFullTableName().equals(cld.getFullTableName())
+//                        && !cld.getClassOfObject().equals(tmpCld.getClassOfObject()))
+//                {
+//                    retval.add(tmpCld);
+//                }
+//            }
+//        }
+//        return retval;
+//    }
+
+    /**
+     * Return a list of sub-class {@link ClassDescriptor} mapped to the same table
+     * as the specified class using OJB's table-per-hierarchy inheritence via
+     * extent-declaration.
+     *
+     * @param cld The source class descriptor.
+     * @return A list of found descriptor. If the specified class isn't mapped
+     * to a table <em>null</em> will be returned. If no sub-classes can be found
+     * an empty list is returned.
+     * @see #getSubClassesMultipleJoinedTables(ClassDescriptor, boolean)
+     * @see #getClassesMappedToSameTable(ClassDescriptor)
+     */
+    public List getSubClassesMappedToSameTable(ClassDescriptor cld)
+    {
+        if(m_subClassesToSameTableMap == null)
+        {
+            m_subClassesToSameTableMap = new HashMap();
+        }
+        // we can't do anything if class is not mapped to a table
+        if(cld.getFullTableName() == null) return null;
+
+        List result = (List) m_subClassesToSameTableMap.get(cld);
+        if(result == null)
+        {
+            result = new ArrayList();
+            Collection extents = getSubclassDescriptors(cld);
+            if(extents != null)
+            {
+                for(Iterator iterator = extents.iterator(); iterator.hasNext();)
+                {
+                    ClassDescriptor tmp = (ClassDescriptor) iterator.next();
+                    if(cld.getFullTableName().equals(tmp.getFullTableName()))
+                    {
+                        result.add(tmp);
+                    }
+                }
+            }
+            m_subClassesToSameTableMap.put(cld, result);
+        }
+        return result;
     }
 
     /**
      * Return the first found concrete class {@link ClassDescriptor}.
      * This means a class which is not an interface or an abstract class.
      * If given class descriptor is a concrete class, given class descriptor
-     * was returned. If no concrete class can be found <code>null</code> will be
-     * returned.
+     * was returned.
+     *
+     * @param cld The {@link ClassDescriptor} to search for concrete class.
+     * @return The first found concrete class or if the specified class is
+     * already a non-interface or abstract class.
      */
     public ClassDescriptor findFirstConcreteClass(ClassDescriptor cld)
     {
@@ -350,8 +466,8 @@
                 }
                 else
                 {
-                    LoggerFactory.getDefaultLogger().error("["+this.getClass().getName()+"] Found interface/abstract class" +
-                            " in metadata declarations without concrete class: "+cld.getClassNameOfObject());
+                    log.error("Found interface/abstract class in metadata declarations without " +
+                            "concrete class extent: "+cld.getClassNameOfObject());
                 }
                 m_firstConcreteClassMap.put(cld.getClassNameOfObject(), result);
             }
@@ -368,44 +484,66 @@
      * of a given super class.
      *
      * @return a collection of ClassDescriptor objects
+     * @deprecated please use {@link #getSubclassDescriptors(org.apache.ojb.broker.metadata.ClassDescriptor)}.
      */
     public Collection getAllConcreteSubclassDescriptors(ClassDescriptor aCld)
     {
+        return getSubclassDescriptors(aCld);
+    }
+
+    /**
+     * Utility method to discover all concrete (none abstract or interface) sub-class
+     * {@link ClassDescriptor} of the specified class using OJB's extent-declaration -
+     * includes all class mapping using table-per-hierarchy or table-per-class inheritance
+     * via OJB's extent-declaration.
+     *
+     * @return A collection of {@link ClassDescriptor} objects.
+     */
+    public Collection getSubclassDescriptors(ClassDescriptor cld)
+    {
         if(m_allConcreteSubClass == null)
         {
             m_allConcreteSubClass = new HashMap();
         }
-        Collection concreteSubclassClds = (Collection) m_allConcreteSubClass.get(aCld.getClassOfObject());
+        Collection concreteSubclassClds = (Collection) m_allConcreteSubClass.get(cld.getClassOfObject());
 
         if (concreteSubclassClds == null)
         {
-            // BRJ: ListOrderedSet prevents duplicates and ensures the order.
-            concreteSubclassClds = new ListOrderedSet();
-            Iterator iter = aCld.getExtentClasses().iterator();
+            // BRJ: As long as we do not have an ordered Set
+            // duplicates have to be prevented manually.
+            // a HashSet should not be used because the order is unpredictable
+            concreteSubclassClds = new ArrayList();
+            Iterator iter = cld.getExtentClasses().iterator();
 
             while (iter.hasNext())
             {
                 Class extentClass = (Class) iter.next();
                 ClassDescriptor extCld = getDescriptorFor(extentClass);
-                if (aCld.equals(extCld))
+                if (cld.equals(extCld))
                 {
                     // prevent infinite recursion caused by cyclic references
                     continue;
                 }
                 if (!extCld.isInterface() && !extCld.isAbstract())
                 {
-                    concreteSubclassClds.add(extCld);
+                    if (!concreteSubclassClds.contains(extCld))
+                    {
+                        concreteSubclassClds.add(extCld);
+                    }
                 }
 
                 // recurse
-                Iterator subIter = getAllConcreteSubclassDescriptors(extCld).iterator();
+                Iterator subIter = getSubclassDescriptors(extCld).iterator();
                 while (subIter.hasNext())
                 {
                     ClassDescriptor subCld = (ClassDescriptor)subIter.next();
-                    concreteSubclassClds.add(subCld);
+                    if (!concreteSubclassClds.contains(subCld))
+                    {
+                        concreteSubclassClds.add(subCld);
+                    }
                 }
             }
-            m_allConcreteSubClass.put(aCld.getClassOfObject(), concreteSubclassClds);
+            m_allConcreteSubClass.put(cld.getClassOfObject(), concreteSubclassClds);
         }
 
         return concreteSubclassClds;
@@ -454,8 +592,13 @@
     }
 
     /**
-     * Add a ClassDescriptor to the internal Hashtable<br>
-     * Set the Repository for ClassDescriptor
+     * Register an persistence capable class and add a {@link ClassDescriptor}
+     * - it's important that the added instance is completely configurated before
+     * before calling this method.
+     *
+     * @param c The class to register.
+     * @param cld The associated {@link ClassDescriptor}.
+     * @see #remove(Class) to remove an added descriptor.
      */
     public void put(Class c, ClassDescriptor cld)
     {
@@ -463,26 +606,60 @@
     }
 
     /**
-     * Add a ClassDescriptor to the internal Hashtable<br>
-     * Set the Repository for ClassDescriptor
+     * Register an persistence capable class and add a {@link ClassDescriptor}
+     * - it's important that the added instance is completely configurated before
+     * before calling this method.
+     *
+     * @param classname The full qualified class name to register.
+     * @param cld The associated {@link ClassDescriptor}.
+     * @see #remove(String) to remove an added descriptor.
      */
     public void put(String classname, ClassDescriptor cld)
     {
         cld.setRepository(this); // BRJ
         synchronized (descriptorTable)
         {
+            if(descriptorTable.containsKey(classname))
+            {
+//                try{throw new Exception("Warn: New class-descriptor added (without removing the old one first) for: "
+//                        + classname);}catch(Exception e)
+//                {
+//                    log.warn("Replace already registered class '" + classname + "' with descriptor " + cld, e);
+//                }
+                log.warn("Replace already registered class '" + classname + "' with descriptor " + cld);
+            }
             descriptorTable.put(classname, cld);
             List extentClasses = cld.getExtentClasses();
             for (int i = 0; i < extentClasses.size(); ++i)
             {
-                addExtent(((Class) extentClasses.get(i)).getName(), cld);
+                addSuperClassForExtent(((Class) extentClasses.get(i)), cld);
             }
+            registerClassesMappedToSameTable(cld);
             changeDescriptorEvent();
         }
     }
 
+    /**
+     * Remove an registered {@link ClassDescriptor} of a persistence
+     * capable object.
+     * <br/>
+     * NOTE: All <em>extent class</em> entries of this class in other classes will be removed too.
+     *
+     * @param className The full qualified class name.
+     * @see #put(String, ClassDescriptor) to add an {@link ClassDescriptor}.
+     */
     public void remove(String className)
     {
+        Class clazz = null;
+        try
+        {
+            clazz = ClassHelper.getClass(className);
+        }
+        catch(ClassNotFoundException e)
+        {
+            log.error("Remove of class fails: Unable to find class [" + className
+                + "]. Make sure it is available on the classpath.", e);
+        }
         synchronized (descriptorTable)
         {
             ClassDescriptor cld = (ClassDescriptor) descriptorTable.remove(className);
@@ -494,32 +671,47 @@
                 {
                     ((ClassDescriptor) it.next()).removeExtentClass(className);
                 }
-                removeExtent(className);
+                removeSuperClassForExtent(clazz);
                 List extentClasses = cld.getExtentClasses();
                 for (int i = 0; i < extentClasses.size(); ++i)
                 {
-                    removeExtent(((Class) extentClasses.get(i)).getName());
+                    removeSuperClassForExtent(((Class) extentClasses.get(i)));
                 }
+                deregisterClassesToSameTable(cld);
                 changeDescriptorEvent();
                 // deregister classes using mapping of classes to multiple joined tables
                 // the registration is done by the class-descriptor itself
-                deregisterSuperClassMultipleJoinedTables(cld);
+                deregisterTablePerSubclassInheritance(cld);
             }
         }
     }
 
+    /**
+     * Remove an registered {@link ClassDescriptor} of a persistence
+     * capable object.
+     * <br/>
+     * NOTE: All <em>extent class</em> entries of this class in other classes will be removed too.
+     *
+     * @param clazz The class.
+     * @see #put(Class, ClassDescriptor) to add an {@link ClassDescriptor}.
+     */
     public void remove(Class clazz)
     {
         remove(clazz.getName());
     }
 
-    private synchronized void changeDescriptorEvent()
+    /**
+     * Remove an registered {@link ClassDescriptor} of a persistence
+     * capable object.
+     * <br/>
+     * NOTE: All <em>extent class</em> entries of this class in other classes will be removed too.
+     *
+     * @param cld The {@link ClassDescriptor} of the class.
+     * @see #put(Class, ClassDescriptor) to add an {@link ClassDescriptor}.
+     */
+    public void remove(ClassDescriptor cld)
     {
-        m_multiMappedTableMap = null;
-        m_topLevelClassTable = null;
-        m_firstConcreteClassMap = null;
-        m_allConcreteSubClass = null;
-        m_batchConnectionKeyToFKMap = null;
+        remove(cld.getClassNameOfObject());
     }
 
     /**
@@ -534,89 +726,6 @@
     }
 
     /**
-     * Returns the defaultIsolationLevel.
-     * @return int
-     */
-    public int getDefaultIsolationLevel()
-    {
-        return defaultIsolationLevel;
-    }
-
-    /**
-     * Sets the defaultIsolationLevel.
-     * @param defaultIsolationLevel The defaultIsolationLevel to set
-     */
-    public void setDefaultIsolationLevel(int defaultIsolationLevel)
-    {
-        this.defaultIsolationLevel = defaultIsolationLevel;
-    }
-
-    /**
-     * returns a string representation
-     */
-    public String toString()
-    {
-        Iterator it = descriptorTable.entrySet().iterator();
-        ToStringBuilder buf = new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE);
-        String className = "class name: ";
-        String tableName = "> table name: ";
-        while (it.hasNext())
-        {
-            Map.Entry me = (Map.Entry) it.next();
-            ClassDescriptor descriptor = (ClassDescriptor) me.getValue();
-            buf.append(className + me.getKey() + " =", tableName + descriptor.getFullTableName());
-        }
-        return buf.toString();
-    }
-
-    /*
-     * @see XmlCapable#toXML()
-     */
-    public String toXML()
-    {
-        String eol = SystemUtils.LINE_SEPARATOR;
-        StringBuffer buf = new StringBuffer();
-
-        // write all ClassDescriptors
-        Iterator i = this.iterator();
-        while (i.hasNext())
-        {
-            buf.append(((XmlCapable) i.next()).toXML()).append(eol);
-        }
-        return buf.toString();
-    }
-
-    /**
-     * returns IsolationLevel literal as matching
-     * to the corresponding id
-     * @return the IsolationLevel literal
-     */
-    protected String getIsolationLevelAsString()
-    {
-        if (defaultIsolationLevel == IL_READ_UNCOMMITTED)
-        {
-            return LITERAL_IL_READ_UNCOMMITTED;
-        }
-        else if (defaultIsolationLevel == IL_READ_COMMITTED)
-        {
-            return LITERAL_IL_READ_COMMITTED;
-        }
-        else if (defaultIsolationLevel == IL_REPEATABLE_READ)
-        {
-            return LITERAL_IL_REPEATABLE_READ;
-        }
-        else if (defaultIsolationLevel == IL_SERIALIZABLE)
-        {
-            return LITERAL_IL_SERIALIZABLE;
-        }
-        else if (defaultIsolationLevel == IL_OPTIMISTIC)
-        {
-            return LITERAL_IL_OPTIMISTIC;
-        }
-        return LITERAL_IL_READ_UNCOMMITTED;
-    }
-
-    /**
      * Starts by looking to see if the <code>className</code> is
      * already mapped specifically to the descritpor repository.
      * If the <code>className</code> is not specifically mapped we
@@ -698,16 +807,16 @@
     }
 
     /**
-     * Internal used! Register sub-classes of specified class when mapping class to
-     * multiple joined tables is used. Normally this method is called by the {@link ClassDescriptor}
-     * itself.
+     * Internal used! Register the specified class as sub-class of it's base class.
+     * Specific method when table per subclass inheritance is used. Normally this
+     * method is called by the {@link ClassDescriptor} itself.
      *
      * @param cld The {@link ClassDescriptor} of the class to register.
      */
-    protected void registerSuperClassMultipleJoinedTables(ClassDescriptor cld)
+    protected void registerTablePerSubclassInheritance(ClassDescriptor cld)
     {
         /*
-        arminw: Sadly, we can't map to sub class-descriptor, because it's not guaranteed
+        arminw: Unfortunately, we can't map class-descriptors, because it's not guaranteed
         that they exist when this method is called. Thus we map the class instance instead
         of the class-descriptor.
         */
@@ -750,7 +859,7 @@
      *
      * @param cld The {@link ClassDescriptor} of the class to register.
      */
-    protected void deregisterSuperClassMultipleJoinedTables(ClassDescriptor cld)
+    protected void deregisterTablePerSubclassInheritance(ClassDescriptor cld)
     {
         try
         {
@@ -790,44 +899,73 @@
 
     /**
      * Return <em>sub-classes</em> of the specified class using the
-     * <em>"super"-Reference</em> concept.
+     * <em>"super"-Reference</em> concept - table-per-subclass inheritance.
+     *
      * @param cld The {@link ClassDescriptor} of the class to search for sub-classes.
      * @param wholeTree If set <em>true</em>, the whole sub-class tree of the specified
      * class will be returned. If <em>false</em> only the direct sub-classes of the specified class
      * will be returned.
      * @return An array of <em>sub-classes</em> for the specified class.
+     * @see #getClassesMappedToSameTable(ClassDescriptor)
+     * @see #getSubClassesMappedToSameTable(ClassDescriptor)
      */
     public Class[] getSubClassesMultipleJoinedTables(ClassDescriptor cld, boolean wholeTree)
     {
-        ArrayList result = new ArrayList();
-        createResultSubClassesMultipleJoinedTables(result, cld, wholeTree);
-        return (Class[]) result.toArray(new Class[result.size()]);
+        List result = createResultSubClassesMultipleJoinedTables(cld, wholeTree);
+        return result != null ? (Class[]) result.toArray(new Class[result.size()]) : new Class[]{};
     }
 
     /**
      * Add all sub-classes using multiple joined tables feature for specified class.
-     * @param result The list to add results.
+     *
      * @param cld The {@link ClassDescriptor} of the class to search for sub-classes.
      * @param wholeTree If set <em>true</em>, the whole sub-class tree of the specified
      * class will be returned. If <em>false</em> only the direct sub-classes of the specified class
      * will be returned.
+     * @return A list of sub classes or <em>null</em> if none found.
      */
-    private void createResultSubClassesMultipleJoinedTables(List result, ClassDescriptor cld, boolean wholeTree)
+    private List createResultSubClassesMultipleJoinedTables(ClassDescriptor cld, boolean wholeTree)
     {
         List tmp = (List) superClassMultipleJoinedTablesMap.get(cld.getClassOfObject());
-        if(tmp != null)
+        if(wholeTree && tmp != null && tmp.size() > 0)
         {
-            result.addAll(tmp);
-            if(wholeTree)
+            ArrayList list = new ArrayList(tmp);
+            for(int i = 0; i < tmp.size(); i++)
             {
-                for(int i = 0; i < tmp.size(); i++)
-                {
-                    Class subClass = (Class) tmp.get(i);
-                    ClassDescriptor subCld = getDescriptorFor(subClass);
-                    createResultSubClassesMultipleJoinedTables(result, subCld, wholeTree);
-                }
+                Class subClass = (Class) tmp.get(i);
+                ClassDescriptor subCld = getDescriptorFor(subClass);
+                List subList = createResultSubClassesMultipleJoinedTables(subCld, wholeTree);
+                if(subList != null) list.addAll(subList);
             }
+            tmp = list;
         }
+        return tmp;
+    }
+
+    /**
+     * Returns whether or not mapped classes should be included in
+     * object state detection. Default state is <em>true</em>.
+     *
+     * @return If <em>true</em> the classes will be included in
+     * automatic object state detection.
+     * @see #setStateDetection(boolean)
+     */
+    public boolean isStateDetection()
+    {
+        return stateDetection;
+    }
+
+    /**
+     * If the used API supports object state detection (e.g. ODMG-api does),
+     * this attribute indicate whether or not this mapped classes should be
+     * included in object state detection (automatic check for changed object fields).
+     *
+     * @param stateDetection Set <em>true</em> if automatic state detection should
+     * be enabled.
+     */
+    public void setStateDetection(boolean stateDetection)
+    {
+        this.stateDetection = stateDetection;
     }
 
     /**
@@ -904,17 +1042,15 @@
     {
         String tableName;
         HashSet tableNamesSet = new HashSet();
-        Collection extents = desc.getExtentClasses();
-
         tableName = desc.getFullTableName();
         if (tableName != null)
         {
             tableNamesSet.add(tableName);
         }
+        Collection extents = getSubclassDescriptors(desc);
         for (Iterator it = extents.iterator(); it.hasNext();)
         {
-            Class extClass = (Class) it.next();
-            ClassDescriptor extDesc = getDescriptorFor(extClass);
+            ClassDescriptor extDesc = (ClassDescriptor) it.next();
             tableName = extDesc.getFullTableName();
             if (tableName != null)
             {
@@ -925,34 +1061,85 @@
     }
 
     /**
-     * Returns whether or not mapped classes should be included in
-     * object state detection. Default state is <em>true</em>.
-     *
-     * @return If <em>true</em> the classes will be included in
-     * automatic object state detection.
-     * @see #setStateDetection(boolean)
+     * Returns the defaultIsolationLevel.
+     * @return int
      */
-    public boolean isStateDetection()
+    public int getDefaultIsolationLevel()
     {
-        return stateDetection;
+        return defaultIsolationLevel;
     }
 
     /**
-     * If the used API supports object state detection (e.g. ODMG-api does),
-     * this attribute indicate whether or not this mapped classes should be
-     * included in object state detection (automatic check for changed object fields).
-     *
-     * @param stateDetection Set <em>true</em> if automatic state detection should
-     * be enabled.
+     * Sets the defaultIsolationLevel.
+     * @param defaultIsolationLevel The defaultIsolationLevel to set
      */
-    public void setStateDetection(boolean stateDetection)
+    public void setDefaultIsolationLevel(int defaultIsolationLevel)
     {
-        this.stateDetection = stateDetection;
+        this.defaultIsolationLevel = defaultIsolationLevel;
+    }
+
+    /**
+     * returns IsolationLevel literal as matching
+     * to the corresponding id
+     * @return the IsolationLevel literal
+     */
+    protected String getIsolationLevelAsString()
+    {
+        if (defaultIsolationLevel == IL_READ_UNCOMMITTED)
+        {
+            return LITERAL_IL_READ_UNCOMMITTED;
+        }
+        else if (defaultIsolationLevel == IL_READ_COMMITTED)
+        {
+            return LITERAL_IL_READ_COMMITTED;
+        }
+        else if (defaultIsolationLevel == IL_REPEATABLE_READ)
+        {
+            return LITERAL_IL_REPEATABLE_READ;
+        }
+        else if (defaultIsolationLevel == IL_SERIALIZABLE)
+        {
+            return LITERAL_IL_SERIALIZABLE;
+        }
+        else if (defaultIsolationLevel == IL_OPTIMISTIC)
+        {
+            return LITERAL_IL_OPTIMISTIC;
+        }
+        return LITERAL_IL_READ_UNCOMMITTED;
     }
 
-    protected void finalize() throws Throwable
+    /**
+     * returns a string representation
+     */
+    public String toString()
     {
-        log.info("# finalize DescriptorRepository instance #");
-        super.finalize();
+        Iterator it = descriptorTable.entrySet().iterator();
+        ToStringBuilder buf = new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE);
+        String className = "class name: ";
+        String tableName = "> table name: ";
+        while (it.hasNext())
+        {
+            Map.Entry me = (Map.Entry) it.next();
+            ClassDescriptor descriptor = (ClassDescriptor) me.getValue();
+            buf.append(className + me.getKey() + " =", tableName + descriptor.getFullTableName());
+        }
+        return buf.toString();
+    }
+
+    /*
+     * @see XmlCapable#toXML()
+     */
+    public String toXML()
+    {
+        String eol = SystemUtils.LINE_SEPARATOR;
+        StringBuffer buf = new StringBuffer();
+
+        // write all ClassDescriptors
+        Iterator i = this.iterator();
+        while (i.hasNext())
+        {
+            buf.append(((XmlCapable) i.next()).toXML()).append(eol);
+        }
+        return buf.toString();
     }
 }



---------------------------------------------------------------------
To unsubscribe, e-mail: ojb-dev-unsubscribe@db.apache.org
For additional commands, e-mail: ojb-dev-help@db.apache.org