/* **************************************************************************

  $Archive: /njcl_v2/src/com/novell/service/file/nw/naming/SchemaAttrDef.java $
  $Revision: 14 $
  $Modtime: 2/22/00 5:16p $
 
  Copyright (c) 1998 Novell, Inc.  All Rights Reserved.

  THIS WORK IS  SUBJECT  TO  U.S.  AND  INTERNATIONAL  COPYRIGHT  LAWS  AND
  TREATIES.   NO  PART  OF  THIS  WORK MAY BE  USED,  PRACTICED,  PERFORMED
  COPIED, DISTRIBUTED, REVISED, MODIFIED, TRANSLATED,  ABRIDGED, CONDENSED,
  EXPANDED,  COLLECTED,  COMPILED,  LINKED,  RECAST, TRANSFORMED OR ADAPTED
  WITHOUT THE PRIOR WRITTEN CONSENT OF NOVELL, INC. ANY USE OR EXPLOITATION
  OF THIS WORK WITHOUT AUTHORIZATION COULD SUBJECT THE PERPETRATOR TO
  CRIMINAL AND CIVIL LIABILITY.

****************************************************************************/

/*
   As you add attribute values (attribute IDs) do the following in this file:

   1. Go to SchemaClassDef.java and do the list at the top of that file.

   2. Go to the _ATTRDEF data members and add a new one with a prefix of the
      new attribute that you are adding.  Keep this sequential, starting at 0.
      Remember that the SchemaSyntaxDef class will also use these same values.

   3. Go to the SchemaADNCEnumerator class (bottom of this file) and add the
      name of the new schema attr def node into the name data member.  This
      name should be exactly the same as the name used in step 2 in the
      SchemaClassDef file.  These must be at the same index as their
      corrisponding _ATTRDEF index in step 2.

   4. Go to the SchemaAttrDef(int) constructor and add the _ATTRDEF from step
      1 into the switch statement.  Put in the name of the syntax definition
      node (if one exists).  You can also set up the customId and customValue
      arrays with any attribute data that you want.  If you do not have any
      custom data or syntax, skip this step.  (if you put in a syntax name,
      it must be the exact same name as in SchemaSyntaxDef step 2).

   5. Go to the SchemaSyntaxDef.java and do the list at the top of that file.

*/

package com.novell.service.file.nw.naming;

import java.util.Enumeration;
import java.util.NoSuchElementException;
import java.util.Hashtable;

import javax.naming.*;
import javax.naming.Binding;
import javax.naming.NamingEnumeration;
import javax.naming.Context;
import javax.naming.InvalidNameException;
import javax.naming.Name;
import javax.naming.NamingEnumeration;
import javax.naming.NameClassPair;
import javax.naming.NameNotFoundException;
import javax.naming.NameParser;
import javax.naming.NamingException;
import javax.naming.OperationNotSupportedException;
import javax.naming.directory.BasicAttribute;
import javax.naming.directory.AttributeModificationException;
import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.ModificationItem;
import javax.naming.directory.SearchControls;
//import javax.naming.directory.SearchEnumeration; - changed to NamingEnumeration

import com.novell.utility.naming.NamingEnumerator;

import com.novell.utility.naming.directory.NAttributes;

import com.novell.service.file.nw.calls.DirectoryEntryInfoImpl;
import com.novell.service.file.nw.calls.DirectorySpaceInfoImpl;
import com.novell.service.file.nw.calls.EAEnumeratorImpl;
//import com.novell.service.file.nw.calls.NSInfoEnumeratorImpl;
import com.novell.service.file.nw.calls.TrusteeEnumeratorImpl;
import com.novell.service.file.nw.calls.VolumeInfoImpl;
import com.novell.service.file.nw.calls.VolumeUtilizationImpl;
import com.novell.service.file.nw.calls.VolumeRestrictionEnumeratorImpl;
import com.novell.service.file.nw.calls.EffectiveRightsImpl;

