You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@harmony.apache.org by le...@apache.org on 2007/10/12 04:34:30 UTC

svn commit: r584029 - 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/ test/java/org/apache/har...

Author: leoli
Date: Thu Oct 11 19:34:26 2007
New Revision: 584029

URL: http://svn.apache.org/viewvc?rev=584029&view=rev
Log:
Apply patch for HARMONY-4928([classlib][jndi] Implements Ldap bind operation request and response messages).

Added:
    harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/BindOp.java   (with props)
    harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapClient.java   (with props)
    harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapMessage.java   (with props)
    harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/asn1/ASN1ChoiceWrap.java   (with props)
    harmony/enhanced/classlib/trunk/modules/jndi/src/test/java/org/apache/harmony/jndi/provider/ldap/BindOpTest.java   (with props)
    harmony/enhanced/classlib/trunk/modules/jndi/src/test/java/org/apache/harmony/jndi/provider/ldap/asn1/ASN1ChoiceWrapTest.java   (with props)
Modified:
    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/main/java/org/apache/harmony/jndi/provider/ldap/asn1/Utils.java
    harmony/enhanced/classlib/trunk/modules/jndi/src/test/java/org/apache/harmony/jndi/provider/ldap/asn1/ASN1TestUtils.java

Added: harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/BindOp.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/BindOp.java?rev=584029&view=auto
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/BindOp.java (added)
+++ harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/BindOp.java Thu Oct 11 19:34:26 2007
@@ -0,0 +1,165 @@
+/* 
+ *  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 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.LdapASN1Constant;
+import org.apache.harmony.jndi.provider.ldap.asn1.Utils;
+import org.apache.harmony.jndi.provider.ldap.asn1.ASN1ChoiceWrap.ChosenValue;
+import org.apache.harmony.security.asn1.ASN1Integer;
+
+/**
+ * Ldap Bind operation. Refer to
+ * {@link http://www.rfc-editor.org/rfc/rfc2251.txt} for detailed information
+ * 
+ */
+final public class BindOp implements LdapOperation, ASN1Encodable,
+        ASN1Decodable {
+
+    private int version = DEFAULT_VERSION;
+
+    private static final int DEFAULT_VERSION = 3;
+
+    private String name;
+
+    private AuthenticationChoice authentication;
+
+    final public static class SaslCredentials implements ASN1Encodable {
+
+        private String mechanism;
+
+        private String credentials;
+
+        public void encodeValues(Object[] values) {
+            values[0] = Utils.getBytes(mechanism);
+            values[1] = Utils.getBytes(credentials);
+        }
+
+        public void setMechanism(String mechanism) {
+            this.mechanism = mechanism;
+        }
+
+        public void setCredentials(String credentials) {
+            this.credentials = credentials;
+        }
+
+    }
+
+    final public static class AuthenticationChoice implements ASN1Encodable {
+
+        public AuthenticationChoice(int index, SaslCredentials sasl) {
+            this.index = index;
+            this.sasl = sasl;
+            this.value = new Object[2];
+            sasl.encodeValues((Object[]) value);
+        }
+
+        public AuthenticationChoice(int index, String password) {
+            this.index = index;
+            this.password = password;
+            this.value = Utils.getBytes(this.password);
+        }
+
+        private int index;
+
+        private Object value;
+
+        private SaslCredentials sasl;
+
+        private String password;
+
+        public void encodeValues(Object[] values) {
+            values[0] = new ChosenValue(index, value);
+
+        }
+
+        public int getIndex() {
+            return index;
+        }
+
+        public SaslCredentials getSasl() {
+            return sasl;
+        }
+
+    }
+
+    private LdapResult result;
+
+    private byte[] response; // response from previous negotiation
+
+    public BindOp(int version, String dn) {
+        this.version = version;
+        this.name = dn;
+    }
+
+    public BindOp(String dn, String pwd) {
+        this.name = dn;
+        this.authentication = new AuthenticationChoice(0, pwd);
+        this.response = null;
+    }
+
+    public BindOp(String dn, String pwd, String saslMechanism, byte[] res) {
+        this.name = dn;
+        SaslCredentials sasl = new SaslCredentials();
+        sasl.setMechanism(saslMechanism);
+        sasl.setCredentials(pwd);
+        this.authentication = new AuthenticationChoice(1, sasl);
+        this.response = res;
+    }
+
+    public LdapResult getResult() {
+        return result;
+    }
+
+    public ASN1Encodable getRequest() {
+
+        return this;
+    }
+
+    public ASN1Decodable getResponse() {
+
+        return this;
+    }
+
+    public int getRequestId() {
+        return LdapASN1Constant.OP_BIND_REQUEST;
+    }
+
+    public int getResponseId() {
+        return LdapASN1Constant.OP_BIND_RESPONSE;
+    }
+
+    public void encodeValues(Object[] values) {
+        values[0] = ASN1Integer.fromIntValue(version);
+        values[1] = Utils.getBytes(name);
+        Object[] auth = new Object[1];
+        // TODO: encoding AuthenticationChoice
+        authentication.encodeValues(auth);
+        values[2] = auth[0];
+    }
+
+    public void decodeValues(Object[] values) {
+        result = new LdapResult();
+        result.decodeValues(values);
+        if (values[4] != null) {
+            authentication.getSasl().setCredentials(
+                    Utils.getString((byte[]) values[4]));
+        }
+    }
+}

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

