harmony-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From telli...@apache.org
Subject svn commit: r596693 [3/9] - in /harmony/enhanced/classlib/branches/java6: ./ depends/jars/ depends/libs/build/ make/ modules/auth/src/main/java/common/org/apache/harmony/auth/jgss/kerberos/ modules/auth/src/main/java/common/org/apache/harmony/auth/jgss...
Date Tue, 20 Nov 2007 14:43:29 GMT
Modified: harmony/enhanced/classlib/branches/java6/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapContextImpl.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/branches/java6/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapContextImpl.java?rev=596693&r1=596692&r2=596693&view=diff
==============================================================================
--- harmony/enhanced/classlib/branches/java6/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapContextImpl.java (original)
+++ harmony/enhanced/classlib/branches/java6/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapContextImpl.java Tue Nov 20 06:42:33 2007
@@ -17,30 +17,55 @@
 
 package org.apache.harmony.jndi.provider.ldap;
 
+import java.io.IOException;
+import java.util.ArrayList;
 import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.StringTokenizer;
 
 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.InvalidSearchFilterException;
 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.nls.Messages;
+import org.apache.harmony.jndi.internal.parser.AttributeTypeAndValuePair;
 import org.apache.harmony.jndi.internal.parser.LdapNameParser;
+import org.apache.harmony.jndi.provider.ldap.asn1.Utils;
+import org.apache.harmony.jndi.provider.ldap.parser.FilterParser;
+import org.apache.harmony.jndi.provider.ldap.parser.ParseException;
+import org.apache.harmony.jndi.provider.ldap.sasl.SaslBind;
 
 /**
  * This context implements LdapContext, it's main entry point of all JNDI ldap
@@ -56,12 +81,16 @@
     /**
      * name of the context
      */
-    private Name contextDn;
+    protected Name contextDn;
+
+    private Control[] requestControls;
+
+    private Control[] responseControls;
 
     /**
      * environment properties for this context
      */
-    private Hashtable<Object, Object> env;
+    protected Hashtable<Object, Object> env;
 
     /**
      * name parser for this context
@@ -69,10 +98,24 @@
     private NameParser parser;
 
     /**
+     * connection controls for this context
+     */
+    private Control[] connCtls;
+
+    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$
+
+    private static final String LDAP_DEREF_ALIASES = "java.naming.ldap.derefAliases"; //$NON-NLS-1$
+
+    private static final String LDAP_TYPES_ONLY = "java.naming.ldap.typesOnly"; //$NON-NLS-1$
+
+    /**
      * construct a new inherit <code>LdapContextImpl</code>
      * 
      * @param context
-     * @param env
+     * @param environment
      * @param dn
      * @throws InvalidNameException
      */
@@ -95,7 +138,14 @@
             Hashtable<Object, Object> environment, String dn)
             throws NamingException {
         initial(client, environment, dn);
-        //TODO do ldap bind operation
+
+        try {
+            doBindOperation(connCtls);
+        } catch (IOException e) {
+            CommunicationException ex = new CommunicationException();
+            ex.setRootCause(e);
+            throw ex;
+        }
     }
 
     private void initial(LdapClient ldapClient,
@@ -107,11 +157,47 @@
         } else {
             this.env = (Hashtable<Object, Object>) environment.clone();
         }
-        
+
         contextDn = new LdapName(dn);
         parser = new LdapNameParser(dn);
     }
 
+    /**
+     * Perform a LDAP Bind operation.
+     * 
+     * @param env
+     * @throws IOException
+     * @throws IOException
+     * @throws NamingException
+     * @throws ParseException
+     */
+    private void doBindOperation(Control[] connCtsl) throws IOException,
+            NamingException {
+
+        SaslBind saslBind = new SaslBind();
+        LdapResult result = null;
+
+        SaslBind.AuthMech authMech = saslBind.valueAuthMech(env);
+        if (authMech == SaslBind.AuthMech.None) {
+            BindOp bind = new BindOp("", "", null, null);
+            client.doOperation(bind, connCtsl);
+            result = bind.getResult();
+        } else if (authMech == SaslBind.AuthMech.Simple) {
+            String principal = (String) env.get(Context.SECURITY_PRINCIPAL);
+            String credential = Utils.getString(env
+                    .get(Context.SECURITY_CREDENTIALS));
+            BindOp bind = new BindOp(principal, credential, null, null);
+            client.doOperation(bind, connCtsl);
+            result = bind.getResult();
+        } else if (authMech == SaslBind.AuthMech.SASL) {
+            result = saslBind.doSaslBindOperation(env, client, connCtsl);
+        }
+
+        if (LdapUtils.getExceptionFromResult(result) != null) {
+            throw LdapUtils.getExceptionFromResult(result);
+        }
+    }
+
     public ExtendedResponse extendedOperation(ExtendedRequest request)
             throws NamingException {
         // TODO not yet implemented
@@ -124,13 +210,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 +238,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 +277,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", this);
+            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(), this));
+        }
+
+        // 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(), this);
+        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)
@@ -176,8 +400,55 @@
 
     public Attributes getAttributes(Name name, String[] as)
             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
+             */
+            DirContext nns = (DirContext) findNnsContext(name);
+            Name remainingName = name.getSuffix(1);
+            return nns.getAttributes(remainingName, as);
+        }
+
+        /*
+         * there is only one ldap ns
+         */
+        // absolute dn name to list
+        String targetDN = getTargetDN(name, contextDn);
+
+        // construct one-level search using filter "(objectclass=*)"
+        SearchControls controls = new SearchControls();
+        controls.setSearchScope(SearchControls.OBJECT_SCOPE);
+
+        /*
+         * none should be retrieved, send OID "1.1" to server, according to RFC
+         * 2251, 4.5.1
+         */
+        if (as != null && as.length == 0) {
+            // "1.1" means no attributes should return
+            as = new String[] { "1.1" }; //$NON-NLS-1$
+        }
+        controls.setReturningAttributes(as);
+
+        Filter filter = new Filter(Filter.PRESENT_FILTER);
+        filter.setValue("objectClass");
+
+        LdapSearchResult result = doSearch(targetDN, filter, controls);
+        Iterator<Attributes> it = result.getEntries().values().iterator();
+        if (it.hasNext()) {
+            // FIXME: there must be only one Attributes?
+            return it.next();
+        } else if (result.getException() != null) {
+            throw result.getException();
+        }
+
+        // no attribute retrieved from server, return a empty Attributes
+        return new BasicAttributes();
     }
 
     public Attributes getAttributes(String s) throws NamingException {
@@ -189,13 +460,234 @@
         return getAttributes(convertFromStringToName(s), as);
     }
 