/**@internal
 * This class is the attribute definition schema context for the file system
 * provider.  This means that the attributes of this context describe
 * or define how a particular file system attribute is structured.
 *
 * <p>This is the schema DirContext that is returned from calling
 * getAttributeDefinition() on all Attribute instances returned the
 * from the file system DSContexts.
 *
 * @see javax.naming.directory.Attribute#getAttributeDefinition
 * @see FSAttribute
 */
public class SchemaAttrDef implements DirContext
{
   public static final int DEI_ATTRDEF    = 0; // DirectoryEntryInformation
   public static final int EA_ATTRDEF     = 1; // EAInformation
   public static final int TL_ATTRDEF     = 2; // Trustee
   public static final int DSI_ATTRDEF    = 3; // DirectorySpaceInformation
   public static final int VI_ATTRDEF     = 4; // VolumeInformation
   public static final int VU_ATTRDEF     = 5; // VolumeUtilization
   public static final int VR_ATTRDEF     = 6; // VolumeRestrictions
   public static final int EFR_ATTRDEF    = 7; // EffectiveRights
//   public static final int NSI_ATTRDEF    = 7; // NSInformation

   private String[] nodesAttrIds = null;
   private boolean staticSchemaTree = true;
   private int contextType = -1;
   private String syntaxName = null;
   private String attributeType = null;
   private String[] implemented = null;

   private String distinguishedName;

   private FSEnvironment environment;

   public SchemaAttrDef(FSEnvironment environment)
   {
      this.environment = environment;
      distinguishedName = FSSchema.ATTRIBUTE_DEFINITIONS;
   }

   /*
      This is the constructor that should be used by
      Attribute.getAttributeDefinition.  The caller should use a valid
      _ATTRDEF value from this class for the type.
   */

   public SchemaAttrDef(int type, FSEnvironment environment)
   {
      this(environment);

      staticSchemaTree = false;
      contextType = type;
      switch (contextType)
      {
         case DEI_ATTRDEF:
            syntaxName = DirectoryEntryInfoImpl.SCHEMA_BINDING_NAME;
            attributeType = "com.novell.service.file.nw.DirectoryEntryInformation";

            implemented = new String[1];
            implemented[0] = new String("java.io.Serializable");
            break;

         case EA_ATTRDEF:
            syntaxName = EAEnumeratorImpl.SCHEMA_BINDING_NAME;
            attributeType = "com.novell.service.file.nw.ExtendedAttribute";

            implemented = new String[1];
            implemented[0] = new String("java.io.Serializable");
            break;

         case TL_ATTRDEF:
            syntaxName = TrusteeEnumeratorImpl.SCHEMA_BINDING_NAME;
            attributeType = "com.novell.service.file.nw.Trustee";

            implemented = new String[1];
            implemented[0] = new String("java.io.Serializable");
            break;

         case DSI_ATTRDEF:
            syntaxName = DirectorySpaceInfoImpl.SCHEMA_BINDING_NAME;
            attributeType = "com.novell.service.file.nw.DirectorySpaceInformation";

            implemented = new String[1];
            implemented[0] = new String("java.io.Serializable");
            break;

         case VI_ATTRDEF:
            syntaxName = VolumeInfoImpl.SCHEMA_BINDING_NAME;
            attributeType = "com.novell.service.file.nw.VolumeInformation";

            implemented = new String[1];
            implemented[0] = new String("java.io.Serializable");
            break;

         case VU_ATTRDEF:
            syntaxName = VolumeUtilizationImpl.SCHEMA_BINDING_NAME;
            attributeType = "com.novell.service.file.nw.VolumeUtilization";

            implemented = new String[1];
            implemented[0] = new String("java.io.Serializable");
            break;

         case VR_ATTRDEF:
            syntaxName = VolumeRestrictionEnumeratorImpl.SCHEMA_BINDING_NAME;
            attributeType = "com.novell.service.file.nw.VolumeRestriction";

            implemented = new String[1];
            implemented[0] = new String("java.io.Serializable");
            break;

         case EFR_ATTRDEF:
            syntaxName = EffectiveRightsImpl.SCHEMA_BINDING_NAME;
            attributeType = "com.novell.service.file.nw.EffectiveRights";

            implemented = new String[1];
            implemented[0] = new String("java.io.Serializable");
            break;
/*
         case NSI_ATTRDEF:
            syntaxName = NSInfoEnumeratorImpl.SCHEMA_BINDING_NAME;
            break;
*/
      }
      distinguishedName = FSSchema.ATTRIBUTE_DEFINITIONS + "/" + syntaxName;
   }

