You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@harmony.apache.org by qi...@apache.org on 2008/06/04 08:48:11 UTC

svn commit: r663009 - in /harmony/enhanced/classlib/trunk/modules/jndi/src: main/java/org/apache/harmony/jndi/provider/ldap/ test/java/org/apache/harmony/jndi/provider/ldap/

Author: qiuxx
Date: Tue Jun  3 23:48:10 2008
New Revision: 663009

URL: http://svn.apache.org/viewvc?rev=663009&view=rev
Log:
Apply patch for HARMONY-5861,([classlib][jndi][ldap] - moving code of constructing NamingEnumeration from Context class to LdapSearchResult)

Added:
    harmony/enhanced/classlib/trunk/modules/jndi/src/test/java/org/apache/harmony/jndi/provider/ldap/LdapSearchResultTest.java   (with props)
Modified:
    harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapContextImpl.java
    harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapNamingEnumeration.java
    harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapSchemaContextImpl.java
    harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapSearchResult.java
    harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/ldapURLContext.java

Modified: harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapContextImpl.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapContextImpl.java?rev=663009&r1=663008&r2=663009&view=diff
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapContextImpl.java (original)
+++ harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapContextImpl.java Tue Jun  3 23:48:10 2008
@@ -209,6 +209,11 @@
         doBindOperation(connCtls);
     }
 
+    public LdapContextImpl(LdapContextImpl context, String dn)
+            throws NamingException {
+        this(context.client, context.env, dn);
+    }
+
     private void initial(LdapClient ldapClient,
             Hashtable<Object, Object> environment, String dn)
             throws InvalidNameException {
@@ -887,7 +892,6 @@
                 Hashtable<String, String> schemaDef = (Hashtable<String, String>) schemaTable
                         .get(schemaType.toLowerCase());
                 LdapAttribute attribute = (LdapAttribute) as.get(schemaType);
-               
                 String value;
                 String attrName;
                 for (int i = 0; i < attribute.size(); i++) {
@@ -898,8 +902,8 @@
             }
         }
 
-        ldapSchemaCtx = new LdapSchemaContextImpl(this, env, name,
-                schemaTable, LdapSchemaContextImpl.SCHEMA_ROOT_LEVEL);
+        ldapSchemaCtx = new LdapSchemaContextImpl(this, env, name, schemaTable,
+                LdapSchemaContextImpl.SCHEMA_ROOT_LEVEL);
         return ldapSchemaCtx;
     }
 