+
+    public static Hashtable<String, Hashtable<String, Hashtable<String, Object>>> schemaTree = new Hashtable<String, Hashtable<String, Hashtable<String, Object>>>();
+
+    private LdapSchemaContextImpl ldapSchemaCtx = null;
+
+    protected String subschemasubentry = null;
+
     public DirContext getSchema(Name name) throws NamingException {
-        // TODO not yet implemented
-        throw new NotYetImplementedException();
+        checkName(name);
+        if (null != ldapSchemaCtx)
+            return ldapSchemaCtx;
+
+        SearchControls searchControls = new SearchControls();
+        SearchOp search = null;
+        Filter filter = null;
+        FilterParser filterParser = null;
+        LdapSearchResult sre = null;
+        Map<String, Attributes> names = null;
+        Set<String> keyset = null;
+
+        if (name.size() != 0) {
+            subschemasubentry = name.toString() + "," + contextDn.toString();
+        }
+        if (null == subschemasubentry) {
+            filterParser = new FilterParser("(objectClass=*)");
+            try {
+                filter = filterParser.parse();
+            } catch (ParseException e) {
+                InvalidSearchFilterException ex = new InvalidSearchFilterException(
+                        Messages.getString("ldap.29")); //$NON-NLS-1$
+                ex.setRootCause(e);
+                throw ex;
+            }
+
+            searchControls.setSearchScope(SearchControls.OBJECT_SCOPE);
+            searchControls.setReturningAttributes(new String[] {
+                    "namingContexts", "subschemaSubentry", "altServer", });
+            search = new SearchOp("", searchControls, filter);
+
+            try {
+                client.doOperation(search, requestControls);
+            } catch (IOException e) {
+                CommunicationException ex = new CommunicationException(e
+                        .getMessage());
+                ex.setRootCause(e);
+                if (search.getSearchResult().isEmpty()) {
+                    throw ex;
+                }
+                search.getSearchResult().setException(ex);
+            }
+
+            sre = search.getSearchResult();
+            names = sre.getEntries();
+
+            keyset = names.keySet();
+            for (Iterator<String> iterator = keyset.iterator(); iterator
+                    .hasNext();) {
+                String key = iterator.next();
+                Attributes as = names.get(key);
+                subschemasubentry = (String) as.get("subschemasubentry").get();
+            }
+        }
+
+        searchControls.setSearchScope(SearchControls.OBJECT_SCOPE);
+        searchControls.setReturningAttributes(new String[] { "objectclasses",
+                "attributetypes", "matchingrules", "ldapsyntaxes" });
+        searchControls.setReturningObjFlag(true);
+        filterParser = new FilterParser("(objectClass=subschema)");
+        try {
+            filter = filterParser.parse();
+        } catch (ParseException e) {
+            InvalidSearchFilterException ex = new InvalidSearchFilterException(
+                    Messages.getString("ldap.29")); //$NON-NLS-1$
+            ex.setRootCause(e);
+            throw ex;
+        }
+        search = new SearchOp(subschemasubentry, searchControls, filter);
+
+        try {
+            client.doOperation(search, requestControls);
+        } catch (IOException e) {
+            CommunicationException ex = new CommunicationException(e
+                    .getMessage());
+            ex.setRootCause(e);
+            if (search.getSearchResult().isEmpty()) {
+                throw ex;
+            }
+            search.getSearchResult().setException(ex);
+        }
+        if (search.getResult().getResultCode() == LdapResult.INVALID_DN_SYNTAX) {
+            throw new InvalidNameException(Messages.getString("ldap.34"));
+        }
+        sre = search.getSearchResult();
+        names = sre.getEntries();
+
+        keyset = names.keySet();
+        for (Iterator<String> iterator = keyset.iterator(); iterator.hasNext();) {
+            String key = iterator.next();
+            Attributes as = names.get(key);
+            NamingEnumeration<String> ids = as.getIDs();
+
+            while (ids.hasMoreElements()) {
+                String schemaType = ids.nextElement();
+                if (!schemaTree.contains(schemaType)) {
+                    schemaTree.put(schemaType,
+                            new Hashtable<String, Hashtable<String, Object>>());
+                }
+                Hashtable<String, Hashtable<String, Object>> schemaDefs = schemaTree
+                        .get(schemaType);
+                LdapAttribute attribute = (LdapAttribute) as.get(schemaType);
+                for (int i = 0; i < attribute.size(); i++) {
+                    String value = (String) attribute.get(i);
+                    parseValue(value, schemaDefs);
+                }
+            }
+        }
+        ldapSchemaCtx = new LdapSchemaContextImpl(this, env, name);
+        return ldapSchemaCtx;
+    }
+
+    Hashtable<String, Object> findSchemaDefInfo(String schemaType,
+            String className) {
+        Hashtable<String, Hashtable<String, Object>> schemaDefs = schemaTree
+                .get(schemaType);
+        Hashtable<String, Object> schemaDef = schemaDefs.get(className);
+        return schemaDef;
+    }
+
+    /*
+     * Sample schema value from Openldap server is ( 2.5.13.8 NAME
+     * 'numericStringMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 ) TODO check
+     * with RFC to see whether all the schema definition has been catered for
+     */
+    private static void parseValue(String value,
+            Hashtable<String, Hashtable<String, Object>> schemaDefs) {
+        StringTokenizer st = new StringTokenizer(value);
+        // Skip (
+        st.nextToken();
+
+        String oid = st.nextToken();
+
+        Hashtable<String, Object> schemaDef = new Hashtable<String, Object>();
+        schemaDef.put("orig", value);
+        schemaDef.put("numericoid", oid);
+        String token = null;
+        ArrayList<String> values = null;
+        StringBuilder desc = new StringBuilder();
+        while (st.hasMoreTokens()) {
+            String attrName = st.nextToken();
+            if (attrName.startsWith("x-")) {
+                token = st.nextToken();
+                // remove the ending ' symbol
+                token = token.substring(0, token.length() - 1);
+                schemaDef.put(attrName, token);
+            }
+            if (attrName.equals("usage") || attrName.equals("equality")
+                    || attrName.equals("syntax") || attrName.equals("ordering")
+                    || attrName.equals("substr")) {
+                token = st.nextToken();
+                schemaDef.put(attrName, token);
+            }
+            if (attrName.equals("desc")) {
+                token = st.nextToken();
+
+                // remove the leading ' symbol
+                if (token.startsWith("'"))
+                    token = token.substring(1);
+                while (!token.endsWith("'")) {
+                    desc.append(token).append(" ");
+                    token = st.nextToken();
+                }
+
+                // remove the ending ' symbol
+                desc.append(token.substring(0, token.length() - 1));
+                schemaDef.put(attrName, desc.toString());
+                desc.delete(0, desc.length());
+            }
+            if (attrName.equals("name")) {
+                token = st.nextToken();
+                values = new ArrayList<String>();
+                // Name has multiple values
+                if (token.startsWith("(")) {
+                    token = st.nextToken();
+                    while (!token.equals(")")) {
+                        // remove enclosing quotation
+                        token = token.substring(1, token.length() - 1);
+                        values.add(token);
+                        token = st.nextToken();
+                    }
+                } else {
+                    // remove enclosing quotation
+                    token = token.substring(1, token.length() - 1);
+                    values.add(token);
+                }
+                schemaDef.put(attrName, values);
+                schemaDefs.put(values.get(0), schemaDef);
+            }
+            if (attrName.equals("must") || attrName.equals("sup")
+                    || attrName.equals("may")) {
+                token = st.nextToken();
+                values = new ArrayList<String>();
+                // has multiple values
+                if (token.startsWith("(")) {
+                    token = st.nextToken();
+                    while (!token.equals(")")) {
+                        if (!token.equals("$"))
+                            values.add(token);
+                        token = st.nextToken();
+                    }
+                } else {
+                    values.add(token);
+                }
+                schemaDef.put(attrName, values);
+            }
+            if (attrName.equals("abstract") || attrName.equals("structual")
+                    || attrName.equals("auxiliary")
+                    || attrName.equals("single-value")
+                    || attrName.equals("no-user-modification")) {
+                schemaDef.put(attrName, "true");
+            }
+        }
+        if (!schemaDef.keySet().contains("name")) {
+            schemaDefs.put(oid, schemaDef);
+        }
     }
 
     public DirContext getSchema(String s) throws NamingException {
-        return getSchema(convertFromStringToName(s));
+        return getSchema(new CompositeName(s));
     }
 
     public DirContext getSchemaClassDefinition(Name name)