   public int getContextType()
   {
      return contextType;
   }


   // ******************** Context Interface ********************

   /** @internal
    *
    */
   public String getNameInNamespace ()
      throws NamingException
   {
      throw (new OperationNotSupportedException ());
   }

   public NamingEnumeration list(String name)
      throws NamingException
   {
      if (name == null || name.length() == 0)
      {
         NamingEnumeration rvalue = null;
         if (staticSchemaTree)
            rvalue = new SchemaADNCEnumerator();
         else
            rvalue = new NamingEnumerator();
         return rvalue;
      }
      else
         return (NamingEnumeration)
            objectFromName(name, Schema.NCP_OBJECT, environment);
   }

   public NamingEnumeration list(Name name)
      throws NamingException
   {
      return list(name.toString());
   }

   public NamingEnumeration listBindings(String name)
      throws NamingException
   {
      if (name == null || name.length() == 0)
      {
         NamingEnumeration rvalue = null;
         if (staticSchemaTree)
            rvalue = new SchemaADBindingEnumerator(environment);
         else
            rvalue = new NamingEnumerator();
         return rvalue;
      }
      else
         return (NamingEnumeration)
            objectFromName(name, Schema.BINDING_OBJECT, environment);
   }

   public NamingEnumeration listBindings(Name name)
      throws NamingException
   {
      return listBindings(name.toString());
   }

   public Object lookup(String name) 
      throws NamingException
   {
      if (name == null || name.length() == 0)
         return this;

      return objectFromName(name, Schema.LOOKUP_OBJECT, environment);
   }

   public Object lookup(Name name) 
      throws NamingException
   {
      return lookup(name.toString());
   }

   public NameParser getNameParser(String name) 
      throws NamingException
   {
      if (name == null || name.length() == 0)
         return new FileSystemNameParser(environment.getServerName(), true);

      return (NameParser)
         objectFromName(name, Schema.NP_OBJECT, environment);
   }

   public NameParser getNameParser(Name name) 
      throws NamingException
   {
      return getNameParser(name.toString());
   }

   public String composeName (
         String name,
         String prefix)
      throws NamingException
   {
      Name fullName;

      fullName = composeName(
                                 new CompositeName(name),
                                 new CompositeName(prefix));
      return fullName.toString();
   }

   public Name composeName (
         Name name,
         Name prefix)
      throws NamingException
   {
      Name res = (Name)prefix.clone();

      if (name == null)
      {
         return res;
      }
      res.addAll(name);

      return res;
   }

   public Hashtable getEnvironment()
      throws NamingException
   {
      return environment.getEnvironment(true);
   }

   public Object addToEnvironment(String propName, Object propVal)
      throws NamingException
   {
      return (environment.addToEnvironment(propName, propVal));
   }

   public Object removeFromEnvironment(String propName)
      throws NamingException
   {
      return (environment.removeFromEnvironment(propName));
   }

   /* methods that don't just throw an exception (but do nothing) */

   /* methods that just throw an exception */

   public void bind(String name, Object obj) 
      throws NamingException
   {
      throw new OperationNotSupportedException();
   }

   public void bind(Name name, Object obj) 
      throws NamingException
   {
      throw new OperationNotSupportedException();
   }

   public void rebind(String name, Object obj) 
      throws NamingException
   {
      throw new OperationNotSupportedException();
   }