Added: harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapClient.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapClient.java?rev=584029&view=auto
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapClient.java (added)
+++ harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapClient.java Thu Oct 11 19:34:26 2007
@@ -0,0 +1,113 @@
+/* 
+ *  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 java.io.InputStream;
+import java.io.OutputStream;
+import java.net.Socket;
+import java.net.UnknownHostException;
+
+import javax.naming.ldap.Control;
+import javax.net.SocketFactory;
+
+import org.apache.harmony.jndi.provider.ldap.asn1.ASN1Decodable;
+import org.apache.harmony.jndi.provider.ldap.asn1.ASN1Encodable;
+
+/**
+ * LdapClient is the actual class used to communicate with Ldap Server.
+ * 
+ */
+final public class LdapClient {
+    /*
+     * Socket used to communicate with Ldap Server.
+     */
+    private Socket socket;
+
+    /*
+     * Input stream of socket.
+     */
+    private InputStream in;
+
+    /*
+     * Output stream of socket.
+     */
+    private OutputStream out;
+
+    /**
+     * Constructor for LdapClient.
+     * 
+     * @param factory
+     *            used to construct socket through its factory method
+     * @param address
+     *            the Internet Protocol (IP) address of ldap server
+     * @param port
+     *            the port number of ldap server
+     * @throws UnknownHostException
+     *             if the host cannot be resolved
+     * @throws IOException
+     *             if an error occurs while instantiating the socket
+     */
+    public LdapClient(SocketFactory factory, String address, int port)
+            throws UnknownHostException, IOException {
+        socket = factory.createSocket(address, port);
+        in = socket.getInputStream();
+        out = socket.getOutputStream();
+    }
+
+    /**
+     * Carry out the ldap operation encapsulated in operation with controls.
+     * 
+     * @param operation
+     *            the ldap operation
+     * @param controls
+     *            extra controls for some ldap operations
+     * @return the encapsulated response message from ldap server
+     * @throws IOException
+     */
+    public LdapMessage doOperation(LdapOperation operation, Control[] controls)
+            throws IOException {
+        return doOperation(operation.getRequestId(), operation.getRequest(),
+                operation.getResponse(), controls);
+    }
+
+    /**
+     * Send out the ldap operation in request with controls, and decode response
+     * into LdapMessage.
+     * 
+     * @param opIndex
+     * @param request
+     *            the ldap request
+     * @param response
+     *            the ldap response
+     * @param controls
+     *            extra controls for some ldap operations
+     * @return the encapsulated response message from ldap server
+     * @throws IOException
+     */
+    public LdapMessage doOperation(int opIndex, ASN1Encodable request,
+            ASN1Decodable response, Control[] controls) throws IOException {
+
+        LdapMessage requestMsg = new LdapMessage(opIndex, request, controls);
+        out.write(requestMsg.encode());
+        out.flush();
+        LdapMessage responseMsg = new LdapMessage(response);
+        responseMsg.decode(in);
+        return responseMsg;
+    }
+}

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

