docs: private void addForeignkeys(CollectionDescriptorDef collDef, TableDef tableDef)
      {
          if (!collDef.getBooleanProperty(PropertyHelper.OJB_PROPERTY_DATABASE_FOREIGNKEY, true))
          {
              // we shall not generate a database foreignkey
              return;
          }
  
          // a foreignkey is added to the table schema if for both ends of the collection
          // a table exists
          // then the foreignkey consists of:
          //   remote table  = table of collection owner
          //   local fields  = foreignkey fields in the element type 
          //   remote fields = primarykeys of the collection owner type
          ClassDescriptorDef ownerClassDef    = (ClassDescriptorDef)collDef.getOwner();
          String             elementClassName = collDef.getProperty(PropertyHelper.OJB_PROPERTY_ELEMENT_CLASS_REF);
          ClassDescriptorDef elementClassDef  = ((ModelDef)ownerClassDef.getOwner()).getClass(elementClassName);
  
          // we can only generate foreignkeys if the collection itself is not shared by
          // several classes in the hierarchy
          for (Iterator it = ownerClassDef.getAllBaseTypes(); it.hasNext();)
          {
              if (containsCollectionAndMapsToDifferentTable(collDef, tableDef, (ClassDescriptorDef)it.next()))
              {
                  return;
              }
          }
          for (Iterator it = ownerClassDef.getAllExtentClasses(); it.hasNext();)
          {
              if (containsCollectionAndMapsToDifferentTable(collDef, tableDef, (ClassDescriptorDef)it.next()))
              {
                  return;
              }
          }
  
          // We add a foreignkey to all classes in the subtype hierarchy of the element type
          // that map to a table (we're silently assuming that they contain the fk fields) 
          ArrayList candidates = new ArrayList();
  
          if (elementClassDef.getBooleanProperty(PropertyHelper.OJB_PROPERTY_GENERATE_TABLE_INFO, true))
          {
              candidates.add(elementClassDef);
          }
          for (Iterator it = elementClassDef.getAllExtentClasses(); it.hasNext();)
          {
              ClassDescriptorDef curSubTypeDef = (ClassDescriptorDef)it.next();
  
              if (curSubTypeDef.getBooleanProperty(PropertyHelper.OJB_PROPERTY_GENERATE_TABLE_INFO, true))
              {
                  candidates.add(curSubTypeDef);
              }
          }
  
          String    name            = collDef.getName();
          ArrayList remoteFields    = ownerClassDef.getPrimaryKeys();
          HashMap   processedTables = new HashMap();
  
          for (Iterator it = candidates.iterator(); it.hasNext();)
          {
              elementClassDef = (ClassDescriptorDef)it.next();
              try
              {
                  // for the element class and its subclasses
                  String elementTableName = elementClassDef.getProperty(PropertyHelper.OJB_PROPERTY_TABLE);
  
                  // ensure that tables are only processed once
                  if (!processedTables.containsKey(elementTableName))
                  {
                      ArrayList localFields     = elementClassDef.getFields(collDef.getProperty(PropertyHelper.OJB_PROPERTY_FOREIGNKEY));
                      TableDef  elementTableDef = getTable(elementTableName);
      
                      if (elementTableDef == null)
                      {
                          elementTableDef = new TableDef(elementTableName);
                          addTable(elementTableDef);
                      }
                      elementTableDef.addForeignkey(name, tableDef.getName(), getColumns(localFields), getColumns(remoteFields));
                      processedTables.put(elementTableName, null);
                  }
              }
              catch (NoSuchFieldException ex)
              {
                  // Shouldn't happen, but even if, then we're ignoring it and simply don't add the fk
              }
          }
      }