   public void rebind(Name name, Object obj) 
      throws NamingException
   {
      throw new OperationNotSupportedException();
   }

   public void unbind(String name) 
      throws NamingException
   {
      throw new OperationNotSupportedException();
   }

   public void unbind(Name name) 
      throws NamingException
   {
      throw new OperationNotSupportedException();
   }

   public void rename(String oldName, String newName)
      throws NamingException
   {
      throw new OperationNotSupportedException();
   }

   public void rename(Name oldName, Name newName) 
      throws NamingException
   {
      throw new OperationNotSupportedException();
   }

   public void destroySubcontext(String name) 
      throws NamingException
   {
      throw new OperationNotSupportedException();
   }

   public void destroySubcontext(Name name) 
      throws NamingException
   {
      throw new OperationNotSupportedException();
   }

   public Context createSubcontext(String name) 
      throws NamingException
   {
      throw new OperationNotSupportedException();
   }

   public Context createSubcontext(Name name) 
      throws NamingException
   {
      throw new OperationNotSupportedException();
   }

   public Object lookupLink(String name) 
      throws NamingException
   {
      return (lookup (name));
   }

   public Object lookupLink(Name name) 
      throws NamingException
   {
      return (lookup (name));
   }

   public void close() throws NamingException
   {
      //no action necessary
   }

/* **************************************************************************
*  DSContext implementation
****************************************************************************/

   /* methods that actually do something */

   public Attributes getAttributes(String name)
      throws NamingException
   {
      return getAttributes(name, null);
   }

   public Attributes getAttributes(Name name)
      throws NamingException
   {
      return getAttributes(name.toString(), null);
   }

   public Attributes getAttributes(String name, String[] attrIds)
      throws NamingException
   {
      if (name == null || name.length() == 0)
      {
         Attributes attrSet = new NAttributes(true);

         if (staticSchemaTree)
            return attrSet;         // there are no attributes at this level

         if (attrIds == null)
         {
            // they want the whole attribute set
            if (syntaxName != null)
            {
               BasicAttribute attr = new BasicAttribute(FSSchema.SYNTAX_ID);
               attr.add(new String(syntaxName));
               attrSet.put(attr);
            }
            if (attributeType != null)
            {
               BasicAttribute attr = new BasicAttribute(FSSchema.ATTRIBUTE_TYPE);
               attr.add(new String(attributeType));
               attrSet.put(attr);
            }
            if (implemented != null)
            {
               BasicAttribute attr = new BasicAttribute(FSSchema.INTERFACES_IMPLEMENTED);
               for (int i=0; i < implemented.length; i++)
                  attr.add(new String(implemented[i]));
               attrSet.put(attr);
            }
         }else
         {
            // find which ones they want
            for (int i=0; i < attrIds.length; i++)
            {
               if (syntaxName != null)
                  if (attrIds[i].equalsIgnoreCase(syntaxName))
                  {
                     BasicAttribute attr = new BasicAttribute(FSSchema.SYNTAX_ID);
                     attr.add(new String(syntaxName));
                     attrSet.put(attr);
                  }

               if (attributeType != null)
                  if (attrIds[i].equalsIgnoreCase(attributeType))
                  {
                     BasicAttribute attr = new BasicAttribute(FSSchema.ATTRIBUTE_TYPE);
                     attr.add(new String(attributeType));
                     attrSet.put(attr);
                  }

               if (attrIds[i].equalsIgnoreCase(FSSchema.INTERFACES_IMPLEMENTED))
               {
                  BasicAttribute attr = new BasicAttribute(FSSchema.INTERFACES_IMPLEMENTED);
                  if (implemented != null)
                  {
                     for (int j=0; j < implemented.length; j++)
                        attr.add(new String(implemented[j]));
                     attrSet.put(attr);
                  }
               }
            }
         }
         return attrSet;
      }
      else
         return (Attributes)objectFromName(
                              name, 
                              Schema.AS_OBJECT, 
                              environment);
   }