@@ -210,14 +702,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(), this));
+                break;
+            case DirContext.REMOVE_ATTRIBUTE:
+                op.addModification(1, new LdapAttribute(item.getAttribute(), this));
+                break;
+            case DirContext.REPLACE_ATTRIBUTE:
+                op.addModification(2, new LdapAttribute(item.getAttribute(), this));
+                break;
+            default:
+                throw new IllegalArgumentException(Messages.getString(
+                        "jndi.14", item.getModificationOp())); //$NON-NLS-1$
+            }
+        }
+
+        doBasicOperation(op);
     }
 
     public void modifyAttributes(String s, int i, Attributes attributes)
@@ -248,15 +803,127 @@
 
     public NamingEnumeration<SearchResult> search(Name name,
             Attributes attributes, String[] as) 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.search(remainingName, attributes, as);
+        }
+
+        /*
+         * there is only one ldap ns
+         */
+        // get absolute dn name
+        String targetDN = getTargetDN(name, contextDn);
+        Filter filter = null;
+
+        // construct filter
+        if (attributes == null || attributes.size() == 0) {
+            filter = new Filter(Filter.PRESENT_FILTER);
+            filter.setValue("objectClass");
+        } else {
+            NamingEnumeration<? extends Attribute> attrs = attributes.getAll();
+            filter = new Filter(Filter.AND_FILTER);
+            while (attrs.hasMore()) {
+                Attribute attr = attrs.next();
+                String type = attr.getID();
+                NamingEnumeration<?> enuValues = attr.getAll();
+                while (enuValues.hasMore()) {
+                    Object value = enuValues.next();
+                    Filter child = new Filter(Filter.EQUALITY_MATCH_FILTER);
+                    child.setValue(new AttributeTypeAndValuePair(type, value));
+                    filter.addChild(child);
+                }
+            }
+        }
+
+        SearchControls controls = new SearchControls();
+        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()) {
+            String relativeName = convertToRelativeName(dn, baseDN);
+            SearchResult sr = new SearchResult(relativeName, null, entries
+                    .get(dn));
+            sr.setNameInNamespace(dn);
+            list.add(sr);
+        }
+
+        return new LdapNamingEnumeration<SearchResult>(list, result
+                .getException());
     }
 
     public NamingEnumeration<SearchResult> search(Name name, String filter,
             Object[] objs, SearchControls searchControls)
             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.search(remainingName, filter, objs, searchControls);
+        }
+
+        /*
+         * there is only one ldap ns
+         */
+        if (filter == null) {
+            throw new NullPointerException(Messages.getString("ldap.28")); //$NON-NLS-1$
+        }
+
+        if (objs == null) {
+            objs = new Object[0];
+        }
+
+        if (searchControls == null) {
+            searchControls = new SearchControls();
+        }
+
+        // get absolute dn name
+        String targetDN = getTargetDN(name, contextDn);
+        FilterParser filterParser = new FilterParser(filter);
+        filterParser.setArgs(objs);
+        Filter f = null;
+        try {
+            f = filterParser.parse();
+        } catch (ParseException e) {
+            InvalidSearchFilterException ex = new InvalidSearchFilterException(
+                    Messages.getString("ldap.29")); //$NON-NLS-1$
+            ex.setRootCause(e);
+            throw ex;
+        }
+
+        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()) {
+            String relativeName = convertToRelativeName(dn, baseDN);
+            SearchResult sr = new SearchResult(relativeName, null, entries
+                    .get(dn));
+            sr.setNameInNamespace(dn);
+            list.add(sr);
+        }
+
+        return new LdapNamingEnumeration<SearchResult>(list, result
+                .getException());
     }
 
     public NamingEnumeration<SearchResult> search(Name name, String filter,
@@ -286,6 +953,91 @@
         return search(convertFromStringToName(name), filter, searchControls);
     }
 
+    LdapSearchResult doSearch(SearchOp op) throws NamingException {
+        if (env.get(LDAP_DEREF_ALIASES) != null) {
+            String derefAliases = (String) env.get(LDAP_DEREF_ALIASES);
+            if (derefAliases.equals("always")) {
+                op.setDerefAliases(0);
+            } else if (derefAliases.equals("never")) {
+                op.setDerefAliases(1);
+            } else if (derefAliases.equals("finding")) {
+                op.setDerefAliases(2);
+            } else if (derefAliases.equals("searching")) {
+                op.setDerefAliases(3);
+            } else {
+                throw new IllegalArgumentException(Messages.getString(
+                        "ldap.30", new Object[] { env.get(LDAP_DEREF_ALIASES), //$NON-NLS-1$
+                                LDAP_DEREF_ALIASES }));
+            }
+
+        }
+
+        if (env.containsKey(LDAP_TYPES_ONLY)) {
+            String typesOnly = (String) env.get(LDAP_TYPES_ONLY);
+            if ("true".equals(typesOnly)) {
+                op.setTypesOnly(true);
+            } else if ("false".equals(typesOnly)) {
+                op.setTypesOnly(false);
+            } else {
+                throw new IllegalArgumentException(Messages.getString(
+                        "ldap.30", new Object[] { env.get(LDAP_TYPES_ONLY), //$NON-NLS-1$
+                                LDAP_TYPES_ONLY }));
+            }
+        }
+
+        LdapMessage message = null;
+        try {
+            message = client.doOperation(op, requestControls);
+        } catch (IOException e) {
+            CommunicationException ex = new CommunicationException(e
+                    .getMessage());
+            ex.setRootCause(e);
+            if (op.getSearchResult() == null || op.getSearchResult().isEmpty()) {
+                throw ex;
+            }
+            op.getSearchResult().setException(ex);
+            // occurs errors, just return, doesn't deal with referral and
+            // controls
+            return op.getSearchResult();
+        }
+
+        // TODO: assume response controls returned in last message, it may
+        // be not correct
+        Control[] rawControls = message.getControls();
+        responseControls = narrowingControls(rawControls);
+
+        LdapResult result = op.getResult();
+
+        op.getSearchResult().setException(
+                LdapUtils.getExceptionFromResult(result));
+
+        // has error, not deal with referrals
+        if (op.getSearchResult().getException() != null) {
+            return op.getSearchResult();
+        }
+
+        // baseObject is not located at the server
+        if (result.getResultCode() == 10) {
+            // TODO deal with referrals
+            throw new NotYetImplementedException();
+        }
+
+        // there are SearchResultReference in search result
+        if (op.getSearchResult().getRefURLs() != null
+                && op.getSearchResult().getRefURLs().size() != 0) {
+            // TODO deal with referrals
+            throw new NotYetImplementedException();
+        }
+
+        return op.getSearchResult();
+    }
+
+    LdapSearchResult doSearch(String dn, Filter filter, SearchControls controls)
+            throws NamingException {
+        SearchOp op = new SearchOp(dn, controls, filter);
+        return doSearch(op);
+    }
+
     public Object addToEnvironment(String s, Object o) throws NamingException {
         // TODO not yet implemented
         throw new NotYetImplementedException();
@@ -348,13 +1100,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 +1163,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;
     }
 
