| Schema

## Object Class Definitions

> All LDAP entries in the directory are typed. That is, each entry belongs to object classes that identify the type of data represented by the entry. The object class specifies the mandatory and optional attributes that can be associated with an entry of that class.

> The object classes for all objects in the directory form a class hierarchy. The classes `"top"` and `"alias"` are at the root of the hierarchy. For example, the `"organizationalPerson"` object class is a subclass of the `"Person"` object class, which in turn is a subclass of `"top"`. When creating a new LDAP entry, you must always specify all of the object classes to which the new entry belongs. Because many directories do not support object class subclassing, you also should always include all of the superclasses of the entry. For example, for an `"organizationalPerson"` object, you should list in its object classes the `"organizationalPerson"`, `"person"`, and `"top"` classes.

> Three types of object classes are possible:

> - Structural. Indicates the attributes that the entry may have and where each entry may occur in the DIT.
> - Auxiliary. Indicates the attributes that the entry may have.
> - Abstract. Indicates a "partial" specification in the object class hierarchy; only structural and auxiliary subclasses may appear as entries in the directory.

> In the schema tree, the name `"ClassDefinition"` is bound to a flat context containing `DirContext` objects that represents object class definitions in the schema. For example, if a directory supports a `"person"` object class, then the `"ClassDefinition"` context will have a binding with the name `"person"` that is bound to a `DirContext` object. Each object in the `"ClassDefinition"` context has mandatory and optional attributes shown in the following table. Only `"NUMERICOID"` is mandatory.

> Attribute Identifier | Attribute Value Description
> --- | ---
> NUMERICOID (mandatory) | Unique object identifier (OID)
> NAME | Object class's name
> DESC | Object class's description
> OBSOLETE | `"true"` if obsolete; `"false"` or absent otherwise
> SUP | Names of superior object classes from which this object class is derived
> ABSTRACT | `"true"` if object class is abstract; `"false"` or absent otherwise
> STRUCTURAL | `"true"` if object class is structural; `"false"` or absent otherwise
> AUXILIARY | `"true"` if object class is auxiliary; `"false"` or absent otherwise
> MUST | List of type names of attributes that must be present
> MAY | List of type names of attributes that may be present

> These attributes correspond to the definition of "ObjectClassDescription" in RFC 2252. All of the attribute values are represented by the `java.lang.String` class. Some directories do not publish all of the schema data. For example, the Netscape Directory Server v4.1 does not publish whether an object class is abstract, structural, or auxiliary. In such cases, the schema objects do not completely describe the object classes definitions.

> #### Retrieving the Schema Object of an Object Class

> To retrieve the schema object of an object class, you look for it in the schema tree. For example, you can obtain the schema object that represents the `"person"` object class by using the following code.

> >     // Get the schema tree root
> >     DirContext schema = ctx.getSchema("");

> >     // Get the schema object for "person"
> >     DirContext personSchema = (DirContext)schema.lookup("ClassDefinition/person");

> If you get the attributes of the `personSchema` schema object, then you will see the following.

> >     NUMERICOID: 2.5.6.6
> >     NAME: person
> >     MAY:  description, seealso, telephonenumber, userpassword
> >     MUST: objectclass, sn, cn
> >     DESC: Standard ObjectClass
> >     SUP: top

> In addition to using `lookup()`, you can use methods such as `list()` or `search()` to retrieve schema objects from the schema tree.

> #### Getting an Entry's Object Classes

> Given a `DirContext` object representing an LDAP entry, you can get that entry's object classes by invoking `DirContext.getSchemaClassDefinition()` on it.

> Following is an example that enumerates the object class definitions for the entry `"cn=Ted Geisel, ou=People"`. `getSchemaClassDefinition()` returns a context that contains the entry's object class definitions. Using this context, you can look up an individual definition, search for a definition, enumerate all definitions, or perform other `DirContext` operations.

> >     // Create the initial context
> >     DirContext ctx = new InitialDirContext(env);

> >     // Get context containing class definitions for the "cn=Ted Geisel" entry
> >     DirContext tedClasses = ctx.getSchemaClassDefinition("cn=Ted Geisel, ou=People");

> >     // Enumerate the class definitions
> >     NamingEnumeration enum = tedClasses.search("", null);
> >     while (enum.hasMore()) {
> >         System.out.println(enum.next());
> >     }

> #### Adding a New Object Class

> > Before you go on: To update the schema, you must authenticate as the directory administrator. This is the name that you supplied to the directory administration program when you first configured the directory. For example, if you configured `"cn=Directory Manager"` as the administrator, then you need to do something like the following when creating the initial context.

