harmony-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From py...@apache.org
Subject svn commit: r594074 - in /harmony/enhanced/classlib/trunk/modules/jndi/src: main/java/org/apache/harmony/jndi/provider/ldap/ main/java/org/apache/harmony/jndi/provider/ldap/asn1/ test/java/org/apache/harmony/jndi/provider/ldap/
Date Mon, 12 Nov 2007 10:02:42 GMT
Author: pyang
Date: Mon Nov 12 02:02:40 2007
New Revision: 594074

URL: http://svn.apache.org/viewvc?rev=594074&view=rev
Log:
Apply patch for HARMONY-5107([classlib][jndi][ldap] implements LdapContextImpl.createSubcontext,
destroySubcontext and some other methods)

Added:
    harmony/enhanced/classlib/trunk/modules/jndi/src/test/java/org/apache/harmony/jndi/provider/ldap/MockLdapClient.java
Modified:
    harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/DeleteOp.java
    harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapAttribute.java
    harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapContextFactory.java
    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/LdapMessage.java
    harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/asn1/LdapASN1Constant.java
    harmony/enhanced/classlib/trunk/modules/jndi/src/test/java/org/apache/harmony/jndi/provider/ldap/LdapAttributeTest.java
    harmony/enhanced/classlib/trunk/modules/jndi/src/test/java/org/apache/harmony/jndi/provider/ldap/LdapContextImplTest.java

Modified: harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/DeleteOp.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/DeleteOp.java?rev=594074&r1=594073&r2=594074&view=diff
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/DeleteOp.java
(original)
+++ harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/DeleteOp.java
Mon Nov 12 02:02:40 2007
@@ -67,4 +67,8 @@
         dn = Utils.getString((byte[]) values[0]);
     }
 
+    public String getDn() {
+        return dn;
+    }
+
 }

Modified: harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapAttribute.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapAttribute.java?rev=594074&r1=594073&r2=594074&view=diff
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapAttribute.java
(original)
+++ harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapAttribute.java
Mon Nov 12 02:02:40 2007
@@ -76,8 +76,8 @@
             add(values.next());
         }
 
-        attributeDefinition = attr.getAttributeDefinition();
-        attributeSyntaxDefinition = attr.getAttributeSyntaxDefinition();
+        attributeDefinition = null;
+        attributeSyntaxDefinition = null;
     }
 
     @SuppressWarnings("unchecked")
@@ -111,11 +111,20 @@
 
     @Override
     public DirContext getAttributeDefinition() throws NamingException {
-        return attributeDefinition;
+        if (attributeDefinition != null) {
+            return attributeDefinition;
+        }
+        // TODO: Not yet implemented
+        throw new NotYetImplementedException();
+
     }
 
     @Override
     public DirContext getAttributeSyntaxDefinition() throws NamingException {
-        return attributeSyntaxDefinition;
+        if (attributeSyntaxDefinition != null) {
+            return attributeSyntaxDefinition;
+        }
+        // TODO: Not yet implemented
+        throw new NotYetImplementedException();
     }
 }

Modified: harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapContextFactory.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapContextFactory.java?rev=594074&r1=594073&r2=594074&view=diff
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapContextFactory.java
(original)
+++ harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapContextFactory.java
Mon Nov 12 02:02:40 2007
@@ -25,15 +25,10 @@
 import javax.naming.NamingException;
 import javax.naming.spi.InitialContextFactory;
 
