From 3441a670cdb9b46d3d4afc9c638ef2b41d35c05f Mon Sep 17 00:00:00 2001
From: Mark Craig <mark.craig@forgerock.com>
Date: Mon, 27 May 2013 16:03:13 +0000
Subject: [PATCH] CR-1746 Fix for OPENDJ-857: Dev guide should explain how to use a GenericControl

---
 opendj3/opendj-ldap-sdk-examples/src/site/xdoc/index.xml.vm                                                |    6 +
 opendj3/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/GetADChangeNotifications.java |  150 ++++++++++++++++++++++++++++++
 opendj3/src/main/docbkx/dev-guide/chap-controls.xml                                                        |   93 ++++++++++++++++++
 opendj3/pom.xml                                                                                            |   12 ++
 4 files changed, 260 insertions(+), 1 deletions(-)

diff --git a/opendj3/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/GetADChangeNotifications.java b/opendj3/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/GetADChangeNotifications.java
new file mode 100644
index 0000000..54df59b
--- /dev/null
+++ b/opendj3/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/GetADChangeNotifications.java
@@ -0,0 +1,150 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
+ * or http://forgerock.org/license/CDDLv1.0.html.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at legal-notices/CDDLv1_0.txt.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information:
+ *      Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
+ *      Portions copyright 2011-2013 ForgeRock AS
+ */
+
+package org.forgerock.opendj.examples;
+
+import java.io.IOException;
+
+import org.forgerock.opendj.ldap.Connection;
+import org.forgerock.opendj.ldap.ErrorResultException;
+import org.forgerock.opendj.ldap.ErrorResultIOException;
+import org.forgerock.opendj.ldap.LDAPConnectionFactory;
+import org.forgerock.opendj.ldap.ResultCode;
+import org.forgerock.opendj.ldap.SearchScope;
+import org.forgerock.opendj.ldap.controls.GenericControl;
+import org.forgerock.opendj.ldap.requests.Requests;
+import org.forgerock.opendj.ldap.requests.SearchRequest;
+import org.forgerock.opendj.ldap.responses.SearchResultEntry;
+import org.forgerock.opendj.ldap.responses.SearchResultReference;
+import org.forgerock.opendj.ldif.ConnectionEntryReader;
+import org.forgerock.opendj.ldif.LDIFEntryWriter;
+
+/**
+ * An example client application which searches Microsoft Active Directory
+ * synchronously, using {@link GenericControl} to pass the <a
+ * href="http://msdn.microsoft.com/en-us/library/windows/desktop/ms676877(v=vs.85).aspx"
+ * >Microsoft LDAP Notification control</a>.
+ *
+ * <p>This example is a near copy of {@link Search}, but works only with
+ * directory servers like Active Directory that support the control with OID
+ * 1.2.840.113556.1.4.528.
+ *
+ * <p>This example takes the following command line parameters:
+ *
+ * <pre>
+ *  &lt;host> &lt;port> &lt;username> &lt;password> &lt;baseDN>
+ * </pre>
+ *
+ * <p>The {@code baseDN} must be the root of a naming context in this example.
+ */
+@SuppressWarnings("resource")
+public final class GetADChangeNotifications {
+    /**
+     * Main method.
+     *
+     * @param args
+     *            The command line arguments: host, port, username, password,
+     *            base DN, where the base DN is the root of a naming context.
+     */
+    public static void main(final String[] args) {
+        if (args.length < 5) {
+            System.err.println("Usage: host port username password baseDN");
+            System.exit(1);
+        }
+
+        // Parse command line arguments.
+        final String hostName = args[0];
+        final int port = Integer.parseInt(args[1]);
+        final String userName = args[2];
+        final String password = args[3];
+        final String baseDN = args[4];
+
+        // See http://msdn.microsoft.com/en-us/library/windows/desktop/aa772153(v=vs.85).aspx
+        /* --- JCite --- */
+        final SearchScope scope = SearchScope.WHOLE_SUBTREE;
+        final String filter = "(objectclass=*)";
+        final String[] attributes = {
+            "objectclass", "objectGUID", "isDeleted", "uSNChanged"
+        };
+
+        // Create an LDIF writer which will write the search results to stdout.
+        final LDIFEntryWriter writer = new LDIFEntryWriter(System.out);
+
+        // Connect and bind to the server.
+        final LDAPConnectionFactory factory =
+                new LDAPConnectionFactory(hostName, port);
+        Connection connection = null;
+
+        try {
+            connection = factory.getConnection();
+            connection.bind(userName, password.toCharArray());
+
+            // Read the entries and output them as LDIF.
+            final SearchRequest request =
+                    Requests
+                            .newSearchRequest(baseDN, scope, filter, attributes)
+                            .addControl(
+                                    GenericControl
+                                            .newControl(
+                                                    "1.2.840.113556.1.4.528",
+                                                    true));
+            final ConnectionEntryReader reader = connection.search(request);
+            while (reader.hasNext()) {
+                if (!reader.isReference()) {
+                    final SearchResultEntry entry = reader.readEntry();
+                    writer.writeComment("Search result entry: "
+                            + entry.getName().toString());
+                    writer.writeEntry(entry);
+                    writer.flush();
+                } else {
+                    final SearchResultReference ref = reader.readReference();
+
+                    // Got a continuation reference.
+                    writer.writeComment("Search result reference: "
+                            + ref.getURIs().toString());
+                }
+            }
+        } /* --- JCite --- */ catch (final ErrorResultException e) {
+            System.err.println(e.getMessage());
+            System.exit(e.getResult().getResultCode().intValue());
+        } catch (final ErrorResultIOException e) {
+            System.err.println(e.getMessage());
+            System.exit(e.getCause().getResult().getResultCode().intValue());
+        } catch (final IOException e) {
+            System.err.println(e.getMessage());
+            System.exit(ResultCode.CLIENT_SIDE_LOCAL_ERROR.intValue());
+        } finally {
+            if (connection != null) {
+                connection.close();
+            }
+        }
+    }
+
+    private GetADChangeNotifications() {
+        // Not used.
+    }
+}
diff --git a/opendj3/opendj-ldap-sdk-examples/src/site/xdoc/index.xml.vm b/opendj3/opendj-ldap-sdk-examples/src/site/xdoc/index.xml.vm
index a941826..eee539b 100644
--- a/opendj3/opendj-ldap-sdk-examples/src/site/xdoc/index.xml.vm
+++ b/opendj3/opendj-ldap-sdk-examples/src/site/xdoc/index.xml.vm
@@ -20,7 +20,7 @@
   !
   ! CCPL HEADER END
   !
