// Sample code file: FilesystemNamespace.java

// Warning: This code has been marked up for HTML

/*
   Copyright (c) 1997-1999 Novell, Inc.  All Rights Reserved.

   THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND TREATIES.
   USE AND REDISTRIBUTION OF THIS WORK IS SUBJECT TO THE LICENSE AGREEMENT
   ACCOMPANYING THE SOFTWARE DEVELOPMENT KIT (SDK) THAT CONTAINS THIS WORK.
   PURSUANT TO THE SDK LICENSE AGREEMENT, NOVELL HEREBY GRANTS TO DEVELOPER A
   ROYALTY-FREE, NON-EXCLUSIVE LICENSE TO INCLUDE NOVELL'S SAMPLE CODE IN ITS
   PRODUCT. NOVELL GRANTS DEVELOPER WORLDWIDE DISTRIBUTION RIGHTS TO MARKET,
   DISTRIBUTE, OR SELL NOVELL'S SAMPLE CODE AS A COMPONENT OF DEVELOPER'S
   PRODUCTS. NOVELL SHALL HAVE NO OBLIGATIONS TO DEVELOPER OR DEVELOPER'S
   CUSTOMERS WITH RESPECT TO THIS CODE.
*/

package com.novell.sample.snapins.filesystem;

import java.io.*;
import java.util.*;
import com.novell.application.console.snapin.*;
import com.novell.application.console.snapin.scope.*;
import com.novell.application.console.snapin.context.*;

  /**
   This is an example of a filesystem namespace. It takes the root
   directory of the current path as its root.
  */
public class FilesystemNamespace implements NamespaceSnapin
{
   /** Shell instance */
   private Shell shell = null;

   private static ObjectType directory = null;
   private static ObjectType fileType = null;
   private static ObjectType unknownType = null;
   private static Hashtable table = null;

   private static final String NamespaceUniqueID = "Novell Sample File System";

   /*
    Implementation of the property book page snap-in interface.
   */

   /**
    The getChildren() method returns the enumeration of children for the
    'parent' ObjectEntry.
   */
   public ObjectEntryEnumeration getChildren(ObjectEntry parent)
         throws NotAContainerException
   {
      File file = new File(parent.getName());
      if(!file.isDirectory())
      {
         throw new NotAContainerException();
      }
      String [] children = file.list();
      if (children != null)
      {
         return new FilesystemEnumeration(children, parent, this);
      }
      else
      {
         children = new String[1];
         children[0] = "nothing";
         return new FilesystemEnumeration(children, parent, this);
      }
   }

   public ObjectEntryEnumeration getChildren(ObjectEntry parent, ResultModifier modifier) throws NotAContainerException
   {
      return new SortModifiedEnumeration(new ResultModifiedEnumeration(getChildren(parent), modifier), modifier);
   }

   public ObjectEntryEnumeration getChildContainers(ObjectEntry parent, ResultModifier modifier) throws NotAContainerException
   {
      return new AutoPromoteObjectEntryEnumeration(getChildren(parent));
   }

   public ObjectType[] getObjectTypes(ObjectEntry referenceContext)
   {
      ObjectType[] types = new ObjectType[table.size()+2];
      types[0] = unknownType;
      types[1] = directory;

      Enumeration enum = table.elements();

      int i=2;
      while(enum.hasMoreElements())
      {
         ObjectType ot = (ObjectType) enum.nextElement();
         types[i++] = ot;
      }

      return types;
   }


   /**
    The getUniqueID() method is used to get the unique identifier or name
    of the namespace. You must return a name that the shell will use for
    the namespace being described. The unique namespace identifier is the
    key used to register snap-ins that will operate against this namespace.
    It is suggested that you return, as the uniqueID string, the package
    name and class implemented in the namespace snap-in.
    */
   public String getUniqueID()
   {
      return NamespaceUniqueID;
   }

   /**
     The getFullName() method is used to return the full name of the passed
     in ObjectEntry for which the full name is desired. The full name should
     represent a unique name in the namespace.
    */
   public String getFullName(ObjectEntry entry)
   {
      return entry.getName();
   }

   /**
     The getObjectEntry() method is used to return the ObjectEntry associated
     with a unique string, 'name'. If no ObjectEntry is found an exception is
     thrown.
    */
   public ObjectEntry getObjectEntry(String name)
         throws ObjectNotFoundException
   {
      return makeObjectEntry(name, null);
   }