-import org.apache.harmony.jndi.internal.nls.Messages;
 import org.apache.harmony.jndi.provider.ldap.parser.LdapUrlParser;
 
 public class LdapContextFactory implements InitialContextFactory {
 
-    private static final int DEFAULT_PORT = 389;
-
-    private static final String DEFAULT_HOST = "localhost"; //$NON-NLS-1$
-
     public Context getInitialContext(Hashtable<?, ?> envmt)
             throws NamingException {
         Hashtable<Object, Object> myEnv = null;
@@ -53,18 +48,6 @@
         String host = parser.getHost();
         int port = parser.getPort();
         String dn = parser.getBaseObject();
-
-        if (host == null) {
-            host = DEFAULT_HOST;
-        }
-
-        if (port == -1) {
-            port = DEFAULT_PORT;
-        }
-
-        if (dn == null) {
-            dn = "";
-        }
 
         LdapClient client = LdapClient.newInstance(host, port, myEnv);
 

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=594074&r1=594073&r2=594074&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
Mon Nov 12 02:02:40 2007
@@ -17,28 +17,44 @@
 
 package org.apache.harmony.jndi.provider.ldap;
 
+import java.io.IOException;
+import java.util.ArrayList;
 import java.util.Hashtable;
+import java.util.List;
 
 import javax.naming.Binding;
+import javax.naming.CannotProceedException;
+import javax.naming.CommunicationException;
 import javax.naming.CompositeName;
 import javax.naming.Context;
 import javax.naming.InvalidNameException;
 import javax.naming.Name;
 import javax.naming.NameClassPair;
+import javax.naming.NameNotFoundException;
 import javax.naming.NameParser;
 import javax.naming.NamingEnumeration;
 import javax.naming.NamingException;
+import javax.naming.RefAddr;
+import javax.naming.Reference;
+import javax.naming.directory.Attribute;
 import javax.naming.directory.Attributes;
+import javax.naming.directory.BasicAttributes;
 import javax.naming.directory.DirContext;
 import javax.naming.directory.ModificationItem;
 import javax.naming.directory.SearchControls;
 import javax.naming.directory.SearchResult;
 import javax.naming.ldap.Control;
+import javax.naming.ldap.ControlFactory;
 import javax.naming.ldap.ExtendedRequest;
 import javax.naming.ldap.ExtendedResponse;
 import javax.naming.ldap.LdapContext;
 import javax.naming.ldap.LdapName;
+import javax.naming.ldap.ManageReferralControl;
+import javax.naming.ldap.Rdn;
+import javax.naming.spi.DirectoryManager;
+import javax.naming.spi.NamingManager;
 
+import org.apache.harmony.jndi.internal.Util;
 import org.apache.harmony.jndi.internal.nls.Messages;
 import org.apache.harmony.jndi.internal.parser.LdapNameParser;
 
@@ -58,6 +74,10 @@
      */
     private Name contextDn;
 
+    private Control[] requestControls;
+
+    private Control[] responseControls;
+
     /**
      * environment properties for this context
      */
@@ -68,6 +88,11 @@
      */
     private NameParser parser;
 
+    private static final Control NON_CRITICAL_MANAGE_REF_CONTROL = new ManageReferralControl(
+            Control.NONCRITICAL);
+
+    private static final String LDAP_DELETE_RDN = "java.naming.ldap.deleteRDN"; //$NON-NLS-1$
+
     /**
      * construct a new inherit <code>LdapContextImpl</code>
      * 
@@ -95,7 +120,7 @@
             Hashtable<Object, Object> environment, String dn)
             throws NamingException {
         initial(client, environment, dn);
-        //TODO do ldap bind operation
+        // TODO do ldap bind operation
     }
 
     private void initial(LdapClient ldapClient,
@@ -107,7 +132,7 @@
         } else {
             this.env = (Hashtable<Object, Object>) environment.clone();
         }
-        
+
         contextDn = new LdapName(dn);
         parser = new LdapNameParser(dn);
     }
@@ -124,13 +149,21 @@
     }
 
     public Control[] getRequestControls() throws NamingException {
-        // TODO not yet implemented
-        throw new NotYetImplementedException();
+        return copyControls(requestControls);
     }
 
     public Control[] getResponseControls() throws NamingException {
-        // TODO not yet implemented
-        throw new NotYetImplementedException();
+        return copyControls(responseControls);
+    }
+
+    private Control[] copyControls(Control[] controls) {
+        if (controls == null) {
+            return null;
+        }
+
+        Control[] rtValue = new Control[controls.length];
+        System.arraycopy(controls, 0, rtValue, 0, controls.length);
+        return rtValue;
     }
 
     public LdapContext newInstance(Control[] ac) throws NamingException {
@@ -144,8 +177,30 @@
     }
 
     public void setRequestControls(Control[] controls) throws NamingException {
-        // TODO not yet implemented
-        throw new NotYetImplementedException();
+        boolean hasManageDsaITConntrol = false;
+
+        if (env.get(Context.REFERRAL) == null
+                || env.get(Context.REFERRAL).equals("ignore")) {
+            hasManageDsaITConntrol = true;
+        }
+
+        if (controls == null) {
+            if (hasManageDsaITConntrol) {
+                requestControls = new Control[] { NON_CRITICAL_MANAGE_REF_CONTROL };
+            } else {
+                requestControls = null;
+            }
+            return;
+        }
+
+        if (hasManageDsaITConntrol) {
+            requestControls = new Control[controls.length + 1];
+            System.arraycopy(controls, 0, requestControls, 0, controls.length);
+            requestControls[controls.length] = NON_CRITICAL_MANAGE_REF_CONTROL;
+        } else {
+            requestControls = new Control[controls.length];
+            System.arraycopy(controls, 0, requestControls, 0, controls.length);
+        }
     }
 
     public void bind(Name name, Object obj, Attributes attributes)
@@ -161,8 +216,116 @@
 
     public DirContext createSubcontext(Name name, Attributes attributes)
             throws NamingException {
-        // TODO not yet implemented
-        throw new NotYetImplementedException();
+        checkName(name);
+
+        if (name instanceof CompositeName && name.size() > 1) {
+            /*
+             * multi ns, find next ns context, delegate operation to the next
+             * context
+             */
+            DirContext nns = (DirContext) findNnsContext(name);
+            Name remainingName = name.getSuffix(1);
+            return nns.createSubcontext(remainingName, attributes);
+        }
+
+        /*
+         * there is only one ldap ns
+         */
+
+        if (attributes == null) {
+            attributes = new BasicAttributes();
+            Attribute attr = new LdapAttribute("objectClass");
+            attr.add("top");
+            attr.add("javaContainer");
+            attributes.put(attr);
+        }
+
+        // get absolute dn name
+        String targetDN = getTargetDN(name, contextDn);
+        // merge attributes from dn and args
+        Attributes attrs = mergeAttributes(attributes,
+                getAttributesFromDN(name));
+
+        // convert to LdapAttribute
+        List<LdapAttribute> la = new ArrayList<LdapAttribute>(attrs.size());
+        NamingEnumeration<? extends Attribute> enu = attrs.getAll();
+        while (enu.hasMore()) {
+            la.add(new LdapAttribute(enu.next()));
+        }
+
+        // do add operation
+        AddOp op = new AddOp(targetDN, la);
+
+        doBasicOperation(op);
+
+        LdapResult result = op.getResult();
+        return new LdapContextImpl(this, env, result.getMachedDN());
+    }
+
+    /**
+     * merge two instanceof <code>Attributes</code> to one
+     * 
+     * @param first
+     * @param second
+     * @return
+     * @throws NamingException
+     */
+    private Attributes mergeAttributes(Attributes first, Attributes second)
+            throws NamingException {
+        if (first == null) {
+            return second;
+        }
+
+        if (second == null) {
+            return first;
+        }
+
+        BasicAttributes attrs = new BasicAttributes();
+        NamingEnumeration<? extends Attribute> enu = first.getAll();
+        while (enu.hasMore()) {
+            attrs.put(enu.next());
+        }
+
+        enu = second.getAll();
+        while (enu.hasMore()) {
+            Attribute element = enu.next();
+            element = mergeAttribute(element, attrs.get(element.getID()));
+            attrs.put(element);
+        }
+
+        return attrs;
+    }
+
+    /**
+     * merge two instance of <code>Attribute</code> to one
+     * 
+     * @param first
+     * @param second
+     * @return
+     * @throws NamingException
+     */
+    private Attribute mergeAttribute(Attribute first, Attribute second)
+            throws NamingException {
+        if (first == null) {
+            return second;
+        }
+
+        if (second == null) {
+            return first;
+        }
+
+        Attribute attr = new LdapAttribute(first.getID());
+        NamingEnumeration<?> enu = first.getAll();
+        while (enu.hasMore()) {
+            attr.add(enu.next());
+        }
+
+        enu = second.getAll();
+        while (enu.hasMore()) {
+            attr.add(enu.next());
+        }
+
+        return attr;
     }
 
     public DirContext createSubcontext(String s, Attributes attributes)