   public Attributes getAttributes(Name name, String[] attrIds)
      throws NamingException
   {
      return getAttributes(name.toString(), attrIds);
   }

   /* methods that don't just throw an exception (but do nothing) */

   /* methods that just throw an exception */

   public void modifyAttributes(String name, int mod_op, Attributes attrs)
      throws NamingException
   {
      throw new AttributeModificationException();
   }

   public void modifyAttributes(Name name, int mod_op, Attributes attrs)
      throws NamingException
   {
      throw new AttributeModificationException();
   }

   public void modifyAttributes(String name, ModificationItem[] mods)
      throws NamingException
   {
      throw new AttributeModificationException();
   }

   public void modifyAttributes(Name name, ModificationItem[] mods)
      throws NamingException
   {
      throw new AttributeModificationException();
   }

   public void bind(String name, Object obj, Attributes attrs)
      throws NamingException
   {
      throw new OperationNotSupportedException();
   }

   public void bind(Name name, Object obj, Attributes attrs)
      throws NamingException
   {
      throw new OperationNotSupportedException();
   }

   public void rebind(String name, Object obj, Attributes attrs)
      throws NamingException
   {
      throw new OperationNotSupportedException();
   }

   public void rebind(Name name, Object obj, Attributes attrs)
      throws NamingException
   {
      throw new OperationNotSupportedException();
   }

   public DirContext createSubcontext(String name,
                     Attributes attrs)
      throws NamingException
   {
      throw new OperationNotSupportedException();
   }

   public DirContext createSubcontext(Name name,
                     Attributes attrs)
      throws NamingException
   {
      throw new OperationNotSupportedException();
   }

   public DirContext getSchema(String name)
       throws NamingException
   {
      throw new OperationNotSupportedException();
   }

   public DirContext getSchema(Name name)
       throws NamingException
   {
      throw new OperationNotSupportedException();
   }

   public DirContext getSchemaClassDefinition(String name)
       throws NamingException
   {
      throw new OperationNotSupportedException();
   }

   public DirContext getSchemaClassDefinition(Name name)
       throws NamingException
   {
      throw new OperationNotSupportedException();
   }

   /* *************** searches *************** */

   public NamingEnumeration search(
      String name, 
      Attributes matchingAttributes)
      throws NamingException
   {
      throw new OperationNotSupportedException();
   }

   public NamingEnumeration search(
      Name name,
      Attributes matchingAttributes)
      throws NamingException
   {
      throw new OperationNotSupportedException();
   }

   public NamingEnumeration search(
      String name,
      Attributes matchingAttributes,
      String[] attributesToReturn)
      throws NamingException
   {
      throw new OperationNotSupportedException();
   }

   public NamingEnumeration search(
      Name name,
      Attributes matchingAttributes,
      String[] attributesToReturn)
      throws NamingException
   {
      throw new OperationNotSupportedException();
   }

   public NamingEnumeration search(
      String name,
      String filter,
      SearchControls cons)
      throws NamingException
   {
      throw new OperationNotSupportedException();
   }

   public NamingEnumeration search(
      Name name,
      String filter,
      SearchControls cons)
      throws NamingException
   {
      throw new OperationNotSupportedException();
   }

   public NamingEnumeration search(
      String name,
      String filterExpr,
      Object [] filterArgs,
      SearchControls cons)
      throws NamingException
   {
      throw new OperationNotSupportedException();
   }

   public NamingEnumeration search(
      Name name,
      String filterExpr,
      Object [] filterArgs,
      SearchControls cons)
      throws NamingException
   {
      throw new OperationNotSupportedException();
   }

/* **************************************************************************
*  Helper methods
****************************************************************************/

   public static int typeFromName(String attrid)
   {
      for (int i = 0; i < SchemaADNCEnumerator.names.length; i++)
      {
         if (SchemaADNCEnumerator.names[i].equalsIgnoreCase(attrid))
            return i;
      }
      return -1;  // not a name that i know about
   }