-  !      Copyright 2011-2012 ForgeRock AS
+  !      Copyright 2011-2013 ForgeRock AS
   !    
 -->
 <document xmlns="http://maven.apache.org/XDOC/2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
@@ -102,6 +102,10 @@
           <a href="xref/org/forgerock/opendj/examples/UpdateGroup.html">Update group</a>
           - illustrates how to add or remove a member from a static group
         </li>
+        <li>
+          <a href="xref/org/forgerock/opendj/examples/GetADChangeNotifications.html">Use <code>GenericControl</code></a>
+          - illustrates how to use <code>GenericControl</code> to get change notifications from Active Directory
+        </li>
       </ul>
     </section>
     <section name="Get the OpenDJ LDAP SDK Examples">
diff --git a/opendj3/pom.xml b/opendj3/pom.xml
index e471743..311f896 100644
--- a/opendj3/pom.xml
+++ b/opendj3/pom.xml
@@ -170,6 +170,18 @@
         </configuration>
         <executions>
           <execution>
+           <id>run-jcite</id>
+           <phase>pre-site</phase>
+           <configuration>
+            <sourcePaths>
+             <sourcePath>${project.basedir}/opendj-ldap-sdk-examples/src/main/java</sourcePath>
+            </sourcePaths>
+           </configuration>
+           <goals>
+            <goal>jcite</goal>
+           </goals>
+          </execution>
+          <execution>
             <id>copy-common</id>
             <phase>pre-site</phase>
             <goals>