@@ -379,8 +1185,152 @@
 
     public NamingEnumeration<NameClassPair> list(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);
+            return nns.list(remainingName);
+        }
+
+        /*
+         * there is only one ldap ns
+         */
+        // absolute dn name to list
+        String targetDN = getTargetDN(name, contextDn);
+
+        // 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");
+
+        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 = 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);
+        }
+
+        return new LdapNamingEnumeration<NameClassPair>(list, result
+                .getException());
+    }
+
+    /**
+     * convert absolute dn to the dn relatived to the dn of
+     * <code>targetContextDN</code>.
+     * 
+     * @param dn
+     *            absolute dn
+     * @param base
+     *            base dn of the relative name
+     * @return dn relatived to the <code>dn</code> of <code>base</code>
+     */
+    protected String convertToRelativeName(String dn, String base) {
+
+        if (base.equals("")) {
+            return dn;
+        }
+
+        int index = dn.lastIndexOf(base);
+        if (index == 0) {
+            return "";
+        }
+
+        return dn.substring(0, index - 1);
+    }
+
+    protected 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();
+    }
+
+    protected 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<NameClassPair> list(String s)
@@ -419,7 +1369,7 @@
      * @throws InvalidNameException
      *             occurs error while converting
      */
-    private Name convertFromStringToName(String s) throws InvalidNameException {
+    protected Name convertFromStringToName(String s) throws InvalidNameException {
         if (s == null) {
             // jndi.2E=The name is null
             throw new NullPointerException(Messages.getString("jndi.2E")); //$NON-NLS-1$
@@ -456,8 +1406,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 +1462,72 @@
 
     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
+     */
+    protected 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
+
+        NamingException ex = LdapUtils.getExceptionFromResult(result);
+        if (ex != null) {
+            throw ex;
+        }
+    }
+
+    /**
+     * 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/branches/java6/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapMessage.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/branches/java6/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapMessage.java?rev=596693&r1=596692&r2=596693&view=diff
==============================================================================
--- harmony/enhanced/classlib/branches/java6/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapMessage.java (original)
+++ harmony/enhanced/classlib/branches/java6/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapMessage.java Tue Nov 20 06:42:33 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;
 
@@ -34,28 +36,34 @@
  * 
  */
 public class LdapMessage implements ASN1Encodable, ASN1Decodable {
-    
+
     /**
      * operation request which could be encoded using ASN.1 BER
      */
     private ASN1Encodable requestOp;
-    
+
     /**
      * operation response operation which could be decoded using ASN.1 BER
      */
     private ASN1Decodable responseOp;
-    
+
+    /**
+     * controls for this message
+     */
+    private Control[] controls;
+
     /**
      * index of the operation, determine which operation is encapsulated in this
      * message.
      */
     private int opIndex;
-    
+
+
     /**
      * unique request id for each session
      */
     private int messageId;
-    
+
     private static int nextMessageId = 1;
 
     /**
@@ -66,6 +74,7 @@
     public static synchronized int getNextMessageId() {
         return nextMessageId++;
     }
+
     /**
      * Get message id of this message
      * 
@@ -74,6 +83,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,9 +99,10 @@
     public LdapMessage(int opIndex, ASN1Encodable op, Control[] controls) {
         this.opIndex = opIndex;
         requestOp = op;
+        this.controls = controls;
         messageId = getNextMessageId();
     }
-    
+
     /**
      * Construct a response message. <code>op</code> indicate which operation
      * to be used, and the message would be initialized after calling
@@ -106,7 +117,7 @@
         opIndex = -1;
         messageId = -1;
     }
-    
+
     /**
      * Encode this message using ASN.1 Basic Encoding Rules (BER)
      * 
@@ -115,7 +126,7 @@
     public byte[] encode() {
         return LdapASN1Constant.LDAPMessage.encode(this);
     }
-    
+
     /**
      * Decode values from <code>InputStream</code> using ASN.1 BER, and the
      * decoded values will initialize this <code>LdapMessage</code> instance.
@@ -129,15 +140,32 @@
         Object[] values = (Object[]) LdapASN1Constant.LDAPMessage.decode(in);
         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]);
         if (values[1] == null) {
             return;
         }
+
         ChosenValue chosen = (ChosenValue) values[1];
         opIndex = chosen.getIndex();
+        // failed to retrieve responseOp
+        responseOp = getResponseOp();
+        if (responseOp == null) {
+            return;
+        }
+
         if (opIndex == LdapASN1Constant.OP_SEARCH_RESULT_DONE
                 || opIndex == LdapASN1Constant.OP_SEARCH_RESULT_ENTRY
                 || opIndex == LdapASN1Constant.OP_SEARCH_RESULT_REF) {
@@ -154,23 +182,28 @@
 
     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;
+        }
     }
 
     /**
-     * Get message id of this message
-     * 
-     * @return id of this message
-     */
-    /**
      * Get index of the operation, determine which operation is encapsulated in
      * this message. If this <code>LdapMessage</code> instance is not initial,
      * <code>-1</code> will be returned.
@@ -180,4 +213,9 @@
     public int getOperationIndex() {
         return opIndex;
     }
+
+    public ASN1Decodable getResponseOp() {
+        return responseOp;
+    }
+
 }

Modified: harmony/enhanced/classlib/branches/java6/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapNamingEnumeration.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/branches/java6/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapNamingEnumeration.java?rev=596693&r1=596692&r2=596693&view=diff
==============================================================================
--- harmony/enhanced/classlib/branches/java6/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapNamingEnumeration.java (original)
+++ harmony/enhanced/classlib/branches/java6/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapNamingEnumeration.java Tue Nov 20 06:42:33 2007
@@ -115,5 +115,9 @@
     protected void setException(NamingException exception) {
         this.exception = exception;
     }
+    
+    void add(T pair) {
+        values.add(pair);
+    }
 
 }

Modified: harmony/enhanced/classlib/branches/java6/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapOperation.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/branches/java6/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapOperation.java?rev=596693&r1=596692&r2=596693&view=diff
==============================================================================
--- harmony/enhanced/classlib/branches/java6/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapOperation.java (original)
+++ harmony/enhanced/classlib/branches/java6/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapOperation.java Tue Nov 20 06:42:33 2007
@@ -53,4 +53,15 @@
      * @return index of response of this operation
      */
     public int getResponseId();
+
+    /**
+     * Get <code>LdapResult</code> from response. Except unbind and abandon
+     * operation, all ldap operation response contains LdapResult, which
+     * indicate whether the operation is successful or what error occurs.
+     * 
+     * @return instance of <code>LdapResult</code>. <code>null</code> if
+     *         operation has not completed or response donesn't contian
+     *         LDAPResult.
+     */
+    public LdapResult getResult();
 }

Modified: harmony/enhanced/classlib/branches/java6/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapResult.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/branches/java6/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapResult.java?rev=596693&r1=596692&r2=596693&view=diff
==============================================================================
--- harmony/enhanced/classlib/branches/java6/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapResult.java (original)
+++ harmony/enhanced/classlib/branches/java6/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapResult.java Tue Nov 20 06:42:33 2007
@@ -27,6 +27,83 @@
  * This class represents LDAPResult defined in RFC 2251 page 16.
  */
 public class LdapResult implements ASN1Decodable {
+    public static final int SUCCESS = 0;
+
+    public static final int OPERATIONS_ERROR = 1;
+
+    public static final int PROTOCOL_ERROR = 2;
+
+    public static final int TIME_LIMIT_EXCEEDED = 3;
+
+    public static final int SIZE_LIMIT_EXCEEDED = 4;
+
+    public static final int COMPARE_FALSE = 5;
+
+    public static final int COMPARE_TRUE = 6;
+
+    public static final int AUTH_METHOD_NOT_SUPPORTED = 7;
+
+    public static final int STRONGER_AUTH_REQUIRED = 8;
+
+    public static final int REFERRAL = 10;
+
+    public static final int ADMIN_LIMIT_EXCEEDED = 11;
+
+    public static final int UNAVAILABLE_CRITICAL_EXTENSION = 12;
+
+    public static final int CONFIDENTIALITY_REQUIRED = 13;
+
+    public static final int SASL_BIND_IN_PROGRESS = 14;
+
+    public static final int NO_SUCH_ATTRIBUTE = 16;
+
+    public static final int UNDEFINED_ATTRIBUTE_TYPE = 17;
+
+    public static final int INAPPROPRIATE_MATCHING = 18;
+
+    public static final int CONSTRAINT_VIOLATION = 19;
+
+    public static final int ATTRIBUTE_OR_VALUE_EXISTS = 20;
+
+    public static final int INVALID_ATTRIBUTE_SYNTAX = 21;
+
+    public static final int NO_SUCH_OBJECT = 32;
+
+    public static final int ALIAS_PROBLEM = 33;
+
+    public static final int INVALID_DN_SYNTAX = 34;
+
+    public static final int ALIAS_DEREFERENCING_PROBLEM = 36;
+
+    public static final int INAPPROPRIATE_AUTHENTICATION = 48;
+
+    public static final int INVALID_CREDENTIALS = 49;
+
+    public static final int INSUFFICIENT_ACCESS_RIGHTS = 50;
+
+    public static final int BUSY = 51;
+
+    public static final int UNAVAILABLE = 52;
+
+    public static final int UNWILLING_TO_PERFORM = 53;
+
+    public static final int LOOP_DETECT = 54;
+
+    public static final int NAMING_VIOLATION = 64;
+
+    public static final int OBJECT_CLASS_VIOLATION = 65;
+
+    public static final int NOT_ALLOWED_ON_NON_LEAF = 66;
+
+    public static final int NOT_ALLOWED_ON_RDN = 67;
+
+    public static final int ENTRY_ALREADY_EXISTS = 68;
+
+    public static final int OBJECT_CLASS_MODS_PROHIBITED = 69;
+
+    public static final int AFFECTS_MULTIPLE_DSAS = 71;
+
+    public static final int OTHER = 80;
 
     private int resultCode;
 
@@ -66,10 +143,26 @@
      * Retrieves the referrals.
      * 
      * @return A prossibly null array. <code>null</code> means no referrals
-     *         retrieved from server
+     *         retrieves from server
      */
     public String[] getReferrals() {
         return referrals;
+    }
+
+    public void setErrorMessage(String errorMessage) {
+        this.errorMessage = errorMessage;
+    }
+
+    public void setMachedDN(String machedDN) {
+        this.machedDN = machedDN;
+    }
+
+    public void setReferrals(String[] referrals) {
+        this.referrals = referrals;
+    }
+
+    public void setResultCode(int resultCode) {
+        this.resultCode = resultCode;
     }
 
     public int getResultCode() {

Modified: harmony/enhanced/classlib/branches/java6/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapSearchResult.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/branches/java6/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapSearchResult.java?rev=596693&r1=596692&r2=596693&view=diff
==============================================================================
--- harmony/enhanced/classlib/branches/java6/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapSearchResult.java (original)
+++ harmony/enhanced/classlib/branches/java6/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapSearchResult.java Tue Nov 20 06:42:33 2007
@@ -19,17 +19,14 @@
 
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
-import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
 import javax.naming.directory.Attributes;
 import javax.naming.directory.BasicAttributes;
-import javax.naming.directory.SearchResult;
 
-import org.apache.harmony.jndi.provider.dns.BasicNamingEnumerator;
 import org.apache.harmony.jndi.provider.ldap.asn1.LdapASN1Constant;
 import org.apache.harmony.jndi.provider.ldap.asn1.Utils;
 import org.apache.harmony.jndi.provider.ldap.asn1.ASN1ChoiceWrap.ChosenValue;
@@ -39,7 +36,7 @@
     /**
      * all search result entries
      */
-    private Map<String, SearchResult> entries = new HashMap<String, SearchResult>();
+    private Map<String, Attributes> entries = new HashMap<String, Attributes>();
 
     /**
      * SearchResultReference from server
@@ -49,6 +46,8 @@
 
     private LdapResult result;
 
+    private NamingException ex;
+
     public void decodeSearchResponse(Object[] values) {
         ChosenValue chosen = (ChosenValue) values[0];
         switch (chosen.getIndex()) {
@@ -79,13 +78,14 @@
     private void decodeEntry(Object value) {
         Object[] values = (Object[]) value;
         String name = Utils.getString((byte[]) values[0]);
+
         Attributes attrs = null;
 
         if (entries.containsKey(name)) {
-            attrs = entries.get(name).getAttributes();
+            attrs = entries.get(name);
         } else {
             attrs = new BasicAttributes();
-            entries.put(name, new SearchResult(name, new Object(), attrs));
+            entries.put(name, attrs);
         }
 
         Collection<Object[]> list = (Collection<Object[]>) values[1];
@@ -96,31 +96,8 @@
         }
     }
 
-    public NamingEnumeration<SearchResult> getEnumeration() {
-        //TODO: this is simple implementation, need to be completed
-        return new BasicNamingEnumerator<SearchResult>(
-                new Enumeration<SearchResult>() {
-                    private ArrayList<SearchResult> values = new ArrayList<SearchResult>(
-                            entries.values());
-
-                    private int index = -1;
-
-                    public boolean hasMoreElements() {
-                        if (index == -1) {
-                            index = 0;
-                        }
-                        
-                        if (index + 1 <= values.size()) {
-                            return true;
-                        }
-
-                        return false;
-                    }
-
-                    public SearchResult nextElement() {
-                        return values.get(index++);
-                    }
-                });
+    public Map<String, Attributes> getEntries() {
+        return entries;
     }
 
     public List<String> getRefURLs() {
@@ -129,5 +106,21 @@
 
     public LdapResult getResult() {
         return result;
+    }
+
+    public NamingException getException() {
+        return ex;
+    }
+
+    public void setException(NamingException ex) {
+        this.ex = ex;
+    }
+
+    public boolean isEmpty() {
+        return entries.size() == 0 && refURLs.size() == 0;
+    }
+
+    public void setRefURLs(List<String> refURLs) {
+        this.refURLs = refURLs;
     }
 }

Modified: harmony/enhanced/classlib/branches/java6/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapUtils.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/branches/java6/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapUtils.java?rev=596693&r1=596692&r2=596693&view=diff
==============================================================================
--- harmony/enhanced/classlib/branches/java6/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapUtils.java (original)
+++ harmony/enhanced/classlib/branches/java6/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapUtils.java Tue Nov 20 06:42:33 2007
@@ -17,15 +17,77 @@
 
 package org.apache.harmony.jndi.provider.ldap;
 
+import java.lang.reflect.Constructor;
+import java.util.HashMap;
+
+import javax.naming.AuthenticationException;
+import javax.naming.AuthenticationNotSupportedException;
+import javax.naming.CommunicationException;
+import javax.naming.ContextNotEmptyException;
 import javax.naming.InvalidNameException;
+import javax.naming.LimitExceededException;
+import javax.naming.NameAlreadyBoundException;
+import javax.naming.NameNotFoundException;
+import javax.naming.NamingException;
+import javax.naming.NoPermissionException;
+import javax.naming.OperationNotSupportedException;
+import javax.naming.PartialResultException;
+import javax.naming.ServiceUnavailableException;
+import javax.naming.SizeLimitExceededException;
+import javax.naming.TimeLimitExceededException;
+import javax.naming.directory.AttributeInUseException;
+import javax.naming.directory.InvalidAttributeIdentifierException;
+import javax.naming.directory.InvalidAttributeValueException;
 import javax.naming.directory.InvalidSearchFilterException;
+import javax.naming.directory.NoSuchAttributeException;
+import javax.naming.directory.SchemaViolationException;
 
 import org.apache.harmony.jndi.internal.nls.Messages;
 import org.apache.harmony.jndi.provider.ldap.parser.FilterParser;
 import org.apache.harmony.jndi.provider.ldap.parser.LdapUrlParser;
 import org.apache.harmony.jndi.provider.ldap.parser.ParseException;
 
+@SuppressWarnings("boxing")
 public class LdapUtils {
+    private static HashMap<Integer, Class<?>> errorCodesMap = new HashMap<Integer, Class<?>>();
+
+    static {
+        errorCodesMap.put(1, NamingException.class);
+        errorCodesMap.put(2, CommunicationException.class);
+        errorCodesMap.put(3, TimeLimitExceededException.class);
+        errorCodesMap.put(4, SizeLimitExceededException.class);
+        errorCodesMap.put(7, AuthenticationNotSupportedException.class);
+        errorCodesMap.put(8, AuthenticationNotSupportedException.class);
+        errorCodesMap.put(9, PartialResultException.class);
+        errorCodesMap.put(11, LimitExceededException.class);
+        errorCodesMap.put(12, OperationNotSupportedException.class);
+        errorCodesMap.put(13, AuthenticationNotSupportedException.class);
+        errorCodesMap.put(16, NoSuchAttributeException.class);
+        errorCodesMap.put(17, InvalidAttributeIdentifierException.class);
+        errorCodesMap.put(18, InvalidSearchFilterException.class);
+        errorCodesMap.put(19, InvalidAttributeValueException.class);
+        errorCodesMap.put(20, AttributeInUseException.class);
+        errorCodesMap.put(21, InvalidAttributeValueException.class);
+        errorCodesMap.put(32, NameNotFoundException.class);
+        errorCodesMap.put(33, NamingException.class);
+        errorCodesMap.put(34, InvalidNameException.class);
+        errorCodesMap.put(36, NamingException.class);
+        errorCodesMap.put(48, AuthenticationNotSupportedException.class);
+        errorCodesMap.put(49, AuthenticationException.class);
+        errorCodesMap.put(50, NoPermissionException.class);
+        errorCodesMap.put(51, ServiceUnavailableException.class);
+        errorCodesMap.put(52, ServiceUnavailableException.class);
+        errorCodesMap.put(53, OperationNotSupportedException.class);
+        errorCodesMap.put(54, NamingException.class);
+        errorCodesMap.put(64, InvalidNameException.class);
+        errorCodesMap.put(65, SchemaViolationException.class);
+        errorCodesMap.put(66, ContextNotEmptyException.class);
+        errorCodesMap.put(67, SchemaViolationException.class);
+        errorCodesMap.put(68, NameAlreadyBoundException.class);
+        errorCodesMap.put(69, SchemaViolationException.class);
+        errorCodesMap.put(71, NamingException.class);
+        errorCodesMap.put(80, NamingException.class);
+    }
 
     public static Filter parseFilter(String filter)
             throws InvalidSearchFilterException {
@@ -71,5 +133,43 @@
         }
 
         return parser;
+    }
+
+    public static NamingException getExceptionFromResult(LdapResult result) {
+        int errorCode = result.getResultCode();
+        // 0 means successful
+        if (errorCode == 0) {
+            return null;
+        }
+
+        Class<?> exceptionClass = errorCodesMap.get(errorCode);
+        // not in map, using NamingException
+        if (exceptionClass == null) {
+            exceptionClass = NamingException.class;
+        }
+
+        try {
+            Constructor<?> constructor = exceptionClass
+                    .getConstructor(new Class[] { String.class });
+            String message = null;
+
+            if (result.getErrorMessage() != null
+                    && !result.getErrorMessage().equals("")) { //$NON-NLS-1$
+                // ldap.34=[LDAP: error code {0} - {1}]
+                message = Messages.getString("ldap.34", new Object[] { //$NON-NLS-1$
+                        errorCode, result.getErrorMessage() });
+            } else {
+                // ldap.35=[LDAP: error code {0}]
+                message = Messages.getString("ldap.35", //$NON-NLS-1$
+                        new Object[] { errorCode });
+            }
+
+            return (NamingException) constructor
+                    .newInstance(new Object[] { message });
+        } catch (Exception e) {
+            // ldap.35=[LDAP: error code {0}]
+            return new NamingException(Messages.getString("ldap.35", //$NON-NLS-1$
+                    new Object[] { errorCode }));
+        }
     }
 }

Modified: harmony/enhanced/classlib/branches/java6/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/ModifyDNOp.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/branches/java6/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/ModifyDNOp.java?rev=596693&r1=596692&r2=596693&view=diff
==============================================================================
--- harmony/enhanced/classlib/branches/java6/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/ModifyDNOp.java (original)
+++ harmony/enhanced/classlib/branches/java6/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/ModifyDNOp.java Tue Nov 20 06:42:33 2007
@@ -66,4 +66,24 @@
         }
     }
 
+    public LdapResult getResult() {
+        return result;
+    }
+
+    public boolean isDeleteoldrdn() {
+        return deleteoldrdn;
+    }
+
+    public String getEntry() {
+        return entry;
+    }
+
+    public String getNewrdn() {
+        return newrdn;
+    }
+
+    public String getNewSuperior() {
+        return newSuperior;
+    }
+
 }

Modified: harmony/enhanced/classlib/branches/java6/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/ModifyOp.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/branches/java6/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/ModifyOp.java?rev=596693&r1=596692&r2=596693&view=diff
==============================================================================
--- harmony/enhanced/classlib/branches/java6/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/ModifyOp.java (original)
+++ harmony/enhanced/classlib/branches/java6/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/ModifyOp.java Tue Nov 20 06:42:33 2007
@@ -82,4 +82,9 @@
             values[1] = attr;
         }
     }
+
+    public LdapResult getResult() {
+        return result;
+    }
+    
 }

Modified: harmony/enhanced/classlib/branches/java6/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/SearchOp.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/branches/java6/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/SearchOp.java?rev=596693&r1=596692&r2=596693&view=diff
==============================================================================
--- harmony/enhanced/classlib/branches/java6/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/SearchOp.java (original)
+++ harmony/enhanced/classlib/branches/java6/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/SearchOp.java Tue Nov 20 06:42:33 2007
@@ -33,14 +33,17 @@
     private String baseObject;
 
     private boolean typesOnly = false;
+    
+    // default value is 'always' = 3
+    private int derefAliases = 3;
 
     private Filter filter;
 
     private SearchControls controls;
 
-    private LdapSearchResult result = new LdapSearchResult();
+    private LdapSearchResult result;
 
-    public LdapSearchResult getResult() {
+    public LdapSearchResult getSearchResult() {
         return result;
     }
 
@@ -70,20 +73,15 @@
     public void encodeValues(Object[] values) {
         values[0] = Utils.getBytes(baseObject);
         values[1] = ASN1Integer.fromIntValue(controls.getSearchScope());
-        if (controls.getDerefLinkFlag()) {
-            // derefAlways
-            values[2] = ASN1Integer.fromIntValue(3);
-        } else {
-            // neverDerefAliases
-            values[2] = ASN1Integer.fromIntValue(0);
-        }
+        values[2] = ASN1Integer.fromIntValue(derefAliases);
         values[3] = ASN1Integer.fromIntValue((int) controls.getCountLimit());
         values[4] = ASN1Integer.fromIntValue(controls.getTimeLimit());
         values[5] = Boolean.valueOf(typesOnly);
         values[6] = filter;
         String[] attributes = controls.getReturningAttributes();
+        // if null, return all attributes
         if (attributes == null) {
-            attributes = new String[] { "" };
+            attributes = new String[0];
         }
 
         List<byte[]> list = new ArrayList<byte[]>(attributes.length);
@@ -95,8 +93,57 @@
     }
 
     public void decodeValues(Object[] values) {
-        
+        if (result == null) {
+            result = new LdapSearchResult();
+        }
         result.decodeSearchResponse(values);
+    }
+
+    public String getBaseObject() {
+        return baseObject;
+    }
+
+    public SearchControls getControls() {
+        return controls;
+    }
+
+    public Filter getFilter() {
+        return filter;
+    }
+
+    public boolean isTypesOnly() {
+        return typesOnly;
+    }
+
+    public void setSearchResult(LdapSearchResult result) {
+        this.result = result;
+    }
+
+    public LdapResult getResult() {
+        if (result == null) {
+            return null;
+        }
+        return result.getResult();
+    }
+
+    public int getDerefAliases() {
+        return derefAliases;
+    }
+
+    public void setDerefAliases(int derefAliases) {
+        this.derefAliases = derefAliases;
+    }
+
+    public void setTypesOnly(boolean typesOnly) {
+        this.typesOnly = typesOnly;
+    }
+
+    public void setBaseObject(String baseObject) {
+        this.baseObject = baseObject;
+    }
+
+    public void setFilter(Filter filter) {
+        this.filter = filter;
     }
 
 }

Modified: harmony/enhanced/classlib/branches/java6/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/asn1/ASN1Encodable.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/branches/java6/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/asn1/ASN1Encodable.java?rev=596693&r1=596692&r2=596693&view=diff
==============================================================================
--- harmony/enhanced/classlib/branches/java6/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/asn1/ASN1Encodable.java (original)
+++ harmony/enhanced/classlib/branches/java6/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/asn1/ASN1Encodable.java Tue Nov 20 06:42:33 2007
@@ -31,8 +31,8 @@
  * OCTET STRING         byte[] (encode: Utils.getBytes(String s)    decode: getString(byte[] bytes))
  * ENUMERATED           byte[] (encode: ASN1Integer.fromIntValue(int value)  decode: ASN1Integer.toIntValue(Object decoded))
  * SEQUENCE             Object[] or ASN1Encodable
- * SEQUENCE OF          java.util.List
- * SET OF               java.util.List
+ * SEQUENCE OF          Collection
+ * SET OF               Collection
  * CHOICE               Object[] or ChosenValue
  * </code>
  * 

Modified: harmony/enhanced/classlib/branches/java6/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/asn1/ASN1LdapFilter.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/branches/java6/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/asn1/ASN1LdapFilter.java?rev=596693&r1=596692&r2=596693&view=diff
==============================================================================
--- harmony/enhanced/classlib/branches/java6/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/asn1/ASN1LdapFilter.java (original)
+++ harmony/enhanced/classlib/branches/java6/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/asn1/ASN1LdapFilter.java Tue Nov 20 06:42:33 2007
@@ -19,6 +19,7 @@
 
 import java.io.IOException;
 
+import org.apache.harmony.jndi.provider.ldap.Filter;
 import org.apache.harmony.jndi.provider.ldap.asn1.ASN1ChoiceWrap.ChosenValue;
 import org.apache.harmony.security.asn1.ASN1Choice;
 import org.apache.harmony.security.asn1.ASN1Type;
@@ -52,11 +53,14 @@
         if (type == null) {
             type = (ASN1Choice) LdapASN1Constant.Filter;
         }
-        ChosenValue chosen = (ChosenValue) out.content;
-        int index = chosen.getIndex();
-        byte[] bytes = type.type[index].encode(chosen.getValue());
-        out.content = bytes;
-        out.length = bytes.length;
+        // has not been decoded
+        if (!(out.content instanceof byte[])) {
+            ChosenValue chosen = (ChosenValue) out.content;
+            int index = chosen.getIndex();
+            byte[] bytes = type.type[index].encode(chosen.getValue());
+            out.content = bytes;
+            out.length = bytes.length;
+        }
         // TODO: Any way better to do this(append out.content to out.encoded)?
         out.encodeString();
     }
@@ -69,8 +73,24 @@
 
     @Override
     public void setEncodingContent(BerOutputStream out) {
-        // FIXME: do nothing if never be called
-        throw new RuntimeException();
+        if (type == null) {
+            type = (ASN1Choice) LdapASN1Constant.Filter;
+        }
+
+        ChosenValue chosen = null;
+        if (out.content instanceof Filter) {
+            Object[] values = new Object[1];
+            ((Filter) out.content).encodeValues(values);
+            chosen = (ChosenValue) values[0];
+        } else {
+            chosen = (ChosenValue) out.content;
+        }
+
+        int index = chosen.getIndex();
+        byte[] bytes = type.type[index].encode(chosen.getValue());
+
+        out.content = bytes;
+        out.length = bytes.length;
     }
 
 }

Modified: harmony/enhanced/classlib/branches/java6/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/asn1/LdapASN1Constant.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/branches/java6/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/asn1/LdapASN1Constant.java?rev=596693&r1=596692&r2=596693&view=diff
==============================================================================
--- harmony/enhanced/classlib/branches/java6/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/asn1/LdapASN1Constant.java (original)
+++ harmony/enhanced/classlib/branches/java6/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/asn1/LdapASN1Constant.java Tue Nov 20 06:42:33 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/branches/java6/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/asn1/Utils.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/branches/java6/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/asn1/Utils.java?rev=596693&r1=596692&r2=596693&view=diff
==============================================================================
--- harmony/enhanced/classlib/branches/java6/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/asn1/Utils.java (original)
+++ harmony/enhanced/classlib/branches/java6/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/asn1/Utils.java Tue Nov 20 06:42:33 2007
@@ -24,8 +24,8 @@
 
 public class Utils {
 
-    private static final String CODING_CHARSET = "UTF-8"; //$NON-NLS-1$
-    
+    public static final String CODING_CHARSET = "UTF-8"; //$NON-NLS-1$
+
     /**
      * conjoin two ASN1Sequence type as new one
      * 
@@ -65,36 +65,95 @@
     }
 
     /**
-     * Convert <code>bytes</code> to <code>String</code> using UTF-8
-     * charset. when <code>bytes</code> is <code>null</code>, empty String
-     * will be returned.
+     * Convert <code>obj</code> to <code>String</code>. If obj is byte[],
+     * then using UTF-8 charset. when <code>obj</code> is <code>null</code>,
+     * empty String would be returned.
      * 
-     * @param bytes
-     *            bytes to be decoded into a UTF-8 string
-     * @return UTF-8 String composed of bytes, never be empty string
+     * @param obj
+     *            object to be covert
+     * @return UTF-8 String
      */
-    public static String getString(byte[] bytes) {
-        try {
-            return (bytes == null) ? "" : new String(bytes, CODING_CHARSET); //$NON-NLS-1$
-        } catch (UnsupportedEncodingException e) {
-            // never reached, because UTF-8 is supported by all java platform
+    public static String getString(Object obj) {
+        if (obj == null) {
             return ""; //$NON-NLS-1$
         }
+
+        if (obj instanceof byte[]) {
+            try {
+                return new String((byte[]) obj, CODING_CHARSET);
+            } catch (UnsupportedEncodingException e) {
+                // never reached, because UTF-8 is supported by all java
+                // platform
+                return ""; //$NON-NLS-1$
+            }
+        } else if (obj instanceof char[]) {
+            return new String((char[]) obj);
+        } else  {
+            return (String) obj;
+        }
+        
     }
 
     /**
-     * Encodes <code>s</code> into a sequence of bytes using UTF-8 charset.
+     * Encodes <code>obj</code> into a sequence of bytes using UTF-8 charset.
      * 
-     * @param s
-     *            String to be encoded
-     * @return UTF-8 String
+     * @param obj
+     *            object to be encoded
+     * @return UTF-8 byte[]
      */
-    public static byte[] getBytes(String s) {
-        try {
-            return (s == null) ? new byte[0] : s.getBytes(CODING_CHARSET);
-        } catch (UnsupportedEncodingException e) {
-            // never reached, because UTF-8 is supported by all java platform
+    public static byte[] getBytes(Object obj) {
+        if (obj == null) {
             return new byte[0];
+        }
+
+        if (obj instanceof String) {
+            try {
+                return ((String) obj).getBytes(CODING_CHARSET);
+            } catch (UnsupportedEncodingException e) {
+                // never reached, because UTF-8 is supported by all java platform
+                return new byte[0];
+            }
+        } else if (obj instanceof char[]) {
+            try {
+                return new String((char[]) obj).getBytes(CODING_CHARSET);
+            } catch (UnsupportedEncodingException e) {
+                // never reached, because UTF-8 is supported by all java platform
+                return new byte[0];
+            }
+        } else {
+            // no other types, ignore class cast expection
+            return (byte[]) obj;
+        }
+    }
+    
+
+    /**
+     * Convert <code>obj</code> to <code>char[]</code>. If obj is byte[],
+     * then using UTF-8 charset. when <code>obj</code> is <code>null</code>,
+     * zero length char array would be returned.
+     * 
+     * @param obj
+     *            object to be covert
+     * @return UTF-8 char[]
+     */
+    public static char[] getCharArray(Object obj) {
+        if (obj == null) {
+            return new char[0];
+        }
+
+        if (obj instanceof String) {
+            return ((String) obj).toCharArray();
+        } else if (obj instanceof byte[]) {
+            try {
+                return new String((byte[]) obj, CODING_CHARSET).toCharArray();
+            } catch (UnsupportedEncodingException e) {
+                // never reached, because UTF-8 is supported by all java
+                // platform
+                return new char[0];
+            }
+        } else {
+            // no other types, ignore class cast expection
+            return (char[]) obj;
         }
     }
 }

Modified: harmony/enhanced/classlib/branches/java6/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/parser/FilterParserConstants.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/branches/java6/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/parser/FilterParserConstants.java?rev=596693&r1=596692&r2=596693&view=diff
==============================================================================
--- harmony/enhanced/classlib/branches/java6/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/parser/FilterParserConstants.java (original)
+++ harmony/enhanced/classlib/branches/java6/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/parser/FilterParserConstants.java Tue Nov 20 06:42:33 2007
@@ -1,4 +1,3 @@
-/* Generated By:JavaCC: Do not edit this line. FilterParserConstants.java */
 /* 
  *  Licensed to the Apache Software Foundation (ASF) under one or more 
  *  contributor license agreements.  See the NOTICE file distributed with 
@@ -15,6 +14,7 @@
  *  See the License for the specific language governing permissions and 
  *  limitations under the License. 
  */
+/* Generated By:JavaCC: Do not edit this line. FilterParserConstants.java */
 
 package org.apache.harmony.jndi.provider.ldap.parser;
 



Mime
View raw message