@@ -210,14 +373,77 @@
 
     public void modifyAttributes(Name name, int i, Attributes attributes)
             throws NamingException {
-        // TODO not yet implemented
-        throw new NotYetImplementedException();
+        checkName(name);
+        if (attributes == null) {
+            // jndi.13=Non-null attribute is required for modification
+            throw new NullPointerException(Messages.getString("jndi.13")); //$NON-NLS-1$
+        }
+
+        if (i != DirContext.ADD_ATTRIBUTE && i != DirContext.REMOVE_ATTRIBUTE
+                && i != DirContext.REPLACE_ATTRIBUTE) {
+            /*
+             * jndi.14=Modification code {0} must be one of
+             * DirContext.ADD_ATTRIBUTE, DirContext.REPLACE_ATTRIBUTE and
+             * DirContext.REMOVE_ATTRIBUTE
+             */
+            throw new IllegalArgumentException(Messages.getString("jndi.14", i)); //$NON-NLS-1$
+        }
+
+        NamingEnumeration<? extends Attribute> enu = attributes.getAll();
+        ModificationItem[] items = new ModificationItem[attributes.size()];
+        int index = 0;
+        while (enu.hasMore()) {
+            items[index++] = new ModificationItem(i, enu.next());
+        }
+
+        modifyAttributes(name, items);
     }
 
     public void modifyAttributes(Name name, ModificationItem[] modificationItems)
             throws NamingException {
-        // TODO not yet implemented
-        throw new NotYetImplementedException();
+        checkName(name);
+
+        if (modificationItems == null) {
+            // FIXME: spec say ModificationItem may not be null, but ri
+            // silence in this case
+            throw new NullPointerException(Messages.getString("ldap.27")); //$NON-NLS-1$
+        }
+
+        if (name instanceof CompositeName && name.size() > 1) {
+            /*
+             * multi ns, find next ns context, delegate operation to the next
+             * context
+             */
+            DirContext nns = (DirContext) findNnsContext(name);
+            Name remainingName = name.getSuffix(1);
+            nns.modifyAttributes(remainingName, modificationItems);
+            return;
+        }
+
+        /*
+         * there is only one ldap ns
+         */
+        // get absolute dn name
+        String targetDN = getTargetDN(name, contextDn);
+        ModifyOp op = new ModifyOp(targetDN);
+        for (ModificationItem item : modificationItems) {
+            switch (item.getModificationOp()) {
+            case DirContext.ADD_ATTRIBUTE:
+                op.addModification(0, new LdapAttribute(item.getAttribute()));
+                break;
+            case DirContext.REMOVE_ATTRIBUTE:
+                op.addModification(1, new LdapAttribute(item.getAttribute()));
+                break;
+            case DirContext.REPLACE_ATTRIBUTE:
+                op.addModification(2, new LdapAttribute(item.getAttribute()));
+                break;
+            default:
+                throw new IllegalArgumentException(Messages.getString(
+                        "jndi.14", item.getModificationOp()));
+            }
+        }
+
+        doBasicOperation(op);
     }
 
     public void modifyAttributes(String s, int i, Attributes attributes)
@@ -348,13 +574,54 @@
         return createSubcontext(name, null);
     }
 