diff --git a/opendj3/src/main/docbkx/dev-guide/chap-controls.xml b/opendj3/src/main/docbkx/dev-guide/chap-controls.xml
index 660f8e8..f00ca2f 100644
--- a/opendj3/src/main/docbkx/dev-guide/chap-controls.xml
+++ b/opendj3/src/main/docbkx/dev-guide/chap-controls.xml
@@ -1343,4 +1343,97 @@
 # Entries are sorted.
 # Position in list: 92/150</programlisting>
  </section>
+
+ <section xml:id="use-generic-control">
+  <title>Using a Generic Control</title>
+  <indexterm>
+   <primary>Controls</primary>
+   <secondary>Generic</secondary>
+  </indexterm>
+
+  <para>OpenDJ LDAP SDK supports many controls, but you might still need to
+  work with additional controls. If so, then in some cases you can use the
+  <literal>GenericControl</literal> class when adding the control to your
+  request.</para>
+
+  <para>For example, the Microsoft <link xlink:show="new"
+  xlink:href="http://msdn.microsoft.com/en-us/library/windows/desktop/aa366983(v=vs.85).aspx"
+  >LDAP Server Notification Control</link> with OID
+  <literal>1.2.840.113556.1.4.528</literal> can be used to register a change
+  notification request for a search on Microsoft Active Directory. You can use
+  a <literal>GenericControl.newControl()</literal> static method to add the
+  request control to your search.</para>
+
+  <programlisting language="java"
+  >[jcp:org.forgerock.opendj.examples.GetADChangeNotifications:--- JCite ---]</programlisting>
+
+  <para>When you run the search against Active Directory and then create,
+  update, and delete a new user, in this example
+  <literal>CN=New User,CN=Users,DC=ad,DC=example,DC=com</literal>, Active
+  Directory notifies you of changes to directory data.</para>
+
+  <programlisting language="ldif"
+  ># Search result entry: CN=RID Set,CN=WIN2008R2641,OU=Domain Controllers,
+ DC=ad,DC=example,DC=com
+dn: CN=RID Set,CN=WIN2008R2641,OU=Domain Controllers,DC=ad,DC=example,DC=com
+objectClass: top
+objectClass: rIDSet
+objectGUID:: 178zQQic3EOoBOB1j2QVgQ==
+uSNChanged: 12446
+
+# Search result entry: CN=New User,CN=Users,DC=ad,DC=example,DC=com
+dn: CN=New User,CN=Users,DC=ad,DC=example,DC=com
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: user
+objectGUID:: 7XE/OoJdFEqAegwAi2eNlA==
+uSNChanged: 12753
+
+# Search result entry: CN=New User,CN=Users,DC=ad,DC=example,DC=com
+dn: CN=New User,CN=Users,DC=ad,DC=example,DC=com
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: user
+objectGUID:: 7XE/OoJdFEqAegwAi2eNlA==
+uSNChanged: 12755
+
+# Search result entry: CN=New User,CN=Users,DC=ad,DC=example,DC=com
+dn: CN=New User,CN=Users,DC=ad,DC=example,DC=com
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: user
+objectGUID:: 7XE/OoJdFEqAegwAi2eNlA==
+uSNChanged: 12757
+
+# Search result entry: CN=New User,CN=Users,DC=ad,DC=example,DC=com
+dn: CN=New User,CN=Users,DC=ad,DC=example,DC=com
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: user
+objectGUID:: 7XE/OoJdFEqAegwAi2eNlA==
+uSNChanged: 12758
+
+# Search result entry: CN=New User\0ADEL:3a3f71ed-5d82-4a14-807a-0c008b678d94,
+# CN=Deleted Objects,DC=ad,DC=example,DC=com
+dn: CN=New User\0ADEL:3a3f71ed-5d82-4a14-807a-0c008b678d94,CN=Deleted Objects,
+ DC=ad,DC=example,DC=com
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: user
+objectGUID:: 7XE/OoJdFEqAegwAi2eNlA==
+isDeleted: TRUE
+uSNChanged: 12759
+</programlisting>
+
+  <para>The <literal>GenericControl</literal> class is useful with controls that
+  do not require you to encode complex request values, or decode complex
+  response values. If the control you want to you requires complex encoding
+  or decoding, you might have to implement
+  <literal>org.forgerock.opendj.ldap.controls.Control</literal>.</para>
+ </section>
 </chapter>

--
Gitblit v1.10.0