@@ -1083,7 +1087,8 @@
             filter.setValue("objectClass");
         } else {
             // only one attribute type and value pair
-            if (attributes.size() == 1 && attributes.getAll().next().size() == 1) {
+            if (attributes.size() == 1
+                    && attributes.getAll().next().size() == 1) {
                 filter = new Filter(Filter.EQUALITY_MATCH_FILTER);
                 Attribute att = attributes.getAll().next();
                 filter.setValue(new AttributeTypeAndValuePair(att.getID(), att
@@ -1111,33 +1116,10 @@
         controls.setReturningAttributes(as);
         LdapSearchResult result = doSearch(targetDN, filter, controls);
 
-        List<SearchResult> list = new ArrayList<SearchResult>();
-        Map<String, Attributes> entries = result.getEntries();
-        Name tempName = new LdapName(contextDn.toString());
-        tempName.addAll(name);
-        String baseDN = tempName.toString();
-        for (String dn : entries.keySet()) {
-            SearchResult sr = null;
-            if (dn.startsWith("ldap://")) {
-                sr = new SearchResult(dn, null, entries.get(dn), false);
-                int index = dn.indexOf("/", 7);
-                sr.setNameInNamespace(dn.substring(index + 1, dn.length()));
-                list.add(sr);
-            } else {
-                String relativeName = LdapUtils.convertToRelativeName(dn,
-                        baseDN);
-                sr = new SearchResult(relativeName, null, entries.get(dn));
-                sr.setNameInNamespace(dn);
-            }
-            list.add(sr);
-        }
-
-        if (list.size() == 0 && result.getException() != null) {
+        if (result.isEmpty() && result.getException() != null) {
             throw result.getException();
         }
-
-        return new LdapNamingEnumeration<SearchResult>(list, result
-                .getException());
+        return result.toSearchResultEnumeration(targetDN);
     }
 
     public NamingEnumeration<SearchResult> search(Name name, String filter,
@@ -1170,33 +1152,11 @@
 
         LdapSearchResult result = doSearch(targetDN, f, searchControls);
 
-        List<SearchResult> list = new ArrayList<SearchResult>();
-        Map<String, Attributes> entries = result.getEntries();
-        Name tempName = new LdapName(contextDn.toString());
-        tempName.addAll(name);
-        String baseDN = tempName.toString();
-        for (String dn : entries.keySet()) {
-            SearchResult sr = null;
-            if (dn.startsWith("ldap://")) {
-                sr = new SearchResult(dn, null, entries.get(dn), false);
-                int index = dn.indexOf("/", 7);
-                sr.setNameInNamespace(dn.substring(index + 1, dn.length()));
-                list.add(sr);
-            } else {
-                String relativeName = LdapUtils.convertToRelativeName(dn,
-                        baseDN);
-                sr = new SearchResult(relativeName, null, entries.get(dn));
-                sr.setNameInNamespace(dn);
-            }
-            list.add(sr);
-        }
-
-        if (list.size() == 0 && result.getException() != null) {
+        if (result.isEmpty() && result.getException() != null) {
             throw result.getException();
         }
-
-        return new LdapNamingEnumeration<SearchResult>(list, result
-                .getException());
+        
+        return result.toSearchResultEnumeration(targetDN);
     }
 
     public NamingEnumeration<SearchResult> search(Name name, String filter,
@@ -1285,33 +1245,34 @@
 
         LdapResult result = op.getResult();
 
-        op.getSearchResult().setException(
-                LdapUtils.getExceptionFromResult(result));
-
-        // has error, not deal with referrals
-        if (result.getResultCode() != LdapResult.REFERRAL
-                && op.getSearchResult().getException() != null) {
-            return op.getSearchResult();
-        }
+        if (result != null) {
+            op.getSearchResult().setException(
+                    LdapUtils.getExceptionFromResult(result));
+
+            // has error, not deal with referrals
+            if (result.getResultCode() != LdapResult.REFERRAL
+                    && op.getSearchResult().getException() != null) {
+                return op.getSearchResult();
+            }
 
-        // baseObject is not located at the server
-        if (result.getResultCode() == LdapResult.REFERRAL) {
-            ReferralException ex = new ReferralExceptionImpl(contextDn
-                    .toString(), result.getReferrals(), env);
-            try {
-                if (isFollowReferral(ex)) {
-                    LdapContextImpl ctx = (LdapContextImpl) getReferralContext(ex);
-                    return ctx.doSearch(op);
-                } else {
-                    op.getSearchResult().setException(ex);
+            // baseObject is not located at the server
+            if (result.getResultCode() == LdapResult.REFERRAL) {
+                ReferralException ex = new ReferralExceptionImpl(contextDn
+                        .toString(), result.getReferrals(), env);
+                try {
+                    if (isFollowReferral(ex)) {
+                        LdapContextImpl ctx = (LdapContextImpl) getReferralContext(ex);
+                        return ctx.doSearch(op);
+                    } else {
+                        op.getSearchResult().setException(ex);
+                        return op.getSearchResult();
+                    }
+                } catch (PartialResultException e) {
+                    op.getSearchResult().setException(e);
                     return op.getSearchResult();
                 }
-            } catch (PartialResultException e) {
-                op.getSearchResult().setException(e);
-                return op.getSearchResult();
             }
         }
-
         // there are SearchResultReference in search result
         if (op.getSearchResult().getRefURLs() != null
                 && op.getSearchResult().getRefURLs().size() != 0) {
@@ -1605,34 +1566,11 @@
 
         LdapSearchResult result = doSearch(targetDN, filter, controls);
 
-        List<NameClassPair> list = new ArrayList<NameClassPair>();
-        Map<String, Attributes> entries = result.getEntries();
-        Name tempName = new LdapName(contextDn.toString());
-        tempName.addAll(name);
-        String baseDN = tempName.toString();
-        for (String dn : entries.keySet()) {
-            String relativeName = LdapUtils.convertToRelativeName(dn, baseDN);
-            Attributes attrs = entries.get(dn);
-            Attribute attrClass = attrs.get("javaClassName");
-            String className = null;
-            if (attrClass != null) {
-                className = (String) attrClass.get(0);
-            } else {
-                className = DirContext.class.getName();
-            }
-            NameClassPair pair = new NameClassPair(relativeName, className,
-                    true);
-            pair.setNameInNamespace(dn);
-            list.add(pair);
-        }
-
-        // no entries return
-        if (list.size() == 0 && result.getException() != null) {
+        if (result.isEmpty() && result.getException() != null) {
             throw result.getException();
         }
 
-        return new LdapNamingEnumeration<NameClassPair>(list, result
-                .getException());
+        return result.toNameClassPairEnumeration(targetDN);
     }
 
     protected String getTargetDN(Name name, Name prefix)
@@ -1750,28 +1688,23 @@
          * there is only one ldap ns
          */
 
-        NamingEnumeration<NameClassPair> enu = list(name);
-
-        List<Binding> bindings = new ArrayList<Binding>();
+        // NamingEnumeration<NameClassPair> enu = list(name);
+        // absolute dn name to list
+        String targetDN = getTargetDN(name, contextDn);
 
-        while (enu.hasMore()) {
-            NameClassPair pair = enu.next();
-            Object bound = null;
-            if (!pair.getClassName().equals(DirContext.class.getName())) {
-                bound = lookup(pair.getName());
-            } else {
-                bound = new LdapContextImpl(this, env, contextDn.toString());
-            }
+        // construct one-level search using filter "(objectclass=*)"
+        SearchControls controls = new SearchControls();
+        controls.setSearchScope(SearchControls.ONELEVEL_SCOPE);
+        Filter filter = new Filter(Filter.PRESENT_FILTER);
+        filter.setValue("objectClass");
 
-            Binding binding = new Binding(pair.getName(), bound.getClass()
-                    .getName(), bound);
-            binding.setNameInNamespace(pair.getNameInNamespace());
-            bindings.add(binding);
+        LdapSearchResult result = doSearch(targetDN, filter, controls);
 
+        if (result.isEmpty() && result.getException() != null) {
+            throw result.getException();
         }
 
-        // FIXME: deal with exception
-        return new LdapNamingEnumeration<Binding>(bindings, null);
+        return result.toBindingEnumeration(this, name);
     }
 
     public NamingEnumeration<Binding> listBindings(String s)

Modified: harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapNamingEnumeration.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapNamingEnumeration.java?rev=663009&r1=663008&r2=663009&view=diff
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapNamingEnumeration.java (original)
+++ harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapNamingEnumeration.java Tue Jun  3 23:48:10 2008
@@ -17,66 +17,111 @@
 
 package org.apache.harmony.jndi.provider.ldap;
 
-import java.util.ArrayList;
 import java.util.Collection;
+import java.util.LinkedList;
 import java.util.NoSuchElementException;
 
+import javax.naming.CommunicationException;
 import javax.naming.NamingEnumeration;
 import javax.naming.NamingException;
 
+import org.apache.harmony.jndi.internal.nls.Messages;
+
 /**
  * TODO: dynamic load elements from server
  */
 public class LdapNamingEnumeration<T> implements NamingEnumeration<T> {
 
-    private ArrayList<T> values;
-
-    private int currentIndex;
+    private LinkedList<T> values;
 
     private NamingException exception;
 
     /**
+     * flag to indicate whether all element have been added
+     */
+    private boolean isFinished;
+
+    /**
+     * max time to wait next element in millisconds
+     */
+    private long timeout = DEFAULT_TIMEOUT;
+
+    private static final long DEFAULT_TIMEOUT = 30000;
+
+    /**
+     * This constructor equals to
+     * <code>LdapNamingEnumeration(Collection<T>, NamingException, true)</code>
+     */
+    public LdapNamingEnumeration(Collection<T> list, NamingException ex) {
+        this(list, ex, true);
+    }
+
+    /**
      * <code>list</code> and <code>ex</code> both can be <code>null</code>,
      * <code>null</code> of <code>list</code> will be treated as empty List.
      * 
      * @param list
-     *            All elements to be enumerate
+     *            elements added to the enumeration.
      * @param ex
-     *            exception would be thrown when over iterate
+     *            exception would be thrown when over iterate.
+     * @param isFinished
+     *            if all elements have been added.
      */
-    public LdapNamingEnumeration(Collection<T> list, NamingException ex) {
+    public LdapNamingEnumeration(Collection<T> list, NamingException ex,
+            boolean isFinished) {
         if (list == null) {
-            values = new ArrayList<T>();
+            values = new LinkedList<T>();
         } else {
-            values = new ArrayList<T>(list);
+            values = new LinkedList<T>(list);
         }
 
         exception = ex;
-        currentIndex = 0;
+        this.isFinished = isFinished;
     }
 
     /**
      * release all relative resources, current implementation just set
-     * enumeration values to <code>null</code>.
+     * enumeration values to <code>null</code> which indicate the enumeration
+     * is closed.
      */
-    public void close() throws NamingException {
+    public void close() {
         // no other resources need to release
-        values = null;
+        synchronized (values) {
+            values.clear();
+            values = null;
+        }
     }
 
     public boolean hasMore() throws NamingException {
+        // has been closed
         if (values == null) {
             return false;
         }
 
-        if (currentIndex < values.size()) {
+        if (!values.isEmpty()) {
             return true;
         }
-        // no elemnts to iterate, release resource first
+
+        synchronized (values) {
+            if (values.isEmpty() && !isFinished) {
+                waitMoreElement();
+                if (!values.isEmpty()) {
+                    return true;
+                }
+            }
+        }
+
         close();
+
         if (exception != null) {
             throw exception;
         }
+
+        if (!isFinished) {
+            // ldap.31=Read LDAP response message time out
+            throw new CommunicationException(Messages.getString("ldap.31")); //$NON-NLS-1$
+        }
+
         return false;
     }
 
@@ -86,11 +131,27 @@
      * invoked.
      */
     public T next() throws NamingException {
-        if (values == null || currentIndex >= values.size()) {
+        if (values == null || (values.isEmpty() && isFinished)) {
             throw new NoSuchElementException();
         }
 
-        return values.get(currentIndex++);
+        synchronized (values) {
+            if (values.isEmpty() && !isFinished) {
+                waitMoreElement();
+                // wait timeout
+                if (values.isEmpty() && !isFinished) {
+                    if (exception != null) {
+                        throw exception;
+                    }
+                    // ldap.31=Read LDAP response message time out
+                    throw new CommunicationException(Messages
+                            .getString("ldap.31")); //$NON-NLS-1$
+                } else if (values.isEmpty()) {
+                    throw new NoSuchElementException();
+                }
+            }
+            return values.poll();
+        }
     }
 
     public boolean hasMoreElements() {
@@ -98,26 +159,86 @@
             return false;
         }
 
-        if (currentIndex < values.size()) {
+        if (!values.isEmpty()) {
             return true;
         }
+
+        synchronized (values) {
+            if (values.isEmpty() && !isFinished) {
+                waitMoreElement();
+                if (!values.isEmpty()) {
+                    return true;
+                }
+            }
+        }
+
         return false;
     }
 
     public T nextElement() {
-        if (values == null || currentIndex >= values.size()) {
+        if (values == null || (values.isEmpty() && isFinished)) {
             throw new NoSuchElementException();
         }
 
-        return values.get(currentIndex++);
+        synchronized (values) {
+            if (values.isEmpty() && !isFinished) {
+                waitMoreElement();
+                if (values.isEmpty()) {
+                    throw new NoSuchElementException();
+                }
+            }
+            return values.poll();
+        }
+    }
+
+    private void waitMoreElement() {
+        try {
+            values.wait(timeout);
+        } catch (InterruptedException e) {
+            // ignore
+        }
     }
 
-    protected void setException(NamingException exception) {
+    void setException(NamingException exception) {
         this.exception = exception;
     }
-    
-    void add(T pair) {
-        values.add(pair);
+
+    void add(T pair, boolean isFinished) {
+        if (values == null) {
+            return;
+        }
+
+        synchronized (values) {
+            values.add(pair);
+            if (isFinished) {
+                this.isFinished = true;
+            }
+            values.notifyAll();
+        }
     }
 
+    void add(Collection<T> list, boolean isFinished) {
+        if (values == null) {
+            return;
+        }
+
+        synchronized (values) {
+            values.addAll(list);
+            if (isFinished) {
+                this.isFinished = true;
+            }
+            values.notifyAll();
+        }
+    }
+
+    boolean isFinished() {
+        return isFinished;
+    }
+
+    void setFinished() {
+        synchronized (values) {
+            isFinished = true;
+            values.notifyAll();
+        }
+    }
 }

Modified: harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapSchemaContextImpl.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapSchemaContextImpl.java?rev=663009&r1=663008&r2=663009&view=diff
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapSchemaContextImpl.java (original)
+++ harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapSchemaContextImpl.java Tue Jun  3 23:48:10 2008
@@ -16,6 +16,7 @@
  */
 package org.apache.harmony.jndi.provider.ldap;
 
+import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.Hashtable;
 import java.util.Iterator;
@@ -490,21 +491,19 @@
 
         Hashtable<String, Object> tempSchema = doLookup(name, size);
 
-        LdapNamingEnumeration<NameClassPair> enumeration = new LdapNamingEnumeration<NameClassPair>(
-                null, null);
-
         if (size == level - 1) {
-            return enumeration;
+            return new LdapNamingEnumeration<NameClassPair>(null, null);
         }
 
         Iterator<String> keys = tempSchema.keySet().iterator();
 
+        List<NameClassPair> list = new ArrayList<NameClassPair>();
         while (keys.hasNext()) {
-            enumeration.add(new NameClassPair(ldap2jndi(keys.next()), this
-                    .getClass().getName()));
+            list.add(new NameClassPair(ldap2jndi(keys.next()), this.getClass()
+                    .getName()));
         }
 
-        return enumeration;
+        return new LdapNamingEnumeration<NameClassPair>(list, null);
     }
 
     @Override
@@ -527,21 +526,19 @@
 
         Hashtable<String, Object> tempSchema = doLookup(name, size);
 
-        LdapNamingEnumeration<Binding> enumeration = new LdapNamingEnumeration<Binding>(
-                null, null);
-
         if (size == level - 1) {
-            return enumeration;
+            return new LdapNamingEnumeration<Binding>(null, null);
         }
 
         Iterator<String> keys = tempSchema.keySet().iterator();
 
+        List<Binding> list = new ArrayList<Binding>();
         while (keys.hasNext()) {
-            enumeration.add(new Binding(ldap2jndi(keys.next()), this.getClass()
+            list.add(new Binding(ldap2jndi(keys.next()), this.getClass()
                     .getName()));
         }
 
-        return enumeration;
+        return new LdapNamingEnumeration<Binding>(list, null);
     }
 
     @Override
@@ -647,8 +644,6 @@
 
         Hashtable<String, Object> subschemaTable = doLookup(name, size);
 
-        LdapNamingEnumeration<SearchResult> enumeration = new LdapNamingEnumeration<SearchResult>(
-                null, null);
         SearchResult searchResult;
         Attributes schemaAttributes;
         String schemaName;
@@ -656,6 +651,7 @@
 
         if (level - size > 1) {
             keyset = subschemaTable.keySet();
+            List<SearchResult> list = new ArrayList<SearchResult>();
             for (Iterator<String> i = keyset.iterator(); i.hasNext();) {
                 schemaName = ldap2jndi(i.next());
                 Name tempName = (Name) name.clone();
@@ -666,11 +662,12 @@
                             attributesToReturn);
                     searchResult = new SearchResult(ldap2jndi(schemaName), this
                             .getClass().getName(), null, schemaAttributes);
-                    enumeration.add(searchResult);
+                    list.add(searchResult);
                 }
             }
+            return new LdapNamingEnumeration<SearchResult>(list, null);
         }
-        return enumeration;
+        return new LdapNamingEnumeration<SearchResult>(null, null);
     }
 
     @Override
@@ -734,15 +731,13 @@
             }
         }
 
-        LdapNamingEnumeration<SearchResult> enumeration = new LdapNamingEnumeration<SearchResult>(
-                null, null);
-
         iterator = searchResults.iterator();
+        List<SearchResult> list = new ArrayList<SearchResult>();
         while (iterator.hasNext()) {
-            enumeration.add(iterator.next());
+            list.add(iterator.next());
         }
 
-        return enumeration;
+        return new LdapNamingEnumeration<SearchResult>(list, null);
     }
 
     @Override

Modified: harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapSearchResult.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapSearchResult.java?rev=663009&r1=663008&r2=663009&view=diff
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapSearchResult.java (original)
+++ harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapSearchResult.java Tue Jun  3 23:48:10 2008
@@ -23,9 +23,17 @@
 import java.util.List;
 import java.util.Map;
 
+import javax.naming.Binding;
+import javax.naming.Name;
+import javax.naming.NameClassPair;
+import javax.naming.NamingEnumeration;
 import javax.naming.NamingException;
+import javax.naming.directory.Attribute;
 import javax.naming.directory.Attributes;
 import javax.naming.directory.BasicAttributes;
+import javax.naming.directory.DirContext;
+import javax.naming.directory.SearchResult;
+import javax.naming.ldap.LdapName;
 
 import org.apache.harmony.jndi.provider.ldap.asn1.LdapASN1Constant;
 import org.apache.harmony.jndi.provider.ldap.asn1.Utils;
@@ -34,14 +42,14 @@
 public class LdapSearchResult {
 
     /**
-     * all search result entries
+     * All search result entries
      */
-    private Map<String, Attributes> entries = new HashMap<String, Attributes>();
+    protected HashMap<String, Attributes> entries = new HashMap<String, Attributes>();
 
     /**
      * SearchResultReference from server
      */
-    private List<String> refURLs;
+    protected List<String> refURLs;
 
     private LdapResult result;
 
@@ -51,13 +59,54 @@
 
     private String[] binaryAttributes;
 
+    /**
+     * batch size for this search operation
+     */
+    private int batchSize;
+
+    /**
+     * NamingEnumeration for this LdapSearchResult. One LdapSearchResult
+     * instance can only has one corresponding NamingEnumeration instance.
+     */
+    private LdapNamingEnumeration<Object> enumeration;
+
+    /**
+     * Currently there are three different typs of LdapNamingEnumeration:
+     *
+     * <code>
+     * 1    NameClassPair
+     * 2    Binding
+     * 3    SearchResult
+     * </code>
+     */
+    private int enumerationType;
+
+    private String baseDN;
+
+    private LdapContextImpl context;
+
+    private Name name;
+
+    /**
+     * whether received all search result from server
+     */
+    private boolean isFinished;
+
+    public int getBatchSize() {
+        return batchSize;
+    }
+
+    public void setBatchSize(int batchSize) {
+        this.batchSize = batchSize;
+    }
+
     public String getAddress() {
-		return address;
-	}
+        return address;
+    }
 
-	public void setAddress(String address) {
-		this.address = address;
-	}
+    public void setAddress(String address) {
+        this.address = address;
+    }
 
     public void decodeSearchResponse(Object[] values) {
         ChosenValue chosen = (ChosenValue) values[0];
@@ -77,6 +126,8 @@
     protected void decodeDone(Object value) {
         result = new LdapResult();
         result.decodeValues((Object[]) value);
+        isFinished = true;
+        addToEnumeration();
     }
 
     protected void decodeRef(Object value) {
@@ -92,19 +143,20 @@
 
     protected void decodeEntry(Object value) {
         Object[] values = (Object[]) value;
-        String name = Utils.getString((byte[]) values[0]);
+        String name = Utils.getString(values[0]);
 
         if (address != null) {
-        	name = address + name;
+            name = address + name;
         }
 
         Attributes attrs = null;
-
-        if (entries.containsKey(name)) {
-            attrs = entries.get(name);
-        } else {
-            attrs = new BasicAttributes(true);
-            entries.put(name, attrs);
+        synchronized (entries) {
+            if (entries.containsKey(name)) {
+                attrs = entries.get(name);
+            } else {
+                attrs = new BasicAttributes(true);
+                entries.put(name, attrs);
+            }
         }
 
         Collection<Object[]> list = (Collection<Object[]>) values[1];
@@ -116,6 +168,7 @@
             }
             attrs.put(attr);
         }
+        addToEnumeration();
     }
 
     public Map<String, Attributes> getEntries() {
@@ -134,12 +187,21 @@
         return ex;
     }
 
-    public void setException(NamingException ex) {
-        this.ex = ex;
+    public void setException(Exception ex) {
+        if (ex == null) {
+            this.ex = null;
+            return;
+        }
+        if (!(ex instanceof NamingException)) {
+            this.ex = new NamingException(ex.getMessage());
+            this.ex.initCause(ex);
+        } else {
+            this.ex = (NamingException) ex;
+        }
     }
 
     public boolean isEmpty() {
-        return entries.size() == 0 && refURLs.size() == 0;
+        return entries.size() == 0 && (refURLs == null || refURLs.size() == 0);
     }
 
     public void setRefURLs(List<String> refURLs) {
@@ -154,4 +216,111 @@
         this.binaryAttributes = binaryAttributes;
     }
 
+    public NamingEnumeration<NameClassPair> toNameClassPairEnumeration(
+            String baseDN) {
+        enumerationType = 1;
+        enumeration = new LdapNamingEnumeration<Object>(null, null);
+        this.baseDN = baseDN;
+        addToEnumeration();
+        return (NamingEnumeration) enumeration;
+    }
+
+    public NamingEnumeration<Binding> toBindingEnumeration(
+            LdapContextImpl context, Name name) throws NamingException {
+        enumerationType = 2;
+        enumeration = new LdapNamingEnumeration<Object>(null, null);
+        this.context = context;
+        this.name = name;
+
+        Name tempName = new LdapName(context.getNameInNamespace());
+        tempName.addAll(name);
+        baseDN = tempName.toString();
+
+        addToEnumeration();
+
+        return (NamingEnumeration) enumeration;
+    }
+
+    public NamingEnumeration<SearchResult> toSearchResultEnumeration(
+            String baseDN) {
+        enumerationType = 3;
+        enumeration = new LdapNamingEnumeration<Object>(null, null);
+        this.baseDN = baseDN;
+
+        addToEnumeration();
+
+        return (NamingEnumeration) enumeration;
+    }
+
+    private void addToEnumeration() {
+        if (enumeration == null || entries == null || entries.isEmpty()) {
+            return;
+        }
+
+        List<Object> list = new ArrayList<Object>();
+        HashMap<String, Attributes> tempEntries = null;
+
+        synchronized (entries) {
+            tempEntries = (HashMap<String, Attributes>) entries.clone();
+            entries.clear();
+        }
+
+        try {
+            for (String dn : tempEntries.keySet()) {
+                String relativeName = LdapUtils.convertToRelativeName(dn,
+                        baseDN);
+                Attributes attrs = tempEntries.get(dn);
+                Attribute attrClass = attrs.get("javaClassName"); //$NON-NLS-1$
+                String className = null;
+                switch (enumerationType) {
+                case 1:
+                    if (attrClass != null) {
+                        className = (String) attrClass.get(0);
+                    } else {
+                        className = DirContext.class.getName();
+                    }
+                    NameClassPair pair = new NameClassPair(relativeName,
+                            className, true);
+                    pair.setNameInNamespace(dn);
+                    list.add(pair);
+                    break;
+                case 2:
+                    Object bound = null;
+
+                    if (attrClass != null) {
+                        className = (String) attrClass.get(0);
+                        bound = context.lookup(name);
+                    } else {
+                        className = DirContext.class.getName();
+                        bound = new LdapContextImpl(context, baseDN);
+                    }
+
+                    Binding binding = new Binding(relativeName, className,
+                            bound);
+                    binding.setNameInNamespace(dn);
+                    list.add(binding);
+                    break;
+                case 3:
+                    SearchResult sr = null;
+                    if (dn.startsWith("ldap://")) {
+                        sr = new SearchResult(dn, null, attrs, false);
+                        int index = dn.indexOf("/", 7);
+                        sr.setNameInNamespace(dn.substring(index + 1, dn
+                                .length()));
+                    } else {
+                        sr = new SearchResult(relativeName, null, attrs);
+                        sr.setNameInNamespace(dn);
+                    }
+                    list.add(sr);
+                    break;
+                }
+            }
+        } catch (NamingException e) {
+            ex = e;
+            isFinished = true;
+        }
+
+        enumeration.setException(ex);
+        enumeration.add(list, isFinished);
+    }
 }

Modified: harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/ldapURLContext.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/ldapURLContext.java?rev=663009&r1=663008&r2=663009&view=diff
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/ldapURLContext.java (original)
+++ harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/ldapURLContext.java Tue Jun  3 23:48:10 2008
@@ -548,22 +548,11 @@
 
             LdapSearchResult result = context.doSearch(dn, filter, controls);
             
-            List<SearchResult> list = new ArrayList<SearchResult>();
-            Map<String, Attributes> entries = result.getEntries();
-            for (String name : entries.keySet()) {
-                String relativeName = convertToRelativeName(dn, name);
-                SearchResult sr = new SearchResult(relativeName, null, entries
-                        .get(name));
-                sr.setNameInNamespace(name);
-                list.add(sr);
-            }
-
-            if (list.size() == 0 && result.getException() != null) {
+            if (result.isEmpty() && result.getException() != null) {
                 throw result.getException();
             }
-
-            return new LdapNamingEnumeration<SearchResult>(list, result
-                    .getException());
+            
+            return result.toSearchResultEnumeration(dn);
         } finally {
             if (context != null) {
                 context.close();
@@ -609,22 +598,11 @@
             LdapSearchResult result = context.doSearch(dn, f,
                     searchControls);
             
-            List<SearchResult> list = new ArrayList<SearchResult>();
-            Map<String, Attributes> entries = result.getEntries();
-            for (String name : entries.keySet()) {
-                String relativeName = convertToRelativeName(dn, name);
-                SearchResult sr = new SearchResult(relativeName, null, entries
-                        .get(name));
-                sr.setNameInNamespace(name);
-                list.add(sr);
-            }
-
-            if (list.size() == 0 && result.getException() != null) {
+            if (result.isEmpty() && result.getException() != null) {
                 throw result.getException();
             }
-
-            return new LdapNamingEnumeration<SearchResult>(list, result
-                    .getException());
+            
+            return result.toSearchResultEnumeration(dn);
         } finally {
             if (context != null) {
                 context.close();

Added: harmony/enhanced/classlib/trunk/modules/jndi/src/test/java/org/apache/harmony/jndi/provider/ldap/LdapSearchResultTest.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/jndi/src/test/java/org/apache/harmony/jndi/provider/ldap/LdapSearchResultTest.java?rev=663009&view=auto
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/jndi/src/test/java/org/apache/harmony/jndi/provider/ldap/LdapSearchResultTest.java (added)
+++ harmony/enhanced/classlib/trunk/modules/jndi/src/test/java/org/apache/harmony/jndi/provider/ldap/LdapSearchResultTest.java Tue Jun  3 23:48:10 2008
@@ -0,0 +1,202 @@
+/* 
+ *  Licensed to the Apache Software Foundation (ASF) under one or more 
+ *  contributor license agreements.  See the NOTICE file distributed with 
+ *  this work for additional information regarding copyright ownership. 
+ *  The ASF licenses this file to You under the Apache License, Version 2.0 
+ *  (the "License"); you may not use this file except in compliance with 
+ *  the License.  You may obtain a copy of the License at 
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ * 
+ *  Unless required by applicable law or agreed to in writing, software 
+ *  distributed under the License is distributed on an "AS IS" BASIS, 
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ *  See the License for the specific language governing permissions and 
+ *  limitations under the License. 
+ */
+package org.apache.harmony.jndi.provider.ldap;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.List;
+
+import javax.naming.Binding;
+import javax.naming.NameClassPair;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.BasicAttributes;
+import javax.naming.directory.DirContext;
+import javax.naming.directory.SearchResult;
+import javax.naming.ldap.LdapName;
+
+import junit.framework.TestCase;
+
+public class LdapSearchResultTest extends TestCase {
+    public void test_getter_setter() {
+        LdapSearchResult result = new LdapSearchResult();
+
+        assertNull(result.getAddress());
+        assertNull(result.getBinaryAttributes());
+        assertNotNull(result.getEntries());
+        assertEquals(0, result.getEntries().size());
+        assertNull(result.getException());
+        assertNull(result.getRefURLs());
+        assertNull(result.getResult());
+        assertTrue(result.isEmpty());
+
+        result.setAddress("localhost");
+        assertEquals("localhost", result.getAddress());
+
+        result.setBinaryAttributes(new String[] { "cn", "objectClass" });
+        assertEquals("cn", result.getBinaryAttributes()[0]);
+        assertEquals("objectClass", result.getBinaryAttributes()[1]);
+
+        NamingException exception = new NamingException();
+        result.setException(exception);
+        assertSame(exception, result.getException());
+
+        List<String> refs = new ArrayList<String>();
+        refs.add("ldap://localhost:2008");
+        refs.add("ldap://localhost:1997/cn=test");
+        assertNull(result.getRefURLs());
+        result.setRefURLs(refs);
+
+        assertEquals(2, result.getRefURLs().size());
+        assertTrue(result.getRefURLs().contains("ldap://localhost:2008"));
+        assertTrue(result.getRefURLs()
+                .contains("ldap://localhost:1997/cn=test"));
+    }
+
+    public void test_toNameClassPairEnumeration() throws Exception {
+        HashMap<String, Attributes> entries = new HashMap<String, Attributes>();
+        entries.put("ou=harmony,o=apache,cn=test", new BasicAttributes("ou",
+                "harmony", true));
+        entries.put("module=jndi,cn=test", new BasicAttributes(
+                "javaClassName", String.class.getName()));
+
+        MockLdapSearchResult result = new MockLdapSearchResult();
+
+        result.decodeEntry(entries);
+
+        NamingEnumeration<NameClassPair> enu = result
+                .toNameClassPairEnumeration("cn=test");
+
+        HashMap<String, NameClassPair> values = new HashMap<String, NameClassPair>();
+        while (enu.hasMore()) {
+            NameClassPair pair = enu.next();
+            values.put(pair.getName(), pair);
+        }
+
+        assertEquals(entries.size(), values.size());
+
+        assertTrue(values.containsKey("ou=harmony,o=apache"));
+        NameClassPair pair = values.get("ou=harmony,o=apache");
+        assertEquals("ou=harmony,o=apache", pair.getName());
+        assertEquals(DirContext.class.getName(), pair.getClassName());
+        assertEquals("ou=harmony,o=apache,cn=test", pair.getNameInNamespace());
+
+        assertTrue(values.containsKey("module=jndi"));
+        pair = values.get("module=jndi");
+        assertEquals("module=jndi", pair.getName());
+        assertEquals(String.class.getName(), pair.getClassName());
+        assertEquals("module=jndi,cn=test", pair.getNameInNamespace());
+    }
+
+    public void test_toBindingEnumeration() throws Exception {
+        HashMap<String, Attributes> entries = new HashMap<String, Attributes>();
+        entries.put("ou=harmony,o=apache,cn=test", new BasicAttributes("ou",
+                "harmony", true));
+        entries.put("module=jndi,o=apache,cn=test", new BasicAttributes(
+                "javaClassName", String.class.getName()));
+
+        MockLdapSearchResult result = new MockLdapSearchResult();
+
+        result.decodeEntry(entries);
+
+        NamingEnumeration<Binding> enu = result.toBindingEnumeration(
+                new LdapContextImpl(new MockLdapClient(),
+                        new Hashtable<Object, Object>(), "cn=test"),
+                new LdapName("o=apache"));
+
+        HashMap<String, Binding> values = new HashMap<String, Binding>();
+        while (enu.hasMore()) {
+            Binding binding = enu.next();
+            values.put(binding.getName(), binding);
+        }
+
+        assertEquals(entries.size(), values.size());
+
+        assertTrue(values.containsKey("ou=harmony"));
+        Binding binding = values.get("ou=harmony");
+        assertEquals("ou=harmony", binding.getName());
+        assertEquals(DirContext.class.getName(), binding.getClassName());
+        assertEquals("ou=harmony,o=apache,cn=test", binding
+                .getNameInNamespace());
+        assertEquals(LdapContextImpl.class, binding.getObject().getClass());
+
+        assertTrue(values.containsKey("module=jndi"));
+        binding = values.get("module=jndi");
+        assertEquals("module=jndi", binding.getName());
+        assertEquals(String.class.getName(), binding.getClassName());
+        assertEquals("module=jndi,o=apache,cn=test", binding
+                .getNameInNamespace());
+    }
+
+    public void test_toSearchResultEnumeration() throws Exception {
+        HashMap<String, Attributes> entries = new HashMap<String, Attributes>();
+        entries.put("ou=harmony,o=apache,cn=test", new BasicAttributes("ou",
+                "harmony", true));
+        entries.put("module=jndi,o=apache,cn=test", new BasicAttributes(
+                "javaClassName", String.class.getName()));
+
+        MockLdapSearchResult result = new MockLdapSearchResult();
+
+        result.decodeEntry(entries);
+
+        NamingEnumeration<SearchResult> enu = result
+                .toSearchResultEnumeration("cn=test");
+
+        HashMap<String, SearchResult> values = new HashMap<String, SearchResult>();
+        while (enu.hasMore()) {
+            SearchResult searchResult = enu.next();
+            values.put(searchResult.getName(), searchResult);
+        }
+
+        assertEquals(entries.size(), values.size());
+
+        assertTrue(values.containsKey("ou=harmony,o=apache"));
+        SearchResult searchResult = values.get("ou=harmony,o=apache");
+        assertEquals("ou=harmony,o=apache", searchResult.getName());
+        assertNull(searchResult.getClassName());
+        assertEquals("ou=harmony,o=apache,cn=test", searchResult
+                .getNameInNamespace());
+        assertNull(searchResult.getObject());
+        
+        Attributes attrs = searchResult.getAttributes();
+        assertEquals(1, attrs.size());
+        assertEquals(1, attrs.get("ou").size());
+        assertEquals("harmony", attrs.get("ou").get());
+
+        assertTrue(values.containsKey("module=jndi,o=apache"));
+        searchResult = values.get("module=jndi,o=apache");
+        assertEquals("module=jndi,o=apache", searchResult.getName());
+        assertNull(searchResult.getClassName());
+        assertEquals("module=jndi,o=apache,cn=test", searchResult
+                .getNameInNamespace());
+        assertNull(searchResult.getObject());
+        
+        attrs = searchResult.getAttributes();
+        assertEquals(1, attrs.size());
+        assertEquals(1, attrs.get("javaClassName").size());
+        assertEquals(String.class.getName(), attrs.get("javaClassName").get());
+    }
+    
+    public static class MockLdapSearchResult extends LdapSearchResult {
+        public void decodeEntry(Object value) {
+            entries = (HashMap<String, Attributes>) ((HashMap<String, Attributes>) value)
+                    .clone();
+        }
+    }
+}

Propchange: harmony/enhanced/classlib/trunk/modules/jndi/src/test/java/org/apache/harmony/jndi/provider/ldap/LdapSearchResultTest.java
------------------------------------------------------------------------------
    svn:eol-style = native