Added: 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=584029&view=auto
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapMessage.java (added)
+++ harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/LdapMessage.java Thu Oct 11 19:34:26 2007
@@ -0,0 +1,151 @@
+/* 
+ *  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 java.io.InputStream;
+
+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.LdapASN1Constant;
+import org.apache.harmony.jndi.provider.ldap.asn1.ASN1ChoiceWrap.ChosenValue;
+import org.apache.harmony.security.asn1.ASN1Integer;
+
+/**
+ * Ldap Message. Refer to {@link http://www.rfc-editor.org/rfc/rfc2251.txt} for
+ * detailed information
+ * 
+ */
+public class LdapMessage implements ASN1Encodable {
+    
+    /**
+     * 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;
+    
+    /**
+     * 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;
+
+    /**
+     * Get next unique message id
+     * 
+     * @return the next unique message id
+     */
+    public static synchronized int getNextMessageId() {
+        return nextMessageId++;
+    }
+    
+    /**
+     * Construct a request message. <code>op</code> may not be
+     * <code>null</code>. <code>controls</code> is <code>null</code> or a
+     * array of zero length means there is no control for this message.
+     * 
+     * @param opIndex
+     *            request index to indicate which operation is encapsulated
+     * @param op
+     *            encodable operation
+     * @param controls
+     *            message controls
+     */
+    public LdapMessage(int opIndex, ASN1Encodable op, Control[] controls) {
+        this.opIndex = opIndex;
+        requestOp = op;
+        messageId = getNextMessageId();
+    }
+    
+    /**
+     * Construct a response message. <code>op</code> indicate which operation
+     * to be used, and the message would be initialized after calling
+     * <code>decode(byte[])</code> or <code>decode(InputStream)</code>
+     * method.
+     * 
+     * @param op
+     *            response index to indicate which operation to be encapsulated
+     */
+    public LdapMessage(ASN1Decodable op) {
+        responseOp = op;
+        opIndex = -1;
+        messageId = -1;
+    }
+    
+    /**
+     * Encode this message using ASN.1 Basic Encoding Rules (BER)
+     * 
+     * @return the encoded values of this <code>LdapMessage</code> instance
+     */
+    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.
+     * 
+     * @param in
+     * 
+     * @throws IOException
+     *             error occurs when decoding
+     */
+    public void decode(InputStream in) throws IOException {
+        Object[] values = (Object[]) LdapASN1Constant.LDAPMessage.decode(in);
+        decodeValues(values);
+    }
+    
+    @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();
+        responseOp.decodeValues((Object[]) chosen.getValue());
+
+    }
+
+    public void encodeValues(Object[] values) {
+        values[0] = ASN1Integer.fromIntValue(messageId);
+        values[1] = new ChosenValue(opIndex, requestOp);
+    }
+
+    /**
+     * Get message id of this message
+     * 
+     * @return id of this message
+     */
+    public int getMessageId() {
+        return messageId;
+    }
+}

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

Added: harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/asn1/ASN1ChoiceWrap.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/asn1/ASN1ChoiceWrap.java?rev=584029&view=auto
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/asn1/ASN1ChoiceWrap.java (added)
+++ harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/asn1/ASN1ChoiceWrap.java Thu Oct 11 19:34:26 2007
@@ -0,0 +1,100 @@
+/* 
+ *  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.asn1;
+
+import java.io.IOException;
+
+import org.apache.harmony.security.asn1.ASN1Choice;
+import org.apache.harmony.security.asn1.ASN1Type;
+import org.apache.harmony.security.asn1.BerInputStream;
+
+/**
+ * When encoding, the value bind to ASN1ChoiceWrap must be Object array length
+ * of two or ChosenValue instance. For array, Object[0] is Integer, which is the
+ * index of the chosen type (NOTE: not the tag number), Object[1] is the bind
+ * value of the chosen type. For ChosenValue instance, methods
+ * <code>getIndex()</code> and <code>getValue</code> should return chosen
+ * index and value respectively.
+ * <p>
+ * 
+ * When decoding, we always return ChosenValue instance
+ */
+public class ASN1ChoiceWrap extends ASN1Choice {
+
+    public ASN1ChoiceWrap(ASN1Type[] types) {
+        super(types);
+    }
+
+    @Override
+    public int getIndex(Object object) {
+        if (object instanceof ChosenValue) {
+            ChosenValue chosen = (ChosenValue) object;
+            return chosen.getIndex();
+        }
+        
+        if (object instanceof ASN1Encodable) {
+            Object[] value = new Object[1];
+            ((ASN1Encodable) object).encodeValues(value);
+            return getIndex(value[0]);
+        }
+        
+        Object[] values = (Object[]) object;
+        return ((Integer) values[0]).intValue();
+    }
+
+    @Override
+    public Object getObjectToEncode(Object object) {
+        if (object instanceof ChosenValue) {
+            ChosenValue chosen = (ChosenValue) object;
+            return chosen.getValue();
+        }
+        
+        if (object instanceof ASN1Encodable) {
+            Object[] value = new Object[1];
+            ((ASN1Encodable) object).encodeValues(value);
+            return getObjectToEncode(value[0]);
+        }
+        
+        return ((Object[]) object)[1];
+    }
+
+    @Override
+    public Object decode(BerInputStream in) throws IOException {
+        super.decode(in);
+        return new ChosenValue(in.choiceIndex, getDecodedObject(in));
+    }
+
+    public static class ChosenValue {
+        private int index;
+
+        private Object value;
+
+        public ChosenValue(int index, Object value) {
+            this.index = index;
+            this.value = value;
+        }
+
+        public int getIndex() {
+            return index;
+        }
+
+        public Object getValue() {
+            return value;
+        }
+    }
+}

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

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=584029&r1=584028&r2=584029&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 Thu Oct 11 19:34:26 2007
@@ -17,9 +17,13 @@
 
 package org.apache.harmony.jndi.provider.ldap.asn1;
 