   public static Object getEnumeration(int type, FSEnvironment environment)
      throws NamingException
   {
      if (type == Schema.NCP_OBJECT)
         return new SchemaADNCEnumerator();
      if (type == Schema.BINDING_OBJECT)
         return new SchemaADBindingEnumerator(environment);
      throw new InvalidNameException();
   }

   private Object objectFromName(
                     String name, 
                     int returnType,
                     FSEnvironment environment)
      throws NamingException
   {
      int type = typeFromName(name);
      if (type == -1)                        // no attrid of this name
         throw new NameNotFoundException();

      switch (returnType)
      {
         case Schema.NCP_OBJECT:     // name class pair enumeration
            return new NamingEnumerator();
         case Schema.BINDING_OBJECT: // binding enumeration
            return new NamingEnumerator();
         case Schema.LOOKUP_OBJECT:
         case Schema.AS_OBJECT:
            DirContext ctx = new SchemaAttrDef(type, environment);
            if (returnType == Schema.LOOKUP_OBJECT)
               return ctx;
            return ctx.getAttributes("");
         case Schema.NP_OBJECT:     // nameparser
            return new FileSystemNameParser(
                           environment.getServerName(), 
                           true);
         default:
            throw new InvalidNameException();
      }
   }
}

/* *************************************************************************/

class SchemaADNCEnumerator implements NamingEnumeration
{
   private final String classDef =
         "com.novell.service.file.nw.naming.SchemaAttrDef";

   public final static String[] names =
      {
         DirectoryEntryInfoImpl.SCHEMA_BINDING_NAME,
         EAEnumeratorImpl.SCHEMA_BINDING_NAME,
         TrusteeEnumeratorImpl.SCHEMA_BINDING_NAME,
         DirectorySpaceInfoImpl.SCHEMA_BINDING_NAME,
         VolumeInfoImpl.SCHEMA_BINDING_NAME,
         VolumeUtilizationImpl.SCHEMA_BINDING_NAME,
         VolumeRestrictionEnumeratorImpl.SCHEMA_BINDING_NAME,
         EffectiveRightsImpl.SCHEMA_BINDING_NAME,
//         NSInfoEnumeratorImpl.SCHEMA_BINDING_NAME,
      };

   private int index = 0;
   private boolean moreElements = true;

   public boolean hasMoreElements()
   {
      return moreElements;
   }

   public boolean hasMore()
      throws NamingException
   {
      return moreElements;
   }

   public Object nextElement()
   {
      try
      {
         return next();
      } catch (NamingException ne)
      {
         throw new RuntimeException(ne.getMessage());
      }
   }

   public Object next()
      throws NamingException
   {
      if (!moreElements)
         throw new NoSuchElementException();

      NameClassPair rvalue = new NameClassPair(names[index++], classDef, true);

      if (index >= names.length)
         moreElements = false;
      return rvalue;
   }

   public void close() throws NamingException
   {
      moreElements = false;
   }
}


/* *************************************************************************/

class SchemaADBindingEnumerator implements NamingEnumeration
{
   private int index = 0;
   private boolean moreElements = true;

   private FSEnvironment environment;

   public SchemaADBindingEnumerator (FSEnvironment environment)
   {
      this.environment = environment;
   }

   public boolean hasMoreElements()
   {
      return moreElements;
   }

   public boolean hasMore()
      throws NamingException
   {
      return moreElements;
   }

   public Object nextElement()
   {
      try
      {
         return next();
      } catch (NamingException ne)
      {
         throw new RuntimeException(ne.getMessage());
      }
   }

   public Object next()
      throws NamingException
   {
      if (moreElements)
         throw new NoSuchElementException();

      Binding rvalue = new Binding(
                              SchemaADNCEnumerator.names[index],
                              new SchemaAttrDef(index++, environment),
                              true);
      if (index >= SchemaADNCEnumerator.names.length)
         moreElements = false;
      return rvalue;
   }

   public void close() throws NamingException
   {
      moreElements = false;
   }
}


