/*****************************************************************************/
/* File name: Registry.java                                                  */
/* Purpose: to register mount Entry objects                                  */
/*                                                                           */
/* Last modified: 15.08.99                                                   */
/* Author: Victor Klimov, 1999                                               */
/*                                                                           */
/* This program is distributed in the hope that it will be useful, but       */
/* WITHOUT ANY WARRANTY; without even the implied warranty of                */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General */
/* Public License for more details.                                          */
/*                                                                           */
/* This software is distributed under the terms                              */
/* of the GNU General Public License as published                            */
/* by the Free Software Foundation; either version 2, or (at your option)    */
/* any later version.                                                        */
/* See file COPYING for your rights (GNU GPL)                                */
/*****************************************************************************/


package mount;


import java.io.*;
import java.util.*;
import io.*;


public
class

Registry
          implements Serializable
{

  private final static String RCSID =
"$Header: /d/NFS/mount/RCS/Registry.java,v 1.13 1999/08/15 23:38:59 vklimov Exp $";


  protected DirPathHashtable dirPathHashtable = null;
  protected Hashtable fileHandlesHashtable = null;
  protected int nEntries = 0;
  protected boolean saveByPutAndClear = true;
  protected static long currentFileId = Constants.FILE_ID_NOT_VALID;
  protected String cacheDir = null;


  public

  Registry( String cacheDir )
/*****************************************************************************/
/* Function name: Registry                                                   */
/* File name: Registry.java                                                  */
/* Purpose: constructor for the Registry class                               */
/* Parameters: cacheDir                                                      */
/* Returns:                                                                  */
/* Last modified: 15.08.99                                                   */
/* Author: Victor Klimov, 1999                                               */
/*****************************************************************************/
    {
                                                       /* Registry */
/*---------------------------------------------------------------------------*/

      this.cacheDir = cacheDir;

      dirPathHashtable = new DirPathHashtable();

      fileHandlesHashtable = new
        Hashtable();

    }
/*end of Registry*/


  public

  Registry( boolean saveByPutAndClear,
            String cacheDir            )
/*****************************************************************************/
/* Function name: Registry                                                   */
/* File name: Registry.java                                                  */
/* Purpose: constructor for the Registry class                               */
/* Parameters: saveByPutAndClear                                             */
/*             cacheDir                                                      */
/* Returns:                                                                  */
/* Last modified: 15.08.99                                                   */
/* Author: Victor Klimov, 1999                                               */
/*****************************************************************************/
    {
                                                       /* Registry */
/*---------------------------------------------------------------------------*/

      this.saveByPutAndClear = saveByPutAndClear;
      this.cacheDir = cacheDir;

      dirPathHashtable = new DirPathHashtable();

      fileHandlesHashtable = new
        Hashtable();

    }
/*end of Registry*/


  public
  synchronized
  void

  save()
/*****************************************************************************/
/* Function name: save                                                       */
/* File name: Registry.java                                                  */
/* Purpose: to save this Registry object into a file in the current dir      */
/* Parameters:                                                               */
/* Returns:                                                                  */
/* Last modified: 15.06.99                                                   */
/* Author: Victor Klimov, 1999                                               */
/*****************************************************************************/
    {
      FileOutputStream fileOutputStream = null;
      ObjectOutputStream
        registryOutputStream = null;
                                                         /* save */
/*---------------------------------------------------------------------------*/

      try
        {
          fileOutputStream = new
            FileOutputStream( Constants.REGISTRY_SAVE_FILE_NAME );
          registryOutputStream = new
            ObjectOutputStream( fileOutputStream );
          registryOutputStream.writeObject( this );
          registryOutputStream.close();
          fileOutputStream.close();
        }
      catch( IOException e )
        {
          System.out.println( "*** Registry, method \'save\': " +
                              "can\'t write to file " +
                              Constants.REGISTRY_SAVE_FILE_NAME +
                              "\n" + e.getMessage()                  );
        }
    /*end of try-catch*/

    }
/*end of save*/


  public
  static
  synchronized
  Registry

  restore()
/*****************************************************************************/
/* Function name: restore                                                    */
/* File name: Registry.java                                                  */
/* Purpose: to restore this Registry object from a file in the current dir   */
/* Parameters:                                                               */
/* Returns: a registry object or null in case of an error                    */
/* Last modified: 15.06.99                                                   */
/* Author: Victor Klimov, 1999                                               */
/*****************************************************************************/
    {
      Registry result = null;
      ObjectInputStream registryInputStream = null;
      FileInputStream fileInputStream = null;
                                                         /* restore */
/*---------------------------------------------------------------------------*/

      try
        {
          fileInputStream = new
            FileInputStream(
              Constants.REGISTRY_SAVE_FILE_NAME );
          registryInputStream = new
            ObjectInputStream( fileInputStream );
          result = (Registry)
            registryInputStream.readObject();
          registryInputStream.close();
          return result;                                   /* return ! */
        }
      catch( FileNotFoundException e )
        {
          System.out.println( "*** Registry, restore: " +
                              "can\'t find file " +
                              Constants.REGISTRY_SAVE_FILE_NAME +
                              "\n" + e.getMessage()                  );
        }
      catch( SecurityException e )
        {
          System.out.println( "*** Registry, restore: " +
                              "can\'t read file " +
                              Constants.REGISTRY_SAVE_FILE_NAME +
                              "not permitted\n" + e.getMessage()   );
        }
      catch( IOException e )
        {
          System.out.println( "*** Registry, restore: " +
                              "can\'t read file " +
                              Constants.REGISTRY_SAVE_FILE_NAME +
                              "\n" + e.getMessage()                );
        }
      catch( ClassNotFoundException e )
        {
          System.out.println( "*** Registry, restore: " +
                              "can\'t find a class\n" +
                              e.getMessage()                     );
        }
    /*end of try-catch*/

      return null;

    }
/*end of restore*/


  public
  synchronized
  boolean

  put( Entry mountEntry )
/*****************************************************************************/
/* Function name: put                                                        */
/* File name: Registry.java                                                  */
/* Purpose: to register a mount Entry                                        */
/* Parameters: mountEntry                                                    */
/* Returns: true - if registered OK, false - otherwise                       */
/* Last modified: 22.06.99                                                   */
/* Author: Victor Klimov, 1999                                               */
/*****************************************************************************/
    {
      String dirPath = null;
      String hostName = null;
      boolean resultFileHandlePut;
      Fhandle fileHandle = null;
      Long fileHandleKey = null;
      boolean containsThisMountEntry;
      HostNameHashtable hostNameHashtable = null;
                                                               /* put */
/*---------------------------------------------------------------------------*/


      if (mountEntry == null)
        return false;                                      /* return ! */
      else
        ;
    /*end of if*/

      dirPath = mountEntry.getDirPath();
      hostName = mountEntry.getHostName();

      hostNameHashtable = (HostNameHashtable)
        dirPathHashtable.get( (Object) dirPath );

      if (hostNameHashtable == null)                    /* have to create   */
        {                                              /* hostNameHashtable */
          hostNameHashtable = new
            HostNameHashtable();
          hostNameHashtable.put(
            (Object) hostName,
            (Object) mountEntry            );
          dirPathHashtable.put(
            (Object) dirPath,
            (Object) hostNameHashtable  );
        }
      else /* OK got hostNameHashtable */
        {
          containsThisMountEntry =
            hostNameHashtable.
              containsKey( (Object) hostName );

          if (containsThisMountEntry)                 /* have already ! */
            {
              return false;                              /* return ! */
            }
          else /* OK, may put this mountEntry */
            {
              hostNameHashtable.put(
                (Object) hostName,
                (Object) mountEntry           );
            }
        /*end of if on containsThisMountEntry*/

        }
    /*end of if on hostNameHashtable*/

      fileHandle =
        mountEntry.getFileHandle();

      resultFileHandlePut = put( fileHandle );

      if (resultFileHandlePut)
        {
          nEntries++;

          fileHandle.markAsAMountedFileSystem();

          return true;                                       /* return ! */
        }
      else
        {
          hostNameHashtable.remove(
            (Object) hostName       );
          return false;                                      /* return ! */
        }
    }
/*end of put*/


  public
  synchronized
  boolean

  put( Fhandle fileHandle )
/*****************************************************************************/
/* Function name: put                                                        */
/* File name: Registry.java                                                  */
/* Purpose: to register a file handle                                        */
/* Parameters: fileHandle                                                    */
/* Returns: true - if registered OK, false - otherwise                       */
/* Last modified: 24.07.99                                                   */
/* Author: Victor Klimov, 1999                                               */
/*****************************************************************************/
    {
      long fileId;
      Long fileHandleKey = null;
                                                               /* put */
/*---------------------------------------------------------------------------*/


      if (fileHandle == null)
        return false;                                        /* return ! */
      else
        ;
    /*end of if*/

      fileId = fileHandle.getFileId();
      fileHandleKey = new Long( fileId );

      fileHandlesHashtable.put(
        (Object) fileHandleKey,
        (Object) fileHandle     );

      if (saveByPutAndClear)
        save();
      else
        ;
    /*end of if*/

      return true;

    }
/*end of put*/


  public
  synchronized
  boolean

  remove( Fhandle fileHandle )
/*****************************************************************************/
/* Function name: remove                                                     */
/* File name: Registry.java                                                  */
/* Purpose: to unregister a file handle                                      */
/* Parameters: fileHandle                                                    */
/* Returns: true - if unregistered OK, false - otherwise                     */
/* Last modified: 22.06.99                                                   */
/* Author: Victor Klimov, 1999                                               */
/*****************************************************************************/
    {
      Long fileHandleKey = null;
                                                               /* remove */
/*---------------------------------------------------------------------------*/


      if (fileHandle == null)
        return true;                                        /* return ! */
      else
        ;
    /*end of if*/

      fileHandleKey = new Long( fileHandle.getFileId() );
      fileHandlesHashtable.remove(
        (Object) fileHandleKey     );

      return true;

    }
/*end of remove*/


  public
  synchronized
  Fhandle

  get( long fileId )
/*****************************************************************************/
/* Function name: get                                                        */
/* File name: Registry.java                                                  */
/* Purpose: to get a file handle based on the fileId                         */
/* Parameters: fileId                                                        */
/* Returns: the file handle or null if not found or in case of an error      */
/* Last modified: 21.06.99                                                   */
/* Author: Victor Klimov, 1999                                               */
/*****************************************************************************/
    {
      Fhandle fileHandle = null;
      Long fileHandleKey = null;
                                                               /* get */
/*---------------------------------------------------------------------------*/

      if (fileId < 0)
        return null;                                        /* return ! */
      else
        ;
    /*end of if*/

      fileHandleKey = new Long( fileId );
      fileHandle = (Fhandle)
        fileHandlesHashtable.get(
          (Object) fileHandleKey  );

      return fileHandle;

    }
/*end of get*/


  public
  synchronized
  void

  clearFileHandles( String dirPath )
/*****************************************************************************/
/* Function name: clearFileHandles                                           */
/* File name: Registry.java                                                  */
/* Purpose: to remove file handles beginning with the specific prefix        */
/*          from the fileHandlesHashtable                                    */
/* Parameters: dirPath                                                       */
/* Returns:                                                                  */
/* Last modified: 15.08.99                                                   */
/* Author: Victor Klimov, 1999                                               */
/*****************************************************************************/
    {
      int i;
      long fileId = 0;
      Long fileHandleKey = null;
      String currentDirPath = null;
      Fhandle fileHandle = null;
      Enumeration fileHandles = null;
                                                     /* clearFileHandles */
/*---------------------------------------------------------------------------*/

      dirPath = util.String.
        removeTrailingPathSeparator(
          dirPath                    );
      dirPath = dirPath + File.separator;

      fileHandles = fileHandlesHashtable.elements();

      i = 0;
      while( fileHandles.hasMoreElements() )
        {
          try
            {
              fileHandle = (Fhandle)
                fileHandles.nextElement();

              currentDirPath =
                fileHandle.getDirPath();

              if ( currentDirPath.startsWith( dirPath ) )
                {
                  fileId = fileHandle.getFileId();
                  FileSystemExpert.processUnmount( fileHandle,
                                                   cacheDir    );
                  fileHandleKey = new Long( fileId );
                  fileHandlesHashtable.remove(
                    (Object) fileHandleKey     );
                }
              else
                ;
            /*end of if on startsWith*/

            }
          catch( NoSuchElementException e )
            {
              break;                                          /* break ! */
            }
        /*end of try-catch*/

          i++;

        }
    /*end of while-loop*/

      if (saveByPutAndClear)
        save();
      else
        ;
    /*end of if*/

    }
/*end of clearFileHandles*/


  public
  synchronized
  Fhandle

  get( String path )
/*****************************************************************************/
/* Function name: get                                                        */
/* File name: Registry.java                                                  */
/* Purpose: to get first file handle corresponding to the given path         */
/* Parameters: path                                                          */
/* Returns: the file handle or null if not found or in case of an error      */
/* Last modified: 24.07.99                                                   */
/* Author: Victor Klimov, 1999                                               */
/*****************************************************************************/
    {
      int i;
      String currentPath = null;
      Fhandle fileHandle = null;
      Enumeration fileHandles = null;
                                                     /* get */
/*---------------------------------------------------------------------------*/


      if (path == null)
        return null;                                   /* return ! */
      else
        ;
    /*end of if*/

      path = util.String.
        removeTrailingPathSeparator(
          path                       );

      fileHandles = fileHandlesHashtable.elements();

      i = 0;
      while( fileHandles.hasMoreElements() )
        {
          try
            {
              fileHandle = (Fhandle)
                fileHandles.nextElement();

              currentPath =
                fileHandle.getDirPath();

              if ( currentPath.equals( path ) )
                {
                  return fileHandle;                   /* return ! */
                }
              else
                ;
            /*end of if on startsWith*/

            }
          catch( NoSuchElementException e )
            {
              break;                                          /* break ! */
            }
        /*end of try-catch*/

          i++;

        }
    /*end of while-loop*/

      return null;

    }
/*end of get*/


  public
  synchronized
  boolean

  remove( Entry mountEntry )
/*****************************************************************************/
/* Function name: remove                                                     */
/* File name: Registry.java                                                  */
/* Purpose: to unregister a mountEntry                                       */
/* Parameters: mountEntry                                                    */
/* Returns: true - if unregistered OK, false - otherwise                     */
/* Last modified: 23.06.99                                                   */
/* Author: Victor Klimov, 1999                                               */
/*****************************************************************************/
    {
      Fhandle fileHandle = null;
      String dirPath = null;
      String hostName = null;
      boolean containsThisMountEntry;
      HostNameHashtable hostNameHashtable = null;
      int nRemoved;
      Long fileHandleKey = null;
      int i;
                                                               /* remove */
/*---------------------------------------------------------------------------*/

      if (mountEntry == null)
        return false;                                  /* return ! */
      else
        ;
    /*end of if on null*/

      dirPath = mountEntry.getDirPath();
      hostName = mountEntry.getHostName();
      fileHandle = mountEntry.getFileHandle();

      fileHandleKey = new Long( fileHandle.getFileId() );
      fileHandlesHashtable.remove( (Object) fileHandleKey );

      hostNameHashtable = (HostNameHashtable)
        dirPathHashtable.get( (Object) dirPath );

      if (hostNameHashtable == null)
        {
          clearFileHandles( dirPath );
        }
      else /* OK got hostNameHashtable */
        {
          mountEntry = (Entry)
            hostNameHashtable.remove(
              (Object) hostName       );

          if (mountEntry == null)
            {
            }
          else /* OK removed */
            {

              if (hostNameHashtable.size() == 0)        /* no more hosts */
                {
                  dirPathHashtable.
                    remove( (Object) dirPath );
                  clearFileHandles( dirPath );
                }
              else
                ;
            /*end of if on 0*/

              nEntries--;
              return true;                              /* return ! */
            }
        /*end of if on mountEntry*/
        }
    /*end of if on hostNameHashtable*/

      return false;

    }
/*end of remove*/


  public
  synchronized
  void

  clear()
/*****************************************************************************/
/* Function name: clear                                                      */
/* File name: Registry.java                                                  */
/* Purpose: to remove all mount entries from the registry object             */
/* Parameters:                                                               */
/* Returns:                                                                  */
/* Last modified: 21.06.99                                                   */
/* Author: Victor Klimov, 1999                                               */
/*****************************************************************************/
    {
                                                               /* clear */
/*---------------------------------------------------------------------------*/

      dirPathHashtable.clear();
      fileHandlesHashtable.clear();
      nEntries = 0;

    }
/*end of clear*/


  public
  int

  nFileHandles()
/*****************************************************************************/
/* Function name: nFileHandles                                               */
/* File name: Registry.java                                                  */
/* Purpose: to return number of file handles in this registry                */
/* Parameters:                                                               */
/* Returns: the number                                                       */
/* Last modified: 23.06.99                                                   */
/* Author: Victor Klimov, 1999                                               */
/*****************************************************************************/
    {
                                                        /* nFileHandles */
/*---------------------------------------------------------------------------*/

      if (fileHandlesHashtable == null)
        return 0;
      else
        return fileHandlesHashtable.size();
    /*end of if*/

    }
/*end of nFileHandles*/


  public
  int

  size()
/*****************************************************************************/
/* Function name: size                                                       */
/* File name: Registry.java                                                  */
/* Purpose: to return number of mount Entries in this registry               */
/* Parameters:                                                               */
/* Returns: size                                                             */
/* Last modified: 14.06.99                                                   */
/* Author: Victor Klimov, 1999                                               */
/*****************************************************************************/
    {
                                                               /* size */
/*---------------------------------------------------------------------------*/

      return nEntries;

    }
/*end of size*/


  public
  synchronized
  Enumeration

  mountEntries()
/*****************************************************************************/
/* Function name: mountEntries                                               */
/* File name: Registry.java                                                  */
/* Purpose: to return enumeration of all mount Entries in this registry      */
/* Parameters:                                                               */
/* Returns: the enumeration of mount Entries                                 */
/* Last modified: 15.06.99                                                   */
/* Author: Victor Klimov, 1999                                               */
/*****************************************************************************/
    {
                                                           /* mountEntries */
/*---------------------------------------------------------------------------*/

       return new RegistryEnumerator( this );

    }
/*end of mountEntries*/


  public
  synchronized
  boolean

  containsFileId( long fileId )
/*****************************************************************************/
/* Function name: containsFileId                                             */
/* File name: Registry.java                                                  */
/* Purpose: to check all mount Entries in this registry whether one contains */
/*          the specified file ID                                            */
/* Parameters: fileId                                                        */
/* Returns: true - if a file handle in the registry the fileId has           */
/*          false - otherwise                                                */
/* Last modified: 21.06.99                                                   */
/* Author: Victor Klimov, 1999                                               */
/*****************************************************************************/
    {
      Fhandle fileHandle;
                                                     /* containsFileId */
/*---------------------------------------------------------------------------*/

      fileHandle =
        get( fileId );

      if (fileHandle == null)
        return false;
      else
        return true;
    /*end of if*/

    }
/*end of containsFileId*/


  public
  synchronized
  String

  toString()
/*****************************************************************************/
/* Function name: toString                                                   */
/* File name: Registry.java                                                  */
/* Purpose: to represent this registry object including all mount Entries    */
/*          as a string                                                      */
/* Parameters:                                                               */
/* Returns: the string representation of this registry object                */
/* Last modified: 19.06.99                                                   */
/* Author: Victor Klimov, 1999                                               */
/*****************************************************************************/
    {
      int i;
      String result = "";
      Fhandle fileHandle = null;
      Enumeration fileHandles = null;
      Entry mountEntry = null;
      Enumeration entries = null;
                                                     /* toString */
/*---------------------------------------------------------------------------*/

      result = result +
        "Mount entries:\n";

      entries =
        mountEntries();

      i = 0;
      while( entries.hasMoreElements() )
        {
          try
            {
              mountEntry = (Entry)
                entries.nextElement();

              result = result +
                "\ni=" + i +
                "\n\t\tdirPath=" +
                mountEntry.getDirPath()     +
                "\n\t\thostName=" +
                mountEntry.getHostName();

              fileHandle =
                mountEntry.getFileHandle();
              if (fileHandle == null)
                {
                  result = result +
                    "\n\t\tfileHandle is null !";
                }
              else
                {
                  result = result +
                    "\n\t\tfileHandle=\n" +
                    "\n\t\t" + fileHandle.toString();
                }
            /*end of if*/

            }
          catch( NoSuchElementException e )
            {
              break;                                          /* break ! */
            }
        /*end of try-catch*/

          i++;

        }
    /*end of while-loop*/

      if (fileHandlesHashtable == null)
        return result;                                      /* return ! */
      else
        ;
    /*end of if*/

      fileHandles = fileHandlesHashtable.elements();

      if (fileHandles == null)
        return result;                                      /* return ! */
      else
        ;
    /*end of if*/

      result = result +
        "\nFiles:\n";

      i = 0;
      while( fileHandles.hasMoreElements() )
        {
          try
            {
              fileHandle = (Fhandle)
                fileHandles.nextElement();

              result += fileHandle.toString() + "\n";
            }
          catch( NoSuchElementException e )
            {
              break;                                          /* break ! */
            }
        /*end of try-catch*/

          i++;

        }
    /*end of while-loop*/


      return result;

    }
/*end of toString*/


  public
  synchronized
  Entry

  get( String dirPath,
       String hostName  )
/*****************************************************************************/
/* Function name: get                                                        */
/* File name: Registry.java                                                  */
/* Purpose: to get a mount Entry from this registry with the specified       */
/*          dirPath and hostName                                             */
/* Parameters: dirPath                                                       */
/*             hostName                                                      */
/* Returns: the Entry or null if there is nothing of the sort in here        */
/* Last modified: 17.06.99                                                   */
/* Author: Victor Klimov, 1999                                               */
/*****************************************************************************/
    {
      Entry mountEntry = null;
      HostNameHashtable hostNameHashtable = null;
                                                          /* get */
/*---------------------------------------------------------------------------*/


      hostNameHashtable = (HostNameHashtable)
        dirPathHashtable.get( dirPath );

      if (hostNameHashtable == null)
        return null;                                   /* return ! */
      else
        ;
    /*end of if*/

      mountEntry = (Entry)
        hostNameHashtable.get( hostName );

      return mountEntry;

    }
/*end of get*/


  public
  synchronized
  long

  getNewFileId()
/*****************************************************************************/
/* Function name: getNewFileId                                               */
/* File name: Registry.java                                                  */
/* Purpose: to get a new fileId                                              */
/* Parameters:                                                               */
/* Returns: the number                                                       */
/* Last modified: 22.06.99                                                   */
/* Author: Victor Klimov, 1999                                               */
/*****************************************************************************/
    {
                                                     /* getNewFileId */
/*---------------------------------------------------------------------------*/

      return ++currentFileId;

    }
/*end of getNewFileId*/


  public
  synchronized
  long

  getUniqueFileId()
/*****************************************************************************/
/* Function name: getUniqueFileId                                            */
/* File name: Registry.java                                                  */
/* Purpose: to get a new fileId                                              */
/* Parameters:                                                               */
/* Returns: the number or                                                    */
/*          Constants.FILE_ID_NOT_VALID if there are too many files          */
/* Last modified: 22.06.99                                                   */
/* Author: Victor Klimov, 1999                                               */
/*****************************************************************************/
    {
      long fileId;
                                                     /* getUniqueFileId */
/*---------------------------------------------------------------------------*/

      fileId = getNewFileId();
      while( containsFileId( fileId ) &&
             (fileId > 0)
           )
        {
          fileId = getNewFileId();
        }
    /*end of while-loop*/

      if (fileId > 0)
        return fileId;
      else
        return Constants.FILE_ID_NOT_VALID;
    /*end of if*/

    }
/*end of getUniqueFileId*/


  public
  static
  void

  main( String argv[] )
/*****************************************************************************/
/* Function name: main                                                       */
/* File name: Registry.java                                                  */
/* Purpose: to test the Registry class                                       */
/* Parameters: agrument strings array                                        */
/* Returns:                                                                  */
/* Last modified: 15.08.99                                                   */
/* Author: Victor Klimov, 1999                                               */
/*****************************************************************************/
    {
      int mainI;
      Fhandle fhandle;
      Registry registry;
      Entry mountEntry;
      boolean result;
      Enumeration mountEntries;
                                                           /* main */
/*---------------------------------------------------------------------------*/

      registry = new Registry( null );

      fhandle = new Fhandle( 0,  "/a/", "aaa", null );
      mountEntry = new Entry( fhandle );
      result =
        registry.put( mountEntry );
      if (!result)
        System.out.println( "put rejected for mountEntry " +
                            mountEntry.toString() );

      fhandle = new Fhandle( 1,  "/b/", "bbb", null );
      mountEntry = new Entry( fhandle );
      result =
        registry.put( mountEntry );
      if (!result)
        System.out.println( "put rejected for mountEntry " +
                            mountEntry.toString() );

      fhandle = new Fhandle( 2,  "/c/", "ccc", null );
      mountEntry = new Entry( fhandle );
      result =
        registry.put( mountEntry );
      if (!result)
        System.out.println( "put rejected for mountEntry " +
                            mountEntry.toString() );

      fhandle = new Fhandle( 3,  "/d/", "ddd", null );
      mountEntry = new Entry( fhandle );
      result =
        registry.put( mountEntry );
      if (!result)
        System.out.println( "put rejected for mountEntry " +
                            mountEntry.toString() );

      fhandle = new Fhandle( 4,  "/e/", "eee", null );
      mountEntry = new Entry( fhandle );
      result =
        registry.put( mountEntry );
      if (!result)
        System.out.println( "put rejected for mountEntry " +
                            mountEntry.toString() );

      fhandle = new Fhandle( 5,  "/f/", "fff", null );
      mountEntry = new Entry( fhandle );
      result =
        registry.put( mountEntry );
      if (!result)
        System.out.println( "put rejected for mountEntry " +
                            mountEntry.toString() );

      fhandle = new Fhandle( 6,  "/g/", "ggg", null );
      mountEntry = new Entry( fhandle );
      result =
        registry.put( mountEntry );
      if (!result)
        System.out.println( "put rejected for mountEntry " +
                            mountEntry.toString() );

      mountEntries =
        registry.mountEntries();

      for (mainI=0;mountEntries.hasMoreElements(); mainI++)
        {
          try
            {
              System.out.println( "mainI=" + mainI +
                                  " mountEntry=" +
                                  mountEntries.nextElement() );
            }
          catch( NoSuchElementException e )
            {
              System.out.println( "\n\nno more mountEntries" );
              break;                                          /* break ! */
            }
        /*end of try-catch*/
        }
    /*end of for-loop*/

    }
/*end of main*/


} /* end of Registry class */


