From faf61b625328a8cf6df3936397fdb38dfa1badc8 Mon Sep 17 00:00:00 2001
From: pgamba <pgamba@localhost>
Date: Thu, 27 Aug 2009 08:00:38 +0000
Subject: [PATCH] Fix 4193: Cannot see ECL cookie exchange response control with ldapsearch

---
 opends/src/server/org/opends/server/controls/EntryChangelogNotificationControl.java                |   19 +++--
 opends/tests/unit-tests-testng/src/server/org/opends/server/replication/ExternalChangeLogTest.java |   80 +++++++++++++++++++++++++-
 opends/src/messages/messages/protocol.properties                                                   |    5 +
 opends/src/messages/messages/tools.properties                                                      |    4 +
 opends/src/server/org/opends/server/tools/LDAPSearch.java                                          |   19 ++++++
 5 files changed, 115 insertions(+), 12 deletions(-)

diff --git a/opends/src/messages/messages/protocol.properties b/opends/src/messages/messages/protocol.properties
index 337198c..5ffa795 100644
--- a/opends/src/messages/messages/protocol.properties
+++ b/opends/src/messages/messages/protocol.properties
@@ -1414,4 +1414,9 @@
 MILD_ERR_CANNOT_DECODE_CONTROL_VALUE_1508=Cannot decode the provided \
  control %s because an error occurred while attempting to \
  decode the control value:  %s
+MILD_ERR_ECLN_NO_CONTROL_VALUE_1509=Cannot decode the provided entry changelog \
+ notification control because it does not have a value
+MILD_ERR_ECLN_CANNOT_DECODE_VALUE_1510=Cannot decode the provided entry \
+ changelog notification control because an error occurred while attempting to \
+ decode the control value:  %s
 
diff --git a/opends/src/messages/messages/tools.properties b/opends/src/messages/messages/tools.properties
index 9b254cf..14cd41d 100644
--- a/opends/src/messages/messages/tools.properties
+++ b/opends/src/messages/messages/tools.properties
@@ -2515,3 +2515,7 @@
 INFO_LDIFIMPORT_THREAD_COUNT_PLACEHOLDER_1687={count}
 SEVERE_ERR_LDIFIMPORT_CANNOT_PARSE_THREAD_COUNT_1688=The value %s for \
 threadCount cannot be parsed: %s
+
+INFO_LDAPSEARCH_PUBLIC_CHANGELOG_COOKIE_EXC_1689=# Public \
+ changelog exchange control(%s): %s
+
diff --git a/opends/src/server/org/opends/server/controls/EntryChangelogNotificationControl.java b/opends/src/server/org/opends/server/controls/EntryChangelogNotificationControl.java
index 402e4d1..7001fc2 100644
--- a/opends/src/server/org/opends/server/controls/EntryChangelogNotificationControl.java
+++ b/opends/src/server/org/opends/server/controls/EntryChangelogNotificationControl.java
@@ -25,8 +25,8 @@
  *      Copyright 2009 Sun Microsystems, Inc.
  */
 package org.opends.server.controls;
-import static org.opends.messages.ProtocolMessages.ERR_ECN_CANNOT_DECODE_VALUE;
-import static org.opends.messages.ProtocolMessages.ERR_ECN_NO_CONTROL_VALUE;
+import static org.opends.messages.ProtocolMessages.ERR_ECLN_CANNOT_DECODE_VALUE;
+import static org.opends.messages.ProtocolMessages.ERR_ECLN_NO_CONTROL_VALUE;
 import static org.opends.server.loggers.debug.DebugLogger.debugEnabled;
 import static org.opends.server.loggers.debug.DebugLogger.getTracer;
 import static org.opends.server.protocols.asn1.ASN1Constants.*;
@@ -72,12 +72,12 @@
      * {@inheritDoc}
      */
     public EntryChangelogNotificationControl decode(
-        boolean isCritical, ByteString value) throws DirectoryException
-        {
+        boolean isCritical, ByteString value)
+    throws DirectoryException
+    {
       if (value == null)
       {
-        // FIXME:ECL Create error messages dedicated to this control
-        Message message = ERR_ECN_NO_CONTROL_VALUE.get();
+        Message message = ERR_ECLN_NO_CONTROL_VALUE.get();
         throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message);
       }
 
@@ -97,11 +97,11 @@
         }
 
         Message message =
-          ERR_ECN_CANNOT_DECODE_VALUE.get(getExceptionMessage(e));
+          ERR_ECLN_CANNOT_DECODE_VALUE.get(getExceptionMessage(e));
         throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message, e);
       }
       return new EntryChangelogNotificationControl(isCritical, cookie);
