# RemapTestDriver1.java

    /*
    ** Module   : RemapTestDriver1.java
    ** Abstract : simplest test application
    **
    ** Copyright (c) 2005-2022, Golden Code Development Corporation.
    **
    ** -#- -I- --Date-- -T- --JPRM-- ----------------Description-----------------
    ** 001 SIY 20050224 ADD   @20049 Created initial version.
    ** 002 SIY 20050308 CHG   @20370 Test now is part of the package.
    ** 003 SIY 20050317 CHG   @20586 Added missing tests for basic functionality.
    **                               Cleaned up code and fixed comments.
    ** 004 SIY 20050429 CHG   @21028 Fixed comments and formatting, fixed object
    **                               classes to match current state, added batch
    **                               editing.
    ** 005 SIY 20050516 CHG   @21202 Updated documentation, added prompt before
    **                               starting work.
    ** 006 NVS 20050905 CHG   @22467 Initial log level is specified with directory
    **                               service.
    ** 007 GES 20070112 CHG   @31810 Removed initial log level.
    ** 008 TJD 20220504              Java 11 compatibility minor changes
    */
    /*
    ** This program is free software: you can redistribute it and/or modify
    ** it under the terms of the GNU Affero General Public License as
    ** published by the Free Software Foundation, either version 3 of the
    ** License, or (at your option) any later version.
    **
    ** 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 Affero General Public License for more details.
    **
    ** You may find a copy of the GNU Affero GPL version 3 at the following
    ** location: https://www.gnu.org/licenses/agpl-3.0.en.html
    **
    ** Additional terms under GNU Affero GPL version 3 section 7:
    **
    **   Under Section 7 of the GNU Affero GPL version 3, the following additional
    **   terms apply to the works covered under the License.  These additional terms
    **   are non-permissive additional terms allowed under Section 7 of the GNU
    **   Affero GPL version 3 and may not be removed by you.
    **
    **   0. Attribution Requirement.
    **
    **     You must preserve all legal notices or author attributions in the covered
    **     work or Appropriate Legal Notices displayed by works containing the covered
    **     work.  You may not remove from the covered work any author or developer
    **     credit already included within the covered work.
    **
    **   1. No License To Use Trademarks.
    **
    **     This license does not grant any license or rights to use the trademarks
    **     Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
    **     of Golden Code Development Corporation. You are not authorized to use the
    **     name Golden Code, FWD, or the names of any author or contributor, for
    **     publicity purposes without written authorization.
    **
    **   2. No Misrepresentation of Affiliation.
    **
    **     You may not represent yourself as Golden Code Development Corporation or FWD.
    **
    **     You may not represent yourself for publicity purposes as associated with
    **     Golden Code Development Corporation, FWD, or any author or contributor to
    **     the covered work, without written authorization.
    **
    **   3. No Misrepresentation of Source or Origin.
    **
    **     You may not represent the covered work as solely your work.  All modified
    **     versions of the covered work must be marked in a reasonable way to make it
    **     clear that the modified work is not originating from Golden Code Development
    **     Corporation or FWD.  All modified versions must contain the notices of
    **     attribution required in this license.
    */

    package com.goldencode.p2j.directory;

    import java.io.*;

    import com.goldencode.p2j.cfg.*;

    /**
     * Simple test application. This test performs simplest operations: it
     * instantiates <code>DirectoryService</code>, adds a number of nodes and
     * performs operations with them.
     * <p>
     * <b>WARNING: </b> THIS IS A TEST APPLICATION! UNDER NO CIRCUMSTANCES IT
     * SHOULD BE INVOKED AGAINST PRODUCTION DIRECTORY BECAUSE THIS WILL CAUSE
     * SEVERE DAMAGE OF THE DIRECTORY AND LOSS OF IMPORTANT SECURITY DATA!!!
     */
    class RemapTestDriver1
    {
       /** Total number of failed tests. */
       private static int failed = 0;

       /** Total number of performed tests. */
       private static int tests = 0;

       /**
        * Print text and operation result code.
        *
        * @param   text
        *          Text banner for the test.
        * @param   rc
        *          Actual result
        * @param   expected
        *          Expected result
        */
       private static void prc(String text, boolean rc, boolean expected)
       {
          tests++;

          if (rc != expected)
             failed++;

          System.out.println("Testing " + text
             + ((rc == expected) ? " passed" : " failed"));
       }

       /**
        * Print provided array into stdout
        *
        * @param   arr
        *          Array to print.
        */
       private static void printArray(Object[] arr)
       {
          if (arr == null)
          {
             System.out.println("null");
             return;
          }

          System.out.println("array of " + arr.length + " elements");

          for (int i = 0; i < arr.length; i++)
          {
             System.out.println("[" + i + "] = " + arr[i]);
          }

          System.out.println();
       }

       /**
        * Print testing summary report.
        */
       private static void printReport()
       {
          System.out.println("\nTotal: " + tests + " tests performed\n" + failed
             + " tests failed");
       }

       /**
        * Print directory tree.
        *
        * @param   nodeId
        *          Root of the subtree which will be removed.
        */
       private static void printSubtree(String nodeId)
       {
          DirectoryService directory = DirectoryService.getInstance();

          String[] nodes = directory.enumerateNodes(nodeId);

          System.out.println(nodeId);

          for (int i = 0; nodes != null && i < nodes.length; i++)
          {
             if (nodeId.equals(""))
                printSubtree("/" + nodes[i] + "/");
             else
                printSubtree(nodeId + nodes[i] + "/");

          }
       }

       /**
        * Remove entire subtree. Note that all errors are ignored, so there is no
        * warranty that subtree will be removed. As a consequence it can be
        * invoked for "" or "/meta" subtree and everything that can be deleted
        * will be deleted.
        *
        * @param   nodeId
        *          Root of the subtree which will be removed.
        */
       private static void pruneSubtree(String nodeId)
       {
          DirectoryService directory = DirectoryService.getInstance();

          String[] nodes = directory.enumerateNodes(nodeId);

          //System.out.println(nodeId);

          for (int i = 0; nodes != null && i < nodes.length; i++)
          {
             if (nodeId.equals(""))
                pruneSubtree("/" + nodes[i] + "/");
             else
                pruneSubtree(nodeId + nodes[i] + "/");
          }

          directory.deleteNode(nodeId);
    //      boolean rc = directory.deleteNode(nodeId);
    //      System.out.println("Removing [" + nodeId + "] => "
    //         + (rc ? "success" : "failure"));
       }

       /**
        * Compare two byte arrays.
        *
        * @param   one
        *          First array to compare.
        * @param   two
        *          Second array to compare.
        * @return  <code>true</code> if arrays are equal (i.e. have identical
        *          number of elements and all elements are equal).
        */
       private static boolean cmp(byte[] one, byte[] two)
       {
          if (one == null && two == null)
             return true;

          if (one == two)
             return true;

          if (one.length != two.length)
             return false;

          for (int i = 0; i < one.length; i++)
             if (one[i] != two[i])
                return false;

          return true;
       }

       /**
        * Main application entry point.
        *
        * @param   args
        *          Application command line parameters.
        * @throws  ConfigurationException
        *          forwarded from <code>BootstrapConfig</code> constructor.
        */
       public static void main(String[] args)
       throws ConfigurationException
       {
          if (args.length != 2)
          {
             System.out.println("usage: java RemapTestDriver1 "
                + "<config.xml> <pw>");
             return;
          }

          try
          {
             System.out.println("WARNING! This test application is about to " +
                                "overwrite existing directory!");
             System.out.println("Press Enter to continue or Ctrl+C to break:");
             System.out.flush();

             int ch = System.in.read();

             if (ch < 0)
                return;
          }
          catch (IOException e)
          {
             return;
          }

          BootstrapConfig bc = null;

          if (args.length == 2)
          {
             bc = new BootstrapConfig(args[0],
                                      args[1].toCharArray(),
                                      null,
                                      null);
          }

          DirectoryService directory = DirectoryService.createInstance(bc);

          boolean bindRes = directory.bind();

          prc("Binding", bindRes, true);

          if (!bindRes)
          {
             System.out.println("Testing can't continue");
             return;
          }

          bindRes = directory.openBatch("");

          if (!bindRes)
          {
             System.out.println("Testing can't continue");
             return;
          }

          pruneSubtree("/Security/");
          pruneSubtree("/Application/");

          //Make Eclipse happy
          if (false)
          {
             printSubtree("");
             printArray(new String[0]);
          }

          //Prepare attributes
          //User1
          Attribute[] attrUser1 = new Attribute[]
          {
             new Attribute(directory.getClassNodeAttribute("user", "person"),
                           new Object[]
                           { new String("Gregory Shah") }),
             new Attribute(directory.getClassNodeAttribute("user", "groups"),
                           new Object[]
                           { new String("users"), new String("admins") }),
             new Attribute(directory.getClassNodeAttribute("user", "mode"),
                           new Object[]
                           { 0 }), };

          //User2
          Attribute[] attrUser2 = new Attribute[]
          {
             new Attribute(directory.getClassNodeAttribute("user", "person"),
                           new Object[]
                           { new String("Sergey Yevtushenko") }),
             new Attribute(directory.getClassNodeAttribute("user", "groups"),
                           new Object[]
                           { new String("users") }),
             new Attribute(directory.getClassNodeAttribute("user", "mode"),
                           new Object[]
                           { 0 }), };

          //boolean, booleanOption, booleans
          Attribute[] attrBoolean = new Attribute[]
          { new Attribute(directory.getClassNodeAttribute("boolean", "value"),
                          new Object[]
                          { true }) };

          //bytes, bytesOption, bytess
          Attribute[] attrBytes = new Attribute[]
          { new Attribute(directory.getClassNodeAttribute("bytes", "value"),
                          new Object[]
                          { new byte[]
                          { 0, 1, 2 } }) };

          //integer, integerOption, integers
          Attribute[] attrInteger = new Attribute[]
          { new Attribute(directory.getClassNodeAttribute("integer", "value"),
                          new Object[]
                          { 0 }) };

          //string, stringOption, strings
          Attribute[] attrString = new Attribute[]
          { new Attribute(directory.getClassNodeAttribute("string", "value"),
                          new Object[]
                          { new String("initial value") }) };

          //auditDecision, auditResource, authMode, directoryRights

          Attribute[] attrAuthResource = new Attribute[]
          { new Attribute(directory.getClassNodeAttribute("auditResource", "type"),
                          new Object[]
                          { "auditResource:type" }) };

          Attribute[] attrAuthMode = new Attribute[]
          { new Attribute(directory.getClassNodeAttribute("authMode", "mode"),
                          new Object[]
                          { 1 }) };

          Attribute[] attrDirectoryRights = new Attribute[]
          { new Attribute(directory.getClassNodeAttribute("directoryRights",
                                                          "permissions"),
                          new Object[]
                          { new BitField(8) }) };

          //binding, lock, process, terminal
          Attribute[] attrBinding = new Attribute[]
          {
             new Attribute(directory.getClassNodeAttribute("binding", "reftype"),
                           new Object[]
                           { false }),
             new Attribute(
                           directory.getClassNodeAttribute("binding", "reference"),
                           new Object[]
                           { new String("reference") }) };

          //Stage #1: base tree, and tests for container, user and group
          prc("Adding \"/security/test\" out of order",
              directory.addNode("/Security/Test", "container", null), false);

          prc("Add \"/security\"", directory.addNode("/Security", "container",
                                                     null), true);
          prc("Add \"/security/groups\"", directory.addNode("/Security/Groups",
                                                            "container", null),
              true);
          prc("Add \"/security/groups/users\"",
              directory.addNode("/Security/Groups/Users", "group", null), true);
          prc("Add \"/security/groups/admins\"",
              directory.addNode("/SecuritY/GroupS/AdminS", "group", null), true);
          prc("Add \"/security/users\"", directory.addNode("/security/users/",
                                                           "container", null),
              true);

          prc("Add \"/security/users/ges\"",
              directory.addNode("/security/users/ges", "user", attrUser1), true);
          prc("Add \"/security/users/siy\"",
              directory.addNode("/security/users/siy", "user", attrUser2), true);

          //Stage #2:
          //Add different types of nodes

          //Root containers
          prc("Add \"/application\"", directory.addNode("/application",
                                                        "container", null), true);
          prc("Add \"/application/data\"", directory.addNode("/application/data",
                                                             "container", null),
              true);

          prc("Add \"/application/security\"",
              directory.addNode("/application/security", "container", null), true);

          //boolean, booleanOption, booleans

          prc("Class boolean", directory.addNode("/application/data/boolean",
                                                 "boolean", attrBoolean), true);
          prc("Class booleanOption",
              directory.addNode("/application/data/booleanOption",
                                "booleanOption", null), true);
          prc("Class booleans", directory.addNode("/application/data/booleans",
                                                  "booleans", null), true);

          //bytes, bytesOption, bytess

          prc("Class bytes attribute[0]", attrBytes[0].isValid(), true);

          prc("Class bytes", directory.addNode("/application/data/bytes",
                                               "bytes", attrBytes), true);
          prc("Class bytesOption",
              directory.addNode("/application/data/bytesOption", "bytesOption",
                                null), true);
          prc("Class bytess", directory.addNode("/application/data/bytess",
                                                "bytess", null), true);

          //integer, integerOption, integers

          prc("Class integer", directory.addNode("/application/data/integer",
                                                 "integer", attrInteger), true);
          prc("Class integerOption",
              directory.addNode("/application/data/integerOption",
                                "integerOption", null), true);
          prc("Class integers", directory.addNode("/application/data/integers",
                                                  "integers", null), true);

          //string, stringOption, strings
          prc("Class string", directory.addNode("/application/data/string",
                                                "string", attrString), true);
          prc("Class stringOption",
              directory.addNode("/application/data/stringOption", "stringOption",
                                null), true);
          prc("Class strings", directory.addNode("/application/data/strings",
                                                 "strings", null), true);

          //auditDecision, auditResource, authMode, directoryRights

          prc("Class auditDecision",
              directory.addNode("/application/data/auditDecision",
                                "auditDecision", null), true);
          prc("Class auditResource",
              directory.addNode("/application/data/auditResource",
                                "auditResource", attrAuthResource), true);
          prc("Class authMode", directory.addNode("/application/data/authMode",
                                                  "authMode", attrAuthMode), true);
          prc("Class directoryRights",
              directory.addNode("/application/data/directoryRights",
                                "directoryRights", attrDirectoryRights), true);

          //binding, lock, process, terminal
          prc("Class binding", directory.addNode("/application/data/binding",
                                                 "binding", attrBinding), true);
          prc("Class lock", directory.addNode("/application/data/lock", "lock",
                                              null), true);
          prc("Class process", directory.addNode("/application/data/process",
                                                 "process", null), true);
          prc("Class terminal", directory.addNode("/application/data/terminal",
                                                  "terminal", null), true);

          //Stage #3
          //string (add/remove/change)
          prc("Add value to class string",
              directory.addNodeString("/application/data/string", "value",
                                      "new value"), false);

          System.out.println(directory.getNodeString("/application/data/string",
                                                     "value", 0));

          prc("Remove value from the class string",
              directory.deleteNodeAttributeValue("/application/data/string",
                                                 "value", 0), false);

          System.out.println(directory.getNodeString("/application/data/string",
                                                     "value", 0));

          prc("Check value of the class string (before change)",
              "initial value".equals(
                 directory.getNodeString("/application/data/string", "value", 0)),
              true);

          prc("Change value of the class string",
              directory.setNodeString("/application/data/string", "value", 0,
                                      "new value"), true);

          prc("Check value of the class string (after change)",
              "new value".equals(
                 directory.getNodeString("/application/data/string", "value", 0)),
              true);

          //strings (multiple add/multiple change/multiple remove)
          prc("Add value to class strings",
              directory.addNodeString("/application/data/strings", "values",
                                      "value #0"), true);

          prc("Add value to class strings",
              directory.addNodeString("/application/data/strings", "values",
                                      "value #1"), true);

          prc("Check value #0 of the class strings",
              "value #0".equals(directory.getNodeString(
                                                      "/application/data/strings",
                                                      "values", 0)), true);

          prc("Check value #1 of the class strings",
              "value #1".equals(directory.getNodeString(
                                                      "/application/data/strings",
                                                      "values", 1)), true);

          prc("Remove value #1 from the class strings",
              directory.deleteNodeAttributeValue("/application/data/strings",
                                                 "values", 1), true);

          prc("Check value #1 of the class strings",
              directory.getNodeString("/application/data/strings", "values", 1)
                 == null,
              true);

          prc("Check value #0 of the class strings",
              "value #0".equals(directory.getNodeString(
                                                      "/application/data/strings",
                                                      "values", 0)), true);

          prc("Remove value #0 from the class strings",
              directory.deleteNodeAttributeValue("/application/data/strings",
                                                 "values", 0), true);

          prc("Remove value #0 from the class strings",
              directory.deleteNodeAttributeValue("/application/data/strings",
                                                 "values", 0), false);

          prc("Add multiple values to class strings",
              directory.setNodeStrings("/application/data/strings", "values",
                                       new String[]
                                       { "value #0", "value #1" }), true);

          prc("Check value #0 of the class strings",
              "value #0".equals(directory.getNodeString(
                                                      "/application/data/strings",
                                                      "values", 0)), true);

          prc("Check value #1 of the class strings",
              "value #1".equals(directory.getNodeString(
                                                      "/application/data/strings",
                                                      "values", 1)), true);

          prc("Remove value #0 from the class strings",
              directory.deleteNodeAttributeValue("/application/data/strings",
                                                 "values", 0), true);

          prc("Check value #0 of the class strings",
              "value #1".equals(directory.getNodeString(
                                                      "/application/data/strings",
                                                      "values", 0)), true);

          //stringOption
          prc("Add value to class stringOption",
              directory.addNodeString("/application/data/stringOption", "option",
                                      "value #0"), true);

          prc("Add one more value to class stringOption",
              directory.addNodeString("/application/data/stringOption", "option",
                                      "value #1"), false);

          prc("Check value of the class stringOption (before change)",
              "value #0".equals(directory.getNodeString(
                                                 "/application/data/stringOption",
                                                 "option", 0)), true);

          prc("Change value of the class stringOption",
              directory.setNodeString("/application/data/stringOption", "option",
                                      0, "value #1"), true);

          prc("Check value of the class stringOption (after change)",
              "value #1".equals(directory.getNodeString(
                                                 "/application/data/stringOption",
                                                 "option", 0)), true);

          prc("Remove value from the class stringOption",
              directory.deleteNodeAttributeValue(
                                                 "/application/data/stringOption",
                                                 "option", 0), true);

          prc("Remove value from the class stringOption",
              directory.deleteNodeAttributeValue(
                                                 "/application/data/stringOption",
                                                 "option", 0), false);

          prc("Check value of the class stringOption",
              directory.getNodeString("/application/data/stringOption", "option",
                                      1) == null, true);

          //--------------------------------------------------------------
          //integer
          prc("Add value to class integer",
              directory.addNodeInteger("/application/data/integer", "value", 1),
              false);

          prc("Remove value from the class integer",
              directory.deleteNodeAttributeValue("/application/data/integer",
                                                 "value", 0), false);

          prc("Check value of the class integer (before change)",
              (Integer.valueOf(0)).equals(directory.getNodeInteger(
                                                      "/application/data/integer",
                                                      "value", 0)), true);

          prc("Change value of the class integer",
              directory.setNodeInteger("/application/data/integer", "value", 0, 2),
              true);

          prc("Check value of the class integer (after change)",
              (Integer.valueOf(2)).equals(directory.getNodeInteger(
                                                      "/application/data/integer",
                                                      "value", 0)), true);

          //integers (multiple add/multiple change/multiple remove)
          prc("Add value to class integers",
              directory.addNodeInteger("/application/data/integers", "values", 1),
              true);

          prc("Add value to class integers",
              directory.addNodeInteger("/application/data/integers", "values", 2),
              true);

          prc("Check value #0 of the class integers",
              (Integer.valueOf(1)).equals(directory.getNodeInteger(
                                                     "/application/data/integers",
                                                     "values", 0)),
              true);

          prc("Check value #1 of the class integers",
              (Integer.valueOf(2)).equals(directory.getNodeInteger(
                                                     "/application/data/integers",
                                                     "values", 1)),
              true);

          prc("Remove value #1 from the class integers",
              directory.deleteNodeAttributeValue("/application/data/integers",
                                                 "values", 1), true);

          prc("Check value #1 of the class integers",
              directory.getNodeInteger("/application/data/integers", "values", 1)
                 == null,
              true);

          prc("Check value #0 of the class integers",
              (Integer.valueOf(1)).equals(directory.getNodeInteger(
                                                     "/application/data/integers",
                                                     "values", 0)),
              true);

          prc("Remove value #0 from the class integers",
              directory.deleteNodeAttributeValue("/application/data/integers",
                                                 "values", 0), true);

          prc("Remove value #0 from the class integers",
              directory.deleteNodeAttributeValue("/application/data/integers",
                                                 "values", 0), false);

          prc("Add multiple values to class integers",
              directory.setNodeIntegers("/application/data/integers", "values",
                                        new int[]
                                        { 1, 2 }), true);

          Integer[] in = directory.getNodeIntegers("/application/data/integers",
                                                   "values");
          prc("Check array of values of the class integers", in.length == 2
             && in[0].equals(Integer.valueOf(1)) && in[1].equals(Integer.valueOf(2)),
              true);

          prc("Check value #0 of the class integers",
              (Integer.valueOf(1)).equals(directory.getNodeInteger(
                                                     "/application/data/integers",
                                                     "values", 0)),
              true);

          prc("Check value #1 of the class integers",
              (Integer.valueOf(2)).equals(directory.getNodeInteger(
                                                     "/application/data/integers",
                                                     "values", 1)),
              true);

          prc("Remove value #0 from the class integers",
              directory.deleteNodeAttributeValue("/application/data/integers",
                                                 "values", 0), true);

          prc("Check value #0 of the class integers",
              (Integer.valueOf(2)).equals(directory.getNodeInteger(
                                                     "/application/data/integers",
                                                     "values", 0)),
              true);

          //      integerOption
          prc("Add value to class integerOption",
              directory.addNodeInteger("/application/data/integerOption",
                                       "option", 1), true);

          prc("Add one more value to class integerOption",
              directory.addNodeInteger("/application/data/integerOption",
                                       "option", 2), false);

          prc("Check value of the class integerOption (before change)",
              (Integer.valueOf(1)).equals(directory.getNodeInteger(
                                                "/application/data/integerOption",
                                                "option", 0)),
              true);

          prc("Change value of the class integerOption",
              directory.setNodeInteger("/application/data/integerOption",
                                       "option", 0, 2), true);

          prc("Check value of the class integerOption (after change)",
              (Integer.valueOf(2)).equals(directory.getNodeInteger(
                                                "/application/data/integerOption",
                                                "option", 0)),
              true);

          prc("Remove value from the class integerOption",
              directory.deleteNodeAttributeValue(
                                                 "/application/data/integerOption",
                                                 "option", 0), true);

          prc("Remove value from the class integerOption",
              directory.deleteNodeAttributeValue(
                                                 "/application/data/integerOption",
                                                 "option", 0), false);

          prc("Check value of the class integerOption",
              directory.getNodeInteger("/application/data/integerOption",
                                       "option", 1) == null, true);
          //--------------------------------------------------------------
          //boolean
          prc("Add value to class boolean",
              directory.addNodeBoolean("/application/data/boolean", "value", true),
              false);

          prc("Remove value from the class boolean",
              directory.deleteNodeAttributeValue("/application/data/boolean",
                                                 "value", 0), false);

          prc("Check value of the class boolean (before change)",
              (Boolean.TRUE).equals(directory.getNodeBoolean(
                                                      "/application/data/boolean",
                                                      "value", 0)),
              true);

          prc("Change value of the class boolean",
              directory.setNodeBoolean("/application/data/boolean", "value", 0,
                                       false), true);

          prc("Check value of the class boolean (after change)",
              (Boolean.FALSE).equals(directory.getNodeBoolean(
                                                      "/application/data/boolean",
                                                      "value", 0)),
              true);

          //booleans (multiple add/multiple change/multiple remove)
          prc("Add value to class booleans",
              directory.addNodeBoolean("/application/data/booleans", "values",
                                       true), true);

          prc("Add value to class booleans",
              directory.addNodeBoolean("/application/data/booleans", "values",
                                       false), true);

          prc("Check value #0 of the class booleans",
              (Boolean.TRUE).equals(directory.getNodeBoolean(
                                                     "/application/data/booleans",
                                                     "values", 0)),
              true);

          prc("Check value #1 of the class booleans",
              (Boolean.FALSE).equals(directory.getNodeBoolean(
                                                     "/application/data/booleans",
                                                     "values", 1)),
              true);

          prc("Remove value #1 from the class booleans",
              directory.deleteNodeAttributeValue("/application/data/booleans",
                                                 "values", 1), true);

          prc("Check value #1 of the class booleans",
              directory.getNodeBoolean("/application/data/booleans", "values", 1)
                 == null,
              true);

          prc("Check value #0 of the class booleans",
              (Boolean.TRUE).equals(directory.getNodeBoolean(
                                                     "/application/data/booleans",
                                                     "values", 0)),
              true);

          prc("Remove value #0 from the class booleans",
              directory.deleteNodeAttributeValue("/application/data/booleans",
                                                 "values", 0), true);

          prc("Remove value #0 from the class booleans",
              directory.deleteNodeAttributeValue("/application/data/booleans",
                                                 "values", 0), false);

          prc("Add multiple values to class booleans",
              directory.setNodeBooleans("/application/data/booleans", "values",
                                        new boolean[]
                                        { true, false }), true);

          Boolean[] bo = directory.getNodeBooleans("/application/data/booleans",
                                                   "values");
          prc("Check array of values of the class booleans", bo.length == 2
             && bo[0].equals(Boolean.TRUE)
             && bo[1].equals(Boolean.FALSE), true);

          prc("Check value #0 of the class booleans",
              (Boolean.TRUE).equals(directory.getNodeBoolean(
                                                     "/application/data/booleans",
                                                     "values", 0)),
              true);

          prc("Check value #1 of the class booleans",
              (Boolean.FALSE).equals(directory.getNodeBoolean(
                                                     "/application/data/booleans",
                                                     "values", 1)),
              true);

          prc("Remove value #0 from the class booleans",
              directory.deleteNodeAttributeValue("/application/data/booleans",
                                                 "values", 0), true);

          prc("Check value #0 of the class booleans",
              (Boolean.FALSE).equals(directory.getNodeBoolean(
                                                     "/application/data/booleans",
                                                     "values", 0)),
              true);

          //booleanOption
          prc("Add value to class booleanOption",
              directory.addNodeBoolean("/application/data/booleanOption",
                                       "option", false), true);

          prc("Add one more value to class booleanOption",
              directory.addNodeBoolean("/application/data/booleanOption",
                                       "option", true), false);

          prc("Check value of the class booleanOption (before change)",
              (Boolean.FALSE).equals(directory.getNodeBoolean(
                                                "/application/data/booleanOption",
                                                "option", 0)),
              true);

          prc("Change value of the class booleanOption",
              directory.setNodeBoolean("/application/data/booleanOption",
                                       "option", 0, true), true);

          prc("Check value of the class booleanOption (after change)",
              (Boolean.TRUE).equals(directory.getNodeBoolean(
                                                "/application/data/booleanOption",
                                                "option", 0)),
              true);

          prc("Remove value from the class booleanOption",
              directory.deleteNodeAttributeValue(
                                                 "/application/data/booleanOption",
                                                 "option", 0), true);

          prc("Remove value from the class booleanOption",
              directory.deleteNodeAttributeValue(
                                                 "/application/data/booleanOption",
                                                 "option", 0), false);

          prc("Check value of the class booleanOption",
              directory.getNodeBoolean("/application/data/booleanOption",
                                       "option", 1) == null, true);

          //--------------------------------------------------------------
          //bytes
          prc("Add value to class bytes",
              directory.addNodeByteArray("/application/data/bytes", "value",
                                         new byte[]
                                         { 0, 1, 2 }), false);

          prc("Remove value from the class bytes",
              directory.deleteNodeAttributeValue("/application/data/bytes",
                                                 "value", 0), false);

          prc("Check value of the class bytes (before change)", cmp(new byte[]
          { 0, 1, 2 }, directory.getNodeByteArray("/application/data/bytes",
                                                  "value", 0)), true);

          prc("Change value of the class bytes",
              directory.setNodeByteArray("/application/data/bytes", "value", 0,
                                         new byte[]
                                         { 0, 1, 2 }), true);

          prc("Check value of the class bytes (after change)", cmp(new byte[]
          { 0, 1, 2 }, directory.getNodeByteArray("/application/data/bytes",
                                                  "value", 0)), true);

          //bytess (multiple add/multiple change/multiple remove)
          prc("Add value to class bytess",
              directory.addNodeByteArray("/application/data/bytess", "values",
                                         new byte[]
                                         { 0, 1, 2 }), true);

          prc("Add value to class bytess",
              directory.addNodeByteArray("/application/data/bytess", "values",
                                         new byte[]
                                         { 3, 2, 1 }), true);

          prc("Check value #0 of the class bytess", cmp(new byte[]
          { 0, 1, 2 }, directory.getNodeByteArray("/application/data/bytess",
                                                  "values", 0)), true);

          prc("Check value #1 of the class bytess", cmp(new byte[]
          { 3, 2, 1 }, directory.getNodeByteArray("/application/data/bytess",
                                                  "values", 1)), true);

          prc("Remove value #1 from the class bytess",
              directory.deleteNodeAttributeValue("/application/data/bytess",
                                                 "values", 1), true);

          prc("Check value #1 of the class bytess",
              directory.getNodeByteArray("/application/data/bytess", "values", 1)
                 == null,
              true);

          prc("Check value #0 of the class bytess", cmp(new byte[]
          { 0, 1, 2 }, directory.getNodeByteArray("/application/data/bytess",
                                                  "values", 0)), true);

          prc("Remove value #0 from the class bytess",
              directory.deleteNodeAttributeValue("/application/data/bytess",
                                                 "values", 0), true);

          prc("Remove value #0 from the class bytess",
              directory.deleteNodeAttributeValue("/application/data/bytess",
                                                 "values", 0), false);

          prc("Add multiple values to class bytess",
              directory.setNodeByteArrays("/application/data/bytess", "values",
                                          new byte[][]
                                          { new byte[]
                                          { 0, 1, 2 }, new byte[]
                                          { 3, 2, 1 } }), true);

          byte[][] ba = directory.getNodeByteArrays("/application/data/bytess",
                                                    "values");

          prc("Check array of values of the class bytess",
              ba.length == 2 &&
              cmp(new byte[] { 0, 1, 2 }, ba[0]) &&
              cmp(new byte[] { 3, 2, 1 }, ba[1]),
              true);

          prc("Check value #0 of the class bytess",
              cmp(new byte[] { 0, 1, 2 },
                  directory.getNodeByteArray("/application/data/bytess",
                                             "values", 0)), true);

          prc("Check value #1 of the class bytess",
              cmp(new byte[] { 3, 2, 1 },
                  directory.getNodeByteArray("/application/data/bytess",
                                             "values", 1)), true);

          prc("Remove value #0 from the class bytess",
              directory.deleteNodeAttributeValue("/application/data/bytess",
                                                 "values", 0), true);

          prc("Check value #0 of the class bytess",
              cmp(new byte[] { 3, 2, 1 },
                  directory.getNodeByteArray("/application/data/bytess",
                                             "values", 0)), true);

          //bytesOption
          prc("Add value to class bytesOption",
              directory.addNodeByteArray("/application/data/bytesOption",
                                         "option", new byte[] { 0, 1, 2 }), true);

          prc("Add one more value to class bytesOption",
              directory.addNodeByteArray("/application/data/bytesOption",
                                         "option", new byte[] { 3, 2, 1 }), false);

          prc("Check value of the class bytesOption (before change)",
              cmp(new byte[] { 0, 1, 2 },
                  directory.getNodeByteArray("/application/data/bytesOption",
                                             "option", 0)), true);

          prc("Change value of the class bytesOption",
              directory.setNodeByteArray("/application/data/bytesOption",
                                         "option", 0, new byte[] { 4, 5, 6 }),
              true);

          prc("Check value of the class bytesOption (after change)",
              cmp(new byte[] { 4, 5, 6 },
                  directory.getNodeByteArray("/application/data/bytesOption",
                                             "option", 0)), true);

          prc("Remove value from the class bytesOption",
              directory.deleteNodeAttributeValue("/application/data/bytesOption",
                                                 "option", 0), true);

          prc("Remove value from the class bytesOption",
              directory.deleteNodeAttributeValue("/application/data/bytesOption",
                                                 "option", 0), false);

          prc("Check value of the class bytesOption",
              directory.getNodeByteArray("/application/data/bytesOption",
                                         "option", 1) == null, true);
          //--------------------------------------------------------------
          //time, date
          //--------------------------------------------------------------
          prc("Add date value to \"/security/users/siy\"",
              directory.addNodeDate("/security/users/siy", "pwsetdate",
                                    new DateValue(2005, 3, 15)), true);

          prc("Check date value of \"/security/users/siy\"",
              (new DateValue(2005, 3, 15)).equals(
                                    directory.getNodeDate("/security/users/siy",
                                                          "pwsetdate", 0)), true);

          prc("Change date value of \"/security/users/siy\"",
              directory.setNodeDate("/security/users/siy", "pwsetdate", 0,
                                    new DateValue(2005, 3, 16)), true);

          prc("Check date value of \"/security/users/siy\"",
              (new DateValue(2005, 3, 16)).equals(
                                    directory.getNodeDate("/security/users/siy",
                                                          "pwsetdate", 0)), true);

          prc("Add date value to \"/security/users/siy\"",
              directory.addNodeDate("/security/users/siy", "pwsetdate",
                                    new DateValue(2005, 3, 15)), false);

          prc("Remove date value from \"/security/users/siy\"",
              directory.deleteNodeAttributeValue("/security/users/siy",
                                                 "pwsetdate", 0), true);

          prc("Add date as array to \"/security/users/siy\"",
              directory.setNodeDates("/security/users/siy", "pwsetdate",
                                     new DateValue[]
                                     { new DateValue(2005, 3, 19) }), true);

          DateValue[] d = directory.getNodeDates("/security/users/siy",
                                                 "pwsetdate");

          prc("Check array of dates",
              d.length == 1 && d[0].equals(new DateValue(2005, 3, 19)),
              true);

          //--------------------------------------------------------------
          prc("Add time value to \"/security/users/siy\"",
              directory.addNodeTime("/security/users/siy", "pwsettime",
                                    new TimeValue(10, 10, 10)), true);

          prc("Check time value of \"/security/users/siy\"",
              (new TimeValue(10, 10, 10)).equals(
                                     directory.getNodeTime("/security/users/siy",
                                                           "pwsettime", 0)), true);

          prc("Change time value of \"/security/users/siy\"",
              directory.setNodeTime("/security/users/siy", "pwsettime", 0,
                                    new TimeValue(10, 10, 11)), true);

          prc("Check time value of \"/security/users/siy\"",
              (new TimeValue(10, 10, 11)).equals(
                                     directory.getNodeTime("/security/users/siy",
                                                           "pwsettime", 0)), true);

          prc("Add time value to \"/security/users/siy\"",
              directory.addNodeTime("/security/users/siy", "pwsettime",
                                    new TimeValue(10, 10, 12)), false);

          prc("Remove time value from \"/security/users/siy\"",
              directory.deleteNodeAttributeValue("/security/users/siy",
                                                 "pwsettime", 0), true);

          prc("Add time as array to \"/security/users/siy\"",
              directory.setNodeTimes("/security/users/siy", "pwsettime",
                                     new TimeValue[]
                                     { new TimeValue(12, 11, 12) }), true);

          TimeValue[] t = directory.getNodeTimes("/security/users/siy",
                                                 "pwsettime");

          prc("Check array of times", t.length == 1
             && t[0].equals(new TimeValue(12, 11, 12)), true);

          //--------------------------------------------------------------
          //
          ///application/data/directoryRights
          BitField bitField0 = new BitField(7);
          BitField bitField1 = new BitField(7);

          bitField1.set(2);

          prc("Check bitfield value of \"/application/data/directoryRights\"",
              bitField0.equals(
                    directory.getNodeBitField("/application/data/directoryRights",
                                              "permissions", 0)), true);

          prc("Change bitfield value of \"/application/data/directoryRights\" #1",
              directory.setNodeBitField("/application/data/directoryRights",
                                        "permissions", 0, bitField1), true);

          prc("Check bitfield value of \"/application/data/directoryRights\" #1",
              bitField1.equals(
                    directory.getNodeBitField("/application/data/directoryRights",
                                              "permissions", 0)), true);

          prc("Change bitfield value of \"/application/data/directoryRights\" #2",
              directory.setNodeBitFields("/application/data/directoryRights",
                                         "permissions", new BitField[]
                                         { bitField0 }), true);

          prc("Check bitfield value of \"/application/data/directoryRights\" #2",
              bitField0.equals(
                    directory.getNodeBitField("/application/data/directoryRights",
                                              "permissions", 0)), true);

          prc("Add bitfield value to \"/application/data/directoryRights\"",
              directory.addNodeBitField("/application/data/directoryRights",
                                        "permissions", bitField0), false);

          prc("Remove bitfield value from \"/application/data/directoryRights\"",
              directory.deleteNodeAttributeValue(
                                              "/application/data/directoryRights",
                                              "permissions", 0), false);

          prc("Set bitfield as array to \"/application/data/directoryRights\"",
              directory.setNodeBitFields("/application/data/directoryRights",
                                         "permissions", new BitField[]
                                         { bitField0 }), true);

          BitField[] f;
          f = directory.getNodeBitFields("/application/data/directoryRights",
                                         "permissions");

          prc("Check array of bitfields",
              f.length == 1 && f[0].equals(bitField0), true);

          //--------------------------------------------------------------
          //wrong parameters check
          prc("Add value to class stringOption (wrong attribute)",
              directory.addNodeString("/application/data/stringOption", "value",
                                      "value #0"), false);

          prc("Remove value from the class stringOption (wrong attribute)",
              directory.deleteNodeAttributeValue(
                                                 "/application/data/stringOption",
                                                 "value", 0), false);

          //--------------------------------------------------------------
          // Remaining methods

          boolean rc = false;

          rc = directory.deleteNodeAttribute("/application/data/strings",
                                             "values");

          prc("Checking deleteNodeAttribute() for non-mandatory attribute", rc,
              true);

          String[] a = directory.getNodeStrings("/application/data/strings",
                                                "values");

          //printArray(a);

          prc("Checking getNodeStrings() from empty attribute", a == null, true);

          Attribute[] attrStrings =
          { new Attribute(directory.getClassNodeAttribute("strings", "values"),
                          new Object[]
                          { new String("value 1"), new String("value 2") }), };

          prc("Checking setNodeAttributes()",
              directory.setNodeAttributes("/application/data/strings",
                                          attrStrings), true);

          a = directory.getNodeStrings("/application/data/strings", "values");

          rc = (a != null && a[0].equals("value 1") && a[1].equals("value 2"));

          prc("Checking getNodeStrings() from non-empty attribute", rc, true);

          Attribute[] aa;
          aa = directory.getNodeAttributes("/security/users/siy");

          //printArray(aa);

          prc("Checking getNodeAttributes() for \"/security/users/siy\"",
              aa != null &&
              aa.length == 5 &&
              aa[0].isValid() &&
              aa[1].isValid() &&
              aa[2].isValid() &&
              aa[3].isValid() &&
              aa[4].isValid(), true);

          prc("Checking getNodeClass() for \"/security/users/siy\"",
              "/meta/class/user".equals(directory.getNodeClass("/security/users/siy")),
              true);

          NodeAttribute[] na;
          na = directory.enumerateNodeAttributes("/security/users/siy");

          //printArray(na);
          prc("Checking enumerateNodeAttributes() for \"/security/users/siy\"",
              na != null && na.length == 5, true);

          //System.out.println(directory.getClassNodeAttribute("user",
          // "person"));
          prc("Checking getClassNodeAttribute() for class user",
              directory.getClassNodeAttribute("user", "person") != null, true);

          prc("Comitting chnages", directory.closeBatch(true), true);

          //--------------------------------------------------------------
          prc("Unbinding", directory.unbind(), true);

          printReport();
       }
    }