<!--

Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved.
Portions copyright 1999 Netscape Communications Corporation. All
Rights Reserved.

The contents of this document are subject to the terms of the
Creative Commons Attribution-ShareAlike 2.5 license or any later
version (the "License"). You may not use this document except in
compliance with the License.

See the License for the specific language governing
permissions and limitations under the License. You can obtain
a copy of the License at
http://creativecommons.org/licenses/by-sa/2.5/legalcode.

-->
<chapter id="server-info"><title>Getting Server Information With &DirectorySDKForJava;
</title>
<highlights>
<para>This chapter explains how to access and modify information about your
LDAP server over the LDAP protocol.</para>
<itemizedlist>
<para>This chapter covers the following topics:</para>
<listitem><para><olink targetptr="server-info-dse-intro">About DSEs</olink></para>
</listitem>
<listitem><para><olink targetptr="server-info-dse-info">Getting the Root DSE
With Directory SDK for Java</olink></para></listitem>
<listitem><para><olink targetptr="server-info-ldapv3">Checking Support for
LDAP v3 With Directory SDK for Java</olink></para></listitem>
<listitem><para><olink targetptr="server-info-schema">Getting Schema Information
With Directory SDK for Java</olink></para></listitem>
</itemizedlist>
</highlights>
<sect1 id="server-info-dse-intro"><title>About DSEs</title>
<para>The acronym <acronym>DSE</acronym> refers to a <emphasis>DSA-specific
entry</emphasis> in the directory. A DSA is a <emphasis>directory system agent</emphasis>,
an X.500 term for a directory server. A DSE contains information specific
to the server.</para>
<para>LDAP v3 uses the concept of the <firstterm>root DSE</firstterm>. In
a directory tree, the root of the tree is the root DSE. The root DSE is not
part of any naming context. In other words, the entry is superior to <literal>dc=example,dc=com
</literal>, <literal>cn=config</literal>, and similar suffixes in the directory
tree. Servers that do not support LDAP v3 therefore do not necessarily have
a root DSE.</para>
<itemizedlist>
<para>The root DSE can contain the following information:</para>
<listitem><para>The naming contexts the server supports, such as <literal>dc=example,dc=com
</literal> or <literal>cn=config</literal></para></listitem>
<listitem><para>URLs to alternate servers that can be contacted if the server
is unavailable</para></listitem>
<listitem><para>The LDAP v3 extended operations the server supports</para>
</listitem>
<listitem><para>The LDAP v3 controls the server supports</para></listitem>
<listitem><para>The SASL mechanisms the server supports</para></listitem>
<listitem><para>The versions of LDAP the server supports</para></listitem>
<listitem><para>Additional, server-specific information</para></listitem>
</itemizedlist>
</sect1>
<sect1 id="server-info-dse-info"><title>Getting the Root DSE With &DirectorySDKForJava;
</title>
<indexterm>
<primary>DSE</primary>
<secondary>root</secondary>
</indexterm><indexterm>
<primary>root DSE</primary>
</indexterm>
<para>The root DSE for an LDAP server specifies information about the server.
The attributes of the root DSE and what the attributes provide are shown here.</para>
<variablelist>
<varlistentry><term><literal>altServer</literal></term>
<listitem><para>LDAP URLs that identify other servers to contact when the
server is not available.</para>
</listitem>
</varlistentry>
<varlistentry><term><literal>namingContexts</literal></term>
<listitem><para>Naming contexts, such as <literal>dc=example,dc=com</literal>,
supported by the server.</para>
</listitem>
</varlistentry>
<varlistentry><term><literal>supportedControl</literal></term>
<listitem><para><firstterm>Object identifiers</firstterm> (OIDs) of LDAP v3
controls supported by the server.</para>
<para>If this attribute is not present, the server does not support LDAP v3
controls.</para>
</listitem>
</varlistentry>
<varlistentry><term><literal>supportedExtension</literal></term>
<listitem><para>Object identifiers (OIDs) of LDAP v3 extended operations supported
by the server.</para>
<para>If this attribute is not present, the server does not support LDAP v3
extended operations.</para>
</listitem>
</varlistentry>
<varlistentry><term><literal>supportedLDAPVersion</literal></term>
<listitem><para>Versions of LDAP, <literal>2</literal> or <literal>3</literal>,
supported by the server.</para>
</listitem>
</varlistentry>
<varlistentry><term><literal>supportedSASLMechanisms</literal></term>
<listitem><para>Names of SASL mechanisms supported by the server.</para>
<para>If this attribute is not present, the server does not support any SASL
mechanisms.</para>
</listitem>
</varlistentry>
</variablelist>
<orderedlist>
<para>To access the root DSE of an LDAP server, do the following:</para>
<listitem><para>Turn off automatic referral handling, and connect to the LDAP
server.</para><para>See <olink type="auto-generated" targetptr="prepare-client">Creating
a Connection and Setting Preferences With Directory SDK for Java</olink> and <olink type="auto-generated" targetptr="connect-client">Connecting to an LDAP Server
With Directory SDK for Java</olink>. See also <olink type="auto-generated" targetptr="handling-referrals">Handling Referrals With Directory SDK for Java</olink> for
instructions.</para></listitem>
<listitem>
<itemizedlist>
<para>Search the directory with the following criteria:</para>
<listitem><para>Set the search scope to a <literal>base</literal> search.</para>
</listitem>
<listitem><para>Specify an empty string for the base DN.</para></listitem>
<listitem><para>Use the search filter <literal>(objectclass=*)</literal>.</para>
</listitem>
</itemizedlist>
<para>Refer to <olink type="auto-generated" targetptr="searching">Chapter&nbsp;4, Searching the Directory With Directory SDK for Java</olink> for instructions.</para>
<para>If an <classname>LDAPException</classname> is returned with a result
code such as <returnvalue>OPERATION_ERROR</returnvalue>, <returnvalue>PROTOCOL_ERROR
</returnvalue>, <returnvalue>REFERRAL</returnvalue>, or <returnvalue>NO_SUCH_OBJECT
</returnvalue>, the LDAP server probably does not support LDAP v3.</para>
</listitem>
</orderedlist>
<para>The following code excerpt retrieves the root DSE, and then displays
the attributes.</para>
<programlisting>/* Create a new connection. */
LDAPConnection ld = new LDAPConnection();
String hostname = "localhost";
int portnumber = LDAPv3.DEFAULT_PORT;