-        }
+    }
 
     public String getOID()
     {
@@ -141,8 +141,11 @@
    */
   public void writeValue(ASN1Writer writer) throws IOException {
     writer.writeStartSequence(UNIVERSAL_OCTET_STRING_TYPE);
+    writer.writeStartSequence();
     writer.writeOctetString(cookie.toString());
     writer.writeEndSequence();
+    writer.writeEndSequence();
+    writer.flush();
   }
 
 
diff --git a/opends/src/server/org/opends/server/tools/LDAPSearch.java b/opends/src/server/org/opends/server/tools/LDAPSearch.java
index 1d3e377..9a79ba3 100644
--- a/opends/src/server/org/opends/server/tools/LDAPSearch.java
+++ b/opends/src/server/org/opends/server/tools/LDAPSearch.java
@@ -274,6 +274,25 @@
                       }
                     } catch (Exception e) {}
                   }
+                  else if (c.getOID().equals(OID_ECL_COOKIE_EXCHANGE_CONTROL))
+                  {
+                    try
+                    {
+                      EntryChangelogNotificationControl ctrl =
+                        EntryChangelogNotificationControl.DECODER.decode(
+                          c.isCritical(), ((LDAPControl) c).getValue());
+                      out.println(
+                          INFO_LDAPSEARCH_PUBLIC_CHANGELOG_COOKIE_EXC.get(
+                            c.getOID(), ctrl.getCookie()));
+                    }
+                    catch (Exception e)
+                    {
+                      if (debugEnabled())
+                      {
+                        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+                      }
+                    }
+                  }
                 }
 
                 SearchResultEntryProtocolOp searchEntryOp =
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/ExternalChangeLogTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/ExternalChangeLogTest.java
index 69f2d4a..ecb556d 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/ExternalChangeLogTest.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/ExternalChangeLogTest.java
@@ -28,6 +28,7 @@
 
 import static org.opends.server.TestCaseUtils.TEST_ROOT_DN_STRING;
 import static org.opends.server.loggers.ErrorLogger.logError;
+import static org.opends.server.loggers.debug.DebugLogger.debugEnabled;
 import static org.opends.server.loggers.debug.DebugLogger.getTracer;
 import static org.opends.server.replication.protocol.OperationContext.SYNCHROCONTEXT;
 import static org.opends.server.util.StaticUtils.createEntry;
@@ -37,11 +38,14 @@
 import static org.testng.Assert.assertTrue;
 import static org.testng.Assert.fail;
 
+import java.io.BufferedReader;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
+import java.io.StringReader;
 import java.net.ServerSocket;
 import java.net.Socket;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedHashSet;
 import java.util.LinkedList;
@@ -104,6 +108,7 @@
 import org.opends.server.replication.server.ReplicationServer;
 import org.opends.server.replication.server.ReplicationServerDomain;
 import org.opends.server.replication.service.ReplicationBroker;
+import org.opends.server.tools.LDAPSearch;
 import org.opends.server.tools.LDAPWriter;
 import org.opends.server.types.Attribute;
 import org.opends.server.types.AttributeValue;
@@ -128,6 +133,7 @@
 import org.opends.server.util.TimeThread;
 import org.opends.server.workflowelement.externalchangelog.ECLSearchOperation;
 import org.opends.server.workflowelement.localbackend.LocalBackendModifyDNOperation;
+import org.testng.Assert;
 import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
@@ -1199,6 +1205,11 @@
       assertEquals(searchOp.getResultCode(), ResultCode.SUCCESS,
           searchOp.getErrorMessage().toString());
       // test 4 entries returned
+      String cookie1 = "o=test:"+cn1.toString()+";o=test2:;";
+      String cookie2 = "o=test:"+cn2.toString()+";o=test2:;";
+      String cookie3 = "o=test:"+cn3.toString()+";o=test2:;";
+      String cookie4 = "o=test:"+cn4.toString()+";o=test2:;";
+      
       assertEquals(searchOp.getSearchEntries().size(), 4);
       LinkedList<SearchResultEntry> entries = searchOp.getSearchEntries();
       if (entries != null)
@@ -1218,7 +1229,7 @@
             checkValue(resultEntry,"replicaidentifier","1201");
             checkValue(resultEntry,"targetdn","uid="+tn+"1," + TEST_ROOT_DN_STRING);
             checkValue(resultEntry,"changetype","delete");
-            checkValue(resultEntry,"changelogcookie","o=test:"+cn1.toString()+";o=test2:;");
+            checkValue(resultEntry,"changelogcookie",cookie1);
             checkValue(resultEntry,"targetentryuuid",tn+"uuid1");
             checkValue(resultEntry,"changenumber","0");
           } else if (i==2)