final
class

RegistryEnumerator implements Enumeration
{

  private Registry registry;
  private int count;

  private Vector dirPathsVector = null;
  private Vector hostNamesVector = null;

  private String currentDirPath = null;
  private String currentHostName = null;
  private HostNameHashtable hostNameHashtable = null;


  public

  RegistryEnumerator( Registry registry )
/*****************************************************************************/
/* Function name: RegistryEnumerator                                         */
/* File name: Registry.java                                                  */
/* Purpose: constructor for the RegistryEnumerator class                     */
/* Parameters: registry                                                      */
/* Returns:                                                                  */
/* Last modified: 05.06.99                                                   */
/* Author: Victor Klimov, 1999                                               */
/*****************************************************************************/
    {
                                                   /* RegistryEnumerator */
/*---------------------------------------------------------------------------*/

      this.registry = registry;
      count = 0;

    }
/*end of RegistryEnumerator*/


  public
  synchronized
  void

  nullAllInstanceVariables()
/*****************************************************************************/
/* Function name: nullAllInstanceVariables                                   */
/* File name: Registry.java                                                  */
/* Purpose: to assign null to all instance variables                         */
/*          of this RegistryEnumeration object                               */
/* Parameters:                                                               */
/* Returns:                                                                  */
/* Last modified: 06.06.99                                                   */
/* Author: Victor Klimov, 1999                                               */
/*****************************************************************************/
    {
                                              /* nullAllInstanceVariables */
/*---------------------------------------------------------------------------*/

      dirPathsVector = null;
      hostNamesVector = null;

      currentDirPath = null;
      currentHostName = null;
      hostNameHashtable = null;

    }
/*end of nullAllInstanceVariables */


  public
  boolean

  hasMoreElements()
/*****************************************************************************/
/* Function name: hasMoreElements                                            */
/* File name: Registry.java                                                  */
/* Purpose: to check whether there are more mountEntries to serve up         */
/* Parameters:                                                               */
/* Returns: true - if there are more mountEntries to serve up,               */
/*          false - otherwise                                                */
/* Last modified: 14.06.99                                                   */
/* Author: Victor Klimov, 1999                                               */
/*****************************************************************************/
    {
                                                       /* hasMoreElements */
/*---------------------------------------------------------------------------*/

      if (count < registry.nEntries)
        return true;
      else
        return false;
    /*end of if*/

    }
/*end of hasMoreElements*/


  private
  synchronized
  void

  createAndFillDirPathsVector()
/*****************************************************************************/
/* Function name: createAndFillDirPathsVector                                */
/* File name: Registry.java                                                  */
/* Purpose: to create a Vector containing all dirPath strings                */
/* Parameters:                                                               */
/* Returns:                                                                  */
/* Last modified: 14.06.99                                                   */
/* Author: Victor Klimov, 1999                                               */
/*****************************************************************************/
    {
      int i;
      String dirPath;
      Enumeration dirPathStringsEnumeration;

                               /* createAndFillDirPathsVector */
/*---------------------------------------------------------------------------*/

      dirPathsVector = new Vector();

      dirPathStringsEnumeration =
        registry.dirPathHashtable.keys();

      i = 0;
      while( dirPathStringsEnumeration.hasMoreElements() )
        {
          try
            {
              dirPath = (String)
                 dirPathStringsEnumeration.nextElement() ;

              dirPathsVector.addElement(
                (Object) dirPath          );
            }
          catch( NoSuchElementException e )
            {
              break;                                             /* break ! */
            }
        /*end of try-catch*/
          i++;
        }
    /*end of while-loop on dirPathStringsEnumeration*/

      currentDirPath = (String)
        dirPathsVector.firstElement();

    }
/*end of createAndFillDirPathsVector*/


  private
  synchronized
  void

  createAndFillHostNameStringsVector()
/*****************************************************************************/
/* Function name: createAndFillHostNameStringsVector                         */
/* File name: Registry.java                                                  */
/* Purpose: to create a Vector containing all hostName strings               */
/* Parameters:                                                               */
/* Returns:                                                                  */
/* Last modified: 14.06.99                                                   */
/* Author: Victor Klimov, 1999                                               */
/*****************************************************************************/
    {
      int i;
      Enumeration hostNamesEnumeration;
      String hostName;

                               /* createAndFillHostNameStringsVector() */
/*---------------------------------------------------------------------------*/

      hostNamesVector = new Vector();

      hostNamesEnumeration =
        hostNameHashtable.keys();

      i = 0;
      while( hostNamesEnumeration.hasMoreElements() )
        {
          try
            {
              hostName = (String)
                 hostNamesEnumeration.nextElement() ;

              hostNamesVector.addElement(
                (Object) hostName );
            }
          catch( NoSuchElementException e )
            {
              break;                                             /* break ! */
            }
        /*end of try-catch*/
          i++;
        }
    /*end of while-loop on hostNamesEnumeration*/

      currentHostName = (String)
        hostNamesVector.firstElement();

    }
/*end of createAndFillHostNameStringsVector()*/


  private
  synchronized
  void

  getNewDirPathAndRemoveTheOld()
/*****************************************************************************/
/* Function name: getNewDirPathAndRemoveTheOld                               */
/* File name: Registry.java                                                  */
/* Purpose: to get a new dirPath from the Vector and remove                  */
/*          the old element from the vector                                  */
/* Parameters:                                                               */
/* Returns:                                                                  */
/* Last modified: 14.06.99                                                   */
/* Author: Victor Klimov, 1999                                               */
/*****************************************************************************/
    {
                                      /* getNewDirPathAndRemoveTheOld */
/*---------------------------------------------------------------------------*/

      try
        {
          dirPathsVector.removeElementAt( 0 );

          currentDirPath = (String)
            dirPathsVector.firstElement();
        }
      catch( NoSuchElementException e )
        {
          currentDirPath = null;
        }
      catch( ArrayIndexOutOfBoundsException e )
        {
          currentDirPath = null;
        }
    /*end of try-catch*/

    }
/*end of getNewDirPathAndRemoveTheOld*/


  private
  synchronized
  void

  getNewHostNameAndRemoveTheOld()
/*****************************************************************************/
/* Function name: getNewHostNameAndRemoveTheOld                              */
/* File name: Registry.java                                                  */
/* Purpose: to get a new hostName from the Vector and remove                 */
/*          the old element from the vector                                  */
/* Parameters:                                                               */
/* Returns:                                                                  */
/* Last modified: 14.06.99                                                   */
/* Author: Victor Klimov, 1999                                               */
/*****************************************************************************/
    {
                                       /* getNewHostNameAndRemoveTheOld */
/*---------------------------------------------------------------------------*/

      try
        {
          hostNamesVector.removeElementAt( 0 );

          currentHostName = (String)
            hostNamesVector.firstElement();
        }
      catch( NoSuchElementException e )
        {
          currentHostName = null;
        }
      catch( ArrayIndexOutOfBoundsException e )
        {
          currentHostName = null;
        }
    /*end of try-catch*/

    }
/*end of getNewHostNameAndRemoveTheOld*/


  private
  synchronized
  void

  getNewHostNameHashtable() throws NoSuchElementException
/*****************************************************************************/
/* Function name: getNewHostNameHashtable                                    */
/* File name: Registry.java                                                  */
/* Purpose: to get a new hostNameHashtable                                   */
/* Parameters:                                                               */
/* Throws: NoSuchElementException if there are no more hostNameHashtables    */
/* Returns:                                                                  */
/* Last modified: 17.06.99                                                   */
/* Author: Victor Klimov, 1999                                               */
/*****************************************************************************/
    {
                                             /* getNewHostNameHashtable */
/*---------------------------------------------------------------------------*/

      do
        {
          if (currentDirPath == null)
            {
              getNewDirPathAndRemoveTheOld();
              if (currentDirPath == null)
                {
                  nullAllInstanceVariables();
                  throw new
                    NoSuchElementException("RegistryEnumerator"); /* throw ! */
                }
              else
                ;
            /*end of if on null*/
            }
          else
            ;
        /*end of if currentDirPath*/

          hostNameHashtable = (HostNameHashtable)
            registry.dirPathHashtable.get(
              (Object) currentDirPath       );

          if (hostNameHashtable == null)
            getNewDirPathAndRemoveTheOld();
          else
            ;
        /*end of if*/

        }
      while( (hostNameHashtable == null) &&
             (currentDirPath != null)
           );

      if ( (currentDirPath == null) ||
           (hostNameHashtable == null)
         )
        {
          nullAllInstanceVariables();
          throw new
            NoSuchElementException("RegistryEnumerator");      /* throw ! */
        }
      else /* got new dirPath string */
        {
          createAndFillHostNameStringsVector();
        }
    /*end of if*/

    }
/*end of getNewHostNameHashtable*/


  public
  Object

  nextElement() throws NoSuchElementException
/*****************************************************************************/
/* Function name: nextElement                                                */
/* File name: Registry.java                                                  */
/* Purpose: to get a next element (a mountEntry) from the registry           */
/* Parameters:                                                               */
/* Throws: NoSuchElementException if there are no more mountEntries left     */
/* Returns: the next mountEntry                                              */
/* Last modified: 14.06.99                                                   */
/* Author: Victor Klimov, 1999                                               */
/*****************************************************************************/
    {
      Entry mountEntry;
                                                         /* nextElement */
/*---------------------------------------------------------------------------*/

      if (dirPathsVector == null)
        createAndFillDirPathsVector();
      else
        ;
    /*end of if*/

      do
        {
          if (hostNameHashtable == null)
            getNewHostNameHashtable();
          else
            ;
        /*end of if*/

          if (currentHostName == null)
            getNewHostNameAndRemoveTheOld();
          else
            ;
        /*end of if on currentHostName*/

          if (currentHostName == null)
            {
              getNewDirPathAndRemoveTheOld();
              getNewHostNameHashtable();
            }
          else
            ;
        /*end of if on currentHostName*/

          mountEntry = (Entry)
            hostNameHashtable.get(
              (Object) currentHostName );

          if (mountEntry != null)
            {
              getNewHostNameAndRemoveTheOld();
              count++;
              return (Object) mountEntry;                   /* return ! */
            }
          else
            getNewHostNameAndRemoveTheOld();
        /*end of if*/
        }
      while( true ); /* control goes out of the do-while loop either */
                     /* through return or by exception               */
                     /* in the getNewHostNameHashtable               */
    }
/*end of nextElement*/

} /* end of RegistryEnumerator class */

/*****************************************************************************/
/* End of file: Registry.java                                                */
/*****************************************************************************/