+    private Attributes getAttributesFromDN(Name name)
+            throws InvalidNameException {
+        if (name instanceof LdapName) {
+            Rdn rdn = ((LdapName) name).getRdn(name.size() - 1);
+            return rdn.toAttributes();
+        }
+
+        if (name instanceof CompositeName) {
+            LdapName lname = new LdapName(name.get(0));
+            Rdn rdn = lname.getRdn(lname.size() - 1);
+            return rdn.toAttributes();
+        }
+
+        throw new InvalidNameException(Messages.getString("ldap.26")); //$NON-NLS-1$
+    }
+
     public Context createSubcontext(String s) throws NamingException {
         return createSubcontext(convertFromStringToName(s));
     }
 
     public void destroySubcontext(Name name) throws NamingException {
-        // TODO not yet implemented
-        throw new NotYetImplementedException();
+        checkName(name);
+
+        if (name instanceof CompositeName && name.size() > 1) {
+            if (!(name.getPrefix(0) instanceof LdapName)) {
+                throw new InvalidNameException(Messages.getString("ldap.26")); //$NON-NLS-1$
+            }
+            /*
+             * multi ns, find next ns context, delegate operation to the next
+             * context
+             */
+            Context nns = findNnsContext(name);
+            Name remainingName = name.getSuffix(1);
+            nns.destroySubcontext(remainingName);
+            return;
+        }
+
+        /*
+         * there is only one ldap ns
+         */
+        // absolute dn name to list
+        String targetDN = getTargetDN(name, contextDn);
+        DeleteOp op = new DeleteOp(targetDN);
+        try {
+            doBasicOperation(op);
+        } catch (NameNotFoundException e) {
+            // target dn doesn't exist, do nothing
+        }
     }
 
     public void destroySubcontext(String s) throws NamingException {
@@ -370,6 +637,19 @@
     }
 
     public NameParser getNameParser(Name name) throws NamingException {
+        if (name instanceof CompositeName && name.size() > 1) {
+            if (!(name.getPrefix(0) instanceof LdapName)) {
+                throw new InvalidNameException(Messages.getString("ldap.26")); //$NON-NLS-1$
+            }
+            /*
+             * multi ns, find next ns context, delegate operation to the next
+             * context
+             */
+            Context nns = findNnsContext(name);
+            Name remainingName = name.getSuffix(1);
+            return nns.getNameParser(remainingName);
+        }
+
         return parser;
     }
 
@@ -388,6 +668,76 @@
         return list(convertFromStringToName(s));
     }
 
+    private String getTargetDN(Name name, Name prefix) throws NamingException,
+            InvalidNameException {
+        Name target = null;
+        if (name.size() == 0) {
+            target = prefix;
+        } else if (name instanceof LdapName) {
+            target = composeName(name, prefix);
+        } else if (name instanceof CompositeName) {
+            LdapName alt = new LdapName(name.get(0));
+            target = composeName(alt, prefix);
+        } else {
+            throw new InvalidNameException(Messages.getString("ldap.26")); //$NON-NLS-1$
+        }
+        return target.toString();
+    }
+
+    private Context findNnsContext(Name name) throws NamingException {
+        CannotProceedException cpe = null;
+        if (env.containsKey(NamingManager.CPE)) {
+            cpe = (CannotProceedException) env.get(NamingManager.CPE);
+        } else {
+            cpe = new CannotProceedException();
+        }
+
+        Name remainingName = name.getSuffix(1);
+        Name altName = name.getPrefix(0);
+        Name targetName = composeName(altName, contextDn);
+
+        Name resolvedName = cpe.getResolvedName();
+        if (resolvedName == null) {
+            resolvedName = new CompositeName();
+
+        } else if (resolvedName.size() >= 2
+                && resolvedName.get(resolvedName.size() - 1).equals("")) {
+            // remove the last component if it is ""
+            // (the sign of the next naming system), so there must be at least
+            // one name before "".
+            resolvedName.remove(resolvedName.size() - 1);
+        }
+
+        resolvedName.add(targetName.toString());
+        // add empty component name to indicate nns pointer
+        resolvedName.add("");
+
+        cpe.setAltName(altName);
+        cpe.setAltNameCtx(this);
+        cpe.setEnvironment((Hashtable<Object, Object>) env.clone());
+        cpe.setRemainingName(remainingName);
+        cpe.setResolvedName(resolvedName);
+
+        final LdapContextImpl context = new LdapContextImpl(this, env,
+                composeName(altName, contextDn).toString());
+
+        RefAddr addr = new RefAddr("nns") { //$NON-NLS-1$
+
+            private static final long serialVersionUID = -5428706819217461955L;
+
+            @Override
+            public Object getContent() {
+                return context;
+            }
+
+        };
+
+        Reference ref = new Reference(context.getClass().getName(), addr);
+        cpe.setResolvedObj(ref);
+
+        return DirectoryManager.getContinuationDirContext(cpe);
+    }
+
     public NamingEnumeration<Binding> listBindings(Name name)
             throws NamingException {
         // TODO not yet implemented
@@ -456,8 +806,49 @@
     }
 
     public void rename(Name nOld, Name nNew) throws NamingException {
-        // TODO not yet implemented
-        throw new NotYetImplementedException();
+        checkName(nOld);
+        checkName(nNew);
+
+        if (!isInSameNamespace(nOld, nNew)) {
+            throw new InvalidNameException(Messages.getString("ldap.2A")); //$NON-NLS-1$
+        }
+
+        if (nOld instanceof CompositeName && nOld.size() > 1
+                && nNew instanceof CompositeName && nNew.size() > 1) {
+            Context context = findNnsContext(nOld);
+            context.rename(nOld.getSuffix(1), nNew.getSuffix(1));
+            return;
+        }
+
+        // get absolute dn name
+        String oldTargetDN = getTargetDN(nOld, contextDn);
+        String newTargetDN = getTargetDN(nNew, contextDn);
+        LdapName name = new LdapName(newTargetDN);
+        Rdn rdn = name.getRdn(name.size() - 1);
+        String value = (String) env.get(LDAP_DELETE_RDN);
+        // true is default value
+        boolean isDeleteRdn = true;
+        if (value != null) {
+            isDeleteRdn = Boolean.getBoolean(value);
+        }
+
+        ModifyDNOp op = new ModifyDNOp(oldTargetDN, rdn.toString(),
+                isDeleteRdn, name.getPrefix(name.size() - 1).toString());
+
+        doBasicOperation(op);
+    }
+
+    private boolean isInSameNamespace(Name first, Name second) {
+        if (first instanceof CompositeName && second instanceof CompositeName) {
+            // TODO need more test in detail
+            return first.size() == second.size();
+        }
+
+        if (first instanceof LdapName && second instanceof LdapName) {
+            return true;
+        }
+
+        return false;
     }
 
     public void rename(String sOld, String sNew) throws NamingException {
@@ -471,5 +862,71 @@
 
     public void unbind(String s) throws NamingException {
         unbind(convertFromStringToName(s));
+    }
+
+    /**
+     * Do operations with one request and one response which contains
+     * LdapResult. This is the convenience way to do the most of ldap operation
+     * except search opeartion which has multi-response, bind operation, abandon
+     * and unbind operations which have no response.
+     * 
+     * @param op
+     * @throws NamingException
+     */
+    private void doBasicOperation(LdapOperation op) throws NamingException {
+        LdapMessage message = null;
+        try {
+            message = client.doOperation(op, requestControls);
+        } catch (IOException e) {
+            CommunicationException ex = new CommunicationException();
+            ex.setRootCause(e);
+            // operation failed, clear responseControls
+            responseControls = null;
+            throw ex;
+        }
+
+        Control[] rawControls = message.getControls();
+        responseControls = narrowingControls(rawControls);
+
+        LdapResult result = op.getResult();
+
+        // TODO deal with referrals
+
+        if (Util.getExceptionFromErrorCode(result.getResultCode()) != null) {
+            throw Util.getExceptionFromErrorCode(result.getResultCode());
+        }
+    }
+
+    /**
+     * convert raw controls to particular type of controls using
+     * <code>getControlInstance(Control, Context,
+     Hashtable<?, ?>)</code>
+     * 
+     * @param rawControls
+     *            raw controls
+     * @return particular type of controls
+     * 
+     * @throws NamingException
+     */
+    private Control[] narrowingControls(Control[] rawControls)
+            throws NamingException {
+        if (rawControls == null) {
+            return null;
+        }
+
+        Control[] controls = new Control[rawControls.length];
+        for (int i = 0; i < rawControls.length; ++i) {
+            controls[i] = ControlFactory.getControlInstance(rawControls[i],
+                    this, env);
+        }
+
+        return controls;
+    }
+
+    private void checkName(Name name) {
+        if (name == null) {
+            // jndi.2E=The name is null
+            throw new NullPointerException(Messages.getString("jndi.2E")); //$NON-NLS-1$
+        }
     }
 }