try {
    /* Connect to the LDAP server. */
    ld.connect(3, hostname, portnumber);

    int MY_SCOPE = LDAPv3.SCOPE_BASE;
    String MY_FILTER = "(objectclass=*)";
    String MY_SEARCHBASE = "";
    LDAPSearchResults res = ld.search(MY_SEARCHBASE,
        MY_SCOPE, MY_FILTER, null, false);

    /* There should be only one result (the root DSE). */
    while (res.hasMoreElements()) {
        LDAPEntry findEntry = (LDAPEntry)res.nextElement();

        /* Get the attributes of the root DSE. */
        LDAPAttributeSet findAttrs = findEntry.getAttributeSet();
        Enumeration enumAttrs = findAttrs.getAttributes();

        /* Iterate through each attribute. */
        while (enumAttrs.hasMoreElements()) {
            LDAPAttribute anAttr = (LDAPAttribute)enumAttrs.nextElement();

            /* Get and print the attribute name. */
            String attrName = anAttr.getName();
            System.out.println(attrName);

            /* Get the values of the attribute. */
            Enumeration enumVals = anAttr.getStringValues();

            /* Get and print each value. */
            if (enumVals == null) {
                System.out.println("\tNo values found.");
                continue;
            }
            while (enumVals.hasMoreElements()) {
                String aVal = (String)enumVals.nextElement();
                System.out.println("\t" + aVal);
            }
        }
    }
} catch( LDAPException e ) {
    System.out.println("Error: " + e.toString());
}</programlisting>
</sect1>
<sect1 id="server-info-ldapv3"><title>Checking Support for LDAP v3 With &DirectorySDKForJava;
</title>
<indexterm>
<primary>LDAP servers</primary>
<secondary>protocol version supported</secondary>
</indexterm>
<para>You can determine what version an LDAP server supports by getting the <literal>
supportedLDAPVersion</literal> attribute from the root DSE. This attribute
should contain the value <literal>3</literal>. The attribute can also contain
other values, such as <literal>2</literal>, so iterate through the values
of this attribute.</para>
<para>You are not required to authenticate or bind before performing a search.
Unlike LDAP v2, LDAP v3 states that clients do not need to bind to the server
before performing LDAP operations. The following section of code connects
to an LDAP server. The code then determines whether the server supports LDAP
v3.</para>
<programlisting>/* Create a new connection. */
LDAPConnection ld = new LDAPConnection();
String hostname = "localhost";
int portnumber = LDAPv3.DEFAULT_PORT;