@@ -1235,7 +1246,7 @@
             checkValue(resultEntry,"replicaidentifier","1201");
             checkValue(resultEntry,"targetdn","uid="+tn+"2," + TEST_ROOT_DN_STRING);
             checkValue(resultEntry,"changetype","add");
-            checkValue(resultEntry,"changelogcookie","o=test:"+cn2.toString()+";o=test2:;");
+            checkValue(resultEntry,"changelogcookie",cookie2);
             checkValue(resultEntry,"targetentryuuid",user1entryUUID);
             checkValue(resultEntry,"changenumber","0");
           } else if (i==3)
@@ -1250,7 +1261,7 @@
             checkValue(resultEntry,"replicaidentifier","1201");
             checkValue(resultEntry,"targetdn","uid="+tn+"3," + TEST_ROOT_DN_STRING);
             checkValue(resultEntry,"changetype","modify");
-            checkValue(resultEntry,"changelogcookie","o=test:"+cn3.toString()+";o=test2:;");
+            checkValue(resultEntry,"changelogcookie",cookie3);
             checkValue(resultEntry,"targetentryuuid",tn+"uuid3");
             checkValue(resultEntry,"changenumber","0");
           } else if (i==4)
@@ -1262,7 +1273,7 @@
             checkValue(resultEntry,"replicaidentifier","1201");
             checkValue(resultEntry,"targetdn","uid="+tn+"4," + TEST_ROOT_DN_STRING);
             checkValue(resultEntry,"changetype","modrdn");
-            checkValue(resultEntry,"changelogcookie","o=test:"+cn4.toString()+";o=test2:;");
+            checkValue(resultEntry,"changelogcookie",cookie4);
             checkValue(resultEntry,"targetentryuuid",tn+"uuid4");
             checkValue(resultEntry,"newrdn","uid=ECLAllOpsnew4");            
             checkValue(resultEntry,"newsuperior",TEST_ROOT_DN_STRING2);
@@ -1271,6 +1282,17 @@
           }
         }
       }
+      
+      // Test the response control with ldapsearch tool
+      String result = ldapsearch("cn=changelog");
+      debugInfo(tn, "Entries:" + result);
+
+      ArrayList<String> ctrlList = getControls(result);
+      assertTrue(ctrlList.get(0).equals(cookie1));
+      assertTrue(ctrlList.get(1).equals(cookie2));
+      assertTrue(ctrlList.get(2).equals(cookie3));
+      assertTrue(ctrlList.get(3).equals(cookie4));
+      
       server01.stop();
       if (server02 != null)
         server02.stop();
@@ -1283,6 +1305,56 @@
     debugInfo(tn, "Ending test with success");
   }
 
+  protected ArrayList<String> getControls(String resultString)
+  {
+    StringReader r=new StringReader(resultString);
+    BufferedReader br=new BufferedReader(r);
+    ArrayList<String> ctrlList = new ArrayList<String>();
+    try {
+      while(true) {
+        String s = br.readLine();
+        if(s == null)
+          break;
+        if(!s.startsWith("#"))
+          continue;
+        String[] a=s.split(": ");
+        if(a.length != 2)
+          break;
+        ctrlList.add(a[1]);
+      }
+    } catch (IOException e) {
+      Assert.assertEquals(0, 1,  e.getMessage());
+    }
+    return ctrlList;
+  }
+
+  private static final ByteArrayOutputStream oStream = new ByteArrayOutputStream();
+  private static final ByteArrayOutputStream eStream = new ByteArrayOutputStream();
+
+  private String ldapsearch(String baseDN)
+  {
+    // test search as directory manager returns content
+    String[] args3 =
+    {
+      "-h", "127.0.0.1",
+      "-p", String.valueOf(TestCaseUtils.getServerAdminPort()),
+      "-Z", "-X",
+      "-D", "cn=Directory Manager",
+      "-w", "password",
+      "-b", baseDN,
+      "-s", "sub",
+      "--control", "1.3.6.1.4.1.26027.1.5.4:false:;",
+      "(objectclass=*)"
+    };
+
+    oStream.reset();
+    eStream.reset();
+    int retVal =
+      LDAPSearch.mainSearch(args3, false, oStream, eStream);
+    Assert.assertEquals(0, retVal,  "Returned error: " + eStream.toString());
+    return oStream.toString();
+  }
+
   private static void checkValue(Entry entry, String attrName, String expectedValue)
   {
     AttributeValue av = null;

--
Gitblit v1.10.0