Modified: harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapMessage.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapMessage.java?rev=594074&r1=594073&r2=594074&view=diff
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapMessage.java
(original)
+++ harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapMessage.java
Mon Nov 12 02:02:40 2007
@@ -19,6 +19,8 @@
 
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
 
 import javax.naming.ldap.Control;
 
@@ -46,6 +48,11 @@
     private ASN1Decodable responseOp;
     
     /**
+     * controls for this message
+     */
+    private Control[] controls;
+    
+    /**
      * index of the operation, determine which operation is encapsulated in this
      * message.
      */
@@ -74,6 +81,7 @@
     public int getMessageId() {
         return messageId;
     }
+
     /**
      * Construct a request message. <code>op</code> may not be
      * <code>null</code>. <code>controls</code> is <code>null</code>
or a
@@ -89,6 +97,7 @@
     public LdapMessage(int opIndex, ASN1Encodable op, Control[] controls) {
         this.opIndex = opIndex;
         requestOp = op;
+        this.controls = controls;
         messageId = getNextMessageId();
     }
     
@@ -130,6 +139,16 @@
         decodeValues(values);
     }
     
+    /**
+     * Return controls of the message, if there is no control, <code>null</code>
+     * will be returned.
+     * 
+     * @return controls of the message
+     */
+    public Control[] getControls() {
+        return controls;
+    }
+    
     @SuppressWarnings("unchecked")
     public void decodeValues(Object[] values) {
         messageId = ASN1Integer.toIntValue(values[0]);
@@ -154,14 +173,24 @@
 
     public void encodeValues(Object[] values) {
         values[0] = ASN1Integer.fromIntValue(messageId);
-        // Abandon & DelRequest are ASN.1 primitive
+        // ABANDON, UNBIND and DELETE request are ASN.1 primitive
         if (opIndex == LdapASN1Constant.OP_ABANDON_REQUEST
-                || opIndex == LdapASN1Constant.OP_DEL_REQUEST) {
+                || opIndex == LdapASN1Constant.OP_DEL_REQUEST
+                || opIndex == LdapASN1Constant.OP_UNBIND_REQUEST) {
             Object[] objs = new Object[1];
             requestOp.encodeValues(objs);
             values[1] = new ChosenValue(opIndex, objs[0]);
         } else {
             values[1] = new ChosenValue(opIndex, requestOp);
+        }
+
+        // encode controls, wrap to LdapControl, so it could be encoded
+        if (controls != null) {
+            List<LdapControl> list = new ArrayList<LdapControl>(controls.length);
+            for (int i = 0; i < controls.length; ++i) {
+                list.add(new LdapControl(controls[i]));
+            }
+            values[2] = list;
         }
     }
 

Modified: harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/asn1/LdapASN1Constant.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/asn1/LdapASN1Constant.java?rev=594074&r1=594073&r2=594074&view=diff
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/asn1/LdapASN1Constant.java
(original)
+++ harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/asn1/LdapASN1Constant.java
Mon Nov 12 02:02:40 2007
@@ -36,41 +36,42 @@
     public static final int OP_BIND_REQUEST = 0;
 
     public static final int OP_BIND_RESPONSE = 1;
-    
-    public static final int OP_SEARCH_REQUEST = 2;
 
-    public static final int OP_SEARCH_RESULT_ENTRY = 3;
+    public static final int OP_UNBIND_REQUEST = 2;
 
-    public static final int OP_SEARCH_RESULT_DONE = 4;
+    public static final int OP_SEARCH_REQUEST = 3;
 
-    public static final int OP_SEARCH_RESULT_REF = 5;
-    
-    // FIXME change them to appropriate index number in the future.
-    public static final int OP_MODIFY_REQUEST = 6;
-    
-    public static final int OP_MODIFY_RESPONSE = 7;
+    public static final int OP_SEARCH_RESULT_ENTRY = 4;
 
-    public static final int OP_ADD_REQUEST = 8;
-    
-    public static final int OP_ADD_RESPONSE = 9;
-    
-    public static final int OP_DEL_REQUEST = 10;
+    public static final int OP_SEARCH_RESULT_DONE = 5;
 
-    public static final int OP_DEL_RESPONSE = 11;
+    public static final int OP_SEARCH_RESULT_REF = 6;
 
-    public static final int OP_MODIFY_DN_REQUEST = 12;
-    
-    public static final int OP_MODIFY_DN_RESPONSE = 13;
+    public static final int OP_MODIFY_REQUEST = 7;
 
-    public static final int OP_COMPARE_REQUEST = 14;
-    
-    public static final int OP_COMPARE_RESPONSE = 15;
+    public static final int OP_MODIFY_RESPONSE = 8;
 
-    public static final int OP_ABANDON_REQUEST = 16;
+    public static final int OP_ADD_REQUEST = 9;
 
-    public static final int OP_EXTENDED_REQUEST = 17;
-    
-    public static final int OP_EXTENDED_RESPONSE = 18;
+    public static final int OP_ADD_RESPONSE = 10;
+
+    public static final int OP_DEL_REQUEST = 11;
+
+    public static final int OP_DEL_RESPONSE = 12;
+
+    public static final int OP_MODIFY_DN_REQUEST = 13;
+
+    public static final int OP_MODIFY_DN_RESPONSE = 14;
+
+    public static final int OP_COMPARE_REQUEST = 15;
+
+    public static final int OP_COMPARE_RESPONSE = 16;
+
+    public static final int OP_ABANDON_REQUEST = 17;
+
+    public static final int OP_EXTENDED_REQUEST = 18;
+
+    public static final int OP_EXTENDED_RESPONSE = 19;
     
     public static final ASN1Type Attribute = new ASN1SequenceWrap(
             new ASN1Type[] { ASN1OctetString.getInstance(), // type
@@ -329,6 +330,7 @@
                     new ASN1ChoiceWrap(new ASN1Type[] { 
                             BindRequest,
                             BindResponse,
+                            UnbindRequest,
                             SearchRequest,
                             SearchResultEntry, 
                             SearchResultDone,
@@ -347,7 +349,8 @@
                             ExtendedRequest, 
                             ExtendedResponse
                             }),
-                    new ASN1SequenceOf(Control) }) {
+                    new ASN1Implicit(ASN1Constants.CLASS_CONTEXTSPECIFIC, 0,
+                            new ASN1SequenceOf(Control)) }) {
         {
             setOptional(2);
         }

Modified: harmony/enhanced/classlib/trunk/modules/jndi/src/test/java/org/apache/harmony/jndi/provider/ldap/LdapAttributeTest.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/jndi/src/test/java/org/apache/harmony/jndi/provider/ldap/LdapAttributeTest.java?rev=594074&r1=594073&r2=594074&view=diff
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/jndi/src/test/java/org/apache/harmony/jndi/provider/ldap/LdapAttributeTest.java
(original)
+++ harmony/enhanced/classlib/trunk/modules/jndi/src/test/java/org/apache/harmony/jndi/provider/ldap/LdapAttributeTest.java
Mon Nov 12 02:02:40 2007
@@ -18,6 +18,7 @@
 package org.apache.harmony.jndi.provider.ldap;
 
 import javax.naming.NamingException;
+import javax.naming.directory.BasicAttribute;
 
 import junit.framework.TestCase;
 
@@ -44,5 +45,15 @@
         
         assertEquals(attr.getID(), decoded.getID());
 
+    }
+    
+    public void test_constructor_LAttribute() throws Exception {
+        BasicAttribute attr = new BasicAttribute("cn");
+        attr.add("test");
+        attr.add("harmony");
+        LdapAttribute la = new LdapAttribute(attr);
+        
+        ASN1TestUtils.checkEncode(la, LdapASN1Constant.Attribute);
+        
     }
 }