   /**
     The getInitialObjectEntries() method is used to return the root ObjectEntry
     array. Null can be returned if there are no root object entries in the
     namespace.
    */
   public ObjectEntry[] getInitialObjectEntries()
   {
      String strFileName = File.separator;
      ObjectEntry[] roots = new ObjectEntry[1];
      try
      {
         // This entire try block is to get around the fact that the java.io.File
         // class lists zero children for a Netware volume.  So, if you are running
         // this filesystem snapin on a Netware server, and the root of the file
         // system is a volume, this code will provide the name of that volume.
         // To accomplish this, start by creating a File object using the File.separator
         // name.  If the File.list(), using this object, results in zero children, then
         // it may be running on a Novell Netware Server, so use the File.getCanonicalPath()
         // routine to get a more complete path specification, create a new File object
         // using that new path and try to list the children again.  If more than zero
         // children result from the new path, use the new path as the name of the root object.
         try
         {
            File candidateFile = new File(strFileName);
            if (candidateFile.isDirectory())
            {  // The File.separator File resulted in a directory
               String [] children = candidateFile.list();
               if (null != children)
               {
                  if (0 == children.length)
                  {  // The File.separator File resulted in zero children, try canonical path
                     String strCononicalFileName = candidateFile.getCanonicalPath();
                     File canonicalFile = new File(strCononicalFileName);
                     if (canonicalFile.isDirectory())
                     {  // The canonicalFile File resulted in a directory
                        String [] canonChildren = canonicalFile.list();
                        if (null != canonChildren)
                        {
                           if (0 != canonChildren.length)
                           {  // The canonicalFile File resulted in non-zero children, use canonical path
                              strFileName = strCononicalFileName;
                           }
                        }
                     }
                  }
               }
            }
         }
         catch (IOException ioe)
         {  // Fall thru and use the original File.separator string
         }
         roots[0] = makeObjectEntry(strFileName, null);
         return roots;
      }
      catch(ObjectNotFoundException e)
      {
         return null;
      }
   }

   /**
    The getSnapinName() method (derived from Snapin interface) is called by
    configurators to display the localized name of this snap-in. It returns
    the translated name for this snap-in. The shell displays the name you
    provide together with all the snap-ins of a given type. The user is then
    allowed to select which snap-ins should be set as active in the current
    configuration. The getSnapinName() method may be called before initSnapin().
    */
   public String getSnapinName()
   {
      return "Novell's Sample Filesystem Namespace";
   }

   /**
    The getSnapinDescription() method (derived from Snapin interface) is called
    by the configurators to display the localized description information
    about this snap-in. It returns the snap-in description as a String.
    */
   public String getSnapinDescription()
   {
      return "This is a sample filesystem namespace snapin";
   }

   /**
    The initSnapin() method initializes this class. You should do any
    onetime initialization here, such as adding event listeners. The method
    returns a boolean set to <i>true</i> if the snap-in is able to successfully
    complete initialization, or <i>false</i> if initialization fails. The 'info'
    parameter contains data the snap-in may use for initialization, such as
    references to the shell and the snap-in type, and may contain a reference
    to snap-in context data.
    */
   public boolean initSnapin(InitSnapinInfo info)
   {
      shell = info.getShell();
      if (directory == null)
      {
         directory = new ObjectType("Directory", this, true);
         fileType = new ObjectType("File", this, false);
         unknownType = new ObjectType("UnknownType", this, false);
         table = new Hashtable();
      }
      return true;
   }

   /**
    Implement shutdownSnapin() in your extending snap-in if there is
    anything that needs to be cleaned up, such as removing shell event listeners.
    */
   public void shutdownSnapin()
   {
   }

   /**
       Internal helper method.
    */
   ObjectEntry makeObjectEntry(String name, ObjectEntry parent)
         throws ObjectNotFoundException
   {
      ObjectType type = null;
      File file = null;
      if(parent == null)
      {
         file = new File(name);
      }
      else
      {
         file = new File(parent.getName(), name);
      }

      if(!file.exists())
      {
         return new ObjectEntry(file.getAbsolutePath(), unknownType, parent);
      }
      if(file.isDirectory())
      {
         type = directory;
      }
      else
      {
         int index = name.lastIndexOf(".");
         if(index == -1)
         {
            type = unknownType;
         }
         else
         {
            //type = fileType;
            //table.put(fileTypeName, type);

            String fileTypeName = name.substring(index+1).toLowerCase();
            if(table.containsKey(fileTypeName))
            {
               type = (ObjectType)table.get(fileTypeName);
            }
            else
            {
               type = new ObjectType(fileTypeName, this, false);
               table.put(fileTypeName, type);
            }
         }
      }
      return new ObjectEntry(file.getAbsolutePath(), type, parent);
   }
}