> > >     env.put(Context.SECURITY_PRINCIPAL, "cn=Directory Manager");
> > >     env.put(Context.SECURITY_CREDENTIALS, "secret99");

> > Netscape v4.0 Bugs: The Netscape Directory Server v4.0 and earlier releases do not support schema entries that comply with RFC 2252. Specifically, contrary to RFC 2252, the Netscape server requires that OIDs (such as those for SUP and SYNTAX) be delimited by single quotation marks and MUST/MAY lists be enclosed by parentheses. By default, the LDAP service provider produces schema entries that comply with RFC 2252 but are not acceptable to the Netscape server. To produce schema entries that are acceptable to the Netscape v4.0 server, you must add the following to the environment properties before creating the initial context:

> > >     env.put("com.sun.jndi.ldap.netscape.schemaBugs", "true");

> > Netscape v4.1 Bugs: The Netscape Directory Server v4.1 has fixed some of the schema-handling problems found in the version 4.0 server, so you should not use the `"com.sun.jndi.ldap.netscape.schemaBugs"` property with version 4.1. However, the version 4.1 server still requires that MUST/MAY lists be enclosed by parentheses. Sun's LDAP provider uses a quoted item instead of a parenthetical list for single-item MUST/MAY specifications. You can work around this problem by creating a single-valued `"MUST"`/`"MAY"` attribute and then adding a superfluous value, such as `"objectclass"`, when you are modifying or creating an object class definition that has a single-itme MUST/MAY list.

> > Windows Active Directory: Active Directory does not support the modification of the RFC 2252 schema descriptions. Instead, you must update Active Directory's internal schema representation. See the Windows 2000 Planning Guide for details on how to enable and perform schema updates.

> Adding a new object class to the schema is like adding a new entry to the directory. This is because the schema tree and schema objects are `DirContext` objects.

> Following is an example that adds a new object class (`"fooObjectClas"`) to the schema. It first declares the attributes that describe the new object class and then adds the object class definition to the schema by using `DirContext.createSubcontext()`.

> >     // Specify attributes for the schema object
> >     Attributes attrs = new BasicAttributes(true); // Ignore case
> >     attrs.put("NUMERICOID", "1.3.6.1.4.1.42.2.27.4.2.3.1.1.1");
> >     attrs.put("NAME", "fooObjectClass");
> >     attrs.put("DESC", "for JNDITutorial example only");
> >     attrs.put("SUP", "top");
> >     attrs.put("STRUCTURAL", "true");
> >     Attribute must = new BasicAttribute("MUST", "cn");
> >     must.add("objectclass");
> >     attrs.put(must);

> >     // Get the schema tree root
> >     DirContext schema = ctx.getSchema("");

> >     // Add the new schema object for "fooObjectClass"
> >     DirContext newClass = schema.createSubcontext("ClassDefinition/fooObjectClass", attrs);

> Some servers might modify the definition before adding it to the schema. To check the newly added definition, use a new initial context to read the definition so that any cached definition is not used.

> #### Modifying an Object Class

> > Note: In versions of the LDAP provider prior to the Java 2 SDK, v1.4, you cannot modify an existing object class. In those releases, you must first delete the existing object class definition and then add the updated version.

> > Before you go on: See the Adding a New Object Class section for notes regarding updating the schema.

> Modifying an existing object class in the schema is like modifying an entry in the directory. Here's an example that adds a `"description"` optional attribute to the object class `"fooObjectClass"` in the schema by using `DirContext.modifyAttributes()`.

> >     // Specify new MAY attribute for schema object
> >     Attribute may = new BasicAttribute("MAY", "description");
> >     Attributes attrs = new BasicAttributes(false);
> >     attrs.put(may);

> >     // Get the schema tree root
> >     DirContext schema = ctx.getSchema("");

> >     // Modify schema object for "fooObjectClass"
> >     schema.modifyAttributes("ClassDefinition/fooObjectClass",
> >         DirContext.ADD_ATTRIBUTE, attrs);

> Some servers might modify the definition before performing the update on the schema or ignore the update. To check the newly updated definition, use a new initial context to read the definition so that any cached definition is not used.

> #### Deleting an Object Class

> > Before you go on: See the Adding a New Object Class section for notes regarding updating the schema.

> Deleting an existing object class from the schema is like deleting an entry from the directory. Here's an example that removes the object class `"fooObjectClass"` from the schema by using `DirContext.destroySubcontext()`.

> >     // Get the schema tree root
> >     DirContext schema = ctx.getSchema("");

> >     // Remove the schema object for "fooObjectClass"
> >     schema.destroySubcontext("ClassDefinition/fooObjectClass");

> Some servers might not let you delete an object class that's being used by entries in the directory. You might be able to get around this restriction by turning off schema checking.

| Schema