Modified: harmony/enhanced/classlib/trunk/modules/jndi/src/test/java/org/apache/harmony/jndi/provider/ldap/LdapContextImplTest.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/jndi/src/test/java/org/apache/harmony/jndi/provider/ldap/LdapContextImplTest.java?rev=594074&r1=594073&r2=594074&view=diff
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/jndi/src/test/java/org/apache/harmony/jndi/provider/ldap/LdapContextImplTest.java
(original)
+++ harmony/enhanced/classlib/trunk/modules/jndi/src/test/java/org/apache/harmony/jndi/provider/ldap/LdapContextImplTest.java
Mon Nov 12 02:02:40 2007
@@ -17,8 +17,21 @@
 
 package org.apache.harmony.jndi.provider.ldap;
 
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+
 import javax.naming.CompositeName;
+import javax.naming.Context;
 import javax.naming.Name;
+import javax.naming.directory.Attribute;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.BasicAttribute;
+import javax.naming.directory.BasicAttributes;
+import javax.naming.directory.DirContext;
+import javax.naming.ldap.BasicControl;
+import javax.naming.ldap.Control;
 import javax.naming.ldap.LdapName;
 
 import junit.framework.TestCase;
@@ -27,7 +40,7 @@
     private LdapContextImpl context;
 
     public void test_composeName_LNameLName() throws Exception {
-        context = new LdapContextImpl(new LdapClient(), null, "");
+        context = new LdapContextImpl(new MockLdapClient(), null, "");
         Name name = new LdapName("cn=happy,dc=test");
         Name prefix = new LdapName("o=harmony");
         Name result = context.composeName(name, prefix);
@@ -63,4 +76,225 @@
         assertTrue(result instanceof CompositeName);
         assertEquals("bin/cn=ok/usr", result.toString());
     }