boolean supportsV3 = false;

try {
    /* Connect to the LDAP server. */
    ld.connect( 3, hostname, portnumber );

    int MY_SCOPE = LDAPv3.SCOPE_BASE;
    String MY_FILTER = "(objectclass=*)";
    String MY_SEARCHBASE = "";
    LDAPSearchResults res = ld.search(MY_SEARCHBASE,
        MY_SCOPE, MY_FILTER, null, false);

    /* There should be only one result (the root DSE). */
    while (res.hasMoreElements()) {
        LDAPEntry findEntry = (LDAPEntry)res.nextElement();

        /* Get the supportedLDAPVersion attribute values. */
        LDAPAttribute versionAttr =
            findEntry.getAttribute("supportedLDAPVersion");
        
        /* Check for "3". */
        Enumeration enumVals = versionAttr.getStringValues();
        if (enumVals == null) {
            System.out.println("\tNo values found.");
            continue;
        }
        while (enumVals.hasMoreElements()) {
            String aVal = (String)enumVals.nextElement();
            if (aVal.equalsIgnoreCase("3")) {
                supportsV3 = true;
                break;
            }
        }
    }
} catch( LDAPException e ) {
    System.out.println("Error: " + e.toString());
}

if (supportsV3) {
    System.out.println("This server supports LDAP v3.");
} else {
    System.out.println("This server does not support LDAP v3.");
}</programlisting>
</sect1>
<sect1 id="server-info-schema"><title>Getting Schema Information With &DirectorySDKForJava;
</title>
<indexterm>
<primary>LDAP servers</primary>
<secondary>schema</secondary>
</indexterm><indexterm>
<primary>schema</primary>
</indexterm>
<para>In LDAP v3, you can get LDAP schema over LDAP. You can also modify schema
over LDAP. This section explains how to carry out such modifications.</para>
<sect2 id="server-info-schema-overview"><title>Understanding Schema Over LDAP</title>
<para>An entry can specify the schema that defines the object classes, attributes,
syntaxes, and matching rules used by the directory. This entry is called the <firstterm>
subschema entry</firstterm>.</para>
<para>To find the DN of the subschema entry, get the <literal>subschemaSubentry</literal> operational
attribute from the root DSE or from any entry. This code excerpt demonstrates
how to retrieve the subschema entry DN.</para>
<programlisting>LDAPConnection ld = null;
try {
    ld = new LDAPConnection();
    ld.connect("localhost", LDAPv3.DEFAULT_PORT);

    String [] schemaAttr = {"subschemaSubentry"};
    LDAPEntry rootDSE = ld.read("", schemaAttr);
    LDAPAttribute resAttr = rootDSE.getAttribute(schemaAttr[0]);
    Enumeration enumVals = resAttr.getStringValues();
    if (enumVals != null) {
        while (enumVals.hasMoreElements()) {
            System.out.println(schemaAttr[0] + ": " +
                (String)enumVals.nextElement());
        }
    }
    ld.disconnect();
} catch(LDAPException e) {
    System.out.println("Error: " + e.toString());
}</programlisting>
<para>The subschema entry can have the following attributes.</para>
<variablelist>
<varlistentry><term><literal>objectClasses</literal></term>
<listitem><para>Specifies the object class definitions in the schema.</para>
<para>Each value of this attribute is an object class that is known to the
server.</para>
</listitem>
</varlistentry>
<varlistentry><term><literal>attributeTypes</literal></term>
<listitem><para>Specifies the attribute type definitions in the schema.</para>
<para>Each value of this attribute is an attribute type that is known to the
server.</para>
</listitem>
</varlistentry>
<varlistentry><term><literal>matchingRules</literal></term>
<listitem><para>Specifies the matching rule definitions in the schema.</para>
<para>Each value of this attribute is a matching rule that is known to the
server.</para>
</listitem>
</varlistentry>
<varlistentry><term><literal>matchingRuleUse</literal></term>
<listitem><para>Specifies the use of a matching rule in the schema.</para>
<para>Each value of this attribute is a matching rule use description. A matching
rule use description specifies the OIDs of the attributes that can be used
with this extensible matching rule.</para>
</listitem>
</varlistentry>
<varlistentry><term><literal>syntaxes</literal></term>
<listitem><para>Specifies the syntax definitions in the schema.</para>
<para>Each value of this attribute is syntax that is known to the server.</para>
</listitem>
</varlistentry>
</variablelist>
<para>In &DirectorySDKForJava;, the schema and elements in the schema are
represented by classes in the <literal>netscape.ldap</literal> package. These
classes include the following.</para>
<variablelist>
<varlistentry><term><classname>LDAPSchema</classname></term>
<listitem><para>Schema used by an LDAP server</para>
</listitem>
</varlistentry>
<varlistentry><term><classname>LDAPSchemaElement</classname></term>
<listitem><para>Base class that represents a generic element in the schema</para>
</listitem>
</varlistentry>
<varlistentry><term><classname>LDAPObjectClassSchema</classname></term>
<listitem><para>Object class description in the schema</para>
</listitem>
</varlistentry>
<varlistentry><term><classname>LDAPAttributeSchema</classname></term>
<listitem><para>Attribute type description in the schema</para>
</listitem>
</varlistentry>
<varlistentry><term><classname>LDAPMatchingRuleSchema</classname></term>
<listitem><para>Matching rule description in the schema</para>
</listitem>
</varlistentry>
<varlistentry><term><classname>LDAPMatchingRuleUseSchema</classname></term>
<listitem><para>Use of a matching rule in the schema</para>
</listitem>
</varlistentry>
<varlistentry><term><classname>LDAPSyntaxSchema</classname></term>
<listitem><para>Syntax description in the schema</para>
</listitem>
</varlistentry>
</variablelist>
<para>These classes with their methods handle the subschema entry by using
standard LDAP operations, such as <literal>search</literal> and <literal>modify</literal>.
</para></sect2>
<sect2 id="server-info-schema-get"><title>Getting Information About LDAP Schema</title>
<para>To get the schema for an LDAP v3 server, construct a new <classname>LDAPSchema
</classname> object. Then, invoke the <literal>fetchSchema</literal> method,
passing in an <classname>LDAPConnection</classname> object.</para>
<programlisting>LDAPConnection ld = new LDAPConnection();
/* Construct an LDAPSchema object to hold the schema to retrieve. */
LDAPSchema dirSchema = new LDAPSchema();
try {
    ld.connect(hostname, portnumber, bindDN, bindPW);
    /* Get the schema. Anonymous access is OK. */
    dirSchema.fetchSchema(ld);
    /* Use the schema. */
} catch (Exception e) {
    System.err.println(e.toString());
}</programlisting>
</sect2>
<sect2 id="server-info-schema-objectclasses"><title>Working With Object Class
Descriptions</title>
<para>In the LDAP Java classes, the object class descriptions in a schema
are represented by objects of the <classname>LDAPObjectClassSchema</classname> class.
</para>
<itemizedlist>
<para>To get the object class descriptions from the schema, invoke one of
the following methods:</para>
<listitem><para>To get an enumeration of <classname>LDAPObjectClassSchema</classname> objects
that represent the object classes in the schema, invoke the <literal>getObjectClasses
</literal> method.</para></listitem>
<listitem><para>To get a specific object class description, invoke the <literal>getObjectClass
</literal> method and pass in the name of the object class.</para></listitem>
<listitem><para>To get an enumeration of the names of object classes in the
schema, invoke the <literal>getObjectClassNames</literal> method.</para>
</listitem>
</itemizedlist>
<itemizedlist>
<para>An object class description consists of the following information, which
you can retrieve by invoking methods of the <classname>LDAPObjectClassSchema</classname> object:
</para>
<listitem><para>An OID that identifies the object class, retrieved by invoking
the <literal>getOID</literal> method</para></listitem>
<listitem><para>A name that identifies the object class, retrieved by invoking
the <literal>getName</literal> method</para></listitem>
<listitem><para>A description that identifies the object class, retrieved
by invoking the <literal>getDescription</literal> method</para></listitem>
<listitem><para>A name that identifies the parent object class, retrieved
by invoking the <literal>getSuperior</literal> method</para></listitem>
<listitem><para>The list of required attributes, retrieved by invoking the <literal>
getRequiredAttributes</literal> method</para></listitem>
<listitem><para>The list of optional attributes that are allowed, retrieved
by invoking the <literal>getOptionalAttributes</literal> method</para>
</listitem>
</itemizedlist>
<para>To add an object class description to the schema, construct a new <classname>
LDAPObjectClassSchema</classname> object. You can specify the pieces of information
in the object as individual arguments or in a description formatted according
to <ulink url="http://www.ietf.org/rfc/rfc4517.txt" type="text_url">RFC 4517</ulink>, <citetitle>
Lightweight Directory Access Protocol (LDAP): Syntaxes and Matching Rules</citetitle>.
</para>
<para>Then, you can either invoke the <literal>add</literal> method of this
object or the <literal>addObjectClass</literal> method of the <classname>LDAPSchema
</classname> object.</para>
<para>To remove an object class description, invoke the <literal>remove</literal> method
of this object.</para></sect2>
<sect2 id="server-info-schema-attributetypes"><title>Working With Attribute
Type Descriptions</title>
<para>In the LDAP Java classes, the attribute type descriptions in a schema
are represented by objects of the <classname>LDAPAttributeSchema</classname> class.
</para>
<itemizedlist>
<para>To get the attribute type descriptions from the schema, invoke one of
the following methods:</para>
<listitem><para>To get an enumeration of <classname>LDAPAttributeSchema</classname> objects
that represent the attribute types in the schema, invoke the <literal>getAttributes
</literal> method.</para></listitem>
<listitem><para>To get a specific attribute type description, invoke the <literal>
getAttribute</literal> method and pass in the name of the attribute type.</para>
</listitem>
<listitem><para>To get an enumeration of the names of attribute types in the
schema, invoke the <literal>getAttributeNames</literal> method.</para>
</listitem>
</itemizedlist>
<itemizedlist>
<para>An attribute type description consists of the following information,
which you can retrieve by invoking methods of the <classname>LDAPAttributeSchema</classname> object:
</para>
<listitem><para>An OID that identifies the attribute type, retrieved by invoking
the <literal>getOID</literal> method</para></listitem>
<listitem><para>A name that identifies the attribute type, retrieved by invoking
the <literal>getName</literal> method</para></listitem>
<listitem><para>A description that identifies the attribute type, retrieved
by invoking the <literal>getDescription</literal> method</para></listitem>
<listitem><para>The syntax used by the attribute type, retrieved by invoking
the <literal>getSyntax</literal> method</para></listitem>
<listitem><para>An indication whether the attribute type is single-valued
or multivalued, retrieved by invoking the <literal>isSingleValued</literal> method
</para></listitem>
</itemizedlist>
<para>To add an attribute type description to the schema, construct a new <classname>
LDAPAttributeSchema</classname> object. You can specify the pieces of information
in the object as individual arguments or in a description formatted according
to <ulink url="http://www.ietf.org/rfc/rfc4517.txt" type="text_url">RFC 4517</ulink>, <citetitle>
Lightweight Directory Access Protocol (LDAP): Syntaxes and Matching Rules</citetitle>.
</para>
<para>Then, you can either invoke the <literal>add</literal> method of this
object or the <literal>addAttributeType</literal> method of the <classname>LDAPSchema
</classname> object.</para>
<para>To remove an <literal>attributeType</literal> description, invoke the <literal>
remove</literal> method of this object.</para></sect2>
<sect2 id="server-info-schema-matchingrules"><title>Working With Matching
Rule Descriptions</title>
<para>In the LDAP Java classes, the matching rule and matching rule use descriptions
in a schema are represented by objects of the <classname>LDAPMatchingRuleSchema</classname> class.
</para>
<itemizedlist>
<para>To get the matching rule descriptions from the schema, invoke one of
the following methods:</para>
<listitem><para>To get an enumeration of <classname>LDAPMatchingRuleSchema</classname> objects
that represent the matching rules in the schema, invoke the <literal>getMatchingRules
</literal> method.</para></listitem>
<listitem><para>To get a specific matching rule description, invoke the <literal>
getMatchingRule</literal> method and pass in the name of the matching rule.</para>
</listitem>
<listitem><para>To get an enumeration of the names of matching rules in the
schema, invoke the <literal>getMatchingRuleNames</literal> method.</para>
</listitem>
</itemizedlist>
<itemizedlist>
<para>A matching rule description consists of the following information, which
you can retrieve by invoking methods of the <classname>LDAPMatchingRuleSchema</classname> object:
</para>
<listitem><para>An OID that identifies the matching rule, retrieved by invoking
the <literal>getOID</literal> method</para></listitem>
<listitem><para>A name that identifies the matching rule, retrieved by invoking
the <literal>getName</literal> method</para></listitem>
<listitem><para>A description that identifies the matching rule, retrieved
by invoking the <literal>getDescription</literal> method</para></listitem>
<listitem><para>The syntax of the matching rule, retrieved by invoking the <literal>
getSyntax</literal> method</para></listitem>
</itemizedlist>
<para>To add a matching rule description to the schema, construct a new <classname>
LDAPMatchingSchema</classname> object. You can specify the pieces of information
in the object as individual arguments or in a description formatted according
to <ulink url="http://www.ietf.org/rfc/rfc4517.txt" type="text_url">RFC 4517</ulink>, <citetitle>Lightweight Directory Access Protocol (LDAP):
Syntaxes and Matching Rules</citetitle>.</para>
<para>Then, you can either invoke the <literal>add</literal> method of this
object or the <literal>addMatchingRule</literal> method of the <classname>LDAPSchema
</classname> object.</para>
<para>To remove a matching rule description, invoke the <literal>remove</literal> method
of this object.</para></sect2>
<sect2 id="server-info-schema-example"><title>Example of Working With Schema</title>
<para>The following example illustrates how to get the schema and how to add
object classes and attribute types.</para>
<programlisting>import netscape.ldap.*;
import java.util.*;
 
