From 32034d853f3a284424ccfa87b6de210f1ca814e1 Mon Sep 17 00:00:00 2001
From: Matthew Swift <matthew.swift@forgerock.com>
Date: Tue, 29 Nov 2011 00:31:21 +0000
Subject: [PATCH] Fix OPENDJ-43 (Synchronous Connection decorator implementations should not use AsynchronousConnections) and OPENDJ-328 (Make it easier to implement connection decorators).

---
 opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AbstractConnection.java |  334 ++++++++++++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 301 insertions(+), 33 deletions(-)

diff --git a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AbstractConnection.java b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AbstractConnection.java
index b1b34f4..869c71d 100644
--- a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AbstractConnection.java
+++ b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AbstractConnection.java
@@ -38,10 +38,11 @@
 import java.util.Collection;
 import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
 
 import org.forgerock.i18n.LocalizedIllegalArgumentException;
-import org.forgerock.opendj.ldap.requests.Requests;
-import org.forgerock.opendj.ldap.requests.SearchRequest;
+import org.forgerock.opendj.ldap.requests.*;
 import org.forgerock.opendj.ldap.responses.*;
 import org.forgerock.opendj.ldif.ConnectionEntryReader;
 
@@ -56,16 +57,66 @@
 public abstract class AbstractConnection implements Connection
 {
 
-  private static final class SingleEntryHandler implements SearchResultHandler
+  private static final class SingleEntryFuture implements
+      FutureResult<SearchResultEntry>, SearchResultHandler
   {
+    private final ResultHandler<? super SearchResultEntry> handler;
+
     private volatile SearchResultEntry firstEntry = null;
 
     private volatile SearchResultReference firstReference = null;
 
     private volatile int entryCount = 0;
 
+    private volatile FutureResult<Result> future = null;
 
 
+
+    private SingleEntryFuture(
+        final ResultHandler<? super SearchResultEntry> handler)
+    {
+      this.handler = handler;
+    }
+
+
+
+    @Override
+    public boolean cancel(final boolean mayInterruptIfRunning)
+    {
+      return future.cancel(mayInterruptIfRunning);
+    }
+
+
+
+    @Override
+    public SearchResultEntry get() throws ErrorResultException,
+        InterruptedException
+    {
+      future.get();
+      return get0();
+    }
+
+
+
+    @Override
+    public SearchResultEntry get(final long timeout, final TimeUnit unit)
+        throws ErrorResultException, TimeoutException, InterruptedException
+    {
+      future.get(timeout, unit);
+      return get0();
+    }
+
+
+
+    @Override
+    public int getRequestID()
+    {
+      return future.getRequestID();
+    }
+
+
+
+    @Override
     public boolean handleEntry(final SearchResultEntry entry)
     {
       if (firstEntry == null)
@@ -78,6 +129,137 @@
 
 
 
+    @Override
+    public void handleErrorResult(final ErrorResultException error)
+    {
+      if (handler != null)
+      {
+        handler.handleErrorResult(error);
+      }
+    }
+
+
+
+    @Override
+    public boolean handleReference(final SearchResultReference reference)
+    {
+      if (firstReference == null)
+      {
+        firstReference = reference;
+      }
+      return true;
+    }
+
+
+
+    @Override
+    public void handleResult(final Result result)
+    {
+      if (handler != null)
+      {
+        try
+        {
+          handler.handleResult(get0());
+        }
+        catch (final ErrorResultException e)
+        {
+          handler.handleErrorResult(e);
+        }
+      }
+    }
+
+
+
+    @Override
+    public boolean isCancelled()
+    {
+      return future.isCancelled();
+    }
+
+
+
+    @Override
+    public boolean isDone()
+    {
+      return future.isDone();
+    }
+
+
+
+    private SearchResultEntry get0() throws ErrorResultException
+    {
+      if (entryCount == 0)
+      {
+        // Did not find any entries.
+        throw newErrorResult(ResultCode.CLIENT_SIDE_NO_RESULTS_RETURNED,
+            ERR_NO_SEARCH_RESULT_ENTRIES.get().toString());
+      }
+      else if (entryCount > 1)
+      {
+        // Got more entries than expected.
+        throw newErrorResult(
+            ResultCode.CLIENT_SIDE_UNEXPECTED_RESULTS_RETURNED,
+            ERR_UNEXPECTED_SEARCH_RESULT_ENTRIES.get(entryCount).toString());
+      }
+      else if (firstReference != null)
+      {
+        // Got an unexpected search result reference.
+        throw newErrorResult(
+            ResultCode.CLIENT_SIDE_UNEXPECTED_RESULTS_RETURNED,
+            ERR_UNEXPECTED_SEARCH_RESULT_REFERENCES.get(
+                firstReference.getURIs().iterator().next()).toString());
+      }
+      else
+      {
+        return firstEntry;
+      }
+    }
+
+
+
+    private void setResultFuture(final FutureResult<Result> future)
+    {
+      this.future = future;
+    }
+  }
+
+
+
+  private static final class SingleEntryHandler implements SearchResultHandler
+  {
+    private volatile SearchResultEntry firstEntry = null;
+
+    private volatile SearchResultReference firstReference = null;
+
+    private volatile int entryCount = 0;
+
+
+
+    @Override
+    public boolean handleEntry(final SearchResultEntry entry)
+    {
+      if (firstEntry == null)
+      {
+        firstEntry = entry;
+      }
+      entryCount++;
+      return true;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void handleErrorResult(final ErrorResultException error)
+    {
+      // Ignore.
+    }
+
+
+
+    @Override
     public boolean handleReference(final SearchResultReference reference)
     {
       if (firstReference == null)
@@ -92,17 +274,8 @@
     /**
      * {@inheritDoc}
      */
-    public void handleErrorResult(ErrorResultException error)
-    {
-      // Ignore.
-    }
-
-
-
-    /**
-     * {@inheritDoc}
-     */
-    public void handleResult(Result result)
+    @Override
+    public void handleResult(final Result result)
     {
       // Ignore.
     }
@@ -124,6 +297,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public Result add(final Entry entry) throws ErrorResultException,
       InterruptedException, UnsupportedOperationException,
       IllegalStateException, NullPointerException
@@ -136,6 +310,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public Result add(final String... ldifLines) throws ErrorResultException,
       InterruptedException, UnsupportedOperationException,
       LocalizedIllegalArgumentException, IllegalStateException,
@@ -149,6 +324,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public BindResult bind(final String name, final char[] password)
       throws ErrorResultException, InterruptedException,
       LocalizedIllegalArgumentException, UnsupportedOperationException,
@@ -162,6 +338,18 @@
   /**
    * {@inheritDoc}
    */
+  @Override
+  public void close()
+  {
+    close(Requests.newUnbindRequest(), null);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
   public CompareResult compare(final String name,
       final String attributeDescription, final String assertionValue)
       throws ErrorResultException, InterruptedException,
@@ -177,6 +365,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public Result delete(final String name) throws ErrorResultException,
       InterruptedException, LocalizedIllegalArgumentException,
       UnsupportedOperationException, IllegalStateException,
@@ -190,6 +379,21 @@
   /**
    * {@inheritDoc}
    */
+  @Override
+  public <R extends ExtendedResult> R extendedRequest(
+      final ExtendedRequest<R> request) throws ErrorResultException,
+      InterruptedException, UnsupportedOperationException,
+      IllegalStateException, NullPointerException
+  {
+    return extendedRequest(request, null);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
   public GenericExtendedResult extendedRequest(final String requestName,
       final ByteString requestValue) throws ErrorResultException,
       InterruptedException, UnsupportedOperationException,
@@ -204,6 +408,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public Result modify(final String... ldifLines) throws ErrorResultException,
       InterruptedException, UnsupportedOperationException,
       LocalizedIllegalArgumentException, IllegalStateException,
@@ -217,6 +422,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public Result modifyDN(final String name, final String newRDN)
       throws ErrorResultException, InterruptedException,
       LocalizedIllegalArgumentException, UnsupportedOperationException,
@@ -230,6 +436,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public SearchResultEntry readEntry(final DN baseObject,
       final String... attributeDescriptions) throws ErrorResultException,
       InterruptedException, UnsupportedOperationException,
@@ -246,6 +453,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public SearchResultEntry readEntry(final String baseObject,
       final String... attributeDescriptions) throws ErrorResultException,
       InterruptedException, LocalizedIllegalArgumentException,
@@ -260,6 +468,42 @@
   /**
    * {@inheritDoc}
    */
+  @Override
+  public FutureResult<SearchResultEntry> readEntryAsync(final DN name,
+      final Collection<String> attributeDescriptions,
+      final ResultHandler<? super SearchResultEntry> handler)
+      throws UnsupportedOperationException, IllegalStateException,
+      NullPointerException
+  {
+    final SearchRequest request = Requests.newSearchRequest(name,
+        SearchScope.BASE_OBJECT, Filter.getObjectClassPresentFilter());
+    if (attributeDescriptions != null)
+    {
+      request.getAttributes().addAll(attributeDescriptions);
+    }
+    return searchSingleEntryAsync(request, handler);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public ConnectionEntryReader search(final SearchRequest request,
+      final BlockingQueue<Response> entries)
+      throws UnsupportedOperationException, IllegalStateException,
+      NullPointerException
+  {
+    return new ConnectionEntryReader(this, request, entries);
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
   public Result search(final SearchRequest request,
       final Collection<? super SearchResultEntry> entries)
       throws ErrorResultException, InterruptedException,
@@ -274,6 +518,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public Result search(final SearchRequest request,
       final Collection<? super SearchResultEntry> entries,
       final Collection<? super SearchResultReference> references)
@@ -287,6 +532,7 @@
     final SearchResultHandler handler = new SearchResultHandler()
     {
 
+      @Override
       public boolean handleEntry(final SearchResultEntry entry)
       {
         entries.add(entry);
@@ -295,6 +541,18 @@
 
 
 
+      /**
+       * {@inheritDoc}
+       */
+      @Override
+      public void handleErrorResult(final ErrorResultException error)
+      {
+        // Ignore.
+      }
+
+
+
+      @Override
       public boolean handleReference(final SearchResultReference reference)
       {
         if (references != null)
@@ -309,17 +567,8 @@
       /**
        * {@inheritDoc}
        */
-      public void handleErrorResult(ErrorResultException error)
-      {
-        // Ignore.
-      }
-
-
-
-      /**
-       * {@inheritDoc}
-       */
-      public void handleResult(Result result)
+      @Override
+      public void handleResult(final Result result)
       {
         // Ignore.
       }
@@ -333,6 +582,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public ConnectionEntryReader search(final String baseObject,
       final SearchScope scope, final String filter,
       final String... attributeDescriptions)
@@ -350,6 +600,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public SearchResultEntry searchSingleEntry(final SearchRequest request)
       throws ErrorResultException, InterruptedException,
       UnsupportedOperationException, IllegalStateException,
@@ -361,17 +612,15 @@
     if (handler.entryCount == 0)
     {
       // Did not find any entries.
-      throw newErrorResult(
-          ResultCode.CLIENT_SIDE_NO_RESULTS_RETURNED,
+      throw newErrorResult(ResultCode.CLIENT_SIDE_NO_RESULTS_RETURNED,
           ERR_NO_SEARCH_RESULT_ENTRIES.get().toString());
     }
     else if (handler.entryCount > 1)
     {
       // Got more entries than expected.
-      throw newErrorResult(
-          ResultCode.CLIENT_SIDE_UNEXPECTED_RESULTS_RETURNED,
-          ERR_UNEXPECTED_SEARCH_RESULT_ENTRIES
-              .get(handler.entryCount).toString());
+      throw newErrorResult(ResultCode.CLIENT_SIDE_UNEXPECTED_RESULTS_RETURNED,
+          ERR_UNEXPECTED_SEARCH_RESULT_ENTRIES.get(handler.entryCount)
+              .toString());
     }
     else if (handler.firstReference != null)
     {
@@ -379,8 +628,7 @@
       throw newErrorResult(
           ResultCode.CLIENT_SIDE_UNEXPECTED_RESULTS_RETURNED,
           ERR_UNEXPECTED_SEARCH_RESULT_REFERENCES.get(
-              handler.firstReference.getURIs().iterator().next())
-              .toString());
+              handler.firstReference.getURIs().iterator().next()).toString());
     }
     else
     {
@@ -393,6 +641,7 @@
   /**
    * {@inheritDoc}
    */
+  @Override
   public SearchResultEntry searchSingleEntry(final String baseObject,
       final SearchScope scope, final String filter,
       final String... attributeDescriptions) throws ErrorResultException,
@@ -409,10 +658,29 @@
 
   /**
    * {@inheritDoc}
+   */
+  @Override
+  public FutureResult<SearchResultEntry> searchSingleEntryAsync(
+      final SearchRequest request,
+      final ResultHandler<? super SearchResultEntry> handler)
+      throws UnsupportedOperationException, IllegalStateException,
+      NullPointerException
+  {
+    final SingleEntryFuture innerFuture = new SingleEntryFuture(handler);
+    final FutureResult<Result> future = searchAsync(request, null, innerFuture);
+    innerFuture.setResultFuture(future);
+    return innerFuture;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
    * <p>
    * Sub-classes should provide an implementation which returns an appropriate
    * description of the connection which may be used for debugging purposes.
    */
+  @Override
   public abstract String toString();
 
 }

--
Gitblit v1.10.0