+import org.apache.harmony.security.asn1.ASN1Boolean;
 import org.apache.harmony.security.asn1.ASN1Constants;
+import org.apache.harmony.security.asn1.ASN1Enumerated;
 import org.apache.harmony.security.asn1.ASN1Implicit;
+import org.apache.harmony.security.asn1.ASN1Integer;
 import org.apache.harmony.security.asn1.ASN1OctetString;
+import org.apache.harmony.security.asn1.ASN1Sequence;
 import org.apache.harmony.security.asn1.ASN1SequenceOf;
 import org.apache.harmony.security.asn1.ASN1SetOf;
 import org.apache.harmony.security.asn1.ASN1Type;
@@ -28,6 +32,11 @@
  * This class contains all ASN.1 type defined in RFC 2251.
  */
 public class LdapASN1Constant {
+
+    public static final int OP_BIND_REQUEST = 0;
+
+    public static final int OP_BIND_RESPONSE = 1;
+
     public static final int OP_ADD_REQUEST = 9;
     
     public static final int OP_ADD_RESPONSE = 10;
@@ -45,6 +54,72 @@
             ASN1Constants.CLASS_APPLICATION, 8, new ASN1SequenceWrap(
                     new ASN1Type[] { ASN1OctetString.getInstance(), // entry
                             AttributeList })); // attributes