+
+    public void test_createSubcontext_LName() throws Exception {
+        MockLdapClient client = new MockLdapClient();
+        context = new LdapContextImpl(client, new Hashtable<Object, Object>(),
+                "cn=test");
+
+        Name name = new LdapName("cn=add+dc=hello,o=harmony");
+        context.createSubcontext(name);
+
+        AddOp op = (AddOp) client.getRequest();
+        assertEquals("cn=add+dc=hello,o=harmony,cn=test", op.getEntry());
+        List<LdapAttribute> list = op.getAttributeList();
+
+        assertEquals(3, list.size());
+        Map<String, LdapAttribute> map = new HashMap<String, LdapAttribute>();
+        for (LdapAttribute attribute : list) {
+            map.put(attribute.getID(), attribute);
+        }
+
+        assertTrue(map.containsKey("objectClass"));
+        Attribute attr = map.get("objectClass");
+        assertEquals(2, attr.size());
+        assertTrue(attr.get(0) instanceof String);
+        assertTrue(attr.get(1) instanceof String);
+        assertTrue(attr.get(0).equals("top")
+                || attr.get(0).equals("javaContainer"));
+        assertTrue(attr.get(1).equals("top")
+                || attr.get(1).equals("javaContainer"));
+
+        assertTrue(map.containsKey("cn"));
+        attr = map.get("cn");
+        assertEquals(1, attr.size());
+        assertEquals("add", attr.get(0));
+
+        assertTrue(map.containsKey("dc"));
+        attr = map.get("dc");
+        assertEquals(1, attr.size());
+        assertEquals("hello", attr.get(0));
+    }
+
+    public void test_createSubcontext_LNameLAttributes() throws Exception {
+        MockLdapClient client = new MockLdapClient();
+        context = new LdapContextImpl(client, new Hashtable<Object, Object>(),
+                "cn=test");
+
+        Name name = new LdapName("cn=add+dc=hello,o=harmony");
+        Attributes attrs = new BasicAttributes();
+        Attribute attr = new BasicAttribute("ou");
+        attr.add("harmony");
+        attr.add("apache");
+        attrs.put(attr);
+
+        context.createSubcontext(name, attrs);
+
+        AddOp op = (AddOp) client.getRequest();
+        assertEquals("cn=add+dc=hello,o=harmony,cn=test", op.getEntry());
+        List<LdapAttribute> list = op.getAttributeList();
+
+        assertEquals(3, list.size());
+        Map<String, LdapAttribute> map = new HashMap<String, LdapAttribute>();
+        for (LdapAttribute attribute : list) {
+            map.put(attribute.getID(), attribute);
+        }
+
+        assertTrue(map.containsKey("ou"));
+        attr = map.get("ou");
+        assertEquals(2, attr.size());
+        assertTrue(attr.get(0) instanceof String);
+        assertTrue(attr.get(1) instanceof String);
+        assertTrue(attr.get(0).equals("harmony")
+                || attr.get(0).equals("apache"));
+        assertTrue(attr.get(1).equals("harmony")
+                || attr.get(1).equals("apache"));
+
+        assertTrue(map.containsKey("cn"));
+        attr = map.get("cn");
+        assertEquals(1, attr.size());
+        assertEquals("add", attr.get(0));
+
+        assertTrue(map.containsKey("dc"));
+        attr = map.get("dc");
+        assertEquals(1, attr.size());
+        assertEquals("hello", attr.get(0));
+    }
+
+    public void test_modifyAttributes() throws Exception {
+        MockLdapClient client = new MockLdapClient();
+        context = new LdapContextImpl(client, new Hashtable<Object, Object>(),
+                "cn=test");
+
+        Attributes attributes = new BasicAttributes();
+        Attribute attr = new BasicAttribute("cn");
+        attr.add("hello");
+        attr.add("world");
+        attributes.put(attr);
+
+        context.modifyAttributes("o=apache", DirContext.ADD_ATTRIBUTE,
+                attributes);
+        try {
+            context.modifyAttributes("", null);
+            fail("Should throw NullPointerException");
+        } catch (NullPointerException e) {
+            // expected
+        }
+
+        try {
+            context.modifyAttributes("", -1, attributes);
+            fail("Should throw IllegalArgumentException");
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+    }
+
+    // TODO: add test for names not in same namespace
+    public void test_rename() throws Exception {
+        MockLdapClient client = new MockLdapClient();
+        context = new LdapContextImpl(client, new Hashtable<Object, Object>(),
+                "cn=test");
+
+        context.rename("cn=what", "cn=how");
+
+        ModifyDNOp op = (ModifyDNOp) client.getRequest();
+        assertEquals("cn=what,cn=test", op.getEntry());
+        assertEquals("cn=how", op.getNewrdn());
+        assertEquals("cn=test", op.getNewSuperior());
+        assertEquals(true, op.isDeleteoldrdn());
+
+        Hashtable<Object, Object> env = new Hashtable<Object, Object>();
+        env.put("java.naming.ldap.deleteRDN", "false");
+        context = new LdapContextImpl(client, env, "cn=test");
+
+        context.rename("cn=what,o=harmony", "o=apache");
+
+        op = (ModifyDNOp) client.getRequest();
+        assertEquals("cn=what,o=harmony,cn=test", op.getEntry());
+        assertEquals("o=apache", op.getNewrdn());
+        assertEquals("cn=test", op.getNewSuperior());
+        assertEquals(false, op.isDeleteoldrdn());
+
+        try {
+            context.rename(null, "cn=hello");
+            fail("should throw NullPointerException");
+        } catch (NullPointerException e) {
+            // expected
+        }
+
+        try {
+            context.rename("cn=hello", null);
+            fail("should throw NullPointerException");
+        } catch (NullPointerException e) {
+            // expected
+        }
+    }
+
+    public void test_destroySubcontext() throws Exception {
+        MockLdapClient client = new MockLdapClient();
+        context = new LdapContextImpl(client, new Hashtable<Object, Object>(),
+                "cn=test");
+        context.destroySubcontext("cn=bad");
+
+        DeleteOp op = (DeleteOp) client.getRequest();
+        assertEquals("cn=bad,cn=test", op.getDn());
+
+        try {
+            String name = null;
+            context.destroySubcontext(name);
+            fail("Should throw NullPointerException");
+        } catch (NullPointerException e) {
+            // expected
+        }
+    }
+
+    public void test_setRequestControls() throws Exception {
+        MockLdapClient client = new MockLdapClient();
+        Hashtable<Object, Object> env = new Hashtable<Object, Object>();
+        env.put(Context.REFERRAL, "follow");
+        context = new LdapContextImpl(client, env, "cn=test");
+
+        context.setRequestControls(null);
+        assertNull(context.getRequestControls());
+
+        Control[] controls = new Control[] { new BasicControl("0"),
+                new BasicControl("1"), new BasicControl("2"),
+                new BasicControl("3") };
+
+        context.setRequestControls(controls);
+
+        Control[] actual = context.getRequestControls();
+
+        assertEquals(controls.length, actual.length);
+        assertNotSame(controls, actual);
+
+        // Context.REFERRAL is 'ignore' add ManageDsaIT Control
+        env.put(Context.REFERRAL, "ignore");
+        context = new LdapContextImpl(client, env, "cn=test");
+        context.setRequestControls(null);
+        actual = context.getRequestControls();
+        assertEquals(1, actual.length);
+        assertEquals("2.16.840.1.113730.3.4.2", actual[0].getID());
+        assertNull(actual[0].getEncodedValue());
+        assertFalse(actual[0].isCritical());
+
+        context.setRequestControls(controls);
+        actual = context.getRequestControls();
+        assertEquals(controls.length + 1, actual.length);
+
+        // Context.REFERRAL is 'ignore', add ManageDsaIT Control
+        context = new LdapContextImpl(client, new Hashtable<Object, Object>(),
+                "cn=test");
+        context.setRequestControls(null);
+        actual = context.getRequestControls();
+        assertEquals(1, actual.length);
+        assertEquals("2.16.840.1.113730.3.4.2", actual[0].getID());
+        assertNull(actual[0].getEncodedValue());
+        assertFalse(actual[0].isCritical());
+
+        context.setRequestControls(controls);
+        actual = context.getRequestControls();
+        assertEquals(controls.length + 1, actual.length);
+    }
+
 }