public class GetSchema {
    public static void main(String[] args) {
        try {
            UserArgs userArgs = new UserArgs("GetSchema", args, true);
            LDAPConnection ld = new LDAPConnection();
            ld.connect(userArgs.getHost(), userArgs.getPort());
            ld.authenticate(userArgs.getBindDN(), userArgs.getPassword());
 
            /* Get the schema. */
            LDAPSchema dirSchema = new LDAPSchema();
            dirSchema.fetchSchema(ld);
 
            /* Get and print the inetOrgPerson object class. */
            LDAPObjectClassSchema objClass =
                dirSchema.getObjectClass("inetOrgPerson");
            if (objClass != null)
                System.out.println("inetOrgPerson := " +
                    objClass.toString());
 
            /* Get and print the userPassword attribute. */
            LDAPAttributeSchema attrType =
                dirSchema.getAttribute("userpassword");
            if (attrType != null)
                System.out.println("userPassword := " +
                    attrType.toString());
 
            /* Add a new object class. Requires write access. */
            String[] requiredAttrs = {"cn", "mail"};
            String[] optionalAttrs = {"sn", "telephoneNumber"};
            LDAPObjectClassSchema newObjClass =
                new LDAPObjectClassSchema("newInetOrgPerson",
                    "1.2.3.4.5.6.7", "top", "Experiment",
                    requiredAttrs, optionalAttrs);
 
            /* Add the new object class to the schema. */
            newObjClass.add(ld);
 
            /* Create a new attribute type "hairColor". */
            LDAPAttributeSchema newAttrType =
                new LDAPAttributeSchema("hairColor",
                    "1.2.3.4.5.4.3.2.1", "Blonde, red, etc",
                    LDAPAttributeSchema.cis, false);
 
            /* Add the new attribute type to the schema. */
            newAttrType.add(ld);
 
            /* Fetch schema again to verify changes */
            dirSchema.fetchSchema(ld);
 
            /* Get and print the new attribute type. */
            newAttrType = dirSchema.getAttribute("hairColor");
            if (newAttrType != null)
                System.out.println("hairColor := " +
                    newAttrType.toString());
 
            /* Get and print the new object class. */
            newObjClass = dirSchema.getObjectClass("newInetOrgPerson");
            if (newObjClass != null)
                System.out.println("newInetOrgPerson := " +
                    newObjClass.toString());
 
            ld.disconnect();
        } catch ( Exception e ) {
            System.err.println(e.toString());
            System.exit(1);
        }
    }
}</programlisting>
</sect2>
</sect1>
</chapter>