+    
+    public static final ASN1Type SaslCredentials = new ASN1SequenceWrap(
+            new ASN1Type[] { ASN1OctetString.getInstance(), // mechanism
+                    ASN1OctetString.getInstance() }) { // credentials
+        {
+            setOptional(1); // credentials is optional
+        }
+    };
+    
+    public static final ASN1Type AuthenticationChoice = new ASN1ChoiceWrap(
+            new ASN1Type[] {
+                    new ASN1Implicit(ASN1Constants.CLASS_CONTEXTSPECIFIC, 0, // simple
+                            ASN1OctetString.getInstance()),
+                    new ASN1Implicit(ASN1Constants.CLASS_CONTEXTSPECIFIC, 3, // sasl
+                            SaslCredentials) });
+    
+    public static final ASN1Type LDAPResult = new ASN1SequenceWrap(
+            new ASN1Type[] { ASN1Enumerated.getInstance(), // resultCode
+                    ASN1OctetString.getInstance(), // matchedDN
+                    ASN1OctetString.getInstance(), // errorMessage
+                    new ASN1Implicit(ASN1Constants.CLASS_CONTEXTSPECIFIC, 3, // referral
+                            new ASN1SequenceOf(ASN1OctetString.getInstance())) }) {
+        {
+            setOptional(3); // referral is optional
+        }
+    };
+    
+    public static final ASN1Type Control = new ASN1SequenceWrap(new ASN1Type[] {
+            ASN1OctetString.getInstance(), // controlType
+            ASN1Boolean.getInstance(), // criticality
+            ASN1OctetString.getInstance() }) { // controlValue
+        {
+            setDefault(Boolean.FALSE, 1); // criticality default false
+            setOptional(2); // controlValue is optional
+        }
+    };
+    
+    public static final ASN1Type BindRequest = new ASN1Implicit(
+            ASN1Constants.CLASS_APPLICATION, 0, new ASN1SequenceWrap(
+                    new ASN1Type[] { ASN1Integer.getInstance(), // version
+                            ASN1OctetString.getInstance(), // name
+                            AuthenticationChoice })); // authentication
+    
+    public static final ASN1Type BindResponse = new ASN1Implicit(
+            ASN1Constants.CLASS_APPLICATION, 1, Utils.conjoinSequence(
+                    (ASN1Sequence) LDAPResult, // result
+                    new ASN1SequenceWrap(new ASN1Type[] { new ASN1Implicit(
+                            ASN1Constants.CLASS_CONTEXTSPECIFIC, 7, // serverSaslCreds
+                            ASN1OctetString.getInstance()) }) {
+                        {
+                            setOptional(0); // serverSaslCreds is optional
+                        }
+                    }));
+    
+    public static final ASN1Type LDAPMessage = new ASN1SequenceWrap(
+            new ASN1Type[] {
+                    ASN1Integer.getInstance(),
+                    new ASN1ChoiceWrap(new ASN1Type[] { BindRequest,
+                            BindResponse, 
+                            AddRequest, 
+                            }),
+                    new ASN1SequenceOf(Control) }) {
+        {
+            setOptional(2);
+        }
+    };
     
 
 }

Modified: harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/asn1/Utils.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/asn1/Utils.java?rev=584029&r1=584028&r2=584029&view=diff
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/asn1/Utils.java (original)
+++ harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/ldap/asn1/Utils.java Thu Oct 11 19:34:26 2007
@@ -19,9 +19,50 @@
 
 import java.io.UnsupportedEncodingException;
 