Added: harmony/enhanced/classlib/trunk/modules/jndi/src/test/java/org/apache/harmony/jndi/provider/ldap/MockLdapClient.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/jndi/src/test/java/org/apache/harmony/jndi/provider/ldap/MockLdapClient.java?rev=594074&view=auto
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/jndi/src/test/java/org/apache/harmony/jndi/provider/ldap/MockLdapClient.java
(added)
+++ harmony/enhanced/classlib/trunk/modules/jndi/src/test/java/org/apache/harmony/jndi/provider/ldap/MockLdapClient.java
Mon Nov 12 02:02:40 2007
@@ -0,0 +1,71 @@
+/* 
+ *  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.io.IOException;
+
+import javax.naming.ldap.Control;
+
+import org.apache.harmony.jndi.provider.ldap.asn1.ASN1Decodable;
+import org.apache.harmony.jndi.provider.ldap.asn1.ASN1Encodable;
+import org.apache.harmony.jndi.provider.ldap.asn1.Utils;
+import org.apache.harmony.security.asn1.ASN1Integer;
+
+public class MockLdapClient extends LdapClient {
+
+    private ASN1Encodable request;
+
+    private ASN1Decodable response;
+
+    public MockLdapClient() {
+        super();
+    }
+
+    @Override
+    public LdapMessage doOperation(int opIndex, ASN1Encodable requestOp,
+            ASN1Decodable responseOp, Control[] controls) throws IOException {
+        request = requestOp;
+        response = responseOp;
+        if (response instanceof LdapResult) {
+            LdapResult result = (LdapResult) response;
+            Object[] values = new Object[] { ASN1Integer.fromIntValue(0),
+                    Utils.getBytes(""), Utils.getBytes(""), null };
+            result.decodeValues(values);
+        }
+        return new LdapMessage(response);
+    }
+
+    @Override
+    public void doOperationWithoutResponse(int opIndex, ASN1Encodable op,
+            Control[] controls) throws IOException {
+        request = op;
+    }
+
+    public ASN1Encodable getRequest() {
+        return request;
+    }
+
+    public ASN1Decodable getResponse() {
+        return response;
+    }
+
+    public void setResponse(ASN1Decodable response) {
+        this.response = response;
+    }
+
+}



Mime
View raw message