+import org.apache.harmony.security.asn1.ASN1Sequence;
+import org.apache.harmony.security.asn1.ASN1Type;
+
 public class Utils {
 
     private static final String CODING_CHARSET = "UTF-8"; //$NON-NLS-1$
+    
+    /**
+     * conjoin two ASN1Sequence type as new one
+     * 
+     * @param first
+     *            first ASN1Sequence type
+     * @param second
+     *            secod ASN1Sequence type
+     * @return a new joined ASN1Sequence type
+     */
+    public static ASN1Sequence conjoinSequence(ASN1Sequence first,
+            ASN1Sequence second) {
+        if (first == null) {
+            return second;
+        }
+
+        if (second == null) {
+            return first;
+        }
+
+        ASN1Type[] result = new ASN1Type[first.type.length + second.type.length];
+        System.arraycopy(first.type, 0, result, 0, first.type.length);
+        System.arraycopy(second.type, 0, result, first.type.length,
+                second.type.length);
+
+        ASN1Sequence sequence = new ASN1SequenceWrap(result);
+
+        System.arraycopy(first.OPTIONAL, 0, sequence.OPTIONAL, 0,
+                first.OPTIONAL.length);
+        System.arraycopy(second.OPTIONAL, 0, sequence.OPTIONAL,
+                first.OPTIONAL.length, second.OPTIONAL.length);
+
+        System.arraycopy(first.DEFAULT, 0, sequence.DEFAULT, 0,
+                first.DEFAULT.length);
+        System.arraycopy(second.DEFAULT, 0, sequence.DEFAULT,
+                first.DEFAULT.length, second.DEFAULT.length);
+        return sequence;
+    }
 
     /**
      * Convert <code>bytes</code> to <code>String</code> using UTF-8

Added: harmony/enhanced/classlib/trunk/modules/jndi/src/test/java/org/apache/harmony/jndi/provider/ldap/BindOpTest.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/jndi/src/test/java/org/apache/harmony/jndi/provider/ldap/BindOpTest.java?rev=584029&view=auto
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/jndi/src/test/java/org/apache/harmony/jndi/provider/ldap/BindOpTest.java (added)
+++ harmony/enhanced/classlib/trunk/modules/jndi/src/test/java/org/apache/harmony/jndi/provider/ldap/BindOpTest.java Thu Oct 11 19:34:26 2007
@@ -0,0 +1,33 @@
+/* 
+ *  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 junit.framework.TestCase;
+
+import org.apache.harmony.jndi.provider.ldap.asn1.ASN1TestUtils;
+import org.apache.harmony.jndi.provider.ldap.asn1.LdapASN1Constant;
+
+public class BindOpTest extends TestCase {
+    public void test_encodeValues_$LObject() {
+        String dn = "o=Entry";
+        String pwd = "secret";
+        BindOp op = new BindOp(dn, pwd);
+
+        ASN1TestUtils.checkEncode(op.getRequest(), LdapASN1Constant.BindRequest);
+    }
+}

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

Added: harmony/enhanced/classlib/trunk/modules/jndi/src/test/java/org/apache/harmony/jndi/provider/ldap/asn1/ASN1ChoiceWrapTest.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/jndi/src/test/java/org/apache/harmony/jndi/provider/ldap/asn1/ASN1ChoiceWrapTest.java?rev=584029&view=auto
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/jndi/src/test/java/org/apache/harmony/jndi/provider/ldap/asn1/ASN1ChoiceWrapTest.java (added)
+++ harmony/enhanced/classlib/trunk/modules/jndi/src/test/java/org/apache/harmony/jndi/provider/ldap/asn1/ASN1ChoiceWrapTest.java Thu Oct 11 19:34:26 2007
@@ -0,0 +1,66 @@
+/* 
+ *  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.asn1;
+
+import java.io.IOException;
+
+import junit.framework.TestCase;
+
+import org.apache.harmony.jndi.provider.ldap.asn1.ASN1ChoiceWrap.ChosenValue;
+import org.apache.harmony.security.asn1.ASN1Boolean;
+import org.apache.harmony.security.asn1.ASN1Integer;
+import org.apache.harmony.security.asn1.ASN1OctetString;
+import org.apache.harmony.security.asn1.ASN1Type;
+
+public class ASN1ChoiceWrapTest extends TestCase {
+    private static ASN1ChoiceWrap choice = new ASN1ChoiceWrap(new ASN1Type[] {
+            ASN1OctetString.getInstance(), ASN1Integer.getInstance(),
+            ASN1Boolean.getInstance() });
+
+    public void test_getIndex_LObject() {
+        Object[] values = new Object[] { Integer.valueOf(1),
+                Integer.valueOf(100) };
+        assertEquals(1, choice.getIndex(values));
+
+        ChosenValue chosen = new ChosenValue(2, Boolean.valueOf(true));
+        assertEquals(2, choice.getIndex(chosen));
+    }
+
+    public void test_getObjectToEncode_LObject() {
+        Object[] values = new Object[] { Integer.valueOf(1),
+                Integer.valueOf(100) };
+        assertEquals(values[1], choice.getObjectToEncode(values));
+
+        ChosenValue chosen = new ChosenValue(0, "hello");
+        assertEquals(chosen.getValue(), choice.getObjectToEncode(chosen));
+    }
+
+    public void test_decode_LBerInputStream() throws IOException {
+        int index = 2;
+        Boolean value = Boolean.FALSE;
+        Object[] values = new Object[] { Integer.valueOf(index), value };
+        byte[] encoded = choice.encode(values);
+        Object decoded = choice.decode(encoded);
+
+        assertTrue(decoded instanceof ChosenValue);
+        ChosenValue chosen = (ChosenValue) decoded;
+
+        assertEquals(index, chosen.getIndex());
+        assertEquals(value, chosen.getValue());
+    }
+}

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

Modified: harmony/enhanced/classlib/trunk/modules/jndi/src/test/java/org/apache/harmony/jndi/provider/ldap/asn1/ASN1TestUtils.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/jndi/src/test/java/org/apache/harmony/jndi/provider/ldap/asn1/ASN1TestUtils.java?rev=584029&r1=584028&r2=584029&view=diff
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/jndi/src/test/java/org/apache/harmony/jndi/provider/ldap/asn1/ASN1TestUtils.java (original)
+++ harmony/enhanced/classlib/trunk/modules/jndi/src/test/java/org/apache/harmony/jndi/provider/ldap/asn1/ASN1TestUtils.java Thu Oct 11 19:34:26 2007
@@ -21,6 +21,7 @@
 
 import junit.framework.Assert;
 
+import org.apache.harmony.jndi.provider.ldap.asn1.ASN1ChoiceWrap.ChosenValue;
 import org.apache.harmony.security.asn1.ASN1Boolean;
 import org.apache.harmony.security.asn1.ASN1Enumerated;
 import org.apache.harmony.security.asn1.ASN1Implicit;
@@ -32,16 +33,18 @@
 import org.apache.harmony.security.asn1.ASN1ValueCollection;
 
 public class ASN1TestUtils {
+    private static final String ASN1ENCODABLE_NAME = ASN1Encodable.class.getCanonicalName();
+    private static final String CHOSENVALUE_NAME = ChosenValue.class.getCanonicalName();
+
     public static void checkEncode(Object value, ASN1Type type) {
         if (type instanceof ASN1Implicit) {
             type = getWrappedType((ASN1Implicit) type);
         }
 
-        if (type instanceof ASN1Integer 
-                || type instanceof ASN1Enumerated) {
+        if (type instanceof ASN1Integer || type instanceof ASN1Enumerated) {
             Assert.assertTrue(value instanceof byte[]);
-            
-            Assert.assertFalse("value should not be zero-length byte array",
+
+            Assert.assertTrue("value should not be zero-length byte array",
                     ((byte[]) value).length != 0);
         } else if (type instanceof ASN1Boolean) {
             Assert.assertTrue(value instanceof Boolean);
@@ -49,18 +52,42 @@
             Assert.assertTrue(value instanceof byte[]);
         } else if (type instanceof ASN1SequenceWrap) {
             checkEncodeSequence(value, (ASN1SequenceWrap) type);
-        } else if (type instanceof ASN1SequenceOf 
-                || type instanceof ASN1SetOf) {
+        } else if (type instanceof ASN1SequenceOf || type instanceof ASN1SetOf) {
             Assert.assertTrue(value instanceof Collection);
             Collection collection = (Collection) value;
             for (Object object : collection) {
                 checkEncode(object, ((ASN1ValueCollection) type).type);
             }
+        } else if (type instanceof ASN1ChoiceWrap) {
+            checkEncodeChoice(value, (ASN1ChoiceWrap) type);
         } else {
             Assert.fail("Not supported ASN.1 type");
         }
     }
-    
+
+    private static void checkEncodeChoice(Object value, ASN1ChoiceWrap type) {
+        if (value instanceof Object[]) {
+            Object[] objs = (Object[]) value;
+            Assert.assertEquals(2, objs.length);
+            Assert.assertTrue(objs[0] instanceof Integer);
+
+            int index = ((Integer) objs[0]).intValue();
+            checkEncode(objs[1], type.type[index]);
+        } else if (value instanceof ChosenValue) {
+            ChosenValue chosen = (ChosenValue) value;
+            checkEncode(chosen.getValue(), type.type[chosen.getIndex()]);
+        } else if (value instanceof ASN1Encodable) {
+            Object[] objs = new Object[1];
+            ((ASN1Encodable) value).encodeValues(objs);
+            checkEncode(objs[0], type);
+        } else {
+
+            Assert.fail("Value for ASN1ChoiceWrap should be Object[2], "
+                    + CHOSENVALUE_NAME + " or "
+                    + ASN1ENCODABLE_NAME);
+        }
+    }
+
     private static void checkEncodeSequence(Object value, ASN1SequenceWrap type) {
         if (value instanceof Object[]) {
             Object[] objs = (Object[]) value;
@@ -77,11 +104,11 @@
             checkEncodeSequence(objs, type);
         } else {
             Assert
-                    .fail("Value for ASN1SequenceWrap should be Object[], "
-                            + "or org.apache.harmony.jndi.provider.ldap.asn1.ASN1Encodable");
+                    .fail("Value for ASN1SequenceWrap should be Object[], or "
+                            + ASN1ENCODABLE_NAME);
         }
     }
-    
+
     private static ASN1Type getWrappedType(ASN1Implicit type) {
         try {
             Field field = ASN1Implicit.class.getDeclaredField("type");
@@ -90,6 +117,6 @@
         } catch (Exception e) {
             // can't reach, unless implement changed
             throw new RuntimeException("Can't get wrapped type.", e);
-        } 
+        }
     }
 }